summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/H5B2.c135
-rw-r--r--src/H5FL.c65
-rw-r--r--test/btree2.c91
3 files changed, 289 insertions, 2 deletions
diff --git a/src/H5B2.c b/src/H5B2.c
index 05d8f54..087f0c7 100644
--- a/src/H5B2.c
+++ b/src/H5B2.c
@@ -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) */
diff --git a/src/H5FL.c b/src/H5FL.c
index be5ff8d..4b39fd9 100644
--- a/src/H5FL.c
+++ b/src/H5FL.c
@@ -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.");