summaryrefslogtreecommitdiffstats
path: root/src/H5HFcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5HFcache.c')
-rw-r--r--src/H5HFcache.c684
1 files changed, 64 insertions, 620 deletions
diff --git a/src/H5HFcache.c b/src/H5HFcache.c
index ffdac9a..302fe04 100644
--- a/src/H5HFcache.c
+++ b/src/H5HFcache.c
@@ -116,17 +116,14 @@ static herr_t H5HF__cache_dblock_free_icr(void *thing);
/* 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 *fd_clean, hbool_t *clean);
-static herr_t H5HF__cache_verify_iblock_descendants_clean(H5F_t *f,
- hid_t dxpl_id, haddr_t fd_parent_addr, H5HF_indirect_t *iblock,
- unsigned *iblock_status, hbool_t *fd_clean, hbool_t *clean);
-static herr_t H5HF__cache_verify_iblocks_dblocks_clean(H5F_t *f,
- haddr_t fd_parent_addr, H5HF_indirect_t *iblock, hbool_t *fd_clean,
- hbool_t *clean, hbool_t *has_dblocks);
-static herr_t H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f,
- hid_t dxpl_id, haddr_t fd_parent_addr, H5HF_indirect_t *iblock,
- hbool_t *fd_clean, hbool_t *clean, hbool_t *has_iblocks);
+static herr_t H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, H5HF_hdr_t *hdr,
+ hbool_t *clean);
+static herr_t H5HF__cache_verify_iblock_descendants_clean(H5F_t *f,
+ H5HF_indirect_t *iblock, unsigned *iblock_status, hbool_t *clean);
+static herr_t H5HF__cache_verify_iblocks_dblocks_clean(H5F_t *f,
+ H5HF_indirect_t *iblock, hbool_t *clean, hbool_t *has_dblocks);
+static herr_t H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f,
+ H5HF_indirect_t *iblock, hbool_t *clean, hbool_t *has_iblocks);
#endif /* NDEBUG */
@@ -690,7 +687,6 @@ H5HF__cache_hdr_pre_serialize(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id,
#ifndef NDEBUG
{
hbool_t descendants_clean = TRUE;
- hbool_t fd_children_clean = TRUE;
/* Verify that flush dependencies are working correctly. Do this
* by verifying that either:
@@ -705,22 +701,10 @@ H5HF__cache_hdr_pre_serialize(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id,
* constraint is met by default.
*
* Do this with a call to H5HF__cache_verify_hdr_descendants_clean().
- *
- * Note that decendants need not be clean if the pre_serialize call
- * is made during a cache serialization instead of an entry or cache
- * flush.
- *
- * Note also that with the recent change in the definition of flush
- * dependency, not all decendants need be clean -- only direct flush
- * dependency children.
- *
- * Finally, observe that the H5HF__cache_verify_hdr_descendants_clean()
- * call still looks for dirty descendants. At present we do not check
- * this value.
*/
- if(H5HF__cache_verify_hdr_descendants_clean((H5F_t *)f, dxpl_id, hdr, &fd_children_clean, &descendants_clean) < 0)
+ if(H5HF__cache_verify_hdr_descendants_clean((H5F_t *)f, hdr, &descendants_clean) < 0)
HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify hdr descendants clean.")
- HDassert(fd_children_clean);
+ HDassert(descendants_clean);
}
#endif /* NDEBUG */
@@ -1192,9 +1176,8 @@ H5HF__cache_iblock_image_len(const void *_thing, size_t *image_len)
* and if so, to move it to real file space before the entry is
* serialized.
*
- * In debug compiles, this function also verifies that all
- * immediate flush dependency children of this indirect block
- * are either clean or are not in cache.
+ * In debug compiles, this function also verifies that all children
+ * of this indirect block are either clean or are not in cache.
*
* Return: Success: SUCCEED
* Failure: FAIL
@@ -1234,12 +1217,10 @@ H5HF__cache_iblock_pre_serialize(H5F_t *f, hid_t dxpl_id, void *_thing,
#ifndef NDEBUG
{
hbool_t descendants_clean = TRUE;
- hbool_t fd_children_clean = TRUE;
unsigned iblock_status = 0;
/* verify that flush dependencies are working correctly. Do this
- * by verifying that all immediate flush dependency children of this
- * iblock are clean.
+ * by verifying that all children of this iblock are clean.
*/
if(H5AC_get_entry_status(f, iblock->addr, &iblock_status) < 0)
HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status")
@@ -1249,9 +1230,9 @@ H5HF__cache_iblock_pre_serialize(H5F_t *f, hid_t dxpl_id, void *_thing,
* 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((H5F_t *)f, dxpl_id, iblock->addr, iblock, &iblock_status, &fd_children_clean, &descendants_clean) < 0)
+ if(H5HF__cache_verify_iblock_descendants_clean((H5F_t *)f, iblock, &iblock_status, &descendants_clean) < 0)
HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify descendants clean.")
- HDassert(fd_children_clean);
+ HDassert(descendants_clean);
}
#endif /* NDEBUG */
@@ -2604,54 +2585,6 @@ done:
* instance of H5HF_hdr_t are clean. Set *clean to
* TRUE if this is the case, and to FALSE otherwise.
*
- * Update -- 8/24/15
- *
- * With the advent of the metadata cache image feature, it is
- * possible for the pre-serialize and serialize calls to be
- * invoked outside of a flush. While this serialization
- * observes flush dependencies for the order of serialization,
- * the entries are not written to disk, and hence dirty entries
- * remain dirty.
- *
- * To address this, updated the sanity checks in this function
- * to treat entries whose images are up to date as clean if
- * a cache serialization is in progress.
- *
- * Update -- 9/29/16
- *
- * The implementation of flush dependencies has been changed.
- * Prior to this change, a flush dependency parent could be
- * flushed if and only if all its flush dependency decendants
- * were clean. In the new definition, a flush dependency
- * parent can be flushed if all its immediate flush dependency
- * children are clean, regardless of any other dirty
- * decendants.
- *
- * Further, metadata cache entries are now allowed to have
- * multiple flush dependency parents.
- *
- * This means that the fractal heap is no longer ncessarily
- * flushed from the bottom up.
- *
- * For example, it is now possible for a dirty fractal heap
- * header to be flushed before a dirty dblock, as long as the
- * there in an interviening iblock, and the header has no
- * dirty immediate flush dependency children.
- *
- * Also, I gather that under some circumstances, a dblock
- * will be direct a flush dependency child both of the iblock
- * that points to it, and of the fractal heap header.
- *
- * As a result of these changes, the functionality of these
- * sanity checking routines has been modified significantly.
- * Instead of scanning the fractal heap from a starting point
- * down, and verifying that there were no dirty entries, the
- * functions now scan downward from the starting point and
- * verify that there are no dirty flush dependency children
- * of the specified flush dependency parent. In passing,
- * they also walk the data structure, and verify it.
- *
- *
* Return: Non-negative on success/Negative on failure
*
* Programmer: John Mainzer
@@ -2661,10 +2594,9 @@ done:
*/
#ifndef NDEBUG
static herr_t
-H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id,
- H5HF_hdr_t *hdr, hbool_t *fd_clean, hbool_t *clean)
+H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, H5HF_hdr_t *hdr,
+ hbool_t *clean)
{
- hbool_t fd_exists = FALSE; /* whether flush dependency exists. */
haddr_t hdr_addr; /* Address of header */
unsigned hdr_status = 0; /* Header cache entry status */
herr_t ret_value = SUCCEED; /* Return value */
@@ -2676,7 +2608,6 @@ H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id,
HDassert(hdr);
HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
- HDassert(fd_clean);
HDassert(clean);
hdr_addr = hdr->cache_info.addr;
HDassert(hdr_addr == hdr->heap_addr);
@@ -2741,165 +2672,15 @@ H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id,
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 = TRUE;
- *fd_clean = TRUE;
- } /* end if */
- else if((root_iblock_status & H5AC_ES__IS_DIRTY) &&
- (((root_iblock_status & H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
- (!H5AC_get_serialization_in_progress(f)))) {
- *clean = FALSE;
-
- /* verify that a flush dependency exists between the header and
- * the root inode.
- */
- if(H5AC_flush_dependency_exists(f, hdr->heap_addr, root_iblock_addr, &fd_exists) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
- HDassert(fd_exists);
-
- *fd_clean = FALSE;
- } /* end else-if */
- else { /* must examine children */
- hbool_t unprotect_root_iblock = FALSE;
-
- /* 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.
- *
- * The tag specified in the dxpl we received
- * as a parameter (via dxpl_id) may not be correct.
- * Grab the (hopefully) correct tag from the header,
- * and load it into the dxpl via the H5_BEGIN_TAG and
- * H5_END_TAG macros. Note that any error bracked by
- * these macros must be reported with HGOTO_ERROR_TAG.
- */
- H5_BEGIN_TAG(dxpl_id, hdr->heap_addr, FAIL)
-
- if(NULL == (root_iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC__READ_ONLY_FLAG)))
- HGOTO_ERROR_TAG(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.")
-
- H5_END_TAG(FAIL)
-
- unprotect_root_iblock = TRUE;
- } /* end if */
- 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);
- } /* end else */
- } /* end if */
- 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.
- *
- * The tag associated specified in the dxpl we received
- * as a parameter (via dxpl_id) may not be correct.
- * Grab the (hopefully) correct tag from the header,
- * and load it into the dxpl via the H5_BEGIN_TAG and
- * H5_END_TAG macros. Note that any error bracked by
- * these macros must be reported with HGOTO_ERROR_TAG.
- */
- H5_BEGIN_TAG(dxpl_id, hdr->heap_addr, FAIL)
-
- if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC__READ_ONLY_FLAG)))
- HGOTO_ERROR_TAG(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.")
-
- H5_END_TAG(FAIL)
-
- unprotect_root_iblock = TRUE;
- HDassert(iblock == root_iblock);
- } /* end if */
- } /* end else */
-
- /* 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(root_iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
- HDassert(root_iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
-
- if(H5HF__cache_verify_iblock_descendants_clean(f, dxpl_id, hdr->heap_addr, root_iblock, &root_iblock_status, fd_clean, clean) < 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.")
- } /* end if */
- } /* end else */
+ if(!root_iblock_in_cache) /* we are done */
+ *clean = TRUE;
+ else if(root_iblock_status & H5AC_ES__IS_DIRTY)
+ *clean = FALSE;
} /* end if */
else if((hdr->man_dtable.curr_root_rows == 0) &&
(HADDR_UNDEF != hdr->man_dtable.table_addr)) {
haddr_t root_dblock_addr;
unsigned root_dblock_status = 0;
- hbool_t in_cache;
- hbool_t type_ok;
/* this is scenario 2 -- we have a root dblock */
root_dblock_addr = hdr->man_dtable.table_addr;
@@ -2907,48 +2688,25 @@ H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id,
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 a flush dependency
- * relationship with the header.
+ * dependency relationship with the header.
*/
- if(H5AC_flush_dependency_exists(f, hdr->heap_addr, root_dblock_addr, &fd_exists) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
- if(!fd_exists)
- HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "root dblock is not a flush dep parent of header.")
-
+ 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 = !((root_dblock_status & H5AC_ES__IS_DIRTY) &&
- (((root_dblock_status &
- H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
- (!H5AC_get_serialization_in_progress(f))));
-
- *fd_clean = *clean;
- } /* end if */
- else { /* root dblock not in cache */
- *fd_clean = TRUE;
- *clean = TRUE;
- } /* end else */
+ if(root_dblock_status & H5AC_ES__IS_DIRTY)
+ *clean = FALSE;
+ } /* end if */
+ else /* root dblock not in cache */
+ *clean = TRUE;
} /* end else-if */
- else {
- /* this is scenario 3 -- the fractal heap is empty, and we
- * have nothing to do.
- */
- *fd_clean = TRUE;
- *clean = TRUE;
- } /* end else */
+ else
+ /* this is scenario 3 -- the fractal heap is empty, and we
+ * have nothing to do.
+ */
+ *clean = TRUE;
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -2983,40 +2741,6 @@ done:
* H5HF__cache_verify_descendant_iblocks_clean() are
* recursive co-routines.
*
- * Update -- 9/29/16
- *
- * The implementation of flush dependencies has been changed.
- * Prior to this change, a flush dependency parent could be
- * flushed if and only if all its flush dependency decendants
- * were clean. In the new definition, a flush dependency
- * parent can be flushed if all its immediate flush dependency
- * children are clean, regardless of any other dirty
- * decendants.
- *
- * Further, metadata cache entries are now allowed to have
- * multiple flush dependency parents.
- *
- * This means that the fractal heap is no longer ncessarily
- * flushed from the bottom up.
- *
- * For example, it is now possible for a dirty fractal heap
- * header to be flushed before a dirty dblock, as long as the
- * there in an interviening iblock, and the header has no
- * dirty immediate flush dependency children.
- *
- * Also, I gather that under some circumstances, a dblock
- * will be direct a flush dependency child both of the iblock
- * that points to it, and of the fractal heap header.
- *
- * As a result of these changes, the functionality of these
- * sanity checking routines has been modified significantly.
- * Instead of scanning the fractal heap from a starting point
- * down, and verifying that there were no dirty entries, the
- * functions now scan downward from the starting point and
- * verify that there are no dirty flush dependency children
- * of the specified flush dependency parent. In passing,
- * they also walk the data structure, and verify it.
- *
* Return: Non-negative on success/Negative on failure
*
* Programmer: John Mainzer
@@ -3026,9 +2750,8 @@ done:
*/
#ifndef NDEBUG
static herr_t
-H5HF__cache_verify_iblock_descendants_clean(H5F_t *f, hid_t dxpl_id,
- haddr_t fd_parent_addr, H5HF_indirect_t *iblock, unsigned *iblock_status,
- hbool_t * fd_clean, hbool_t *clean)
+H5HF__cache_verify_iblock_descendants_clean(H5F_t *f, H5HF_indirect_t *iblock,
+ unsigned *iblock_status, hbool_t *clean)
{
hbool_t has_dblocks = FALSE;
hbool_t has_iblocks = FALSE;
@@ -3038,19 +2761,17 @@ H5HF__cache_verify_iblock_descendants_clean(H5F_t *f, hid_t dxpl_id,
/* Sanity checks */
HDassert(f);
- HDassert(H5F_addr_defined(fd_parent_addr));
HDassert(iblock);
HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
HDassert(iblock_status);
- HDassert(fd_clean);
- HDassert(*fd_clean);
- HDassert(clean); /* note that *clean need not be TRUE */
+ HDassert(clean);
+ HDassert(*clean);
- if((*fd_clean) && H5HF__cache_verify_iblocks_dblocks_clean(f, fd_parent_addr, iblock, fd_clean, clean, &has_dblocks) < 0)
+ if((*clean) && H5HF__cache_verify_iblocks_dblocks_clean(f, iblock, clean, &has_dblocks) < 0)
HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify dblocks clean.")
- if((*fd_clean) && H5HF__cache_verify_descendant_iblocks_clean(f, dxpl_id, fd_parent_addr, iblock, fd_clean, clean, &has_iblocks) < 0)
+ if((*clean) && H5HF__cache_verify_descendant_iblocks_clean(f, iblock, clean, &has_iblocks) < 0)
HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify iblocks clean.")
/* verify that flush dependency setup is plausible */
@@ -3087,53 +2808,6 @@ done:
* during the call. Caller must ensure that this is
* the case before the call.
*
- * Update -- 8/24/15
- *
- * With the advent of the metadata cache image feature, it is
- * possible for the pre-serialize and serialize calls to be
- * invoked outside of a flush. While this serialization
- * observes flush dependencies for the order of serialization,
- * the entries are not written to disk, and hence dirty entries
- * remain dirty.
- *
- * To address this, updated the sanity checks in this function
- * to treat entries whose images are up to date as clean if
- * a cache serialization is in progress.
- *
- * Update -- 9/29/16
- *
- * The implementation of flush dependencies has been changed.
- * Prior to this change, a flush dependency parent could be
- * flushed if and only if all its flush dependency decendants
- * were clean. In the new definition, a flush dependency
- * parent can be flushed if all its immediate flush dependency
- * children are clean, regardless of any other dirty
- * decendants.
- *
- * Further, metadata cache entries are now allowed to have
- * multiple flush dependency parents.
- *
- * This means that the fractal heap is no longer ncessarily
- * flushed from the bottom up.
- *
- * For example, it is now possible for a dirty fractal heap
- * header to be flushed before a dirty dblock, as long as the
- * there in an interviening iblock, and the header has no
- * dirty immediate flush dependency children.
- *
- * Also, I gather that under some circumstances, a dblock
- * will be direct a flush dependency child both of the iblock
- * that points to it, and of the fractal heap header.
- *
- * As a result of these changes, the functionality of these
- * sanity checking routines has been modified significantly.
- * Instead of scanning the fractal heap from a starting point
- * down, and verifying that there were no dirty entries, the
- * functions now scan downward from the starting point and
- * verify that there are no dirty flush dependency children
- * of the specified flush dependency parent. In passing,
- * they also walk the data structure, and verify it.
- *
* Return: Non-negative on success/Negative on failure
*
* Programmer: John Mainzer
@@ -3143,82 +2817,53 @@ done:
*/
#ifndef NDEBUG
static herr_t
-H5HF__cache_verify_iblocks_dblocks_clean(H5F_t *f, haddr_t fd_parent_addr,
- H5HF_indirect_t *iblock, hbool_t *fd_clean, hbool_t *clean,
- hbool_t *has_dblocks)
+H5HF__cache_verify_iblocks_dblocks_clean(H5F_t *f, H5HF_indirect_t *iblock,
+ hbool_t *clean, hbool_t *has_dblocks)
{
unsigned num_direct_rows;
unsigned max_dblock_index;
unsigned i;
- haddr_t iblock_addr;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
/* Sanity checks */
HDassert(f);
- HDassert(H5F_addr_defined(fd_parent_addr));
HDassert(iblock);
HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
- HDassert(fd_clean);
- HDassert(*fd_clean);
- HDassert(clean); /* note that *clean need not be true */
+ HDassert(clean);
+ HDassert(*clean);
HDassert(has_dblocks);
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;
- iblock_addr = iblock->addr;
- HDassert(H5F_addr_defined(iblock_addr));
-
- while((*fd_clean) && (i <= max_dblock_index)) {
+ while((*clean) && (i <= max_dblock_index)) {
haddr_t dblock_addr;
dblock_addr = iblock->ents[i].addr;
if(H5F_addr_defined(dblock_addr)) {
- hbool_t in_cache;
- hbool_t type_ok;
-
- 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 */
- hbool_t fd_exists;
- unsigned dblock_status = 0;
-
- 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);
+ unsigned dblock_status = 0;
+ if(H5AC_get_entry_status(f, dblock_addr, &dblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get dblock status")
+ if(dblock_status & H5AC_ES__IN_CACHE) {
*has_dblocks = TRUE;
- if((dblock_status & H5AC_ES__IS_DIRTY) &&
- (((dblock_status & H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
- (!H5AC_get_serialization_in_progress(f)))) {
+ if(dblock_status & H5AC_ES__IS_DIRTY)
*clean = FALSE;
-
- if(H5AC_flush_dependency_exists(f, fd_parent_addr, dblock_addr, &fd_exists) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
-
- if(fd_exists)
- *fd_clean = FALSE;
- } /* end if */
- /* If a child dblock is in cache, it must have a flush
- * dependency relationship with this iblock. Test this
- * here.
+ /* 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.
*/
- if(H5AC_flush_dependency_exists(f, iblock_addr, dblock_addr, &fd_exists) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
-
- if(!fd_exists)
- HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "dblock in cache and not a flush dep child of iblock.")
+ 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.")
} /* end if */
} /* end if */
@@ -3251,54 +2896,6 @@ done:
* during the call. Caller must ensure that this is
* the case before the call.
*
- * Update -- 8/24/15
- *
- * With the advent of the metadata cache image feature, it is
- * possible for the pre-serialize and serialize calls to be
- * invoked outside of a flush. While this serialization
- * observes flush dependencies for the order of serialization,
- * the entries are not written to disk, and hence dirty entries
- * remain dirty.
- *
- * To address this, updated the sanity checks in this function
- * to treat entries whose images are up to date as clean if
- * a cache serialization is in progress.
- *
- * Update -- 9/29/16
- *
- * The implementation of flush dependencies has been changed.
- * Prior to this change, a flush dependency parent could be
- * flushed if and only if all its flush dependency decendants
- * were clean. In the new definition, a flush dependency
- * parent can be flushed if all its immediate flush dependency
- * children are clean, regardless of any other dirty
- * decendants.
- *
- * Further, metadata cache entries are now allowed to have
- * multiple flush dependency parents.
- *
- * This means that the fractal heap is no longer ncessarily
- * flushed from the bottom up.
- *
- * For example, it is now possible for a dirty fractal heap
- * header to be flushed before a dirty dblock, as long as the
- * there in an interviening iblock, and the header has no
- * dirty immediate flush dependency children.
- *
- * Also, I gather that under some circumstances, a dblock
- * will be direct a flush dependency child both of the iblock
- * that points to it, and of the fractal heap header.
- *
- * As a result of these changes, the functionality of these
- * sanity checking routines has been modified significantly.
- * Instead of scanning the fractal heap from a starting point
- * down, and verifying that there were no dirty entries, the
- * functions now scan downward from the starting point and
- * verify that there are no dirty flush dependency children
- * of the specified flush dependency parent. In passing,
- * they also walk the data structure, and verify it.
- *
- *
* Return: Non-negative on success/Negative on failure
*
* Programmer: John Mainzer
@@ -3308,38 +2905,33 @@ done:
*/
#ifndef NDEBUG
static herr_t
-H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, hid_t dxpl_id,
- haddr_t fd_parent_addr, H5HF_indirect_t *iblock, hbool_t *fd_clean,
+H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, H5HF_indirect_t *iblock,
hbool_t *clean, hbool_t *has_iblocks)
{
unsigned first_iblock_index;
unsigned last_iblock_index;
unsigned num_direct_rows;
unsigned i;
- haddr_t iblock_addr;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
/* Sanity checks */
HDassert(f);
- HDassert(H5F_addr_defined(fd_parent_addr));
HDassert(iblock);
HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
- HDassert(fd_clean);
- HDassert(*fd_clean);
- HDassert(clean); /* note that *clean need not be true */
+ HDassert(clean);
+ HDassert(*clean);
HDassert(has_iblocks);
num_direct_rows = MIN(iblock->nrows, iblock->hdr->man_dtable.max_direct_rows);
HDassert(num_direct_rows <= iblock->nrows);
- iblock_addr = iblock->addr;
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((*fd_clean) && (i <= last_iblock_index)) {
+ while((*clean) && (i <= last_iblock_index)) {
haddr_t child_iblock_addr = iblock->ents[i].addr;
if(H5F_addr_defined(child_iblock_addr)) {
@@ -3349,157 +2941,9 @@ H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, hid_t dxpl_id,
HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status")
if(child_iblock_status & H5AC_ES__IN_CACHE) {
- hbool_t fd_exists;
-
*has_iblocks = TRUE;
-
- if((child_iblock_status & H5AC_ES__IS_DIRTY) &&
- (((child_iblock_status & H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
- (!H5AC_get_serialization_in_progress(f)))) {
-
- *clean = FALSE;
-
- if(H5AC_flush_dependency_exists(f, fd_parent_addr, child_iblock_addr, &fd_exists) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
-
- if(fd_exists)
- *fd_clean = FALSE;
- } /* end if */
-
- /* if the child iblock is in cache and *fd_clean is TRUE,
- * we must continue to explore down the fractal heap tree
- * structure to verify that all descendant blocks that are
- * flush dependency children of the entry at parent_addr 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(*fd_clean) {
- H5HF_indirect_t *child_iblock = NULL;
- hbool_t 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 */
- /* */
- /* The tag associated specified in the dxpl */
- /* we received as a parameter (via dxpl_id) */
- /* may not be correct. */
- /* */
- /* Grab the (hopefully) correct tag from the */
- /* parent iblock, and load it into the dxpl */
- /* via the H5_BEGIN_TAG and H5_END_TAG */
- /* macros. Note that any error bracked by */
- /* these macros must be reported with */
- /* HGOTO_ERROR_TAG. */
-
- H5_BEGIN_TAG(dxpl_id, iblock->hdr->heap_addr, FAIL)
-
- if(NULL == (child_iblock = (H5HF_indirect_t *) H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, NULL, H5AC__READ_ONLY_FLAG)))
- HGOTO_ERROR_TAG(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.")
-
- H5_END_TAG(FAIL)
-
- unprotect_child_iblock = TRUE;
- } /* end if */
- 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)) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "H5AC_get_entry_ptr_from_addr() faild.")
- HDassert(child_iblock);
- } /* end else */
- } /* end if */
- else {
- /* child iblock is pinned -- look it up in the */
- /* parent iblocks child_iblocks array. */
- HDassert(iblock->child_iblocks);
- child_iblock = iblock->child_iblocks[i - first_iblock_index];
- } /* end else */
-
- /* 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);
- HDassert(child_iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
- HDassert(child_iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
- HDassert(child_iblock->addr == child_iblock_addr);
-
- /* now make the recursive call */
- if(H5HF__cache_verify_iblock_descendants_clean(f, dxpl_id, fd_parent_addr, child_iblock, &child_iblock_status, fd_clean, clean) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify child iblock clean.")
-
- /* if iblock_addr != fd_parent_addr, verify that a flush
- * dependency relationship exists between iblock and
- * the child iblock.
- */
- if(fd_parent_addr != iblock_addr) {
- if(H5AC_flush_dependency_exists(f, iblock_addr, child_iblock_addr, &fd_exists) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
-
- if(!fd_exists)
- HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "iblock is not a flush dep parent of child_iblock.")
- } /* end if */
-
- /* 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, H5AC__NO_FLAGS_SET) < 0)
- HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "H5AC_unprotect() faild.")
- } /* end if */
- } /* end if */
+ if(child_iblock_status & H5AC_ES__IS_DIRTY)
+ *clean = FALSE;
} /* end if */
} /* end if */