summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNeil Fortner <nfortne2@hdfgroup.org>2012-02-27 16:34:55 (GMT)
committerNeil Fortner <nfortne2@hdfgroup.org>2012-02-27 16:34:55 (GMT)
commit73c139e29b45941dfc4e558d9096a0869a184260 (patch)
tree422cc12e6675238cd92edadc078fa427a4f6bcd0 /src
parente2cd00055204f6b264002e70b21a6e2ca4c98c77 (diff)
downloadhdf5-73c139e29b45941dfc4e558d9096a0869a184260.zip
hdf5-73c139e29b45941dfc4e558d9096a0869a184260.tar.gz
hdf5-73c139e29b45941dfc4e558d9096a0869a184260.tar.bz2
[svn-r21989] Purpose: Add SWMR capability to v1 b-tree
Description: Adds SWMR capability to v1 b-trees, and the chunk index using v1 b-trees. With this implementation, flush dependencies are always on when in the cache. This will allow attritbutes to be used for "checkpointing" data when object header dependencies are fixed - i.e. if a writer writes data before an attribute in that dataset's object header, then if a reader sees the updated attribute the written data is guaranteed to be visible, as long as that dataset's b-tree nodes are evicted from the reader's cache. Also adds support for compression with SWMR. Also fixes earray implementation to not free (reuse) the file space for deleted chunks and outdated versions of compressed chunks when doing SWMR writes. These should eventually be added to a timeout list. Adds testing for these cases. Tested: durandal
Diffstat (limited to 'src')
-rw-r--r--src/H5B.c722
-rw-r--r--src/H5Bcache.c68
-rw-r--r--src/H5Bpkg.h4
-rw-r--r--src/H5Bprivate.h26
-rw-r--r--src/H5Dbtree.c386
-rw-r--r--src/H5Dchunk.c121
-rw-r--r--src/H5Dearray.c35
-rw-r--r--src/H5Dpkg.h16
-rw-r--r--src/H5Dproxy.c96
-rw-r--r--src/H5Gnode.c2
-rw-r--r--src/H5Gstab.c34
-rw-r--r--src/H5Gtest.c5
-rw-r--r--src/H5Ostab.c2
13 files changed, 1259 insertions, 258 deletions
diff --git a/src/H5B.c b/src/H5B.c
index 40b221d..61c5856 100644
--- a/src/H5B.c
+++ b/src/H5B.c
@@ -111,7 +111,6 @@
#include "H5MFprivate.h" /* File memory management */
#include "H5Pprivate.h" /* Property lists */
-
/****************/
/* Local Macros */
/****************/
@@ -154,12 +153,15 @@ static H5B_ins_t H5B_insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
hbool_t *rt_key_changed,
H5B_ins_ud_t *split_bt_ud/*out*/);
static herr_t H5B_insert_child(H5B_t *bt, unsigned *bt_flags,
- unsigned idx, haddr_t child,
+ unsigned *idx, haddr_t child,
H5B_ins_t anchor, const void *md_key);
static herr_t H5B_split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
unsigned idx, void *udata,
H5B_ins_ud_t *split_bt_ud/*out*/);
static H5B_t * H5B_copy(const H5B_t *old_bt);
+static herr_t H5B_find_node(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, void *udata, void *parent,
+ H5B_t **node);
/*********************/
@@ -216,7 +218,7 @@ H5FL_SEQ_DEFINE_STATIC(size_t);
*/
herr_t
H5B_create(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, void *udata,
- haddr_t *addr_p/*out*/)
+ void *parent, haddr_t *addr_p/*out*/)
{
H5B_t *bt = NULL;
H5B_shared_t *shared=NULL; /* Pointer to shared B-tree info */
@@ -249,6 +251,7 @@ H5B_create(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, void *udata,
if(NULL == (bt->native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)) ||
NULL == (bt->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for B-tree root node")
+ bt->parent = parent;
if(HADDR_UNDEF == (*addr_p = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)shared->sizeof_rnode)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "file allocation failed for B-tree root node")
@@ -301,7 +304,8 @@ done:
*-------------------------------------------------------------------------
*/
htri_t
-H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *udata)
+H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ void *udata, void *parent)
{
H5B_t *bt = NULL;
H5RC_t *rc_shared; /* Ref-counted shared info */
@@ -335,6 +339,7 @@ H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *u
*/
cache_udata.f = f;
cache_udata.type = type;
+ cache_udata.parent = parent;
cache_udata.rc_shared = rc_shared;
if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
@@ -358,7 +363,7 @@ H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *u
HDassert(idx < bt->nchildren);
if(bt->level > 0) {
- if((ret_value = H5B_find(f, dxpl_id, type, bt->child[idx], udata)) < 0)
+ if((ret_value = H5B_find(f, dxpl_id, type, bt->child[idx], udata, bt)) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in subtree")
} /* end if */
else {
@@ -375,6 +380,109 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5B_find_node
+ *
+ * Purpose: Locate the B-tree node containing the item specified in
+ * UDATA, if present. If found, the B-tree node will be
+ * pinned on return and must be unpinned after the caller is
+ * done using it. If not found, *node will be set to NULL.
+ *
+ * Return: Non-negative on success. Negative on failure.
+ *
+ * Programmer: Neil Fortner
+ * Aug 18 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B_find_node(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ void *udata, void *parent, H5B_t **node)
+{
+ H5B_t *bt = NULL;
+ H5RC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned idx = 0, lt = 0, rt; /* Final, left & right key indices */
+ int cmp = 1; /* Key comparison value */
+ htri_t found; /* Whether the correct node has been found */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5B_find_node, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(type->decode);
+ HDassert(type->cmp3);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5RC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /*
+ * Perform a binary search to locate the child which contains
+ * the thing for which we're searching.
+ */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.parent = parent;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
+
+ rt = bt->nchildren;
+ while(lt < rt && cmp) {
+ idx = (lt + rt) / 2;
+ /* compare */
+ if((cmp = (type->cmp3)(H5B_NKEY(bt, shared, idx), udata, H5B_NKEY(bt, shared, (idx + 1)))) < 0)
+ rt = idx;
+ else
+ lt = idx + 1;
+ } /* end while */
+ /* Check if not found */
+ if(cmp)
+ *node = NULL;
+ else {
+ /*
+ * Follow the link to the subtree, or return the leaf node.
+ */
+ HDassert(idx < bt->nchildren);
+
+ if(bt->level > 0) {
+ if(H5B_find_node(f, dxpl_id, type, bt->child[idx], udata, bt, node) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in subtree")
+ } /* end if */
+ else {
+ /* Check if this is really the correct child */
+ if((found = (type->found)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx), udata)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in leaf node")
+
+ if(found) {
+ /* Return this leaf node, pinned */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__PIN_ENTRY_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release node")
+ *node = bt;
+ bt = NULL;
+ } /* end if */
+ else
+ *node = NULL;
+ } /* end else */
+ } /* end else */
+
+done:
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_find_node() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5B_split
*
* Purpose: Split a single node into two nodes. The old node will
@@ -405,6 +513,7 @@ H5B_split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, unsigned idx,
H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
unsigned nleft, nright; /* Number of keys in left & right halves */
double split_ratios[3]; /* B-tree split ratios */
+ hbool_t bt_pinned = FALSE;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5B_split)
@@ -480,10 +589,11 @@ H5B_split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, unsigned idx,
/*
* Create the new B-tree node.
*/
- if(H5B_create(f, dxpl_id, shared->type, udata, &split_bt_ud->addr/*out*/) < 0)
+ if(H5B_create(f, dxpl_id, shared->type, udata, bt_ud->bt->parent, &split_bt_ud->addr/*out*/) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create B-tree")
cache_udata.f = f;
cache_udata.type = shared->type;
+ cache_udata.parent = bt_ud->bt->parent;
cache_udata.rc_shared = bt_ud->bt->rc_shared;
if(NULL == (split_bt_ud->bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, split_bt_ud->addr, &cache_udata, H5AC_WRITE)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree")
@@ -509,29 +619,117 @@ H5B_split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, unsigned idx,
bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
bt_ud->bt->nchildren = nleft;
+ /* Actions to take if swmr writes are on */
+ if(shared->swmr_write) {
+ haddr_t new_bt_addr = HADDR_UNDEF;
+ unsigned i;
+
+ /*
+ * We must clone the old btree so readers with an out-of-date version
+ * of the parent can still see all its children, via the shadowed
+ * non-split bt. Remove it from cache but do not mark it free on disk.
+ */
+ /* Allocate space for the cloned child */
+ H5_CHECK_OVERFLOW(shared->sizeof_rnode,size_t,hsize_t);
+ if(HADDR_UNDEF == (new_bt_addr = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)shared->sizeof_rnode)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move b-tree")
+
+ /* Pin old entry so it is not flushed when we unprotect */
+ if(H5AC_pin_protected_entry(bt_ud->bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPIN, FAIL, "unable to pin old b-tree node")
+ bt_pinned = TRUE;
+
+ /* Unprotect bt so we can move it. Also, note that it will be marked
+ * dirty so it will be written to the new location. */
+ HDassert(bt_ud->cache_flags & H5AC__DIRTIED_FLAG);
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud->addr, bt_ud->bt, bt_ud->cache_flags) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release old b-tree")
+ bt_ud->cache_flags = H5AC__NO_FLAGS_SET;
+
+ /* Move the location of the old child on the disk */
+ if(H5AC_move_entry(f, H5AC_BT, bt_ud->addr, new_bt_addr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to move B-tree root node")
+ bt_ud->addr = new_bt_addr;
+
+ /* Re-protect bt at new address */
+ if(bt_ud->bt != H5AC_protect(f, dxpl_id, H5AC_BT, new_bt_addr, &cache_udata, H5AC_WRITE))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree node")
+
+ /*
+ * Update flush dependencies for children that moved to the new node
+ */
+ if(bt_ud->bt->level > 0) {
+ H5B_t *child;
+
+ for(i=0; i<nright; i++) {
+ /* Protect child b-tree node */
+ cache_udata.parent = split_bt_ud->bt;
+ if(NULL == (child = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, split_bt_ud->bt->child[i], &cache_udata, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
+
+ /* Update the flush dependency, if necessary */
+ HDassert(child->parent);
+ if(child->parent == bt_ud->bt) {
+ child->parent = split_bt_ud->bt;
+ if(H5AC_destroy_flush_dependency(bt_ud->bt, child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ if(H5AC_create_flush_dependency(child->parent, child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ } /* end if */
+ else
+ HDassert(child->parent == split_bt_ud->bt);
+
+ /* Unprotect the child */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, split_bt_ud->bt->child[idx], child, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ } /* end for */
+ } /* end if */
+ else {
+ /* At leaf node, delegate to client */
+ HDassert(shared->type->update_flush_dep);
+ for(i=0; i<nright; i++) {
+ if((shared->type->update_flush_dep)(H5B_NKEY(split_bt_ud->bt, shared, i), udata, bt_ud->bt, split_bt_ud->bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to update flush dependency")
+ } /* end for */
+ } /* end else */
+
+ /*
+ * Update left sibling to point to new bt. Only necessary when doing
+ * swmr writes as otherwise the address of bt doesn't change.
+ */
+ if(H5F_addr_defined(bt_ud->bt->left)) {
+ H5B_t *tmp_bt;
+
+ if(NULL == (tmp_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt_ud->bt->left, &cache_udata, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load right sibling")
+
+ tmp_bt->right = bt_ud->addr;
+
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud->bt->left, tmp_bt, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ } /* end if */
+ } /* end if */
+
/*
- * Update sibling pointers.
+ * Update other sibling pointers.
*/
split_bt_ud->bt->left = bt_ud->addr;
split_bt_ud->bt->right = bt_ud->bt->right;
if(H5F_addr_defined(bt_ud->bt->right)) {
- H5B_t *tmp_bt;
- H5B_cache_ud_t cache_udata2; /* User-data for metadata cache callback */
+ H5B_t *tmp_bt;
- cache_udata2.f = f;
- cache_udata2.type = shared->type;
- cache_udata2.rc_shared = bt_ud->bt->rc_shared;
- if(NULL == (tmp_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt_ud->bt->right, &cache_udata2, H5AC_WRITE)))
- HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load right sibling")
+ if(NULL == (tmp_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt_ud->bt->right, &cache_udata, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load right sibling")
- tmp_bt->left = split_bt_ud->addr;
+ tmp_bt->left = split_bt_ud->addr;
if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud->bt->right, tmp_bt, H5AC__DIRTIED_FLAG) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
} /* end if */
bt_ud->bt->right = split_bt_ud->addr;
+ bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
done:
if(ret_value < 0) {
@@ -539,6 +737,13 @@ done:
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
split_bt_ud->bt = NULL;
split_bt_ud->addr = HADDR_UNDEF;
+ split_bt_ud->cache_flags = H5AC__NO_FLAGS_SET;
+ } /* end if */
+
+ if(bt_pinned) {
+ HDassert(shared->swmr_write);
+ if(H5AC_unpin_entry(bt_ud->bt) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin old root")
} /* end if */
FUNC_LEAVE_NOAPI(ret_value)
@@ -560,7 +765,7 @@ done:
*/
herr_t
H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
- void *udata)
+ void *udata, void *parent)
{
/*
* These are defined this way to satisfy alignment constraints.
@@ -580,6 +785,8 @@ H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
H5B_shared_t *shared; /* Pointer to shared B-tree info */
H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
H5B_ins_t my_ins = H5B_INS_ERROR;
+ hbool_t bt_protected = FALSE;
+ hbool_t nrbt_pinned = FALSE; /* TRUE if new_root_bt is pinned */
herr_t ret_value = SUCCEED;
FUNC_ENTER_NOAPI(H5B_insert, FAIL)
@@ -599,20 +806,27 @@ H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
/* Protect the root node */
cache_udata.f = f;
cache_udata.type = type;
+ cache_udata.parent = parent;
cache_udata.rc_shared = rc_shared;
bt_ud.addr = addr;
if(NULL == (bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_WRITE)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to locate root of B-tree")
+ bt_protected = TRUE;
/* Insert the object */
if((int)(my_ins = H5B_insert_helper(f, dxpl_id, &bt_ud, type, lt_key,
&lt_key_changed, md_key, udata, rt_key, &rt_key_changed,
&split_bt_ud/*out*/)) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to insert key")
+
+ /* Check if the root node split */
if(H5B_INS_NOOP == my_ins) {
+ /* The root node did not split - just update the flush dependency (if
+ * necessary) and exit */
HDassert(!split_bt_ud.bt);
HGOTO_DONE(SUCCEED)
} /* end if */
+
HDassert(H5B_INS_RIGHT == my_ins);
HDassert(split_bt_ud.bt);
HDassert(H5F_addr_defined(split_bt_ud.addr));
@@ -631,33 +845,33 @@ H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
* at the old root's previous address. This prevents the B-tree from
* "moving".
*/
- H5_CHECK_OVERFLOW(shared->sizeof_rnode,size_t,hsize_t);
- if(HADDR_UNDEF == (old_root_addr = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)shared->sizeof_rnode)))
- HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move root")
-
- /*
- * Move the node to the new location
- */
+ /* Note that this is not necessary if swmr writes are on, as H5B_split
+ * already moved the node in this case */
+ if(!shared->swmr_write) {
+ H5_CHECK_OVERFLOW(shared->sizeof_rnode,size_t,hsize_t);
+ if(HADDR_UNDEF == (old_root_addr = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)shared->sizeof_rnode)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move root")
+
+ /* Unprotect the old root so we can move it. Also force it to be marked
+ * dirty so it is written to the new location. */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud.addr, bt_ud.bt, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release old root")
+ bt_protected = FALSE;
+
+ /* Move the location of the old root on the disk */
+ if(H5AC_move_entry(f, H5AC_BT, bt_ud.addr, old_root_addr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to move B-tree root node")
+ bt_ud.addr = old_root_addr;
+
+ /* Update the split b-tree's left pointer to point to the new location */
+ split_bt_ud.bt->left = bt_ud.addr;
+ split_bt_ud.cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end else */
/* Make a copy of the old root information */
if(NULL == (new_root_bt = H5B_copy(bt_ud.bt)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to copy old root");
- /* Unprotect the old root so we can move it. Also force it to be marked
- * dirty so it is written to the new location. */
- if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud.addr, bt_ud.bt, H5AC__DIRTIED_FLAG) < 0)
- HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release old root")
- bt_ud.bt = NULL; /* Make certain future references will be caught */
-
- /* Move the location of the old root on the disk */
- if(H5AC_move_entry(f, H5AC_BT, bt_ud.addr, old_root_addr) < 0)
- HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to move B-tree root node")
- bt_ud.addr = old_root_addr;
-
- /* Update the split b-tree's left pointer to point to the new location */
- split_bt_ud.bt->left = bt_ud.addr;
- split_bt_ud.cache_flags |= H5AC__DIRTIED_FLAG;
-
/* clear the old root info at the old address (we already copied it) */
new_root_bt->left = HADDR_UNDEF;
new_root_bt->right = HADDR_UNDEF;
@@ -673,23 +887,61 @@ H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
HDmemcpy(H5B_NKEY(new_root_bt, shared, 1), md_key, shared->type->sizeof_nkey);
HDmemcpy(H5B_NKEY(new_root_bt, shared, 2), rt_key, shared->type->sizeof_nkey);
- /* Insert the modified copy of the old root into the file again */
- if(H5AC_insert_entry(f, dxpl_id, H5AC_BT, addr, new_root_bt, H5AC__NO_FLAGS_SET) < 0)
- HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to add old B-tree root node to cache")
+ /* Insert the modified copy of the old root into the file again, and pin if
+ * doing swmr writes */
+ if(shared->swmr_write) {
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_BT, addr, new_root_bt, H5AC__PIN_ENTRY_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to add new B-tree root node to cache")
+ nrbt_pinned = TRUE;
+
+ /* Set up flush dependencies */
+ HDassert(parent);
+ HDassert(bt_ud.bt->parent == parent);
+ if(H5AC_destroy_flush_dependency(parent, bt_ud.bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to destroy flush dependency")
+ if(H5AC_create_flush_dependency(new_root_bt, bt_ud.bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ bt_ud.bt->parent = new_root_bt;
+
+ HDassert(split_bt_ud.bt->parent == parent);
+ if(H5AC_destroy_flush_dependency(parent, split_bt_ud.bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to destroy flush dependency")
+ if(H5AC_create_flush_dependency(new_root_bt, split_bt_ud.bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ split_bt_ud.bt->parent = new_root_bt;
+
+ HDassert(new_root_bt->parent == parent);
+ } /* end if */
+ else {
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_BT, addr, new_root_bt, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to add new B-tree root node to cache")
-done:
- if(ret_value < 0)
- if(new_root_bt && H5B_node_dest(new_root_bt) < 0)
- HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "unable to free B-tree root node");
+ /* Mark new_root_bt as NULL, as it is not pinned or protected and does
+ * not need to be freed as it is now in the cache. */
+ new_root_bt = NULL;
+ } /* end else */
- if(bt_ud.bt)
- if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud.addr, bt_ud.bt, bt_ud.cache_flags) < 0)
+done:
+ if(bt_protected)
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud.addr, bt_ud.bt,
+ bt_ud.cache_flags) < 0)
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to unprotect old root")
if(split_bt_ud.bt)
if(H5AC_unprotect(f, dxpl_id, H5AC_BT, split_bt_ud.addr, split_bt_ud.bt, split_bt_ud.cache_flags) < 0)
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to unprotect new child")
+ if(nrbt_pinned) {
+ HDassert(shared->swmr_write);
+ if(H5AC_unpin_entry(new_root_bt) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin new root")
+ } /* end if */
+ else if(new_root_bt) {
+ HDassert(ret_value < 0);
+ if(H5B_node_dest(new_root_bt) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free B-tree root node");
+ } /* end if */
+
#ifdef H5B_DEBUG
if(ret_value >= 0)
H5B_assert(f, dxpl_id, addr, type, udata);
@@ -715,7 +967,7 @@ done:
*-------------------------------------------------------------------------
*/
static herr_t
-H5B_insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx,
+H5B_insert_child(H5B_t *bt, unsigned *bt_flags, unsigned *idx,
haddr_t child, H5B_ins_t anchor, const void *md_key)
{
H5B_shared_t *shared; /* Pointer to shared B-tree info */
@@ -733,8 +985,8 @@ H5B_insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx,
/* Check for inserting right-most key into node (common when just appending
* records to an unlimited dimension chunked dataset)
*/
- base = H5B_NKEY(bt, shared, (idx + 1));
- if((idx + 1) == bt->nchildren) {
+ base = H5B_NKEY(bt, shared, (*idx + 1));
+ if((*idx + 1) == bt->nchildren) {
/* Make room for the new key */
HDmemcpy(base + shared->type->sizeof_nkey, base,
shared->type->sizeof_nkey); /* No overlap possible - memcpy() OK */
@@ -742,34 +994,34 @@ H5B_insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx,
/* The MD_KEY is the left key of the new node */
if(H5B_INS_RIGHT == anchor)
- idx++; /* Don't have to memmove() child addresses down, just add new child */
+ (*idx)++; /* Don't have to memmove() child addresses down, just add new child */
else
/* Make room for the new child address */
- bt->child[idx + 1] = bt->child[idx];
+ bt->child[*idx + 1] = bt->child[*idx];
} /* end if */
else {
/* Make room for the new key */
HDmemmove(base + shared->type->sizeof_nkey, base,
- (bt->nchildren - idx) * shared->type->sizeof_nkey);
+ (bt->nchildren - *idx) * shared->type->sizeof_nkey);
HDmemcpy(base, md_key, shared->type->sizeof_nkey);
/* The MD_KEY is the left key of the new node */
if(H5B_INS_RIGHT == anchor)
- idx++;
+ (*idx)++;
/* Make room for the new child address */
- HDmemmove(bt->child + idx + 1, bt->child + idx,
- (bt->nchildren - idx) * sizeof(haddr_t));
+ HDmemmove(bt->child + *idx + 1, bt->child + *idx,
+ (bt->nchildren - *idx) * sizeof(haddr_t));
} /* end if */
- bt->child[idx] = child;
+ bt->child[*idx] = child;
bt->nchildren += 1;
/* Mark node as dirty */
*bt_flags |= H5AC__DIRTIED_FLAG;
FUNC_LEAVE_NOAPI(SUCCEED)
-}
+} /* end H5B_insert_child() */
/*-------------------------------------------------------------------------
@@ -873,6 +1125,7 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
/* Set up user data for cache callbacks */
cache_udata.f = f;
cache_udata.type = type;
+ cache_udata.parent = bt;
cache_udata.rc_shared = rc_shared;
if(0 == bt->nchildren) {
@@ -1046,18 +1299,30 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
else
HDmemcpy(rt_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey);
} /* end if */
- if(H5B_INS_CHANGE == my_ins) {
- /*
- * The insertion simply changed the address for the child.
- */
- HDassert(!child_bt_ud.bt);
- HDassert(bt->level == 0);
- bt->child[idx] = new_child_bt_ud.addr;
- bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
- } else if(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins) {
+
+ /*
+ * Handle changes/additions to children
+ */
+ HDassert(!(bt->level == 0) != !(child_bt_ud.bt));
+ if(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins) {
hbool_t *tmp_bt_flags_ptr = NULL;
H5B_t *tmp_bt;
+ /* Update child pointer to (old) child if swmr writes are on and level >
+ * 0, as it has been moved by H5B_split (one level down) */
+ if(shared->swmr_write && bt->level > 0) {
+ HDassert(child_bt_ud.bt);
+ HDassert(bt_ud->bt->child[idx] != child_bt_ud.addr);
+
+ bt_ud->bt->child[idx] = child_bt_ud.addr;
+ } /* end if */
+#ifndef NDEBUG
+ if(!(shared->swmr_write) && bt->level > 0) {
+ HDassert(child_bt_ud.bt);
+ HDassert(bt_ud->bt->child[idx] == child_bt_ud.addr);
+ } /* end if */
+#endif /* NDEBUG */
+
/*
* If this node is full then split it before inserting the new child.
*/
@@ -1079,9 +1344,34 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
} /* end else */
/* Insert the child */
- if(H5B_insert_child(tmp_bt, tmp_bt_flags_ptr, idx, new_child_bt_ud.addr, my_ins, md_key) < 0)
+ if(H5B_insert_child(tmp_bt, tmp_bt_flags_ptr, &idx, new_child_bt_ud.addr, my_ins, md_key) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert child")
- }
+
+ /* Set up flush dependency on child client object, if appropriate */
+ if(shared->swmr_write && bt->level == 0) {
+ HDassert(!child_bt_ud.bt);
+ HDassert(shared->type->create_flush_dep);
+ if((shared->type->create_flush_dep)(H5B_NKEY(tmp_bt, shared, idx), udata, tmp_bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, H5B_INS_ERROR, "unable to create flush dependency")
+ } /* end if */
+ } else {
+ if(H5B_INS_CHANGE == my_ins) {
+ /*
+ * The insertion simply changed the address for the child.
+ */
+ HDassert(!child_bt_ud.bt);
+ HDassert(bt->level == 0);
+ bt->child[idx] = new_child_bt_ud.addr;
+ bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ /*Set up flush dependency on child client object, if appropriate */
+ if(shared->swmr_write && bt->level == 0) {
+ HDassert(!child_bt_ud.bt);
+ HDassert(shared->type->create_flush_dep);
+ if((shared->type->create_flush_dep)(H5B_NKEY(bt, shared, idx), udata, bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, H5B_INS_ERROR, "unable to create flush dependency")
+ } /* end if */
+ } /* end if */
/*
* If this node split, return the mid key (the one that is shared
@@ -1105,7 +1395,8 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
done:
if(child_bt_ud.bt)
- if(H5AC_unprotect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, child_bt_ud.bt, child_bt_ud.cache_flags) < 0)
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, child_bt_ud.bt,
+ child_bt_ud.cache_flags) < 0)
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect child")
if(new_child_bt_ud.bt)
@@ -1113,7 +1404,7 @@ done:
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect new child")
FUNC_LEAVE_NOAPI(ret_value)
-}
+} /* end H5B_insert_helper() */
/*-------------------------------------------------------------------------
@@ -1128,19 +1419,24 @@ done:
* matzke@llnl.gov
* Jun 23 1997
*
+ * Modifications: Neil Fortner
+ * Jun 23 2011
+ * Replaced original function with new algorithm that doesn't
+ * use sibling pointers (for SWMR consistency) or unprotect
+ * nodes during recursion (for performance and safety).
+ *
*-------------------------------------------------------------------------
*/
static herr_t
H5B_iterate_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
- H5B_operator_t op, void *udata)
+ H5B_operator_t op, void *udata, void *parent)
{
- H5B_t *bt = NULL; /* Pointer to current B-tree node */
- H5RC_t *rc_shared; /* Ref-counted shared info */
+ H5B_t *bt = NULL; /* Pointer to current B-tree node */
+ H5RC_t *rc_shared; /* Ref-counted shared info */
H5B_shared_t *shared; /* Pointer to shared B-tree info */
H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
- uint8_t *native = NULL; /* Array of keys in native format */
- haddr_t *child = NULL; /* Array of child pointers */
- herr_t ret_value; /* Return value */
+ unsigned i; /* Index */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5B_iterate_helper)
@@ -1155,108 +1451,33 @@ H5B_iterate_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t add
/* Get shared info for B-tree */
if(NULL == (rc_shared = (type->get_shared)(f, udata)))
- HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
shared = (H5B_shared_t *)H5RC_GET_OBJ(rc_shared);
HDassert(shared);
/* Protect the initial/current node */
cache_udata.f = f;
cache_udata.type = type;
+ cache_udata.parent = parent;
cache_udata.rc_shared = rc_shared;
if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ)))
- HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load B-tree node")
-
- if(bt->level > 0) {
- haddr_t left_child = bt->child[0]; /* Address of left-most child in node */
-
- /* Release current node */
- if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
- HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release B-tree node")
- bt = NULL;
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load B-tree node")
- /* Keep following the left-most child until we reach a leaf node. */
- if((ret_value = H5B_iterate_helper(f, dxpl_id, type, left_child, op, udata)) < 0)
- HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, H5_ITER_ERROR, "unable to list B-tree node")
- } /* end if */
- else {
- unsigned nchildren; /* Number of child pointers */
- haddr_t next_addr; /* Address of next node to the right */
-
- /* Allocate space for a copy of the native records & child pointers */
- if(NULL == (native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)))
- HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, H5_ITER_ERROR, "memory allocation failed for shared B-tree native records")
- if(NULL == (child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
- HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, H5_ITER_ERROR, "memory allocation failed for shared B-tree child addresses")
-
- /* Cache information from this node */
- nchildren = bt->nchildren;
- next_addr = bt->right;
-
- /* Copy the native keys & child pointers into local arrays */
- HDmemcpy(native, bt->native, shared->sizeof_keys);
- HDmemcpy(child, bt->child, (nchildren * sizeof(haddr_t)));
-
- /* Release current node */
- if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
- HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release B-tree node")
- bt = NULL;
-
- /*
- * We've reached the left-most leaf. Now follow the right-sibling
- * pointer from leaf to leaf until we've processed all leaves.
- */
- ret_value = H5_ITER_CONT;
- while(ret_value == H5_ITER_CONT) {
- haddr_t *curr_child; /* Pointer to node's child addresses */
- uint8_t *curr_native; /* Pointer to node's native keys */
- unsigned u; /* Local index variable */
-
- /*
- * Perform the iteration operator, which might invoke an
- * application callback.
- */
- for(u = 0, curr_child = child, curr_native = native; u < nchildren && ret_value == H5_ITER_CONT; u++, curr_child++, curr_native += type->sizeof_nkey) {
- ret_value = (*op)(f, dxpl_id, curr_native, *curr_child, curr_native + type->sizeof_nkey, udata);
- if(ret_value < 0)
- HERROR(H5E_BTREE, H5E_CANTLIST, "iterator function failed");
- } /* end for */
-
- /* Check for continuing iteration */
- if(ret_value == H5_ITER_CONT) {
- /* Check for another node */
- if(H5F_addr_defined(next_addr)) {
- /* Protect the next node to the right */
- addr = next_addr;
- if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ)))
- HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "B-tree node")
-
- /* Cache information from this node */
- nchildren = bt->nchildren;
- next_addr = bt->right;
-
- /* Copy the native keys & child pointers into local arrays */
- HDmemcpy(native, bt->native, shared->sizeof_keys);
- HDmemcpy(child, bt->child, nchildren * sizeof(haddr_t));
-
- /* Unprotect node */
- if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
- HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release B-tree node")
- bt = NULL;
- } /* end if */
- else
- /* Exit loop */
- break;
- } /* end if */
- } /* end while */
- } /* end else */
+ /* Iterate over children */
+ for(i=0; i<bt->nchildren && ret_value == H5_ITER_CONT; i++) {
+ if(bt->level > 0) {
+ /* Keep following the left-most child until we reach a leaf node. */
+ if((ret_value = H5B_iterate_helper(f, dxpl_id, type, bt->child[i], op, udata, bt)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, H5_ITER_ERROR, "unable to list B-tree node")
+ } /* end if */
+ else
+ if((ret_value = (*op)(f, dxpl_id, H5B_NKEY(bt, shared, i), bt->child[i], H5B_NKEY(bt, shared, i + 1), udata)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, H5_ITER_ERROR, "iterator function failed")
+ } /* end for */
done:
if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release B-tree node")
- if(native)
- native = H5FL_BLK_FREE(native_block, native);
- if(child)
- child = H5FL_SEQ_FREE(haddr_t, child);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5B_iterate_helper() */
@@ -1278,7 +1499,7 @@ done:
*/
herr_t
H5B_iterate(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
- H5B_operator_t op, void *udata)
+ H5B_operator_t op, void *udata, void *parent)
{
herr_t ret_value; /* Return value */
@@ -1294,7 +1515,7 @@ H5B_iterate(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
HDassert(udata);
/* Iterate over the B-tree records */
- if((ret_value = H5B_iterate_helper(f, dxpl_id, type, addr, op, udata)) < 0)
+ if((ret_value = H5B_iterate_helper(f, dxpl_id, type, addr, op, udata, parent)) < 0)
HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
FUNC_LEAVE_NOAPI(ret_value)
@@ -1329,7 +1550,8 @@ static H5B_ins_t
H5B_remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type,
int level, uint8_t *lt_key/*out*/,
hbool_t *lt_key_changed/*out*/, void *udata,
- uint8_t *rt_key/*out*/, hbool_t *rt_key_changed/*out*/)
+ uint8_t *rt_key/*out*/, hbool_t *rt_key_changed/*out*/,
+ void *parent)
{
H5B_t *bt = NULL, *sibling = NULL;
unsigned bt_flags = H5AC__NO_FLAGS_SET;
@@ -1343,7 +1565,6 @@ H5B_remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type
FUNC_ENTER_NOAPI(H5B_remove_helper, H5B_INS_ERROR)
HDassert(f);
- HDassert(H5F_addr_defined(addr));
HDassert(type);
HDassert(type->decode);
HDassert(type->cmp3);
@@ -1364,6 +1585,7 @@ H5B_remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type
cache_udata.f = f;
cache_udata.type = type;
cache_udata.rc_shared = rc_shared;
+ cache_udata.parent = parent;
if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_WRITE)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load B-tree node")
@@ -1388,7 +1610,7 @@ H5B_remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type
if((int)(ret_value = H5B_remove_helper(f, dxpl_id,
bt->child[idx], type, level + 1, H5B_NKEY(bt, shared, idx)/*out*/,
lt_key_changed/*out*/, udata, H5B_NKEY(bt, shared, idx + 1)/*out*/,
- rt_key_changed/*out*/)) < 0)
+ rt_key_changed/*out*/, bt)) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, H5B_INS_ERROR, "key not found in subtree")
} else if(type->remove) {
/*
@@ -1504,9 +1726,10 @@ H5B_remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type
bt->nchildren = 0;
/* Delete the node from disk (via the metadata cache) */
- bt_flags |= H5AC__DIRTIED_FLAG;
+ if(!shared->swmr_write)
+ bt_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
H5_CHECK_OVERFLOW(shared->sizeof_rnode, size_t, hsize_t);
- if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, bt_flags | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0) {
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, bt_flags | H5AC__DELETED_FLAG) < 0) {
bt = NULL;
bt_flags = H5AC__NO_FLAGS_SET;
HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to free B-tree node")
@@ -1652,7 +1875,8 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5B_remove(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *udata)
+H5B_remove(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ void *udata, void *parent)
{
/* These are defined this way to satisfy alignment constraints */
uint64_t _lt_key[128], _rt_key[128];
@@ -1672,7 +1896,8 @@ H5B_remove(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void
/* The actual removal */
if(H5B_remove_helper(f, dxpl_id, addr, type, 0, lt_key, &lt_key_changed,
- udata, rt_key, &rt_key_changed) == H5B_INS_ERROR)
+ udata, rt_key, &rt_key_changed, parent)
+ == H5B_INS_ERROR)
HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to remove entry from B-tree")
#ifdef H5B_DEBUG
@@ -1697,7 +1922,8 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *udata)
+H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ void *udata, void *parent)
{
H5B_t *bt = NULL; /* B-tree node being operated on */
H5RC_t *rc_shared; /* Ref-counted shared info */
@@ -1722,6 +1948,7 @@ H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void
/* Lock this B-tree node into memory for now */
cache_udata.f = f;
cache_udata.type = type;
+ cache_udata.parent = parent;
cache_udata.rc_shared = rc_shared;
if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_WRITE)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
@@ -1730,7 +1957,7 @@ H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void
if(bt->level > 0) {
/* Iterate over all children in node, deleting them */
for(u = 0; u < bt->nchildren; u++)
- if(H5B_delete(f, dxpl_id, type, bt->child[u], udata) < 0)
+ if(H5B_delete(f, dxpl_id, type, bt->child[u], udata, bt) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "unable to delete B-tree node")
} /* end if */
@@ -1751,7 +1978,7 @@ H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void
} /* end else */
done:
- if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__DELETED_FLAG | (shared->swmr_write ? 0 : H5AC__FREE_FILE_SPACE_FLAG)) < 0)
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node in cache")
FUNC_LEAVE_NOAPI(ret_value)
@@ -1816,6 +2043,11 @@ HDmemset(shared->page, 0, shared->sizeof_rnode);
for(u = 0; u < (shared->two_k + 1); u++)
shared->nkey[u] = u * type->sizeof_nkey;
+ /* Determine if we are doing SWMR writes. Only enable for chunks for now.
+ */
+ shared->swmr_write = (H5F_INTENT(f) & H5F_ACC_SWMR_WRITE) > 0
+ && type->id == H5B_CHUNK_ID;
+
/* Set return value */
ret_value = shared;
@@ -1948,7 +2180,7 @@ done:
*/
static herr_t
H5B_get_info_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
- const H5B_info_ud_t *info_udata)
+ const H5B_info_ud_t *info_udata, void *parent)
{
H5B_t *bt = NULL; /* Pointer to current B-tree node */
H5RC_t *rc_shared; /* Ref-counted shared info */
@@ -1984,6 +2216,7 @@ H5B_get_info_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t ad
/* Protect the initial/current node */
cache_udata.f = f;
cache_udata.type = type;
+ cache_udata.parent = parent;
cache_udata.rc_shared = rc_shared;
if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
@@ -2028,7 +2261,7 @@ H5B_get_info_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t ad
/* Check for another "row" of B-tree nodes to iterate over */
if(level > 0) {
/* Keep following the left-most child until we reach a leaf node. */
- if(H5B_get_info_helper(f, dxpl_id, type, left_child, info_udata) < 0)
+ if(H5B_get_info_helper(f, dxpl_id, type, left_child, info_udata, bt) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "unable to list B-tree node")
} /* end if */
@@ -2054,7 +2287,7 @@ done:
*/
herr_t
H5B_get_info(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
- H5B_info_t *bt_info, H5B_operator_t op, void *udata)
+ H5B_info_t *bt_info, H5B_operator_t op, void *udata, void *parent)
{
H5B_info_ud_t info_udata; /* User-data for B-tree size iteration */
herr_t ret_value = SUCCEED; /* Return value */
@@ -2078,13 +2311,13 @@ H5B_get_info(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
info_udata.udata = udata;
/* Iterate over the B-tree nodes */
- if(H5B_get_info_helper(f, dxpl_id, type, addr, &info_udata) < 0)
+ if(H5B_get_info_helper(f, dxpl_id, type, addr, &info_udata, parent) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_BADITER, FAIL, "B-tree iteration failed")
/* Iterate over the B-tree records, making any "leaf" callbacks */
/* (Only if operator defined) */
if(op)
- if((ret_value = H5B_iterate_helper(f, dxpl_id, type, addr, op, udata)) < 0)
+ if((ret_value = H5B_iterate_helper(f, dxpl_id, type, addr, op, udata, parent)) < 0)
HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
done:
@@ -2105,7 +2338,8 @@ done:
*-------------------------------------------------------------------------
*/
htri_t
-H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr)
+H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ void *parent)
{
H5B_t *bt = NULL; /* The B-tree */
H5RC_t *rc_shared; /* Ref-counted shared info */
@@ -2135,6 +2369,7 @@ H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr)
*/
cache_udata.f = f;
cache_udata.type = type;
+ cache_udata.parent = parent;
cache_udata.rc_shared = rc_shared;
if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ)))
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree node")
@@ -2179,3 +2414,122 @@ H5B_node_dest(H5B_t *bt)
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5B_node_dest() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_support
+ *
+ * Purpose: Add a flush dependency between the b-tree child object (as
+ * the flush dependency child) and the b-tree node containing
+ * the address of that child. If the child has not yet been
+ * inserted, does nothing.
+ *
+ * Return: TRUE if flush dependency created
+ * FALSE if child is not in b-tree
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Aug 18 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5B_support(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ void *udata, void *parent, void *child)
+{
+ H5B_t *node = NULL; /* Node containing direct link to child */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5B_support, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(type->decode);
+ HDassert(type->cmp3);
+ HDassert(type->found);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata);
+ HDassert(child);
+
+ /* Lookup the node which points to the requested child */
+ if(H5B_find_node(f, dxpl_id, type, addr, udata, parent, &node) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in B-tree")
+
+ /* Set the return value, and add the flush dependency if the ndoe was found
+ */
+ if(node) {
+ if(H5AC_create_flush_dependency(node, child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ ret_value = TRUE;
+ } /* end if */
+ else
+ ret_value = FALSE;
+
+done:
+ if(node && H5AC_unpin_entry(node) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_support() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_unsupport
+ *
+ * Purpose: Destroy a flush dependency between the b-tree child object
+ * and the b-tree node containing the address of that child.
+ * This dependency *must* have been created earlier either by
+ * a call to H5B_support() or by the client (presumably via
+ * the create_flush_dep() callback on insertion).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Aug 18 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_unsupport(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ void *udata, void *parent, void *child)
+{
+ H5B_t *node = NULL; /* Node containing direct link to child */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5B_unsupport, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(type->decode);
+ HDassert(type->cmp3);
+ HDassert(type->found);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata);
+ HDassert(child);
+
+ /* Lookup the node which points to the requested child */
+ if(H5B_find_node(f, dxpl_id, type, addr, udata, parent, &node) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in B-tree")
+
+ /* It is an error if the node does not exist yet - the client should only
+ * call this function if support() succeeded or if the client's
+ * create_flush_dep() callback has been called. */
+ if(!node)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "node not found in B-tree")
+
+ /* Add the flush dependency */
+ if(H5AC_destroy_flush_dependency(node, child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+done:
+ if(node && H5AC_unpin_entry(node) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_unsupport() */
+
diff --git a/src/H5Bcache.c b/src/H5Bcache.c
index 7c006bc..64c8b56 100644
--- a/src/H5Bcache.c
+++ b/src/H5Bcache.c
@@ -60,6 +60,7 @@ static herr_t H5B_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr,
static herr_t H5B_dest(H5F_t *f, H5B_t *bt);
static herr_t H5B_clear(H5F_t *f, H5B_t *b, hbool_t destroy);
static herr_t H5B_compute_size(const H5F_t *f, const H5B_t *bt, size_t *size_ptr);
+static herr_t H5B_notify(H5AC_notify_action_t action, H5B_t *bt);
/*********************/
@@ -73,7 +74,7 @@ const H5AC_class_t H5AC_BT[1] = {{
(H5AC_flush_func_t)H5B_flush,
(H5AC_dest_func_t)H5B_dest,
(H5AC_clear_func_t)H5B_clear,
- (H5AC_notify_func_t)NULL,
+ (H5AC_notify_func_t)H5B_notify,
(H5AC_size_func_t)H5B_compute_size,
}};
@@ -176,6 +177,13 @@ H5B_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)
HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode key")
} /* end if */
+ /* Set up flush dependency. The dependency will actually be created in the
+ * "notify" callback. */
+ if(shared->swmr_write) {
+ HDassert(udata->parent);
+ bt->parent = udata->parent;
+ } /* end if */
+
/* Set return value */
ret_value = bt;
@@ -370,6 +378,64 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5B_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Aug 17 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B_notify(H5AC_notify_action_t action, H5B_t *bt)
+{
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT(H5B_notify)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(bt);
+ HDassert(bt->rc_shared);
+ shared = (H5B_shared_t *)H5RC_GET_OBJ(bt->rc_shared);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(shared->swmr_write) {
+ HDassert(bt->parent);
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ /* Create flush dependency on parent */
+ if(H5AC_create_flush_dependency(bt->parent, bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5AC_destroy_flush_dependency(bt->parent, bt) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_notify() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5B_compute_size
*
* Purpose: Compute the size in bytes of the specified instance of
diff --git a/src/H5Bpkg.h b/src/H5Bpkg.h
index 46e2b28..8478ae3 100644
--- a/src/H5Bpkg.h
+++ b/src/H5Bpkg.h
@@ -59,12 +59,16 @@ typedef struct H5B_t {
haddr_t right; /*address of right sibling */
uint8_t *native; /*array of keys in native format */
haddr_t *child; /*2k child pointers */
+
+ /* Not stored on disk */
+ void *parent; /* Flush dependency parent */
} H5B_t;
/* Callback info for loading a B-tree node into the cache */
typedef struct H5B_cache_ud_t {
H5F_t *f; /* File that B-tree node is within */
const struct H5B_class_t *type; /* Type of tree */
+ void *parent; /* Flush dependency parent */
H5RC_t *rc_shared; /* Ref-counted shared info */
} H5B_cache_ud_t;
diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h
index 83a357b..a7b303d 100644
--- a/src/H5Bprivate.h
+++ b/src/H5Bprivate.h
@@ -100,6 +100,7 @@ typedef struct H5B_shared_t {
size_t sizeof_len; /* Size of file lengths (in bytes) */
uint8_t *page; /* Disk page */
size_t *nkey; /* Offsets of each native key in native key buffer */
+ hbool_t swmr_write; /* Whether we are doing SWMR writes */
} H5B_shared_t;
/*
@@ -138,6 +139,10 @@ typedef struct H5B_class_t {
herr_t (*decode)(const H5B_shared_t*, const uint8_t*, void*);
herr_t (*encode)(const H5B_shared_t*, uint8_t*, const void*);
herr_t (*debug_key)(FILE*, int, int, const void*, const void*);
+
+ /* flush dependency functions */
+ herr_t (*create_flush_dep)(void*, void *, void *);
+ herr_t (*update_flush_dep)(void*, void *, void *, void*);
} H5B_class_t;
/* Information about B-tree */
@@ -157,25 +162,30 @@ typedef struct H5B_info_t {
/* Library-private Function Prototypes */
/***************************************/
H5_DLL herr_t H5B_create(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- void *udata, haddr_t *addr_p/*out*/);
+ void *udata, void *parent, haddr_t *addr_p/*out*/);
H5_DLL herr_t H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- haddr_t addr, void *udata);
+ haddr_t addr, void *udata, void *parent);
H5_DLL herr_t H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- haddr_t addr, void *udata);
+ haddr_t addr, void *udata, void *parent);
H5_DLL herr_t H5B_iterate(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- haddr_t addr, H5B_operator_t op, void *udata);
+ haddr_t addr, H5B_operator_t op, void *udata, void *parent);
H5_DLL herr_t H5B_get_info(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- haddr_t addr, H5B_info_t *bt_info, H5B_operator_t op, void *udata);
+ haddr_t addr, H5B_info_t *bt_info, H5B_operator_t op, void *udata,
+ void *parent);
H5_DLL herr_t H5B_remove(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- haddr_t addr, void *udata);
+ haddr_t addr, void *udata, void *parent);
H5_DLL herr_t H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- haddr_t addr, void *udata);
+ haddr_t addr, void *udata, void *parent);
H5_DLL H5B_shared_t *H5B_shared_new(const H5F_t *f, const H5B_class_t *type,
size_t sizeof_rkey);
H5_DLL herr_t H5B_shared_free(void *_shared);
+H5_DLL htri_t H5B_support(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, void *udata, void *parent, void *child);
+H5_DLL herr_t H5B_unsupport(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, void *udata, void *parent, void *child);
H5_DLL herr_t H5B_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream,
int indent, int fwidth, const H5B_class_t *type, void *udata);
H5_DLL htri_t H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
- haddr_t addr);
+ haddr_t addr, void *parent);
#endif /* _H5Bprivate_H */
diff --git a/src/H5Dbtree.c b/src/H5Dbtree.c
index e61811d..f511d90 100644
--- a/src/H5Dbtree.c
+++ b/src/H5Dbtree.c
@@ -124,6 +124,10 @@ static herr_t H5D_btree_encode_key(const H5B_shared_t *shared, uint8_t *raw,
const void *_key);
static herr_t H5D_btree_debug_key(FILE *stream, int indent, int fwidth,
const void *key, const void *udata);
+static herr_t H5D_btree_create_flush_dep(void *_key, void *_udata,
+ void *parent);
+static herr_t H5D_btree_update_flush_dep(void *_key, void *_udata,
+ void *old_parent, void *new_parent);
/* Chunked layout indexing callbacks */
static herr_t H5D_btree_idx_init(const H5D_chk_idx_info_t *idx_info,
@@ -146,6 +150,10 @@ static herr_t H5D_btree_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
static herr_t H5D_btree_idx_size(const H5D_chk_idx_info_t *idx_info,
hsize_t *size);
static herr_t H5D_btree_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+static herr_t H5D_btree_idx_support(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, H5AC_info_t *child_entry);
+static herr_t H5D_btree_idx_unsupport(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata, H5AC_info_t *child_entry);
static herr_t H5D_btree_idx_dump(const H5O_storage_chunk_t *storage,
FILE *stream);
static herr_t H5D_btree_idx_dest(const H5D_chk_idx_info_t *idx_info);
@@ -157,7 +165,7 @@ static herr_t H5D_btree_idx_dest(const H5D_chk_idx_info_t *idx_info);
/* v1 B-tree indexed chunk I/O ops */
const H5D_chunk_ops_t H5D_COPS_BTREE[1] = {{
- FALSE, /* v1 B-tree indices don't support SWMR access */
+ TRUE, /* v1 B-tree indices do support SWMR access */
H5D_btree_idx_init,
H5D_btree_idx_create,
H5D_btree_idx_is_space_alloc,
@@ -171,8 +179,8 @@ const H5D_chunk_ops_t H5D_COPS_BTREE[1] = {{
H5D_btree_idx_copy_shutdown,
H5D_btree_idx_size,
H5D_btree_idx_reset,
- NULL,
- NULL,
+ H5D_btree_idx_support,
+ H5D_btree_idx_unsupport,
H5D_btree_idx_dump,
H5D_btree_idx_dest
}};
@@ -199,6 +207,8 @@ H5B_class_t H5B_BTREE[1] = {{
H5D_btree_decode_key, /*decode */
H5D_btree_encode_key, /*encode */
H5D_btree_debug_key, /*debug */
+ H5D_btree_create_flush_dep, /*create_flush_dep */
+ H5D_btree_update_flush_dep, /*update_flush_dep */
}};
@@ -561,13 +571,20 @@ H5D_btree_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key,
* QAK - 11/19/2002
*/
#ifdef OLD_WAY
+ /* Note that this does not take SWMR writes into account! Fix this
+ * if we ever want to go back to this code. -NAF 8/2/11 */
if(HADDR_UNDEF == (*new_node_p = H5MF_realloc(f, H5FD_MEM_DRAW, addr,
(hsize_t)lt_key->nbytes, (hsize_t)udata->nbytes)))
HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, H5B_INS_ERROR, "unable to reallocate chunk storage")
#else /* OLD_WAY */
- H5_CHECK_OVERFLOW(lt_key->nbytes, uint32_t, hsize_t);
- if(H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, addr, (hsize_t)lt_key->nbytes) < 0)
- HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, H5B_INS_ERROR, "unable to free chunk")
+ /* Only free the old location if not doing SWMR writes - otherwise
+ * we must keep the old chunk around in case a reader has an
+ * outdated version of the b-tree node */
+ if(!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(lt_key->nbytes, uint32_t, hsize_t);
+ if(H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, addr, (hsize_t)lt_key->nbytes) < 0)
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, H5B_INS_ERROR, "unable to free chunk")
+ } /* end if */
H5_CHECK_OVERFLOW(udata->nbytes, uint32_t, hsize_t);
if(HADDR_UNDEF == (*new_node_p = H5MF_alloc(f, H5FD_MEM_DRAW, dxpl_id, (hsize_t)udata->nbytes)))
HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, H5B_INS_ERROR, "unable to reallocate chunk")
@@ -644,9 +661,11 @@ H5D_btree_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key /*in,out *
FUNC_ENTER_NOAPI_NOINIT(H5D_btree_remove)
/* Remove raw data chunk from file */
- H5_CHECK_OVERFLOW(lt_key->nbytes, uint32_t, hsize_t);
- if(H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, addr, (hsize_t)lt_key->nbytes) < 0)
- HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, H5B_INS_ERROR, "unable to free chunk")
+ if(!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(lt_key->nbytes, uint32_t, hsize_t);
+ if(H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, addr, (hsize_t)lt_key->nbytes) < 0)
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, H5B_INS_ERROR, "unable to free chunk")
+ } /* end if */
/* Mark keys as unchanged */
*lt_key_changed = FALSE;
@@ -801,7 +820,7 @@ H5D_btree_shared_create(const H5F_t *f, H5O_storage_chunk_t *store, unsigned ndi
/* Set up the "local" information for this dataset's chunks */
/* <none> */
-
+HDassert(!store->u.btree.shared);
/* Make shared B-tree info reference counted */
if(NULL == (store->u.btree.shared = H5RC_create(shared, H5B_shared_free)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create ref-count wrapper for shared B-tree info")
@@ -812,6 +831,91 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5D_btree_create_flush_dep
+ *
+ * Purpose: Creates a flush dependency between the specified chunk
+ * (child) and parent.
+ *
+ * Return: Success: 0
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, September 21, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D_btree_create_flush_dep(void *_key, void *_udata, void *parent)
+{
+ H5D_btree_key_t *key = (H5D_btree_key_t *)_key;
+ H5D_chunk_common_ud_t *udata = (H5D_chunk_common_ud_t *) _udata;
+ int ret_value;
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_btree_create_flush_dep)
+
+ HDassert(key);
+ HDassert(udata);
+ HDassert(udata->layout->ndims > 0 && udata->layout->ndims <= H5O_LAYOUT_NDIMS);
+ HDassert(parent);
+
+ /* If there is no rdcc, then there are no cached chunks to create
+ * dependencies on. This should only happen when copying */
+ if(udata->rdcc)
+ /* Delegate to chunk routine */
+ if(H5D_chunk_create_flush_dep(udata->rdcc, udata->layout, key->offset,
+ parent) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_btree_create_flush_dep() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_btree_update_flush_dep
+ *
+ * Purpose: Updates the flush dependency of the specified chunk from
+ * old_parent to new_parent, but only if the current parent
+ * is cached. If the chunk is not cached, does nothing.
+ *
+ * Return: Success: 0
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, August 31, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D_btree_update_flush_dep(void *_key, void *_udata, void *old_parent,
+ void *new_parent)
+{
+ H5D_btree_key_t *key = (H5D_btree_key_t *)_key;
+ H5D_chunk_common_ud_t *udata = (H5D_chunk_common_ud_t *) _udata;
+ int ret_value;
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_btree_update_flush_dep)
+
+ HDassert(key);
+ HDassert(udata);
+ HDassert(udata->layout->ndims > 0 && udata->layout->ndims <= H5O_LAYOUT_NDIMS);
+ HDassert(old_parent);
+ HDassert(new_parent);
+
+ /* If there is no rdcc, then there are no cached chunks to update
+ * dependencies. This should only happen when copying */
+ if(udata->rdcc)
+ /* Delegate to chunk routine */
+ if(H5D_chunk_update_flush_dep(udata->rdcc, udata->layout, key->offset,
+ old_parent, new_parent) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to update flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_btree_update_flush_dep() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5D_btree_idx_init
*
* Purpose: Initialize the indexing information for a dataset.
@@ -871,7 +975,9 @@ done:
static herr_t
H5D_btree_idx_create(const H5D_chk_idx_info_t *idx_info)
{
- H5D_chunk_common_ud_t udata; /* User data for B-tree callback */
+ H5D_chunk_common_ud_t udata; /* User data for B-tree callback */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_create)
@@ -888,11 +994,26 @@ H5D_btree_idx_create(const H5D_chk_idx_info_t *idx_info)
udata.layout = idx_info->layout;
udata.storage = idx_info->storage;
+ /* Check for SWMR writes to the file */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) {
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+ } /* end if */
+
/* Create the v1 B-tree for the chunk index */
- if(H5B_create(idx_info->f, idx_info->dxpl_id, H5B_BTREE, &udata, &(idx_info->storage->idx_addr)/*out*/) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create B-tree")
+ if(H5B_create(idx_info->f, idx_info->dxpl_id, H5B_BTREE, &udata, oh, &(idx_info->storage->idx_addr)/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create B-tree")
done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D_btree_idx_create() */
@@ -942,7 +1063,9 @@ H5D_btree_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
static herr_t
H5D_btree_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
{
- herr_t ret_value = SUCCEED; /* Return value */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_insert)
@@ -954,14 +1077,30 @@ H5D_btree_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
HDassert(udata);
+ /* Check for SWMR writes to the file. If so we must pin the dataset object
+ * header so it can be set as a flush dependency parent. */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) {
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+ } /* end if */
+
/*
* Create the chunk it if it doesn't exist, or reallocate the chunk if
* its size changed.
*/
- if(H5B_insert(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0)
+ if(H5B_insert(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata, oh) < 0)
HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to allocate chunk")
done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5D_btree_idx_insert() */
@@ -983,6 +1122,8 @@ done:
static herr_t
H5D_btree_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
{
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_get_addr)
@@ -996,11 +1137,27 @@ H5D_btree_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata
HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
HDassert(udata);
+ /* Check for SWMR writes to the file. If so we must pin the dataset object
+ * header so it can be set as a flush dependency parent. */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) {
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+ } /* end if */
+
/* Go get the chunk information from the B-tree */
- if(H5B_find(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0)
+ if(H5B_find(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata, oh) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info")
done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5D_btree_idx_get_addr() */
@@ -1071,9 +1228,11 @@ H5D_btree_idx_iterate(const H5D_chk_idx_info_t *idx_info,
H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
{
H5D_btree_it_ud_t udata; /* User data for B-tree iterator callback */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
int ret_value; /* Return value */
- FUNC_ENTER_NOAPI_NOINIT_NOERR(H5D_btree_idx_iterate)
+ FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_iterate)
HDassert(idx_info);
HDassert(idx_info->f);
@@ -1084,6 +1243,19 @@ H5D_btree_idx_iterate(const H5D_chk_idx_info_t *idx_info,
HDassert(chunk_cb);
HDassert(chunk_udata);
+ /* Check for SWMR writes to the file. If so we must pin the dataset object
+ * header so it can be set as a flush dependency parent. */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) {
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+ } /* end if */
+
/* Initialize userdata */
HDmemset(&udata, 0, sizeof udata);
udata.common.layout = idx_info->layout;
@@ -1092,9 +1264,13 @@ H5D_btree_idx_iterate(const H5D_chk_idx_info_t *idx_info,
udata.udata = chunk_udata;
/* Iterate over existing chunks */
- if((ret_value = H5B_iterate(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, H5D_btree_idx_iterate_cb, &udata)) < 0)
+ if((ret_value = H5B_iterate(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, H5D_btree_idx_iterate_cb, &udata, oh)) < 0)
HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over chunk B-tree");
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D_btree_idx_iterate() */
@@ -1114,6 +1290,8 @@ H5D_btree_idx_iterate(const H5D_chk_idx_info_t *idx_info,
static herr_t
H5D_btree_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata)
{
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_remove)
@@ -1126,13 +1304,29 @@ H5D_btree_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *
HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
HDassert(udata);
+ /* Check for SWMR writes to the file. If so we must pin the dataset object
+ * header so it can be set as a flush dependency parent. */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) {
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+ } /* end if */
+
/* Remove the chunk from the v1 B-tree index and release the space for the
* chunk (in the B-tree callback).
*/
- if(H5B_remove(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0)
+ if(H5B_remove(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata, oh) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to remove chunk entry")
done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5D_btree_idx_remove() */
@@ -1154,7 +1348,9 @@ done:
static herr_t
H5D_btree_idx_delete(const H5D_chk_idx_info_t *idx_info)
{
- herr_t ret_value = SUCCEED; /* Return value */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_delete)
@@ -1170,6 +1366,19 @@ H5D_btree_idx_delete(const H5D_chk_idx_info_t *idx_info)
H5O_storage_chunk_t tmp_storage; /* Local copy of storage info */
H5D_chunk_common_ud_t udata; /* User data for B-tree operations */
+ /* Check for SWMR writes to the file. If so we must pin the dataset object
+ * header so it can be set as a flush dependency parent. */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) {
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+ } /* end if */
+
/* Set up temporary chunked storage info */
tmp_storage = *idx_info->storage;
@@ -1183,7 +1392,7 @@ H5D_btree_idx_delete(const H5D_chk_idx_info_t *idx_info)
udata.storage = &tmp_storage;
/* Delete entire B-tree */
- if(H5B_delete(idx_info->f, idx_info->dxpl_id, H5B_BTREE, tmp_storage.idx_addr, &udata) < 0)
+ if(H5B_delete(idx_info->f, idx_info->dxpl_id, H5B_BTREE, tmp_storage.idx_addr, &udata, oh) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk B-tree")
/* Release the shared B-tree page */
@@ -1194,6 +1403,9 @@ H5D_btree_idx_delete(const H5D_chk_idx_info_t *idx_info)
} /* end if */
done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D_btree_idx_delete() */
@@ -1300,6 +1512,8 @@ H5D_btree_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
H5D_chunk_common_ud_t udata; /* User-data for loading B-tree nodes */
H5B_info_t bt_info; /* B-tree info */
hbool_t shared_init = FALSE; /* Whether shared B-tree info is initialized */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5D_btree_idx_size, FAIL)
@@ -1312,6 +1526,19 @@ H5D_btree_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
HDassert(idx_info->storage);
HDassert(index_size);
+ /* Check for SWMR writes to the file. If so we must pin the dataset object
+ * header so it can be set as a flush dependency parent. */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) {
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+ } /* end if */
+
/* Initialize the shared info for the B-tree traversal */
if(H5D_btree_shared_create(idx_info->f, idx_info->storage, idx_info->layout->ndims) < 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for shared B-tree info")
@@ -1323,13 +1550,16 @@ H5D_btree_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
udata.storage = idx_info->storage;
/* Get metadata information for B-tree */
- if(H5B_get_info(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, &bt_info, NULL, &udata) < 0)
+ if(H5B_get_info(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, &bt_info, NULL, &udata, oh) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to iterate over chunk B-tree")
/* Set the size of the B-tree */
*index_size = bt_info.size;
done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
if(shared_init) {
if(NULL == idx_info->storage->u.btree.shared)
HDONE_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "ref-counted page nil")
@@ -1370,6 +1600,118 @@ H5D_btree_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
/*-------------------------------------------------------------------------
+ * Function: H5D_btree_idx_support
+ *
+ * Purpose: Create a dependency between a chunk [proxy] and the index
+ * metadata that contains the record for the chunk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Friday, Jun 24, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5D_btree_idx_support(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, H5AC_info_t *child_entry)
+{
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_support)
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+ HDassert(child_entry);
+ HDassert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE);
+
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+
+ /* Add the flush dependency on the chunk */
+ if((ret_value = H5B_support(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr,
+ udata, oh, child_entry)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on b-tree array metadata")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_btree_idx_support() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_btree_idx_unsupport
+ *
+ * Purpose: Destroy a dependency between a chunk [proxy] and the index
+ * metadata that contains the record for the chunk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, Jul 6, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D_btree_idx_unsupport(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata, H5AC_info_t *child_entry)
+{
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5O_t *oh = NULL; /* Dataset's object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_btree_idx_unsupport)
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+ HDassert(child_entry);
+ HDassert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE);
+
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Pin the dataset's object header */
+ if(NULL == (oh = H5O_pin(&oloc, idx_info->dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+
+ /* Add the flush dependency on the chunk */
+ if((ret_value = H5B_unsupport(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr,
+ udata, oh, child_entry)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency on b-tree array metadata")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_btree_idx_unsupport() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5D_btree_idx_dump
*
* Purpose: Dump indexing information to a stream.
diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c
index abebe2a..48a7c20 100644
--- a/src/H5Dchunk.c
+++ b/src/H5Dchunk.c
@@ -3137,7 +3137,7 @@ H5D_chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata,
* flush dependencies are maintained in the proper way for SWMR
* access to work.
*/
- if(H5D_chunk_proxy_create(io_info->dset, io_info->dxpl_id, (H5D_chunk_common_ud_t *)udata, ent) < 0)
+ if(H5D_chunk_proxy_create(io_info->dset, io_info->dxpl_id, udata, ent) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, NULL, "can't insert proxy for chunk in metadata cache")
} /* end if */
} /* end if */
@@ -5871,3 +5871,122 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5D_chunk_is_partial_edge_chunk() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_chunk_create_flush_dep
+ *
+ * Purpose: Creates a flush dependency between the specified chunk
+ * (child) and parent.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, September 21, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_chunk_create_flush_dep(const H5D_rdcc_t *rdcc,
+ const H5O_layout_chunk_t *layout, const hsize_t offset[], void *parent)
+{
+ hsize_t chunk_idx; /* Chunk index */
+ H5D_rdcc_ent_t *ent = NULL; /* Cache entry */
+ hbool_t found = FALSE; /* In cache? */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_create_flush_dep)
+
+ /* Check args */
+ HDassert(rdcc);
+ HDassert(layout);
+ HDassert(offset);
+ HDassert(parent);
+
+ /* Calculate the index of this chunk */
+ if(H5V_chunk_index(layout->ndims - 1, offset, layout->dim,
+ layout->down_chunks, &chunk_idx) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index")
+
+ /* Check for chunk in cache */
+ if(rdcc->nslots > 0) {
+ ent = rdcc->slot[H5F_addr_hash(chunk_idx, rdcc->nslots)];
+
+ if(ent)
+ for(u = 0, found = TRUE; u < layout->ndims - 1; u++)
+ if(offset[u] != ent->offset[u]) {
+ found = FALSE;
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Create the dependency on the chunk proxy */
+ if(found)
+ if(H5D_chunk_proxy_create_flush_dep(ent, parent) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D_chunk_create_flush_dep() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_chunk_update_flush_dep
+ *
+ * Purpose: Updates the flush dependency of the specified chunk from
+ * old_parent to new_parent, but only if the current parent
+ * is cached. If the chunk is not cached, does nothing.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 7 Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_chunk_update_flush_dep(const H5D_rdcc_t *rdcc,
+ const H5O_layout_chunk_t *layout, const hsize_t offset[], void *old_parent,
+ void *new_parent)
+{
+ hsize_t chunk_idx; /* Chunk index */
+ H5D_rdcc_ent_t *ent = NULL; /* Cache entry */
+ hbool_t found = FALSE; /* In cache? */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_update_flush_dep)
+
+ /* Check args */
+ HDassert(rdcc);
+ HDassert(layout);
+ HDassert(offset);
+ HDassert(old_parent);
+ HDassert(new_parent);
+
+ /* Calculate the index of this chunk */
+ if(H5V_chunk_index(layout->ndims - 1, offset, layout->dim,
+ layout->down_chunks, &chunk_idx) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index")
+
+ /* Check for chunk in cache */
+ if(rdcc->nslots > 0) {
+ ent = rdcc->slot[H5F_addr_hash(chunk_idx, rdcc->nslots)];
+
+ if(ent)
+ for(u = 0, found = TRUE; u < layout->ndims - 1; u++)
+ if(offset[u] != ent->offset[u]) {
+ found = FALSE;
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Update the dependencies on the chunk proxy */
+ if(found)
+ if(H5D_chunk_proxy_update_flush_dep(ent, old_parent, new_parent) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to update flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D_chunk_update_flush_dep() */
+
diff --git a/src/H5Dearray.c b/src/H5Dearray.c
index bcdedc5..ba965a0 100644
--- a/src/H5Dearray.c
+++ b/src/H5Dearray.c
@@ -1151,9 +1151,14 @@ H5D_earray_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
/* Check for chunk being same size */
if(udata->nbytes != elmt.nbytes) {
/* Release previous chunk */
- H5_CHECK_OVERFLOW(elmt.nbytes, uint32_t, hsize_t);
- if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, elmt.addr, (hsize_t)elmt.nbytes) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ /* Only free the old location if not doing SWMR writes - otherwise
+ * we must keep the old chunk around in case a reader has an
+ * outdated version of the b-tree node */
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(elmt.nbytes, uint32_t, hsize_t);
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, elmt.addr, (hsize_t)elmt.nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ } /* end if */
elmt.addr = HADDR_UNDEF;
alloc_chunk = TRUE;
} /* end if */
@@ -1526,11 +1531,13 @@ H5D_earray_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t
if(H5EA_get(ea, idx_info->dxpl_id, idx, &elmt) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info")
- /* Remove raw data chunk from file */
+ /* Remove raw data chunk from file if not doing SWMR writes */
HDassert(H5F_addr_defined(elmt.addr));
- H5_CHECK_OVERFLOW(elmt.nbytes, /*From: */uint32_t, /*To: */hsize_t);
- if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, elmt.addr, (hsize_t)elmt.nbytes) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(elmt.nbytes, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, elmt.addr, (hsize_t)elmt.nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ } /* end if */
/* Reset the info about the chunk for the index */
elmt.addr = HADDR_UNDEF;
@@ -1546,11 +1553,13 @@ H5D_earray_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t
if(H5EA_get(ea, idx_info->dxpl_id, idx, &addr) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
- /* Remove raw data chunk from file */
+ /* Remove raw data chunk from file if not doing SWMR writes */
HDassert(H5F_addr_defined(addr));
- H5_CHECK_OVERFLOW(idx_info->layout->size, /*From: */uint32_t, /*To: */hsize_t);
- if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, addr, (hsize_t)idx_info->layout->size) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(idx_info->layout->size, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, addr, (hsize_t)idx_info->layout->size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ } /* end if */
/* Reset the address of the chunk for the index */
addr = HADDR_UNDEF;
@@ -1868,13 +1877,13 @@ H5D_earray_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
*
*-------------------------------------------------------------------------
*/
-static herr_t
+static htri_t
H5D_earray_idx_support(const H5D_chk_idx_info_t *idx_info,
H5D_chunk_common_ud_t *udata, H5AC_info_t *child_entry)
{
H5EA_t *ea; /* Pointer to extensible array structure */
hsize_t idx; /* Array index of chunk */
- herr_t ret_value = SUCCEED; /* Return value */
+ herr_t ret_value = TRUE; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5D_earray_idx_support)
diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h
index 02eb950..50a10ef 100644
--- a/src/H5Dpkg.h
+++ b/src/H5Dpkg.h
@@ -322,7 +322,7 @@ typedef herr_t (*H5D_chunk_copy_shutdown_func_t)(H5O_storage_chunk_t *storage_sr
typedef herr_t (*H5D_chunk_size_func_t)(const H5D_chk_idx_info_t *idx_info,
hsize_t *idx_size);
typedef herr_t (*H5D_chunk_reset_func_t)(H5O_storage_chunk_t *storage, hbool_t reset_addr);
-typedef herr_t (*H5D_chunk_support_func_t)(const H5D_chk_idx_info_t *idx_info,
+typedef htri_t (*H5D_chunk_support_func_t)(const H5D_chk_idx_info_t *idx_info,
H5D_chunk_common_ud_t *udata, H5AC_info_t *child_entry);
typedef herr_t (*H5D_chunk_unsupport_func_t)(const H5D_chk_idx_info_t *idx_info,
H5D_chunk_common_ud_t *udata, H5AC_info_t *child_entry);
@@ -553,6 +553,7 @@ typedef struct H5D_chunk_proxy_t {
/* first field in structure */
H5D_t *dset; /* Pointer to dataset that chunk proxies are related to */
H5D_rdcc_ent_t *ent; /* Pointer to chunk cache entry this proxy is standing in for */
+ hbool_t supported; /* Whether the proxy is a flush dependency of the index */
} H5D_chunk_proxy_t;
@@ -694,6 +695,11 @@ H5_DLL herr_t H5D_chunk_bh_info(H5F_t *f, hid_t dxpl_id, H5O_layout_t *layout,
const H5O_pline_t *pline, hsize_t *btree_size);
H5_DLL herr_t H5D_chunk_dump_index(H5D_t *dset, hid_t dxpl_id, FILE *stream);
H5_DLL herr_t H5D_chunk_dest(H5F_t *f, hid_t dxpl_id, H5D_t *dset);
+H5_DLL herr_t H5D_chunk_create_flush_dep(const H5D_rdcc_t *rdcc,
+ const H5O_layout_chunk_t *layout, const hsize_t offset[], void *parent);
+H5_DLL herr_t H5D_chunk_update_flush_dep(const H5D_rdcc_t *rdcc,
+ const H5O_layout_chunk_t *layout, const hsize_t offset[], void *old_parent,
+ void *new_parent);
#ifdef H5D_CHUNK_DEBUG
H5_DLL herr_t H5D_chunk_stats(const H5D_t *dset, hbool_t headers);
#endif /* H5D_CHUNK_DEBUG */
@@ -724,10 +730,14 @@ H5_DLL herr_t H5D_fill_term(H5D_fill_buf_info_t *fb_info);
/* Functions that operate on chunk proxy objects */
H5_DLL herr_t H5D_chunk_proxy_create(H5D_t *dset, hid_t dxpl_id,
- H5D_chunk_common_ud_t *udata, H5D_rdcc_ent_t *ent);
+ H5D_chunk_ud_t *udata, H5D_rdcc_ent_t *ent);
H5_DLL herr_t H5D_chunk_proxy_remove(const H5D_t *dset, hid_t dxpl_it,
H5D_rdcc_ent_t *ent);
-H5_DLL herr_t H5D_chunk_proxy_mark(const H5D_rdcc_ent_t *ent, hbool_t dirty);
+H5_DLL herr_t H5D_chunk_proxy_mark(H5D_rdcc_ent_t *ent, hbool_t dirty);
+H5_DLL herr_t H5D_chunk_proxy_create_flush_dep(H5D_rdcc_ent_t *ent,
+ void *parent);
+H5_DLL herr_t H5D_chunk_proxy_update_flush_dep(H5D_rdcc_ent_t *ent,
+ void *old_parent, void *new_parent);
#ifdef H5_HAVE_PARALLEL
diff --git a/src/H5Dproxy.c b/src/H5Dproxy.c
index fb52517..7be2121 100644
--- a/src/H5Dproxy.c
+++ b/src/H5Dproxy.c
@@ -319,17 +319,19 @@ H5D_cache_proxy_size(const H5F_t UNUSED *f, const H5D_chunk_proxy_t UNUSED *prox
*-------------------------------------------------------------------------
*/
herr_t
-H5D_chunk_proxy_create(H5D_t *dset, hid_t dxpl_id, H5D_chunk_common_ud_t *udata,
+H5D_chunk_proxy_create(H5D_t *dset, hid_t dxpl_id, H5D_chunk_ud_t *udata,
H5D_rdcc_ent_t *ent)
{
H5D_chunk_proxy_t *proxy = NULL; /* Chunk proxy */
H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ htri_t supported; /* Return value from "support" callback */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_proxy_create)
HDassert(dset);
HDassert(ent);
+ HDassert(dset->shared->layout.storage.u.chunk.ops->support);
/* Get a temp. address for chunk proxy */
if(HADDR_UNDEF == (ent->proxy_addr = H5MF_alloc_tmp(dset->oloc.file, (hsize_t)1)))
@@ -363,8 +365,9 @@ HDfprintf(stderr, "%s: ent->proxy_addr = %a\n", FUNC, ent->proxy_addr);
/* Create a flush dependency between the proxy (as the child) and the
* metadata object in the index (as the parent).
*/
- if((dset->shared->layout.storage.u.chunk.ops->support)(&idx_info, udata, (H5AC_info_t *)proxy) < 0)
+ if((supported = (dset->shared->layout.storage.u.chunk.ops->support)(&idx_info, udata, (H5AC_info_t *)proxy)) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency for chunk proxy")
+ proxy->supported = (hbool_t)supported;
done:
if(ret_value < 0) {
@@ -402,6 +405,7 @@ H5D_chunk_proxy_remove(const H5D_t *dset, hid_t dxpl_id, H5D_rdcc_ent_t *ent)
HDassert(dset);
HDassert(ent);
+ HDassert(dset->shared->layout.storage.u.chunk.ops->unsupport);
#ifdef QAK
HDfprintf(stderr, "%s: ent->proxy_addr = %a\n", FUNC, ent->proxy_addr);
#endif /* QAK */
@@ -425,8 +429,11 @@ HDfprintf(stderr, "%s: ent->proxy_addr = %a\n", FUNC, ent->proxy_addr);
/* Remove flush dependency between the proxy (as the child) and the
* metadata object in the index (as the parent).
*/
- if((dset->shared->layout.storage.u.chunk.ops->unsupport)(&idx_info, &udata, (H5AC_info_t *)proxy) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency for chunk proxy")
+ if(proxy->supported) {
+ if((dset->shared->layout.storage.u.chunk.ops->unsupport)(&idx_info, &udata, (H5AC_info_t *)proxy) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to remove flush dependency for chunk proxy")
+ proxy->supported = FALSE;
+ } /* end if */
/* Unpin & delete chunk proxy from metadata cache, taking ownership of it */
if(H5AC_unprotect(dset->oloc.file, dxpl_id, H5AC_CHUNK_PROXY, ent->proxy_addr, proxy, (H5AC__UNPIN_ENTRY_FLAG | H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG)) < 0)
@@ -456,7 +463,7 @@ done:
* be invoked collectively when operating in parallel I/O mode
* and it's possible that this routine can be invoked during
* indepedent raw data I/O.
- *
+ *
* So, the chunk proxy's dirty state in the metadata cache may
* be out of sync with the chunk itself, but only in the direction
* of being dirty when the chunk itself is clean. We'll call
@@ -473,7 +480,7 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5D_chunk_proxy_mark(const H5D_rdcc_ent_t *ent, hbool_t dirty)
+H5D_chunk_proxy_mark(H5D_rdcc_ent_t *ent, hbool_t dirty)
{
herr_t ret_value = SUCCEED; /* Return value */
@@ -522,3 +529,80 @@ H5D_chunk_proxy_destroy(H5D_chunk_proxy_t *proxy)
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D_chunk_proxy_destroy() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_chunk_proxy_create_flush_dep
+ *
+ * Purpose: Creates a flush dependency between the specified chunk
+ * (child) and parent, if not already present.
+ *
++ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 21 Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_chunk_proxy_create_flush_dep(H5D_rdcc_ent_t *ent, void *parent)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_proxy_create_flush_dep)
+
+ HDassert(ent);
+ HDassert(parent);
+
+ /* If the proxy already has a parent, do nothing. */
+ if(!(ent->proxy->supported)) {
+ /* Create the flush dependency */
+ if(H5AC_create_flush_dependency(parent, ent->proxy) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ ent->proxy->supported = TRUE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_chunk_proxy_create_flush_dep() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_chunk_proxy_update_flush_dep
+ *
+ * Purpose: Updates the flush dependency of the specified chunk from
+ * old_parent to new_parent, if the dependency exists.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 7 Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_chunk_proxy_update_flush_dep(H5D_rdcc_ent_t *ent, void *old_parent,
+ void *new_parent)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_proxy_update_flush_dep)
+
+ HDassert(ent);
+ HDassert(old_parent);
+ HDassert(new_parent);
+
+ /* It is guaranteed that the proxy has a parent, because the dependency
+ * should always be present if the parent object exists in the index, and
+ * this should only be called when updating the parent object */
+ HDassert(ent->proxy->supported);
+
+ /* Update the flush dependencies */
+ if(H5AC_destroy_flush_dependency(old_parent, ent->proxy) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ if(H5AC_create_flush_dependency(new_parent, ent->proxy) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_chunk_proxy_update_flush_dep() */
+
diff --git a/src/H5Gnode.c b/src/H5Gnode.c
index 5f32eb5..9da5a6e 100644
--- a/src/H5Gnode.c
+++ b/src/H5Gnode.c
@@ -96,6 +96,8 @@ H5B_class_t H5B_SNODE[1] = {{
H5G_node_decode_key, /*decode */
H5G_node_encode_key, /*encode */
H5G_node_debug_key, /*debug */
+ NULL, /*create_flush_dep */
+ NULL, /*update_flush_dep */
}};
/* Declare a free list to manage the H5G_node_t struct */
diff --git a/src/H5Gstab.c b/src/H5Gstab.c
index afa137c..37c54e4 100644
--- a/src/H5Gstab.c
+++ b/src/H5Gstab.c
@@ -113,7 +113,7 @@ H5G_stab_create_components(H5F_t *f, H5O_stab_t *stab, size_t size_hint, hid_t d
HDassert(size_hint > 0);
/* Create the B-tree */
- if(H5B_create(f, dxpl_id, H5B_SNODE, NULL, &(stab->btree_addr)/*out*/) < 0)
+ if(H5B_create(f, dxpl_id, H5B_SNODE, NULL, NULL, &(stab->btree_addr)/*out*/) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create B-tree")
/* Create symbol table private heap */
@@ -248,7 +248,7 @@ H5G_stab_insert_real(H5F_t *f, H5O_stab_t *stab, const char *name,
udata.crt_info = crt_info;
/* Insert into symbol table */
- if(H5B_insert(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata) < 0)
+ if(H5B_insert(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry")
done:
@@ -343,7 +343,7 @@ H5G_stab_remove(H5O_loc_t *loc, hid_t dxpl_id, H5RS_str_t *grp_full_path_r,
udata.grp_full_path_r = grp_full_path_r;
/* Remove from symbol table */
- if(H5B_remove(loc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &udata) < 0)
+ if(H5B_remove(loc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &udata, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry")
done:
@@ -401,7 +401,7 @@ H5G_stab_remove_by_idx(H5O_loc_t *grp_oloc, hid_t dxpl_id, H5RS_str_t *grp_full_
udata.grp_full_path_r = grp_full_path_r;
/* Remove link from symbol table */
- if(H5B_remove(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &udata) < 0)
+ if(H5B_remove(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &udata, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry")
done:
@@ -454,7 +454,7 @@ H5G_stab_delete(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab)
udata.common.heap = heap;
/* Delete entire B-tree */
- if(H5B_delete(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata) < 0)
+ if(H5B_delete(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table B-tree")
/* Release resources */
@@ -523,7 +523,7 @@ H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
udata.op_data = op_data;
/* Iterate over the group members */
- if((ret_value = H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_iterate, &udata)) < 0)
+ if((ret_value = H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_iterate, &udata, NULL)) < 0)
HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
/* Check for too high of a starting index (ex post facto :-) */
@@ -540,7 +540,7 @@ H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
udata.ltable = &ltable;
/* Iterate over the group members */
- if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_build_table, &udata) < 0)
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_build_table, &udata, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to build link table")
/* Check for skipping out of bounds */
@@ -599,7 +599,7 @@ H5G_stab_count(H5O_loc_t *oloc, hsize_t *num_objs, hid_t dxpl_id)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")
/* Iterate over the group members */
- if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_sumup, num_objs) < 0)
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_sumup, num_objs, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
done:
@@ -638,7 +638,7 @@ H5G_stab_bh_size(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab,
snode_size = 0;
/* Get the B-tree & symbol table node size info */
- if(H5B_get_info(f, dxpl_id, H5B_SNODE, stab->btree_addr, &bt_info, H5G_node_iterate_size, &snode_size) < 0)
+ if(H5B_get_info(f, dxpl_id, H5B_SNODE, stab->btree_addr, &bt_info, H5G_node_iterate_size, &snode_size, NULL) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "iteration operator failed")
/* Add symbol table & B-tree node sizes to index info */
@@ -732,7 +732,7 @@ H5G_stab_get_name_by_idx(H5O_loc_t *oloc, H5_iter_order_t order, hsize_t n,
hsize_t nlinks = 0; /* Number of links in group */
/* Iterate over the symbol table nodes, to count the links */
- if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_sumup, &nlinks) < 0)
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_sumup, &nlinks, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
/* Map decreasing iteration order index to increasing iteration order index */
@@ -748,7 +748,7 @@ H5G_stab_get_name_by_idx(H5O_loc_t *oloc, H5_iter_order_t order, hsize_t n,
udata_valid = TRUE;
/* Iterate over the group members */
- if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_by_idx, &udata) < 0)
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_by_idx, &udata, NULL) < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "iteration operator failed")
/* If we don't know the name now, we almost certainly went out of bounds */
@@ -861,7 +861,7 @@ H5G_stab_lookup(H5O_loc_t *grp_oloc, const char *name, H5O_link_t *lnk,
bt_udata.op_data = &udata;
/* Search the B-tree */
- if((ret_value = H5B_find(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &bt_udata)) < 0)
+ if((ret_value = H5B_find(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &bt_udata, NULL)) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found")
done:
@@ -955,7 +955,7 @@ H5G_stab_lookup_by_idx(H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_t n,
hsize_t nlinks = 0; /* Number of links in group */
/* Iterate over the symbol table nodes, to count the links */
- if(H5B_iterate(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_sumup, &nlinks) < 0)
+ if(H5B_iterate(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_sumup, &nlinks, NULL) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
/* Map decreasing iteration order index to increasing iteration order index */
@@ -971,7 +971,7 @@ H5G_stab_lookup_by_idx(H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_t n,
udata.found = FALSE;
/* Iterate over the group members */
- if(H5B_iterate(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_by_idx, &udata) < 0)
+ if(H5B_iterate(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_by_idx, &udata, NULL) < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "iteration operator failed")
/* If we didn't find the link, we almost certainly went out of bounds */
@@ -1019,10 +1019,10 @@ H5G_stab_valid(H5O_loc_t *grp_oloc, hid_t dxpl_id, H5O_stab_t *alt_stab)
HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message");
/* Check if the symbol table message's b-tree address is valid */
- if(H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr) < 0) {
+ if(H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, NULL) < 0) {
/* Address is invalid, try the b-tree address in the alternate symbol
* table message */
- if(!alt_stab || H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, alt_stab->btree_addr) < 0)
+ if(!alt_stab || H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, alt_stab->btree_addr, NULL) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to locate b-tree")
else {
/* The alternate symbol table's b-tree address is valid. Adjust the
@@ -1163,7 +1163,7 @@ H5G_stab_get_type_by_idx(H5O_loc_t *oloc, hsize_t idx, hid_t dxpl_id)
udata.type = H5G_UNKNOWN;
/* Iterate over the group members */
- if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_by_idx, &udata) < 0)
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G_node_by_idx, &udata, NULL) < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5G_UNKNOWN, "iteration operator failed")
/* If we don't know the type now, we almost certainly went out of bounds */
diff --git a/src/H5Gtest.c b/src/H5Gtest.c
index ec55e47..b6e3e141 100644
--- a/src/H5Gtest.c
+++ b/src/H5Gtest.c
@@ -626,7 +626,7 @@ H5G_verify_cached_stab_test(H5O_loc_t *grp_oloc, H5G_entry_t *ent)
HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "cached stab info does not match object header")
/* Verify that the btree address is valid */
- if(H5B_valid(grp_oloc->file, H5AC_ind_dxpl_id, H5B_SNODE, stab.btree_addr) < 0)
+ if(H5B_valid(grp_oloc->file, H5AC_ind_dxpl_id, H5B_SNODE, stab.btree_addr, NULL) < 0)
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "b-tree address is invalid")
/* Verify that the heap address is valid */
@@ -794,7 +794,8 @@ H5G_verify_cached_stabs_test(hid_t gid)
/* Iterate over the b-tree, checking validity of cached information */
if((ret_value = H5B_iterate(grp->oloc.file, H5AC_ind_dxpl_id, H5B_SNODE,
- stab.btree_addr, H5G_verify_cached_stabs_test_cb, &udata)) < 0)
+ stab.btree_addr, H5G_verify_cached_stabs_test_cb, &udata, NULL))
+ < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "iteration operator failed");
/* Reset metadata tagging */
diff --git a/src/H5Ostab.c b/src/H5Ostab.c
index e29a856..5d1909b 100644
--- a/src/H5Ostab.c
+++ b/src/H5Ostab.c
@@ -399,7 +399,7 @@ H5O_stab_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src, H5O_loc
udata.cpy_info = cpy_info;
/* Iterate over objects in group, copying them */
- if((H5B_iterate(src_oloc->file, dxpl_id, H5B_SNODE, stab_src->btree_addr, H5G_node_copy, &udata)) < 0)
+ if((H5B_iterate(src_oloc->file, dxpl_id, H5B_SNODE, stab_src->btree_addr, H5G_node_copy, &udata, NULL)) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
done: