Coverage Report

Created: 2026-01-17 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5B.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: H5B.c
16
 *
17
 * Purpose: Implements balanced, sibling-linked, N-ary trees
18
 *      capable of storing any type of data with unique key
19
 *      values.
20
 *
21
 *      A B-link-tree is a balanced tree where each node has
22
 *      a pointer to its left and right siblings.  A
23
 *      B-link-tree is a rooted tree having the following
24
 *      properties:
25
 *
26
 *      1. Every node, x, has the following fields:
27
 *
28
 *         a. level[x], the level in the tree at which node
29
 *            x appears.  Leaf nodes are at level zero.
30
 *
31
 *         b. n[x], the number of children pointed to by the
32
 *            node.  Internal nodes point to subtrees while
33
 *            leaf nodes point to arbitrary data.
34
 *
35
 *         c. The child pointers themselves, child[x,i] such
36
 *            that 0 <= i < n[x].
37
 *
38
 *         d. n[x]+1 key values stored in increasing
39
 *            order:
40
 *
41
 *        key[x,0] < key[x,1] < ... < key[x,n[x]].
42
 *
43
 *         e. left[x] is a pointer to the node's left sibling
44
 *            or the null pointer if this is the left-most
45
 *            node at this level in the tree.
46
 *
47
 *         f. right[x] is a pointer to the node's right
48
 *            sibling or the null pointer if this is the
49
 *            right-most node at this level in the tree.
50
 *
51
 *      3. The keys key[x,i] partition the key spaces of the
52
 *         children of x:
53
 *
54
 *            key[x,i] <= key[child[x,i],j] <= key[x,i+1]
55
 *
56
 *         for any valid combination of i and j.
57
 *
58
 *      4. There are lower and upper bounds on the number of
59
 *         child pointers a node can contain.  These bounds
60
 *         can be expressed in terms of a fixed integer k>=2
61
 *         called the `minimum degree' of the B-tree.
62
 *
63
 *         a. Every node other than the root must have at least
64
 *            k child pointers and k+1 keys.  If the tree is
65
 *            nonempty, the root must have at least one child
66
 *            pointer and two keys.
67
 *
68
 *         b. Every node can contain at most 2k child pointers
69
 *            and 2k+1 keys.  A node is `full' if it contains
70
 *            exactly 2k child pointers and 2k+1 keys.
71
 *
72
 *      5. When searching for a particular value, V, and
73
 *         key[V] = key[x,i] for some node x and entry i,
74
 *         then:
75
 *
76
 *         a. If i=0 the child[0] is followed.
77
 *
78
 *         b. If i=n[x] the child[n[x]-1] is followed.
79
 *
80
 *         c. Otherwise, the child that is followed
81
 *            (either child[x,i-1] or child[x,i]) is
82
 *            determined by the type of object to which the
83
 *            leaf nodes of the tree point and is controlled
84
 *            by the key comparison function registered for
85
 *            that type of B-tree.
86
 *
87
 *
88
 *-------------------------------------------------------------------------
89
 */
90
91
/****************/
92
/* Module Setup */
93
/****************/
94
95
#include "H5Bmodule.h" /* This source code file is part of the H5B module */
96
97
/***********/
98
/* Headers */
99
/***********/
100
#include "H5private.h"   /* Generic Functions     */
101
#include "H5Bpkg.h"      /* B-link trees      */
102
#include "H5CXprivate.h" /* API Contexts                        */
103
#include "H5Eprivate.h"  /* Error handling        */
104
#include "H5FLprivate.h" /* Free Lists                          */
105
#include "H5MFprivate.h" /* File memory management    */
106
#include "H5MMprivate.h" /* Memory management     */
107
108
/****************/
109
/* Local Macros */
110
/****************/
111
#define H5B_SIZEOF_HDR(F)                                                                                    \
112
3
    (H5_SIZEOF_MAGIC +       /*magic number       */                                                           \
113
3
     4 +                     /*type, level, num entries     */                                                \
114
3
     2 * H5F_SIZEOF_ADDR(F)) /*left and right sibling addresses   */
115
116
/* Default initializer for H5B_ins_ud_t */
117
#define H5B_INS_UD_T_NULL                                                                                    \
118
0
    {                                                                                                        \
119
0
        NULL, HADDR_UNDEF, H5AC__NO_FLAGS_SET                                                                \
120
0
    }
121
122
/******************/
123
/* Local Typedefs */
124
/******************/
125
126
/* "user data" for iterating over B-tree (collects B-tree metadata size) */
127
typedef struct H5B_iter_ud_t {
128
    H5B_info_t *bt_info; /* Information about B-tree */
129
    void       *udata;   /* Node type's 'udata' for loading & iterator callback */
130
} H5B_info_ud_t;
131
132
/* Convenience struct for the arguments needed to unprotect a b-tree after a
133
 * call to H5B__iterate_helper() or H5B__split() */
134
typedef struct H5B_ins_ud_t {
135
    H5B_t   *bt;          /* B-tree */
136
    haddr_t  addr;        /* B-tree address */
137
    unsigned cache_flags; /* Cache flags for H5AC_unprotect() */
138
} H5B_ins_ud_t;
139
140
/********************/
141
/* Local Prototypes */
142
/********************/
143
static herr_t    H5B_find_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_level, bool *found,
144
                                 void *udata);
145
static H5B_ins_t H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8_t *lt_key,
146
                                    bool *lt_key_changed, uint8_t *md_key, void *udata, uint8_t *rt_key,
147
                                    bool *rt_key_changed, H5B_ins_ud_t *split_bt_ud /*out*/);
148
static herr_t H5B__insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx, haddr_t child, H5B_ins_t anchor,
149
                                const void *md_key);
150
static herr_t H5B__split(H5F_t *f, H5B_ins_ud_t *bt_ud, unsigned idx, void *udata,
151
                         H5B_ins_ud_t *split_bt_ud /*out*/);
152
static H5B_t *H5B__copy(const H5B_t *old_bt);
153
154
/*********************/
155
/* Package Variables */
156
/*********************/
157
158
/* Package initialization variable */
159
bool H5_PKG_INIT_VAR = false;
160
161
/* Declare a free list to manage the haddr_t sequence information */
162
H5FL_SEQ_DEFINE(haddr_t);
163
164
/* Declare a PQ free list to manage the native block information */
165
H5FL_BLK_DEFINE(native_block);
166
167
/* Declare a free list to manage the H5B_t struct */
168
H5FL_DEFINE(H5B_t);
169
170
/*****************************/
171
/* Library Private Variables */
172
/*****************************/
173
174
/*******************/
175
/* Local Variables */
176
/*******************/
177
178
/* Declare a free list to manage the H5B_shared_t struct */
179
H5FL_DEFINE_STATIC(H5B_shared_t);
180
181
/* Declare a free list to manage the raw page information */
182
H5FL_BLK_DEFINE_STATIC(page);
183
184
/* Declare a free list to manage the native key offset sequence information */
185
H5FL_SEQ_DEFINE_STATIC(size_t);
186
187
/*-------------------------------------------------------------------------
188
 * Function:  H5B_create
189
 *
190
 * Purpose: Creates a new empty B-tree leaf node.  The UDATA pointer is
191
 *    passed as an argument to the sizeof_rkey() method for the
192
 *    B-tree.
193
 *
194
 * Return:  Success:  Non-negative, and the address of new node is
195
 *        returned through the ADDR_P argument.
196
 *
197
 *    Failure:  Negative
198
 *
199
 *-------------------------------------------------------------------------
200
 */
201
herr_t
202
H5B_create(H5F_t *f, const H5B_class_t *type, void *udata, haddr_t *addr_p /*out*/)
203
0
{
204
0
    H5B_t        *bt        = NULL;
205
0
    H5B_shared_t *shared    = NULL; /* Pointer to shared B-tree info */
206
0
    herr_t        ret_value = SUCCEED;
207
208
0
    FUNC_ENTER_NOAPI(FAIL)
209
210
    /*
211
     * Check arguments.
212
     */
213
0
    assert(f);
214
0
    assert(type);
215
0
    assert(addr_p);
216
217
    /*
218
     * Allocate file and memory data structures.
219
     */
220
0
    if (NULL == (bt = H5FL_CALLOC(H5B_t)))
221
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for B-tree root node");
222
0
    memset(&bt->cache_info, 0, sizeof(H5AC_info_t));
223
0
    bt->level     = 0;
224
0
    bt->left      = HADDR_UNDEF;
225
0
    bt->right     = HADDR_UNDEF;
226
0
    bt->nchildren = 0;
227
0
    if (NULL == (bt->rc_shared = (type->get_shared)(f, udata)))
228
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree node buffer");
229
0
    H5UC_INC(bt->rc_shared);
230
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
231
0
    assert(shared);
232
0
    if (NULL == (bt->native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)) ||
233
0
        NULL == (bt->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
234
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for B-tree root node");
235
0
    if (HADDR_UNDEF == (*addr_p = H5MF_alloc(f, H5FD_MEM_BTREE, (hsize_t)shared->sizeof_rnode)))
236
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "file allocation failed for B-tree root node");
237
238
    /*
239
     * Cache the new B-tree node.
240
     */
241
0
    if (H5AC_insert_entry(f, H5AC_BT, *addr_p, bt, H5AC__NO_FLAGS_SET) < 0)
242
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINS, FAIL, "can't add B-tree root node to cache");
243
244
0
done:
245
0
    if (ret_value < 0) {
246
0
        if (shared && shared->sizeof_rnode > 0) {
247
0
            H5_CHECK_OVERFLOW(shared->sizeof_rnode, size_t, hsize_t);
248
0
            (void)H5MF_xfree(f, H5FD_MEM_BTREE, *addr_p, (hsize_t)shared->sizeof_rnode);
249
0
        } /* end if */
250
0
        if (bt)
251
            /* Destroy B-tree node */
252
0
            if (H5B__node_dest(bt) < 0)
253
0
                HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "unable to destroy B-tree node");
254
0
    } /* end if */
255
256
0
    FUNC_LEAVE_NOAPI(ret_value)
257
0
} /* end H5B_create() */
258
259
/*-------------------------------------------------------------------------
260
 * Function:    H5B_find
261
 *
262
 * Purpose:     Locate the specified information in a B-tree and return
263
 *              that information by filling in fields of the
264
 *              caller-supplied UDATA pointer depending on the type of leaf
265
 *              node requested.  The UDATA can point to additional data
266
 *              passed to the key comparison function.
267
 *
268
 * Note:        This function does not follow the left/right sibling
269
 *              pointers since it assumes that all nodes can be reached
270
 *              from the parent node.
271
 *
272
 * Return:      Non-negative (true/false) on success (if found, values
273
 *              returned through the UDATA argument). Negative on failure
274
 *              (if not found, UDATA is undefined).
275
 *
276
 *-------------------------------------------------------------------------
277
 */
278
herr_t
279
H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *udata)
280
1
{
281
1
    herr_t ret_value = SUCCEED;
282
283
1
    FUNC_ENTER_NOAPI(FAIL)
284
285
    /*
286
     * Check arguments.
287
     */
288
1
    assert(f);
289
1
    assert(type);
290
1
    assert(type->decode);
291
1
    assert(type->cmp3);
292
1
    assert(type->found);
293
1
    assert(H5_addr_defined(addr));
294
295
1
    if ((ret_value = H5B_find_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, found, udata)) < 0)
