Coverage Report

Created: 2026-01-09 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5B2cache.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:     H5B2cache.c
16
 *
17
 * Purpose:     Implement v2 B-tree metadata cache methods
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 "H5ACprivate.h" /* Metadata Cache                           */
33
#include "H5B2pkg.h"     /* B-Trees (Version 2)                      */
34
#include "H5Eprivate.h"  /* Error Handling                           */
35
#include "H5Fprivate.h"  /* Files                                    */
36
#include "H5FLprivate.h" /* Free Lists                               */
37
#include "H5MMprivate.h" /* Memory Management                        */
38
39
/****************/
40
/* Local Macros */
41
/****************/
42
43
/* B-tree format version #'s */
44
0
#define H5B2_HDR_VERSION  0 /* Header */
45
0
#define H5B2_INT_VERSION  0 /* Internal node */
46
0
#define H5B2_LEAF_VERSION 0 /* Leaf node */
47
48
/******************/
49
/* Local Typedefs */
50
/******************/
51
52
/********************/
53
/* Package Typedefs */
54
/********************/
55
56
/********************/
57
/* Local Prototypes */
58
/********************/
59
60
/* Metadata cache callbacks */
61
static herr_t H5B2__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
62
static htri_t H5B2__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata);
63
static void  *H5B2__cache_hdr_deserialize(const void *image, size_t len, void *udata, bool *dirty);
64
static herr_t H5B2__cache_hdr_image_len(const void *thing, size_t *image_len);
65
static herr_t H5B2__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing);
66
static herr_t H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *thing);
67
static herr_t H5B2__cache_hdr_free_icr(void *thing);
68
69
static herr_t H5B2__cache_int_get_initial_load_size(void *udata, size_t *image_len);
70
static htri_t H5B2__cache_int_verify_chksum(const void *image_ptr, size_t len, void *udata);
71
static void  *H5B2__cache_int_deserialize(const void *image, size_t len, void *udata, bool *dirty);
72
static herr_t H5B2__cache_int_image_len(const void *thing, size_t *image_len);
73
static herr_t H5B2__cache_int_serialize(const H5F_t *f, void *image, size_t len, void *thing);
74
static herr_t H5B2__cache_int_notify(H5AC_notify_action_t action, void *thing);
75
static herr_t H5B2__cache_int_free_icr(void *thing);
76
77
static herr_t H5B2__cache_leaf_get_initial_load_size(void *udata, size_t *image_len);
78
static htri_t H5B2__cache_leaf_verify_chksum(const void *image_ptr, size_t len, void *udata);
79
static void  *H5B2__cache_leaf_deserialize(const void *image, size_t len, void *udata, bool *dirty);
80
static herr_t H5B2__cache_leaf_image_len(const void *thing, size_t *image_len);
81
static herr_t H5B2__cache_leaf_serialize(const H5F_t *f, void *image, size_t len, void *thing);
82
static herr_t H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *thing);
83
static herr_t H5B2__cache_leaf_free_icr(void *thing);
84
85
/*********************/
86
/* Package Variables */
87
/*********************/
88
89
/* H5B2 inherits cache-like properties from H5AC */
90
const H5AC_class_t H5AC_BT2_HDR[1] = {{
91
    H5AC_BT2_HDR_ID,                       /* Metadata client ID */
92
    "v2 B-tree header",                    /* Metadata client name (for debugging) */
93
    H5FD_MEM_BTREE,                        /* File space memory type for client */
94
    H5AC__CLASS_NO_FLAGS_SET,              /* Client class behavior flags */
95
    H5B2__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
96
    NULL,                                  /* 'get_final_load_size' callback */
97
    H5B2__cache_hdr_verify_chksum,         /* 'verify_chksum' callback */
98
    H5B2__cache_hdr_deserialize,           /* 'deserialize' callback */
99
    H5B2__cache_hdr_image_len,             /* 'image_len' callback */
100
    NULL,                                  /* 'pre_serialize' callback */
101
    H5B2__cache_hdr_serialize,             /* 'serialize' callback */
102
    H5B2__cache_hdr_notify,                /* 'notify' callback */
103
    H5B2__cache_hdr_free_icr,              /* 'free_icr' callback */
104
    NULL,                                  /* 'fsf_size' callback */
105
}};
106
107
/* H5B2 inherits cache-like properties from H5AC */
108
const H5AC_class_t H5AC_BT2_INT[1] = {{
109
    H5AC_BT2_INT_ID,                       /* Metadata client ID */
110
    "v2 B-tree internal node",             /* Metadata client name (for debugging) */
111
    H5FD_MEM_BTREE,                        /* File space memory type for client */
112
    H5AC__CLASS_NO_FLAGS_SET,              /* Client class behavior flags */
113
    H5B2__cache_int_get_initial_load_size, /* 'get_initial_load_size' callback */
114
    NULL,                                  /* 'get_final_load_size' callback */
115
    H5B2__cache_int_verify_chksum,         /* 'verify_chksum' callback */
116
    H5B2__cache_int_deserialize,           /* 'deserialize' callback */
117
    H5B2__cache_int_image_len,             /* 'image_len' callback */
118
    NULL,                                  /* 'pre_serialize' callback */
119
    H5B2__cache_int_serialize,             /* 'serialize' callback */
120
    H5B2__cache_int_notify,                /* 'notify' callback */
121
    H5B2__cache_int_free_icr,              /* 'free_icr' callback */
122
    NULL,                                  /* 'fsf_size' callback */
123
}};
124
125
/* H5B2 inherits cache-like properties from H5AC */
126
const H5AC_class_t H5AC_BT2_LEAF[1] = {{
127
    H5AC_BT2_LEAF_ID,                       /* Metadata client ID */
128
    "v2 B-tree leaf node",                  /* Metadata client name (for debugging) */
129
    H5FD_MEM_BTREE,                         /* File space memory type for client */
130
    H5AC__CLASS_NO_FLAGS_SET,               /* Client class behavior flags */
131
    H5B2__cache_leaf_get_initial_load_size, /* 'get_initial_load_size' callback */
132
    NULL,                                   /* 'get_final_load_size' callback */
133
    H5B2__cache_leaf_verify_chksum,         /* 'verify_chksum' callback */
134
    H5B2__cache_leaf_deserialize,           /* 'deserialize' callback */
135
    H5B2__cache_leaf_image_len,             /* 'image_len' callback */
136
    NULL,                                   /* 'pre_serialize' callback */
137
    H5B2__cache_leaf_serialize,             /* 'serialize' callback */
138
    H5B2__cache_leaf_notify,                /* 'notify' callback */
139
    H5B2__cache_leaf_free_icr,              /* 'free_icr' callback */
140
    NULL,                                   /* 'fsf_size' callback */
141
}};
142
143
/*****************************/
144
/* Library Private Variables */
145
/*****************************/
146
147
/*******************/
148
/* Local Variables */
149
/*******************/
150
151
/*-------------------------------------------------------------------------
152
 * Function:    H5B2__cache_hdr_get_initial_load_size
153
 *
154
 * Purpose:     Compute the size of the data structure on disk.
155
 *
156
 * Return:      Non-negative on success/Negative on failure
157
 *
158
 *-------------------------------------------------------------------------
159
 */
