Coverage Report

Created: 2026-02-23 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5B2.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*-------------------------------------------------------------------------
14
 *
15
 * Created:   H5B2.c
16
 *
17
 * Purpose:   Implements a B-tree, with several modifications from
18
 *                      the "standard" methods.
19
 *
20
 *                      Please see the documentation in:
21
 *                      doc/html/TechNotes/Btrees.html for a full description
22
 *                      of how they work, etc.
23
 *
24
 *-------------------------------------------------------------------------
25
 */
26
27
/****************/
28
/* Module Setup */
29
/****************/
30
31
#include "H5B2module.h" /* This source code file is part of the H5B2 module */
32
33
/***********/
34
/* Headers */
35
/***********/
36
#include "H5private.h"   /* Generic Functions     */
37
#include "H5B2pkg.h"     /* v2 B-trees        */
38
#include "H5Eprivate.h"  /* Error handling        */
39
#include "H5FLprivate.h" /* Free Lists                               */
40
#include "H5MMprivate.h" /* Memory management     */
41
42
/****************/
43
/* Local Macros */
44
/****************/
45
46
/******************/
47
/* Local Typedefs */
48
/******************/
49
50
/********************/
51
/* Package Typedefs */
52
/********************/
53
54
/********************/
55
/* Local Prototypes */
56
/********************/
57
58
/*********************/
59
/* Package Variables */
60
/*********************/
61
62
/* Package initialization variable */
63
bool H5_PKG_INIT_VAR = false;
64
65
/* v2 B-tree client ID to class mapping */
66
67
/* Remember to add client ID to H5B2_subid_t in H5B2private.h when adding a new
68
 * client class..
69
 */
70
extern const H5B2_class_t H5B2_TEST[1];
71
extern const H5B2_class_t H5HF_HUGE_BT2_INDIR[1];
72
extern const H5B2_class_t H5HF_HUGE_BT2_FILT_INDIR[1];
73
extern const H5B2_class_t H5HF_HUGE_BT2_DIR[1];
74
extern const H5B2_class_t H5HF_HUGE_BT2_FILT_DIR[1];
75
extern const H5B2_class_t H5G_BT2_NAME[1];
76
extern const H5B2_class_t H5G_BT2_CORDER[1];
77
extern const H5B2_class_t H5SM_INDEX[1];
78
extern const H5B2_class_t H5A_BT2_NAME[1];
79
extern const H5B2_class_t H5A_BT2_CORDER[1];
80
extern const H5B2_class_t H5D_BT2[1];
81
extern const H5B2_class_t H5D_BT2_FILT[1];
82
extern const H5B2_class_t H5B2_TEST2[1];
83
84
const H5B2_class_t *const H5B2_client_class_g[] = {
85
    H5B2_TEST,                /* 0 - H5B2_TEST_ID       */
86
    H5HF_HUGE_BT2_INDIR,      /* 1 - H5B2_FHEAP_HUGE_INDIR_ID   */
87
    H5HF_HUGE_BT2_FILT_INDIR, /* 2 - H5B2_FHEAP_HUGE_FILT_INDIR_ID  */
88
    H5HF_HUGE_BT2_DIR,        /* 3 - H5B2_FHEAP_HUGE_DIR_ID     */
89
    H5HF_HUGE_BT2_FILT_DIR,   /* 4 - H5B2_FHEAP_HUGE_FILT_DIR_ID  */
90
    H5G_BT2_NAME,             /* 5 - H5B2_GRP_DENSE_NAME_ID     */
91
    H5G_BT2_CORDER,           /* 6 - H5B2_GRP_DENSE_CORDER_ID   */
92
    H5SM_INDEX,               /* 7 - H5B2_SOHM_INDEX_ID     */
93
    H5A_BT2_NAME,             /* 8 - H5B2_ATTR_DENSE_NAME_ID    */
94
    H5A_BT2_CORDER,           /* 9 - H5B2_ATTR_DENSE_CORDER_ID  */
95
    H5D_BT2,                  /* 10 - H5B2_CDSET_ID                   */
96
    H5D_BT2_FILT,             /* 11 - H5B2_CDSET_FILT_ID              */
97
    H5B2_TEST2                /* 12 - H5B2_TEST_ID      */
98
};
99
100
/*****************************/
101
/* Library Private Variables */
102
/*****************************/
103
104
/*******************/
105
/* Local Variables */
106
/*******************/
107
108
/* Declare a free list to manage the H5B2_t struct */
109
H5FL_DEFINE_STATIC(H5B2_t);
110
111
/*-------------------------------------------------------------------------
112
 * Function:  H5B2_create
113
 *
114
 * Purpose: Creates a new empty B-tree in the file.
115
 *
116
 * Return:  Non-negative on success (with address of new B-tree
117
 *              filled in), negative on failure
118
 *
119
 *-------------------------------------------------------------------------
120
 */
121
H5B2_t *
122
H5B2_create(H5F_t *f, const H5B2_create_t *cparam, void *ctx_udata)
123
0
{
124
0
    H5B2_t     *bt2 = NULL;       /* Pointer to the B-tree */
125
0
    H5B2_hdr_t *hdr = NULL;       /* Pointer to the B-tree header */
126
0
    haddr_t     hdr_addr;         /* B-tree header address */
127
0
    H5B2_t     *ret_value = NULL; /* Return value */
128
129
0
    FUNC_ENTER_NOAPI(NULL)
130
131
    /*
132
     * Check arguments.
133
     */
134
0
    assert(f);
135
0
    assert(cparam);
136
137
    /* H5B2 interface sanity check */
138
0
    HDcompile_assert(H5B2_NUM_BTREE_ID == NELMTS(H5B2_client_class_g));
139
140
    /* Create shared v2 B-tree header */
141
0
    if (HADDR_UNDEF == (hdr_addr = H5B2__hdr_create(f, cparam, ctx_udata)))
142
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't create v2 B-tree header");
143
144
    /* Create v2 B-tree wrapper */
145
0
    if (NULL == (bt2 = H5FL_MALLOC(H5B2_t)))
146
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for v2 B-tree info");
147
148
    /* Look up the B-tree header */
149
0
    if (NULL == (hdr = H5B2__hdr_protect(f, hdr_addr, ctx_udata, H5AC__NO_FLAGS_SET)))
150
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect v2 B-tree header");
151
152
    /* Point v2 B-tree wrapper at header and bump it's ref count */
153
0
    bt2->hdr = hdr;
154
0
    if (H5B2__hdr_incr(bt2->hdr) < 0)
155
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL,
156
0
                    "can't increment reference count on shared v2 B-tree header");
157
158
    /* Increment # of files using this v2 B-tree header */
159
0
    if (H5B2__hdr_fuse_incr(bt2->hdr) < 0)
160
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL,
161
0
                    "can't increment file reference count on shared v2 B-tree header");
162
163
    /* Set file pointer for this v2 B-tree open context */
164
0
    bt2->f = f;
165
166
    /* Set the return value */
167
0
    ret_value = bt2;
168
169
0
done:
170
0
    if (hdr && H5B2__hdr_unprotect(hdr, H5AC__NO_FLAGS_SET) < 0)
171
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, "unable to release v2 B-tree header");
172
0
    if (!ret_value && bt2)
173
0
        if (H5B2_close(bt2) < 0)
174
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTCLOSEOBJ, NULL, "unable to close v2 B-tree");
175
176
0
    FUNC_LEAVE_NOAPI(ret_value)
177
0
} /* end H5B2_create() */
178
179
/*-------------------------------------------------------------------------
180
 * Function:  H5B2_open
181
 *
182
 * Purpose: Opens an existing v2 B-tree in the file.
183
 *
184
 * Return:  Pointer to v2 B-tree wrapper on success
185
 *              NULL on failure
186
 *
187
 *-------------------------------------------------------------------------
188
 */