296
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key");
297
298
1
done:
299
1
    FUNC_LEAVE_NOAPI(ret_value)
300
1
} /* end H5B_find() */
301
302
/*-------------------------------------------------------------------------
303
 * Function:    H5B_find_helper
304
 *
305
 * Purpose:     Recursive helper routine for H5B_find used to track node
306
 *              levels and attempt to detect B-tree corruption during
307
 *              lookups.
308
 *
309
 * Note:        This function does not follow the left/right sibling
310
 *              pointers since it assumes that all nodes can be reached
311
 *              from the parent node.
312
 *
313
 * Return:      Non-negative on success (if found, values returned through
314
 *              the UDATA argument). Negative on failure (if not found,
315
 *              UDATA is undefined).
316
 *
317
 *-------------------------------------------------------------------------
318
 */
319
static herr_t
320
H5B_find_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_level, bool *found, void *udata)
321
1
{
322
1
    H5B_t         *bt = NULL;
323
1
    H5UC_t        *rc_shared;           /* Ref-counted shared info */
324
1
    H5B_shared_t  *shared;              /* Pointer to shared B-tree info */
325
1
    H5B_cache_ud_t cache_udata;         /* User-data for metadata cache callback */
326
1
    unsigned       idx = 0, lt = 0, rt; /* Final, left & right key indices */
327
1
    int            cmp       = 1;       /* Key comparison value */
328
1
    herr_t         ret_value = SUCCEED; /* Return value */
329
330
1
    FUNC_ENTER_NOAPI(FAIL)
331
332
    /*
333
     * Check arguments.
334
     */
335
1
    assert(f);
336
1
    assert(type);
337
1
    assert(type->decode);
338
1
    assert(type->cmp3);
339
1
    assert(type->found);
340
1
    assert(H5_addr_defined(addr));
341
342
    /* Get shared info for B-tree */
343
1
    if (NULL == (rc_shared = (type->get_shared)(f, udata)))
344
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object");
345
1
    shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
346
1
    assert(shared);
347
348
    /*
349
     * Perform a binary search to locate the child which contains
350
     * the thing for which we're searching.
351
     */
352
1
    cache_udata.f         = f;
353
1
    cache_udata.type      = type;
354
1
    cache_udata.rc_shared = rc_shared;
355
1
    cache_udata.exp_level = exp_level;
356
1
    if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
357
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node");
358
359
1
    rt = bt->nchildren;
360
2
    while (lt < rt && cmp) {
361
1
        idx = (lt + rt) / 2;
362
        /* compare */
363
1
        if ((cmp = (type->cmp3)(H5B_NKEY(bt, shared, idx), udata, H5B_NKEY(bt, shared, (idx + 1)))) < 0)
364
0
            rt = idx;
365
1
        else
366
1
            lt = idx + 1;
367
1
    } /* end while */
368
369
    /* Check if not found */
370
1
    if (cmp)
371
1
        *found = false;
372
0
    else {
373
        /*
374
         * Follow the link to the subtree or to the data node.
375
         */
376
0
        assert(idx < bt->nchildren);
377
378
0
        if (bt->level > 0) {
379
            /* Sanity check to catch the case where the current node points to
380
             * itself and the current node was loaded with an expected node level
381
             * of H5B_UNKNOWN_NODELEVEL, thus bypassing the expected node level
382
             * check during deserialization and in the future if the node was
383
             * cached.
384
             */
385
0
            if (bt->child[idx] == addr)
386
0
                HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "cyclic B-tree detected");
387
388
0
            if ((ret_value = H5B_find_helper(f, type, bt->child[idx], (int)(bt->level - 1), found, udata)) <
389
0
                0)
390
0
                HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in subtree");
391
0
        } /* end if */
392
0
        else {
393
0
            if ((ret_value = (type->found)(f, bt->child[idx], H5B_NKEY(bt, shared, idx), found, udata)) < 0)
394
0
                HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in leaf node");
395
0
        } /* end else */
396
0
    }     /* end else */
397
398
1
done:
399
1
    if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
400
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release node");
401
402
1
    FUNC_LEAVE_NOAPI(ret_value)
403
1
} /* end H5B_find_helper() */
404
405
/*-------------------------------------------------------------------------
406
 * Function:  H5B__split
407
 *
408
 * Purpose: Split a single node into two nodes.  The old node will
409
 *    contain the left children and the new node will contain the
410
 *    right children.
411
 *
412
 *    The UDATA pointer is passed to the sizeof_rkey() method but is
413
 *    otherwise unused.
414
 *
415
 *    The BT_UD argument is a pointer to a protected B-tree
416
 *    node.
417
 *
418
 * Return:  Non-negative on success (The address of the new node is
419
 *              returned through the NEW_ADDR argument). Negative on failure.
420
 *
421
 *-------------------------------------------------------------------------
422
 */
423
static herr_t
424
H5B__split(H5F_t *f, H5B_ins_ud_t *bt_ud, unsigned idx, void *udata, H5B_ins_ud_t *split_bt_ud /*out*/)
425
0
{
426
0
    H5B_shared_t  *shared;              /* Pointer to shared B-tree info */
427
0
    H5B_cache_ud_t cache_udata;         /* User-data for metadata cache callback */
428
0
    unsigned       nleft, nright;       /* Number of keys in left & right halves */
429
0
    double         split_ratios[3];     /* B-tree split ratios */
430
0
    herr_t         ret_value = SUCCEED; /* Return value */
431
432
0
    FUNC_ENTER_PACKAGE
433
434
    /*
435
     * Check arguments.
436
     */
437
0
    assert(f);
438
0
    assert(bt_ud);
439
0
    assert(bt_ud->bt);
440
0
    assert(H5_addr_defined(bt_ud->addr));
441
0
    assert(split_bt_ud);
442
0
    assert(!split_bt_ud->bt);
443
444
    /*
445
     * Initialize variables.
446
     */
447
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(bt_ud->bt->rc_shared);
448
0
    assert(shared);
449
0
    assert(bt_ud->bt->nchildren == shared->two_k);
450
451
    /* Get B-tree split ratios */
452
0
    if (H5CX_get_btree_split_ratios(split_ratios) < 0)
453
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree split ratios");
454
455
    /*
456
     * Decide how to split the children of the old node among the old node
457
     * and the new node.
458
     */
459
0
    if (!H5_addr_defined(bt_ud->bt->right))
460
0
        nleft = (unsigned)((double)shared->two_k * split_ratios[2]); /*right*/
461
0
    else if (!H5_addr_defined(bt_ud->bt->left))
462
0
        nleft = (unsigned)((double)shared->two_k * split_ratios[0]); /*left*/
463
0
    else
464
0
        nleft = (unsigned)((double)shared->two_k * split_ratios[1]); /*middle*/
465
466
    /*
467
     * Keep the new child in the same node as the child that split.  This can
468
     * result in nodes that have an unused child when data is written
469
     * sequentially, but it simplifies stuff below.
470
     */
471
0
    if (idx < nleft && nleft == shared->two_k)
472
0
        --nleft;
473
0
    else if (idx >= nleft && 0 == nleft)
474
0
        nleft++;
475
0
    nright = shared->two_k - nleft;
476
477
    /*
478
     * Create the new B-tree node.
479
     */
480
0
    if (H5B_create(f, shared->type, udata, &split_bt_ud->addr /*out*/) < 0)
481
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create B-tree");
482
0
    cache_udata.f         = f;
483
0
    cache_udata.type      = shared->type;
484
0
    cache_udata.rc_shared = bt_ud->bt->rc_shared;
485
0
    cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
486
0
    if (NULL == (split_bt_ud->bt =
487
0
                     (H5B_t *)H5AC_protect(f, H5AC_BT, split_bt_ud->addr, &cache_udata, H5AC__NO_FLAGS_SET)))
488
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree");
489
0
    split_bt_ud->bt->level = bt_ud->bt->level;
490
491
    /*
492
     * Copy data from the old node to the new node.
493
     */
494
495
0
    split_bt_ud->cache_flags = H5AC__DIRTIED_FLAG;
496
0
    H5MM_memcpy(split_bt_ud->bt->native, bt_ud->bt->native + nleft * shared->type->sizeof_nkey,
497
0
                (nright + 1) * shared->type->sizeof_nkey);
498
0
    H5MM_memcpy(split_bt_ud->bt->child, &bt_ud->bt->child[nleft], nright * sizeof(haddr_t));
499
500
0
    split_bt_ud->bt->nchildren = nright;
501
502
    /*
503
     * Truncate the old node.
504
     */
505
0
    bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
506
0
    bt_ud->bt->nchildren = nleft;
507
508
    /*
509
     * Update other sibling pointers.
510
     */
511
0
    split_bt_ud->bt->left  = bt_ud->addr;
512
0
    split_bt_ud->bt->right = bt_ud->bt->right;
513
514
0
    if (H5_addr_defined(bt_ud->bt->right)) {
515
0
        H5B_t *tmp_bt;
516
517
0
        if (NULL ==
518
0
            (tmp_bt = (H5B_t *)H5AC_protect(f, H5AC_BT, bt_ud->bt->right, &cache_udata, H5AC__NO_FLAGS_SET)))
519
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load right sibling");
520
521
0
        tmp_bt->left = split_bt_ud->addr;
522
523
0
        if (H5AC_unprotect(f, H5AC_BT, bt_ud->bt->right, tmp_bt, H5AC__DIRTIED_FLAG) < 0)
524
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
525
0
    } /* end if */
526
527
0
    bt_ud->bt->right = split_bt_ud->addr;
528
0
    assert(bt_ud->cache_flags & H5AC__DIRTIED_FLAG);
529
530
0
done:
531
0
    if (ret_value < 0) {
532
0
        if (split_bt_ud->bt &&
533
0
            H5AC_unprotect(f, H5AC_BT, split_bt_ud->addr, split_bt_ud->bt, split_bt_ud->cache_flags) < 0)
534
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
535
0
        split_bt_ud->bt          = NULL;
536
0
        split_bt_ud->addr        = HADDR_UNDEF;
537
0
        split_bt_ud->cache_flags = H5AC__NO_FLAGS_SET;
538
0
    } /* end if */
539
540
0
    FUNC_LEAVE_NOAPI(ret_value)
541
0
} /* end H5B__split() */
542
543
/*-------------------------------------------------------------------------
544
 * Function:  H5B_insert
545
 *
546
 * Purpose: Adds a new item to the B-tree.
547
 *
548
 * Return:  Non-negative on success/Negative on failure
549
 *
550
 *-------------------------------------------------------------------------
551
 */