160
static herr_t
161
H5B2__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)
162
0
{
163
0
    H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; /* User data for callback */
164
165
0
    FUNC_ENTER_PACKAGE_NOERR
166
167
    /* Check arguments */
168
0
    assert(udata);
169
0
    assert(udata->f);
170
0
    assert(image_len);
171
172
    /* Set the image length size */
173
0
    *image_len = H5B2_HEADER_SIZE_FILE(udata->f);
174
175
0
    FUNC_LEAVE_NOAPI(SUCCEED)
176
0
} /* end H5B2__cache_hdr_get_initial_load_size() */
177
178
/*-------------------------------------------------------------------------
179
 * Function:  H5B2__cache_hdr_verify_chksum
180
 *
181
 * Purpose:     Verify the computed checksum of the data structure is the
182
 *              same as the stored chksum.
183
 *
184
 * Return:      Success:        true/false
185
 *              Failure:        Negative
186
 *
187
 *-------------------------------------------------------------------------
188
 */
189
static htri_t
190
H5B2__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
191
0
{
192
0
    const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
193
0
    uint32_t       stored_chksum;                   /* Stored metadata checksum value */
194
0
    uint32_t       computed_chksum;                 /* Computed metadata checksum value */
195
0
    htri_t         ret_value = true;                /* Return value */
196
197
0
    FUNC_ENTER_PACKAGE
198
199
    /* Check arguments */
200
0
    assert(image);
201
202
    /* Get stored and computed checksums */
203
0
    if (H5F_get_checksums(image, len, &stored_chksum, &computed_chksum) < 0)
204
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't get checksums");
205
206
0
    if (stored_chksum != computed_chksum)
207
0
        ret_value = false;
208
209
0
done:
210
0
    FUNC_LEAVE_NOAPI(ret_value)
211
0
} /* end H5B2__cache_hdr_verify_chksum() */
212
213
/*-------------------------------------------------------------------------
214
 * Function:  H5B2__cache_hdr_deserialize
215
 *
216
 * Purpose: Loads a B-tree header from the disk.
217
 *
218
 * Return:  Success:  Pointer to a new B-tree.
219
 *    Failure:  NULL
220
 *
221
 *-------------------------------------------------------------------------
222
 */
223
static void *
224
H5B2__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata,
225
                            bool H5_ATTR_UNUSED *dirty)
226
0
{
227
0
    H5B2_hdr_t          *hdr   = NULL; /* B-tree header */
228
0
    H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata;
229
0
    H5B2_create_t        cparam;                              /* B-tree creation parameters */
230
0
    H5B2_subid_t         id;                                  /* ID of B-tree class, as found in file */
231
0
    uint16_t             depth;                               /* Depth of B-tree */
232
0
    uint32_t             stored_chksum;                       /* Stored metadata checksum value */
233
0
    const uint8_t       *image     = (const uint8_t *)_image; /* Pointer into raw data buffer */
234
0
    H5B2_hdr_t          *ret_value = NULL;                    /* Return value */
235
236
0
    FUNC_ENTER_PACKAGE
237
238
    /* Check arguments */
239
0
    assert(image);
240
0
    assert(udata);
241
242
    /* Allocate new B-tree header and reset cache info */
243
0
    if (NULL == (hdr = H5B2__hdr_alloc(udata->f)))
244
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "allocation failed for B-tree header");
245
246
    /* Magic number */
247
0
    if (memcmp(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0)
248
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree header signature");
249
0
    image += H5_SIZEOF_MAGIC;
250
251
    /* Version */
252
0
    if (*image++ != H5B2_HDR_VERSION)
253
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree header version");
254
255
    /* B-tree class */
256
0
    id = (H5B2_subid_t)*image++;
257
0
    if (id >= H5B2_NUM_BTREE_ID)
258
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type");
259
260
    /* Node size (in bytes) */
261
0
    UINT32DECODE(image, cparam.node_size);
262
263
    /* Raw key size (in bytes) */
264
0
    UINT16DECODE(image, cparam.rrec_size);
265
266
    /* Depth of tree */
267
0
    UINT16DECODE(image, depth);
268
269
    /* Split & merge %s */
270
0
    cparam.split_percent = *image++;
271
0
    cparam.merge_percent = *image++;
272
273
    /* Root node pointer */
274
0
    H5F_addr_decode(udata->f, (const uint8_t **)&image, &(hdr->root.addr));
275
0
    UINT16DECODE(image, hdr->root.node_nrec);
276
0
    H5F_DECODE_LENGTH(udata->f, image, hdr->root.all_nrec);
277
278
    /* checksum verification already done in verify_chksum cb */
279
280
    /* Metadata checksum */
281
0
    UINT32DECODE(image, stored_chksum);
282
283
    /* Sanity check */
284
0
    assert((size_t)(image - (const uint8_t *)_image) == hdr->hdr_size);
285
286
    /* Initialize B-tree header info */
287
0
    cparam.cls = H5B2_client_class_g[id];
288
0
    if (H5B2__hdr_init(hdr, &cparam, udata->ctx_udata, depth) < 0)
289
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't initialize B-tree header info");
290
291
    /* Set the B-tree header's address */
292
0
    hdr->addr = udata->addr;
293
294
    /* Sanity check */
295
0
    assert((size_t)(image - (const uint8_t *)_image) <= len);
296
297
    /* Set return value */
298
0
    ret_value = hdr;
299
300
0
done:
301
0
    if (!ret_value && hdr)
302
0
        if (H5B2__hdr_free(hdr) < 0)
303
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, NULL, "can't release v2 B-tree header");
304
305
0
    FUNC_LEAVE_NOAPI(ret_value)
