Coverage Report

Created: 2026-04-29 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5B2leaf.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:   H5B2leaf.c
16
 *
17
 * Purpose:   Routines for managing v2 B-tree leaf nodes.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5B2module.h" /* This source code file is part of the H5B2 module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions     */
32
#include "H5B2pkg.h"     /* v2 B-trees        */
33
#include "H5Eprivate.h"  /* Error handling        */
34
#include "H5FLprivate.h" /* Free Lists                               */
35
#include "H5MFprivate.h" /* File memory management    */
36
#include "H5MMprivate.h" /* Memory management     */
37
38
/****************/
39
/* Local Macros */
40
/****************/
41
42
/******************/
43
/* Local Typedefs */
44
/******************/
45
46
/********************/
47
/* Package Typedefs */
48
/********************/
49
50
/********************/
51
/* Local Prototypes */
52
/********************/
53
static herr_t H5B2__shadow_leaf(H5B2_leaf_t *leaf, H5B2_node_ptr_t *curr_node_ptr);
54
55
/*********************/
56
/* Package Variables */
57
/*********************/
58
59
/* Declare a free list to manage the H5B2_leaf_t struct */
60
H5FL_DEFINE(H5B2_leaf_t);
61
62
/*****************************/
63
/* Library Private Variables */
64
/*****************************/
65
66
/*******************/
67
/* Local Variables */
68
/*******************/
69
70
/*-------------------------------------------------------------------------
71
 * Function:  H5B2__create_leaf
72
 *
73
 * Purpose: Creates empty leaf node of a B-tree and update node pointer
74
 *              to point to it.
75
 *
76
 * Return:  Non-negative on success/Negative on failure
77
 *
78
 *-------------------------------------------------------------------------
79
 */
80
herr_t
81
H5B2__create_leaf(H5B2_hdr_t *hdr, void *parent, H5B2_node_ptr_t *node_ptr)
82
0
{
83
0
    H5B2_leaf_t *leaf      = NULL;    /* Pointer to new leaf node created */
84
0
    bool         inserted  = false;   /* Whether the leaf node was inserted into cache */
85
0
    herr_t       ret_value = SUCCEED; /* Return value */
86
87
0
    FUNC_ENTER_PACKAGE
88
89
    /* Check arguments. */
90
0
    assert(hdr);
91
0
    assert(node_ptr);
92
93
    /* Allocate memory for leaf information */
94
0
    if (NULL == (leaf = H5FL_CALLOC(H5B2_leaf_t)))
95
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree leaf info");
96
97
    /* Increment ref. count on B-tree header */
98
0
    if (H5B2__hdr_incr(hdr) < 0)
99
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, FAIL, "can't increment ref. count on B-tree header");
100
101
    /* Share B-tree header information */
102
0
    leaf->hdr = hdr;
103
104
    /* Allocate space for the native keys in memory */
105
0
    if (NULL == (leaf->leaf_native = (uint8_t *)H5FL_FAC_MALLOC(hdr->node_info[0].nat_rec_fac)))
106
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree leaf native keys");
107
0
    memset(leaf->leaf_native, 0, hdr->cls->nrec_size * hdr->node_info[0].max_nrec);
108
109
    /* Set parent */
110
0
    leaf->parent = parent;
111
112
    /* Set shadowed epoch to header's epoch */
113
0
    leaf->shadow_epoch = hdr->shadow_epoch;
114
115
    /* Allocate space on disk for the leaf */
116
0
    if (HADDR_UNDEF == (node_ptr->addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, (hsize_t)hdr->node_size)))
117
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for B-tree leaf node");
118
119
    /* Cache the new B-tree node */
120
0
    if (H5AC_insert_entry(hdr->f, H5AC_BT2_LEAF, node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0)
121
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't add B-tree leaf to cache");
122
0
    inserted = true;
123
124
    /* Add leaf node as child of 'top' proxy */
125
0
    if (hdr->top_proxy) {
126
0
        if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, leaf) < 0)
127
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, FAIL, "unable to add v2 B-tree node as child of proxy");
128
0
        leaf->top_proxy = hdr->top_proxy;
129
0
    } /* end if */
130
131
0
done:
132
0
    if (ret_value < 0) {
133
0
        if (leaf) {
134
            /* Remove from cache, if inserted */
135
0
            if (inserted)
136
0
                if (H5AC_remove_entry(leaf) < 0)
137
0
                    HDONE_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL,
138
0
                                "unable to remove v2 B-tree leaf node from cache");
139
140
            /* Release leaf node's disk space */
141
0
            if (H5_addr_defined(node_ptr->addr) &&
142
0
                H5MF_xfree(hdr->f, H5FD_MEM_BTREE, node_ptr->addr, (hsize_t)hdr->node_size) < 0)
143
0
                HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL,
144
0
                            "unable to release file space for v2 B-tree leaf node");
145
146
            /* Destroy leaf node */
147
0
            if (H5B2__leaf_free(leaf) < 0)
148
0
                HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree leaf node");
149
0
        } /* end if */
150
0
    }     /* end if */
151
152
0
    FUNC_LEAVE_NOAPI(ret_value)