552
herr_t
553
H5B_insert(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata)
554
0
{
555
    /*
556
     * These are defined this way to satisfy alignment constraints.
557
     */
558
0
    uint64_t _lt_key[128], _md_key[128], _rt_key[128];
559
0
    uint8_t *lt_key = (uint8_t *)_lt_key;
560
0
    uint8_t *md_key = (uint8_t *)_md_key;
561
0
    uint8_t *rt_key = (uint8_t *)_rt_key;
562
563
0
    bool           lt_key_changed = false, rt_key_changed = false;
564
0
    haddr_t        old_root_addr = HADDR_UNDEF;
565
0
    unsigned       level;
566
0
    H5B_ins_ud_t   bt_ud       = H5B_INS_UD_T_NULL; /* (Old) root node */
567
0
    H5B_ins_ud_t   split_bt_ud = H5B_INS_UD_T_NULL; /* Split B-tree node */
568
0
    H5B_t         *new_root_bt = NULL;              /* New root node */
569
0
    H5UC_t        *rc_shared;                       /* Ref-counted shared info */
570
0
    H5B_shared_t  *shared;                          /* Pointer to shared B-tree info */
571
0
    H5B_cache_ud_t cache_udata;                     /* User-data for metadata cache callback */
572
0
    H5B_ins_t      my_ins    = H5B_INS_ERROR;
573
0
    herr_t         ret_value = SUCCEED;
574
575
0
    FUNC_ENTER_NOAPI(FAIL)
576
577
    /* Check arguments. */
578
0
    assert(f);
579
0
    assert(type);
580
0
    assert(type->sizeof_nkey <= sizeof _lt_key);
581
0
    assert(H5_addr_defined(addr));
582
583
    /* Get shared info for B-tree */
584
0
    if (NULL == (rc_shared = (type->get_shared)(f, udata)))
585
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object");
586
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
587
0
    assert(shared);
588
589
    /* Protect the root node */
590
0
    cache_udata.f         = f;
591
0
    cache_udata.type      = type;
592
0
    cache_udata.rc_shared = rc_shared;
593
0
    cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
594
0
    bt_ud.addr            = addr;
595
0
    if (NULL == (bt_ud.bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
596
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to locate root of B-tree");
597
598
    /* Insert the object */
599
0
    if ((int)(my_ins = H5B__insert_helper(f, &bt_ud, type, lt_key, &lt_key_changed, md_key, udata, rt_key,
600
0
                                          &rt_key_changed, &split_bt_ud /*out*/)) < 0)
601
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert key");
602
603
    /* Check if the root node split */
604
0
    if (H5B_INS_NOOP == my_ins) {
605
        /* The root node did not split - just return */
606
0
        assert(!split_bt_ud.bt);
607
0
        HGOTO_DONE(SUCCEED);
608
0
    } /* end if */
609
0
    assert(H5B_INS_RIGHT == my_ins);
610
0
    assert(split_bt_ud.bt);
611
0
    assert(H5_addr_defined(split_bt_ud.addr));
612
613
    /* Get level of old root */
614
0
    level = bt_ud.bt->level;
615
616
    /* update left and right keys */
617
0
    if (!lt_key_changed)
618
0
        H5MM_memcpy(lt_key, H5B_NKEY(bt_ud.bt, shared, 0), type->sizeof_nkey);
619
0
    if (!rt_key_changed)
620
0
        H5MM_memcpy(rt_key, H5B_NKEY(split_bt_ud.bt, shared, split_bt_ud.bt->nchildren), type->sizeof_nkey);
621
622
    /*
623
     * Copy the old root node to some other file location and make the new root
624
     * at the old root's previous address.  This prevents the B-tree from
625
     * "moving".
626
     */
627
0
    H5_CHECK_OVERFLOW(shared->sizeof_rnode, size_t, hsize_t);
628
0
    if (HADDR_UNDEF == (old_root_addr = H5MF_alloc(f, H5FD_MEM_BTREE, (hsize_t)shared->sizeof_rnode)))
629
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move root");
630
631
    /*
632
     * Move the node to the new location
633
     */
634
635
    /* Make a copy of the old root information */
636
0
    if (NULL == (new_root_bt = H5B__copy(bt_ud.bt)))
637
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to copy old root");
638
639
    /* Unprotect the old root so we can move it.  Also force it to be marked
640
     * dirty so it is written to the new location. */
641
0
    if (H5AC_unprotect(f, H5AC_BT, bt_ud.addr, bt_ud.bt, H5AC__DIRTIED_FLAG) < 0)
642
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release old root");
643
0
    bt_ud.bt = NULL; /* Make certain future references will be caught */
644
645
    /* Move the location of the old root on the disk */
646
0
    if (H5AC_move_entry(f, H5AC_BT, bt_ud.addr, old_root_addr) < 0)
647
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTMOVE, FAIL, "unable to move B-tree root node");
648
0
    bt_ud.addr = old_root_addr;
649
650
    /* Update the split b-tree's left pointer to point to the new location */
651
0
    split_bt_ud.bt->left = bt_ud.addr;
652
0
    split_bt_ud.cache_flags |= H5AC__DIRTIED_FLAG;
653
654
    /* clear the old root info at the old address (we already copied it) */
655
0
    new_root_bt->left  = HADDR_UNDEF;
656
0
    new_root_bt->right = HADDR_UNDEF;
657
658
    /* Set the new information for the copy */
659
0
    new_root_bt->level     = level + 1;
660
0
    new_root_bt->nchildren = 2;
661
662
0
    new_root_bt->child[0] = bt_ud.addr;
663
0
    H5MM_memcpy(H5B_NKEY(new_root_bt, shared, 0), lt_key, shared->type->sizeof_nkey);
664
665
0
    new_root_bt->child[1] = split_bt_ud.addr;
666
0
    H5MM_memcpy(H5B_NKEY(new_root_bt, shared, 1), md_key, shared->type->sizeof_nkey);
667
0
    H5MM_memcpy(H5B_NKEY(new_root_bt, shared, 2), rt_key, shared->type->sizeof_nkey);
668
669
    /* Insert the modified copy of the old root into the file again */
670
0
    if (H5AC_insert_entry(f, H5AC_BT, addr, new_root_bt, H5AC__NO_FLAGS_SET) < 0)
671
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINS, FAIL, "unable to add old B-tree root node to cache");
672
673
0
done:
674
0
    if (ret_value < 0)
675
0
        if (new_root_bt && H5B__node_dest(new_root_bt) < 0)
676
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "unable to free B-tree root node");
677
678
0
    if (bt_ud.bt)
679
0
        if (H5AC_unprotect(f, H5AC_BT, bt_ud.addr, bt_ud.bt, bt_ud.cache_flags) < 0)
680
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to unprotect old root");
681
682
0
    if (split_bt_ud.bt)
683
0
        if (H5AC_unprotect(f, H5AC_BT, split_bt_ud.addr, split_bt_ud.bt, split_bt_ud.cache_flags) < 0)
684
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to unprotect new child");
685
686
0
    FUNC_LEAVE_NOAPI(ret_value)
687
0
} /* end H5B_insert() */
688
689
/*-------------------------------------------------------------------------
690
 * Function:  H5B__insert_child
691
 *
692
 * Purpose: Insert a child to the left or right of child[IDX] depending
693
 *    on whether ANCHOR is H5B_INS_LEFT or H5B_INS_RIGHT. The BT
694
 *    argument is a pointer to a protected B-tree node.
695
 *
696
 * Return:  Non-negative on success/Negative on failure
697
 *
698
 *-------------------------------------------------------------------------
699
 */
700
static herr_t
701
H5B__insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx, haddr_t child, H5B_ins_t anchor,
702
                  const void *md_key)
703
0
{
704
0
    H5B_shared_t *shared; /* Pointer to shared B-tree info */
705
0
    uint8_t      *base;   /* Base offset for move */
706
707
0
    FUNC_ENTER_PACKAGE_NOERR
708
709
0
    assert(bt);
710
0
    assert(bt_flags);
711
0
    assert(H5_addr_defined(child));
712
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
713
0
    assert(shared);
714
0
    assert(bt->nchildren < shared->two_k);
715
716
    /* Check for inserting right-most key into node (common when just appending
717
     * records to an unlimited dimension chunked dataset)
718
     */
719
0
    base = H5B_NKEY(bt, shared, (idx + 1));
720
0
    if ((idx + 1) == bt->nchildren) {
721
        /* Make room for the new key */
722
0
        H5MM_memcpy(base + shared->type->sizeof_nkey, base,
723
0
                    shared->type->sizeof_nkey); /* No overlap possible - memcpy() OK */
724
0
        H5MM_memcpy(base, md_key, shared->type->sizeof_nkey);
725
726
        /* The MD_KEY is the left key of the new node */
727
0
        if (H5B_INS_RIGHT == anchor)
728
0
            idx++; /* Don't have to memmove() child addresses down, just add new child */
729
0
        else
730
            /* Make room for the new child address */
731
0
            bt->child[idx + 1] = bt->child[idx];
732
0
    } /* end if */
733
0
    else {
734
        /* Make room for the new key */
735
0
        memmove(base + shared->type->sizeof_nkey, base, (bt->nchildren - idx) * shared->type->sizeof_nkey);
736
0
        H5MM_memcpy(base, md_key, shared->type->sizeof_nkey);
737
738
        /* The MD_KEY is the left key of the new node */
739
0
        if (H5B_INS_RIGHT == anchor)
740
0
            idx++;
741
742
        /* Make room for the new child address */
743
0
        memmove(bt->child + idx + 1, bt->child + idx, (bt->nchildren - idx) * sizeof(haddr_t));
744
0
    } /* end if */
745
746
0
    bt->child[idx] = child;
747
0
    bt->nchildren += 1;
748
749
    /* Mark node as dirty */
750
0
    *bt_flags |= H5AC__DIRTIED_FLAG;
751
752
0
    FUNC_LEAVE_NOAPI(SUCCEED)
753
0
} /* end H5B_insert_child() */
754
755
/*-------------------------------------------------------------------------
756
 * Function:  H5B__insert_helper
757
 *
758
 * Purpose: Inserts the item UDATA into the tree rooted at ADDR and having
759
 *    the specified type.
760
 *
761
 *    On return, if LT_KEY_CHANGED is non-zero, then LT_KEY is
762
 *    the new native left key.  Similarly for RT_KEY_CHANGED
763
 *    and RT_KEY.
764
 *
765
 *    If the node splits, then MD_KEY contains the key that
766
 *    was split between the two nodes (that is, the key that
767
 *    appears as the max key in the left node and the min key
768
 *    in the right node).
769
 *
770
 * Return:  Success:  A B-tree operation.  The address of the new
771
 *        node, if the node splits, is returned through
772
 *        the NEW_NODE_P argument. The new node is always
773
 *        to the right of the previous node.  This
774
 *        function is called recursively and the return
775
 *        value influences the behavior of the caller.
776
 *        See also, declaration of H5B_ins_t.
777
 *
778
 *    Failure:  H5B_INS_ERROR
779
 *
780
 *-------------------------------------------------------------------------
781
 */
782
static H5B_ins_t
783
H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8_t *lt_key,
784
                   bool *lt_key_changed, uint8_t *md_key, void *udata, uint8_t *rt_key, bool *rt_key_changed,
785
                   H5B_ins_ud_t *split_bt_ud /*out*/)