306
0
} /* end H5B2__cache_hdr_deserialize() */
307
308
/*-------------------------------------------------------------------------
309
 * Function:    H5B2__cache_hdr_image_len
310
 *
311
 * Purpose:     Compute the size of the data structure on disk.
312
 *
313
 * Return:      Non-negative on success/Negative on failure
314
 *
315
 *-------------------------------------------------------------------------
316
 */
317
static herr_t
318
H5B2__cache_hdr_image_len(const void *_thing, size_t *image_len)
319
0
{
320
0
    const H5B2_hdr_t *hdr = (const H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */
321
322
0
    FUNC_ENTER_PACKAGE_NOERR
323
324
    /* Check arguments */
325
0
    assert(hdr);
326
0
    assert(image_len);
327
328
    /* Set the image length size */
329
0
    *image_len = hdr->hdr_size;
330
331
0
    FUNC_LEAVE_NOAPI(SUCCEED)
332
0
} /* end H5B2__cache_hdr_image_len() */
333
334
/*-------------------------------------------------------------------------
335
 * Function:  H5B2__cache_hdr_serialize
336
 *
337
 * Purpose: Flushes a dirty B-tree header to disk.
338
 *
339
 * Return:  Non-negative on success/Negative on failure
340
 *
341
 *-------------------------------------------------------------------------
342
 */
343
static herr_t
344
H5B2__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, void *_thing)
345
0
{
346
0
    H5B2_hdr_t *hdr   = (H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */
347
0
    uint8_t    *image = (uint8_t *)_image;    /* Pointer into raw data buffer */
348
0
    uint32_t    metadata_chksum;              /* Computed metadata checksum value */
349
350
0
    FUNC_ENTER_PACKAGE_NOERR
351
352
    /* check arguments */
353
0
    assert(f);
354
0
    assert(image);
355
0
    assert(hdr);
356
357
    /* Magic number */
358
0
    H5MM_memcpy(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
359
0
    image += H5_SIZEOF_MAGIC;
360
361
    /* Version # */
362
0
    *image++ = H5B2_HDR_VERSION;
363
364
    /* B-tree type */
365
0
    assert(hdr->cls->id <= 255);
366
0
    *image++ = (uint8_t)hdr->cls->id;
367
368
    /* Node size (in bytes) */
369
0
    UINT32ENCODE(image, hdr->node_size);
370
371
    /* Raw key size (in bytes) */
372
0
    UINT16ENCODE(image, hdr->rrec_size);
373
374
    /* Depth of tree */
375
0
    UINT16ENCODE(image, hdr->depth);
376
377
    /* Split & merge %s */
378
0
    H5_CHECK_OVERFLOW(hdr->split_percent, /* From: */ unsigned, /* To: */ uint8_t);
379
0
    *image++ = (uint8_t)hdr->split_percent;
380
0
    H5_CHECK_OVERFLOW(hdr->merge_percent, /* From: */ unsigned, /* To: */ uint8_t);
381
0
    *image++ = (uint8_t)hdr->merge_percent;
382
383
    /* Root node pointer */
384
0
    H5F_addr_encode(f, &image, hdr->root.addr);
385
0
    UINT16ENCODE(image, hdr->root.node_nrec);
386
0
    H5F_ENCODE_LENGTH(f, image, hdr->root.all_nrec);
387
388
    /* Compute metadata checksum */
389
0
    metadata_chksum = H5_checksum_metadata(_image, (hdr->hdr_size - H5B2_SIZEOF_CHKSUM), 0);
390
391
    /* Metadata checksum */
392
0
    UINT32ENCODE(image, metadata_chksum);
393
394
    /* Sanity check */
395
0
    assert((size_t)(image - (uint8_t *)_image) == len);
396
397
0
    FUNC_LEAVE_NOAPI(SUCCEED)
398
0
} /* H5B2__cache_hdr_serialize() */
399
400
/*-------------------------------------------------------------------------
401
 * Function:    H5B2__cache_hdr_notify
402
 *
403
 * Purpose:     Handle cache action notifications
404
 *
405
 * Return:      Non-negative on success/Negative on failure
406
 *
407
 *-------------------------------------------------------------------------
408
 */
409
static herr_t
410
H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *_thing)
411
0
{
412
0
    H5B2_hdr_t *hdr       = (H5B2_hdr_t *)_thing;
413
0
    herr_t      ret_value = SUCCEED;
414
415
0
    FUNC_ENTER_PACKAGE
416
417
    /*
418
     * Check arguments.
419
     */
420
0
    assert(hdr);
421
422
    /* Check if the file was opened with SWMR-write access */
423
0
    if (hdr->swmr_write) {
424
0
        switch (action) {
425
0
            case H5AC_NOTIFY_ACTION_AFTER_INSERT:
426
0
            case H5AC_NOTIFY_ACTION_AFTER_LOAD:
427
                /* do nothing */
428
0
                break;
429
430
0
            case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
431
                /* Increment the shadow epoch, forcing new modifications to
432
                 * internal and leaf nodes to create new shadow copies */
433
0
                hdr->shadow_epoch++;
434
0
                break;
435
436
0
            case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
437
0
            case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
438
0
            case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
439
0
            case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
440
0
            case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
441
0
            case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
442
                /* do nothing */
443
0
                break;
444
445
0
            case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
446
                /* If hdr->parent != NULL, hdr->parent is used to destroy
447
                 * the flush dependency before the header is evicted.
448
                 */
449
0
                if (hdr->parent) {
450
                    /* Sanity check */
451
0
                    assert(hdr->top_proxy);
452
453
                    /* Destroy flush dependency on object header proxy */
454
0
                    if (H5AC_proxy_entry_remove_child((H5AC_proxy_entry_t *)hdr->parent,
455
0
                                                      (void *)hdr->top_proxy) < 0)
456
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL,
457
0
                                    "unable to destroy flush dependency between v2 B-tree and proxy");
458
0
                    hdr->parent = NULL;
459
0
                } /* end if */
460
461
                /* Detach from 'top' proxy for extensible array */
462
0
                if (hdr->top_proxy) {
463
0
                    if (H5AC_proxy_entry_remove_child(hdr->top_proxy, hdr) < 0)
464
0
                        HGOTO_ERROR(
465
0
                            H5E_BTREE, H5E_CANTUNDEPEND, FAIL,
466
0
                            "unable to destroy flush dependency between header and v2 B-tree 'top' proxy");
467
                    /* Don't reset hdr->top_proxy here, it's destroyed when the header is freed -QAK */
468
0
                } /* end if */
469
0
                break;
470
471
0
            default:
472
0
#ifdef NDEBUG
473
0
                HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache");
474
#else     /* NDEBUG */
475
                assert(0 && "Unknown action?!?");
476
#endif    /* NDEBUG */
477
0
        } /* end switch */
478
0
    }     /* end if */
479
0
    else
480
0
        assert(NULL == hdr->parent);
481
482
0
done:
483
0
    FUNC_LEAVE_NOAPI(ret_value)
484
0
} /* end H5B2__cache_hdr_notify() */
485
486
/*-------------------------------------------------------------------------
487
 * Function:  H5B2__cache_hdr_free_icr
488
 *
489
 * Purpose: Destroy/release an "in core representation" of a data
490
 *              structure
491
 *
492
 * Return:  Non-negative on success/Negative on failure
493
 *
494
 *-------------------------------------------------------------------------
495
 */
