summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/H5B2.c181
-rw-r--r--src/H5B2private.h7
-rw-r--r--src/H5Edefin.h1
-rw-r--r--src/H5Einit.h5
-rw-r--r--src/H5Epubgen.h2
-rw-r--r--src/H5Eterm.h3
-rw-r--r--src/H5err.txt1
-rw-r--r--test/btree2.c180
8 files changed, 376 insertions, 4 deletions
diff --git a/src/H5B2.c b/src/H5B2.c
index 828aebd..b82a75c 100644
--- a/src/H5B2.c
+++ b/src/H5B2.c
@@ -4051,6 +4051,187 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5B2_neighbor() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_modify
+ *
+ * Purpose: Locate the specified information in a B-tree and modify it.
+ * The UDATA can point to additional data passed
+ * to the key comparison function.
+ *
+ * The 'OP' routine is called with the record found and the
+ * OP_DATA pointer, to allow caller to modify information about
+ * the record.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 10 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_modify(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
+ void *udata, H5B2_modify_t op, void *op_data)
+{
+ H5B2_t *bt2=NULL; /* Pointer to the B-tree header */
+ H5RC_t *bt2_shared=NULL; /* Pointer to ref-counter for shared B-tree info */
+ H5B2_shared_t *shared; /* Pointer to B-tree's shared information */
+ hbool_t incr_rc=FALSE; /* Flag to indicate that we've incremented the B-tree's shared info reference count */
+ H5B2_node_ptr_t curr_node_ptr; /* Node pointer info for current node */
+ unsigned depth; /* Current depth of the tree */
+ int cmp; /* Comparison value of records */
+ unsigned idx; /* Location of record which matches key */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(H5B2_modify, FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(type);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(op);
+
+ /* Look up the B-tree header */
+ if (NULL == (bt2 = H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, type, NULL, H5AC_READ)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree header")
+
+ /* Safely grab pointer to reference counted shared B-tree info, so we can release the B-tree header if necessary */
+ bt2_shared=bt2->shared;
+ H5RC_INC(bt2_shared);
+ incr_rc=TRUE;
+
+ /* Make copy of the root node pointer to start search with */
+ curr_node_ptr = bt2->root;
+
+ /* Current depth of the tree */
+ depth=bt2->depth;
+
+ /* Release header */
+ if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_HDR, addr, bt2, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree header info")
+ bt2=NULL;
+
+ /* Get the pointer to the shared B-tree info */
+ shared=H5RC_GET_OBJ(bt2_shared);
+ HDassert(shared);
+
+ /* Check for empty tree */
+ if(curr_node_ptr.node_nrec==0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records")
+
+ /* Walk down B-tree to find record or leaf node where record is located */
+ cmp = -1;
+ while(depth>0 && cmp != 0) {
+ H5B2_internal_t *internal; /* Pointer to internal node in B-tree */
+ H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */
+
+ /* Lock B-tree current node */
+ if (NULL == (internal = H5AC_protect(f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, &(curr_node_ptr.node_nrec), bt2_shared, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node")
+
+ /* Locate node pointer for child */
+ cmp = H5B2_locate_record(shared->type, internal->nrec, shared->nat_off, internal->int_native, udata, &idx);
+ if(cmp > 0)
+ idx++;
+
+ if(cmp != 0) {
+ /* Get node pointer for next node to search */
+ next_node_ptr=internal->node_ptrs[idx];
+
+ /* Unlock current node */
+ if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Set pointer to next node to load */
+ curr_node_ptr = next_node_ptr;
+ } /* end if */
+ else {
+ hbool_t changed; /* Whether the 'modify' callback changed the record */
+
+ /* Make callback for current record */
+ if ( (op)(H5B2_INT_NREC(internal,shared,idx), op_data, &changed) <0) {
+ /* Make certain that the callback didn't modify the value if it failed */
+ HDassert(changed==FALSE);
+
+ /* Unlock current node */
+ if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ } /* end if */
+
+ /* Mark the node as dirty if it changed */
+ internal->cache_info.is_dirty = changed;
+
+ /* Unlock current node */
+ if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_DONE(SUCCEED);
+ } /* end else */
+
+ /* Decrement depth we're at in B-tree */
+ depth--;
+ } /* end while */
+
+ {
+ H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
+ hbool_t changed; /* Whether the 'modify' callback changed the record */
+
+ /* Lock B-tree leaf node */
+ if (NULL == (leaf = H5AC_protect(f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, &(curr_node_ptr.node_nrec), bt2_shared, H5AC_READ)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node")
+
+ /* Locate record */
+ cmp = H5B2_locate_record(shared->type, leaf->nrec, shared->nat_off, leaf->leaf_native, udata, &idx);
+
+ if(cmp != 0) {
+ /* Unlock leaf node */
+ if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Note: don't push error on stack, leave that to next higher level,
+ * since many times the B-tree is searched in order to determine
+ * if an object exists in the B-tree or not. -QAK
+ */
+#ifdef OLD_WAY
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "key not found in leaf node")
+#else /* OLD_WAY */
+ HGOTO_DONE(FAIL)
+#endif /* OLD_WAY */
+ } /* end if */
+ else {
+ /* Make callback for current record */
+ if ((op)(H5B2_LEAF_NREC(leaf,shared,idx), op_data, &changed) <0) {
+ /* Make certain that the callback didn't modify the value if it failed */
+ HDassert(changed==FALSE);
+
+ /* Unlock current node */
+ if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ } /* end if */
+ } /* end else */
+
+ /* Mark the node as dirty if it changed */
+ leaf->cache_info.is_dirty = changed;
+
+ /* Unlock current node */
+ if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ }
+
+done:
+ /* Check if we need to decrement the reference count for the B-tree's shared info */
+ if(incr_rc)
+ H5RC_DEC(bt2_shared);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_modify() */
+
#ifdef H5B2_DEBUG
/*-------------------------------------------------------------------------
diff --git a/src/H5B2private.h b/src/H5B2private.h
index c0abff9..da67213 100644
--- a/src/H5B2private.h
+++ b/src/H5B2private.h
@@ -59,9 +59,12 @@ typedef enum H5B2_subid_t {
/* Define the operator callback function pointer for H5B2_iterate() */
typedef int (*H5B2_operator_t)(const void *record, void *op_data);
-/* Define the 'found' callback function pointer for H5B2_find() */
+/* Define the 'found' callback function pointer for H5B2_find() & H5B2_neighbor() */
typedef herr_t (*H5B2_found_t)(const void *record, void *op_data);
+/* Define the 'modify' callback function pointer for H5B2_modify() */
+typedef herr_t (*H5B2_modify_t)(void *record, void *op_data, hbool_t *changed);
+
/* Comparisons for H5B2_neighbor() call */
typedef enum H5B2_compare_t {
H5B2_COMPARE_LESS, /* Records with keys less than query value */
@@ -111,6 +114,8 @@ H5_DLL herr_t H5B2_index(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type,
H5_DLL herr_t H5B2_neighbor(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type,
haddr_t addr, H5B2_compare_t comp, void *udata, H5B2_found_t op,
void *op_data);
+H5_DLL herr_t H5B2_modify(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type,
+ haddr_t addr, void *udata, H5B2_modify_t op, void *op_data);
H5_DLL herr_t H5B2_remove(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type,
haddr_t addr, void *udata);
H5_DLL herr_t H5B2_get_nrec(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type,
diff --git a/src/H5Edefin.h b/src/H5Edefin.h
index e606cb9..164ec4c 100644
--- a/src/H5Edefin.h
+++ b/src/H5Edefin.h
@@ -166,6 +166,7 @@ hid_t H5E_CANTREDISTRIBUTE_g = FAIL; /* Unable to redistribute records */
hid_t H5E_CANTSWAP_g = FAIL; /* Unable to swap records */
hid_t H5E_CANTINSERT_g = FAIL; /* Unable to insert object */
hid_t H5E_CANTLIST_g = FAIL; /* Unable to list node */
+hid_t H5E_CANTMODIFY_g = FAIL; /* Unable to modify record */
/* Argument errors */
hid_t H5E_UNINITIALIZED_g = FAIL; /* Information is uinitialized */
diff --git a/src/H5Einit.h b/src/H5Einit.h
index 7471494..5f68721 100644
--- a/src/H5Einit.h
+++ b/src/H5Einit.h
@@ -620,6 +620,11 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to list node"))==NULL)
HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
if((H5E_CANTLIST_g = H5I_register(H5I_ERROR_MSG, msg))<0)
HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTMODIFY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to modify record"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMODIFY_g = H5I_register(H5I_ERROR_MSG, msg))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
/* Argument errors */
assert(H5E_UNINITIALIZED_g==(-1));
diff --git a/src/H5Epubgen.h b/src/H5Epubgen.h
index ab39d3e..c88ed1f 100644
--- a/src/H5Epubgen.h
+++ b/src/H5Epubgen.h
@@ -274,6 +274,7 @@ H5_DLLVAR hid_t H5E_CANTCOMPARE_g; /* Can't compare objects */
#define H5E_CANTSWAP (H5OPEN H5E_CANTSWAP_g)
#define H5E_CANTINSERT (H5OPEN H5E_CANTINSERT_g)
#define H5E_CANTLIST (H5OPEN H5E_CANTLIST_g)
+#define H5E_CANTMODIFY (H5OPEN H5E_CANTMODIFY_g)
H5_DLLVAR hid_t H5E_NOTFOUND_g; /* Object not found */
H5_DLLVAR hid_t H5E_EXISTS_g; /* Object already exists */
H5_DLLVAR hid_t H5E_CANTENCODE_g; /* Unable to encode value */
@@ -283,6 +284,7 @@ H5_DLLVAR hid_t H5E_CANTREDISTRIBUTE_g; /* Unable to redistribute records */
H5_DLLVAR hid_t H5E_CANTSWAP_g; /* Unable to swap records */
H5_DLLVAR hid_t H5E_CANTINSERT_g; /* Unable to insert object */
H5_DLLVAR hid_t H5E_CANTLIST_g; /* Unable to list node */
+H5_DLLVAR hid_t H5E_CANTMODIFY_g; /* Unable to modify record */
/* Argument errors */
#define H5E_UNINITIALIZED (H5OPEN H5E_UNINITIALIZED_g)
diff --git a/src/H5Eterm.h b/src/H5Eterm.h
index dad89ab..b55dfcc 100644
--- a/src/H5Eterm.h
+++ b/src/H5Eterm.h
@@ -167,7 +167,8 @@ H5E_CANTSPLIT_g=
H5E_CANTREDISTRIBUTE_g=
H5E_CANTSWAP_g=
H5E_CANTINSERT_g=
-H5E_CANTLIST_g=
+H5E_CANTLIST_g=
+H5E_CANTMODIFY_g=
/* Argument errors */
H5E_UNINITIALIZED_g=
diff --git a/src/H5err.txt b/src/H5err.txt
index 495bf19..ad15a11 100644
--- a/src/H5err.txt
+++ b/src/H5err.txt
@@ -166,6 +166,7 @@ MINOR, BTREE, H5E_CANTREDISTRIBUTE, Unable to redistribute records
MINOR, BTREE, H5E_CANTSWAP, Unable to swap records
MINOR, BTREE, H5E_CANTINSERT, Unable to insert object
MINOR, BTREE, H5E_CANTLIST, Unable to list node
+MINOR, BTREE, H5E_CANTMODIFY, Unable to modify record
# Object header related errors
MINOR, OHDR, H5E_LINKCOUNT, Bad object header link count
diff --git a/test/btree2.c b/test/btree2.c
index 81d563d..615251f 100644
--- a/test/btree2.c
+++ b/test/btree2.c
@@ -104,7 +104,7 @@ find_cb(const void *_record, void *_op_data)
/*-------------------------------------------------------------------------
* Function: neighbor_cb
*
- * Purpose: v2 B-tree find callback
+ * Purpose: v2 B-tree neighbor callback
*
* Return: Success: 0
*
@@ -130,6 +130,35 @@ neighbor_cb(const void *_record, void *_op_data)
/*-------------------------------------------------------------------------
+ * Function: modify_cb
+ *
+ * Purpose: v2 B-tree modify callback
+ *
+ * Return: Success: 0
+ *
+ * Failure: 1
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 10, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+modify_cb(void *_record, void *_op_data, hbool_t *changed)
+{
+ hsize_t *record = (hsize_t *)_record;
+ hsize_t *modify = (hsize_t *)_op_data;
+
+ *record = *modify;
+ *changed = TRUE;
+
+ return(0);
+} /* end modify_cb() */
+
+
+/*-------------------------------------------------------------------------
* Function: test_insert_basic
*
* Purpose: Basic tests for the B-tree v2 code
@@ -5461,7 +5490,151 @@ error:
H5Fclose(file);
} H5E_END_TRY;
return 1;
-} /* test_find_neighbor() */
+} /* test_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_modify
+ *
+ * Purpose: Basic tests for the B-tree v2 code. This test exercises
+ * code to modify an existing record in the B-tree
+ *
+ * Return: Success: 0
+ *
+ * Failure: 1
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 10, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_modify(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 */
+ hsize_t modify; /* Modified value */
+ hsize_t found; /* Found value */
+ unsigned u; /* Local index variable */
+ herr_t ret; /* Generic error return value */
+
+ 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;
+ } /* end if */
+
+ /*
+ * Create v2 B-tree
+ */
+ 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;
+ }
+
+ /* Insert records */
+ for(u=0; u<100; u++) {
+ record=u*5;
+ if (H5B2_insert(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record)<0) {
+ H5_FAILED();
+ H5Eprint_stack(H5E_DEFAULT, stdout);
+ goto error;
+ } /* end if */
+ } /* end for */
+
+ /*
+ * Test modifying records
+ */
+ TESTING("B-tree modify: attempt to modify non-existant record");
+
+ /* Attempt to modify a non-existant record */
+ record = 3;
+ modify = 4;
+ H5E_BEGIN_TRY {
+ ret = H5B2_modify(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record, modify_cb, &modify);
+ } H5E_END_TRY;
+ /* Should fail */
+ if(ret != FAIL) TEST_ERROR;
+
+ PASSED();
+
+ TESTING("B-tree modify: modify record in leaf node");
+
+ /* Attempt to modify a record in a leaf node */
+ record = 130;
+ modify = 131;
+ if (H5B2_modify(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record, modify_cb, &modify) < 0) {
+ H5_FAILED();
+ H5Eprint_stack(H5E_DEFAULT, stdout);
+ goto error;
+ } /* end if */
+
+ /* Attempt to find modified record */
+ record = 131;
+ found = 131;
+ if(H5B2_find(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record, find_cb, &found)<0) TEST_ERROR;
+ if(found != 131) TEST_ERROR;
+
+ /* Attempt to find original record */
+ record = 130;
+ found = 130;
+ H5E_BEGIN_TRY {
+ ret = H5B2_modify(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record, modify_cb, &modify);
+ } H5E_END_TRY;
+ /* Should fail */
+ if(ret != FAIL) TEST_ERROR;
+
+ PASSED();
+
+ TESTING("B-tree modify: modify record in internal node");
+
+ /* Attempt to modify a record in an internal node */
+ record = 235;
+ modify = 237;
+ if (H5B2_modify(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record, modify_cb, &modify) < 0) {
+ H5_FAILED();
+ H5Eprint_stack(H5E_DEFAULT, stdout);
+ goto error;
+ } /* end if */
+
+ /* Attempt to find modified record */
+ record = 237;
+ found = 237;
+ if(H5B2_find(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record, find_cb, &found)<0) TEST_ERROR;
+ if(found != 237) TEST_ERROR;
+
+ /* Attempt to find original record */
+ record = 235;
+ found = 235;
+ H5E_BEGIN_TRY {
+ ret = H5B2_modify(f, H5P_DATASET_XFER_DEFAULT, H5B2_TEST, bt2_addr, &record, modify_cb, &modify);
+ } H5E_END_TRY;
+ /* Should fail */
+ if(ret != FAIL) TEST_ERROR;
+
+ PASSED();
+
+ if (H5Fclose(file)<0) TEST_ERROR;
+
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file);
+ } H5E_END_TRY;
+ return 1;
+} /* test_modify() */
/*-------------------------------------------------------------------------
@@ -5537,6 +5710,9 @@ main(void)
/* Test deleting B-trees */
nerrors += test_delete(fapl);
+ /* Test modifying B-tree records */
+ nerrors += test_modify(fapl);
+
if (nerrors) goto error;
puts("All v2 B-tree tests passed.");
h5_cleanup(FILENAME, fapl);