786
0
{
787
0
    H5B_t         *bt;                                  /* Convenience pointer to B-tree */
788
0
    H5UC_t        *rc_shared;                           /* Ref-counted shared info */
789
0
    H5B_shared_t  *shared;                              /* Pointer to shared B-tree info */
790
0
    H5B_cache_ud_t cache_udata;                         /* User-data for metadata cache callback */
791
0
    unsigned       lt = 0, idx = 0, rt;                 /* Left, final & right index values */
792
0
    int            cmp             = -1;                /* Key comparison value */
793
0
    H5B_ins_ud_t   child_bt_ud     = H5B_INS_UD_T_NULL; /* Child B-tree */
794
0
    H5B_ins_ud_t   new_child_bt_ud = H5B_INS_UD_T_NULL; /* Newly split child B-tree */
795
0
    H5B_ins_t      my_ins          = H5B_INS_ERROR;
796
0
    H5B_ins_t      ret_value       = H5B_INS_ERROR; /* Return value */
797
798
0
    FUNC_ENTER_PACKAGE
799
800
    /*
801
     * Check arguments
802
     */
803
0
    assert(f);
804
0
    assert(bt_ud);
805
0
    assert(bt_ud->bt);
806
0
    assert(H5_addr_defined(bt_ud->addr));
807
0
    assert(type);
808
0
    assert(type->decode);
809
0
    assert(type->cmp3);
810
0
    assert(type->new_node);
811
0
    assert(lt_key);
812
0
    assert(lt_key_changed);
813
0
    assert(rt_key);
814
0
    assert(rt_key_changed);
815
0
    assert(split_bt_ud);
816
0
    assert(!split_bt_ud->bt);
817
0
    assert(!H5_addr_defined(split_bt_ud->addr));
818
0
    assert(split_bt_ud->cache_flags == H5AC__NO_FLAGS_SET);
819
820
0
    bt = bt_ud->bt;
821
822
0
    *lt_key_changed = false;
823
0
    *rt_key_changed = false;
824
825
    /* Get shared info for B-tree */
826
0
    if (NULL == (rc_shared = (type->get_shared)(f, udata)))
827
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, H5B_INS_ERROR,
828
0
                    "can't retrieve B-tree's shared ref. count object");
829
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
830
0
    assert(shared);
831
832
    /*
833
     * Use a binary search to find the child that will receive the new
834
     * data.  When the search completes IDX points to the child that
835
     * should get the new data.
836
     */
837
0
    rt = bt->nchildren;
838
839
0
    while (lt < rt && cmp) {
840
0
        idx = (lt + rt) / 2;
841
0
        if ((cmp = (type->cmp3)(H5B_NKEY(bt, shared, idx), udata, H5B_NKEY(bt, shared, idx + 1))) < 0)
842
0
            rt = idx;
843
0
        else
844
0
            lt = idx + 1;
845
0
    } /* end while */
846
847
    /* Set up user data for cache callbacks */
848
0
    cache_udata.f         = f;
849
0
    cache_udata.type      = type;
850
0
    cache_udata.rc_shared = rc_shared;
851
0
    cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
852
853
0
    if (0 == bt->nchildren) {
854
        /*
855
         * The value being inserted will be the only value in this tree. We
856
         * must necessarily be at level zero.
857
         */
858
0
        assert(0 == bt->level);
859
0
        if ((type->new_node)(f, H5B_INS_FIRST, H5B_NKEY(bt, shared, 0), udata, H5B_NKEY(bt, shared, 1),
860
0
                             bt->child + 0 /*out*/) < 0)
861
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, H5B_INS_ERROR, "unable to create leaf node");
862
0
        bt->nchildren = 1;
863
0
        bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
864
0
        idx = 0;
865
866
0
        if (type->follow_min) {
867
0
            if ((int)(my_ins = (type->insert)(f, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed,
868
0
                                              md_key, udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed,
869
0
                                              &new_child_bt_ud.addr /*out*/)) < 0)
870
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "unable to insert first leaf node");
871
0
        } /* end if */
872
0
        else
873
0
            my_ins = H5B_INS_NOOP;
874
0
    }
875
0
    else if (cmp < 0 && idx == 0) {
876
0
        if (bt->level > 0) {
877
            /*
878
             * The value being inserted is less than any value in this tree.
879
             * Follow the minimum branch out of this node to a subtree.
880
             */
881
0
            child_bt_ud.addr = bt->child[idx];
882
0
            if (NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, H5AC_BT, child_bt_ud.addr, &cache_udata,
883
0
                                                                H5AC__NO_FLAGS_SET)))
884
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node");
885
886
0
            if ((int)(my_ins = H5B__insert_helper(
887
0
                          f, &child_bt_ud, type, H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata,
888
0
                          H5B_NKEY(bt, shared, idx + 1), rt_key_changed, &new_child_bt_ud /*out*/)) < 0)
889
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum subtree");
890
0
        }
891
0
        else if (type->follow_min) {
892
            /*
893
             * The value being inserted is less than any leaf node out of this
894
             * current node.  Follow the minimum branch to a leaf node and let
895
             * the subclass handle the problem.
896
             */
897
0
            if ((int)(my_ins = (type->insert)(f, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed,
898
0
                                              md_key, udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed,
899
0
                                              &new_child_bt_ud.addr /*out*/)) < 0)
900
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum leaf node");
901
0
        }
902
0
        else {
903
            /*
904
             * The value being inserted is less than any leaf node out of the
905
             * current node. Create a new minimum leaf node out of this B-tree
906
             * node. This node is not empty (handled above).
907
             */
908
0
            my_ins = H5B_INS_LEFT;
909
0
            H5MM_memcpy(md_key, H5B_NKEY(bt, shared, idx), type->sizeof_nkey);
910
0
            if ((type->new_node)(f, H5B_INS_LEFT, H5B_NKEY(bt, shared, idx), udata, md_key,
911
0
                                 &new_child_bt_ud.addr /*out*/) < 0)
912
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum leaf node");
913
0
            *lt_key_changed = true;
914
0
        } /* end else */
915
916
#ifdef H5_STRICT_FORMAT_CHECKS
917
        /* Since we are to the left of the leftmost key there must not be a left
918
         * sibling */
919
        if (H5_addr_defined(bt->left))
920
            HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, H5B_INS_ERROR, "internal error: likely corrupt key values");
921
#endif /* H5_STRICT_FORMAT_CHECKS */
922
0
    }
923
0
    else if (cmp > 0 && idx + 1 >= bt->nchildren) {
924
0
        if (bt->level > 0) {
925
            /*
926
             * The value being inserted is larger than any value in this tree.
927
             * Follow the maximum branch out of this node to a subtree.
928
             */
929
0
            idx              = bt->nchildren - 1;
930
0
            child_bt_ud.addr = bt->child[idx];
931
0
            if (NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, H5AC_BT, child_bt_ud.addr, &cache_udata,
932
0
                                                                H5AC__NO_FLAGS_SET)))
933
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node");
934
935
0
            if ((int)(my_ins = H5B__insert_helper(
936
0
                          f, &child_bt_ud, type, H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata,
937
0
                          H5B_NKEY(bt, shared, idx + 1), rt_key_changed, &new_child_bt_ud /*out*/)) < 0)
938
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum subtree");
939
0
        }
940
0
        else if (type->follow_max) {
941
            /*
942
             * The value being inserted is larger than any leaf node out of the
943
             * current node.  Follow the maximum branch to a leaf node and let
944
             * the subclass handle the problem.
945
             */
946
0
            idx = bt->nchildren - 1;
947
0
            if ((int)(my_ins = (type->insert)(f, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed,
948
0
                                              md_key, udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed,
949
0
                                              &new_child_bt_ud.addr /*out*/)) < 0)
950
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum leaf node");
951
0
        }
952
0
        else {
953
            /*
954
             * The value being inserted is larger than any leaf node out of the
955
             * current node.  Create a new maximum leaf node out of this B-tree
956
             * node.
957
             */
958
0
            idx    = bt->nchildren - 1;
959
0
            my_ins = H5B_INS_RIGHT;
960
0
            H5MM_memcpy(md_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey);
961
0
            if ((type->new_node)(f, H5B_INS_RIGHT, md_key, udata, H5B_NKEY(bt, shared, idx + 1),
962
0
                                 &new_child_bt_ud.addr /*out*/) < 0)
963
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum leaf node");
964
0
            *rt_key_changed = true;
965
0
        } /* end else */
966
967
#ifdef H5_STRICT_FORMAT_CHECKS
968
        /* Since we are to the right of the rightmost key there must not be a
969
         * right sibling */
970
        if (H5_addr_defined(bt->right))
971
            HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, H5B_INS_ERROR, "internal error: likely corrupt key values");
972
#endif /* H5_STRICT_FORMAT_CHECKS */
973
0
    }
974
0
    else if (cmp) {
975
        /* We couldn't figure out which branch to follow out of this node */
976
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR,
977
0
                    "internal error: could not determine which branch to follow out of this node");
978
0
    }
979
0
    else if (bt->level > 0) {
980
        /*
981
         * Follow a branch out of this node to another subtree.
982
         */
983
0
        assert(idx < bt->nchildren);
984
0
        child_bt_ud.addr = bt->child[idx];
985
0
        if (NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, H5AC_BT, child_bt_ud.addr, &cache_udata,
986
0
                                                            H5AC__NO_FLAGS_SET)))
987
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node");
988
989
0
        if ((int)(my_ins = H5B__insert_helper(f, &child_bt_ud, type, H5B_NKEY(bt, shared, idx),
990
0
                                              lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1),
991
0
                                              rt_key_changed, &new_child_bt_ud /*out*/)) < 0)
992
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert subtree");
993
0
    }
994
0
    else {
995
        /*
996
         * Follow a branch out of this node to a leaf node of some other type.
997
         */
998
0
        assert(idx < bt->nchildren);
999
0
        if ((int)(my_ins = (type->insert)(f, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed,
1000
0
                                          md_key, udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed,
1001
0
                                          &new_child_bt_ud.addr /*out*/)) < 0)
1002
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert leaf node");
1003
0
    }
1004
0
    assert((int)my_ins >= 0);
1005
1006
    /*
1007
     * Update the left and right keys of the current node.
1008
     */
1009
0
    if (*lt_key_changed) {
1010
0
        bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
1011
0
        if (idx > 0) {
1012
0
            assert(type->critical_key == H5B_LEFT);
1013
0
            assert(!(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins));
1014
0
            *lt_key_changed = false;
1015
0
        } /* end if */
1016
0
        else
1017
0
            H5MM_memcpy(lt_key, H5B_NKEY(bt, shared, idx), type->sizeof_nkey);
1018
0
    } /* end if */
1019
0
    if (*rt_key_changed) {
1020
0
        bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
1021
0
        if (idx + 1 < bt->nchildren) {
1022
0
            assert(type->critical_key == H5B_RIGHT);
1023
0
            assert(!(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins));
1024
0
            *rt_key_changed = false;
1025
0
        } /* end if */
1026
0
        else
1027
0
            H5MM_memcpy(rt_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey);
1028
0
    } /* end if */
1029
1030
    /*
1031
     * Handle changes/additions to children
1032
     */
1033
0
    assert(!(bt->level == 0) != !(child_bt_ud.bt));
1034
0
    if (H5B_INS_CHANGE == my_ins) {
1035
        /*
1036
         * The insertion simply changed the address for the child.
1037
         */
1038
0
        assert(!child_bt_ud.bt);
1039
0
        assert(bt->level == 0);
1040
0
        bt->child[idx] = new_child_bt_ud.addr;
1041
0
        bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
1042
0
    }
