Coverage Report

Created: 2026-07-25 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Bcache.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:   H5Bcache.c
16
 *
17
 * Purpose:   Implement B-tree metadata cache methods
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Bmodule.h" /* This source code file is part of the H5B module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions     */
32
#include "H5Bpkg.h"      /* B-link trees        */
33
#include "H5Eprivate.h"  /* Error handling        */
34
#include "H5FLprivate.h" /* Free Lists                               */
35
#include "H5MMprivate.h" /* Memory management     */
36
37
/****************/
38
/* Local Macros */
39
/****************/
40
41
/******************/
42
/* Local Typedefs */
43
/******************/
44
45
/********************/
46
/* Local Prototypes */
47
/********************/
48
49
/* Metadata cache callbacks */
50
static herr_t H5B__cache_get_initial_load_size(void *udata, size_t *image_len);
51
static void  *H5B__cache_deserialize(const void *image, size_t len, void *udata, bool *dirty);
52
static herr_t H5B__cache_image_len(const void *thing, size_t *image_len);
53
static herr_t H5B__cache_serialize(const H5F_t *f, void *image, size_t len, void *thing);
54
static herr_t H5B__cache_free_icr(void *thing);
55
56
/*********************/
57
/* Package Variables */
58
/*********************/
59
60
/* H5B inherits cache-like properties from H5AC */
61
const H5AC_class_t H5AC_BT[1] = {{
62
    H5AC_BT_ID,                       /* Metadata client ID */
63
    "v1 B-tree",                      /* Metadata client name (for debugging) */
64
    H5FD_MEM_BTREE,                   /* File space memory type for client */
65
    H5AC__CLASS_NO_FLAGS_SET,         /* Client class behavior flags */
66
    H5B__cache_get_initial_load_size, /* 'get_initial_load_size' callback */
67
    NULL,                             /* 'get_final_load_size' callback */
68
    NULL,                             /* 'verify_chksum' callback */
69
    H5B__cache_deserialize,           /* 'deserialize' callback */
70
    H5B__cache_image_len,             /* 'image_len' callback */
71
    NULL,                             /* 'pre_serialize' callback */
72
    H5B__cache_serialize,             /* 'serialize' callback */
73
    NULL,                             /* 'notify' callback */
74
    H5B__cache_free_icr,              /* 'free_icr' callback */
75
    NULL,                             /* 'fsf_size' callback */
76
}};
77
78
/*******************/
79
/* Local Variables */
80
/*******************/
81
82
/*-------------------------------------------------------------------------
83
 * Function:    H5B__cache_get_initial_load_size
84
 *
85
 * Purpose:     Compute the size of the data structure on disk
86
 *
87
 * Return:      SUCCEED/FAIL
88
 *-------------------------------------------------------------------------
89
 */
90
static herr_t
91
H5B__cache_get_initial_load_size(void *_udata, size_t *image_len)
92
157
{
93
157
    H5B_cache_ud_t *udata = (H5B_cache_ud_t *)_udata; /* User data for callback */
94
157
    H5B_shared_t   *shared;                           /* Pointer to shared B-tree info */
95
96
157
    FUNC_ENTER_PACKAGE_NOERR
97
98
    /* Check arguments */
99
157
    assert(udata);
100
157
    assert(image_len);
101
102
    /* Get shared info for B-tree */
103
157
    shared = (H5B_shared_t *)H5UC_GET_OBJ(udata->rc_shared);
104
157
    assert(shared);
105
106
    /* Set the image length size */
107
157
    *image_len = shared->sizeof_rnode;
108
109
157
    FUNC_LEAVE_NOAPI(SUCCEED)
110
157
} /* end H5B__cache_get_initial_load_size() */
111
112
/*-------------------------------------------------------------------------
113
 * Function:    H5B__cache_deserialize
114
 *
115
 * Purpose:     Deserialize the data structure from disk
116
 *
117
 * Return:      Success:    Pointer to a new B-tree node
118
 *              Failure:    NULL
119
 *-------------------------------------------------------------------------
120
 */