189
H5B2_t *
190
H5B2_open(H5F_t *f, haddr_t addr, void *ctx_udata)
191
0
{
192
0
    H5B2_t     *bt2       = NULL; /* Pointer to the B-tree */
193
0
    H5B2_hdr_t *hdr       = NULL; /* Pointer to the B-tree header */
194
0
    H5B2_t     *ret_value = NULL; /* Return value */
195
196
0
    FUNC_ENTER_NOAPI_NOINIT
197
198
    /* Check arguments. */
199
0
    assert(f);
200
0
    assert(H5_addr_defined(addr));
201
202
    /* Look up the B-tree header */
203
0
    if (NULL == (hdr = H5B2__hdr_protect(f, addr, ctx_udata, H5AC__READ_ONLY_FLAG)))
204
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect v2 B-tree header");
205
206
    /* Check for pending heap deletion */
207
0
    if (hdr->pending_delete)
208
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTOPENOBJ, NULL, "can't open v2 B-tree pending deletion");
209
210
    /* Create v2 B-tree info */
211
0
    if (NULL == (bt2 = H5FL_MALLOC(H5B2_t)))
212
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for v2 B-tree info");
213
214
    /* Point v2 B-tree wrapper at header */
215
0
    bt2->hdr = hdr;
216
0
    if (H5B2__hdr_incr(bt2->hdr) < 0)
217
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL,
218
0
                    "can't increment reference count on shared v2 B-tree header");
219
220
    /* Increment # of files using this v2 B-tree header */
221
0
    if (H5B2__hdr_fuse_incr(bt2->hdr) < 0)
222
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL,
223
0
                    "can't increment file reference count on shared v2 B-tree header");
224
225
    /* Set file pointer for this v2 B-tree open context */
226
0
    bt2->f = f;
227
228
    /* Set the return value */
229
0
    ret_value = bt2;
230
231
0
done:
232
0
    if (hdr && H5B2__hdr_unprotect(hdr, H5AC__NO_FLAGS_SET) < 0)
233
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, "unable to release v2 B-tree header");
234
0
    if (!ret_value && bt2)
235
0
        if (H5B2_close(bt2) < 0)
236
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTCLOSEOBJ, NULL, "unable to close v2 B-tree");
237
238
0
    FUNC_LEAVE_NOAPI(ret_value)
239
0
} /* H5B2_open() */
240
241
/*-------------------------------------------------------------------------
242
 * Function:  H5B2_insert
243
 *
244
 * Purpose: Adds a new record to the B-tree.
245
 *
246
 * Return:  Non-negative on success/Negative on failure
247
 *
248
 *-------------------------------------------------------------------------
249
 */
250
herr_t
251
H5B2_insert(H5B2_t *bt2, void *udata)
252
0
{
253
0
    H5B2_hdr_t *hdr;                 /* Pointer to the B-tree header */
254
0
    herr_t      ret_value = SUCCEED; /* Return value */
255
256
0
    FUNC_ENTER_NOAPI(FAIL)
257
258
    /* Check arguments. */
259
0
    assert(bt2);
260
0
    assert(udata);
261
262
    /* Set the shared v2 B-tree header's file context for this operation */
263
0
    bt2->hdr->f = bt2->f;
264
265
    /* Get the v2 B-tree header */
266
0
    hdr = bt2->hdr;
267
268
    /* Insert the record */
269
0
    if (H5B2__insert(hdr, udata) < 0)
270
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree");
271
272
0
done:
273
0
    FUNC_LEAVE_NOAPI(ret_value)
274
0
} /* H5B2_insert() */
275
276
/*-------------------------------------------------------------------------
277
 * Function:  H5B2_update
278
 *
279
 * Purpose: Insert or modify a record to the B-tree.
280
 *    If the record exists already, it is modified as if H5B2_modify
281
 *    was called).  If it doesn't exist, it is inserted as if
282
 *    H5B2_insert was called.
283
 *
284
 * Return:  Non-negative on success/Negative on failure
285
 *
286
 *-------------------------------------------------------------------------
287
 */
288
herr_t
289
H5B2_update(H5B2_t *bt2, void *udata, H5B2_modify_t op, void *op_data)
290
0
{
291
0
    H5B2_hdr_t          *hdr;                             /* Pointer to the B-tree header */
292
0
    H5B2_update_status_t status    = H5B2_UPDATE_UNKNOWN; /* Whether the record was inserted/modified */
293
0
    herr_t               ret_value = SUCCEED;             /* Return value */
294
295
0
    FUNC_ENTER_NOAPI(FAIL)
296
297
    /* Check arguments. */
298
0
    assert(bt2);
299
0
    assert(udata);
300
301
    /* Set the shared v2 B-tree header's file context for this operation */
302
0
    bt2->hdr->f = bt2->f;
303
304
    /* Get the v2 B-tree header */
305
0
    hdr = bt2->hdr;
306
307
    /* Check if the root node is allocated yet */
308
0
    if (!H5_addr_defined(hdr->root.addr)) {
309
        /* Create root node as leaf node in B-tree */
310
0
        if (H5B2__create_leaf(hdr, hdr, &(hdr->root)) < 0)
311
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create root node");
312
0
    } /* end if */
313
314
    /* Attempt to insert record into B-tree */
315
0
    if (hdr->depth > 0) {
316
0
        if (H5B2__update_internal(hdr, hdr->depth, NULL, &hdr->root, &status, H5B2_POS_ROOT, hdr, udata, op,
317
0
                                  op_data) < 0)
318
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update record in B-tree internal node");
319
0
    } /* end if */
320
0
    else {
321
0
        if (H5B2__update_leaf(hdr, &hdr->root, &status, H5B2_POS_ROOT, hdr, udata, op, op_data) < 0)
322
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update record in B-tree leaf node");
323
0
    } /* end else */
324
325
    /* Sanity check */
326
0
    assert(H5B2_UPDATE_UNKNOWN != status);
327
328
    /* Use insert algorithm if nodes to leaf full */
329
0
    if (H5B2_UPDATE_INSERT_CHILD_FULL == status) {
330
0
        if (H5B2__insert(hdr, udata) < 0)
331
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree");
332
0
    } /* end if */
333
0
    else if (H5B2_UPDATE_SHADOW_DONE == status || H5B2_UPDATE_INSERT_DONE == status) {
334
        /* Mark B-tree header as dirty */
335
0
        if (H5B2__hdr_dirty(hdr) < 0)
336
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark B-tree header dirty");
337
0
    } /* end else-if */
338
0
    else {
339
        /* Sanity check */
340
0
        assert(H5B2_UPDATE_MODIFY_DONE == status);
341
0
    } /* end else */
342
343
0
done:
344
0
    FUNC_LEAVE_NOAPI(ret_value)
345
0
} /* H5B2_update() */
346
347
/*-------------------------------------------------------------------------
348
 * Function:  H5B2_get_addr
349
 *
350
 * Purpose: Get the address of a v2 B-tree
351
 *
352
 * Return:  SUCCEED/FAIL
353
 *
354
 *-------------------------------------------------------------------------
355
 */
356
herr_t
357
H5B2_get_addr(const H5B2_t *bt2, haddr_t *addr_p)
358
0
{
359
0
    FUNC_ENTER_NOAPI_NOERR
360
361
    /*
362
     * Check arguments.
363
     */
364
0
    assert(bt2);
365
0
    assert(addr_p);
366
367
    /* Retrieve the header address for this v2 B-tree */
368
0
    *addr_p = bt2->hdr->addr;
369
370
0
    FUNC_LEAVE_NOAPI(SUCCEED)
371
0
} /* end H5B2_get_addr() */
372
373
/*-------------------------------------------------------------------------
374
 * Function:  H5B2_iterate
375
 *
376
 * Purpose: Iterate over all the records in the B-tree, in "in-order"
377
 *    order, making a callback for each record.
378
 *
379
 *              If the callback returns non-zero, the iteration breaks out
380
 *              without finishing all the records.
381
 *
382
 * Return:  Value from callback: non-negative on success, negative on error
383
 *
384
 *-------------------------------------------------------------------------
385
 */