1043
0
    else if (H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins) {
1044
0
        unsigned *tmp_bt_flags_ptr = NULL;
1045
0
        H5B_t    *tmp_bt;
1046
1047
        /*
1048
         * If this node is full then split it before inserting the new child.
1049
         */
1050
0
        if (bt->nchildren == shared->two_k) {
1051
0
            if (H5B__split(f, bt_ud, idx, udata, split_bt_ud /*out*/) < 0)
1052
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, H5B_INS_ERROR, "unable to split node");
1053
0
            if (idx < bt->nchildren) {
1054
0
                tmp_bt           = bt;
1055
0
                tmp_bt_flags_ptr = &bt_ud->cache_flags;
1056
0
            }
1057
0
            else {
1058
0
                idx -= bt->nchildren;
1059
0
                tmp_bt           = split_bt_ud->bt;
1060
0
                tmp_bt_flags_ptr = &split_bt_ud->cache_flags;
1061
0
            }
1062
0
        } /* end if */
1063
0
        else {
1064
0
            tmp_bt           = bt;
1065
0
            tmp_bt_flags_ptr = &bt_ud->cache_flags;
1066
0
        } /* end else */
1067
1068
        /* Insert the child */
1069
0
        if (H5B__insert_child(tmp_bt, tmp_bt_flags_ptr, idx, new_child_bt_ud.addr, my_ins, md_key) < 0)
1070
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert child");
1071
0
    } /* end else-if */
1072
1073
    /*
1074
     * If this node split, return the mid key (the one that is shared
1075
     * by the left and right node).
1076
     */
1077
0
    if (split_bt_ud->bt) {
1078
0
        H5MM_memcpy(md_key, H5B_NKEY(split_bt_ud->bt, shared, 0), type->sizeof_nkey);
1079
0
        ret_value = H5B_INS_RIGHT;
1080
0
    }
1081
0
    else
1082
0
        ret_value = H5B_INS_NOOP;
1083
1084
0
done:
1085
0
    if (child_bt_ud.bt)
1086
0
        if (H5AC_unprotect(f, H5AC_BT, child_bt_ud.addr, child_bt_ud.bt, child_bt_ud.cache_flags) < 0)
1087
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect child");
1088
1089
0
    if (new_child_bt_ud.bt)
1090
0
        if (H5AC_unprotect(f, H5AC_BT, new_child_bt_ud.addr, new_child_bt_ud.bt,
1091
0
                           new_child_bt_ud.cache_flags) < 0)
1092
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect new child");
1093
1094
0
    FUNC_LEAVE_NOAPI(ret_value)
1095
0
} /* end H5B_insert_helper() */
1096
1097
/*-------------------------------------------------------------------------
1098
 * Function:  H5B__iterate_helper
1099
 *
1100
 * Purpose: Calls the list callback for each leaf node of the
1101
 *    B-tree, passing it the caller's UDATA structure.
1102
 *
1103
 * Return:  Non-negative on success/Negative on failure
1104
 *
1105
 *-------------------------------------------------------------------------
1106
 */
1107
static herr_t
1108
H5B__iterate_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_level, H5B_operator_t op,
1109
                    void *udata)
1110
0
{
1111
0
    H5B_t         *bt = NULL;                /* Pointer to current B-tree node */
1112
0
    H5UC_t        *rc_shared;                /* Ref-counted shared info */
1113
0
    H5B_shared_t  *shared;                   /* Pointer to shared B-tree info */
1114
0
    H5B_cache_ud_t cache_udata;              /* User-data for metadata cache callback */
1115
0
    unsigned       u;                        /* Local index variable */
1116
0
    herr_t         ret_value = H5_ITER_CONT; /* Return value */
1117
1118
0
    FUNC_ENTER_PACKAGE
1119
1120
    /*
1121
     * Check arguments.
1122
     */
1123
0
    assert(f);
1124
0
    assert(type);
1125
0
    assert(H5_addr_defined(addr));
1126
0
    assert(op);
1127
0
    assert(udata);
1128
1129
    /* Get shared info for B-tree */
1130
0
    if (NULL == (rc_shared = (type->get_shared)(f, udata)))
1131
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object");
1132
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
1133
0
    assert(shared);
1134
1135
    /* Protect the initial/current node */
1136
0
    cache_udata.f         = f;
1137
0
    cache_udata.type      = type;
1138
0
    cache_udata.rc_shared = rc_shared;
1139
0
    cache_udata.exp_level = exp_level;
1140
0
    if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
1141
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load B-tree node");
1142
1143
    /* Iterate over node's children */
1144
0
    for (u = 0; u < bt->nchildren && ret_value == H5_ITER_CONT; u++) {
1145
0
        if (bt->level > 0)
1146
0
            ret_value = H5B__iterate_helper(f, type, bt->child[u], (int)(bt->level - 1), op, udata);
1147
0
        else
1148
0
            ret_value = (*op)(f, H5B_NKEY(bt, shared, u), bt->child[u], H5B_NKEY(bt, shared, u + 1), udata);
1149
0
        if (ret_value < 0)
1150
0
            HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
1151
0
    } /* end for */
1152
1153
0
done:
1154
0
    if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
1155
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release B-tree node");
1156
1157
0
    FUNC_LEAVE_NOAPI(ret_value)
1158
0
} /* end H5B__iterate_helper() */
1159
1160
/*-------------------------------------------------------------------------
1161
 * Function:  H5B_iterate
1162
 *
1163
 * Purpose: Calls the list callback for each leaf node of the
1164
 *    B-tree, passing it the UDATA structure.
1165
 *
1166
 * Return:  Non-negative on success/Negative on failure
1167
 *
1168
 *-------------------------------------------------------------------------
1169
 */
1170
herr_t
1171
H5B_iterate(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_operator_t op, void *udata)
1172
0
{
1173
0
    herr_t ret_value = FAIL; /* Return value */
1174
1175
0
    FUNC_ENTER_NOAPI_NOERR
1176
1177
    /*
1178
     * Check arguments.
1179
     */
1180
0
    assert(f);
1181
0
    assert(type);
1182
0
    assert(H5_addr_defined(addr));
1183
0
    assert(op);
1184
0
    assert(udata);
1185
1186
    /* Iterate over the B-tree records */
1187
0
    if ((ret_value = H5B__iterate_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, op, udata)) < 0)
1188
0
        HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
1189
1190
0
    FUNC_LEAVE_NOAPI(ret_value)
1191
0
} /* end H5B_iterate() */
1192
1193
/*-------------------------------------------------------------------------
1194
 * Function:  H5B__remove_helper
1195
 *
1196
 * Purpose: The recursive part of removing an item from a B-tree.  The
1197
 *    sub B-tree that is being considered is located at ADDR and
1198
 *    the item to remove is described by UDATA.  If the removed
1199
 *    item falls at the left or right end of the current level then
1200
 *    it might be necessary to adjust the left and/or right keys
1201
 *    (LT_KEY and/or RT_KEY) to to indicate that they changed by
1202
 *    setting LT_KEY_CHANGED and/or RT_KEY_CHANGED.
1203
 *
1204
 * Return:  Success:  A B-tree operation, see comments for
1205
 *        H5B_ins_t declaration.  This function is
1206
 *        called recursively and the return value
1207
 *        influences the actions of the caller. It is
1208
 *        also called by H5B_remove().
1209
 *
1210
 *    Failure:  H5B_INS_ERROR, a negative value.
1211
 *
1212
 *-------------------------------------------------------------------------
1213
 */
1214
static H5B_ins_t
1215
H5B__remove_helper(H5F_t *f, haddr_t addr, const H5B_class_t *type, int level, uint8_t *lt_key /*out*/,
1216
                   bool *lt_key_changed /*out*/, void *udata, uint8_t *rt_key /*out*/,
1217
                   bool *rt_key_changed /*out*/)
1218
0
{
1219
0
    H5B_t         *bt = NULL, *sibling = NULL;
1220
0
    unsigned       bt_flags = H5AC__NO_FLAGS_SET;
1221
0
    H5UC_t        *rc_shared;           /* Ref-counted shared info */
1222
0
    H5B_shared_t  *shared;              /* Pointer to shared B-tree info */
1223
0
    H5B_cache_ud_t cache_udata;         /* User-data for metadata cache callback */
1224
0
    unsigned       idx = 0, lt = 0, rt; /* Final, left & right indices */
1225
0
    int            cmp       = 1;       /* Key comparison value */
1226
0
    H5B_ins_t      ret_value = H5B_INS_ERROR;
1227
1228
0
    FUNC_ENTER_PACKAGE
1229
1230
0
    assert(f);
1231
0
    assert(H5_addr_defined(addr));
1232
0
    assert(type);
1233
0
    assert(type->decode);
1234
0
    assert(type->cmp3);
1235
0
    assert(lt_key && lt_key_changed);
1236
0
    assert(udata);
1237
0
    assert(rt_key && rt_key_changed);
1238
1239
    /* Get shared info for B-tree */
1240
0
    if (NULL == (rc_shared = (type->get_shared)(f, udata)))
1241
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, H5B_INS_ERROR,
1242
0
                    "can't retrieve B-tree's shared ref. count object");
1243
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
1244
0
    assert(shared);
1245
1246
    /*
1247
     * Perform a binary search to locate the child which contains the thing
1248
     * for which we're searching.
1249
     */
1250
0
    cache_udata.f         = f;
1251
0
    cache_udata.type      = type;
1252
0
    cache_udata.rc_shared = rc_shared;
1253
0
    cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
1254
0
    if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
1255
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load B-tree node");
1256
1257
0
    rt = bt->nchildren;
1258
0
    while (lt < rt && cmp) {
1259
0
        idx = (lt + rt) / 2;
1260
0
        if ((cmp = (type->cmp3)(H5B_NKEY(bt, shared, idx), udata, H5B_NKEY(bt, shared, idx + 1))) < 0)
1261
0
            rt = idx;
1262
0
        else
1263
0
            lt = idx + 1;
1264
0
    } /* end while */
1265
0
    if (cmp)
1266
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, H5B_INS_ERROR, "B-tree key not found");
1267
1268
    /*
1269
     * Follow the link to the subtree or to the data node.  The return value
1270
     * will be one of H5B_INS_ERROR, H5B_INS_NOOP, or H5B_INS_REMOVE.
1271
     */
1272
0
    assert(idx < bt->nchildren);
1273
0
    if (bt->level > 0) {
1274
        /* We're at an internal node -- call recursively */
1275
0
        if ((int)(ret_value =
1276
0
                      H5B__remove_helper(f, bt->child[idx], type, level + 1,
1277
0
                                         H5B_NKEY(bt, shared, idx) /*out*/, lt_key_changed /*out*/, udata,
1278
0
                                         H5B_NKEY(bt, shared, idx + 1) /*out*/, rt_key_changed /*out*/)) < 0)
1279
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, H5B_INS_ERROR, "key not found in subtree");
1280
0
    }