496
static herr_t
497
H5B2__cache_hdr_free_icr(void *thing)
498
0
{
499
0
    herr_t ret_value = SUCCEED; /* Return value */
500
501
0
    FUNC_ENTER_PACKAGE
502
503
    /* Check arguments */
504
0
    assert(thing);
505
506
    /* Destroy v2 B-tree header */
507
0
    if (H5B2__hdr_free((H5B2_hdr_t *)thing) < 0)
508
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree header");
509
510
0
done:
511
0
    FUNC_LEAVE_NOAPI(ret_value)
512
0
} /* H5B2__cache_hdr_free_icr() */
513
514
/*-------------------------------------------------------------------------
515
 * Function:    H5B2__cache_int_get_initial_load_size
516
 *
517
 * Purpose:     Compute the size of the data structure on disk.
518
 *
519
 * Return:      Non-negative on success/Negative on failure
520
 *
521
 *-------------------------------------------------------------------------
522
 */
523
static herr_t
524
H5B2__cache_int_get_initial_load_size(void *_udata, size_t *image_len)
525
0
{
526
0
    H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* User data for callback */
527
528
0
    FUNC_ENTER_PACKAGE_NOERR
529
530
    /* Check arguments */
531
0
    assert(udata);
532
0
    assert(udata->hdr);
533
0
    assert(image_len);
534
535
    /* Set the image length size */
536
0
    *image_len = udata->hdr->node_size;
537
538
0
    FUNC_LEAVE_NOAPI(SUCCEED)
539
0
} /* end H5B2__cache_int_get_initial_load_size() */
540
541
/*-------------------------------------------------------------------------
542
 * Function:  H5B2__cache_int_verify_chksum
543
 *
544
 * Purpose:     Verify the computed checksum of the data structure is the
545
 *              same as the stored chksum.
546
 *
547
 * Return:      Success:        true/false
548
 *              Failure:        Negative
549
 *
550
 *-------------------------------------------------------------------------
551
 */
552
static htri_t
553
H5B2__cache_int_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata)
554
0
{
555
0
    const uint8_t            *image = (const uint8_t *)_image;            /* Pointer into raw data buffer */
556
0
    H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
557
0
    size_t                    chk_size;         /* Exact size of the node with checksum at the end */
558
0
    uint32_t                  stored_chksum;    /* Stored metadata checksum value */
559
0
    uint32_t                  computed_chksum;  /* Computed metadata checksum value */
560
0
    htri_t                    ret_value = true; /* Return value */
561
562
0
    FUNC_ENTER_PACKAGE
563
564
    /* Check arguments */
565
0
    assert(image);
566
0
    assert(udata);
567
568
    /* Internal node prefix header + records + child pointer triplets: size with checksum at the end */
569
0
    chk_size = H5B2_INT_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size) +
570
0
               ((size_t)(udata->nrec + 1) * H5B2_INT_POINTER_SIZE(udata->hdr, udata->depth));
571
572
    /* Get stored and computed checksums */
573
0
    if (H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum) < 0)
574
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't get checksums");
575
576
0
    if (stored_chksum != computed_chksum)
577
0
        ret_value = false;
578
579
0
done:
580
0
    FUNC_LEAVE_NOAPI(ret_value)
581
0
} /* end H5B2__cache_int_verify_chksum() */
582
583
/*-------------------------------------------------------------------------
584
 * Function:  H5B2__cache_int_deserialize
585
 *
586
 * Purpose: Deserialize a B-tree internal node from the disk.
587
 *
588
 * Return:  Success:  Pointer to a new B-tree internal node.
589
 *              Failure:        NULL
590
 *
591
 *-------------------------------------------------------------------------
592
 */
593
static void *
594
H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata,
595
                            bool H5_ATTR_UNUSED *dirty)
596
0
{
597
0
    H5B2_internal_cache_ud_t *udata    = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
598
0
    H5B2_internal_t          *internal = NULL;                               /* Internal node read */
599
0
    const uint8_t            *image    = (const uint8_t *)_image; /* Pointer into raw data buffer */
600
0
    uint8_t                  *native;                             /* Pointer to native record info */
601
0
    H5B2_node_ptr_t          *int_node_ptr;                       /* Pointer to node pointer info */
602
0
    uint32_t                  stored_chksum;                      /* Stored metadata checksum value */
603
0
    unsigned                  u;                                  /* Local index variable */
604
0
    H5B2_internal_t          *ret_value = NULL;                   /* Return value */
605
0
    int                       node_nrec = 0;
606
607
0
    FUNC_ENTER_PACKAGE
608
609
    /* Check arguments */
610
0
    assert(image);
611
0
    assert(udata);
612
613
    /* Allocate new internal node and reset cache info */
614
0
    if (NULL == (internal = H5FL_CALLOC(H5B2_internal_t)))
615
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
616
617
    /* Increment ref. count on B-tree header */
618
0
    if (H5B2__hdr_incr(udata->hdr) < 0)
619
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header");
620
621
    /* Share B-tree information */
622
0
    internal->hdr          = udata->hdr;
623
0
    internal->parent       = udata->parent;
624
0
    internal->shadow_epoch = udata->hdr->shadow_epoch;
625
626
    /* Magic number */
627
0
    if (memcmp(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0)
628
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node signature");
629
0
    image += H5_SIZEOF_MAGIC;
630
631
    /* Version */
632
0
    if (*image++ != H5B2_INT_VERSION)
633
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node version");
634
635
    /* B-tree type */
636
0
    if (*image++ != (uint8_t)udata->hdr->cls->id)
637
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type");
638
639
    /* Allocate space for the native keys in memory */
640
0
    if (NULL ==
641
0
        (internal->int_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].nat_rec_fac)))