386
herr_t
387
H5B2_iterate(H5B2_t *bt2, H5B2_operator_t op, void *op_data)
388
0
{
389
0
    H5B2_hdr_t *hdr;                 /* Pointer to the B-tree header */
390
0
    herr_t      ret_value = SUCCEED; /* Return value */
391
392
0
    FUNC_ENTER_NOAPI_NOERR
393
394
    /* Check arguments. */
395
0
    assert(bt2);
396
0
    assert(op);
397
398
    /* Set the shared v2 B-tree header's file context for this operation */
399
0
    bt2->hdr->f = bt2->f;
400
401
    /* Get the v2 B-tree header */
402
0
    hdr = bt2->hdr;
403
404
    /* Iterate through records */
405
0
    if (hdr->root.node_nrec > 0)
406
        /* Iterate through nodes */
407
0
        if ((ret_value = H5B2__iterate_node(hdr, hdr->depth, &hdr->root, hdr, op, op_data)) < 0)
408
0
            HERROR(H5E_BTREE, H5E_CANTLIST, "node iteration failed");
409
410
0
    FUNC_LEAVE_NOAPI(ret_value)
411
0
} /* H5B2_iterate() */
412
413
/*-------------------------------------------------------------------------
414
 * Function:  H5B2_find
415
 *
416
 * Purpose: Locate the specified information in a B-tree and return
417
 *    that information by calling the provided 'OP' routine with an
418
 *    OP_DATA pointer.  The UDATA parameter points to data passed
419
 *    to the key comparison function.
420
 *
421
 *              The 'OP' routine is called with the record found and the
422
 *              OP_DATA pointer, to allow caller to return information about
423
 *              the record.
424
 *
425
 *              If 'OP' is NULL, then this routine just returns true when
426
 *              a record is present in the B-tree.
427
 *
428
 * Return:  SUCCEED/FAIL
429
 *
430
 *-------------------------------------------------------------------------
431
 */
432
herr_t
433
H5B2_find(H5B2_t *bt2, void *udata, bool *found, H5B2_found_t op, void *op_data)
434
0
{
435
0
    H5B2_hdr_t     *hdr;                 /* Pointer to the B-tree header */
436
0
    H5B2_node_ptr_t curr_node_ptr;       /* Node pointer info for current node */
437
0
    void           *parent = NULL;       /* Parent of current node */
438
0
    uint16_t        depth;               /* Current depth of the tree */
439
0
    int             cmp;                 /* Comparison value of records */
440
0
    unsigned        idx;                 /* Location of record which matches key */
441
0
    H5B2_nodepos_t  curr_pos;            /* Position of the current node */
442
0
    herr_t          ret_value = SUCCEED; /* Return value */
443
444
0
    FUNC_ENTER_NOAPI(FAIL)
445
446
    /* Check arguments. */
447
0
    assert(bt2);
448
0
    assert(found);
449
450
    /* Set the shared v2 B-tree header's file context for this operation */
451
0
    bt2->hdr->f = bt2->f;
452
453
    /* Get the v2 B-tree header */
454
0
    hdr = bt2->hdr;
455
456
    /* Make copy of the root node pointer to start search with */
457
0
    curr_node_ptr = hdr->root;
458
459
    /* Check for empty tree */
460
0
    if (curr_node_ptr.node_nrec == 0) {
461
0
        *found = false;
462
0
        HGOTO_DONE(SUCCEED);
463
0
    }
464
465
    /* Check record against min & max records in tree, to attempt to quickly
466
     *  find candidates or avoid further searching.
467
     */
468
0
    if (hdr->min_native_rec != NULL) {
469
0
        if ((hdr->cls->compare)(udata, hdr->min_native_rec, &cmp) < 0)
470
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
471
0
        if (cmp < 0) {
472
0
            *found = false; /* Less than the least record--not found */
473
0
            HGOTO_DONE(SUCCEED);
474
0
        }
475
0
        else if (cmp == 0) { /* Record is found */
476
0
            if (op && (op)(hdr->min_native_rec, op_data) < 0)
477
0
                HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
478
0
                            "'found' callback failed for B-tree find operation");
479
0
            *found = true;
480
0
            HGOTO_DONE(SUCCEED);
481
0
        } /* end if */
482
0
    }     /* end if */
483
0
    if (hdr->max_native_rec != NULL) {
484
0
        if ((hdr->cls->compare)(udata, hdr->max_native_rec, &cmp) < 0)
485
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
486
0
        if (cmp > 0) {
487
0
            *found = false; /* Greater than the largest record--not found */
488
0
            HGOTO_DONE(SUCCEED);
489
0
        }
490
0
        else if (cmp == 0) { /* Record is found */
491
0
            if (op && (op)(hdr->max_native_rec, op_data) < 0)
492
0
                HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
493
0
                            "'found' callback failed for B-tree find operation");
494
0
            *found = true;
495
0
            HGOTO_DONE(SUCCEED);
496
0
        } /* end if */
497
0
    }     /* end if */
498
499
    /* Current depth of the tree */
500
0
    depth = hdr->depth;
501
502
    /* Set initial parent, if doing swmr writes */
503
0
    if (hdr->swmr_write)
504
0
        parent = hdr;
505
506
    /* Walk down B-tree to find record or leaf node where record is located */
507
0
    cmp      = -1;
508
0
    curr_pos = H5B2_POS_ROOT;
509
0
    while (depth > 0) {
510
0
        H5B2_internal_t *internal;      /* Pointer to internal node in B-tree */
511
0
        H5B2_node_ptr_t  next_node_ptr; /* Node pointer info for next node */
512
513
        /* Lock B-tree current node */
514
0
        if (NULL == (internal = H5B2__protect_internal(hdr, parent, &curr_node_ptr, depth, false,
515
0
                                                       H5AC__READ_ONLY_FLAG)))
516
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node");
517
518
        /* Unpin parent if necessary */
519
0
        if (parent) {
520
0
            if (parent != hdr && H5AC_unpin_entry(parent) < 0)
521
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
522
0
            parent = NULL;
523
0
        } /* end if */
524
525
        /* Locate node pointer for child */
526
0
        if (H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx,
527
0
                                &cmp) < 0) {
528
            /* Unlock current node before failing */
529
0
            H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET);
530
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
531
0
        } /* end if */
532
533
0
        if (cmp > 0)
534
0
            idx++;
535
0
        if (cmp != 0) {
536
            /* Get node pointer for next node to search */
537
0
            next_node_ptr = internal->node_ptrs[idx];
538
539
            /* Set the position of the next node */
540
0
            if (H5B2_POS_MIDDLE != curr_pos) {
541
0
                if (idx == 0) {
542
0
                    if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
543
0
                        curr_pos = H5B2_POS_LEFT;
544
0
                    else
545
0
                        curr_pos = H5B2_POS_MIDDLE;
546
0
                } /* end if */
547
0
                else if (idx == internal->nrec) {
548
0
                    if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
549
0
                        curr_pos = H5B2_POS_RIGHT;
550
0
                    else
551
0
                        curr_pos = H5B2_POS_MIDDLE;
552
0
                } /* end if */
553
0
                else
554
0
                    curr_pos = H5B2_POS_MIDDLE;
555
0
            } /* end if */
556
557
            /* Unlock current node */
558
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal,
559
0
                               (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
560
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
561
562
            /* Keep track of parent if necessary */
563
0
            if (hdr->swmr_write)
564
0
                parent = internal;
565
566
            /* Set pointer to next node to load */
567
0
            curr_node_ptr = next_node_ptr;
568
0
        } /* end if */
569
0
        else {
570
            /* Make callback for current record */
571
0
            if (op && (op)(H5B2_INT_NREC(internal, hdr, idx), op_data) < 0) {
572
                /* Unlock current node */
573
0
                if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) <
574
0
                    0)
575
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
576
577
0
                HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
578
0
                            "'found' callback failed for B-tree find operation");