153
0
} /* H5B2__create_leaf() */
154
155
/*-------------------------------------------------------------------------
156
 * Function:  H5B2__protect_leaf
157
 *
158
 * Purpose: "Protect" an leaf node in the metadata cache
159
 *
160
 * Return:  Pointer to leaf node on success/NULL on failure
161
 *
162
 *-------------------------------------------------------------------------
163
 */
164
H5B2_leaf_t *
165
H5B2__protect_leaf(H5B2_hdr_t *hdr, void *parent, H5B2_node_ptr_t *node_ptr, bool shadow, unsigned flags)
166
0
{
167
0
    H5B2_leaf_cache_ud_t udata;            /* User-data for callback */
168
0
    H5B2_leaf_t         *leaf;             /* v2 B-tree leaf node */
169
0
    H5B2_leaf_t         *ret_value = NULL; /* Return value */
170
171
0
    FUNC_ENTER_PACKAGE
172
173
    /* Check arguments. */
174
0
    assert(hdr);
175
0
    assert(node_ptr);
176
0
    assert(H5_addr_defined(node_ptr->addr));
177
178
    /* only H5AC__READ_ONLY_FLAG may appear in flags */
179
0
    assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
180
181
    /* Set up user data for callback */
182
0
    udata.f      = hdr->f;
183
0
    udata.hdr    = hdr;
184
0
    udata.parent = parent;
185
0
    udata.nrec   = node_ptr->node_nrec;
186
187
    /* Protect the leaf node */
188
0
    if (NULL == (leaf = (H5B2_leaf_t *)H5AC_protect(hdr->f, H5AC_BT2_LEAF, node_ptr->addr, &udata, flags)))
189
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect B-tree leaf node");
190
191
    /* Create top proxy, if it doesn't exist */
192
0
    if (hdr->top_proxy && NULL == leaf->top_proxy) {
193
        /* Add leaf node as child of 'top' proxy */
194
0
        if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, leaf) < 0)
195
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, NULL, "unable to add v2 B-tree leaf node as child of proxy");
196
0
        leaf->top_proxy = hdr->top_proxy;
197
0
    } /* end if */
198
199
    /* Shadow the node, if requested */
200
0
    if (shadow)
201
0
        if (H5B2__shadow_leaf(leaf, node_ptr) < 0)
202
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, NULL, "unable to shadow leaf node");
203
204
    /* Set return value */
205
0
    ret_value = leaf;
206
207
0
done:
208
    /* Clean up on error */
209
0
    if (!ret_value) {
210
        /* Release the leaf node, if it was protected */
211
0
        if (leaf) {
212
            /* Remove from v2 B-tree's proxy, if added */
213
0
            if (leaf->top_proxy) {
214
0
                if (H5AC_proxy_entry_remove_child(leaf->top_proxy, leaf) < 0)
215
0
                    HDONE_ERROR(
216
0
                        H5E_BTREE, H5E_CANTUNDEPEND, NULL,
217
0
                        "unable to destroy flush dependency between leaf node and v2 B-tree 'top' proxy");
218
0
                leaf->top_proxy = NULL;
219
0
            } /* end if */
220
221
            /* Unprotect leaf node */
222
0
            if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0)
223
0
                HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL,
224
0
                            "unable to unprotect v2 B-tree leaf node, address = %llu",
225
0
                            (unsigned long long)node_ptr->addr);
226
0
        } /* end if */
227
0
    }     /* end if */
228
229
0
    FUNC_LEAVE_NOAPI(ret_value)
230
0
} /* H5B2__protect_leaf() */
231
232
/*-------------------------------------------------------------------------
233
 * Function:  H5B2__neighbor_leaf
234
 *
235
 * Purpose: Locate a record relative to the specified information in a
236
 *              B-tree leaf node and return that information by filling in
237
 *              fields of the
238
 *              caller-supplied UDATA pointer depending on the type of leaf node
239
 *    requested.  The UDATA can point to additional data passed
240
 *    to the key comparison function.
241
 *
242
 *              The 'OP' routine is called with the record found and the
243
 *              OP_DATA pointer, to allow caller to return information about
244
 *              the record.
245
 *
246
 *              The RANGE indicates whether to search for records less than or
247
 *              equal to, or greater than or equal to the information passed
248
 *              in with UDATA.
249
 *
250
 * Return:  Non-negative on success, negative on failure.
251
 *
252
 *-------------------------------------------------------------------------
253
 */
254
herr_t
255
H5B2__neighbor_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, void *neighbor_loc, H5B2_compare_t comp,
256
                    void *parent, void *udata, H5B2_found_t op, void *op_data)
257
0
{
258
0
    H5B2_leaf_t *leaf;                /* Pointer to leaf node */
259
0
    unsigned     idx       = 0;       /* Location of record which matches key */
260
0
    int          cmp       = 0;       /* Comparison value of records */
261
0
    herr_t       ret_value = SUCCEED; /* Return value */
262
263
0
    FUNC_ENTER_PACKAGE
264
265
    /* Check arguments. */
266
0
    assert(hdr);
267
0
    assert(curr_node_ptr);
268
0
    assert(H5_addr_defined(curr_node_ptr->addr));
269
0
    assert(op);
270
271
    /* Lock current B-tree node */
272
0
    if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__READ_ONLY_FLAG)))
