summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/H5AC.c131
-rw-r--r--src/H5ACprivate.h12
-rw-r--r--src/H5C.c700
-rw-r--r--src/H5Cpkg.h13
-rw-r--r--src/H5Cprivate.h12
-rw-r--r--src/H5HFcache.c1114
-rw-r--r--src/H5HFdblock.c1
-rw-r--r--src/H5HFiblock.c32
-rw-r--r--src/H5HFpkg.h13
9 files changed, 1938 insertions, 90 deletions
diff --git a/src/H5AC.c b/src/H5AC.c
index d03cc88..8eb0dd9 100644
--- a/src/H5AC.c
+++ b/src/H5AC.c
@@ -2592,6 +2592,137 @@ done:
/*************************************************************************/
+/*************************** Debugging Functions: ************************/
+/*************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_get_entry_ptr_from_addr()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, returns a pointer
+ * to the entry in *entry_ptr_ptr. If the entry is not in the
+ * cache, *entry_ptr_ptr is set to NULL.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * As heavy use of this function is almost certainly a
+ * bad idea, the metadata cache tracks the number of
+ * successful calls to this function, and (if
+ * H5C_DO_SANITY_CHECKS is defined) displays any
+ * non-zero count on cache shutdown.
+ *
+ * This function is just a wrapper that calls the H5C
+ * version of the function.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5AC_get_entry_ptr_from_addr(const H5F_t *f,
+ haddr_t addr,
+ void ** entry_ptr_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if ( H5C_get_entry_ptr_from_addr(f, addr, entry_ptr_ptr) < 0 )
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "H5C_get_entry_ptr_from_addr() failed.")
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5AC_get_entry_ptr_from_addr() */
+
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_verify_entry_type()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, test to see if its
+ * type field contains the expected value.
+ *
+ * If the specified entry is in cache, *in_cache_ptr is set
+ * to TRUE, and *type_ok_ptr is set to TRUE or FALSE
+ * depending on whether the entries type field matches the
+ * expected_type parameter
+ *
+ * If the target entry is not in cache, *in_cache_ptr is
+ * set to FALSE, and *type_ok_ptr is undefined.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * This function is just a wrapper that calls the H5C
+ * version of the function.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5AC_verify_entry_type(const H5F_t *f,
+ haddr_t addr,
+ const H5AC_class_t * expected_type,
+ hbool_t * in_cache_ptr,
+ hbool_t * type_ok_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if ( H5C_verify_entry_type(f, addr, (const H5C_class_t *)expected_type,
+ in_cache_ptr, type_ok_ptr) < 0 )
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "H5C_verify_entry_type() failed.")
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5AC_verify_entry_type() */
+
+#endif /* NDEBUG */
+
+
+
+/*************************************************************************/
/**************************** Private Functions: *************************/
/*************************************************************************/
diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h
index ca6dcbf..623f502 100644
--- a/src/H5ACprivate.h
+++ b/src/H5ACprivate.h
@@ -416,5 +416,17 @@ H5_DLL herr_t H5AC_ignore_tags(H5F_t * f);
H5_DLL herr_t H5AC_add_candidate(H5AC_t * cache_ptr, haddr_t addr);
#endif /* H5_HAVE_PARALLEL */
+#ifndef NDEBUG /* debugging functions */
+
+H5_DLL herr_t H5AC_get_entry_ptr_from_addr(const H5F_t *f, haddr_t addr,
+ void ** entry_ptr_ptr);
+
+H5_DLL herr_t H5AC_verify_entry_type(const H5F_t * f, haddr_t addr,
+ const H5AC_class_t * expected_type,
+ hbool_t * in_cache_ptr,
+ hbool_t * type_ok_ptr);
+
+#endif /* NDEBUG */ /* end debugging functions */
+
#endif /* !_H5ACprivate_H */
diff --git a/src/H5C.c b/src/H5C.c
index 445e4bf..56422e5 100644
--- a/src/H5C.c
+++ b/src/H5C.c
@@ -186,8 +186,8 @@ static herr_t H5C_verify_tag(int id, haddr_t tag);
#if H5C_DO_EXTREME_SANITY_CHECKS
static herr_t H5C_validate_lru_list(H5C_t * cache_ptr);
-static herr_t H5C_verify_not_in_index(H5C_t * cache_ptr,
- H5C_cache_entry_t * entry_ptr);
+static herr_t H5C_validate_pinned_entry_list(H5C_t * cache_ptr);
+static herr_t H5C_validate_protected_entry_list(H5C_t * cache_ptr);
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
@@ -1285,6 +1285,10 @@ H5C_create(size_t max_cache_size,
cache_ptr->prefix[0] = '\0'; /* empty string */
+#ifndef NDEBUG
+ cache_ptr->get_entry_ptr_from_addr_counter = 0;
+#endif /* NDEBUG */
+
/* Set return value */
ret_value = cache_ptr;
@@ -1543,6 +1547,23 @@ H5C_dest(H5F_t * f,
cache_ptr->slist_ptr = NULL;
} /* end if */
+ /* Only display count of number of calls to H5C_get_entry_ptr_from_add()
+ * if NDEBUG is undefined, and H5C_DO_SANITY_CHECKS is defined. Need
+ * this as the print statement will upset windows, and we frequently
+ * run debug builds there.
+ *
+ * Note that the count is still kept whenever NDEBUG is undefined, and
+ * is reasonably accessible via debugger.
+ */
+#ifndef NDEBUG
+#if H5C_DO_SANITY_CHECKS
+ if ( cache_ptr->get_entry_ptr_from_addr_counter > 0 )
+ HDfprintf(stdout,
+ "*** %ld calls to H5C_get_entry_ptr_from_add(). ***\n",
+ cache_ptr->get_entry_ptr_from_addr_counter);
+#endif /* H5C_DO_SANITY_CHECKS */
+#endif /* NDEBUG */
+
cache_ptr->magic = 0;
cache_ptr = H5FL_FREE(H5C_t, cache_ptr);
@@ -1599,7 +1620,7 @@ H5C_expunge_entry(H5F_t * f,
if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
+ "LRU extreme sanity check failed on entry.\n");
}
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
@@ -1654,7 +1675,7 @@ done:
if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
+ "LRU extreme sanity check failed on exit.\n");
}
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
@@ -1719,6 +1740,16 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign
HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
HDassert( cache_ptr->slist_ptr );
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
+ }
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
ignore_protected = ( (flags & H5C__FLUSH_IGNORE_PROTECTED_FLAG) != 0 );
destroy = ( (flags & H5C__FLUSH_INVALIDATE_FLAG) != 0 );
@@ -2006,7 +2037,8 @@ end_of_inner_loop:
HDassert( (initial_slist_len + cache_ptr->slist_len_increase -
flushed_entries_count) == cache_ptr->slist_len );
- HDassert( (initial_slist_size + cache_ptr->slist_size_increase -
+ HDassert( (initial_slist_size +
+ (size_t)(cache_ptr->slist_size_increase) -
flushed_entries_size) == cache_ptr->slist_size );
#endif /* H5C_DO_SANITY_CHECKS */
@@ -2682,17 +2714,15 @@ H5C_insert_entry(H5F_t * f,
HDassert( thing );
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_verify_not_in_index(cache_ptr, (H5C_cache_entry_t *)thing) < 0 ) {
+ /* no need to verify that entry is not already in the index as */
+ /* we already make that check below. */
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "thing already in index.\n");
- }
-#endif /* H5C_DO_SANITY_CHECKS */
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
-#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
-
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
}
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
@@ -2742,6 +2772,7 @@ H5C_insert_entry(H5F_t * f,
entry_ptr->is_pinned = insert_pinned;
entry_ptr->pinned_from_client = insert_pinned;
+ entry_ptr->pinned_from_cache = FALSE;
entry_ptr->flush_me_last = flush_last;
#ifdef H5_HAVE_PARALLEL
entry_ptr->flush_me_collectively = flush_collectively;
@@ -2911,10 +2942,12 @@ H5C_insert_entry(H5F_t * f,
H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, FAIL)
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed just before done.\n");
}
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
@@ -2930,10 +2963,12 @@ H5C_insert_entry(H5F_t * f,
done:
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
}
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
@@ -3010,12 +3045,13 @@ H5C_mark_entries_as_clean(H5F_t * f,
HDassert( ce_array_ptr != NULL );
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HDassert(0);
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
- }
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
+ }
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
for ( i = 0; i < ce_array_len; i++ )
@@ -3042,11 +3078,12 @@ H5C_mark_entries_as_clean(H5F_t * f,
}
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HDassert(0);
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed in for loop.\n");
}
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
#endif /* H5C_DO_SANITY_CHECKS */
@@ -3220,12 +3257,13 @@ H5C_mark_entries_as_clean(H5F_t * f,
done:
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HDassert(0);
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
- }
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
+ }
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
FUNC_LEAVE_NOAPI(ret_value)
@@ -3359,11 +3397,13 @@ H5C_move_entry(H5C_t * cache_ptr,
HDassert( H5F_addr_ne(old_addr, new_addr) );
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
- }
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
+ }
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
H5C__SEARCH_INDEX(cache_ptr, old_addr, entry_ptr, FAIL)
@@ -3463,10 +3503,11 @@ H5C_move_entry(H5C_t * cache_ptr,
* the sanity checks.
*/
HDassert( cache_ptr->slist_len_increase > 1 );
- HDassert( cache_ptr->slist_size_increase > entry_ptr->size );
+ HDassert( cache_ptr->slist_size_increase >
+ (int64_t)(entry_ptr->size) );
cache_ptr->slist_len_increase -= 1;
- cache_ptr->slist_size_increase -= entry_ptr->size;
+ cache_ptr->slist_size_increase -= (int64_t)(entry_ptr->size);
}
#endif /* H5C_DO_SANITY_CHECKS */
@@ -3480,11 +3521,13 @@ H5C_move_entry(H5C_t * cache_ptr,
done:
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
- }
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
+ }
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
FUNC_LEAVE_NOAPI(ret_value)
@@ -3530,6 +3573,15 @@ H5C_resize_entry(void *thing, size_t new_size)
if(!(entry_ptr->is_pinned || entry_ptr->is_protected))
HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, FAIL, "Entry isn't pinned or protected??")
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
+ }
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
/* update for change in entry size if necessary */
if ( entry_ptr->size != new_size ) {
hbool_t was_clean;
@@ -3594,6 +3646,16 @@ H5C_resize_entry(void *thing, size_t new_size)
} /* end if */
done:
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
+ }
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5C_resize_entry() */
@@ -3608,6 +3670,9 @@ done:
* Programmer: Quincey Koziol
* 3/26/09
*
+ * Changes: Added sanity checks to clarify the circumstances under
+ * which an entry can be pinned. JRM -- 4/27/14
+ *
*-------------------------------------------------------------------------
*/
#ifndef NDEBUG
@@ -3627,6 +3692,7 @@ H5C_pin_entry_from_client(H5C_t UNUSED * cache_ptr,
/* Sanity checks */
HDassert( cache_ptr );
HDassert( entry_ptr );
+ HDassert( entry_ptr->is_protected );
/* Check if the entry is already pinned */
if(entry_ptr->is_pinned) {
@@ -3644,7 +3710,9 @@ H5C_pin_entry_from_client(H5C_t UNUSED * cache_ptr,
entry_ptr->pinned_from_client = TRUE;
done:
+
FUNC_LEAVE_NOAPI(ret_value)
+
} /* H5C_pin_entry_from_client() */
@@ -3659,6 +3727,9 @@ done:
* Programmer: John Mainzer
* 4/26/06
*
+ * Changes: Added extreme sanity checks on entry and exit.
+ * JRM -- 4/26/14
+ *
*-------------------------------------------------------------------------
*/
herr_t
@@ -3677,6 +3748,17 @@ H5C_pin_protected_entry(void *thing)
HDassert(cache_ptr);
HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
+ }
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
/* Only protected entries can be pinned */
if(!entry_ptr->is_protected)
HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Entry isn't protected")
@@ -3686,6 +3768,17 @@ H5C_pin_protected_entry(void *thing)
HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client")
done:
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
+ }
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5C_pin_protected_entry() */
@@ -3779,11 +3872,12 @@ H5C_protect(H5F_t * f,
HDassert( H5F_addr_defined(addr) );
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HDassert(0);
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, \
- "LRU sanity check failed.\n");
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
}
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
@@ -4138,11 +4232,13 @@ H5C_protect(H5F_t * f,
done:
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, \
- "LRU sanity check failed.\n");
- }
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
+ }
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
FUNC_LEAVE_NOAPI(ret_value)
@@ -5353,7 +5449,9 @@ H5C_unpin_entry_from_client(H5C_t * cache_ptr,
entry_ptr->pinned_from_client = FALSE;
done:
+
FUNC_LEAVE_NOAPI(ret_value)
+
} /* H5C_unpin_entry_from_client() */
@@ -5368,6 +5466,9 @@ done:
* Programmer: John Mainzer
* 3/22/06
*
+ * Changes: Added extreme sanity checks on entry and exit.
+ JRM -- 4/26/14
+ *
*-------------------------------------------------------------------------
*/
herr_t
@@ -5385,12 +5486,35 @@ H5C_unpin_entry(void *_entry_ptr)
HDassert(cache_ptr);
HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
+ }
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
/* Unpin the entry */
if(H5C_unpin_entry_from_client(cache_ptr, entry_ptr, TRUE) < 0)
HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry from client")
done:
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
+ }
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
FUNC_LEAVE_NOAPI(ret_value)
+
} /* H5C_unpin_entry() */
@@ -5495,14 +5619,15 @@ H5C_unprotect(H5F_t * f,
was_clean = ! ( entry_ptr->is_dirty );
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
- }
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on entry.\n");
+ }
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
-
/* if the entry has multiple read only protects, just decrement
* the ro_ref_counter. Don't actually unprotect until the ref count
* drops to zero.
@@ -5735,11 +5860,13 @@ H5C_unprotect(H5F_t * f,
done:
#if H5C_DO_EXTREME_SANITY_CHECKS
- if ( H5C_validate_lru_list(cache_ptr) < 0 ) {
+ if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) ||
+ ( H5C_validate_lru_list(cache_ptr) < 0 ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "LRU sanity check failed.\n");
- }
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "an extreme sanity check failed on exit.\n");
+ }
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
FUNC_LEAVE_NOAPI(ret_value)
@@ -7958,7 +8085,8 @@ H5C_flush_invalidate_cache(H5F_t * f,
HDassert( (actual_slist_len + cache_ptr->slist_len) ==
(initial_slist_len + cache_ptr->slist_len_increase) );
HDassert( (actual_slist_size + cache_ptr->slist_size) ==
- (initial_slist_size + cache_ptr->slist_size_increase) );
+ (initial_slist_size +
+ (size_t)(cache_ptr->slist_size_increase)) );
}
#endif /* H5C_DO_SANITY_CHECKS */
@@ -8590,6 +8718,8 @@ H5C_flush_single_entry(H5F_t * f,
}
done:
+ HDassert( ( destroy ) ||
+ ( ( entry_ptr ) && ( ! entry_ptr->flush_in_progress ) ) );
FUNC_LEAVE_NOAPI(ret_value)
} /* H5C_flush_single_entry() */
@@ -9083,6 +9213,11 @@ done:
*
* Programmer: John Mainzer, 7/14/05
*
+ * Changes:
+ *
+ * Added code to verify that the LRU contains no pinned
+ * entries. JRM -- 4/25/14
+ *
*-------------------------------------------------------------------------
*/
#if H5C_DO_EXTREME_SANITY_CHECKS
@@ -9162,6 +9297,13 @@ H5C_validate_lru_list(H5C_t * cache_ptr)
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed")
}
+ if ( ( entry_ptr->is_pinned ) ||
+ ( entry_ptr->pinned_from_client ) ||
+ ( entry_ptr->pinned_from_cache ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed")
+ }
+
len++;
size += entry_ptr->size;
entry_ptr = entry_ptr->next;
@@ -9170,7 +9312,7 @@ H5C_validate_lru_list(H5C_t * cache_ptr)
if ( ( cache_ptr->LRU_list_len != len ) ||
( cache_ptr->LRU_list_size != size ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed")
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed")
}
done:
@@ -9189,11 +9331,10 @@ done:
/*-------------------------------------------------------------------------
*
- * Function: H5C_verify_not_in_index
+ * Function: H5C_validate_pinned_entry_list
*
- * Purpose: Debugging function that scans the hash table to verify
- * that the specified instance of H5C_cache_entry_t is not
- * present.
+ * Purpose: Debugging function that scans the pinned entry list for
+ * errors.
*
* If an error is detected, the function generates a
* diagnostic and returns FAIL. If no error is detected,
@@ -9201,42 +9342,245 @@ done:
*
* Return: FAIL if error is detected, SUCCEED otherwise.
*
- * Programmer: John Mainzer, 7/14/05
+ * Programmer: John Mainzer, 4/25/14
+ *
+ * Changes:
+ *
+ * None.
*
*-------------------------------------------------------------------------
*/
#if H5C_DO_EXTREME_SANITY_CHECKS
static herr_t
-H5C_verify_not_in_index(H5C_t * cache_ptr,
- H5C_cache_entry_t * entry_ptr)
+H5C_validate_pinned_entry_list(H5C_t * cache_ptr)
{
herr_t ret_value = SUCCEED; /* Return value */
- int32_t i;
- int32_t depth;
- H5C_cache_entry_t * scan_ptr = NULL;
+ int32_t len = 0;
+ size_t size = 0;
+ H5C_cache_entry_t * entry_ptr = NULL;
FUNC_ENTER_NOAPI_NOINIT
- HDassert( cache_ptr != NULL );
+ HDassert( cache_ptr );
HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
- HDassert( entry_ptr != NULL );
- for ( i = 0; i < H5C__HASH_TABLE_LEN; i++ )
+ if ( ( ( cache_ptr->pel_head_ptr == NULL )
+ ||
+ ( cache_ptr->pel_tail_ptr == NULL )
+ )
+ &&
+ ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed")
+ }
+
+ if ( ( cache_ptr->pel_len < 0 ) || ( cache_ptr->pel_size < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed")
+ }
+
+ if ( ( cache_ptr->pel_len == 1 )
+ &&
+ ( ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr )
+ ||
+ ( cache_ptr->pel_head_ptr == NULL )
+ ||
+ ( cache_ptr->pel_head_ptr->size != cache_ptr->pel_size )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed")
+ }
+
+ if ( ( cache_ptr->pel_len >= 1 )
+ &&
+ ( ( cache_ptr->pel_head_ptr == NULL )
+ ||
+ ( cache_ptr->pel_head_ptr->prev != NULL )
+ ||
+ ( cache_ptr->pel_tail_ptr == NULL )
+ ||
+ ( cache_ptr->pel_tail_ptr->next != NULL )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed")
+ }
+
+ entry_ptr = cache_ptr->pel_head_ptr;
+ while ( entry_ptr != NULL )
{
- depth = 0;
- scan_ptr = cache_ptr->index[i];
- while ( scan_ptr != NULL )
- {
- if ( scan_ptr == entry_ptr ) {
+ if ( ( entry_ptr != cache_ptr->pel_head_ptr ) &&
+ ( ( entry_ptr->prev == NULL ) ||
+ ( entry_ptr->prev->next != entry_ptr ) ) ) {
- HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
- "Entry already in index.")
- }
- depth++;
- scan_ptr = scan_ptr->ht_next;
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed")
+ }
+
+ if ( ( entry_ptr != cache_ptr->pel_tail_ptr ) &&
+ ( ( entry_ptr->next == NULL ) ||
+ ( entry_ptr->next->prev != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed")
+ }
+
+ if ( ! entry_ptr->is_pinned ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed")
+ }
+
+ if ( ! ( ( entry_ptr->pinned_from_client ) ||
+ ( entry_ptr->pinned_from_cache ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed")
+ }
+
+ len++;
+ size += entry_ptr->size;
+ entry_ptr = entry_ptr->next;
+ }
+
+ if ( ( cache_ptr->pel_len != len ) ||
+ ( cache_ptr->pel_size != size ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed")
+ }
+
+done:
+
+ if ( ret_value != SUCCEED ) {
+
+ HDassert(0);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_validate_pinned_entry_list() */
+
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_validate_protected_entry_list
+ *
+ * Purpose: Debugging function that scans the protected entry list for
+ * errors.
+ *
+ * If an error is detected, the function generates a
+ * diagnostic and returns FAIL. If no error is detected,
+ * the function returns SUCCEED.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 4/25/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5C_DO_EXTREME_SANITY_CHECKS
+
+static herr_t
+H5C_validate_protected_entry_list(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int32_t len = 0;
+ size_t size = 0;
+ H5C_cache_entry_t * entry_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if ( ( ( cache_ptr->pl_head_ptr == NULL )
+ ||
+ ( cache_ptr->pl_tail_ptr == NULL )
+ )
+ &&
+ ( cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed")
+ }
+
+ if ( ( cache_ptr->pl_len < 0 ) || ( cache_ptr->pl_size < 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed")
+ }
+
+ if ( ( cache_ptr->pl_len == 1 )
+ &&
+ ( ( cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr )
+ ||
+ ( cache_ptr->pl_head_ptr == NULL )
+ ||
+ ( cache_ptr->pl_head_ptr->size != cache_ptr->pl_size )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed")
+ }
+
+ if ( ( cache_ptr->pl_len >= 1 )
+ &&
+ ( ( cache_ptr->pl_head_ptr == NULL )
+ ||
+ ( cache_ptr->pl_head_ptr->prev != NULL )
+ ||
+ ( cache_ptr->pl_tail_ptr == NULL )
+ ||
+ ( cache_ptr->pl_tail_ptr->next != NULL )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed")
+ }
+
+ entry_ptr = cache_ptr->pl_head_ptr;
+ while ( entry_ptr != NULL )
+ {
+
+ if ( ( entry_ptr != cache_ptr->pl_head_ptr ) &&
+ ( ( entry_ptr->prev == NULL ) ||
+ ( entry_ptr->prev->next != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed")
+ }
+
+ if ( ( entry_ptr != cache_ptr->pl_tail_ptr ) &&
+ ( ( entry_ptr->next == NULL ) ||
+ ( entry_ptr->next->prev != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed")
+ }
+
+ if ( ! entry_ptr->is_protected ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed")
}
+
+ if ( ( entry_ptr->is_read_only ) &&
+ ( entry_ptr->ro_ref_count <= 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed")
+ }
+
+ len++;
+ size += entry_ptr->size;
+ entry_ptr = entry_ptr->next;
+ }
+
+ if ( ( cache_ptr->pl_len != len ) ||
+ ( cache_ptr->pl_size != size ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed")
}
done:
@@ -9248,13 +9592,195 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* H5C_verify_not_in_index() */
+} /* H5C_validate_protected_entry_list() */
#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
/*-------------------------------------------------------------------------
*
+ * Function: H5C_get_entry_ptr_from_addr()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, returns a pointer
+ * to the entry in *entry_ptr_ptr. If the entry is not in the
+ * cache, *entry_ptr_ptr is set to NULL.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * As heavy use of this function is almost certainly a
+ * bad idea, the metadata cache tracks the number of
+ * successful calls to this function, and (if
+ * H5C_DO_SANITY_CHECKS is defined) displays any
+ * non-zero count on cache shutdown.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5C_get_entry_ptr_from_addr(const H5F_t *f,
+ haddr_t addr,
+ void ** entry_ptr_ptr)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( f );
+ HDassert( f->shared );
+
+ cache_ptr = f->shared->cache;
+
+ HDassert( cache_ptr != NULL );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( H5F_addr_defined(addr) );
+ HDassert( entry_ptr_ptr != NULL );
+
+ /* this test duplicates two of the above asserts, but we need an
+ * invocation of HGOTO_ERROR to keep the compiler happy.
+ */
+ if ( ( cache_ptr == NULL ) || ( cache_ptr->magic != H5C__H5C_T_MAGIC ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.")
+ }
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+
+ if ( entry_ptr == NULL ) {
+
+ /* the entry doesn't exist in the cache -- report this
+ * and quit.
+ */
+ *entry_ptr_ptr = NULL;
+
+ } else {
+
+ *entry_ptr_ptr = entry_ptr;
+
+ /* increment call counter */
+ (cache_ptr->get_entry_ptr_from_addr_counter)++;
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_get_entry_ptr_from_addr() */
+
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_verify_entry_type()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, test to see if its
+ * type field contains the expted value.
+ *
+ * If the specified entry is in cache, *in_cache_ptr is set
+ * to TRUE, and *type_ok_ptr is set to TRUE or FALSE
+ * depending on whether the entries type field matches the
+ * expected_type parameter
+ *
+ * If the target entry is not in cache, *in_cache_ptr is
+ * set to FALSE, and *type_ok_ptr is undefined.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5C_verify_entry_type(const H5F_t *f,
+ haddr_t addr,
+ const H5C_class_t * expected_type,
+ hbool_t * in_cache_ptr,
+ hbool_t * type_ok_ptr)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( f );
+ HDassert( f->shared );
+
+ cache_ptr = f->shared->cache;
+
+ HDassert( cache_ptr != NULL );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( H5F_addr_defined(addr) );
+ HDassert( in_cache_ptr != NULL );
+ HDassert( type_ok_ptr != NULL );
+
+ /* this test duplicates two of the above asserts, but we need an
+ * invocation of HGOTO_ERROR to keep the compiler happy.
+ */
+ if ( ( cache_ptr == NULL ) || ( cache_ptr->magic != H5C__H5C_T_MAGIC ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.")
+ }
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+
+ if ( entry_ptr == NULL ) {
+
+ /* the entry doesn't exist in the cache -- report this
+ * and quit.
+ */
+ *in_cache_ptr = FALSE;
+
+ } else {
+
+ *in_cache_ptr = TRUE;
+ *type_ok_ptr = (expected_type == entry_ptr->type);
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_verify_entry_type() */
+
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
* Function: H5C_ignore_tags
*
* Purpose: Override all assertion frameworks associated with making
diff --git a/src/H5Cpkg.h b/src/H5Cpkg.h
index 909578b..0fdaa79 100644
--- a/src/H5Cpkg.h
+++ b/src/H5Cpkg.h
@@ -846,6 +846,11 @@
* field is intended to allow marking of output of with
* the processes mpi rank.
*
+ * get_entry_ptr_from_addr_counter: Counter used to track the number of
+ * times the H5C_get_entry_ptr_from_addr() function has been
+ * called successfully. This field is only defined when
+ * NDEBUG is not #defined.
+ *
****************************************************************************/
#define H5C__HASH_TABLE_LEN (64 * 1024) /* must be a power of 2 */
@@ -1007,6 +1012,12 @@ struct H5C_t
#endif /* H5C_COLLECT_CACHE_STATS */
char prefix[H5C__PREFIX_LEN];
+
+#ifndef NDEBUG
+
+ int64_t get_entry_ptr_from_addr_counter;
+
+#endif /* NDEBUG */
};
@@ -2198,7 +2209,7 @@ if ( (cache_ptr)->index_size != \
(cache_ptr)->slist_len++; \
(cache_ptr)->slist_size += (entry_ptr)->size; \
(cache_ptr)->slist_len_increase++; \
- (cache_ptr)->slist_size_increase += (entry_ptr)->size; \
+ (cache_ptr)->slist_size_increase += (int64_t)((entry_ptr)->size); \
\
HDassert( (cache_ptr)->slist_len > 0 ); \
HDassert( (cache_ptr)->slist_size > 0 ); \
diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h
index 433411f..38b9469 100644
--- a/src/H5Cprivate.h
+++ b/src/H5Cprivate.h
@@ -1223,5 +1223,17 @@ H5_DLL herr_t H5C_ignore_tags(H5C_t * cache_ptr);
H5_DLL void H5C_retag_copied_metadata(H5C_t * cache_ptr, haddr_t metadata_tag);
+#ifndef NDEBUG /* debugging functions */
+
+H5_DLL herr_t H5C_get_entry_ptr_from_addr(const H5F_t *f, haddr_t addr,
+ void ** entry_ptr_ptr);
+
+H5_DLL herr_t H5C_verify_entry_type(const H5F_t * f, haddr_t addr,
+ const H5C_class_t * expected_type,
+ hbool_t * in_cache_ptr,
+ hbool_t * type_ok_ptr);
+
+#endif /* NDEBUG */
+
#endif /* !_H5Cprivate_H */
diff --git a/src/H5HFcache.c b/src/H5HFcache.c
index 030927d..0f73c68 100644
--- a/src/H5HFcache.c
+++ b/src/H5HFcache.c
@@ -88,14 +88,41 @@ static H5HF_indirect_t *H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t
static herr_t H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock, unsigned UNUSED * flags_ptr);
static herr_t H5HF_cache_iblock_dest(H5F_t *f, H5HF_indirect_t *iblock);
static herr_t H5HF_cache_iblock_clear(H5F_t *f, H5HF_indirect_t *iblock, hbool_t destroy);
+static herr_t H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock);
static herr_t H5HF_cache_iblock_size(const H5F_t *f, const H5HF_indirect_t *iblock, size_t *size_ptr);
static H5HF_direct_t *H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata);
static herr_t H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock, unsigned UNUSED * flags_ptr);
static herr_t H5HF_cache_dblock_dest(H5F_t *f, H5HF_direct_t *dblock);
static herr_t H5HF_cache_dblock_clear(H5F_t *f, H5HF_direct_t *dblock, hbool_t destroy);
+static herr_t H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock);
static herr_t H5HF_cache_dblock_size(const H5F_t *f, const H5HF_direct_t *dblock, size_t *size_ptr);
+/*********************************/
+/* Debugging Function Prototypes */
+/*********************************/
+#ifndef NDEBUG
+static herr_t H5HF_cache_verify_hdr_descendants_clean(H5F_t *f,
+ hid_t dxpl_id,
+ H5HF_hdr_t * hdr,
+ hbool_t *clean_ptr);
+static herr_t H5HF_cache_verify_iblock_descendants_clean(H5F_t *f,
+ hid_t dxpl_id,
+ H5HF_indirect_t * iblock,
+ unsigned * iblock_status_ptr,
+ hbool_t *clean_ptr);
+static herr_t H5HF_cache_verify_iblocks_dblocks_clean(H5F_t *f,
+ H5HF_indirect_t * iblock,
+ hbool_t *clean_ptr,
+ hbool_t *has_dblocks_ptr);
+static herr_t H5HF_cache_verify_descendant_iblocks_clean(H5F_t *f,
+ hid_t dxpl_id,
+ H5HF_indirect_t * iblock,
+ hbool_t *clean_ptr,
+ hbool_t *has_iblocks_ptr);
+#endif /* NDEBUG */
+
+
/*********************/
/* Package Variables */
/*********************/
@@ -118,7 +145,7 @@ const H5AC_class_t H5AC_FHEAP_IBLOCK[1] = {{
(H5AC_flush_func_t)H5HF_cache_iblock_flush,
(H5AC_dest_func_t)H5HF_cache_iblock_dest,
(H5AC_clear_func_t)H5HF_cache_iblock_clear,
- (H5AC_notify_func_t)NULL,
+ (H5AC_notify_func_t)H5HF_cache_iblock_notify,
(H5AC_size_func_t)H5HF_cache_iblock_size,
}};
@@ -129,7 +156,7 @@ const H5AC_class_t H5AC_FHEAP_DBLOCK[1] = {{
(H5AC_flush_func_t)H5HF_cache_dblock_flush,
(H5AC_dest_func_t)H5HF_cache_dblock_dest,
(H5AC_clear_func_t)H5HF_cache_dblock_clear,
- (H5AC_notify_func_t)NULL,
+ (H5AC_notify_func_t)H5HF_cache_dblock_notify,
(H5AC_size_func_t)H5HF_cache_dblock_size,
}};
@@ -471,6 +498,33 @@ H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5H
uint8_t heap_flags; /* Status flags for heap */
uint32_t metadata_chksum; /* Computed metadata checksum value */
+#ifndef NDEBUG
+ /* verify that flush dependencies are working correctly. Do this
+ * by verifying that either:
+ *
+ * 1) the header has a root iblock, and that the root iblock and all
+ * of its children are clean, or
+ *
+ * 2) The header has a root dblock, which is clean, or
+ *
+ * 3) The heap is empty, and thus the header has neither a root
+ * iblock no a root dblock. In this case, the flush ordering
+ * constraint is met by default.
+ *
+ * Do this with a call to H5HF_cache_verify_hdr_descendants_clean().
+ */
+ hbool_t descendants_clean = TRUE;
+
+ if ( H5HF_cache_verify_hdr_descendants_clean(f, dxpl_id, hdr,
+ &descendants_clean) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "can't verify hdr descendants clean.")
+
+ HDassert( descendants_clean );
+
+#endif /* NDEBUG */
+
/* Set the shared heap header's file context for this operation */
hdr->f = f;
@@ -778,6 +832,10 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)
/* Address of parent block */
iblock->parent = udata->par_info->iblock;
+ /* this copy of the parent pointer is needed by the notify callback so */
+ /* that it can take down flush dependencies on eviction even if */
+ /* the parent pointer has been nulled out. JRM -- 5/18/14 */
+ iblock->fd_parent = udata->par_info->iblock;
iblock->par_entry = udata->par_info->entry;
if(iblock->parent) {
/* Share parent block */
@@ -927,6 +985,34 @@ H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr,
uint32_t metadata_chksum; /* Computed metadata checksum value */
size_t u; /* Local index variable */
+#ifndef NDEBUG
+ /* verify that flush dependencies are working correctly. Do this
+ * by verifying that all children of this iblock are clean.
+ */
+ hbool_t descendants_clean = TRUE;
+ unsigned iblock_status;
+
+ if ( H5AC_get_entry_status(f, iblock->addr, &iblock_status) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status")
+
+ /* since the current iblock is the guest of honor in a flush, we know
+ * that it is locked into the cache for the duration of the call. Hence
+ * there is no need to check to see if it is pinned or protected, or to
+ * protect it if it is not.
+ */
+
+ if ( H5HF_cache_verify_iblock_descendants_clean(f, dxpl_id,
+ iblock, &iblock_status,
+ &descendants_clean) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "can't verify descendants clean.")
+
+ HDassert(descendants_clean);
+
+#endif /* NDEBUG */
+
/* Get the pointer to the shared heap header */
hdr = iblock->hdr;
@@ -1165,6 +1251,131 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5HF_cache_iblock_notify
+ *
+ * Purpose: Setup / takedown flush dependencies as indirect blocks
+ * are loaded / inserted and evicted from the metadata cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/17/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->hdr);
+ if ( action == H5C_NOTIFY_ACTION_BEFORE_EVICT )
+ HDassert((iblock->parent == iblock->fd_parent) ||
+ ((NULL == iblock->parent) && (iblock->fd_parent)));
+ else
+ HDassert(iblock->parent == iblock->fd_parent);
+
+ /* further sanity checks */
+ if ( iblock->parent == NULL ) {
+
+ /* Either this is the root iblock, or the parent pointer is */
+ /* invalid. Since we save a copy of the parent pointer on */
+ /* the insertion event, it doesn't matter if the parent pointer */
+ /* is invalid just before eviction. However, we will not be */
+ /* able to function if it is invalid on the insertion event. */
+ /* Scream and die if this is the case. */
+
+ HDassert((action == H5C_NOTIFY_ACTION_BEFORE_EVICT) ||
+ (iblock->block_off == 0));
+
+ /* pointer from hdr to root iblock will not be set up unless */
+ /* the fractal heap has already pinned the hdr. Do what */
+ /* sanity checking we can. */
+
+ if ( ( iblock->block_off == 0 ) &&
+ ( iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PINNED ) )
+ HDassert(iblock->hdr->root_iblock == iblock);
+
+ } else {
+ /* if this is a child iblock, verify that the pointers are */
+ /* either uninitialized or set up correctly. */
+ H5HF_indirect_t *par_iblock = iblock->parent;
+ unsigned indir_idx; /* Index in parent's child iblock pointer array */
+
+ /* Sanity check */
+ HDassert(par_iblock->child_iblocks);
+ HDassert(iblock->par_entry >= (iblock->hdr->man_dtable.max_direct_rows
+ * iblock->hdr->man_dtable.cparam.width));
+
+ /* Compute index in parent's child iblock pointer array */
+ indir_idx = iblock->par_entry -
+ (iblock->hdr->man_dtable.max_direct_rows
+ * iblock->hdr->man_dtable.cparam.width);
+
+ /* The pointer to iblock in the parent may not be set yet -- */
+ /* verify that it is either NULL, or that it has been set to */
+ /* iblock. */
+ HDassert((NULL == par_iblock->child_iblocks[indir_idx]) ||
+ (par_iblock->child_iblocks[indir_idx] == iblock));
+ }
+
+ switch ( action )
+ {
+ case H5C_NOTIFY_ACTION_AFTER_INSERT:
+ if ( iblock->parent ) /* this is a child iblock */
+ {
+ /* create flush dependency with parent iblock */
+ if(H5AC_create_flush_dependency(iblock->parent, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, \
+ "unable to create flush dependency")
+ }
+ else /* this is the root iblock */
+ {
+ /* create flush dependency with header */
+ if(H5AC_create_flush_dependency(iblock->hdr, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, \
+ "unable to create flush dependency")
+ }
+ break;
+
+ case H5C_NOTIFY_ACTION_BEFORE_EVICT:
+ if ( iblock->fd_parent ) /* this is a child iblock */
+ {
+ /* destroy flush dependency with parent iblock */
+ if(H5AC_destroy_flush_dependency(iblock->fd_parent,
+ iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, \
+ "unable to destroy flush dependency")
+ }
+ else /* this is the root iblock */
+ {
+ /* destroy flush dependency with header */
+ if(H5AC_destroy_flush_dependency(iblock->hdr, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, \
+ "unable to destroy flush dependency")
+
+ }
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \
+ "unknown action from metadata cache")
+ break;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_cache_iblock_notify() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5HF_cache_iblock_size
*
* Purpose: Compute the size in bytes of a fractal heap indirect block
@@ -1328,6 +1539,7 @@ H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)
/* Address of parent block */
dblock->parent = par_info->iblock;
+ dblock->fd_parent = par_info->iblock;
dblock->par_entry = par_info->entry;
if(dblock->parent) {
/* Share parent block */
@@ -1736,6 +1948,89 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5HF_cache_dblock_notify
+ *
+ * Purpose: Setup / takedown flush dependencies as direct blocks
+ * are loaded / inserted and evicted from the metadata cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/17/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblock->hdr);
+ HDassert((dblock->fd_parent) ||
+ ((dblock->hdr->man_dtable.curr_root_rows == 0) &&
+ (dblock->block_off == (hsize_t)0)));
+
+ switch ( action )
+ {
+ case H5C_NOTIFY_ACTION_AFTER_INSERT:
+ HDassert(dblock->parent == dblock->fd_parent);
+
+ if ( dblock->parent ) /* this is a leaf dblock */
+ {
+ /* create flush dependency with parent iblock */
+ if(H5AC_create_flush_dependency(dblock->parent, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, \
+ "unable to create flush dependency")
+ }
+ else /* this is a root dblock */
+ {
+ /* create flush dependency with header */
+ if(H5AC_create_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, \
+ "unable to create flush dependency")
+ }
+ break;
+
+ case H5C_NOTIFY_ACTION_BEFORE_EVICT:
+ HDassert((dblock->parent == dblock->fd_parent) ||
+ ((NULL == dblock->parent) && (dblock->fd_parent)));
+ if ( dblock->fd_parent ) /* this is a leaf dblock */
+ {
+ /* destroy flush dependency with parent iblock */
+ if(H5AC_destroy_flush_dependency(dblock->fd_parent,
+ dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, \
+ "unable to destroy flush dependency")
+ }
+ else /* this is a root dblock */
+ {
+ /* destroy flush dependency with header */
+ if(H5AC_destroy_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, \
+ "unable to destroy flush dependency")
+
+ }
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \
+ "unknown action from metadata cache")
+ break;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_cache_dblock_notify() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5HF_cache_dblock_size
*
* Purpose: Compute the size in bytes of a fractal heap direct block
@@ -1765,3 +2060,818 @@ H5HF_cache_dblock_size(const H5F_t UNUSED *f, const H5HF_direct_t *dblock, size_
FUNC_LEAVE_NOAPI(SUCCEED)
} /* H5HF_cache_dblock_size() */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF_cache_verify_hdr_descendants_clean
+ *
+ * Purpose: Sanity checking routine that verifies that all indirect
+ * and direct blocks that are descendants of the supplied
+ * instance of H5HF_hdr_t are clean. Set *clean_ptr to
+ * TRUE if this is the case, and to FALSE otherwise.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF_cache_verify_hdr_descendants_clean(H5F_t *f,
+ hid_t dxpl_id,
+ H5HF_hdr_t * hdr,
+ hbool_t *clean_ptr)
+{
+ hbool_t in_cache;
+ hbool_t type_ok;
+ hbool_t root_iblock_in_cache = FALSE;
+ hbool_t unprotect_root_iblock = FALSE;
+ unsigned hdr_status = 0;
+ unsigned root_iblock_status = 0;
+ unsigned root_dblock_status = 0;
+ H5HF_indirect_t * root_iblock = NULL;
+ haddr_t hdr_addr;
+ haddr_t root_iblock_addr = HADDR_UNDEF;
+ haddr_t root_dblock_addr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert((const H5AC_class_t *)(hdr->cache_info.type) == \
+ &(H5AC_FHEAP_HDR[0]));
+ HDassert(clean_ptr);
+
+ hdr_addr = hdr->cache_info.addr;
+
+ HDassert(hdr_addr == hdr->heap_addr);
+
+ if ( H5AC_get_entry_status(f, hdr_addr, &hdr_status) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get hdr status")
+
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+
+ /* We have three basic scenarios we have to deal with:
+ *
+ * The first, and most common case, is that there is a root iblock.
+ * In this case we need to verify that the root iblock and all its
+ * children are clean.
+ *
+ * The second, and much less common case, is that in which the
+ * the fractal heap contains only one direct block, which is
+ * pointed to by hdr->man_dtable.table_addr. In this case, all we
+ * need to do is verify that the root direct block is clean.
+ *
+ * Finally, it is possible that the fractal heap is empty, and
+ * has neither a root indirect block nor a root direct block.
+ * In this case, we have nothing to do.
+ */
+
+ /* There are two ways in which we can arrive at the first scenario.
+ *
+ * By far the most common is when hdr->root_iblock contains a pointer
+ * to the root iblock -- in this case the root iblock is almost certainly
+ * pinned, although we can't count on that.
+ *
+ * However, it is also possible that there is a root iblock that
+ * is no longer pointed to by the header. In this case, the on
+ * disk address of the iblock will be in hdr->man_dtable.table_addr
+ * and hdr->man_dtable.curr_root_rows will contain a positive value.
+ *
+ * Since the former case is far and away the most common, we don't
+ * worry too much about efficiency in the second case.
+ */
+
+ if ( ( hdr->root_iblock ) ||
+ ( ( hdr->man_dtable.curr_root_rows > 0 ) &&
+ ( HADDR_UNDEF != hdr->man_dtable.table_addr ) ) ) {
+
+ root_iblock = hdr->root_iblock;
+
+ /* make note of the on disk address of the root iblock */
+
+ if ( root_iblock == NULL ) {
+
+ /* hdr->man_dtable.table_addr must contain address of root
+ * iblock. Check to see if it is in cache. If it is,
+ * protect it and put its address in root_iblock.
+ */
+ root_iblock_addr = hdr->man_dtable.table_addr;
+
+ } else {
+
+ root_iblock_addr = root_iblock->addr;
+ }
+
+ /* get the status of the root iblock */
+ HDassert(root_iblock_addr != HADDR_UNDEF);
+
+ if ( H5AC_get_entry_status(f, root_iblock_addr,
+ &root_iblock_status) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, \
+ "can't get root iblock status")
+
+ root_iblock_in_cache = ( (root_iblock_status & H5AC_ES__IN_CACHE) != 0 );
+
+ HDassert(root_iblock_in_cache || (root_iblock == NULL));
+
+ if ( ! root_iblock_in_cache ) { /* we are done */
+
+ *clean_ptr = TRUE;
+
+ } else if ( root_iblock_status & H5AC_ES__IS_DIRTY ) {
+
+ *clean_ptr = FALSE;
+
+ } else { /* must examine children */
+
+ /* At this point, the root iblock may be pinned, protected,
+ * both, or neither, and we may or may not have a pointer
+ * to root iblock in memory.
+ *
+ * Before we call H5HF_cache_verify_iblock_descendants_clean(),
+ * we must ensure that the root iblock is either pinned or
+ * protected or both, and that we have a pointer to it.
+ * Do this as follows:
+ */
+ if ( root_iblock == NULL ) { /* we don't have ptr to root iblock */
+
+ if ( 0 == (root_iblock_status & H5AC_ES__IS_PROTECTED) ) {
+
+ /* just protect the root iblock -- this will give us
+ * the pointer we need to proceed, and ensure that
+ * it is locked into the metadata cache for the
+ * duration.
+ *
+ * Note that the udata is only used in the load callback.
+ * While the fractal heap makes heavy use of the udata
+ * in this case, since we know that the entry is in cache,
+ * we can pass NULL udata.
+ */
+
+ root_iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id,
+ H5AC_FHEAP_IBLOCK,
+ root_iblock_addr,
+ NULL, H5AC_READ);
+
+ if ( NULL == root_iblock )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, \
+ "H5AC_protect() faild.")
+
+ unprotect_root_iblock = TRUE;
+
+ } else {
+
+ /* the root iblock is protected, and we have no
+ * legitimate way of getting a pointer to it.
+ *
+ * We square this circle by using the
+ * H5AC_get_entry_ptr_from_addr() to get the needed
+ * pointer.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided there when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Assuming that the flush dependency code is working
+ * as it should, the only reason for the root iblock to
+ * be unpinned is if none of its children are in cache.
+ * This unfortunately means that if it is protected and
+ * not pinned, the fractal heap is in the process of loading
+ * or inserting one of its children. The obvious implication
+ * is that there is a significant chance that the root
+ * iblock is in an unstable state.
+ *
+ * All this suggests that using H5AC_get_entry_ptr_from_addr()
+ * to obtain the pointer to the protected root iblock is
+ * questionable here. However, since this is test/debugging
+ * code, I expect that we will use this approach until it
+ * causes problems, or we think of a better way.
+ */
+ if ( H5AC_get_entry_ptr_from_addr(f, root_iblock_addr,
+ (void **)(&root_iblock)) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, \
+ "H5AC_get_entry_ptr_from_addr() failed.")
+
+ HDassert(root_iblock);
+ }
+ } else /* root_iblock != NULL */ {
+
+ /* we have the pointer to the root iblock. Protect it
+ * if it is neither pinned nor protected -- otherwise we
+ * are ready to go.
+ */
+ H5HF_indirect_t * iblock = NULL;
+
+ if ( ( (root_iblock_status & H5AC_ES__IS_PINNED) == 0 ) &&
+ ( (root_iblock_status & H5AC_ES__IS_PROTECTED) == 0 ) ) {
+
+ /* the root iblock is neither pinned nor protected -- hence
+ * we must protect it before we proceed
+ *
+ * Note that the udata is only used in the load callback.
+ * While the fractal heap makes heavy use of the udata
+ * in this case, since we know that the entry is in cache,
+ * we can pass NULL udata.
+ */
+
+ iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id,
+ H5AC_FHEAP_IBLOCK,
+ root_iblock_addr,
+ NULL, H5AC_READ);
+
+ if ( NULL == iblock )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, \
+ "H5AC_protect() faild.")
+
+ unprotect_root_iblock = TRUE;
+
+ HDassert(iblock == root_iblock);
+
+ }
+ }
+
+ /* at this point, one way or another, the root iblock is locked
+ * in memory for the duration of the call. Do some sanity checks,
+ * and then call H5HF_cache_verify_iblock_descendants_clean().
+ */
+
+ HDassert(hdr->root_iblock->cache_info.magic == \
+ H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert((const H5AC_class_t *)(hdr->root_iblock->cache_info.type) \
+ == &(H5AC_FHEAP_IBLOCK[0]));
+
+ if ( H5HF_cache_verify_iblock_descendants_clean(f, dxpl_id,
+ root_iblock, &root_iblock_status,
+ clean_ptr) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "can't verify root iblock & descendants clean.")
+
+
+ /* unprotect the root indirect block if required */
+ if ( unprotect_root_iblock ) {
+
+ HDassert(root_iblock);
+
+ if ( H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_IBLOCK,
+ root_iblock_addr, root_iblock,
+ H5AC__NO_FLAGS_SET) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, \
+ "H5AC_unprotect() faild.")
+ }
+ }
+ } else if ( ( hdr->man_dtable.curr_root_rows == 0 ) &&
+ ( HADDR_UNDEF != hdr->man_dtable.table_addr ) ) {
+
+ /* this is scenario 2 -- we have a root dblock */
+
+ root_dblock_addr = hdr->man_dtable.table_addr;
+
+ if ( H5AC_get_entry_status(f, root_dblock_addr,
+ &root_dblock_status) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, \
+ "can't get root dblock status")
+
+ if ( root_dblock_status & H5AC_ES__IN_CACHE ) {
+
+ if ( H5AC_verify_entry_type(f, root_dblock_addr,
+ &H5AC_FHEAP_DBLOCK[0],
+ &in_cache, &type_ok) < 0 )
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
+ "can't check dblock type")
+
+ HDassert(in_cache);
+
+ if ( !type_ok )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "root dblock addr doesn't refer to a dblock?!?")
+
+ /* If a root dblock is in cache, it must have a flush
+ * dependency relationship with the header, and it
+ * may not be the parent in any flush dependency
+ * relationship.
+ *
+ * We don't test this fully, but we will verify that
+ * the root iblock is a child in some flush dependency
+ * relationship.
+ */
+ if ( 0 == (root_dblock_status & H5AC_ES__IS_FLUSH_DEP_CHILD) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "root dblock in cache and not a flush dep child.")
+
+ if ( 0 != (root_dblock_status & H5AC_ES__IS_FLUSH_DEP_PARENT) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "root dblock in cache and is a flush dep parent.")
+
+
+ *clean_ptr = ! (root_dblock_status & H5AC_ES__IS_DIRTY);
+
+ } else { /* root dblock not in cache */
+
+ *clean_ptr = TRUE;
+ }
+ } else {
+ /* this is scenario 3 -- the fractal heap is empty, and we
+ * have nothing to do.
+ */
+ *clean_ptr = TRUE;
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5HF_cache_verify_hdr_descendants_clean() */
+
+#endif /* NDEBUG */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF_cache_verify_iblock_descendants_clean
+ *
+ * Purpose: Sanity checking routine that verifies that all indirect
+ * and direct blocks that are decendents of the supplied
+ * instance of H5HF_indirect_t are clean. Set *clean_ptr
+ * to TRUE if this is the case, and to FALSE otherwise.
+ *
+ * In passing, the function also does a cursory check to
+ * spot any obvious errors in the flush dependency setup.
+ * If any problems are found, the function returns failure.
+ * Note that these checks are not exhaustive, thus passing
+ * them does not mean that the flush dependencies are
+ * correct -- only that there is nothing obviously wrong
+ * with them.
+ *
+ * WARNING: At its top level call, this function is
+ * intended to be called from H5HF_cache_iblock_flush(),
+ * and thus presumes that the supplied indirect block
+ * is in cache. Any other use of this function and
+ * its descendants must insure that this assumption is
+ * met.
+ *
+ * Note that this function and
+ * H5HF_cache_verify_descendant_iblocks_clean() are
+ * recursive co-routines.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF_cache_verify_iblock_descendants_clean(H5F_t *f,
+ hid_t dxpl_id,
+ H5HF_indirect_t * iblock,
+ unsigned * iblock_status_ptr,
+ hbool_t *clean_ptr)
+{
+ hbool_t has_dblocks = FALSE;
+ hbool_t has_iblocks = FALSE;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert((const H5AC_class_t *)(iblock->cache_info.type) == \
+ &(H5AC_FHEAP_IBLOCK[0]));
+ HDassert(iblock_status_ptr);
+ HDassert(clean_ptr);
+ HDassert(*clean_ptr);
+
+ if ( ( *clean_ptr ) &&
+ ( H5HF_cache_verify_iblocks_dblocks_clean(f, iblock, clean_ptr,
+ &has_dblocks) < 0 ) )
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify dblocks clean.")
+
+ if ( ( *clean_ptr ) &&
+ ( H5HF_cache_verify_descendant_iblocks_clean(f, dxpl_id, iblock,
+ clean_ptr, &has_iblocks) < 0 ) )
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify iblocks clean.")
+
+ if ( ( NULL == iblock_status_ptr ) &&
+ ( H5AC_get_entry_status(f, iblock->addr, iblock_status_ptr) < 0 ) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status")
+
+ /* verify that flush dependency setup is plausible */
+
+ if ( 0 == (*iblock_status_ptr & H5AC_ES__IS_FLUSH_DEP_CHILD) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "iblock is not a flush dep child.")
+
+ if ( ( ( has_dblocks || has_iblocks ) ) &&
+ ( 0 == (*iblock_status_ptr & H5AC_ES__IS_FLUSH_DEP_PARENT) ) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "iblock has children and is not a flush dep parent.")
+
+ if ( ( ( has_dblocks || has_iblocks ) ) &&
+ ( 0 == (*iblock_status_ptr & H5AC_ES__IS_PINNED) ) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "iblock has children and is not pinned.")
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5HF_cache_verify_iblock_descendants_clean() */
+
+#endif /* NDEBUG */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF_cache_verify_iblocks_dblocks_clean
+ *
+ * Purpose: Sanity checking routine that attempts to verify that all
+ * direct blocks pointed to by the supplied indirect block
+ * are either clean, or not in the cache.
+ *
+ * In passing, the function also does a cursory check to
+ * spot any obvious errors in the flush dependency setup.
+ * If any problems are found, the function returns failure.
+ * Note that these checks are not exhaustive, thus passing
+ * them does not mean that the flush dependencies are
+ * correct -- only that there is nothing obviously wrong
+ * with them.
+ *
+ * WARNING: This function presumes that the supplied
+ * iblock is in the cache, and will not be removed
+ * during the call. Caller must ensure that this is
+ * the case before the call.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF_cache_verify_iblocks_dblocks_clean(H5F_t *f,
+ H5HF_indirect_t * iblock,
+ hbool_t *clean_ptr,
+ hbool_t *has_dblocks_ptr)
+{
+ hbool_t in_cache;
+ hbool_t type_ok;
+ unsigned i;
+ unsigned num_direct_rows;
+ unsigned max_dblock_index;
+ haddr_t dblock_addr;
+ unsigned dblock_status = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(clean_ptr);
+ HDassert(*clean_ptr);
+ HDassert(has_dblocks_ptr);
+
+ i = 0;
+
+ num_direct_rows =
+ MIN(iblock->nrows, iblock->hdr->man_dtable.max_direct_rows);
+
+ HDassert(num_direct_rows <= iblock->nrows );
+
+ max_dblock_index =
+ (num_direct_rows * iblock->hdr->man_dtable.cparam.width) - 1;
+
+ while ( ( *clean_ptr ) && ( i <= max_dblock_index ) ) {
+
+ dblock_addr = iblock->ents[i].addr;
+
+ if ( H5F_addr_defined(dblock_addr) ) {
+
+ if ( H5AC_verify_entry_type(f, dblock_addr, &H5AC_FHEAP_DBLOCK[0],
+ &in_cache, &type_ok) < 0 )
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
+ "can't check dblock type")
+
+ if ( in_cache ) { /* dblock is in cache */
+
+ if ( ! type_ok )
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "dblock addr doesn't refer to a dblock?!?")
+
+ if ( H5AC_get_entry_status(f, dblock_addr,
+ &dblock_status) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
+ "can't get dblock status")
+
+ HDassert(dblock_status & H5AC_ES__IN_CACHE );
+
+ *has_dblocks_ptr = TRUE;
+
+ if ( dblock_status & H5AC_ES__IS_DIRTY ) {
+
+ *clean_ptr = FALSE;
+ }
+
+ /* If a child dblock is in cache, it must have a flush
+ * dependency relationship with this iblock, and it
+ * may not be the parent in any flush dependency
+ * relationship.
+ *
+ * We don't test this fully, but we will verify that
+ * the child iblock is a child in some flush dependency
+ * relationship.
+ */
+ if ( 0 == (dblock_status & H5AC_ES__IS_FLUSH_DEP_CHILD) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "dblock in cache and not a flush dep child.")
+
+ if ( 0 != (dblock_status & H5AC_ES__IS_FLUSH_DEP_PARENT) )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "dblock in cache and is a flush dep parent.")
+
+ }
+ }
+
+ i++;
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5HF_cache_verify_iblocks_dblocks_clean() */
+
+#endif /* NDEBUG */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF_cache_verify_descendant_iblocks_clean
+ *
+ * Purpose: Sanity checking routine that attempts to verify that all
+ * direct blocks pointed to by the supplied indirect block
+ * are either clean, or not in the cache.
+ *
+ * In passing, the function also does a cursory check to
+ * spot any obvious errors in the flush dependency setup.
+ * If any problems are found, the function returns failure.
+ * Note that these checks are not exhaustive, thus passing
+ * them does not mean that the flush dependencies are
+ * correct -- only that there is nothing obviously wrong
+ * with them.
+ *
+ * WARNING: This function presumes that the supplied
+ * iblock is in the cache, and will not be removed
+ * during the call. Caller must ensure that this is
+ * the case before the call.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF_cache_verify_descendant_iblocks_clean(H5F_t *f,
+ hid_t dxpl_id,
+ H5HF_indirect_t * iblock,
+ hbool_t *clean_ptr,
+ hbool_t *has_iblocks_ptr)
+{
+ hbool_t unprotect_child_iblock;
+ unsigned i;
+ unsigned first_iblock_index;
+ unsigned last_iblock_index;
+ unsigned num_direct_rows;
+ unsigned child_iblock_status = 0;
+ haddr_t child_iblock_addr;
+ H5HF_indirect_t * child_iblock_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == &(H5AC_FHEAP_IBLOCK[0]));
+ HDassert(clean_ptr);
+ HDassert(*clean_ptr);
+ HDassert(has_iblocks_ptr);
+
+ num_direct_rows =
+ MIN(iblock->nrows, iblock->hdr->man_dtable.max_direct_rows);
+
+ HDassert(num_direct_rows <= iblock->nrows );
+
+ first_iblock_index = num_direct_rows * iblock->hdr->man_dtable.cparam.width;
+ last_iblock_index =
+ (iblock->nrows * iblock->hdr->man_dtable.cparam.width) - 1;
+
+ i = first_iblock_index;
+
+ while ( ( *clean_ptr ) && ( i <= last_iblock_index ) ) {
+
+ child_iblock_addr = iblock->ents[i].addr;
+
+ if ( H5F_addr_defined(child_iblock_addr) ) {
+
+ if ( H5AC_get_entry_status(f, child_iblock_addr,
+ &child_iblock_status) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, \
+ "can't get iblock status")
+
+ if ( child_iblock_status & H5AC_ES__IN_CACHE ) {
+
+ *has_iblocks_ptr = TRUE;
+
+ if ( child_iblock_status & H5AC_ES__IS_DIRTY ) {
+
+ *clean_ptr = FALSE;
+ }
+
+ /* if the child iblock is in cache and *clean_ptr is TRUE,
+ * we must continue to explore down the fractal heap tree
+ * structure to verify that all descendant blocks are either
+ * clean, or not in the metadata cache. We do this with a
+ * recursive call to
+ * H5HF_cache_verify_iblock_descendants_clean().
+ * However, we can't make this call unless the child iblock
+ * is somehow locked into the cache -- typically via either
+ * pinning or protecting.
+ *
+ * If the child iblock is pinned, we can look up its pointer
+ * on the current iblock's pinned child iblock list, and
+ * and use that pointer in the recursive call.
+ *
+ * If the entry is unprotected and unpinned, we simply
+ * protect it.
+ *
+ * If, however, the the child iblock is already protected,
+ * but not pinned, we have a bit of a problem, as we have
+ * no legitimate way of looking up its pointer in memory.
+ *
+ * To solve this problem, I have added a new metadata cache
+ * call to obtain the pointer.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided there when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Assuming that the flush dependency code is working
+ * as it should, the only reason for the child entry to
+ * be unpinned is if none of its children are in cache.
+ * This unfortunately means that if it is protected and
+ * not pinned, the fractal heap is in the process of loading
+ * or inserting one of its children. The obvious implication
+ * is that there is a significant chance that the child
+ * iblock is in an unstable state.
+ *
+ * All this suggests that using the new call to obtain the
+ * pointer to the protected child iblock is questionable
+ * here. However, since this is test/debugging code, I
+ * expect that we will use this approach until it causes
+ * problems, or we think of a better way.
+ */
+ if ( *clean_ptr ) {
+
+ child_iblock_ptr = NULL;
+ unprotect_child_iblock = FALSE;
+
+ if ( 0 == (child_iblock_status & H5AC_ES__IS_PINNED)) {
+
+ /* child iblock is not pinned */
+
+ if (0 == (child_iblock_status & H5AC_ES__IS_PROTECTED)){
+
+ /* child iblock is unprotected, and unpinned */
+ /* protect it. Note that the udata is only */
+ /* used in the load callback. While the */
+ /* fractal heap makes heavy use of the udata */
+ /* in this case, since we know that the */
+ /* entry is in cache, we can pass NULL udata */
+ child_iblock_ptr = (H5HF_indirect_t *)
+ H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK,
+ child_iblock_addr,
+ NULL, H5AC_READ);
+
+ if ( NULL == child_iblock_ptr )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, \
+ "H5AC_protect() faild.")
+
+ unprotect_child_iblock = TRUE;
+
+ } else {
+
+ /* child iblock is protected -- use */
+ /* H5AC_get_entry_ptr_from_addr() to get a */
+ /* pointer to the entry. This is very slimy -- */
+ /* come up with a better solution. */
+ if ( H5AC_get_entry_ptr_from_addr(f,
+ child_iblock_addr,
+ (void **)(&child_iblock_ptr)) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, \
+ "H5AC_get_entry_ptr_from_addr() faild.")
+
+ HDassert ( child_iblock_ptr );
+ }
+ } else {
+ /* child iblock is pinned -- look it up in the */
+ /* parent iblocks child_iblocks array. */
+
+ HDassert(iblock->child_iblocks);
+
+ child_iblock_ptr =
+ iblock->child_iblocks[i - first_iblock_index];
+ }
+
+ /* At this point, one way or another we should have
+ * a pointer to the child iblock. Verify that we
+ * that we have the correct one.
+ */
+ HDassert(child_iblock_ptr);
+ HDassert(child_iblock_ptr->cache_info.magic ==
+ H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(child_iblock_ptr->cache_info.type ==
+ H5AC_FHEAP_IBLOCK);
+ HDassert(child_iblock_ptr->addr == child_iblock_addr);
+
+ /* now make the recursive call */
+ if ( H5HF_cache_verify_iblock_descendants_clean(f, dxpl_id,
+ child_iblock_ptr, &child_iblock_status,
+ clean_ptr) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, \
+ "can't verify child iblock clean.")
+
+ /* if we protected the child iblock, unprotect it now */
+ if ( unprotect_child_iblock ) {
+
+ if ( H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_IBLOCK,
+ child_iblock_addr, child_iblock_ptr,
+ H5AC__NO_FLAGS_SET) < 0 )
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, \
+ "H5AC_unprotect() faild.")
+
+ }
+ }
+ }
+ }
+
+ i++;
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5HF_cache_verify_descendant_iblocks_clean() */
+
+#endif /* NDEBUG */
+
diff --git a/src/H5HFdblock.c b/src/H5HFdblock.c
index dd36613..c4ae573 100644
--- a/src/H5HFdblock.c
+++ b/src/H5HFdblock.c
@@ -161,6 +161,7 @@ HDmemset(dblock->blk, 0, dblock->size);
/* Attach to parent indirect block, if there is one */
dblock->parent = par_iblock;
+ dblock->fd_parent = par_iblock;
if(dblock->parent)
if(H5HF_man_iblock_attach(dblock->parent, par_entry, dblock_addr) < 0)
HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach direct block to parent indirect block")
diff --git a/src/H5HFiblock.c b/src/H5HFiblock.c
index c989bfc..4473803 100644
--- a/src/H5HFiblock.c
+++ b/src/H5HFiblock.c
@@ -438,7 +438,20 @@ H5HF_man_iblock_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_si
/* Attach direct block to new root indirect block */
dblock->parent = iblock;
+ dblock->fd_parent = iblock;
dblock->par_entry = 0;
+
+ /* destroy flush dependency between direct block and header */
+ if(H5AC_destroy_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, \
+ "unable to destroy flush dependency")
+
+ /* create flush dependency between direct block and new root indirect block */
+ if(H5AC_create_flush_dependency(dblock->parent, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, \
+ "unable to create flush dependency")
+
+
if(H5HF_man_iblock_attach(iblock, 0, hdr->man_dtable.table_addr) < 0)
HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach root direct block to parent indirect block")
@@ -884,6 +897,19 @@ H5HF_man_iblock_root_revert(H5HF_indirect_t *root_iblock, hid_t dxpl_id)
dblock->parent = NULL;
dblock->par_entry = 0;
+ /* destroy flush dependency between old root iblock and new root direct block*/
+ if(H5AC_destroy_flush_dependency(dblock->fd_parent, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, \
+ "unable to destroy flush dependency")
+
+
+ /* create flush dependency between header and new root direct block */
+ if(H5AC_create_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, \
+ "unable to create flush dependency")
+
+ dblock->fd_parent = NULL;
+
/* Point root at direct block */
hdr->man_dtable.curr_root_rows = 0;
hdr->man_dtable.table_addr = dblock_addr;
@@ -1078,6 +1104,12 @@ H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *par_iblo
/* Attach to parent indirect block, if there is one */
iblock->parent = par_iblock;
+ iblock->fd_parent = par_iblock; /* this copy of the parent pointer is */
+ /* needed by the notify callback so */
+ /* that it can take down flush */
+ /* dependencies on eviction even if */
+ /* the parent pointer has been nulled */
+ /* out. JRM -- 5/18/14 */
iblock->par_entry = par_entry;
if(iblock->parent) {
/* Attach new block to parent */
diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h
index a17088b..63c1a3e 100644
--- a/src/H5HFpkg.h
+++ b/src/H5HFpkg.h
@@ -384,6 +384,13 @@ struct H5HF_indirect_t {
size_t rc; /* Reference count of objects using this block */
H5HF_hdr_t *hdr; /* Shared heap header info */
struct H5HF_indirect_t *parent; /* Shared parent indirect block info */
+ struct H5HF_indirect_t
+ *fd_parent; /* Saved copy of the parent pointer -- this */
+ /* necessary as the parent field is sometimes */
+ /* nulled out before the eviction notify call */
+ /* is made from the metadata cache. Since */
+ /* this call cancels flush dependencies, it */
+ /* needs this information. */
unsigned par_entry; /* Entry in parent's table */
haddr_t addr; /* Address of this indirect block on disk */
size_t size; /* Size of indirect block on disk */
@@ -407,6 +414,12 @@ typedef struct H5HF_direct_t {
/* Internal heap information */
H5HF_hdr_t *hdr; /* Shared heap header info */
H5HF_indirect_t *parent; /* Shared parent indirect block info */
+ H5HF_indirect_t *fd_parent; /* Saved copy of the parent pointer -- this */
+ /* necessary as the parent field is sometimes */
+ /* nulled out before the eviction notify call */
+ /* is made from the metadata cache. Since */
+ /* this call cancels flush dependencies, it */
+ /* needs this information. */
unsigned par_entry; /* Entry in parent's table */
size_t size; /* Size of direct block */
hsize_t file_size; /* Size of direct block in file (only valid when block's space is being freed) */