579
0
            } /* end if */
580
581
            /* Unlock current node */
582
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
583
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
584
585
            /* Indicate record found */
586
0
            *found = true;
587
0
            HGOTO_DONE(SUCCEED);
588
0
        } /* end else */
589
590
        /* Decrement depth we're at in B-tree */
591
0
        depth--;
592
0
    } /* end while */
593
594
0
    {
595
0
        H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
596
597
        /* Lock B-tree leaf node */
598
0
        if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, &curr_node_ptr, false, H5AC__READ_ONLY_FLAG)))
599
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
600
601
        /* Unpin parent if necessary */
602
0
        if (parent) {
603
0
            if (parent != hdr && H5AC_unpin_entry(parent) < 0)
604
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
605
0
            parent = NULL;
606
0
        } /* end if */
607
608
        /* Locate record */
609
0
        if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) <
610
0
            0) {
611
            /* Unlock current node before failing */
612
0
            H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET);
613
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
614
0
        } /* end if */
615
616
0
        if (cmp != 0) {
617
            /* Unlock leaf node */
618
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
619
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
620
621
            /* Record not found */
622
0
            *found = false;
623
0
            HGOTO_DONE(SUCCEED);
624
0
        } /* end if */
625
0
        else {
626
            /* Make callback for current record */
627
0
            if (op && (op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0) {
628
                /* Unlock current node */
629
0
                if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
630
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
631
632
0
                HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
633
0
                            "'found' callback failed for B-tree find operation");
634
0
            } /* end if */
635
636
            /* Check for record being the min or max for the tree */
637
            /* (Don't use 'else' for the idx check, to allow for root leaf node) */
638
0
            if (H5B2_POS_MIDDLE != curr_pos) {
639
0
                if (idx == 0) {
640
0
                    if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
641
0
                        if (hdr->min_native_rec == NULL)
642
0
                            if (NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
643
0
                                HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
644
0
                                            "memory allocation failed for v2 B-tree min record info");
645
0
                        H5MM_memcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
646
0
                    } /* end if */
647
0
                }     /* end if */
648
0
                if (idx == (unsigned)(leaf->nrec - 1)) {
649
0
                    if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
650
0
                        if (hdr->max_native_rec == NULL)
651
0
                            if (NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
652
0
                                HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
653
0
                                            "memory allocation failed for v2 B-tree max record info");
654
0
                        H5MM_memcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
655
0
                    } /* end if */
656
0
                }     /* end if */
657
0
            }         /* end if */
658
0
        }             /* end else */
659
660
        /* Unlock current node */
661
0
        if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
662
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
663
664
        /* Indicate record found */
665
0
        *found = true;
666
0
    } /* end block */
667
668
0
done:
669
0
    if (parent) {
670
0
        assert(ret_value < 0);
671
0
        if (parent != hdr && H5AC_unpin_entry(parent) < 0)
672
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
673
0
    } /* end if */
674
675
0
    FUNC_LEAVE_NOAPI(ret_value)
676
0
} /* H5B2_find() */
677
678
/*-------------------------------------------------------------------------
679
 * Function:  H5B2_index
680
 *
681
 * Purpose: Locate the IDX'th record in a B-tree according to the
682
 *              ordering used by the B-tree.  The IDX values are 0-based.
683
 *
684
 *              The 'OP' routine is called with the record found and the
685
 *              OP_DATA pointer, to allow caller to return information about
686
 *              the record.
687
 *
688
 * Return:  Non-negative on success, negative on failure.
689
 *
690
 *-------------------------------------------------------------------------
691
 */
692
herr_t
693
H5B2_index(H5B2_t *bt2, H5_iter_order_t order, hsize_t idx, H5B2_found_t op, void *op_data)
694
0
{
695
0
    H5B2_hdr_t     *hdr;                 /* Pointer to the B-tree header */
696
0
    H5B2_node_ptr_t curr_node_ptr;       /* Node pointer info for current node */
697
0
    void           *parent = NULL;       /* Parent of current node */
698
0
    uint16_t        depth;               /* Current depth of the tree */
699
0
    herr_t          ret_value = SUCCEED; /* Return value */
700
701
0
    FUNC_ENTER_NOAPI(FAIL)
702
703
    /* Check arguments. */
704
0
    assert(bt2);
705
0
    assert(op);
706
707
    /* Set the shared v2 B-tree header's file context for this operation */
708
0
    bt2->hdr->f = bt2->f;
709
710
    /* Get the v2 B-tree header */
711
0
    hdr = bt2->hdr;
712
713
    /* Make copy of the root node pointer to start search with */
714
0
    curr_node_ptr = hdr->root;
715
716
    /* Check for empty tree */
717
0
    if (curr_node_ptr.node_nrec == 0)
718
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records");
719
720
    /* Check for index greater than the number of records in the tree */
721
0
    if (idx >= curr_node_ptr.all_nrec)
722
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree doesn't have that many records");
723
724
    /* Current depth of the tree */
725
0
    depth = hdr->depth;
726
727
    /* Set initial parent, if doing swmr writes */
728
0
    if (hdr->swmr_write)
729
0
        parent = hdr;
730
731
    /* Check for reverse indexing and map requested index to appropriate forward index */
732
0
    if (order == H5_ITER_DEC)
733
0
        idx = curr_node_ptr.all_nrec - (idx + 1);
734
735
    /* Walk down B-tree to find record or leaf node where record is located */
736
0
    while (depth > 0) {
737
0
        H5B2_internal_t *internal;      /* Pointer to internal node in B-tree */
738
0
        H5B2_node_ptr_t  next_node_ptr; /* Node pointer info for next node */
739
0
        unsigned         u;             /* Local index variable */
740
741
        /* Lock B-tree current node */
742
0
        if (NULL == (internal = H5B2__protect_internal(hdr, parent, &curr_node_ptr, depth, false,
743
0
                                                       H5AC__READ_ONLY_FLAG)))
744
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node");
745
746
        /* Unpin parent if necessary */
747
0
        if (parent) {
748
0
            if (parent != hdr && H5AC_unpin_entry(parent) < 0)
749
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
750
0
            parent = NULL;
751
0
        } /* end if */
752
753
        /* Search for record with correct index */
754
0
        for (u = 0; u < internal->nrec; u++) {
755
            /* Check if record is in child node */
756
0
            if (internal->node_ptrs[u].all_nrec > idx) {
757
                /* Get node pointer for next node to search */
758
0
                next_node_ptr = internal->node_ptrs[u];
759
760
                /* Unlock current node */
761
0
                if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal,
762
0
                                   (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) <
763
0
                    0)
764
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
765
766
                /* Keep track of parent if necessary */
767
0
                if (hdr->swmr_write)
768
0
                    parent = internal;
769
770
                /* Set pointer to next node to load */
771
0
                curr_node_ptr = next_node_ptr;
772
773
                /* Break out of for loop */
774
0
                break;
775
0
            } /* end if */
776
777
            /* Check if record is in this node */
778
0
            if (internal->node_ptrs[u].all_nrec == idx) {
779
                /* Make callback for current record */
780
0
                if ((op)(H5B2_INT_NREC(internal, hdr, u), op_data) < 0) {
781
                    /* Unlock current node */
782
0
                    if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal,
783
0
                                       H5AC__NO_FLAGS_SET) < 0)
784
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
785
786
0
                    HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
787
0
                                "'found' callback failed for B-tree find operation");
788
0
                } /* end if */
789
790
                /* Unlock current node */
791
0
                if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) <
792
0
                    0)
793
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
794
795
0
                HGOTO_DONE(SUCCEED);
796
0
            } /* end if */
797
798
            /* Decrement index we are looking for to account for the node we
799
             * just advanced past.
800
             */
801
0
            idx -= (internal->node_ptrs[u].all_nrec + 1);
802
0
        } /* end for */
803
804
        /* Check last node pointer */
