diff options
Diffstat (limited to 'src/H5B.c')
-rw-r--r-- | src/H5B.c | 378 |
1 files changed, 201 insertions, 177 deletions
@@ -120,6 +120,8 @@ 4 + /*type, level, num entries */ \ 2*H5F_SIZEOF_ADDR(F)) /*left and right sibling addresses */ +/* Default initializer for H5B_ins_ud_t */ +#define H5B_INS_UD_T_NULL {NULL, HADDR_UNDEF, H5AC__NO_FLAGS_SET} /******************/ /* Local Typedefs */ @@ -131,24 +133,32 @@ typedef struct H5B_iter_ud_t { void *udata; /* Node type's 'udata' for loading & iterator callback */ } H5B_info_ud_t; +/* Convenience struct for the arguments needed to unprotect a b-tree after a + * call to H5B_iterate_helper() or H5B_split() */ +typedef struct H5B_ins_ud_t { + H5B_t *bt; /* B-tree */ + haddr_t addr; /* B-tree address */ + unsigned cache_flags; /* Cache flags for H5AC_unprotect() */ +} H5B_ins_ud_t; + /********************/ /* Local Prototypes */ /********************/ -static H5B_ins_t H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, +static H5B_ins_t H5B_insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8_t *lt_key, hbool_t *lt_key_changed, uint8_t *md_key, void *udata, uint8_t *rt_key, hbool_t *rt_key_changed, - haddr_t *retval); + 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, H5B_ins_t anchor, const void *md_key); -static herr_t H5B_split(H5F_t *f, hid_t dxpl_id, H5B_t *old_bt, - unsigned *old_bt_flags, haddr_t old_addr, - unsigned idx, void *udata, haddr_t *new_addr/*out*/); +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); @@ -374,7 +384,7 @@ done: * The UDATA pointer is passed to the sizeof_rkey() method but is * otherwise unused. * - * The OLD_BT argument is a pointer to a protected B-tree + * The BT_UD argument is a pointer to a protected B-tree * node. * * Return: Non-negative on success (The address of the new node is @@ -387,14 +397,12 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B_split(H5F_t *f, hid_t dxpl_id, H5B_t *old_bt, unsigned *old_bt_flags, - haddr_t old_addr, unsigned idx, void *udata, haddr_t *new_addr_p/*out*/) +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*/) { H5P_genplist_t *dx_plist; /* Data transfer property list */ - H5B_shared_t *shared; /* Pointer to shared B-tree info */ + H5B_shared_t *shared; /* Pointer to shared B-tree info */ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */ - unsigned new_bt_flags = H5AC__NO_FLAGS_SET; - H5B_t *new_bt = NULL; unsigned nleft, nright; /* Number of keys in left & right halves */ double split_ratios[3]; /* B-tree split ratios */ herr_t ret_value = SUCCEED; /* Return value */ @@ -405,16 +413,18 @@ H5B_split(H5F_t *f, hid_t dxpl_id, H5B_t *old_bt, unsigned *old_bt_flags, * Check arguments. */ HDassert(f); - HDassert(old_bt); - HDassert(old_bt_flags); - HDassert(H5F_addr_defined(old_addr)); + HDassert(bt_ud); + HDassert(bt_ud->bt); + HDassert(H5F_addr_defined(bt_ud->addr)); + HDassert(split_bt_ud); + HDassert(!split_bt_ud->bt); /* * Initialize variables. */ - shared = (H5B_shared_t *)H5RC_GET_OBJ(old_bt->rc_shared); + shared = (H5B_shared_t *)H5RC_GET_OBJ(bt_ud->bt->rc_shared); HDassert(shared); - HDassert(old_bt->nchildren == shared->two_k); + HDassert(bt_ud->bt->nchildren == shared->two_k); /* Get the dataset transfer property list */ if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id))) @@ -428,11 +438,11 @@ H5B_split(H5F_t *f, hid_t dxpl_id, H5B_t *old_bt, unsigned *old_bt_flags, if(H5DEBUG(B)) { const char *side; - if(!H5F_addr_defined(old_bt->left) && !H5F_addr_defined(old_bt->right)) + if(!H5F_addr_defined(bt_ud->bt->left) && !H5F_addr_defined(bt_ud->bt->right)) side = "ONLY"; - else if(!H5F_addr_defined(old_bt->right)) + else if(!H5F_addr_defined(bt_ud->bt->right)) side = "RIGHT"; - else if(!H5F_addr_defined(old_bt->left)) + else if(!H5F_addr_defined(bt_ud->bt->left)) side = "LEFT"; else side = "MIDDLE"; @@ -445,9 +455,9 @@ H5B_split(H5F_t *f, hid_t dxpl_id, H5B_t *old_bt, unsigned *old_bt_flags, * Decide how to split the children of the old node among the old node * and the new node. */ - if(!H5F_addr_defined(old_bt->right)) + if(!H5F_addr_defined(bt_ud->bt->right)) nleft = (unsigned)((double)shared->two_k * split_ratios[2]); /*right*/ - else if(!H5F_addr_defined(old_bt->left)) + else if(!H5F_addr_defined(bt_ud->bt->left)) nleft = (unsigned)((double)shared->two_k * split_ratios[0]); /*left*/ else nleft = (unsigned)((double)shared->two_k * split_ratios[1]); /*middle*/ @@ -470,69 +480,66 @@ H5B_split(H5F_t *f, hid_t dxpl_id, H5B_t *old_bt, unsigned *old_bt_flags, /* * Create the new B-tree node. */ - if(H5B_create(f, dxpl_id, shared->type, udata, new_addr_p/*out*/) < 0) + if(H5B_create(f, dxpl_id, shared->type, udata, &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.rc_shared = old_bt->rc_shared; - if(NULL == (new_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, *new_addr_p, &cache_udata, H5AC_WRITE))) + 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") - new_bt->level = old_bt->level; + split_bt_ud->bt->level = bt_ud->bt->level; /* * Copy data from the old node to the new node. */ - /* this function didn't used to mark the new bt entry as dirty. Since - * we just inserted the entry, this doesn't matter unless the entry - * somehow gets flushed between the insert and the protect. At present, - * I don't think this can happen, but it doesn't hurt to mark the entry - * dirty again. - * -- JRM - */ - new_bt_flags |= H5AC__DIRTIED_FLAG; - HDmemcpy(new_bt->native, - old_bt->native + nleft * shared->type->sizeof_nkey, + split_bt_ud->cache_flags = H5AC__DIRTIED_FLAG; + HDmemcpy(split_bt_ud->bt->native, + bt_ud->bt->native + nleft * shared->type->sizeof_nkey, (nright + 1) * shared->type->sizeof_nkey); - HDmemcpy(new_bt->child, - &old_bt->child[nleft], + HDmemcpy(split_bt_ud->bt->child, + &bt_ud->bt->child[nleft], nright * sizeof(haddr_t)); - new_bt->nchildren = nright; + split_bt_ud->bt->nchildren = nright; /* * Truncate the old node. */ - *old_bt_flags |= H5AC__DIRTIED_FLAG; - old_bt->nchildren = nleft; + bt_ud->cache_flags |= H5AC__DIRTIED_FLAG; + bt_ud->bt->nchildren = nleft; /* * Update sibling pointers. */ - new_bt->left = old_addr; - new_bt->right = old_bt->right; + split_bt_ud->bt->left = bt_ud->addr; + split_bt_ud->bt->right = bt_ud->bt->right; - if(H5F_addr_defined(old_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 */ cache_udata2.f = f; cache_udata2.type = shared->type; - cache_udata2.rc_shared = old_bt->rc_shared; - if(NULL == (tmp_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, old_bt->right, &cache_udata2, H5AC_WRITE))) + 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") - tmp_bt->left = *new_addr_p; + tmp_bt->left = split_bt_ud->addr; - if(H5AC_unprotect(f, dxpl_id, H5AC_BT, old_bt->right, tmp_bt, H5AC__DIRTIED_FLAG) < 0) + 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 */ - old_bt->right = *new_addr_p; + bt_ud->bt->right = split_bt_ud->addr; done: - if(new_bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, *new_addr_p, new_bt, new_bt_flags) < 0) - HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node") + if(ret_value < 0) { + if(split_bt_ud->bt && 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 release B-tree node") + split_bt_ud->bt = NULL; + split_bt_ud->addr = HADDR_UNDEF; + } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5B_split() */ @@ -541,8 +548,7 @@ done: /*------------------------------------------------------------------------- * Function: H5B_insert * - * Purpose: Adds a new item to the B-tree. If the root node of - * the B-tree splits then the B-tree gets a new address. + * Purpose: Adds a new item to the B-tree. * * Return: Non-negative on success/Negative on failure * @@ -565,10 +571,11 @@ H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, uint8_t *rt_key=(uint8_t*)_rt_key; hbool_t lt_key_changed = FALSE, rt_key_changed = FALSE; - haddr_t child, old_root; + haddr_t old_root_addr = HADDR_UNDEF; unsigned level; - H5B_t *bt; - H5B_t *new_bt; /* Copy of B-tree info */ + H5B_ins_ud_t bt_ud = H5B_INS_UD_T_NULL; /* (Old) root node */ + H5B_ins_ud_t split_bt_ud = H5B_INS_UD_T_NULL; /* Split B-tree node */ + H5B_t *new_root_bt = NULL; /* New root 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 */ @@ -583,118 +590,111 @@ H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, HDassert(type->sizeof_nkey <= sizeof _lt_key); HDassert(H5F_addr_defined(addr)); - if((int)(my_ins = H5B_insert_helper(f, dxpl_id, addr, type, lt_key, - <_key_changed, md_key, udata, rt_key, &rt_key_changed, &child/*out*/)) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to insert key") - if(H5B_INS_NOOP == my_ins) - HGOTO_DONE(SUCCEED) - HDassert(H5B_INS_RIGHT == my_ins); - /* 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); - /* the current root */ + /* Protect the root node */ cache_udata.f = f; cache_udata.type = type; 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 locate root of B-tree") + 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") + + /* Insert the object */ + if((int)(my_ins = H5B_insert_helper(f, dxpl_id, &bt_ud, type, lt_key, + <_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") + if(H5B_INS_NOOP == my_ins) { + 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)); - level = bt->level; + /* Get level of old root */ + level = bt_ud.bt->level; + /* update left and right keys */ if(!lt_key_changed) - HDmemcpy(lt_key, H5B_NKEY(bt,shared,0), type->sizeof_nkey); - - if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release new child") - bt = NULL; - - /* the new node */ - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child, &cache_udata, H5AC_READ))) - HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load new node") - + HDmemcpy(lt_key, H5B_NKEY(bt_ud.bt,shared,0), type->sizeof_nkey); if(!rt_key_changed) - HDmemcpy(rt_key, H5B_NKEY(bt,shared,bt->nchildren), type->sizeof_nkey); - - if(H5AC_unprotect(f, dxpl_id, H5AC_BT, child, bt, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release new child") - bt = NULL; + HDmemcpy(rt_key, H5B_NKEY(split_bt_ud.bt,shared,split_bt_ud.bt->nchildren), type->sizeof_nkey); /* - * Copy the old root node to some other file location and make the new - * root at the old root's previous address. This prevents the B-tree - * from "moving". + * Copy the old root node to some other file location and make the new root + * 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 = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)shared->sizeof_rnode))) + 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") - /* update the new child's left pointer */ - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child, &cache_udata, H5AC_WRITE))) - HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load new child") - - bt->left = old_root; - - if(H5AC_unprotect(f, dxpl_id, H5AC_BT, child, bt, H5AC__DIRTIED_FLAG) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release new child") - bt = NULL; /* Make certain future references will be caught */ - /* - * Move the node to the new location by checking it out & checking it in - * at the new location -QAK + * Move the node to the new location */ - /* Bring the old root into the cache if it's not already */ - 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 new child") - - /* Make certain the old root info is marked as dirty before moving it, */ - /* so it is certain to be written out at the new location */ /* Make a copy of the old root information */ - if(NULL == (new_bt = H5B_copy(bt))) { - HCOMMON_ERROR(H5E_BTREE, H5E_CANTCOPY, "unable to copy old root"); + if(NULL == (new_root_bt = H5B_copy(bt_ud.bt))) + HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to copy old root"); - if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__DIRTIED_FLAG) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release new child") - - HGOTO_DONE(FAIL) - } /* end if */ - - if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__DIRTIED_FLAG) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release new child") - bt = NULL; /* Make certain future references will be caught */ + /* 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, addr, old_root) < 0) + 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_bt->left = HADDR_UNDEF; - new_bt->right = HADDR_UNDEF; + new_root_bt->left = HADDR_UNDEF; + new_root_bt->right = HADDR_UNDEF; /* Set the new information for the copy */ - new_bt->level = level + 1; - new_bt->nchildren = 2; + new_root_bt->level = level + 1; + new_root_bt->nchildren = 2; - new_bt->child[0] = old_root; - HDmemcpy(H5B_NKEY(new_bt, shared, 0), lt_key, shared->type->sizeof_nkey); + new_root_bt->child[0] = bt_ud.addr; + HDmemcpy(H5B_NKEY(new_root_bt, shared, 0), lt_key, shared->type->sizeof_nkey); - new_bt->child[1] = child; - HDmemcpy(H5B_NKEY(new_bt, shared, 1), md_key, shared->type->sizeof_nkey); - HDmemcpy(H5B_NKEY(new_bt, shared, 2), rt_key, shared->type->sizeof_nkey); + new_root_bt->child[1] = split_bt_ud.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_bt, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to flush old B-tree root node") + 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") + +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"); + + if(bt_ud.bt) + 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") #ifdef H5B_DEBUG - H5B_assert(f, dxpl_id, addr, type, udata); + if(ret_value >= 0) + H5B_assert(f, dxpl_id, addr, type, udata); #endif -done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5B_insert() */ @@ -725,6 +725,7 @@ H5B_insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx, HDassert(bt); HDassert(bt_flags); + HDassert(H5F_addr_defined(child)); shared = (H5B_shared_t *)H5RC_GET_OBJ(bt->rc_shared); HDassert(shared); HDassert(bt->nchildren < shared->two_k); @@ -803,20 +804,21 @@ H5B_insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx, *------------------------------------------------------------------------- */ static H5B_ins_t -H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type, +H5B_insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, + const H5B_class_t *type, uint8_t *lt_key, hbool_t *lt_key_changed, uint8_t *md_key, void *udata, uint8_t *rt_key, hbool_t *rt_key_changed, - haddr_t *new_node_p/*out*/) + H5B_ins_ud_t *split_bt_ud/*out*/) { - unsigned bt_flags = H5AC__NO_FLAGS_SET, twin_flags = H5AC__NO_FLAGS_SET; - H5B_t *bt = NULL, *twin = NULL; + H5B_t *bt; /* Convenience pointer to B-tree */ H5RC_t *rc_shared; /* Ref-counted shared info */ - H5B_shared_t *shared; /* Pointer to shared B-tree info */ + H5B_shared_t *shared; /* Pointer to shared B-tree info */ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */ unsigned lt = 0, idx = 0, rt; /* Left, final & right index values */ int cmp = -1; /* Key comparison value */ - haddr_t child_addr = HADDR_UNDEF; + H5B_ins_ud_t child_bt_ud = H5B_INS_UD_T_NULL; /* Child B-tree */ + H5B_ins_ud_t new_child_bt_ud = H5B_INS_UD_T_NULL; /* Newly split child B-tree */ H5B_ins_t my_ins = H5B_INS_ERROR; H5B_ins_t ret_value = H5B_INS_ERROR; /* Return value */ @@ -826,7 +828,9 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * Check arguments */ HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(bt_ud); + HDassert(bt_ud->bt); + HDassert(H5F_addr_defined(bt_ud->addr)); HDassert(type); HDassert(type->decode); HDassert(type->cmp3); @@ -835,7 +839,12 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type HDassert(lt_key_changed); HDassert(rt_key); HDassert(rt_key_changed); - HDassert(new_node_p); + HDassert(split_bt_ud); + HDassert(!split_bt_ud->bt); + HDassert(!H5F_addr_defined(split_bt_ud->addr)); + HDassert(split_bt_ud->cache_flags == H5AC__NO_FLAGS_SET); + + bt = bt_ud->bt; *lt_key_changed = FALSE; *rt_key_changed = FALSE; @@ -851,11 +860,6 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * data. When the search completes IDX points to the child that * should get the new data. */ - cache_udata.f = f; - cache_udata.type = type; - 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, H5B_INS_ERROR, "unable to load node") rt = bt->nchildren; while(lt < rt && cmp) { @@ -866,6 +870,11 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type lt = idx + 1; } /* end while */ + /* Set up user data for cache callbacks */ + cache_udata.f = f; + cache_udata.type = type; + cache_udata.rc_shared = rc_shared; + if(0 == bt->nchildren) { /* * The value being inserted will be the only value in this tree. We @@ -876,13 +885,13 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type H5B_NKEY(bt, shared, 1), bt->child + 0/*out*/) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, H5B_INS_ERROR, "unable to create leaf node") bt->nchildren = 1; - bt_flags |= H5AC__DIRTIED_FLAG; + bt_ud->cache_flags |= H5AC__DIRTIED_FLAG; idx = 0; if(type->follow_min) { if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1), - rt_key_changed, &child_addr/*out*/)) < 0) + rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "unable to insert first leaf node") } /* end if */ else @@ -893,10 +902,14 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * The value being inserted is less than any value in this tree. * Follow the minimum branch out of this node to a subtree. */ - if((int)(my_ins = H5B_insert_helper(f, dxpl_id, bt->child[idx], type, + child_bt_ud.addr = bt->child[idx]; + if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC_WRITE))) + HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node") + + if((int)(my_ins = H5B_insert_helper(f, dxpl_id, &child_bt_ud, type, H5B_NKEY(bt,shared,idx), lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed, - &child_addr/*out*/)) < 0) + &new_child_bt_ud/*out*/)) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum subtree") } else if(type->follow_min) { /* @@ -906,7 +919,7 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type */ if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1), - rt_key_changed, &child_addr/*out*/)) < 0) + rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum leaf node") } else { /* @@ -917,7 +930,7 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type my_ins = H5B_INS_LEFT; HDmemcpy(md_key, H5B_NKEY(bt,shared,idx), type->sizeof_nkey); if((type->new_node)(f, dxpl_id, H5B_INS_LEFT, H5B_NKEY(bt, shared, idx), udata, - md_key, &child_addr/*out*/) < 0) + md_key, &new_child_bt_ud.addr/*out*/) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum leaf node") *lt_key_changed = TRUE; } /* end else */ @@ -935,9 +948,14 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * Follow the maximum branch out of this node to a subtree. */ idx = bt->nchildren - 1; - if((int)(my_ins = H5B_insert_helper(f, dxpl_id, bt->child[idx], type, + child_bt_ud.addr = bt->child[idx]; + if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC_WRITE))) + HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node") + + if((int)(my_ins = H5B_insert_helper(f, dxpl_id, &child_bt_ud, type, H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata, - H5B_NKEY(bt, shared, idx + 1), rt_key_changed, &child_addr/*out*/)) < 0) + H5B_NKEY(bt, shared, idx + 1), rt_key_changed, + &new_child_bt_ud/*out*/)) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum subtree") } else if(type->follow_max) { /* @@ -948,7 +966,7 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type idx = bt->nchildren - 1; if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1), - rt_key_changed, &child_addr/*out*/)) < 0) + rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum leaf node") } else { /* @@ -960,7 +978,7 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type my_ins = H5B_INS_RIGHT; HDmemcpy(md_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey); if((type->new_node)(f, dxpl_id, H5B_INS_RIGHT, md_key, udata, - H5B_NKEY(bt, shared, idx + 1), &child_addr/*out*/) < 0) + H5B_NKEY(bt, shared, idx + 1), &new_child_bt_ud.addr/*out*/) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum leaf node") *rt_key_changed = TRUE; } /* end else */ @@ -985,9 +1003,13 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * Follow a branch out of this node to another subtree. */ HDassert(idx < bt->nchildren); - if((int)(my_ins = H5B_insert_helper(f, dxpl_id, bt->child[idx], type, + child_bt_ud.addr = bt->child[idx]; + if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC_WRITE))) + HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node") + + if((int)(my_ins = H5B_insert_helper(f, dxpl_id, &child_bt_ud, type, H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata, - H5B_NKEY(bt, shared, idx + 1), rt_key_changed, &child_addr/*out*/)) < 0) + H5B_NKEY(bt, shared, idx + 1), rt_key_changed, &new_child_bt_ud/*out*/)) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert subtree") } else { /* @@ -996,7 +1018,7 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type HDassert(idx < bt->nchildren); if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1), - rt_key_changed, &child_addr/*out*/)) < 0) + rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert leaf node") } HDassert((int)my_ins >= 0); @@ -1005,18 +1027,20 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * Update the left and right keys of the current node. */ if(*lt_key_changed) { - bt_flags |= H5AC__DIRTIED_FLAG; + bt_ud->cache_flags |= H5AC__DIRTIED_FLAG; if(idx > 0) { HDassert(type->critical_key == H5B_LEFT); + HDassert(!(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins)); *lt_key_changed = FALSE; } /* end if */ else HDmemcpy(lt_key, H5B_NKEY(bt, shared, idx), type->sizeof_nkey); } /* end if */ if(*rt_key_changed) { - bt_flags |= H5AC__DIRTIED_FLAG; + bt_ud->cache_flags |= H5AC__DIRTIED_FLAG; if(idx + 1 < bt->nchildren) { HDassert(type->critical_key == H5B_RIGHT); + HDassert(!(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins)); *rt_key_changed = FALSE; } /* end if */ else @@ -1026,9 +1050,10 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type /* * The insertion simply changed the address for the child. */ - bt->child[idx] = child_addr; - bt_flags |= H5AC__DIRTIED_FLAG; - ret_value = H5B_INS_NOOP; + 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) { hbool_t *tmp_bt_flags_ptr = NULL; H5B_t *tmp_bt; @@ -1037,26 +1062,24 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * If this node is full then split it before inserting the new child. */ if(bt->nchildren == shared->two_k) { - if(H5B_split(f, dxpl_id, bt, &bt_flags, addr, idx, udata, new_node_p/*out*/) < 0) + if(H5B_split(f, dxpl_id, bt_ud, idx, udata, split_bt_ud/*out*/) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, H5B_INS_ERROR, "unable to split node") - if(NULL == (twin = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, *new_node_p, &cache_udata, H5AC_WRITE))) - HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node") if(idx < bt->nchildren) { tmp_bt = bt; - tmp_bt_flags_ptr = &bt_flags; + tmp_bt_flags_ptr = &bt_ud->cache_flags; } else { idx -= bt->nchildren; - tmp_bt = twin; - tmp_bt_flags_ptr = &twin_flags; + tmp_bt = split_bt_ud->bt; + tmp_bt_flags_ptr = &split_bt_ud->cache_flags; } } /* end if */ else { tmp_bt = bt; - tmp_bt_flags_ptr = &bt_flags; + tmp_bt_flags_ptr = &bt_ud->cache_flags; } /* end else */ /* Insert the child */ - if(H5B_insert_child(tmp_bt, tmp_bt_flags_ptr, idx, child_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") } @@ -1064,8 +1087,8 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * If this node split, return the mid key (the one that is shared * by the left and right node). */ - if(twin) { - HDmemcpy(md_key, H5B_NKEY(twin, shared, 0), type->sizeof_nkey); + if(split_bt_ud->bt) { + HDmemcpy(md_key, H5B_NKEY(split_bt_ud->bt, shared, 0), type->sizeof_nkey); ret_value = H5B_INS_RIGHT; #ifdef H5B_DEBUG /* @@ -1073,7 +1096,7 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type * in the new node. */ cmp = (type->cmp2)(H5B_NKEY(bt, shared, bt->nchildren), udata, - H5B_NKEY(twin, shared, 0)); + H5B_NKEY(split_bt_ud->bt, shared, 0)); HDassert(0 == cmp); #endif } /* end if */ @@ -1081,12 +1104,13 @@ H5B_insert_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type ret_value = H5B_INS_NOOP; done: - { - herr_t e1 = (bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, bt_flags) < 0); - herr_t e2 = (twin && H5AC_unprotect(f, dxpl_id, H5AC_BT, *new_node_p, twin, twin_flags) < 0); - if(e1 || e2) /*use vars to prevent short-circuit of side effects */ - HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node(s)") - } + 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) + HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect child") + + if(new_child_bt_ud.bt) + if(H5AC_unprotect(f, dxpl_id, H5AC_BT, new_child_bt_ud.addr, new_child_bt_ud.bt, new_child_bt_ud.cache_flags) < 0) + HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect new child") FUNC_LEAVE_NOAPI(ret_value) } |