642
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
643
0
                    "memory allocation failed for B-tree internal native keys");
644
645
    /* Allocate space for the node pointers in memory */
646
0
    if (NULL == (internal->node_ptrs =
647
0
                     (H5B2_node_ptr_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].node_ptr_fac)))
648
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
649
0
                    "memory allocation failed for B-tree internal node pointers");
650
651
    /* Set the number of records in the leaf & it's depth */
652
0
    internal->nrec  = udata->nrec;
653
0
    internal->depth = udata->depth;
654
655
    /* Deserialize records for internal node */
656
0
    native = internal->int_native;
657
0
    for (u = 0; u < internal->nrec; u++) {
658
        /* Decode record */
659
0
        if ((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0)
660
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode B-tree record");
661
662
        /* Move to next record */
663
0
        image += udata->hdr->rrec_size;
664
0
        native += udata->hdr->cls->nrec_size;
665
0
    } /* end for */
666
667
    /* Deserialize node pointers for internal node */
668
0
    int_node_ptr = internal->node_ptrs;
669
0
    for (u = 0; u < (unsigned)(internal->nrec + 1); u++) {
670
        /* Decode node pointer */
671
0
        H5F_addr_decode(udata->f, (const uint8_t **)&image, &(int_node_ptr->addr));
672
0
        UINT64DECODE_VAR(image, node_nrec, udata->hdr->max_nrec_size);
673
0
        H5_CHECKED_ASSIGN(int_node_ptr->node_nrec, uint16_t, node_nrec, int);
674
0
        if (udata->depth > 1)
675
0
            UINT64DECODE_VAR(image, int_node_ptr->all_nrec,
676
0
                             udata->hdr->node_info[udata->depth - 1].cum_max_nrec_size);
677
0
        else
678
0
            int_node_ptr->all_nrec = int_node_ptr->node_nrec;
679
680
        /* Move to next node pointer */
681
0
        int_node_ptr++;
682
0
    } /* end for */
683
684
    /* checksum verification already done in verify_chksum cb */
685
686
    /* Metadata checksum */
687
0
    UINT32DECODE(image, stored_chksum);
688
689
    /* Sanity check parsing */
690
0
    assert((size_t)(image - (const uint8_t *)_image) <= len);
691
692
    /* Set return value */
693
0
    ret_value = internal;
694
695
0
done:
696
0
    if (!ret_value && internal)
697
0
        if (H5B2__internal_free(internal) < 0)
698
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree internal node");
699
700
0
    FUNC_LEAVE_NOAPI(ret_value)
701
0
} /* H5B2__cache_int_deserialize() */
702
703
/*-------------------------------------------------------------------------
704
 * Function:    H5B2__cache_int_image_len
705
 *
706
 * Purpose:     Compute the size of the data structure on disk.
707
 *
708
 * Return:      Non-negative on success/Negative on failure
709
 *
710
 *-------------------------------------------------------------------------
711
 */