805
0
        if (u == internal->nrec) {
806
            /* Check if record is in child node */
807
0
            if (internal->node_ptrs[u].all_nrec > idx) {
808
                /* Get node pointer for next node to search */
809
0
                next_node_ptr = internal->node_ptrs[u];
810
811
                /* Unlock current node */
812
0
                if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal,
813
0
                                   (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) <
814
0
                    0)
815
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
816
817
                /* Keep track of parent if necessary */
818
0
                if (hdr->swmr_write)
819
0
                    parent = internal;
820
821
                /* Set pointer to next node to load */
822
0
                curr_node_ptr = next_node_ptr;
823
0
            } /* end if */
824
0
            else
825
                /* Index that is greater than the number of records in the tree? */
826
0
                assert(0 && "Index off end of tree??");
827
0
        } /* end if */
828
829
        /* Decrement depth we're at in B-tree */
830
0
        depth--;
831
0
    } /* end while */
832
833
0
    {
834
0
        H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
835
836
        /* Lock B-tree leaf node */
837
0
        if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, &curr_node_ptr, false, H5AC__READ_ONLY_FLAG)))
838
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
839
840
        /* Unpin parent if necessary */
841
0
        if (parent) {
842
0
            if (parent != hdr && H5AC_unpin_entry(parent) < 0)
843
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
844
0
            parent = NULL;
845
0
        } /* end if */
846
847
        /* Sanity check index */
848
0
        assert(idx < leaf->nrec);
849
850
        /* Make callback for correct record */
851
0
        if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0) {
852
            /* Unlock current node */
853
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
854
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
855
856
0
            HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation");
857
0
        } /* end if */
858
859
        /* Unlock current node */
860
0
        if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
861
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
862
0
    } /* end block */
863
864
0
done:
865
0
    if (parent) {
866
0
        assert(ret_value < 0);
867
0
        if (parent != hdr && H5AC_unpin_entry(parent) < 0)
868
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
869
0
    } /* end if */
870
871
0
    FUNC_LEAVE_NOAPI(ret_value)
872
0
} /* H5B2_index() */
873
874
/*-------------------------------------------------------------------------
875
 * Function:  H5B2_remove
876
 *
877
 * Purpose: Removes a record from a B-tree.
878
 *
879
 * Return:  Non-negative on success/Negative on failure
880
 *
881
 *-------------------------------------------------------------------------
882
 */
883
herr_t
884
H5B2_remove(H5B2_t *bt2, void *udata, H5B2_remove_t op, void *op_data)
885
0
{
886
0
    H5B2_hdr_t *hdr;                 /* Pointer to the B-tree header */
887
0
    herr_t      ret_value = SUCCEED; /* Return value */
888
889
0
    FUNC_ENTER_NOAPI(FAIL)
890
891
    /* Check arguments. */
892
0
    assert(bt2);
893
894
    /* Set the shared v2 B-tree header's file context for this operation */
895
0
    bt2->hdr->f = bt2->f;
896
897
    /* Get the v2 B-tree header */
898
0
    hdr = bt2->hdr;
899
900
    /* Check for empty B-tree */
901
0
    if (0 == hdr->root.all_nrec)
902
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree");
903
904
    /* Attempt to remove record from B-tree */
905
0
    if (hdr->depth > 0) {
906
0
        bool depth_decreased = false; /* Flag to indicate whether the depth of the B-tree decreased */
907
908
0
        if (H5B2__remove_internal(hdr, &depth_decreased, NULL, NULL, hdr->depth, &(hdr->cache_info), NULL,
909
0
                                  H5B2_POS_ROOT, &hdr->root, udata, op, op_data) < 0)
910
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node");
911
912
        /* Check for decreasing the depth of the B-tree */
913
0
        if (depth_decreased) {
914
            /* Destroy free list factories for previous depth */
915
0
            if (hdr->node_info[hdr->depth].nat_rec_fac)
916
0
                if (H5FL_fac_term(hdr->node_info[hdr->depth].nat_rec_fac) < 0)
917
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
918
0
                                "can't destroy node's native record block factory");
919
0
            if (hdr->node_info[hdr->depth].node_ptr_fac)
920
0
                if (H5FL_fac_term(hdr->node_info[hdr->depth].node_ptr_fac) < 0)
921
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
922
0
                                "can't destroy node's node pointer block factory");
923
924
0
            assert((uint16_t)(hdr->depth - depth_decreased) < hdr->depth);
925
0
            hdr->depth = (uint16_t)(hdr->depth - depth_decreased);
926
0
        } /* end for */
927
0
    }     /* end if */
928
0
    else {
929
0
        if (H5B2__remove_leaf(hdr, &hdr->root, H5B2_POS_ROOT, hdr, udata, op, op_data) < 0)
930
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node");
931
0
    } /* end else */
932
933
    /* Decrement # of records in B-tree */
934
0
    hdr->root.all_nrec--;
935
936
    /* Mark B-tree header as dirty */
937
0
    if (H5B2__hdr_dirty(hdr) < 0)
938
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark B-tree header dirty");
939
940
0
done:
941
0
    FUNC_LEAVE_NOAPI(ret_value)
942
0
} /* H5B2_remove() */
943
944
/*-------------------------------------------------------------------------
945
 * Function:  H5B2_remove_by_idx
946
 *
947
 * Purpose: Removes the n'th record from a B-tree.
948
 *
949
 * Return:  Non-negative on success/Negative on failure
950
 *
951
 *-------------------------------------------------------------------------
952
 */
953
herr_t
954
H5B2_remove_by_idx(H5B2_t *bt2, H5_iter_order_t order, hsize_t idx, H5B2_remove_t op, void *op_data)
955
0
{
956
0
    H5B2_hdr_t *hdr;                 /* Pointer to the B-tree header */
957
0
    herr_t      ret_value = SUCCEED; /* Return value */
958
959
0
    FUNC_ENTER_NOAPI(FAIL)
960
961
    /* Check arguments. */
962
0
    assert(bt2);
963
964
    /* Set the shared v2 B-tree header's file context for this operation */
965
0
    bt2->hdr->f = bt2->f;
966
967
    /* Get the v2 B-tree header */
968
0
    hdr = bt2->hdr;
969
970
    /* Check for empty B-tree */
971
0
    if (0 == hdr->root.all_nrec)
972
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree");
973
974
    /* Check for index greater than the number of records in the tree */
975
0
    if (idx >= hdr->root.all_nrec)
976
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree doesn't have that many records");
977
978
    /* Check for reverse indexing and map requested index to appropriate forward index */
979
0
    if (H5_ITER_DEC == order)
980
0
        idx = hdr->root.all_nrec - (idx + 1);
981
982
    /* Attempt to remove record from B-tree */
983
0
    if (hdr->depth > 0) {
984
0
        bool depth_decreased = false; /* Flag to indicate whether the depth of the B-tree decreased */
985
986
0
        if (H5B2__remove_internal_by_idx(hdr, &depth_decreased, NULL, NULL, hdr->depth, &(hdr->cache_info),
987
0
                                         NULL, &hdr->root, H5B2_POS_ROOT, idx, op, op_data) < 0)
988
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node");
989
990
        /* Check for decreasing the depth of the B-tree */
991
0
        if (depth_decreased) {
992
            /* Destroy free list factories for previous depth */
993
0
            if (hdr->node_info[hdr->depth].nat_rec_fac)
994
0
                if (H5FL_fac_term(hdr->node_info[hdr->depth].nat_rec_fac) < 0)
995
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
996
0
                                "can't destroy node's native record block factory");
997
0
            if (hdr->node_info[hdr->depth].node_ptr_fac)
998
0
                if (H5FL_fac_term(hdr->node_info[hdr->depth].node_ptr_fac) < 0)
999
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL,
1000
0
                                "can't destroy node's node pointer block factory");
1001
1002
0
            assert((uint16_t)(hdr->depth - depth_decreased) < hdr->depth);
1003
0
            hdr->depth = (uint16_t)(hdr->depth - depth_decreased);
1004
0
        } /* end for */