273
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
274
275
    /* Locate node pointer for child */
276
0
    if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
277
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
278
0
    if (cmp > 0)
279
0
        idx++;
280
0
    else if (cmp == 0 && comp == H5B2_COMPARE_GREATER)
281
0
        idx++;
282
283
    /* Set the neighbor location, if appropriate */
284
0
    if (comp == H5B2_COMPARE_LESS) {
285
0
        if (idx > 0)
286
0
            neighbor_loc = H5B2_LEAF_NREC(leaf, hdr, idx - 1);
287
0
    } /* end if */
288
0
    else {
289
0
        assert(comp == H5B2_COMPARE_GREATER);
290
291
0
        if (idx < leaf->nrec)
292
0
            neighbor_loc = H5B2_LEAF_NREC(leaf, hdr, idx);
293
0
    } /* end else */
294
295
    /* Make callback if neighbor record has been found */
296
0
    if (neighbor_loc) {
297
        /* Make callback for current record */
298
0
        if ((op)(neighbor_loc, op_data) < 0)
299
0
            HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
300
0
                        "'found' callback failed for B-tree neighbor operation");
301
0
    } /* end if */
302
0
    else
303
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree");
304
305
0
done:
306
    /* Release the B-tree leaf node */
307
0
    if (leaf && H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0)
308
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree leaf node");
309
310
0
    FUNC_LEAVE_NOAPI(ret_value)
311
0
} /* H5B2__neighbor_leaf() */
312
313
/*-------------------------------------------------------------------------
314
 * Function:  H5B2__insert_leaf
315
 *
316
 * Purpose: Adds a new record to a B-tree leaf node.
317
 *
318
 * Return:  Non-negative on success/Negative on failure
319
 *
320
 *-------------------------------------------------------------------------
321
 */
322
herr_t
323
H5B2__insert_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent,
324
                  void *udata)
325
0
{
326
0
    H5B2_leaf_t *leaf;                            /* Pointer to leaf node */
327
0
    unsigned     leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */
328
0
    int          cmp;                             /* Comparison value of records */
329
0
    unsigned     idx       = 0;                   /* Location of record which matches key */
330
0
    herr_t       ret_value = SUCCEED;             /* Return value */
331
332
0
    FUNC_ENTER_PACKAGE
333
334
    /* Check arguments. */
335
0
    assert(hdr);
336
0
    assert(curr_node_ptr);
337
0
    assert(H5_addr_defined(curr_node_ptr->addr));
338
339
    /* Lock current B-tree node */
340
0
    if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET)))
341
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
342
343
    /* Must have a leaf node with enough space to insert a record now */
344
0
    assert(curr_node_ptr->node_nrec < hdr->node_info[0].max_nrec);
345
346
    /* Sanity check number of records */
347
0
    assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
348
0
    assert(leaf->nrec == curr_node_ptr->node_nrec);
349
350
    /* Check for inserting into empty leaf */
351
0
    if (leaf->nrec == 0)
352
0
        idx = 0;
353
0
    else {
354
        /* Find correct location to insert this record */
355
0
        if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
356
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
357
0
        if (cmp == 0)
358
0
            HGOTO_ERROR(H5E_BTREE, H5E_EXISTS, FAIL, "record is already in B-tree");
359
0
        if (cmp > 0)
360
0
            idx++;
361
362
        /* Make room for new record */
363
0
        if (idx < leaf->nrec)
364
0
            memmove(H5B2_LEAF_NREC(leaf, hdr, idx + 1), H5B2_LEAF_NREC(leaf, hdr, idx),
365
0
                    hdr->cls->nrec_size * (leaf->nrec - idx));
366
0
    } /* end else */
367
368
    /* Make callback to store record in native form */
369
0
    if ((hdr->cls->store)(H5B2_LEAF_NREC(leaf, hdr, idx), udata) < 0)
370
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into leaf node");
371
372
    /* Mark the node as dirty */
373
0
    leaf_flags |= H5AC__DIRTIED_FLAG;
374
375
    /* Update record count for node pointer to current node */
376
0
    curr_node_ptr->all_nrec++;
377
0
    curr_node_ptr->node_nrec++;
378
379
    /* Update record count for current node */
380
0
    leaf->nrec++;
381
382
    /* Check for new record being the min or max for the tree */
383
    /* (Don't use 'else' for the idx check, to allow for root leaf node) */
384
0
    if (H5B2_POS_MIDDLE != curr_pos) {
385
0
        if (idx == 0) {
386
0
            if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
387
0
                if (hdr->min_native_rec == NULL)
388
0
                    if (NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
389
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
390
0
                                    "memory allocation failed for v2 B-tree min record info");
391
0
                H5MM_memcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
392
0
            } /* end if */
393
0
        }     /* end if */