712
static herr_t
713
H5B2__cache_int_image_len(const void *_thing, size_t *image_len)
714
0
{
715
0
    const H5B2_internal_t *internal =
716
0
        (const H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */
717
718
0
    FUNC_ENTER_PACKAGE_NOERR
719
720
    /* Check arguments */
721
0
    assert(internal);
722
0
    assert(internal->hdr);
723
0
    assert(image_len);
724
725
    /* Set the image length size */
726
0
    *image_len = internal->hdr->node_size;
727
728
0
    FUNC_LEAVE_NOAPI(SUCCEED)
729
0
} /* end H5B2__cache_int_image_len() */
730
731
/*-------------------------------------------------------------------------
732
 * Function:  H5B2__cache_int_serialize
733
 *
734
 * Purpose: Serializes a B-tree internal node for writing to disk.
735
 *
736
 * Return:  Non-negative on success/Negative on failure
737
 *
738
 *-------------------------------------------------------------------------
739
 */
740
static herr_t
741
H5B2__cache_int_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, void *_thing)
742
0
{
743
0
    H5B2_internal_t *internal = (H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */
744
0
    uint8_t         *image    = (uint8_t *)_image;         /* Pointer into raw data buffer */
745
0
    uint8_t         *native;                               /* Pointer to native record info */
746
0
    H5B2_node_ptr_t *int_node_ptr;                         /* Pointer to node pointer info */
747
0
    uint32_t         metadata_chksum;                      /* Computed metadata checksum value */
748
0
    unsigned         u;                                    /* Local index variable */
749
0
    herr_t           ret_value = SUCCEED;                  /* Return value */
750
751
0
    FUNC_ENTER_PACKAGE
752
753
    /* check arguments */
754
0
    assert(f);
755
0
    assert(image);
756
0
    assert(internal);
757
0
    assert(internal->hdr);
758
759
    /* Magic number */
760
0
    H5MM_memcpy(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC);
761
0
    image += H5_SIZEOF_MAGIC;
762
763
    /* Version # */
764
0
    *image++ = H5B2_INT_VERSION;
765
766
    /* B-tree type */
767
0
    assert(internal->hdr->cls->id <= 255);
768
0
    *image++ = (uint8_t)internal->hdr->cls->id;
769
0
    assert((size_t)(image - (uint8_t *)_image) == (H5B2_INT_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM));
770
771
    /* Serialize records for internal node */
772
0
    native = internal->int_native;
773
0
    for (u = 0; u < internal->nrec; u++) {
774
        /* Encode record */
775
0
        if ((internal->hdr->cls->encode)(image, native, internal->hdr->cb_ctx) < 0)
776
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record");
777
778
        /* Move to next record */
779
0
        image += internal->hdr->rrec_size;
780
0
        native += internal->hdr->cls->nrec_size;
781
0
    } /* end for */
782
783
    /* Serialize node pointers for internal node */
784
0
    int_node_ptr = internal->node_ptrs;
785
0
    for (u = 0; u < (unsigned)(internal->nrec + 1); u++) {
786
        /* Encode node pointer */
787
0
        H5F_addr_encode(f, &image, int_node_ptr->addr);
788
0
        UINT64ENCODE_VAR(image, int_node_ptr->node_nrec, internal->hdr->max_nrec_size);
789
0
        if (internal->depth > 1)
790
0
            UINT64ENCODE_VAR(image, int_node_ptr->all_nrec,
791
0
                             internal->hdr->node_info[internal->depth - 1].cum_max_nrec_size);
792
793
        /* Move to next node pointer */
794
0
        int_node_ptr++;
795
0
    } /* end for */
796
797
    /* Compute metadata checksum */
798
0
    metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
799
800
    /* Metadata checksum */
801
0
    UINT32ENCODE(image, metadata_chksum);
802
803
    /* Sanity check */
804
0
    assert((size_t)(image - (uint8_t *)_image) <= len);
805
806
    /* Clear rest of internal node */
807
0
    memset(image, 0, len - (size_t)(image - (uint8_t *)_image));
808
809
0
done:
810
0
    FUNC_LEAVE_NOAPI(ret_value)
811
0
} /* H5B2__cache_int_serialize() */
812
813
/*-------------------------------------------------------------------------
814
 * Function:    H5B2__cache_int_notify
815
 *
816
 * Purpose:     Handle cache action notifications
817
 *
818
 * Return:      Non-negative on success/Negative on failure
819
 *
820
 *-------------------------------------------------------------------------
821
 */
822
static herr_t
823
H5B2__cache_int_notify(H5AC_notify_action_t action, void *_thing)
824
0
{
825
0
    H5B2_internal_t *internal  = (H5B2_internal_t *)_thing;
826
0
    herr_t           ret_value = SUCCEED;
827
828
0
    FUNC_ENTER_PACKAGE
829
830
    /*
831
     * Check arguments.
832
     */
833
0
    assert(internal);
834
0
    assert(internal->hdr);
835
836
    /* Check if the file was opened with SWMR-write access */
837
0
    if (internal->hdr->swmr_write) {
838
0
        switch (action) {
839
0
            case H5AC_NOTIFY_ACTION_AFTER_INSERT:
840
0
            case H5AC_NOTIFY_ACTION_AFTER_LOAD:
841
                /* Create flush dependency on parent */
842
0
                if (H5B2__create_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0)
843
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency");
844
0
                break;
845
846
0
            case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
847
0
            case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
848
0
            case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
849
0
            case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
850
0
            case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
851
0
            case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
852
0
            case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
853
                /* do nothing */
854
0
                break;
855
856
0
            case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
857
                /* Destroy flush dependency on parent */
858
0
                if (H5B2__destroy_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0)
859
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency");
860
861
                /* Detach from 'top' proxy for v2 B-tree */
862
0
                if (internal->top_proxy) {
863
0
                    if (H5AC_proxy_entry_remove_child(internal->top_proxy, internal) < 0)
864
0
                        HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL,
865
0
                                    "unable to destroy flush dependency between internal node and v2 B-tree "
866
0
                                    "'top' proxy");
867
0
                    internal->top_proxy = NULL;
868
0
                } /* end if */
869
0
                break;
870
871
0
            default:
872
0
#ifdef NDEBUG
873
0
                HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache");
874
#else     /* NDEBUG */
875
                assert(0 && "Unknown action?!?");
876
#endif    /* NDEBUG */
877
0
        } /* end switch */
878
0
    }     /* end if */
879
0
    else
880
0
        assert(NULL == internal->top_proxy);
881
882
0
done:
883
0
    FUNC_LEAVE_NOAPI(ret_value)
884
0
} /* end H5B2__cache_int_notify() */
885
886
/*-------------------------------------------------------------------------
887
 * Function:  H5B2__cache_int_free_icr
888
 *
889
 * Purpose: Destroy/release an "in core representation" of a data
890
 *              structure
891
 *
892
 * Return:  Non-negative on success/Negative on failure
893
 *
894
 *-------------------------------------------------------------------------
895
 */
896
static herr_t
897
H5B2__cache_int_free_icr(void *_thing)
898
0
{
899
0
    H5B2_internal_t *internal  = (H5B2_internal_t *)_thing;
900
0
    herr_t           ret_value = SUCCEED; /* Return value */
901
902
0
    FUNC_ENTER_PACKAGE
903
904
    /* Check arguments */
905
0
    assert(internal);
906
907
    /* Release v2 B-tree internal node */
908
0
    if (H5B2__internal_free(internal) < 0)
909
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree internal node");
910
911
0
done:
912
0
    FUNC_LEAVE_NOAPI(ret_value)
913
0
} /* H5B2__cache_int_free_icr() */
914
915
/*-------------------------------------------------------------------------
916
 * Function:    H5B2__cache_leaf_get_initial_load_size
917
 *
918
 * Purpose:     Compute the size of the data structure on disk.
919
 *
920
 * Return:      Non-negative on success/Negative on failure
921
 *
922
 *-------------------------------------------------------------------------
923
 */
924
static herr_t
925
H5B2__cache_leaf_get_initial_load_size(void *_udata, size_t *image_len)
926
0
{
927
0
    H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; /* User data for callback */
928
929
0
    FUNC_ENTER_PACKAGE_NOERR
930
931
    /* Check arguments */
932
0
    assert(udata);
933
0
    assert(udata->hdr);
934
0
    assert(image_len);
935
936
    /* Set the image length size */
937
0
    *image_len = udata->hdr->node_size;
938
939
0
    FUNC_LEAVE_NOAPI(SUCCEED)
940
0
} /* end H5B2__cache_leaf_get_initial_load_size() */
941
942
/*-------------------------------------------------------------------------
943
 * Function:  H5B2__cache_leaf_verify_chksum
944
 *
945
 * Purpose:     Verify the computed checksum of the data structure is the
946
 *              same as the stored chksum.
947
 *
948
 * Return:      Success:        true/false
949
 *              Failure:        Negative
950
 *
951
 *-------------------------------------------------------------------------
952
 */