1005
0
    }     /* end if */
1006
0
    else {
1007
0
        if (H5B2__remove_leaf_by_idx(hdr, &hdr->root, H5B2_POS_ROOT, hdr, (unsigned)idx, op, op_data) < 0)
1008
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node");
1009
0
    } /* end else */
1010
1011
    /* Decrement # of records in B-tree */
1012
0
    hdr->root.all_nrec--;
1013
1014
    /* Mark B-tree header as dirty */
1015
0
    if (H5B2__hdr_dirty(hdr) < 0)
1016
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark B-tree header dirty");
1017
1018
0
done:
1019
0
    FUNC_LEAVE_NOAPI(ret_value)
1020
0
} /* H5B2_remove_by_idx() */
1021
1022
/*-------------------------------------------------------------------------
1023
 * Function:  H5B2_get_nrec
1024
 *
1025
 * Purpose: Retrieves the number of records in a B-tree
1026
 *
1027
 * Return:  Non-negative on success/Negative on failure
1028
 *
1029
 *-------------------------------------------------------------------------
1030
 */
1031
herr_t
1032
H5B2_get_nrec(const H5B2_t *bt2, hsize_t *nrec)
1033
0
{
1034
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1035
1036
    /* Check arguments. */
1037
0
    assert(bt2);
1038
0
    assert(nrec);
1039
1040
    /* Get B-tree number of records */
1041
0
    *nrec = bt2->hdr->root.all_nrec;
1042
1043
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1044
0
} /* H5B2_get_nrec() */
1045
1046
/*-------------------------------------------------------------------------
1047
 * Function:  H5B2_neighbor
1048
 *
1049
 * Purpose: Locate a record relative to the specified information in a
1050
 *              B-tree and return that information by filling in fields of the
1051
 *              caller-supplied UDATA pointer depending on the type of leaf node
1052
 *    requested.  The UDATA can point to additional data passed
1053
 *    to the key comparison function.
1054
 *
1055
 *              The 'OP' routine is called with the record found and the
1056
 *              OP_DATA pointer, to allow caller to return information about
1057
 *              the record.
1058
 *
1059
 *              The RANGE indicates whether to search for records less than or
1060
 *              equal to, or greater than or equal to the information passed
1061
 *              in with UDATA.
1062
 *
1063
 * Return:  Non-negative on success, negative on failure.
1064
 *
1065
 *-------------------------------------------------------------------------
1066
 */
1067
herr_t
1068
H5B2_neighbor(H5B2_t *bt2, H5B2_compare_t range, void *udata, H5B2_found_t op, void *op_data)
1069
0
{
1070
0
    H5B2_hdr_t *hdr;                 /* Pointer to the B-tree header */
1071
0
    herr_t      ret_value = SUCCEED; /* Return value */
1072
1073
0
    FUNC_ENTER_NOAPI(FAIL)
1074
1075
    /* Check arguments. */
1076
0
    assert(bt2);
1077
0
    assert(op);
1078
1079
    /* Set the shared v2 B-tree header's file context for this operation */
1080
0
    bt2->hdr->f = bt2->f;
1081
1082
    /* Get the v2 B-tree header */
1083
0
    hdr = bt2->hdr;
1084
1085
    /* Check for empty tree */
1086
0
    if (!H5_addr_defined(hdr->root.addr))
1087
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records");
1088
1089
    /* Attempt to find neighbor record in B-tree */
1090
0
    if (hdr->depth > 0) {
1091
0
        if (H5B2__neighbor_internal(hdr, hdr->depth, &hdr->root, NULL, range, hdr, udata, op, op_data) < 0)
1092
0
            HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
1093
0
                        "unable to find neighbor record in B-tree internal node");
1094
0
    } /* end if */
1095
0
    else {
1096
0
        if (H5B2__neighbor_leaf(hdr, &hdr->root, NULL, range, hdr, udata, op, op_data) < 0)
1097
0
            HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree leaf node");
1098
0
    } /* end else */
1099
1100
0
done:
1101
0
    FUNC_LEAVE_NOAPI(ret_value)
1102
0
} /* H5B2_neighbor() */
1103
1104
/*-------------------------------------------------------------------------
1105
 * Function:  H5B2_modify
1106
 *
1107
 * Purpose: Locate the specified information in a B-tree and modify it.
1108
 *    The UDATA points to additional data passed
1109
 *    to the key comparison function for locating the record to
1110
 *              modify.
1111
 *
1112
 *              The 'OP' routine is called with the record found and the
1113
 *              OP_DATA pointer, to allow caller to modify information about
1114
 *              the record.
1115
 *
1116
 * Return:  Non-negative on success, negative on failure.
1117
 *
1118
 *-------------------------------------------------------------------------
1119
 */
1120
herr_t
1121
H5B2_modify(H5B2_t *bt2, void *udata, bool try, H5B2_modify_t op, void *op_data)
1122
0
{
1123
0
    H5B2_hdr_t     *hdr;                 /* Pointer to the B-tree header */
1124
0
    H5B2_node_ptr_t curr_node_ptr;       /* Node pointer info for current node */
1125
0
    void           *parent = NULL;       /* Parent of current node */
1126
0
    H5B2_nodepos_t  curr_pos;            /* Position of current node */
1127
0
    uint16_t        depth;               /* Current depth of the tree */
1128
0
    int             cmp;                 /* Comparison value of records */
1129
0
    unsigned        idx;                 /* Location of record which matches key */
1130
0
    herr_t          ret_value = SUCCEED; /* Return value */
1131
1132
0
    FUNC_ENTER_NOAPI(FAIL)
1133
1134
    /* Check arguments. */
1135
0
    assert(bt2);
1136
0
    assert(op);
1137
1138
    /* Set the shared v2 B-tree header's file context for this operation */
1139
0
    bt2->hdr->f = bt2->f;
1140
1141
    /* Get the v2 B-tree header */
1142
0
    hdr = bt2->hdr;
1143
1144
    /* Make copy of the root node pointer to start search with */
1145
0
    curr_node_ptr = hdr->root;
1146
1147
    /* Check for empty tree */
1148
0
    if (0 == curr_node_ptr.node_nrec) {
1149
        /* Don't fail if the caller set the 'try' flag */
1150
0
        if (try)
1151
0
            HGOTO_DONE(SUCCEED);
1152
0
        else
1153
0
            HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records");
1154
0
    } /* end if */
1155
1156
    /* Current depth of the tree */
1157
0
    depth = hdr->depth;
1158
1159
    /* Set initial parent, if doing swmr writes */
1160
0
    if (hdr->swmr_write)
1161
0
        parent = hdr;
1162
1163
    /* Walk down B-tree to find record or leaf node where record is located */
1164
0
    cmp      = -1;
1165
0
    curr_pos = H5B2_POS_ROOT;
1166
0
    while (depth > 0) {
1167
0
        unsigned         internal_flags = H5AC__NO_FLAGS_SET;
1168
0
        H5B2_internal_t *internal;      /* Pointer to internal node in B-tree */
1169
0
        H5B2_node_ptr_t  next_node_ptr; /* Node pointer info for next node */
1170
1171
        /* Lock B-tree current node */
1172
0
        if (NULL == (internal = H5B2__protect_internal(hdr, parent, &curr_node_ptr, depth, false,
1173
0
                                                       H5AC__NO_FLAGS_SET)))
1174
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node");
1175
1176
        /* Unpin parent if necessary */
1177
0
        if (parent) {
1178
0
            if (parent != hdr && H5AC_unpin_entry(parent) < 0)
1179
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
1180
0
            parent = NULL;
1181
0
        } /* end if */
1182
1183
        /* Locate node pointer for child */
1184
0
        if (H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx,
1185
0
                                &cmp) < 0) {
1186
            /* Unlock current node before failing */
1187
0
            H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET);
1188
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
1189
0
        } /* end if */