394
0
        if (idx == (unsigned)(leaf->nrec - 1)) {
395
0
            if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
396
0
                if (hdr->max_native_rec == NULL)
397
0
                    if (NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
398
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
399
0
                                    "memory allocation failed for v2 B-tree max record info");
400
0
                H5MM_memcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
401
0
            } /* end if */
402
0
        }     /* end if */
403
0
    }         /* end if */
404
405
0
done:
406
    /* Release the B-tree leaf node (marked as dirty) */
407
0
    if (leaf) {
408
        /* Shadow the node if doing SWMR writes */
409
0
        if (hdr->swmr_write && (leaf_flags & H5AC__DIRTIED_FLAG))
410
0
            if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0)
411
0
                HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf B-tree node");
412
413
        /* Unprotect leaf node */
414
0
        if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, leaf_flags) < 0)
415
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node");
416
0
    } /* end if */
417
418
0
    FUNC_LEAVE_NOAPI(ret_value)
419
0
} /* H5B2__insert_leaf() */
420
421
/*-------------------------------------------------------------------------
422
 * Function:  H5B2__update_leaf
423
 *
424
 * Purpose: Insert or modify a record in a B-tree leaf node.
425
 *    If the record exists already, it is modified as if H5B2_modify
426
 *    was called).  If it doesn't exist, it is inserted as if
427
 *    H5B2_insert was called.
428
 *
429
 * Return:  Non-negative on success/Negative on failure
430
 *
431
 *-------------------------------------------------------------------------
432
 */
433
herr_t
434
H5B2__update_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_update_status_t *status,
435
                  H5B2_nodepos_t curr_pos, void *parent, void *udata, H5B2_modify_t op, void *op_data)
436
0
{
437
0
    H5B2_leaf_t *leaf;                            /* Pointer to leaf node */
438
0
    unsigned     leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */
439
0
    int          cmp        = -1;                 /* Comparison value of records */
440
0
    unsigned     idx        = 0;                  /* Location of record which matches key */
441
0
    herr_t       ret_value  = SUCCEED;            /* Return value */
442
443
0
    FUNC_ENTER_PACKAGE
444
445
    /* Check arguments. */
446
0
    assert(hdr);
447
0
    assert(curr_node_ptr);
448
0
    assert(H5_addr_defined(curr_node_ptr->addr));
449
450
    /* Lock current B-tree node */
451
0
    if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET)))
452
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
453
454
    /* Sanity check number of records */
455
0
    assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
456
0
    assert(leaf->nrec == curr_node_ptr->node_nrec);
457
458
    /* Check for inserting into empty leaf */
459
0
    if (leaf->nrec == 0)
460
0
        idx = 0;
461
0
    else {
462
        /* Find correct location to insert this record */
463
0
        if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
464
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
465
466
        /* Check for inserting a record */
467
0
        if (0 != cmp) {
468
            /* Check if the leaf node is full */
469
0
            if (curr_node_ptr->node_nrec == hdr->node_info[0].split_nrec) {
470
                /* Indicate that the leaf is full, but we need to insert */
471
0
                *status = H5B2_UPDATE_INSERT_CHILD_FULL;
472
473
                /* Let calling routine handle insertion */
474
0
                HGOTO_DONE(SUCCEED);
475
0
            } /* end if */
476
477
            /* Adjust index to leave room for record to insert */
478
0
            if (cmp > 0)
479
0
                idx++;
480
481
            /* Make room for new record */
482
0
            if (idx < leaf->nrec)
483
0
                memmove(H5B2_LEAF_NREC(leaf, hdr, idx + 1), H5B2_LEAF_NREC(leaf, hdr, idx),
484
0
                        hdr->cls->nrec_size * (leaf->nrec - idx));
485
0
        } /* end if */
486
0
    }     /* end else */
487
488
    /* Check for modifying existing record */
489
0
    if (0 == cmp) {
490
0
        bool changed = false; /* Whether the 'modify' callback changed the record */
491
492
        /* Make callback for current record */
493
0
        if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data, &changed) < 0) {
494
            /* Make certain that the callback didn't modify the value if it failed */
495
0
            assert(changed == false);
496
497
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL,
498
0
                        "'modify' callback failed for B-tree update operation");
499
0
        } /* end if */
500
501
        /* Mark the node as dirty if it changed */
502
0
        leaf_flags |= (changed ? H5AC__DIRTIED_FLAG : 0);
503
504
        /* Indicate that the record was modified */
505
0
        *status = H5B2_UPDATE_MODIFY_DONE;
506
0
    } /* end if */
507
0
    else {
508
        /* Must have a leaf node with enough space to insert a record now */
509
0
        assert(curr_node_ptr->node_nrec < hdr->node_info[0].max_nrec);
510
511
        /* Make callback to store record in native form */
512
0
        if ((hdr->cls->store)(H5B2_LEAF_NREC(leaf, hdr, idx), udata) < 0)
513
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into leaf node");
514
515
        /* Mark the node as dirty */
516
0
        leaf_flags |= H5AC__DIRTIED_FLAG;
517
518
        /* Indicate that the record was inserted */
519
0
        *status = H5B2_UPDATE_INSERT_DONE;
520
521
        /* Update record count for node pointer to current node */
522
0
        curr_node_ptr->all_nrec++;
523
0
        curr_node_ptr->node_nrec++;
524
525
        /* Update record count for current node */
526
0
        leaf->nrec++;
527
0
    } /* end else */