1281
0
    else if (type->remove) {
1282
        /*
1283
         * We're at a leaf node but the leaf node points to an object that
1284
         * has a removal method.  Pass the removal request to the pointed-to
1285
         * object and let it decide how to progress.
1286
         */
1287
0
        if ((int)(ret_value = (type->remove)(f, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed,
1288
0
                                             udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed)) < 0)
1289
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, H5B_INS_ERROR, "key not found in leaf node");
1290
0
    }
1291
0
    else {
1292
        /*
1293
         * We're at a leaf node which points to an object that has no removal
1294
         * method.  The best we can do is to leave the object alone but
1295
         * remove the B-tree reference to the object.
1296
         */
1297
0
        *lt_key_changed = false;
1298
0
        *rt_key_changed = false;
1299
0
        ret_value       = H5B_INS_REMOVE;
1300
0
    }
1301
1302
    /*
1303
     * Update left and right key dirty bits if the subtree indicates that they
1304
     * have changed.  If the subtree's left key changed and the subtree is the
1305
     * left-most child of the current node then we must update the key in our
1306
     * parent and indicate that it changed.  Similarly, if the right subtree
1307
     * key changed and it's the right most key of this node we must update
1308
     * our right key and indicate that it changed.
1309
     */
1310
0
    if (*lt_key_changed) {
1311
0
        assert(type->critical_key == H5B_LEFT);
1312
0
        bt_flags |= H5AC__DIRTIED_FLAG;
1313
1314
0
        if (idx > 0)
1315
            /* Don't propagate change out of this B-tree node */
1316
0
            *lt_key_changed = false;
1317
0
        else
1318
0
            H5MM_memcpy(lt_key, H5B_NKEY(bt, shared, idx), type->sizeof_nkey);
1319
0
    } /* end if */
1320
0
    if (*rt_key_changed) {
1321
0
        assert(type->critical_key == H5B_RIGHT);
1322
0
        bt_flags |= H5AC__DIRTIED_FLAG;
1323
0
        if (idx + 1 < bt->nchildren)
1324
            /* Don't propagate change out of this B-tree node */
1325
0
            *rt_key_changed = false;
1326
0
        else
1327
0
            H5MM_memcpy(rt_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey);
1328
0
    } /* end if */
1329
1330
    /*
1331
     * If the subtree returned H5B_INS_REMOVE then we should remove the
1332
     * subtree entry from the current node.  There are four cases:
1333
     */
1334
0
    if (H5B_INS_REMOVE == ret_value) {
1335
        /* Clients should not change keys when a node is removed.  This function
1336
         * will handle it as appropriate, based on the value of bt->critical_key
1337
         */
1338
0
        assert(!(*lt_key_changed));
1339
0
        assert(!(*rt_key_changed));
1340
1341
0
        if (1 == bt->nchildren) {
1342
            /*
1343
             * The subtree is the only child of this node.  Discard both
1344
             * keys and the subtree pointer. Free this node (unless it's the
1345
             * root node) and return H5B_INS_REMOVE.
1346
             */
1347
            /* Only delete the node if it is not the root node.  Note that this
1348
             * "level" is the opposite of bt->level */
1349
0
            if (level > 0) {
1350
                /* Fix siblings, making sure that the keys remain consistent
1351
                 * between siblings.  Overwrite the key that that is not
1352
                 * "critical" for any child in its node to maintain this
1353
                 * consistency (and avoid breaking key/child consistency) */
1354
0
                if (H5_addr_defined(bt->left)) {
1355
0
                    if (NULL == (sibling = (H5B_t *)H5AC_protect(f, H5AC_BT, bt->left, &cache_udata,
1356
0
                                                                 H5AC__NO_FLAGS_SET)))
1357
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR,
1358
0
                                    "unable to load node from tree");
1359
1360
                    /* Copy right-most key from deleted node to right-most key
1361
                     * in its left neighbor, but only if it is not the critical
1362
                     * key for the right-most child of the left neighbor */
1363
0
                    if (type->critical_key == H5B_LEFT)
1364
0
                        H5MM_memcpy(H5B_NKEY(sibling, shared, sibling->nchildren), H5B_NKEY(bt, shared, 1),
1365
0
                                    type->sizeof_nkey);
1366
1367
0
                    sibling->right = bt->right;
1368
1369
0
                    if (H5AC_unprotect(f, H5AC_BT, bt->left, sibling, H5AC__DIRTIED_FLAG) < 0)
1370
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR,
1371
0
                                    "unable to release node from tree");
1372
0
                    sibling = NULL; /* Make certain future references will be caught */
1373
0
                }                   /* end if */
1374
0
                if (H5_addr_defined(bt->right)) {
1375
0
                    if (NULL == (sibling = (H5B_t *)H5AC_protect(f, H5AC_BT, bt->right, &cache_udata,
1376
0
                                                                 H5AC__NO_FLAGS_SET)))
1377
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR,
1378
0
                                    "unable to unlink node from tree");
1379
1380
                    /* Copy left-most key from deleted node to left-most key in
1381
                     * its right neighbor, but only if it is not the critical
1382
                     * key for the left-most child of the right neighbor */
1383
0
                    if (type->critical_key == H5B_RIGHT)
1384
0
                        H5MM_memcpy(H5B_NKEY(sibling, shared, 0), H5B_NKEY(bt, shared, 0), type->sizeof_nkey);
1385
1386
0
                    sibling->left = bt->left;
1387
1388
0
                    if (H5AC_unprotect(f, H5AC_BT, bt->right, sibling, H5AC__DIRTIED_FLAG) < 0)
1389
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR,
1390
0
                                    "unable to release node from tree");
1391
0
                    sibling = NULL; /* Make certain future references will be caught */
1392
0
                }                   /* end if */
1393
1394
                /* Update bt struct */
1395
0
                bt->left      = HADDR_UNDEF;
1396
0
                bt->right     = HADDR_UNDEF;
1397
0
                bt->nchildren = 0;
1398
1399
                /* Delete the node from disk (via the metadata cache) */
1400
0
                bt_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
1401
0
                H5_CHECK_OVERFLOW(shared->sizeof_rnode, size_t, hsize_t);
1402
0
                if (H5AC_unprotect(f, H5AC_BT, addr, bt, bt_flags | H5AC__DELETED_FLAG) < 0) {
1403
0
                    bt       = NULL;
1404
0
                    bt_flags = H5AC__NO_FLAGS_SET;
1405
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to free B-tree node");
1406
0
                } /* end if */
1407
0
                bt       = NULL;
1408
0
                bt_flags = H5AC__NO_FLAGS_SET;
1409
0
            }
1410
0
            else {
1411
                /* We removed the last child in the root node, set the level
1412
                 * back to 0 (as well as nchildren) */
1413
0
                bt->nchildren = 0;
1414
0
                bt->level     = 0;
1415
0
                bt_flags |= H5AC__DIRTIED_FLAG;
1416
0
            } /* end else */
1417
0
        }
1418
0
        else if (0 == idx) {
1419
            /*
1420
             * The subtree is the left-most child of this node. We update the
1421
             * key and child arrays and lt_key as appropriate, depending on the
1422
             * status of bt->critical_key.  Return H5B_INS_NOOP.
1423
             */
1424
0
            if (type->critical_key == H5B_LEFT) {
1425
                /* Slide all keys down 1, update lt_key */
1426
0
                memmove(H5B_NKEY(bt, shared, 0), H5B_NKEY(bt, shared, 1), bt->nchildren * type->sizeof_nkey);
1427
0
                H5MM_memcpy(lt_key, H5B_NKEY(bt, shared, 0), type->sizeof_nkey);
1428
0
                *lt_key_changed = true;
1429
0
            }
1430
0
            else
1431
                /* Slide all but the leftmost 2 keys down, leaving the leftmost
1432
                 * key intact (the right key of the leftmost child is
1433
                 * overwritten) */
1434
0
                memmove(H5B_NKEY(bt, shared, 1), H5B_NKEY(bt, shared, 2),
1435
0
                        (bt->nchildren - 1) * type->sizeof_nkey);
1436
1437
0
            memmove(bt->child, bt->child + 1, (bt->nchildren - 1) * sizeof(haddr_t));
1438
1439
0
            bt->nchildren -= 1;
1440
0
            bt_flags |= H5AC__DIRTIED_FLAG;
1441
0
            ret_value = H5B_INS_NOOP;
1442
0
        }
1443
0
        else if (idx + 1 == bt->nchildren) {
1444
            /*
1445
             * The subtree is the right-most child of this node. We update the
1446
             * key and child arrays and rt_key as appropriate, depending on the
1447
             * status of bt->critical_key.  Return H5B_INS_NOOP.
1448
             */
1449
0
            if (type->critical_key == H5B_LEFT)
1450
                /* Slide the rightmost key down one, overwriting the left key of
1451
                 * the deleted (rightmost) child */
1452
0
                memmove(H5B_NKEY(bt, shared, bt->nchildren - 1), H5B_NKEY(bt, shared, bt->nchildren),
1453
0
                        type->sizeof_nkey);
1454
0
            else {
1455
                /* Just update rt_key */
1456
0
                H5MM_memcpy(rt_key, H5B_NKEY(bt, shared, bt->nchildren - 1), type->sizeof_nkey);
1457
0
                *rt_key_changed = true;
1458
0
            } /* end else */
1459
1460
0
            bt->nchildren -= 1;
1461
0
            bt_flags |= H5AC__DIRTIED_FLAG;
1462
0
            ret_value = H5B_INS_NOOP;
1463
0
        }
1464
0
        else {
1465
            /*
1466
             * There are subtrees out of this node to both the left and right of
1467
             * the subtree being removed.  The subtree and its critical key are
1468
             * removed from this node and all keys and nodes to the right are
1469
             * shifted left by one place.  The subtree has already been freed.
1470
             * Return H5B_INS_NOOP.
1471
             */
1472
0
            if (type->critical_key == H5B_LEFT)
1473
0
                memmove(H5B_NKEY(bt, shared, idx), H5B_NKEY(bt, shared, idx + 1),
1474
0
                        (bt->nchildren - idx) * type->sizeof_nkey);
1475
0
            else
1476
0
                memmove(H5B_NKEY(bt, shared, idx + 1), H5B_NKEY(bt, shared, idx + 2),
1477
0
                        (bt->nchildren - 1 - idx) * type->sizeof_nkey);
1478
1479
0
            memmove(bt->child + idx, bt->child + idx + 1, (bt->nchildren - 1 - idx) * sizeof(haddr_t));
1480
1481
0
            bt->nchildren -= 1;
1482
0
            bt_flags |= H5AC__DIRTIED_FLAG;
1483
0
            ret_value = H5B_INS_NOOP;
1484
0
        } /* end else */
1485
0
    }
1486
0
    else /* H5B_INS_REMOVE != ret_value */
1487
0
        ret_value = H5B_INS_NOOP;
1488
1489
    /* Patch keys in neighboring trees if necessary */