1190
1191
0
        if (cmp > 0)
1192
0
            idx++;
1193
1194
0
        if (cmp != 0) {
1195
            /* Get node pointer for next node to search */
1196
0
            next_node_ptr = internal->node_ptrs[idx];
1197
1198
            /* Set the position of the next node */
1199
0
            if (H5B2_POS_MIDDLE != curr_pos) {
1200
0
                if (idx == 0) {
1201
0
                    if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
1202
0
                        curr_pos = H5B2_POS_LEFT;
1203
0
                    else
1204
0
                        curr_pos = H5B2_POS_MIDDLE;
1205
0
                } /* end if */
1206
0
                else if (idx == internal->nrec) {
1207
0
                    if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
1208
0
                        curr_pos = H5B2_POS_RIGHT;
1209
0
                    else
1210
0
                        curr_pos = H5B2_POS_MIDDLE;
1211
0
                } /* end if */
1212
0
                else
1213
0
                    curr_pos = H5B2_POS_MIDDLE;
1214
0
            } /* end if */
1215
1216
            /* Unlock current node */
1217
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal,
1218
0
                               (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
1219
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1220
1221
            /* Keep track of parent if necessary */
1222
0
            if (hdr->swmr_write)
1223
0
                parent = internal;
1224
1225
            /* Set pointer to next node to load */
1226
0
            curr_node_ptr = next_node_ptr;
1227
0
        } /* end if */
1228
0
        else {
1229
0
            bool changed; /* Whether the 'modify' callback changed the record */
1230
1231
            /* Make callback for current record */
1232
0
            if ((op)(H5B2_INT_NREC(internal, hdr, idx), op_data, &changed) < 0) {
1233
                /* Make certain that the callback didn't modify the value if it failed */
1234
0
                assert(changed == false);
1235
1236
                /* Unlock current node */
1237
0
                if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) <
1238
0
                    0)
1239
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1240
1241
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL,
1242
0
                            "'modify' callback failed for B-tree find operation");
1243
0
            } /* end if */
1244
1245
            /* Mark the node as dirty if it changed */
1246
0
            internal_flags |= changed ? H5AC__DIRTIED_FLAG : 0;
1247
1248
            /* Unlock current node */
1249
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_INT, curr_node_ptr.addr, internal, internal_flags) < 0)
1250
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1251
1252
0
            HGOTO_DONE(SUCCEED);
1253
0
        } /* end else */
1254
1255
        /* Decrement depth we're at in B-tree */
1256
0
        depth--;
1257
0
    } /* end while */
1258
1259
0
    {
1260
0
        H5B2_leaf_t *leaf;                            /* Pointer to leaf node in B-tree */
1261
0
        unsigned     leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */
1262
0
        bool         changed    = false;              /* Whether the 'modify' callback changed the record */
1263
1264
        /* Lock B-tree leaf node */
1265
0
        if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, &curr_node_ptr, false, H5AC__NO_FLAGS_SET)))
1266
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
1267
1268
        /* Unpin parent if necessary */
1269
0
        if (parent) {
1270
0
            if (parent != hdr && H5AC_unpin_entry(parent) < 0)
1271
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
1272
0
            parent = NULL;
1273
0
        } /* end if */
1274
1275
        /* Locate record */
1276
0
        if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) <
1277
0
            0) {
1278
            /* Unlock current node before failing */
1279
0
            H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET);
1280
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
1281
0
        } /* end if */
1282
1283
0
        if (cmp != 0) {
1284
            /* Unlock leaf node */
1285
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
1286
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1287
1288
            /* Don't fail if the caller set the 'try' flag */
1289
0
            if (try)
1290
0
                HGOTO_DONE(SUCCEED);
1291
0
            else
1292
0
                HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record not found");
1293
0
        }
1294
0
        else {
1295
            /* Make callback for current record */
1296
0
            if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data, &changed) < 0) {
1297
                /* Make certain that the callback didn't modify the value if it failed */
1298
0
                assert(changed == false);
1299
1300
                /* Unlock current node */
1301
0
                if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
1302
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1303
1304
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL,
1305
0
                            "'modify' callback failed for B-tree find operation");
1306
0
            } /* end if */
1307
1308
            /* Check for modified record being the min or max for the tree */
1309
            /* (Don't use 'else' for the idx check, to allow for root leaf node) */
1310
0
            if (H5B2_POS_MIDDLE != curr_pos) {
1311
0
                if (idx == 0) {
1312
0
                    if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
1313
0
                        if (hdr->min_native_rec == NULL)
1314
0
                            if (NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
1315
0
                                HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
1316
0
                                            "memory allocation failed for v2 B-tree min record info");
1317
0
                        H5MM_memcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
1318
0
                    } /* end if */
1319
0
                }     /* end if */
1320
0
                if (idx == (unsigned)(leaf->nrec - 1)) {
1321
0
                    if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
1322
0
                        if (hdr->max_native_rec == NULL)
1323
0
                            if (NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
1324
0
                                HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
1325
0
                                            "memory allocation failed for v2 B-tree max record info");
1326
0
                        H5MM_memcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
1327
0
                    } /* end if */
1328
0
                }     /* end if */
1329
0
            }         /* end if */
1330
0
        }             /* end else */
1331
1332
        /* Mark the node as dirty if it changed */
1333
0
        leaf_flags |= (changed ? H5AC__DIRTIED_FLAG : 0);
1334
1335
        /* Unlock current node */
1336
0
        if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, leaf_flags) < 0)
1337
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1338
0
    } /* end block */
1339
1340
0
done:
1341
0
    if (parent) {
1342
0
        assert(ret_value < 0);
1343
0
        if (parent != hdr && H5AC_unpin_entry(parent) < 0)
1344
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry");
1345
0
    } /* end if */
1346
1347
0
    FUNC_LEAVE_NOAPI(ret_value)
1348
0
} /* H5B2_modify() */
1349
1350
/*-------------------------------------------------------------------------
1351
 * Function:  H5B2_close
1352
 *
1353
 * Purpose: Close a v2 B-tree
1354
 *
1355
 * Return:  Non-negative on success/Negative on failure
1356
 *
1357
 *-------------------------------------------------------------------------
1358
 */
1359
herr_t
1360
H5B2_close(H5B2_t *bt2)
1361
0
{
1362
0
    haddr_t bt2_addr       = HADDR_UNDEF; /* Address of v2 B-tree (for deletion) */
1363
0
    bool    pending_delete = false;       /* Whether the v2 B-tree is pending deletion */
1364
0
    herr_t  ret_value      = SUCCEED;     /* Return value */
1365
1366
0
    FUNC_ENTER_NOAPI_NOINIT
1367
1368
    /* Check arguments. */
1369
0
    assert(bt2);
1370
0
    assert(bt2->f);
1371
1372
    /* Decrement file reference & check if this is the last open v2 B-tree using the shared B-tree header */
1373
0
    if (0 == H5B2__hdr_fuse_decr(bt2->hdr)) {
1374
        /* Set the shared v2 B-tree header's file context for this operation */
1375
0
        bt2->hdr->f = bt2->f;
1376
1377
        /* Check for pending B-tree deletion */
1378
0
        if (bt2->hdr->pending_delete) {
1379
            /* Set local info, so B-tree deletion can occur after decrementing the
1380
             *  header's ref count
1381
             */
1382
0
            pending_delete = true;
1383
0
            bt2_addr       = bt2->hdr->addr;
1384
0
        } /* end if */
1385
0
    }     /* end if */
1386
1387
    /* Check for pending v2 B-tree deletion */
1388
0
    if (pending_delete) {
1389
0
        H5B2_hdr_t *hdr; /* Another pointer to v2 B-tree header */
1390
1391
        /* Sanity check */
1392
0
        assert(H5_addr_defined(bt2_addr));
1393
1394
#ifndef NDEBUG
1395
        {
1396
            unsigned hdr_status = 0; /* Header's status in the metadata cache */
1397
1398
            /* Check the header's status in the metadata cache */
1399
            if (H5AC_get_entry_status(bt2->f, bt2_addr, &hdr_status) < 0)
1400
                HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL,
1401
                            "unable to check metadata cache status for v2 B-tree header, address = %llu",
1402
                            (unsigned long long)bt2_addr);
1403
1404
            /* Sanity checks on header */
1405
            assert(hdr_status & H5AC_ES__IN_CACHE);
1406
            assert(hdr_status & H5AC_ES__IS_PINNED);
1407
            assert(!(hdr_status & H5AC_ES__IS_PROTECTED));
1408
        }
1409
#endif /* NDEBUG */
1410
1411
        /* Lock the v2 B-tree header into memory */
1412
        /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */
1413
0
        if (NULL == (hdr = H5B2__hdr_protect(bt2->f, bt2_addr, NULL, H5AC__NO_FLAGS_SET)))
1414
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect v2 B-tree header");
1415
1416
        /* Set the shared v2 B-tree header's file context for this operation */
1417
0
        hdr->f = bt2->f;
1418
1419
        /* Decrement the reference count on the B-tree header */
1420
        /* (don't put in H5B2__hdr_fuse_decr() as the B-tree header may be evicted
1421
         *  immediately -QAK)
1422
         */
1423
0
        if (H5B2__hdr_decr(bt2->hdr) < 0)
1424
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL,
1425
0
                        "can't decrement reference count on shared v2 B-tree header");