528
529
    /* Check for new record being the min or max for the tree */
530
    /* (Don't use 'else' for the idx check, to allow for root leaf node) */
531
0
    if (H5B2_POS_MIDDLE != curr_pos) {
532
0
        if (idx == 0) {
533
0
            if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
534
0
                if (hdr->min_native_rec == NULL)
535
0
                    if (NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
536
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
537
0
                                    "memory allocation failed for v2 B-tree min record info");
538
0
                H5MM_memcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
539
0
            } /* end if */
540
0
        }     /* end if */
541
0
        if (idx == (unsigned)(leaf->nrec - 1)) {
542
0
            if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
543
0
                if (hdr->max_native_rec == NULL)
544
0
                    if (NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
545
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL,
546
0
                                    "memory allocation failed for v2 B-tree max record info");
547
0
                H5MM_memcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
548
0
            } /* end if */
549
0
        }     /* end if */
550
0
    }         /* end if */
551
552
0
done:
553
    /* Release the B-tree leaf node */
554
0
    if (leaf) {
555
        /* Check if we should shadow this node */
556
0
        if (hdr->swmr_write && (leaf_flags & H5AC__DIRTIED_FLAG)) {
557
            /* Attempt to shadow the node if doing SWMR writes */
558
0
            if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0)
559
0
                HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf B-tree node");
560
561
            /* Change the state to "shadowed" if only modified currently */
562
            /* (Triggers parent to be marked dirty) */
563
0
            if (*status == H5B2_UPDATE_MODIFY_DONE)
564
0
                *status = H5B2_UPDATE_SHADOW_DONE;
565
0
        } /* end if */
566
567
        /* Unprotect leaf node */
568
0
        if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, leaf_flags) < 0)
569
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node");
570
0
    } /* end if */
571
572
0
    FUNC_LEAVE_NOAPI(ret_value)
573
0
} /* H5B2__update_leaf() */
574
575
/*-------------------------------------------------------------------------
576
 * Function:  H5B2__swap_leaf
577
 *
578
 * Purpose: Swap a record in a node with a record in a leaf node
579
 *
580
 * Return:  Success:  Non-negative
581
 *
582
 *    Failure:  Negative
583
 *
584
 *-------------------------------------------------------------------------
585
 */
586
herr_t
587
H5B2__swap_leaf(H5B2_hdr_t *hdr, uint16_t depth, H5B2_internal_t *internal, unsigned *internal_flags_ptr,
588
                unsigned idx, void *swap_loc)
589
0
{
590
0
    const H5AC_class_t *child_class;              /* Pointer to child node's class info */
591
0
    haddr_t             child_addr = HADDR_UNDEF; /* Address of child node */
592
0
    void               *child      = NULL;        /* Pointer to child node */
593
0
    uint8_t            *child_native;             /* Pointer to child's native records */
594
0
    herr_t              ret_value = SUCCEED;      /* Return value */
595
596
0
    FUNC_ENTER_PACKAGE
597
598
    /* Check arguments. */
599
0
    assert(hdr);
600
0
    assert(internal);
601
0
    assert(internal_flags_ptr);
602
0
    assert(idx <= internal->nrec);
603
604
    /* Check for the kind of B-tree node to swap */
605
0
    if (depth > 1) {
606
0
        H5B2_internal_t *child_internal; /* Pointer to internal node */
607
608
        /* Setup information for unlocking child node */
609
0
        child_class = H5AC_BT2_INT;
610
611
        /* Lock B-tree child nodes */
612
0
        if (NULL ==
613
0
            (child_internal = H5B2__protect_internal(hdr, internal, &internal->node_ptrs[idx],
614
0
                                                     (uint16_t)(depth - 1), false, H5AC__NO_FLAGS_SET)))
615
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node");
616
0
        child_addr = internal->node_ptrs[idx].addr;
617
618
        /* More setup for accessing child node information */
619
0
        child        = child_internal;
620
0
        child_native = child_internal->int_native;
621
0
    } /* end if */
622
0
    else {
623
0
        H5B2_leaf_t *child_leaf; /* Pointer to leaf node */
624
625
        /* Setup information for unlocking child nodes */
626
0
        child_class = H5AC_BT2_LEAF;
627
628
        /* Lock B-tree child node */
629
0
        if (NULL == (child_leaf = H5B2__protect_leaf(hdr, internal, &internal->node_ptrs[idx], false,
630
0
                                                     H5AC__NO_FLAGS_SET)))
631
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
632
0
        child_addr = internal->node_ptrs[idx].addr;
633
634
        /* More setup for accessing child node information */
635
0
        child        = child_leaf;
636
0
        child_native = child_leaf->leaf_native;
637
0
    } /* end else */
638
639
    /* Swap records (use disk page as temporary buffer) */
640
0
    H5MM_memcpy(hdr->page, H5B2_NAT_NREC(child_native, hdr, 0), hdr->cls->nrec_size);
641
0
    H5MM_memcpy(H5B2_NAT_NREC(child_native, hdr, 0), swap_loc, hdr->cls->nrec_size);
642
0
    H5MM_memcpy(swap_loc, hdr->page, hdr->cls->nrec_size);
643
644
    /* Mark parent as dirty */
645
0
    *internal_flags_ptr |= H5AC__DIRTIED_FLAG;
646
647
#ifdef H5B2_DEBUG
648
    H5B2__assert_internal((hsize_t)0, hdr, internal);
649
    if (depth > 1)
650
        H5B2__assert_internal(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)child);
