mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-02-17 16:10:24 +08:00
Checkpoint partially working v2 B-tree delete by index code (ifdef'ed out) for further work. Tested on: Linux/32 2.6 (chicago)
1189 lines
46 KiB
C
1189 lines
46 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* Copyright by the Board of Trustees of the University of Illinois. *
|
||
* All rights reserved. *
|
||
* *
|
||
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
||
* terms governing use, modification, and redistribution, is contained in *
|
||
* the files COPYING and Copyright.html. COPYING can be found at the root *
|
||
* of the source code distribution tree; Copyright.html can be found at the *
|
||
* root level of an installed copy of the electronic HDF5 document set and *
|
||
* is linked from the top-level documents page. It can also be found at *
|
||
* http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
||
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
/*-------------------------------------------------------------------------
|
||
*
|
||
* Created: H5B2.c
|
||
* Jan 31 2005
|
||
* Quincey Koziol <koziol@ncsa.uiuc.edu>
|
||
*
|
||
* Purpose: Implements a B-tree, with several modifications from
|
||
* the "standard" methods.
|
||
*
|
||
* Please see the documentation in:
|
||
* doc/html/TechNotes/Btrees.html for a full description
|
||
* of how they work, etc.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
|
||
/****************/
|
||
/* Module Setup */
|
||
/****************/
|
||
|
||
#define H5B2_PACKAGE /*suppress error about including H5B2pkg */
|
||
|
||
/***********/
|
||
/* Headers */
|
||
/***********/
|
||
#include "H5private.h" /* Generic Functions */
|
||
#include "H5B2pkg.h" /* v2 B-trees */
|
||
#include "H5Eprivate.h" /* Error handling */
|
||
#include "H5MFprivate.h" /* File memory management */
|
||
|
||
/****************/
|
||
/* Local Macros */
|
||
/****************/
|
||
|
||
|
||
/******************/
|
||
/* Local Typedefs */
|
||
/******************/
|
||
|
||
|
||
/********************/
|
||
/* Package Typedefs */
|
||
/********************/
|
||
|
||
|
||
/********************/
|
||
/* Local Prototypes */
|
||
/********************/
|
||
|
||
|
||
/*********************/
|
||
/* Package Variables */
|
||
/*********************/
|
||
|
||
/* Declare a free list to manage the H5B2_t struct */
|
||
H5FL_DEFINE(H5B2_t);
|
||
|
||
/*****************************/
|
||
/* Library Private Variables */
|
||
/*****************************/
|
||
|
||
|
||
/*******************/
|
||
/* Local Variables */
|
||
/*******************/
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_create
|
||
*
|
||
* Purpose: Creates a new empty B-tree in the file.
|
||
*
|
||
* Return: Non-negative on success (with address of new B-tree
|
||
* filled in), negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Jan 31 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_create(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type,
|
||
size_t node_size, size_t rrec_size,
|
||
unsigned split_percent, unsigned merge_percent, haddr_t *addr_p)
|
||
{
|
||
H5B2_t *bt2 = NULL; /* The new B-tree header information */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_create, FAIL)
|
||
|
||
/*
|
||
* Check arguments.
|
||
*/
|
||
HDassert(f);
|
||
HDassert(type);
|
||
HDassert(node_size > 0);
|
||
HDassert(rrec_size > 0);
|
||
HDassert(merge_percent > 0 && merge_percent <= 100);
|
||
HDassert(split_percent > 0 && split_percent <= 100);
|
||
HDassert(merge_percent < (split_percent / 2));
|
||
HDassert(addr_p);
|
||
|
||
/*
|
||
* Allocate file and memory data structures.
|
||
*/
|
||
if(NULL == (bt2 = H5FL_MALLOC(H5B2_t)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree header")
|
||
|
||
/* Assign internal information */
|
||
HDmemset(&bt2->cache_info, 0, sizeof(H5AC_info_t));
|
||
bt2->root.addr = HADDR_UNDEF;
|
||
bt2->root.node_nrec = 0;
|
||
bt2->root.all_nrec = 0;
|
||
|
||
/* Initialize shared B-tree info */
|
||
if(H5B2_shared_init(f, bt2, type, 0, node_size, rrec_size, split_percent, merge_percent) < 0)
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create shared B-tree info")
|
||
|
||
/* Allocate space for the header on disk */
|
||
if(HADDR_UNDEF == (*addr_p = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)H5B2_HEADER_SIZE(f))))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for B-tree header")
|
||
|
||
/* Cache the new B-tree node */
|
||
if(H5AC_set(f, dxpl_id, H5AC_BT2_HDR, *addr_p, bt2, H5AC__NO_FLAGS_SET) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't add B-tree header to cache")
|
||
|
||
done:
|
||
if(ret_value < 0) {
|
||
if(bt2)
|
||
(void)H5B2_cache_hdr_dest(f, bt2);
|
||
} /* end if */
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5B2_create() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_insert
|
||
*
|
||
* Purpose: Adds a new record to the B-tree.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 2 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_insert(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
void *udata)
|
||
{
|
||
H5B2_t *bt2 = NULL; /* Pointer to the B-tree header */
|
||
unsigned bt2_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for B-tree header */
|
||
H5B2_shared_t *shared; /* Pointer to B-tree's shared information */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_insert, FAIL)
|
||
|
||
/* Check arguments. */
|
||
HDassert(f);
|
||
HDassert(type);
|
||
HDassert(H5F_addr_defined(addr));
|
||
|
||
/* Look up the b-tree header */
|
||
if(NULL == (bt2 = H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, type, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree header")
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared = H5RC_GET_OBJ(bt2->shared);
|
||
HDassert(shared);
|
||
|
||
/* Check if the root node is allocated yet */
|
||
if(!H5F_addr_defined(bt2->root.addr)) {
|
||
/* Create root node as leaf node in B-tree */
|
||
if(H5B2_create_leaf(f, dxpl_id, bt2->shared, &(bt2->root)) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create root node")
|
||
|
||
/* Mark B-tree header as dirty, since we updated the address of the root node */
|
||
bt2_flags |= H5AC__DIRTIED_FLAG;
|
||
} /* end if */
|
||
/* Check if we need to split the root node (equiv. to a 1->2 node split) */
|
||
else if(bt2->root.node_nrec == shared->node_info[shared->depth].split_nrec) {
|
||
/* Split root node */
|
||
if(H5B2_split_root(f, dxpl_id, bt2, &bt2_flags) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split root node")
|
||
} /* end if */
|
||
|
||
/* Attempt to insert record into B-tree */
|
||
if(shared->depth > 0) {
|
||
if(H5B2_insert_internal(f, dxpl_id, bt2->shared, shared->depth, &bt2_flags, &bt2->root, udata) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree internal node")
|
||
} /* end if */
|
||
else {
|
||
if(H5B2_insert_leaf(f, dxpl_id, bt2->shared, &bt2->root, udata) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree leaf node")
|
||
} /* end else */
|
||
|
||
/* Mark parent node as dirty */
|
||
bt2_flags |= H5AC__DIRTIED_FLAG;
|
||
|
||
done:
|
||
/* Release the B-tree header info */
|
||
if(bt2 && H5AC_unprotect(f, dxpl_id, H5AC_BT2_HDR, addr, bt2, bt2_flags) < 0)
|
||
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree header info")
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* H5B2_insert() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_iterate
|
||
*
|
||
* Purpose: Iterate over all the records in the B-tree, in "in-order"
|
||
* order, making a callback for each record.
|
||
*
|
||
* If the callback returns non-zero, the iteration breaks out
|
||
* without finishing all the records.
|
||
*
|
||
* Return: Value from callback: non-negative on success, negative on error
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 11 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_iterate(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
H5B2_operator_t op, void *op_data)
|
||
{
|
||
H5B2_t *bt2=NULL; /* Pointer to the B-tree header */
|
||
H5B2_shared_t *shared; /* Pointer to B-tree's shared information */
|
||
H5RC_t *bt2_shared=NULL; /* Pointer to ref-counter for shared B-tree info */
|
||
hbool_t incr_rc=FALSE; /* Flag to indicate that we've incremented the B-tree's shared info reference count */
|
||
H5B2_node_ptr_t root_ptr; /* Node pointer info for root node */
|
||
unsigned depth; /* Current depth of the tree */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_iterate, 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;
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared = H5RC_GET_OBJ(bt2->shared);
|
||
HDassert(shared);
|
||
|
||
/* Make copy of the root node pointer */
|
||
root_ptr = bt2->root;
|
||
|
||
/* Current depth of the tree */
|
||
depth = shared->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;
|
||
|
||
/* Iterate through records */
|
||
if(root_ptr.node_nrec > 0) {
|
||
/* Iterate through nodes */
|
||
if((ret_value = H5B2_iterate_node(f, dxpl_id, bt2_shared, depth, &root_ptr, op, op_data)) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "node iteration failed")
|
||
} /* end if */
|
||
|
||
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_iterate() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_find
|
||
*
|
||
* Purpose: Locate the specified information in a B-tree and return
|
||
* that information by calling the provided 'OP' routine with an
|
||
* OP_DATA pointer. The UDATA parameter points to 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 return information about
|
||
* the record.
|
||
*
|
||
* If 'OP' is NULL, then this routine just returns "SUCCEED" when
|
||
* a record is present in the B-tree.
|
||
*
|
||
* Return: Non-negative on success, negative on failure.
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 23 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_find(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
void *udata, H5B2_found_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_find, FAIL)
|
||
|
||
/* Check arguments. */
|
||
HDassert(f);
|
||
HDassert(type);
|
||
HDassert(H5F_addr_defined(addr));
|
||
|
||
/* 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;
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared=H5RC_GET_OBJ(bt2_shared);
|
||
HDassert(shared);
|
||
|
||
/* Make copy of the root node pointer to start search with */
|
||
curr_node_ptr = bt2->root;
|
||
|
||
/* Current depth of the tree */
|
||
depth = shared->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;
|
||
|
||
/* 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 = H5B2_protect_internal(f, dxpl_id, bt2_shared, curr_node_ptr.addr, curr_node_ptr.node_nrec, depth, H5AC_READ)))
|
||
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 {
|
||
/* Make callback for current record */
|
||
if(op && (op)(H5B2_INT_NREC(internal, shared, idx), op_data) < 0) {
|
||
/* 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 */
|
||
|
||
/* 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 */
|
||
|
||
/* 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 && (op)(H5B2_LEAF_NREC(leaf, shared, idx), op_data) < 0) {
|
||
/* 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 */
|
||
|
||
/* 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")
|
||
} /* end block */
|
||
|
||
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_find() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_index
|
||
*
|
||
* Purpose: Locate the IDX'th record in a B-tree according to the
|
||
* ordering used by the B-tree. The IDX values are 0-based.
|
||
*
|
||
* The 'OP' routine is called with the record found and the
|
||
* OP_DATA pointer, to allow caller to return information about
|
||
* the record.
|
||
*
|
||
* Return: Non-negative on success, negative on failure.
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 23 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_index(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
H5_iter_order_t order, hsize_t idx, H5B2_found_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 */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_index, 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;
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared = H5RC_GET_OBJ(bt2_shared);
|
||
HDassert(shared);
|
||
|
||
/* Make copy of the root node pointer to start search with */
|
||
curr_node_ptr = bt2->root;
|
||
|
||
/* Current depth of the tree */
|
||
depth = shared->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;
|
||
|
||
/* Check for empty tree */
|
||
if(curr_node_ptr.node_nrec == 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records")
|
||
|
||
/* Check for index greater than the number of records in the tree */
|
||
if(idx >= curr_node_ptr.all_nrec)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree doesn't have that many records")
|
||
|
||
/* Check for reverse indexing and map requested index to appropriate forward index */
|
||
if(order == H5_ITER_DEC)
|
||
idx = curr_node_ptr.all_nrec - (idx + 1);
|
||
|
||
/* Walk down B-tree to find record or leaf node where record is located */
|
||
while(depth > 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 */
|
||
unsigned u; /* Local index variable */
|
||
|
||
/* Lock B-tree current node */
|
||
if(NULL == (internal = H5B2_protect_internal(f, dxpl_id, bt2_shared, curr_node_ptr.addr, curr_node_ptr.node_nrec, depth, H5AC_READ)))
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node")
|
||
|
||
/* Search for record with correct index */
|
||
for(u = 0; u < internal->nrec; u++) {
|
||
/* Check if record is in child node */
|
||
if(internal->node_ptrs[u].all_nrec > idx) {
|
||
/* Get node pointer for next node to search */
|
||
next_node_ptr = internal->node_ptrs[u];
|
||
|
||
/* 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;
|
||
|
||
/* Break out of for loop */
|
||
break;
|
||
} /* end if */
|
||
|
||
/* Check if record is in this node */
|
||
if(internal->node_ptrs[u].all_nrec == idx) {
|
||
/* Make callback for current record */
|
||
if((op)(H5B2_INT_NREC(internal, shared, u), op_data) < 0) {
|
||
/* 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 */
|
||
|
||
/* 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 if */
|
||
|
||
/* Decrement index we are looking for to account for the node we
|
||
* just advanced past.
|
||
*/
|
||
idx -= (internal->node_ptrs[u].all_nrec + 1);
|
||
} /* end for */
|
||
|
||
/* Check last node pointer */
|
||
if(u == internal->nrec) {
|
||
/* Check if record is in child node */
|
||
if(internal->node_ptrs[u].all_nrec > idx) {
|
||
/* Get node pointer for next node to search */
|
||
next_node_ptr = internal->node_ptrs[u];
|
||
|
||
/* 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
|
||
/* Index that is greater than the number of records in the tree? */
|
||
HDassert("Index off end of tree??" && 0);
|
||
} /* end if */
|
||
|
||
/* Decrement depth we're at in B-tree */
|
||
depth--;
|
||
} /* end while */
|
||
|
||
{
|
||
H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
|
||
|
||
/* 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")
|
||
|
||
/* Sanity check index */
|
||
HDassert(idx < leaf->nrec);
|
||
|
||
/* Make callback for correct record */
|
||
if((op)(H5B2_LEAF_NREC(leaf, shared, idx), op_data) < 0) {
|
||
/* 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 */
|
||
|
||
/* 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")
|
||
} /* end block */
|
||
|
||
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_index() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_remove
|
||
*
|
||
* Purpose: Removes a record from a B-tree.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 25 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_remove(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
void *udata, H5B2_remove_t op, void *op_data)
|
||
{
|
||
H5B2_t *bt2 = NULL; /* Pointer to the B-tree header */
|
||
unsigned bt2_flags = H5AC__NO_FLAGS_SET;
|
||
H5B2_shared_t *shared; /* Pointer to B-tree's shared information */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_remove, FAIL)
|
||
|
||
/* Check arguments. */
|
||
HDassert(f);
|
||
HDassert(type);
|
||
HDassert(H5F_addr_defined(addr));
|
||
|
||
/* Look up the b-tree header */
|
||
if(NULL == (bt2 = H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, type, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree header")
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared = H5RC_GET_OBJ(bt2->shared);
|
||
HDassert(shared);
|
||
|
||
/* Check for empty B-tree */
|
||
if(bt2->root.all_nrec == 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree")
|
||
|
||
/* Attempt to remove record from B-tree */
|
||
if(shared->depth > 0) {
|
||
hbool_t depth_decreased = FALSE; /* Flag to indicate whether the depth of the B-tree decreased */
|
||
|
||
if(H5B2_remove_internal(f, dxpl_id, bt2->shared, &depth_decreased, NULL, shared->depth,
|
||
&(bt2->cache_info), &bt2_flags, &bt2->root, udata, op, op_data) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node")
|
||
|
||
/* Check for decreasing the depth of the B-tree */
|
||
if(depth_decreased) {
|
||
/* Destroy free list factories for previous depth */
|
||
if(shared->node_info[shared->depth].nat_rec_fac)
|
||
if(H5FL_fac_term(shared->node_info[shared->depth].nat_rec_fac) < 0)
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's native record block factory")
|
||
if(shared->node_info[shared->depth].node_ptr_fac)
|
||
if(H5FL_fac_term(shared->node_info[shared->depth].node_ptr_fac) < 0)
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's node pointer block factory")
|
||
|
||
shared->depth -= depth_decreased;
|
||
} /* end for */
|
||
} /* end if */
|
||
else {
|
||
if(H5B2_remove_leaf(f, dxpl_id, bt2->shared, &bt2->root, udata, op, op_data) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node")
|
||
} /* end else */
|
||
|
||
/* Decrement # of records in B-tree */
|
||
bt2->root.all_nrec--;
|
||
|
||
/* Mark parent node as dirty */
|
||
bt2_flags |= H5AC__DIRTIED_FLAG;
|
||
|
||
done:
|
||
/* Release the B-tree header info */
|
||
if (bt2 && H5AC_unprotect(f, dxpl_id, H5AC_BT2_HDR, addr, bt2, bt2_flags) < 0)
|
||
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree header info")
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* H5B2_remove() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_remove_by_idx
|
||
*
|
||
* Purpose: Removes the n'th record from a B-tree.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@hdfgroup.org
|
||
* Nov 14 2006
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_remove_by_idx(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type,
|
||
haddr_t addr, H5_iter_order_t order, hsize_t idx, H5B2_remove_t op,
|
||
void *op_data)
|
||
{
|
||
H5B2_t *bt2 = NULL; /* Pointer to the B-tree header */
|
||
unsigned bt2_flags = H5AC__NO_FLAGS_SET;
|
||
H5B2_shared_t *shared; /* Pointer to B-tree's shared information */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_remove_by_idx, FAIL)
|
||
|
||
/* Check arguments. */
|
||
HDassert(f);
|
||
HDassert(type);
|
||
HDassert(H5F_addr_defined(addr));
|
||
|
||
/* Look up the b-tree header */
|
||
if(NULL == (bt2 = H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, type, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree header")
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared = H5RC_GET_OBJ(bt2->shared);
|
||
HDassert(shared);
|
||
|
||
/* Check for empty B-tree */
|
||
if(bt2->root.all_nrec == 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree")
|
||
|
||
/* Check for index greater than the number of records in the tree */
|
||
if(idx >= bt2->root.all_nrec)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree doesn't have that many records")
|
||
|
||
/* Check for reverse indexing and map requested index to appropriate forward index */
|
||
if(order == H5_ITER_DEC)
|
||
idx = bt2->root.all_nrec - (idx + 1);
|
||
|
||
/* Attempt to remove record from B-tree */
|
||
if(shared->depth > 0) {
|
||
hbool_t depth_decreased = FALSE; /* Flag to indicate whether the depth of the B-tree decreased */
|
||
|
||
if(H5B2_remove_internal_by_idx(f, dxpl_id, bt2->shared, &depth_decreased, NULL, shared->depth,
|
||
&(bt2->cache_info), &bt2_flags, &bt2->root, idx, op, op_data) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node")
|
||
|
||
/* Check for decreasing the depth of the B-tree */
|
||
if(depth_decreased) {
|
||
/* Destroy free list factories for previous depth */
|
||
if(shared->node_info[shared->depth].nat_rec_fac)
|
||
if(H5FL_fac_term(shared->node_info[shared->depth].nat_rec_fac) < 0)
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's native record block factory")
|
||
if(shared->node_info[shared->depth].node_ptr_fac)
|
||
if(H5FL_fac_term(shared->node_info[shared->depth].node_ptr_fac) < 0)
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's node pointer block factory")
|
||
|
||
shared->depth -= depth_decreased;
|
||
} /* end for */
|
||
} /* end if */
|
||
else {
|
||
if(H5B2_remove_leaf_by_idx(f, dxpl_id, bt2->shared, &bt2->root, (unsigned)idx, op, op_data) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node")
|
||
} /* end else */
|
||
|
||
/* Decrement # of records in B-tree */
|
||
bt2->root.all_nrec--;
|
||
|
||
/* Mark parent node as dirty */
|
||
bt2_flags |= H5AC__DIRTIED_FLAG;
|
||
|
||
done:
|
||
/* Release the B-tree header info */
|
||
if (bt2 && H5AC_unprotect(f, dxpl_id, H5AC_BT2_HDR, addr, bt2, bt2_flags) < 0)
|
||
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree header info")
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* H5B2_remove_by_idx() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_get_nrec
|
||
*
|
||
* Purpose: Retrieves the number of records in a B-tree
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 25 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_get_nrec(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
hsize_t *nrec)
|
||
{
|
||
H5B2_t *bt2=NULL; /* Pointer to the B-tree header */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_get_nrec, FAIL)
|
||
|
||
/* Check arguments. */
|
||
HDassert(f);
|
||
HDassert(type);
|
||
HDassert(H5F_addr_defined(addr));
|
||
HDassert(nrec);
|
||
|
||
/* 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")
|
||
|
||
/* Get B-tree number of records */
|
||
*nrec = bt2->root.all_nrec;
|
||
|
||
done:
|
||
/* Release B-tree header node */
|
||
if (bt2 && H5AC_unprotect(f, dxpl_id, H5AC_BT2_HDR, addr, bt2, H5AC__NO_FLAGS_SET) < 0)
|
||
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree header info")
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* H5B2_get_nrec() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_neighbor
|
||
*
|
||
* Purpose: Locate a record relative to the specified information in a
|
||
* B-tree and return that information by filling in fields of the
|
||
* caller-supplied UDATA pointer depending on the type of leaf node
|
||
* requested. 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 return information about
|
||
* the record.
|
||
*
|
||
* The RANGE indicates whether to search for records less than or
|
||
* equal to, or greater than or equal to the information passed
|
||
* in with UDATA.
|
||
*
|
||
* Return: Non-negative on success, negative on failure.
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Mar 8 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_neighbor(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
H5B2_compare_t range, void *udata, H5B2_found_t op, void *op_data)
|
||
{
|
||
H5B2_t *bt2 = NULL; /* Pointer to the B-tree header */
|
||
H5B2_shared_t *shared; /* Pointer to B-tree's shared information */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_neighbor, 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")
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared = H5RC_GET_OBJ(bt2->shared);
|
||
HDassert(shared);
|
||
|
||
/* Check for empty tree */
|
||
if(!H5F_addr_defined(bt2->root.addr))
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records")
|
||
|
||
/* Attempt to find neighbor record in B-tree */
|
||
if(shared->depth > 0) {
|
||
if(H5B2_neighbor_internal(f, dxpl_id, bt2->shared, shared->depth, &bt2->root, NULL, range, udata, op, op_data)<0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree internal node")
|
||
} /* end if */
|
||
else {
|
||
if(H5B2_neighbor_leaf(f, dxpl_id, bt2->shared, &bt2->root, NULL, range, udata, op, op_data)<0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree leaf node")
|
||
} /* end else */
|
||
|
||
done:
|
||
/* Release the B-tree header info */
|
||
if (bt2 && H5AC_unprotect(f, dxpl_id, H5AC_BT2_HDR, addr, bt2, H5AC__NO_FLAGS_SET) < 0)
|
||
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree header info")
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* H5B2_neighbor() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5B2_delete
|
||
*
|
||
* Purpose: Delete an entire B-tree from a file.
|
||
*
|
||
* The 'OP' routine is called for each record and the
|
||
* OP_DATA pointer, to allow caller to perform an operation as
|
||
* each record is removed from the B-tree.
|
||
*
|
||
* If 'OP' is NULL, the records are just removed in the process
|
||
* of deleting the B-tree.
|
||
*
|
||
* Note: The records are _not_ guaranteed to be visited in order.
|
||
*
|
||
* Return: Non-negative on success, negative on failure.
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Mar 9 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5B2_delete(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, haddr_t addr,
|
||
H5B2_remove_t op, void *op_data)
|
||
{
|
||
H5B2_t *bt2 = NULL; /* Pointer to the B-tree header */
|
||
H5B2_shared_t *shared; /* Pointer to B-tree's shared information */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI(H5B2_delete, FAIL)
|
||
|
||
/* Check arguments. */
|
||
HDassert(f);
|
||
HDassert(type);
|
||
HDassert(H5F_addr_defined(addr));
|
||
|
||
/* Look up the B-tree header */
|
||
if(NULL == (bt2 = H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, type, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree header")
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared = H5RC_GET_OBJ(bt2->shared);
|
||
HDassert(shared);
|
||
|
||
/* Delete all nodes in B-tree */
|
||
if(H5F_addr_defined(bt2->root.addr))
|
||
if(H5B2_delete_node(f, dxpl_id, bt2->shared, shared->depth, &bt2->root, op, op_data) < 0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete B-tree nodes")
|
||
|
||
/* Release space for B-tree node on disk */
|
||
if(H5MF_xfree(f, H5FD_MEM_BTREE, dxpl_id, addr, (hsize_t)H5B2_HEADER_SIZE(f))<0)
|
||
HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free B-tree header info")
|
||
|
||
done:
|
||
/* Release the B-tree header info */
|
||
if(bt2 && H5AC_unprotect(f, dxpl_id, H5AC_BT2_HDR, addr, bt2, H5AC__DELETED_FLAG) < 0)
|
||
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to delete B-tree header info")
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* H5B2_delete() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* 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;
|
||
|
||
/* Get the pointer to the shared B-tree info */
|
||
shared=H5RC_GET_OBJ(bt2_shared);
|
||
HDassert(shared);
|
||
|
||
/* Make copy of the root node pointer to start search with */
|
||
curr_node_ptr = bt2->root;
|
||
|
||
/* Current depth of the tree */
|
||
depth = shared->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;
|
||
|
||
/* 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) {
|
||
unsigned internal_flags = H5AC__NO_FLAGS_SET;
|
||
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 = H5B2_protect_internal(f, dxpl_id, bt2_shared, curr_node_ptr.addr, curr_node_ptr.node_nrec, depth, 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_CANTMODIFY, FAIL, "'modify' callback failed for B-tree find operation")
|
||
} /* end if */
|
||
|
||
/* Mark the node as dirty if it changed */
|
||
internal_flags |= changed ? H5AC__DIRTIED_FLAG : 0;
|
||
|
||
/* Unlock current node */
|
||
if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, internal_flags) < 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 */
|
||
|
||
{
|
||
unsigned leaf_flags = H5AC__NO_FLAGS_SET;
|
||
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_CANTMODIFY, FAIL, "'modify' callback failed for B-tree find operation")
|
||
} /* end if */
|
||
} /* end else */
|
||
|
||
/* Mark the node as dirty if it changed */
|
||
leaf_flags |= changed ? H5AC__DIRTIED_FLAG : 0;
|
||
|
||
/* Unlock current node */
|
||
if (H5AC_unprotect(f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, leaf_flags) < 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() */
|
||
|