953
static htri_t
954
H5B2__cache_leaf_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata)
955
0
{
956
0
    const uint8_t            *image = (const uint8_t *)_image;            /* Pointer into raw data buffer */
957
0
    H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
958
0
    size_t                    chk_size;         /* Exact size of the node with checksum at the end */
959
0
    uint32_t                  stored_chksum;    /* Stored metadata checksum value */
960
0
    uint32_t                  computed_chksum;  /* Computed metadata checksum value */
961
0
    htri_t                    ret_value = true; /* Return value */
962
963
0
    FUNC_ENTER_PACKAGE
964
965
    /* Check arguments */
966
0
    assert(image);
967
0
    assert(udata);
968
969
    /* Leaf node prefix header + records: size with checksum at the end */
970
0
    chk_size = H5B2_LEAF_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size);
971
972
    /* Get stored and computed checksums */
973
0
    if (H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum) < 0)
974
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't get checksums");
975
976
0
    if (stored_chksum != computed_chksum)
977
0
        ret_value = false;
978
979
0
done:
980
0
    FUNC_LEAVE_NOAPI(ret_value)
981
0
} /* end H5B2__cache_leaf_verify_chksum() */
982
983
/*-------------------------------------------------------------------------
984
 * Function:  H5B2__cache_leaf_deserialize
985
 *
986
 * Purpose: Deserialize a B-tree leaf from the disk.
987
 *
988
 * Return:  Success:  Pointer to a new B-tree leaf node.
989
 *    Failure:  NULL
990
 *
991
 *-------------------------------------------------------------------------
992
 */
993
static void *
994
H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata,
995
                             bool H5_ATTR_UNUSED *dirty)
996
0
{
997
0
    H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata;
998
0
    H5B2_leaf_t          *leaf  = NULL;                    /* Pointer to lead node loaded */
999
0
    const uint8_t        *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
1000
0
    uint8_t              *native;                          /* Pointer to native keys */
1001
0
    uint32_t              stored_chksum;                   /* Stored metadata checksum value */
1002
0
    unsigned              u;                               /* Local index variable */
1003
0
    H5B2_leaf_t          *ret_value = NULL;                /* Return value */
1004
1005
0
    FUNC_ENTER_PACKAGE
1006
1007
    /* Check arguments */
1008
0
    assert(image);
1009
0
    assert(udata);
1010
1011
    /* Allocate new leaf node and reset cache info */
1012
0
    if (NULL == (leaf = H5FL_CALLOC(H5B2_leaf_t)))
1013
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed");
1014
1015
    /* Increment ref. count on B-tree header */
1016
0
    if (H5B2__hdr_incr(udata->hdr) < 0)
1017
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header");
1018
1019
    /* Share B-tree header information */
1020
0
    leaf->hdr          = udata->hdr;
1021
0
    leaf->parent       = udata->parent;
1022
0
    leaf->shadow_epoch = udata->hdr->shadow_epoch;
1023
1024
    /* Magic number */
1025
0
    if (memcmp(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0)
1026
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree leaf node signature");
1027
0
    image += H5_SIZEOF_MAGIC;
1028
1029
    /* Version */
1030
0
    if (*image++ != H5B2_LEAF_VERSION)
1031
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree leaf node version");
1032
1033
    /* B-tree type */
1034
0
    if (*image++ != (uint8_t)udata->hdr->cls->id)
1035
0
        HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type");
1036
1037
    /* Allocate space for the native keys in memory */
1038
0
    if (NULL == (leaf->leaf_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[0].nat_rec_fac)))
1039
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree leaf native keys");
1040
1041
    /* Set the number of records in the leaf */
1042
0
    leaf->nrec = udata->nrec;
1043
1044
    /* Deserialize records for leaf node */
1045
0
    native = leaf->leaf_native;
1046
0
    for (u = 0; u < leaf->nrec; u++) {
1047
        /* Decode record */
1048
0
        if ((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0)
1049
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, NULL, "unable to decode B-tree record");
1050
1051
        /* Move to next record */
1052
0
        image += udata->hdr->rrec_size;
1053
0
        native += udata->hdr->cls->nrec_size;
1054
0
    } /* end for */
1055
1056
    /* checksum verification already done in verify_chksum cb */
1057
1058
    /* Metadata checksum */
1059
0
    UINT32DECODE(image, stored_chksum);
1060
1061
    /* Sanity check parsing */
1062
0
    assert((size_t)(image - (const uint8_t *)_image) <= udata->hdr->node_size);
1063
1064
    /* Sanity check */
1065
0
    assert((size_t)(image - (const uint8_t *)_image) <= len);
1066
1067
    /* Set return value */
1068
0
    ret_value = leaf;
1069
1070
0
done:
1071
0
    if (!ret_value && leaf)
1072
0
        if (H5B2__leaf_free(leaf) < 0)
1073
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree leaf node");
1074
1075
0
    FUNC_LEAVE_NOAPI(ret_value)
1076
0
} /* H5B2__cache_leaf_deserialize() */
1077
1078
/*-------------------------------------------------------------------------
1079
 * Function:    H5B2__cache_leaf_image_len
1080
 *
1081
 * Purpose:     Compute the size of the data structure on disk.
1082
 *
1083
 * Return:      Non-negative on success/Negative on failure
1084
 *
1085
 *-------------------------------------------------------------------------
1086
 */