651
    else
652
        H5B2__assert_leaf(hdr, (H5B2_leaf_t *)child);
653
#endif /* H5B2_DEBUG */
654
655
0
done:
656
    /* Unlock child node */
657
0
    if (child && H5AC_unprotect(hdr->f, child_class, child_addr, child, H5AC__DIRTIED_FLAG) < 0)
658
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node");
659
660
0
    FUNC_LEAVE_NOAPI(ret_value)
661
0
} /* end H5B2__swap_leaf() */
662
663
/*-------------------------------------------------------------------------
664
 * Function:    H5B2__shadow_leaf
665
 *
666
 * Purpose:     "Shadow" a leaf node - copy it to a new location, leaving
667
 *              the data in the old location intact (for now).  This is
668
 *              done when writing in SWMR mode to ensure that readers do
669
 *              not see nodes that are out of date with respect to each
670
 *              other and thereby inconsistent.
671
 *
672
 * Return:      Non-negative on success/Negative on failure
673
 *
674
 *-------------------------------------------------------------------------
675
 */
676
static herr_t
677
H5B2__shadow_leaf(H5B2_leaf_t *leaf, H5B2_node_ptr_t *curr_node_ptr)
678
0
{
679
0
    H5B2_hdr_t *hdr;                 /* B-tree header */
680
0
    herr_t      ret_value = SUCCEED; /* Return value */
681
682
0
    FUNC_ENTER_PACKAGE
683
684
    /*
685
     * Check arguments.
686
     */
687
0
    assert(leaf);
688
0
    assert(curr_node_ptr);
689
0
    assert(H5_addr_defined(curr_node_ptr->addr));
690
0
    hdr = leaf->hdr;
691
0
    assert(hdr);
692
0
    assert(hdr->swmr_write);
693
694
    /* We only need to shadow the node if it has not been shadowed since the
695
     * last time the header was flushed, as otherwise it will be unreachable by
696
     * the readers so there will be no need to shadow.  To check if it has been
697
     * shadowed, compare the epoch of this node and the header.  If this node's
698
     * epoch is <= to the header's, it hasn't been shadowed yet. */
699
0
    if (leaf->shadow_epoch <= hdr->shadow_epoch) {
700
0
        haddr_t new_node_addr; /* Address to move node to */
701
702
        /*
703
         * We must clone the old node so readers with an out-of-date version of
704
         * the parent can still see the correct number of children, via the
705
         * shadowed node.  Remove it from cache but do not mark it free on disk.
706
         */
707
        /* Allocate space for the cloned node */
708
0
        if (HADDR_UNDEF == (new_node_addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, (hsize_t)hdr->node_size)))
709
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move B-tree node");
710
711
        /* Move the location of the old child on the disk */
712
0
        if (H5AC_move_entry(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, new_node_addr) < 0)
713
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTMOVE, FAIL, "unable to move B-tree node");
714
0
        curr_node_ptr->addr = new_node_addr;
715
716
        /* Should free the space in the file, but this is not supported by
717
         * SWMR_WRITE code yet - QAK, 2016/12/01
718
         */
719
720
        /* Set shadow epoch for node ahead of header */
721
0
        leaf->shadow_epoch = hdr->shadow_epoch + 1;
722
0
    } /* end if */
723
724
0
done:
725
0
    FUNC_LEAVE_NOAPI(ret_value)
726
0
} /* end H5B2__shadow_leaf() */
727
728
/*-------------------------------------------------------------------------
729
 * Function:  H5B2__remove_leaf
730
 *
731
 * Purpose: Removes a record from a B-tree leaf node.
732
 *
733
 * Return:  Non-negative on success/Negative on failure
734
 *
735
 *-------------------------------------------------------------------------
736
 */
737
herr_t
738
H5B2__remove_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent,
739
                  void *udata, H5B2_remove_t op, void *op_data)
740
0
{
741
0
    H5B2_leaf_t *leaf;                            /* Pointer to leaf node */
742
0
    haddr_t      leaf_addr  = HADDR_UNDEF;        /* Leaf address on disk */
743
0
    unsigned     leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting leaf node */
744
0
    unsigned     idx        = 0;                  /* Location of record which matches key */
745
0
    int          cmp;                             /* Comparison value of records */
746
0
    herr_t       ret_value = SUCCEED;             /* Return value */
747
748
0
    FUNC_ENTER_PACKAGE
749
750
    /* Check arguments. */
751
0
    assert(hdr);
752
0
    assert(curr_node_ptr);
753
0
    assert(H5_addr_defined(curr_node_ptr->addr));
754
755
    /* Lock current B-tree node */
756
0
    if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET)))