1490
0
    if (*lt_key_changed && bt != NULL && H5_addr_defined(bt->left)) {
1491
0
        assert(type->critical_key == H5B_LEFT);
1492
0
        assert(level > 0);
1493
1494
        /* Update the rightmost key in the left sibling */
1495
0
        if (NULL == (sibling = (H5B_t *)H5AC_protect(f, H5AC_BT, bt->left, &cache_udata, H5AC__NO_FLAGS_SET)))
1496
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect node");
1497
1498
0
        H5MM_memcpy(H5B_NKEY(sibling, shared, sibling->nchildren), H5B_NKEY(bt, shared, 0),
1499
0
                    type->sizeof_nkey);
1500
1501
0
        if (H5AC_unprotect(f, H5AC_BT, bt->left, sibling, H5AC__DIRTIED_FLAG) < 0)
1502
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node from tree");
1503
0
        sibling = NULL; /* Make certain future references will be caught */
1504
0
    }                   /* end if */
1505
0
    else if (*rt_key_changed && bt != NULL && H5_addr_defined(bt->right)) {
1506
0
        assert(type->critical_key == H5B_RIGHT);
1507
0
        assert(level > 0);
1508
1509
        /* Update the lefttmost key in the right sibling */
1510
0
        if (NULL ==
1511
0
            (sibling = (H5B_t *)H5AC_protect(f, H5AC_BT, bt->right, &cache_udata, H5AC__NO_FLAGS_SET)))
1512
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect node");
1513
1514
0
        H5MM_memcpy(H5B_NKEY(sibling, shared, 0), H5B_NKEY(bt, shared, bt->nchildren), type->sizeof_nkey);
1515
1516
0
        if (H5AC_unprotect(f, H5AC_BT, bt->right, sibling, H5AC__DIRTIED_FLAG) < 0)
1517
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node from tree");
1518
0
        sibling = NULL; /* Make certain future references will be caught */
1519
0
    }                   /* end else */
1520
1521
0
done:
1522
0
    if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt, bt_flags) < 0)
1523
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node");
1524
1525
0
    FUNC_LEAVE_NOAPI(ret_value)
1526
0
} /* end H5B__remove_helper() */
1527
1528
/*-------------------------------------------------------------------------
1529
 * Function:  H5B_remove
1530
 *
1531
 * Purpose: Removes an item from a B-tree.
1532
 *
1533
 * Note:  The current version does not attempt to rebalance the tree.
1534
 *              (Read the paper Yao & Lehman paper for details on why)
1535
 *
1536
 * Return:  Non-negative on success/Negative on failure (failure includes
1537
 *    not being able to find the object which is to be removed).
1538
 *
1539
 *-------------------------------------------------------------------------
1540
 */
1541
herr_t
1542
H5B_remove(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata)
1543
0
{
1544
    /* These are defined this way to satisfy alignment constraints */
1545
0
    uint64_t _lt_key[128], _rt_key[128];
1546
0
    uint8_t *lt_key         = (uint8_t *)_lt_key; /*left key*/
1547
0
    uint8_t *rt_key         = (uint8_t *)_rt_key; /*right key*/
1548
0
    bool     lt_key_changed = false;              /*left key changed?*/
1549
0
    bool     rt_key_changed = false;              /*right key changed?*/
1550
0
    herr_t   ret_value      = SUCCEED;            /* Return value */
1551
1552
0
    FUNC_ENTER_NOAPI(FAIL)
1553
1554
    /* Check args */
1555
0
    assert(f);
1556
0
    assert(type);
1557
0
    assert(type->sizeof_nkey <= sizeof _lt_key);
1558
0
    assert(H5_addr_defined(addr));
1559
1560
    /* The actual removal */
1561
0
    if (H5B_INS_ERROR ==
1562
0
        H5B__remove_helper(f, addr, type, 0, lt_key, &lt_key_changed, udata, rt_key, &rt_key_changed))
1563
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, "unable to remove entry from B-tree");
1564
1565
0
done:
1566
0
    FUNC_LEAVE_NOAPI(ret_value)
1567
0
} /* end H5B_remove() */
1568
1569
/*-------------------------------------------------------------------------
1570
 * Function:  H5B_delete
1571
 *
1572
 * Purpose: Deletes an entire B-tree from the file, calling the 'remove'
1573
 *              callbacks for each node.
1574
 *
1575
 * Return:  Non-negative on success/Negative on failure
1576
 *
1577
 *-------------------------------------------------------------------------
1578
 */
1579
herr_t
1580
H5B_delete(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata)
1581
0
{
1582
0
    H5B_t         *bt = NULL;           /* B-tree node being operated on */
1583
0
    H5UC_t        *rc_shared;           /* Ref-counted shared info */
1584
0
    H5B_shared_t  *shared;              /* Pointer to shared B-tree info */
1585
0
    H5B_cache_ud_t cache_udata;         /* User-data for metadata cache callback */
1586
0
    unsigned       u;                   /* Local index variable */
1587
0
    herr_t         ret_value = SUCCEED; /* Return value */
1588
1589
0
    FUNC_ENTER_NOAPI(FAIL)
1590
1591
    /* Check args */
1592
0
    assert(f);
1593
0
    assert(type);
1594
0
    assert(H5_addr_defined(addr));
1595
1596
    /* Get shared info for B-tree */
1597
0
    if (NULL == (rc_shared = (type->get_shared)(f, udata)))
1598
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object");
1599
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
1600
0
    assert(shared);
1601
1602
    /* Lock this B-tree node into memory for now */
1603
0
    cache_udata.f         = f;
1604
0
    cache_udata.type      = type;
1605
0
    cache_udata.rc_shared = rc_shared;
1606
0
    cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
1607
0
    if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
1608
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node");
1609
1610
    /* Iterate over all children in tree, deleting them */
1611
0
    if (bt->level > 0) {
1612
        /* Iterate over all children in node, deleting them */
1613
0
        for (u = 0; u < bt->nchildren; u++)
1614
0
            if (H5B_delete(f, type, bt->child[u], udata) < 0)
1615
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete B-tree node");
1616
1617
0
    } /* end if */
1618
0
    else {
1619
0
        bool lt_key_changed, rt_key_changed; /* Whether key changed (unused here, just for callback) */
1620
1621
        /* Check for removal callback */
1622
0
        if (type->remove) {
1623
            /* Iterate over all entries in node, calling callback */
1624
0
            for (u = 0; u < bt->nchildren; u++) {
1625
                /* Call user's callback for each entry */
1626
0
                if ((type->remove)(f, bt->child[u], H5B_NKEY(bt, shared, u), &lt_key_changed, udata,
1627
0
                                   H5B_NKEY(bt, shared, u + 1), &rt_key_changed) < H5B_INS_NOOP)
1628
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, "can't remove B-tree node");
1629
0
            } /* end for */
1630
0
        }     /* end if */
1631
0
    }         /* end else */
1632
1633
0
done:
1634
0
    if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
1635
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node in cache");
1636
1637
0
    FUNC_LEAVE_NOAPI(ret_value)
1638
0
} /* end H5B_delete() */
1639
1640
/*-------------------------------------------------------------------------
1641
 * Function:  H5B_shared_new
1642
 *
1643
 * Purpose: Allocates & constructs a shared v1 B-tree struct for client.
1644
 *
1645
 * Return:  Success:  non-NULL pointer to struct allocated
1646
 *    Failure:  NULL
1647
 *
1648
 *-------------------------------------------------------------------------
1649
 */
1650
H5B_shared_t *
1651
H5B_shared_new(const H5F_t *f, const H5B_class_t *type, size_t sizeof_rkey)
1652
3
{
1653
3
    H5B_shared_t *shared = NULL;    /* New shared B-tree struct */
1654
3
    size_t        u;                /* Local index variable */
1655
3
    H5B_shared_t *ret_value = NULL; /* Return value */
1656
1657
3
    FUNC_ENTER_NOAPI(NULL)
1658
1659
    /*
1660
     * Check arguments.
1661
     */
1662
3
    assert(type);
1663
1664
    /* Allocate space for the shared structure */
1665
3
    if (NULL == (shared = H5FL_CALLOC(H5B_shared_t)))
1666
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for shared B-tree info");
1667
1668
    /* Set up the "global" information for this file's groups */
1669
3
    shared->type        = type;
1670
3
    shared->two_k       = 2 * H5F_KVALUE(f, type);
1671
3
    shared->sizeof_addr = H5F_SIZEOF_ADDR(f);
1672
3
    shared->sizeof_len  = H5F_SIZEOF_SIZE(f);
1673
3
    shared->sizeof_rkey = sizeof_rkey;
1674
3
    assert(shared->sizeof_rkey);
1675
3
    shared->sizeof_keys  = (shared->two_k + 1) * type->sizeof_nkey;
1676
3
    shared->sizeof_rnode = ((size_t)H5B_SIZEOF_HDR(f) +                 /*node header */
1677
3
                            shared->two_k * H5F_SIZEOF_ADDR(f) +        /*child pointers */
1678
3
                            (shared->two_k + 1) * shared->sizeof_rkey); /*keys    */
1679
3
    assert(shared->sizeof_rnode);
1680
1681
    /* Allocate and clear shared buffers */
1682
3
    if (NULL == (shared->page = H5FL_BLK_MALLOC(page, shared->sizeof_rnode)))
1683
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree page");
1684
3
    memset(shared->page, 0, shared->sizeof_rnode);
1685
1686
3
    if (NULL == (shared->nkey = H5FL_SEQ_MALLOC(size_t, (size_t)(shared->two_k + 1))))
1687
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree native keys");
1688
1689
    /* Initialize the offsets into the native key buffer */
1690
42
    for (u = 0; u < (shared->two_k + 1); u++)
1691
39
        shared->nkey[u] = u * type->sizeof_nkey;
1692
1693
    /* Set return value */
1694
3
    ret_value = shared;
1695
1696
3
done:
1697
3
    if (NULL == ret_value)
1698
0
        if (shared) {
1699
0
            if (shared->page)
1700
0
                shared->page = H5FL_BLK_FREE(page, shared->page);
1701
0
            if (shared->nkey)
1702
0
                shared->nkey = H5FL_SEQ_FREE(size_t, shared->nkey);
1703
0
            shared = H5FL_FREE(H5B_shared_t, shared);
1704
0
        } /* end if */
1705
1706
3
    FUNC_LEAVE_NOAPI(ret_value)
1707
3
} /* end H5B_shared_new() */
1708
1709
/*-------------------------------------------------------------------------
1710
 * Function:  H5B_shared_free
1711
 *
1712
 * Purpose: Free B-tree shared info
1713
 *
1714
 * Return:  Non-negative on success/Negative on failure
1715
 *
1716
 *-------------------------------------------------------------------------
1717
 */
1718
herr_t
1719
H5B_shared_free(void *_shared)
1720
3
{
1721
3
    H5B_shared_t *shared = (H5B_shared_t *)_shared;
1722
1723
3
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1724
1725
    /* Free the raw B-tree node buffer */
1726
3
    shared->page = H5FL_BLK_FREE(page, shared->page);
1727
1728
    /* Free the B-tree native key offsets buffer */
1729
3
    shared->nkey = H5FL_SEQ_FREE(size_t, shared->nkey);
1730
1731
    /* Free the shared B-tree info */
1732
3
    shared = H5FL_FREE(H5B_shared_t, shared);
1733
1734
3
    FUNC_LEAVE_NOAPI(SUCCEED)
1735
3
} /* end H5B_shared_free() */
1736
1737
/*-------------------------------------------------------------------------
1738
 * Function:  H5B__copy
1739
 *
1740
 * Purpose: Deep copies an existing H5B_t node.
1741
 *
1742
 * Return:  Success:  Pointer to H5B_t object.
1743
 *
1744
 *    Failure:  NULL
1745
 *
1746
 *-------------------------------------------------------------------------
1747
 */