121
static void *
122
H5B__cache_deserialize(const void *_image, size_t len, void *_udata, bool H5_ATTR_UNUSED *dirty)
123
121
{
124
121
    H5B_t          *bt    = NULL;                     /* Pointer to the deserialized B-tree node */
125
121
    H5B_cache_ud_t *udata = (H5B_cache_ud_t *)_udata; /* User data for callback */
126
121
    H5B_shared_t   *shared;                           /* Pointer to shared B-tree info */
127
121
    const uint8_t  *image = (const uint8_t *)_image;  /* Pointer into image buffer */
128
121
    const uint8_t  *p_end = image + len - 1;          /* End of image buffer */
129
121
    uint8_t        *native;                           /* Pointer to native keys */
130
121
    unsigned        u;                                /* Local index variable */
131
121
    H5B_t          *ret_value = NULL;                 /* Return value */
132
133
121
    FUNC_ENTER_PACKAGE
134
135
    /* check arguments */
136
121
    assert(image);
137
121
    assert(udata);
138
139
    /* Allocate the B-tree node in memory */
140
121
    if (NULL == (bt = H5FL_MALLOC(H5B_t)))
141
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate B-tree struct");
142
121
    memset(&bt->cache_info, 0, sizeof(H5AC_info_t));
143
144
    /* Set & increment the ref-counted "shared" B-tree information for the node */
145
121
    bt->rc_shared = udata->rc_shared;
146
121
    H5UC_INC(bt->rc_shared);
147
148
    /* Get a pointer to the shared info, for convenience */
149
121
    shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
150
121
    if (NULL == shared)
151
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, NULL, "can't get a pointer to shared data");
152
153
    /* Allocate space for the native keys and child addresses */
154
121
    if (NULL == (bt->native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)))
155
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate buffer for native keys");
156
121
    if (NULL == (bt->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
157
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate buffer for child addresses");
158
159
    /* Magic number */
160
121
    if (H5_IS_BUFFER_OVERFLOW(image, H5_SIZEOF_MAGIC, p_end))
161
0
        HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
162
121
    if (memcmp(image, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0)
163
3
        HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree signature");
164
118
    image += H5_SIZEOF_MAGIC;
165
166
    /* Node type and level */
167
118
    if (H5_IS_BUFFER_OVERFLOW(image, 2, p_end))
168
0
        HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
169
118
    if (*image++ != (uint8_t)udata->type->id)
170
3
        HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, NULL, "incorrect B-tree node type");
171
115
    bt->level = *image++;
172
173
    /* Check in case of level is corrupted, if expected level is known */
174
115
    if (udata->exp_level != H5B_UNKNOWN_NODELEVEL)
175
1
        if (bt->level != (unsigned)udata->exp_level)
176
1
            HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "level is not as expected, possibly corrupted");
177
178
    /* Entries used */
179
114
    if (H5_IS_BUFFER_OVERFLOW(image, 2, p_end))
180
0
        HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
181
114
    UINT16DECODE(image, bt->nchildren);
182
183
    /* Check if bt->nchildren is greater than two_k */
184
114
    if (bt->nchildren > shared->two_k)
185
3
        HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "number of children is greater than maximum");
186
187
    /* Sibling pointers */
188
111
    if (H5_IS_BUFFER_OVERFLOW(image, H5F_sizeof_addr(udata->f), p_end))
189
0
        HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
190
111
    H5F_addr_decode(udata->f, (const uint8_t **)&image, &(bt->left));
191
192
111
    if (H5_IS_BUFFER_OVERFLOW(image, H5F_sizeof_addr(udata->f), p_end))
193
0
        HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
194
111
    H5F_addr_decode(udata->f, (const uint8_t **)&image, &(bt->right));
195
196
    /* Child/key pairs */
197
111
    native = bt->native;
198
277
    for (u = 0; u < bt->nchildren; u++) {
199
        /* Decode native key value */
200
166
        if (H5_IS_BUFFER_OVERFLOW(image, shared->sizeof_rkey, p_end))
201
0
            HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
202
166
        if ((udata->type->decode)(shared, image, native) < 0)
203
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode key");
204
166
        image += shared->sizeof_rkey;
205
166
        native += udata->type->sizeof_nkey;
206
207
        /* Decode address value */
208
166
        if (H5_IS_BUFFER_OVERFLOW(image, H5F_sizeof_addr(udata->f), p_end))
209
0
            HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
210
166
        H5F_addr_decode(udata->f, (const uint8_t **)&image, bt->child + u);
211
166
    }
212
213
    /* Final key */
214
111
    if (bt->nchildren > 0) {
215
        /* Decode native key value */
216
111
        if ((udata->type->decode)(shared, image, native) < 0)
217
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode key");
218
111
    }
219
220
    /* Set return value */
221
111
    ret_value = bt;
222
223
121
done:
224
121
    if (!ret_value && bt)
225
10
        if (H5B__node_dest(bt) < 0)
226
0
            HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree node");
227
228
121
    FUNC_LEAVE_NOAPI(ret_value)
229
121
} /* end H5B__cache_deserialize() */
230
231
/*-------------------------------------------------------------------------
232
 * Function:    H5B__cache_image_len
233
 *
234
 * Purpose:     Compute the size of the data structure on disk.
235
 *
236
 * Return:      SUCCEED/FAIL
237
 *-------------------------------------------------------------------------
238
 */