757
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
758
0
    leaf_addr = curr_node_ptr->addr;
759
760
    /* Sanity check number of records */
761
0
    assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
762
0
    assert(leaf->nrec == curr_node_ptr->node_nrec);
763
764
    /* Find correct location to remove this record */
765
0
    if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
766
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
767
0
    if (cmp != 0)
768
0
        HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree");
769
770
    /* Check for invalidating the min/max record for the tree */
771
0
    if (H5B2_POS_MIDDLE != curr_pos) {
772
        /* (Don't use 'else' for the idx check, to allow for root leaf node) */
773
0
        if (idx == 0) {
774
0
            if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
775
0
                if (hdr->min_native_rec)
776
0
                    hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec);
777
0
            } /* end if */
778
0
        }     /* end if */
779
0
        if (idx == (unsigned)(leaf->nrec - 1)) {
780
0
            if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
781
0
                if (hdr->max_native_rec)
782
0
                    hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec);
783
0
            } /* end if */
784
0
        }     /* end if */
785
0
    }         /* end if */
786
787
    /* Make 'remove' callback if there is one */
788
0
    if (op)
789
0
        if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0)
790
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record into leaf node");
791
792
    /* Update number of records in node */
793
0
    leaf->nrec--;
794
795
0
    if (leaf->nrec > 0) {
796
        /* Shadow the node if doing SWMR writes */
797
0
        if (hdr->swmr_write) {
798
0
            if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0)
799
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf node");
800
0
            leaf_addr = curr_node_ptr->addr;
801
0
        } /* end if */
802
803
        /* Pack record out of leaf */
804
0
        if (idx < leaf->nrec)
805
0
            memmove(H5B2_LEAF_NREC(leaf, hdr, idx), H5B2_LEAF_NREC(leaf, hdr, (idx + 1)),
806
0
                    hdr->cls->nrec_size * (leaf->nrec - idx));
807
808
        /* Mark leaf node as dirty also */
809
0
        leaf_flags |= H5AC__DIRTIED_FLAG;
810
0
    } /* end if */
811
0
    else {
812
        /* Let the cache know that the object is deleted */
813
0
        leaf_flags |= H5AC__DELETED_FLAG;
814
0
        if (!hdr->swmr_write)
815
0
            leaf_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
816
817
        /* Reset address of parent node pointer */
818
0
        curr_node_ptr->addr = HADDR_UNDEF;
819
0
    } /* end else */
820
821
    /* Update record count for parent of leaf node */
822
0
    curr_node_ptr->node_nrec--;
823
824
0
done:
825
    /* Release the B-tree leaf node */
826
0
    if (leaf && H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, leaf_addr, leaf, leaf_flags) < 0)
827
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node");
828
829
0
    FUNC_LEAVE_NOAPI(ret_value)
830
0
} /* H5B2__remove_leaf() */
831
832
/*-------------------------------------------------------------------------
833
 * Function:  H5B2__remove_leaf_by_idx
834
 *
835
 * Purpose: Removes a record from a B-tree leaf node, according to the
836
 *              offset in the B-tree records.
837
 *
838
 * Return:  Non-negative on success/Negative on failure
839
 *
840
 *-------------------------------------------------------------------------
841
 */
842
herr_t
843
H5B2__remove_leaf_by_idx(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos,
844
                         void *parent, unsigned idx, H5B2_remove_t op, void *op_data)
845
0
{
846
0
    H5B2_leaf_t *leaf;                            /* Pointer to leaf node */
847
0
    haddr_t      leaf_addr  = HADDR_UNDEF;        /* Leaf address on disk */
848
0
    unsigned     leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting leaf node */
849
0
    herr_t       ret_value  = SUCCEED;            /* Return value */
850
851
0
    FUNC_ENTER_PACKAGE
852
853
    /* Check arguments. */
854
0
    assert(hdr);
855
0
    assert(curr_node_ptr);
856
0
    assert(H5_addr_defined(curr_node_ptr->addr));
857
858
    /* Lock B-tree leaf node */
859
0
    if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET)))
860
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node");
861
0
    leaf_addr = curr_node_ptr->addr;
862
863
    /* Sanity check number of records */
864
0
    assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
865
0
    assert(leaf->nrec == curr_node_ptr->node_nrec);
866
0
    assert(idx < leaf->nrec);
867
868
    /* Check for invalidating the min/max record for the tree */
869
0
    if (H5B2_POS_MIDDLE != curr_pos) {
870
        /* (Don't use 'else' for the idx check, to allow for root leaf node) */
871
0
        if (idx == 0) {
872
0
            if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
873
0
                if (hdr->min_native_rec)
874
0
                    hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec);
875
0
            } /* end if */
876
0
        }     /* end if */
877
0
        if (idx == (unsigned)(leaf->nrec - 1)) {
878
0
            if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
879
0
                if (hdr->max_native_rec)
880
0
                    hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec);
881
0
            } /* end if */
882
0
        }     /* end if */