1748
static H5B_t *
1749
H5B__copy(const H5B_t *old_bt)
1750
0
{
1751
0
    H5B_t        *new_node = NULL;
1752
0
    H5B_shared_t *shared;           /* Pointer to shared B-tree info */
1753
0
    H5B_t        *ret_value = NULL; /* Return value */
1754
1755
0
    FUNC_ENTER_PACKAGE
1756
1757
    /*
1758
     * Check arguments.
1759
     */
1760
0
    assert(old_bt);
1761
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(old_bt->rc_shared);
1762
0
    assert(shared);
1763
1764
    /* Allocate memory for the new H5B_t object */
1765
0
    if (NULL == (new_node = H5FL_MALLOC(H5B_t)))
1766
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree root node");
1767
1768
    /* Copy the main structure */
1769
0
    H5MM_memcpy(new_node, old_bt, sizeof(H5B_t));
1770
1771
    /* Reset cache info */
1772
0
    memset(&new_node->cache_info, 0, sizeof(H5AC_info_t));
1773
1774
0
    if (NULL == (new_node->native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)) ||
1775
0
        NULL == (new_node->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
1776
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree root node");
1777
1778
    /* Copy the other structures */
1779
0
    H5MM_memcpy(new_node->native, old_bt->native, shared->sizeof_keys);
1780
0
    H5MM_memcpy(new_node->child, old_bt->child, (sizeof(haddr_t) * shared->two_k));
1781
1782
    /* Increment the ref-count on the raw page */
1783
0
    H5UC_INC(new_node->rc_shared);
1784
1785
    /* Set return value */
1786
0
    ret_value = new_node;
1787
1788
0
done:
1789
0
    if (NULL == ret_value) {
1790
0
        if (new_node) {
1791
0
            new_node->native = H5FL_BLK_FREE(native_block, new_node->native);
1792
0
            new_node->child  = H5FL_SEQ_FREE(haddr_t, new_node->child);
1793
0
            new_node         = H5FL_FREE(H5B_t, new_node);
1794
0
        } /* end if */
1795
0
    }     /* end if */
1796
1797
0
    FUNC_LEAVE_NOAPI(ret_value)
1798
0
} /* end H5B__copy() */
1799
1800
/*-------------------------------------------------------------------------
1801
 * Function:  H5B__get_info_helper
1802
 *
1803
 * Purpose: Walks the B-tree nodes, getting information for all of them.
1804
 *
1805
 * Return:  Non-negative on success/Negative on failure
1806
 *
1807
 *-------------------------------------------------------------------------
1808
 */
1809
static herr_t
1810
H5B__get_info_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, const H5B_info_ud_t *info_udata)
1811
0
{
1812
0
    H5B_t         *bt = NULL;           /* Pointer to current B-tree node */
1813
0
    H5UC_t        *rc_shared;           /* Ref-counted shared info */
1814
0
    H5B_shared_t  *shared;              /* Pointer to shared B-tree info */
1815
0
    H5B_cache_ud_t cache_udata;         /* User-data for metadata cache callback */
1816
0
    unsigned       level;               /* Node level          */
1817
0
    size_t         sizeof_rnode;        /* Size of raw (disk) node       */
1818
0
    haddr_t        next_addr;           /* Address of next node to the right */
1819
0
    haddr_t        left_child;          /* Address of left-most child in node */
1820
0
    herr_t         ret_value = SUCCEED; /* Return value */
1821
1822
0
    FUNC_ENTER_PACKAGE
1823
1824
    /*
1825
     * Check arguments.
1826
     */
1827
0
    assert(f);
1828
0
    assert(type);
1829
0
    assert(H5_addr_defined(addr));
1830
0
    assert(info_udata);
1831
0
    assert(info_udata->bt_info);
1832
0
    assert(info_udata->udata);
1833
1834
    /* Get shared info for B-tree */
1835
0
    if (NULL == (rc_shared = (type->get_shared)(f, info_udata->udata)))
1836
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object");
1837
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
1838
0
    assert(shared);
1839
1840
    /* Get the raw node size for iteration */
1841
0
    sizeof_rnode = shared->sizeof_rnode;
1842
1843
    /* Protect the initial/current node */
1844
0
    cache_udata.f         = f;
1845
0
    cache_udata.type      = type;
1846
0
    cache_udata.rc_shared = rc_shared;
1847
0
    cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
1848
0
    if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
1849
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node");
1850
1851
    /* Cache information from this node */
1852
0
    left_child = bt->child[0];
1853
0
    next_addr  = bt->right;
1854
0
    level      = bt->level;
1855
1856
    /* Update B-tree info */
1857
0
    info_udata->bt_info->size += sizeof_rnode;
1858
0
    info_udata->bt_info->num_nodes++;
1859
1860
    /* Release current node */
1861
0
    if (H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
1862
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1863
0
    bt = NULL;
1864
1865
    /*
1866
     * Follow the right-sibling pointer from node to node until we've
1867
     *      processed all nodes.
1868
     */
1869
0
    while (H5_addr_defined(next_addr)) {
1870
        /* Protect the next node to the right */
1871
0
        addr = next_addr;
1872
0
        if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
1873
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "B-tree node");
1874
1875
        /* Cache information from this node */
1876
0
        next_addr = bt->right;
1877
1878
        /* Update B-tree info */
1879
0
        info_udata->bt_info->size += sizeof_rnode;
1880
0
        info_udata->bt_info->num_nodes++;
1881
1882
        /* Unprotect node */
1883
0
        if (H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
1884
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1885
0
        bt = NULL;
1886
0
    } /* end while */
1887
1888
    /* Check for another "row" of B-tree nodes to iterate over */
1889
0
    if (level > 0) {
1890
        /* Keep following the left-most child until we reach a leaf node. */
1891
0
        if (H5B__get_info_helper(f, type, left_child, info_udata) < 0)
1892
0
            HGOTO_ERROR(H5E_BTREE, H5E_BADITER, FAIL, "unable to list B-tree node");
1893
0
    } /* end if */
1894
1895
0
done:
1896
0
    if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
1897
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1898
1899
0
    FUNC_LEAVE_NOAPI(ret_value)
1900
0
} /* end H5B__get_info_helper() */
1901
1902
/*-------------------------------------------------------------------------
1903
 * Function:    H5B_get_info
1904
 *
1905
 * Purpose:     Return the amount of storage used for the btree.
1906
 *
1907
 * Return:      Non-negative on success/Negative on failure
1908
 *
1909
 *-------------------------------------------------------------------------
1910
 */
1911
herr_t
1912
H5B_get_info(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_info_t *bt_info, H5B_operator_t op,
1913
             void *udata)
1914
0
{
1915
0
    H5B_info_ud_t info_udata;          /* User-data for B-tree size iteration */
1916
0
    herr_t        ret_value = SUCCEED; /* Return value */
1917
1918
0
    FUNC_ENTER_NOAPI(FAIL)
1919
1920
    /*
1921
     * Check arguments.
1922
     */
1923
0
    assert(f);
1924
0
    assert(type);
1925
0
    assert(bt_info);
1926
0
    assert(H5_addr_defined(addr));
1927
0
    assert(udata);
1928
1929
    /* Portably initialize B-tree info struct */
1930
0
    memset(bt_info, 0, sizeof(*bt_info));
1931
1932
    /* Set up internal user-data for the B-tree 'get info' helper routine */
1933
0
    info_udata.bt_info = bt_info;
1934
0
    info_udata.udata   = udata;
1935
1936
    /* Iterate over the B-tree nodes */
1937
0
    if (H5B__get_info_helper(f, type, addr, &info_udata) < 0)
1938
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADITER, FAIL, "B-tree iteration failed");
1939
1940
    /* Iterate over the B-tree records, making any "leaf" callbacks */
1941
    /* (Only if operator defined) */
1942
0
    if (op)
1943
0
        if ((ret_value = H5B__iterate_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, op, udata)) < 0)
1944
0
            HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
1945
1946
0
done:
1947
0
    FUNC_LEAVE_NOAPI(ret_value)
1948
0
} /* end H5B_get_info() */
1949
1950
/*-------------------------------------------------------------------------
1951
 * Function:    H5B_valid
1952
 *
1953
 * Purpose:     Attempt to load a B-tree node.
1954
 *
1955
 * Return:      Non-negative on success/Negative on failure
1956
 *
1957
 *-------------------------------------------------------------------------
1958
 */
1959
herr_t
1960
H5B_valid(H5F_t *f, const H5B_class_t *type, haddr_t addr)
1961
4
{
1962
4
    H5B_t         *bt = NULL;           /* The B-tree */
1963
4
    H5UC_t        *rc_shared;           /* Ref-counted shared info */
1964
4
    H5B_cache_ud_t cache_udata;         /* User-data for metadata cache callback */
1965
4
    herr_t         ret_value = SUCCEED; /* Return value */
1966
1967
4
    FUNC_ENTER_NOAPI(FAIL)
1968
1969
    /*
1970
     * Check arguments.
1971
     */
1972
4
    assert(f);
1973
4
    assert(type);
1974
1975
4
    if (!H5_addr_defined(addr))
1976
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "address is undefined");
1977
1978
    /* Get shared info for B-tree */
1979
4
    if (NULL == (rc_shared = (type->get_shared)(f, NULL)))
1980
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object");
1981
4
    assert(H5UC_GET_OBJ(rc_shared) != NULL);
1982
1983
    /*
1984
     * Load the tree node.
1985
     */
1986
4
    cache_udata.f         = f;
1987
4
    cache_udata.type      = type;
1988
4
    cache_udata.rc_shared = rc_shared;
1989
4
    cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
1990
4
    if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
1991
3
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree node");
1992
1993
4
done:
1994
    /* Release the node */
1995
4
    if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
1996
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node");
1997
1998
4
    FUNC_LEAVE_NOAPI(ret_value)
1999
4
} /* end H5B_valid() */
2000
2001
/*-------------------------------------------------------------------------
2002
 * Function:    H5B__node_dest
2003
 *
2004
 * Purpose:     Destroy/release a B-tree node
2005
 *
2006
 * Return:      Success:        SUCCEED
2007
 *              Failure:        FAIL
2008
 *
2009
 *-------------------------------------------------------------------------
2010
 */
2011
herr_t
2012
H5B__node_dest(H5B_t *bt)
2013
2
{
2014
2
    FUNC_ENTER_PACKAGE_NOERR
2015
2016
    /* check arguments */
2017
2
    assert(bt);
2018
2
    assert(bt->rc_shared);
2019
2020
2
    bt->child  = H5FL_SEQ_FREE(haddr_t, bt->child);
2021
2
    bt->native = H5FL_BLK_FREE(native_block, bt->native);
2022
2
    H5UC_DEC(bt->rc_shared);
2023
2
    bt = H5FL_FREE(H5B_t, bt);
2024
2025
2
    FUNC_LEAVE_NOAPI(SUCCEED)
2026
2
} /* end H5B__node_dest() */