diff options
-rw-r--r-- | src/H5B2.c | 135 | ||||
-rw-r--r-- | src/H5FL.c | 65 | ||||
-rw-r--r-- | test/btree2.c | 91 |
3 files changed, 289 insertions, 2 deletions
@@ -461,6 +461,127 @@ done: FUNC_LEAVE_NOAPI(ret_value); } /* end H5B2_split_root */ +#ifdef LATER + +/*------------------------------------------------------------------------- + * Function: H5B2_redistribute + * + * Purpose: Redistribute records between several nodes + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Feb 8 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5B2_redistribute(H5F_t *f, hid_t dxpl_id, H5B2_t *bt2, H5RC_t *bt2_shared) +{ + H5B2_shared_t *shared; /* B-tree's shared info */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5B2_split_root) + + HDassert(f); + HDassert(bt2); + HDassert(bt2_shared); + + /* Get the pointer to the shared B-tree info */ + shared=H5RC_GET_OBJ(bt2_shared); + HDassert(shared); + + if(bt2->depth==0) { + H5B2_internal_t *new_int=NULL; /* Pointer to new internal node */ + H5B2_leaf_t *old_leaf=NULL, *new_leaf=NULL; /* Pointers to old & new leaf nodes */ + H5B2_node_ptr_t new_int_ptr; /* Node pointer to manage new internal node */ + H5B2_node_ptr_t new_leaf_ptr; /* Node pointer to manage new leaf node */ + H5B2_node_ptr_t old_leaf_ptr; /* Node pointer to manage old leaf node */ + unsigned mid_record; /* Index of "middle" record in current node */ + + /* Create new leaf node */ + new_leaf_ptr.all_nrec=new_leaf_ptr.node_nrec=0; + if(H5B2_create_leaf(f, dxpl_id, bt2, &new_leaf_ptr)<0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create new leaf node") + + /* Determine "middle" record to promote to new root */ + mid_record = shared->split_leaf_nrec/2; + + /* Set "old" leaf pointer to root node */ + old_leaf_ptr = bt2->root; + + /* Protect both leafs */ + if (NULL == (old_leaf = H5AC_protect(f, dxpl_id, H5AC_BT2_LEAF, old_leaf_ptr.addr, &(old_leaf_ptr.node_nrec), bt2_shared, H5AC_WRITE))) + HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree leaf node") + if (NULL == (new_leaf = H5AC_protect(f, dxpl_id, H5AC_BT2_LEAF, new_leaf_ptr.addr, &(new_leaf_ptr.node_nrec), bt2_shared, H5AC_WRITE))) + HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree leaf node") + + /* Copy "upper half" of records to new leaf */ + HDmemcpy(new_leaf->leaf_native,H5B2_LEAF_NREC(old_leaf,shared,mid_record+1),shared->type->nkey_size*(shared->split_leaf_nrec-(mid_record+1))); + + /* Create new internal node */ + new_int_ptr.all_nrec=new_int_ptr.node_nrec=0; + if(H5B2_create_internal(f, dxpl_id, bt2, &new_int_ptr)<0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create new internal node") + + /* Protect new internal node */ + if (NULL == (new_int = H5AC_protect(f, dxpl_id, H5AC_BT2_INT, new_int_ptr.addr, &(new_int_ptr.node_nrec), bt2_shared, H5AC_WRITE))) + HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree internal node") + + /* Copy "middle" record to new internal node */ + HDmemcpy(new_int->int_native,H5B2_LEAF_NREC(old_leaf,shared,mid_record),shared->type->nkey_size); + + /* Update record counts in leaf nodes */ + old_leaf_ptr.all_nrec = old_leaf_ptr.node_nrec = old_leaf->nrec = mid_record; + new_leaf_ptr.all_nrec = new_leaf_ptr.node_nrec = new_leaf->nrec = shared->split_leaf_nrec-(mid_record+1); + + /* Mark leaf nodes as dirty */ + old_leaf->cache_info.is_dirty = TRUE; + new_leaf->cache_info.is_dirty = TRUE; + + /* Release leaf nodes */ + if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_LEAF, old_leaf_ptr.addr, old_leaf, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release B-tree leaf node") + if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_LEAF, new_leaf_ptr.addr, new_leaf, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release B-tree leaf node") + + /* Set internal node pointers to leaf nodes */ + new_int->node_ptrs[0] = old_leaf_ptr; + new_int->node_ptrs[1] = new_leaf_ptr; + + /* Update record count in new internal node */ + new_int->nrec = 1; + + /* Mark new internal node as dirty */ + new_int->cache_info.is_dirty = TRUE; + + /* Release new internal node */ + if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_INT, new_int_ptr.addr, new_int, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release B-tree internal node") + + /* Update depth of B-tree */ + bt2->depth++; + + /* Update pointer to B-tree's root node to pointer to new internal node */ + bt2->root.addr = new_int_ptr.addr; + bt2->root.node_nrec = 1; + + /* Mark B-tree header as dirty */ + bt2->cache_info.is_dirty = TRUE; + } /* end if */ + else { +HDfprintf(stderr,"%s: Need to split internal root! shared->split_int_nrec=%Zu\n",FUNC,shared->split_int_nrec); +HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split internal root node yet") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5B2_split_root */ +#endif /* LATER */ + /*------------------------------------------------------------------------- * Function: H5B2_insert @@ -572,9 +693,19 @@ H5B2_insert(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr, /* Preemptively split/redistribute a node we will enter */ if((depth==1 && child_node_ptr->node_nrec==shared->split_leaf_nrec) || (depth>1 && child_node_ptr->node_nrec==shared->split_int_nrec)) { -HDfprintf(stderr,"%s: need to split child node!, depth=%u\n",FUNC,depth); -HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split child node") /* Attempt to redistribute records among children */ + if(idx==0) { +HDfprintf(stderr,"%s: left-most child\n",FUNC); + } /* end if */ + else if(idx==(internal->nrec-1)) { +HDfprintf(stderr,"%s: right-most child\n",FUNC); + } /* end if */ + else { +HDfprintf(stderr,"%s: middle child\n",FUNC); + } /* end else */ + +HDfprintf(stderr,"%s: need to split child node!, depth=%u, idx=%d\n",FUNC,depth,idx); +HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split child node") /* Split children, if can't redistribute */ /* Update record count info for current node to reflect new # of records (in parent) */ /* Update child_node_ptr (to reflect change in location from split/redistribution) */ @@ -104,6 +104,7 @@ static herr_t H5FL_arr_gc(void); static herr_t H5FL_arr_gc_list(H5FL_arr_head_t *head); static herr_t H5FL_blk_gc(void); static herr_t H5FL_blk_gc_list(H5FL_blk_head_t *head); +static herr_t H5FL_blk_unlink(H5FL_blk_head_t *pq); /* Declare a free list to manage the H5FL_fac_head_t struct */ H5FL_DEFINE(H5FL_fac_head_t); @@ -1005,6 +1006,67 @@ done: } /* end H5FL_blk_realloc() */ +/*-------------------------------------------------------------------------- + NAME + H5FL_blk_unlink + PURPOSE + Remove a block free list from the global list of initialized block free + lists. + USAGE + void H5FL_blk_unlink(H5FL_blk_head_t *pq) + H5FL_blk_head_t *pq; IN: Block free list to remove from global list + RETURNS + Success: Non-negative + Failure: Negative + DESCRIPTION + Search through the global list of initialized block free lists and remove + a particular free list. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5FL_blk_unlink(H5FL_blk_head_t *pq) +{ + H5FL_blk_gc_node_t *last; /* Pointer to the last garbage collection node examined */ + H5FL_blk_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FL_blk_unlink) + + /* Find the node to remove from the global list */ + last=NULL; + tmp=H5FL_blk_gc_head.first; + while(tmp!=NULL) { + /* Check if the list has allocations outstanding */ + if(tmp->pq==pq) { + /* Unlink node from linked list */ + if(last==NULL) + H5FL_blk_gc_head.first=H5FL_blk_gc_head.first->next; + else + last->next=tmp->next; + + /* Free the block node */ + H5MM_xfree(tmp); + + /* Leave now */ + break; + } /* end if */ + + /* Advance to next node in list */ + last=tmp; + tmp=tmp->next; + } /* end while */ + + if(tmp==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't release block free list") + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FL_blk_unlink() */ + + /*------------------------------------------------------------------------- * Function: H5FL_blk_gc_list * @@ -1954,6 +2016,9 @@ H5FL_fac_term(H5FL_fac_head_t *factory) if(factory->queue.allocated>0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "factory still has objects allocated") + /* Unlink block free list for factory from global free list */ + H5FL_blk_unlink(&(factory->queue)); + /* Free factory info */ H5FL_FREE(H5FL_fac_head_t,factory); diff --git a/test/btree2.c b/test/btree2.c index f0d13b1..6366147 100644 --- a/test/btree2.c +++ b/test/btree2.c @@ -227,6 +227,92 @@ error: /*------------------------------------------------------------------------- + * Function: test_insert_level1_2leaf_redistrib + * + * Purpose: Basic tests for the B-tree v2 code. This test inserts enough + * records to split the root node and force the tree to depth 1. + * It continues to add a more records to the each of the + * left and right leaf nodes after the split to force a 2 node + * redistribution + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Quincey Koziol + * Tuesday, February 8, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +test_insert_level1_2leaf_redistrib(hid_t fapl) +{ + hid_t file=-1; + char filename[1024]; + H5F_t *f=NULL; + hsize_t record; /* Record to insert into tree */ + haddr_t bt2_addr; /* Address of B-tree created */ + unsigned u; /* Local index variable */ + + h5_fixname(FILENAME[0], fapl, filename, sizeof filename); + + /* Create the file to work on */ + if ((file=H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl))<0) TEST_ERROR; + + /* Get a pointer to the internal file object */ + if (NULL==(f=H5I_object(file))) { + H5Eprint_stack(H5E_DEFAULT, stdout); + goto error; + } + + /* + * Test v2 B-tree creation + */ + if (H5B2_create(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, 512, 8, 100, 40, &bt2_addr/*out*/)<0) { + H5_FAILED(); + H5Eprint_stack(H5E_DEFAULT, stdout); + goto error; + } + + /* + * Test inserting many records into v2 B-tree + */ + TESTING("B-tree many - redistribute 2 leaves in level 1 B-tree"); + + for(u=0; u<INSERT_SPLIT_ROOT_NREC; u++) { + record=u+INSERT_SPLIT_ROOT_NREC/2; + if (H5B2_insert(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record)<0) { + H5_FAILED(); + H5Eprint_stack(H5E_DEFAULT, stdout); + goto error; + } + } + for(u=0; u<INSERT_SPLIT_ROOT_NREC/2; u++) { + record=u; + if (H5B2_insert(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record)<0) { + H5_FAILED(); + H5Eprint_stack(H5E_DEFAULT, stdout); + goto error; + } + } + + PASSED(); + + if (H5Fclose(file)<0) TEST_ERROR; + + return 0; + +error: + H5E_BEGIN_TRY { + H5Fclose(file); + } H5E_END_TRY; + return 1; +} /* test_insert_level1_2leaf_redistrib() */ + + +/*------------------------------------------------------------------------- * Function: main * * Purpose: Test the B-tree v2 code @@ -255,6 +341,11 @@ main(void) /* Test basic B-tree insertion */ nerrors += test_insert_basic(fapl); nerrors += test_insert_split_root(fapl); +#ifdef QAK + nerrors += test_insert_level1_2leaf_redistrib(fapl); +#else /* QAK */ +HDfprintf(stderr,"Uncomment test!\n"); +#endif /* QAK */ if (nerrors) goto error; puts("All v2 B-tree tests passed."); |