239
static herr_t
240
H5B__cache_image_len(const void *_thing, size_t *image_len)
241
0
{
242
0
    const H5B_t  *bt = (const H5B_t *)_thing; /* Pointer to the B-tree node */
243
0
    H5B_shared_t *shared;                     /* Pointer to shared B-tree info */
244
245
0
    FUNC_ENTER_PACKAGE_NOERR
246
247
    /* Check arguments */
248
0
    assert(bt);
249
0
    assert(image_len);
250
251
    /* Get shared info for B-tree */
252
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
253
0
    assert(shared);
254
255
    /* Set the image length size */
256
0
    *image_len = shared->sizeof_rnode;
257
258
0
    FUNC_LEAVE_NOAPI(SUCCEED)
259
0
} /* end H5B__cache_image_len() */
260
261
/*-------------------------------------------------------------------------
262
 * Function:    H5B__cache_serialize
263
 *
264
 * Purpose:     Serialize the data structure for writing to disk
265
 *
266
 * Return:      SUCCEED/FAIL
267
 *-------------------------------------------------------------------------
268
 */
269
static herr_t
270
H5B__cache_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, void *_thing)
271
0
{
272
0
    H5B_t        *bt = (H5B_t *)_thing;      /* Pointer to the B-tree node */
273
0
    H5B_shared_t *shared;                    /* Pointer to shared B-tree info */
274
0
    uint8_t      *image = (uint8_t *)_image; /* Pointer into image buffer */
275
0
    uint8_t      *native;                    /* Pointer to native keys */
276
0
    unsigned      u;                         /* Local index counter */
277
0
    herr_t        ret_value = SUCCEED;       /* Return value */
278
279
0
    FUNC_ENTER_PACKAGE
280
281
    /* check arguments */
282
0
    assert(image);
283
0
    assert(bt);
284
0
    assert(bt->rc_shared);
285
0
    shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
286
0
    assert(shared);
287
0
    assert(shared->type);
288
0
    assert(shared->type->encode);
289
290
    /* magic number */
291
0
    H5MM_memcpy(image, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC);
292
0
    image += 4;
293
294
    /* node type and level */
295
0
    *image++ = (uint8_t)shared->type->id;
296
297
    /* 2^8 limit: only 1 byte is used to store node level */
298
0
    if (bt->level >= pow(2, LEVEL_BITS))
299
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode node level");
300
301
0
    H5_CHECK_OVERFLOW(bt->level, unsigned, uint8_t);
302
0
    *image++ = (uint8_t)bt->level;
303
304
    /* entries used */
305
0
    UINT16ENCODE(image, bt->nchildren);
306
307
    /* sibling pointers */
308
0
    H5F_addr_encode(f, &image, bt->left);
309
0
    H5F_addr_encode(f, &image, bt->right);
310
311
    /* child keys and pointers */
312
0
    native = bt->native;
313
0
    for (u = 0; u < bt->nchildren; ++u) {
314
        /* encode the key */
315
0
        if (shared->type->encode(shared, image, native) < 0)
316
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key");
317
0
        image += shared->sizeof_rkey;
318
0
        native += shared->type->sizeof_nkey;
319
320
        /* encode the child address */
321
0
        H5F_addr_encode(f, &image, bt->child[u]);
322
0
    } /* end for */
323
0
    if (bt->nchildren > 0) {
324
        /* Encode the final key */
325
0
        if (shared->type->encode(shared, image, native) < 0)
326
0
            HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key");
327
0
        image += shared->sizeof_rkey;
328
0
    } /* end if */
329
330
    /* Sanity check */
331
0
    assert((size_t)(image - (uint8_t *)_image) <= len);
332
333
    /* Clear rest of node */
334
0
    memset(image, 0, len - (size_t)(image - (uint8_t *)_image));
335
336
0
done:
337
0
    FUNC_LEAVE_NOAPI(ret_value)
338
0
} /* end H5B__cache_serialize() */
339
340
/*-------------------------------------------------------------------------
341
 * Function:    H5B__cache_free_icr
342
 *
343
 * Purpose:     Destroy/release an "in core representation" of a data structure
344
 *
345
 * Return:      SUCCEED/FAIL
346
 *-------------------------------------------------------------------------
347
 */
348
static herr_t
349
H5B__cache_free_icr(void *thing)
350
111
{
351
111
    herr_t ret_value = SUCCEED; /* Return value */
352
353
111
    FUNC_ENTER_PACKAGE
354
355
    /* Check arguments */
356
111
    assert(thing);
357
358
    /* Destroy B-tree node */
359
111
    if (H5B__node_dest((H5B_t *)thing) < 0)
360
0
        HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node");
361
362
111
done:
363
111
    FUNC_LEAVE_NOAPI(ret_value)
364
111
} /* end H5B__cache_free_icr() */