1426
1427
        /* Delete v2 B-tree, starting with header (unprotects header) */
1428
0
        if (H5B2__hdr_delete(hdr) < 0)
1429
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree");
1430
0
    } /* end if */
1431
0
    else {
1432
        /* Decrement the reference count on the B-tree header */
1433
        /* (don't put in H5B2__hdr_fuse_decr() as the B-tree header may be evicted
1434
         *  immediately -QAK)
1435
         */
1436
0
        if (H5B2__hdr_decr(bt2->hdr) < 0)
1437
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL,
1438
0
                        "can't decrement reference count on shared v2 B-tree header");
1439
1440
0
    } /* end else */
1441
1442
    /* Release the v2 B-tree wrapper */
1443
0
    bt2 = H5FL_FREE(H5B2_t, bt2);
1444
1445
0
done:
1446
0
    FUNC_LEAVE_NOAPI(ret_value)
1447
0
} /* H5B2_close() */
1448
1449
/*-------------------------------------------------------------------------
1450
 * Function:  H5B2_delete
1451
 *
1452
 * Purpose: Delete an entire B-tree from a file.
1453
 *
1454
 *              The 'OP' routine is called for each record and the
1455
 *              OP_DATA pointer, to allow caller to perform an operation as
1456
 *              each record is removed from the B-tree.
1457
 *
1458
 *              If 'OP' is NULL, the records are just removed in the process
1459
 *              of deleting the B-tree.
1460
 *
1461
 * Note:  The records are _not_ guaranteed to be visited in order.
1462
 *
1463
 * Return:  Non-negative on success, negative on failure.
1464
 *
1465
 *-------------------------------------------------------------------------
1466
 */
1467
herr_t
1468
H5B2_delete(H5F_t *f, haddr_t addr, void *ctx_udata, H5B2_remove_t op, void *op_data)
1469
0
{
1470
0
    H5B2_hdr_t *hdr       = NULL;    /* Pointer to the B-tree header */
1471
0
    herr_t      ret_value = SUCCEED; /* Return value */
1472
1473
0
    FUNC_ENTER_NOAPI(FAIL)
1474
1475
    /* Check arguments. */
1476
0
    assert(f);
1477
0
    assert(H5_addr_defined(addr));
1478
1479
    /* Lock the v2 B-tree header into memory */
1480
0
    if (NULL == (hdr = H5B2__hdr_protect(f, addr, ctx_udata, H5AC__NO_FLAGS_SET)))
1481
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect v2 B-tree header");
1482
1483
    /* Remember the callback & context for later */
1484
0
    hdr->remove_op      = op;
1485
0
    hdr->remove_op_data = op_data;
1486
1487
    /* Check for files using shared v2 B-tree header */
1488
0
    if (hdr->file_rc)
1489
0
        hdr->pending_delete = true;
1490
0
    else {
1491
        /* Set the shared v2 B-tree header's file context for this operation */
1492
0
        hdr->f = f;
1493
1494
        /* Delete v2 B-tree now, starting with header (unprotects header) */
1495
0
        if (H5B2__hdr_delete(hdr) < 0)
1496
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree");
1497
0
        hdr = NULL;
1498
0
    } /* end if */
1499
1500
0
done:
1501
    /* Unprotect the header, if an error occurred */
1502
0
    if (hdr && H5B2__hdr_unprotect(hdr, H5AC__NO_FLAGS_SET) < 0)
1503
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release v2 B-tree header");
1504
1505
0
    FUNC_LEAVE_NOAPI(ret_value)
1506
0
} /* H5B2_delete() */
1507
1508
/*-------------------------------------------------------------------------
1509
 * Function:    H5B2_depend
1510
 *
1511
 * Purpose:     Make a child flush dependency between the v2 B-tree's
1512
 *              header and another piece of metadata in the file.
1513
 *
1514
 * Return:      SUCCEED/FAIL
1515
 *
1516
 *-------------------------------------------------------------------------
1517
 */
1518
herr_t
1519
H5B2_depend(H5B2_t *bt2, H5AC_proxy_entry_t *parent)
1520
0
{
1521
    /* Local variables */
1522
0
    H5B2_hdr_t *hdr       = bt2->hdr; /* Header for B-tree */
1523
0
    herr_t      ret_value = SUCCEED;  /* Return value */
1524
1525
0
    FUNC_ENTER_NOAPI(SUCCEED)
1526
1527
    /*
1528
     * Check arguments.
1529
     */
1530
0
    assert(bt2);
1531
0
    assert(hdr);
1532
0
    assert(parent);
1533
0
    assert(hdr->parent == NULL || hdr->parent == parent);
1534
1535
    /*
1536
     * Check to see if the flush dependency between the parent
1537
     * and the v2 B-tree header has already been setup.  If it hasn't, then
1538
     * set it up.
1539
     */
1540
0
    if (NULL == hdr->parent) {
1541
        /* Sanity check */
1542
0
        assert(hdr->top_proxy);
1543
1544
        /* Set the shared v2 B-tree header's file context for this operation */
1545
0
        hdr->f = bt2->f;
1546
1547
        /* Add the v2 B-tree as a child of the parent (proxy) */
1548
0
        if (H5AC_proxy_entry_add_child(parent, hdr->f, hdr->top_proxy) < 0)
1549
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, FAIL, "unable to add v2 B-tree as child of proxy");
1550
0
        hdr->parent = parent;
1551
0
    } /* end if */
1552
1553
0
done:
1554
0
    FUNC_LEAVE_NOAPI(ret_value)
1555
0
} /* end H5B2_depend() */
1556
1557
/*-------------------------------------------------------------------------
1558
 * Function:    H5B2_patch_file
1559
 *
1560
 * Purpose:     Patch the top-level file pointer contained in bt2
1561
 *              to point to idx_info->f if they are different.
1562
 *    This is possible because the file pointer in bt2 can be
1563
 *    closed out if bt2 remains open.
1564
 *
1565
 * Return:      SUCCEED
1566
 *
1567
 *-------------------------------------------------------------------------
1568
 */
1569
herr_t
1570
H5B2_patch_file(H5B2_t *bt2, H5F_t *f)
1571
0
{
1572
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1573
1574
    /*
1575
     * Check arguments.
1576
     */
1577
0
    assert(bt2);
1578
0
    assert(f);
1579
1580
0
    if (bt2->f != f || bt2->hdr->f != f)
1581
0
        bt2->f = bt2->hdr->f = f;
1582
1583
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1584
0
} /* H5B2_patch_file() */