883
0
    }         /* end if */
884
885
    /* Make 'remove' callback if there is one */
886
0
    if (op)
887
0
        if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0)
888
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record into leaf node");
889
890
    /* Update number of records in node */
891
0
    leaf->nrec--;
892
893
0
    if (leaf->nrec > 0) {
894
        /* Shadow the node if doing SWMR writes */
895
0
        if (hdr->swmr_write) {
896
0
            if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0)
897
0
                HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf node");
898
0
            leaf_addr = curr_node_ptr->addr;
899
0
        } /* end if */
900
901
        /* Pack record out of leaf */
902
0
        if (idx < leaf->nrec)
903
0
            memmove(H5B2_LEAF_NREC(leaf, hdr, idx), H5B2_LEAF_NREC(leaf, hdr, (idx + 1)),
904
0
                    hdr->cls->nrec_size * (leaf->nrec - idx));
905
906
        /* Mark leaf node as dirty also */
907
0
        leaf_flags |= H5AC__DIRTIED_FLAG;
908
0
    } /* end if */
909
0
    else {
910
        /* Let the cache know that the object is deleted */
911
0
        leaf_flags |= H5AC__DELETED_FLAG;
912
0
        if (!hdr->swmr_write)
913
0
            leaf_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
914
915
        /* Reset address of parent node pointer */
916
0
        curr_node_ptr->addr = HADDR_UNDEF;
917
0
    } /* end else */
918
919
    /* Update record count for parent of leaf node */
920
0
    curr_node_ptr->node_nrec--;
921
922
0
done:
923
    /* Release the B-tree leaf node */
924
0
    if (leaf && H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, leaf_addr, leaf, leaf_flags) < 0)
925
0
        HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node");
926
927
0
    FUNC_LEAVE_NOAPI(ret_value)
928
0
} /* H5B2__remove_leaf_by_idx() */
929
930
/*-------------------------------------------------------------------------
931
 * Function:  H5B2__leaf_free
932
 *
933
 * Purpose: Destroys a B-tree leaf node in memory.
934
 *
935
 * Return:  Non-negative on success/Negative on failure
936
 *
937
 *-------------------------------------------------------------------------
938
 */
939
herr_t
940
H5B2__leaf_free(H5B2_leaf_t *leaf)
941
0
{
942
0
    herr_t ret_value = SUCCEED; /* Return value */
943
944
0
    FUNC_ENTER_PACKAGE
945
946
    /*
947
     * Check arguments.
948
     */
949
0
    assert(leaf);
950
951
    /* Release leaf's native key buffer */
952
0
    if (leaf->leaf_native)
953
0
        leaf->leaf_native = (uint8_t *)H5FL_FAC_FREE(leaf->hdr->node_info[0].nat_rec_fac, leaf->leaf_native);
954
955
    /* Decrement ref. count on B-tree header */
956
0
    if (H5B2__hdr_decr(leaf->hdr) < 0)
957
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL, "can't decrement ref. count on B-tree header");
958
959
    /* Sanity check */
960
0
    assert(NULL == leaf->top_proxy);
961
962
    /* Free B-tree leaf node info */
963
0
    leaf = H5FL_FREE(H5B2_leaf_t, leaf);
964
965
0
done:
966
0
    FUNC_LEAVE_NOAPI(ret_value)
967
0
} /* end H5B2__leaf_free() */
968
969
#ifdef H5B2_DEBUG
970
971
/*-------------------------------------------------------------------------
972
 * Function:  H5B2__assert_leaf
973
 *
974
 * Purpose: Verify than a leaf node is mostly sane
975
 *
976
 * Return:  Non-negative on success, negative on failure
977
 *
978
 *-------------------------------------------------------------------------
979
 */
980
H5_ATTR_PURE herr_t
981
H5B2__assert_leaf(const H5B2_hdr_t H5_ATTR_NDEBUG_UNUSED *hdr, const H5B2_leaf_t H5_ATTR_NDEBUG_UNUSED *leaf)
982
{
983
    /* General sanity checking on node */
984
    assert(leaf->nrec <= hdr->node_info->split_nrec);
985
986
    return (0);
987
} /* end H5B2__assert_leaf() */
988
989
/*-------------------------------------------------------------------------
990
 * Function:  H5B2__assert_leaf2
991
 *
992
 * Purpose: Verify than a leaf node is mostly sane
993
 *
994
 * Return:  Non-negative on success, negative on failure
995
 *
996
 *-------------------------------------------------------------------------
997
 */
998
H5_ATTR_PURE herr_t
999
H5B2__assert_leaf2(const H5B2_hdr_t H5_ATTR_NDEBUG_UNUSED *hdr, const H5B2_leaf_t H5_ATTR_NDEBUG_UNUSED *leaf,
1000
                   const H5B2_leaf_t H5_ATTR_UNUSED *leaf2)
1001
{
1002
    /* General sanity checking on node */
1003
    assert(leaf->nrec <= hdr->node_info->split_nrec);
1004
1005
    return (0);
1006
} /* end H5B2__assert_leaf2() */
1007
#endif /* H5B2_DEBUG */