1087
static herr_t
1088
H5B2__cache_leaf_image_len(const void *_thing, size_t *image_len)
1089
0
{
1090
0
    const H5B2_leaf_t *leaf = (const H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node  */
1091
1092
0
    FUNC_ENTER_PACKAGE_NOERR
1093
1094
    /* Check arguments */
1095
0
    assert(leaf);
1096
0
    assert(leaf->hdr);
1097
0
    assert(image_len);
1098
1099
    /* Set the image length size */
1100
0
    *image_len = leaf->hdr->node_size;
1101
1102
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1103
0
} /* end H5B2__cache_leaf_image_len() */
1104
1105
/*-------------------------------------------------------------------------
1106
 * Function:  H5B2__cache_leaf_serialize
1107
 *
1108
 * Purpose: Serializes a B-tree leaf node for writing to disk.
1109
 *
1110
 * Return:  Non-negative on success/Negative on failure
1111
 *
1112
 *-------------------------------------------------------------------------
1113
 */
1114
static herr_t
1115
H5B2__cache_leaf_serialize(const H5F_t H5_ATTR_UNUSED *f, void *_image, size_t H5_ATTR_UNUSED len,
1116
                           void *_thing)
1117
0
{
1118
0
    H5B2_leaf_t *leaf  = (H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node  */
1119
0
    uint8_t     *image = (uint8_t *)_image;     /* Pointer into raw data buffer */
1120
0
    uint8_t     *native;                        /* Pointer to native keys */
1121
0
    uint32_t     metadata_chksum;               /* Computed metadata checksum value */
1122
0
    unsigned     u;                             /* Local index variable */
1123
0
    herr_t       ret_value = SUCCEED;           /* Return value */
1124
1125
0
    FUNC_ENTER_PACKAGE
1126
1127
    /* check arguments */
1128
0
    assert(f);
1129
0
    assert(image);
1130
0
    assert(leaf);
1131
0
    assert(leaf->hdr);
1132
1133
    /* magic number */
1134
0
    H5MM_memcpy(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC);
1135
0
    image += H5_SIZEOF_MAGIC;
1136
1137
    /* version # */
1138
0
    *image++ = H5B2_LEAF_VERSION;
1139
1140
    /* B-tree type */
1141
0
    assert(leaf->hdr->cls->id <= 255);
1142
0
    *image++ = (uint8_t)leaf->hdr->cls->id;
1143
0
    assert((size_t)(image - (uint8_t *)_image) == (H5B2_LEAF_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM));
1144
1145
    /* Serialize records for leaf node */
1146
0
    native = leaf->leaf_native;
1147
0
    for (u = 0; u < leaf->nrec; u++) {
1148
        /* Encode record */
1149
0
        if ((leaf->hdr->cls->encode)(image, native, leaf->hdr->cb_ctx) < 0)
1150
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record");
1151
1152
        /* Move to next record */
1153
0
        image += leaf->hdr->rrec_size;
1154
0
        native += leaf->hdr->cls->nrec_size;
1155
0
    } /* end for */
1156
1157
    /* Compute metadata checksum */
1158
0
    metadata_chksum =
1159
0
        H5_checksum_metadata(_image, (size_t)((const uint8_t *)image - (const uint8_t *)_image), 0);
1160
1161
    /* Metadata checksum */
1162
0
    UINT32ENCODE(image, metadata_chksum);
1163
1164
    /* Sanity check */
1165
0
    assert((size_t)(image - (uint8_t *)_image) <= len);
1166
1167
    /* Clear rest of leaf node */
1168
0
    memset(image, 0, len - (size_t)(image - (uint8_t *)_image));
1169
1170
0
done:
1171
0
    FUNC_LEAVE_NOAPI(ret_value)
1172
0
} /* H5B2__cache_leaf_serialize() */
1173
1174
/*-------------------------------------------------------------------------
1175
 * Function:    H5B2__cache_leaf_notify
1176
 *
1177
 * Purpose:     Handle cache action notifications
1178
 *
1179
 * Return:      Non-negative on success/Negative on failure
1180
 *
1181
 *-------------------------------------------------------------------------
1182
 */
1183
static herr_t
1184
H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *_thing)
1185
0
{
1186
0
    H5B2_leaf_t *leaf      = (H5B2_leaf_t *)_thing;
1187
0
    herr_t       ret_value = SUCCEED;
1188
1189
0
    FUNC_ENTER_PACKAGE
1190
1191
    /*
1192
     * Check arguments.
1193
     */
1194
0
    assert(leaf);
1195
0
    assert(leaf->hdr);
1196
1197
    /* Check if the file was opened with SWMR-write access */
1198
0
    if (leaf->hdr->swmr_write) {
1199
0
        switch (action) {
1200
0
            case H5AC_NOTIFY_ACTION_AFTER_INSERT:
1201
0
            case H5AC_NOTIFY_ACTION_AFTER_LOAD:
1202
                /* Create flush dependency on parent */
1203
0
                if (H5B2__create_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0)
1204
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency");
1205
0
                break;
1206
1207
0
            case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
1208
0
            case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
1209
0
            case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
1210
0
            case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
1211
0
            case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
1212
0
            case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
1213
0
            case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
1214
                /* do nothing */
1215
0
                break;
1216
1217
0
            case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
1218
                /* Destroy flush dependency on parent */
1219
0
                if (H5B2__destroy_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0)
1220
0
                    HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency");
1221
1222
                /* Detach from 'top' proxy for v2 B-tree */
1223
0
                if (leaf->top_proxy) {
1224
0
                    if (H5AC_proxy_entry_remove_child(leaf->top_proxy, leaf) < 0)
1225
0
                        HGOTO_ERROR(
1226
0
                            H5E_BTREE, H5E_CANTUNDEPEND, FAIL,
1227
0
                            "unable to destroy flush dependency between leaf node and v2 B-tree 'top' proxy");
1228
0
                    leaf->top_proxy = NULL;
1229
0
                } /* end if */
1230
0
                break;
1231
1232
0
            default:
1233
0
#ifdef NDEBUG
1234
0
                HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache");
1235
#else     /* NDEBUG */
1236
                assert(0 && "Unknown action?!?");
1237
#endif    /* NDEBUG */
1238
0
        } /* end switch */
1239
0
    }     /* end if */
1240
0
    else
1241
0
        assert(NULL == leaf->top_proxy);
1242
1243
0
done:
1244
0
    FUNC_LEAVE_NOAPI(ret_value)
1245
0
} /* end H5B2__cache_leaf_notify() */
1246
1247
/*-------------------------------------------------------------------------
1248
 * Function:  H5B2__cache_leaf_free_icr
1249
 *
1250
 * Purpose: Destroy/release an "in core representation" of a data
1251
 *              structure
1252
 *
1253
 * Return:  Non-negative on success/Negative on failure
1254
 *
1255
 *-------------------------------------------------------------------------
1256
 */
1257
static herr_t
1258
H5B2__cache_leaf_free_icr(void *_thing)
1259
0
{
1260
0
    H5B2_leaf_t *leaf      = (H5B2_leaf_t *)_thing;
1261
0
    herr_t       ret_value = SUCCEED; /* Return value */
1262
1263
0
    FUNC_ENTER_PACKAGE
1264
1265
    /* Check arguments */
1266
0
    assert(leaf);
1267
1268
    /* Destroy v2 B-tree leaf node */
1269
0
    if (H5B2__leaf_free(leaf) < 0)
1270
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node");
1271
1272
0
done:
1273
0
    FUNC_LEAVE_NOAPI(ret_value)
1274
0
} /* H5B2__cache_leaf_free_icr() */