Coverage Report

Created: 2026-07-16 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Abtree2.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:   H5Abtree2.c
16
 *
17
 * Purpose:   v2 B-tree callbacks for indexing attributes on objects
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Amodule.h" /* This source code file is part of the H5A module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions     */
32
#include "H5Apkg.h"      /* Attributes          */
33
#include "H5Eprivate.h"  /* Error handling        */
34
#include "H5MMprivate.h" /* Memory management     */
35
#include "H5SMprivate.h" /* Shared object header messages        */
36
37
/****************/
38
/* Local Macros */
39
/****************/
40
41
/******************/
42
/* Local Typedefs */
43
/******************/
44
45
/*
46
 * Data exchange structure for dense attribute storage.  This structure is
47
 * passed through the fractal heap layer to compare attributes.
48
 */
49
typedef struct H5A_fh_ud_cmp_t {
50
    /* downward */
51
    H5F_t                          *f;             /* Pointer to file that fractal heap is in */
52
    const char                     *name;          /* Name of attribute to compare      */
53
    const H5A_dense_bt2_name_rec_t *record;        /* v2 B-tree record for attribute */
54
    H5A_bt2_found_t                 found_op;      /* Callback when correct attribute is found */
55
    void                           *found_op_data; /* Callback data when correct attribute is found */
56
57
    /* upward */
58
    int cmp; /* Comparison of two attribute names */
59
} H5A_fh_ud_cmp_t;
60
61
/********************/
62
/* Package Typedefs */
63
/********************/
64
65
/********************/
66
/* Local Prototypes */
67
/********************/
68
69
/* v2 B-tree function callbacks */
70
71
/* v2 B-tree driver callbacks for 'creation order' index */
72
static herr_t H5A__dense_btree2_corder_store(void *native, const void *udata);
73
static herr_t H5A__dense_btree2_corder_compare(const void *rec1, const void *rec2, int *result);
74
static herr_t H5A__dense_btree2_corder_encode(uint8_t *raw, const void *native, void *ctx);
75
static herr_t H5A__dense_btree2_corder_decode(const uint8_t *raw, void *native, void *ctx);
76
static herr_t H5A__dense_btree2_corder_debug(FILE *stream, int indent, int fwidth, const void *record,
77
                                             const void *_udata);
78
79
/* v2 B-tree driver callbacks for 'name' index */
80
static herr_t H5A__dense_btree2_name_store(void *native, const void *udata);
81
static herr_t H5A__dense_btree2_name_compare(const void *rec1, const void *rec2, int *result);
82
static herr_t H5A__dense_btree2_name_encode(uint8_t *raw, const void *native, void *ctx);
83
static herr_t H5A__dense_btree2_name_decode(const uint8_t *raw, void *native, void *ctx);
84
static herr_t H5A__dense_btree2_name_debug(FILE *stream, int indent, int fwidth, const void *record,
85
                                           const void *_udata);
86
87
/* Fractal heap function callbacks */
88
static herr_t H5A__dense_fh_name_cmp(const void *obj, size_t obj_len, void *op_data);
89
90
/*********************/
91
/* Package Variables */
92
/*********************/
93
/* v2 B-tree class for indexing 'name' field of attributes */
94
const H5B2_class_t H5A_BT2_NAME[1] = {{
95
    /* B-tree class information */
96
    H5B2_ATTR_DENSE_NAME_ID,          /* Type of B-tree */
97
    "H5B2_ATTR_DENSE_NAME_ID",        /* Name of B-tree class */
98
    sizeof(H5A_dense_bt2_name_rec_t), /* Size of native record */
99
    NULL,                             /* Create client callback context */
100
    NULL,                             /* Destroy client callback context */
101
    H5A__dense_btree2_name_store,     /* Record storage callback */
102
    H5A__dense_btree2_name_compare,   /* Record comparison callback */
103
    H5A__dense_btree2_name_encode,    /* Record encoding callback */
104
    H5A__dense_btree2_name_decode,    /* Record decoding callback */
105
    H5A__dense_btree2_name_debug      /* Record debugging callback */
106
}};
107
108
/* v2 B-tree class for indexing 'creation order' field of attributes */
109
const H5B2_class_t H5A_BT2_CORDER[1] = {{
110
    /* B-tree class information */
111
    H5B2_ATTR_DENSE_CORDER_ID,          /* Type of B-tree */
112
    "H5B2_ATTR_DENSE_CORDER_ID",        /* Name of B-tree class */
113
    sizeof(H5A_dense_bt2_corder_rec_t), /* Size of native record */
114
    NULL,                               /* Create client callback context */
115
    NULL,                               /* Destroy client callback context */
116
    H5A__dense_btree2_corder_store,     /* Record storage callback */
117
    H5A__dense_btree2_corder_compare,   /* Record comparison callback */
118
    H5A__dense_btree2_corder_encode,    /* Record encoding callback */
119
    H5A__dense_btree2_corder_decode,    /* Record decoding callback */
120
    H5A__dense_btree2_corder_debug      /* Record debugging callback */
121
}};
122
123
/*****************************/
124
/* Library Private Variables */
125
/*****************************/
126
127
/*******************/
128
/* Local Variables */
129
/*******************/
130
131
/*-------------------------------------------------------------------------
132
 * Function:  H5A__dense_fh_name_cmp
133
 *
134
 * Purpose: Compares the name of a attribute in a fractal heap to another
135
 *              name
136
 *
137
 * Return:  SUCCEED/FAIL
138
 *
139
 *-------------------------------------------------------------------------
140
 */
141
static herr_t
142
H5A__dense_fh_name_cmp(const void *obj, size_t obj_len, void *_udata)
143
0
{
144
0
    H5A_fh_ud_cmp_t *udata = (H5A_fh_ud_cmp_t *)_udata; /* User data for 'op' callback */
145
0
    H5A_t           *attr  = NULL;                      /* Pointer to attribute created from heap object */
146
0
    bool   took_ownership  = false;   /* Whether the "found" operator took ownership of the attribute */
147
0
    herr_t ret_value       = SUCCEED; /* Return value */
148
149
0
    FUNC_ENTER_PACKAGE
150
151
    /* Decode attribute information */
152
0
    if (NULL ==
153
0
        (attr = (H5A_t *)H5O_msg_decode(udata->f, NULL, H5O_ATTR_ID, obj_len, (const unsigned char *)obj)))
154
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't decode attribute");
155
156
    /* Compare the string values */
157
0
    udata->cmp = strcmp(udata->name, attr->shared->name);
158
159
    /* Check for correct attribute & callback to make */
160
0
    if (udata->cmp == 0 && udata->found_op) {
161
        /* Check whether we should "reconstitute" the shared message info */
162
0
        if (udata->record->flags & H5O_MSG_FLAG_SHARED)
163
0
            H5SM_reconstitute(&(attr->sh_loc), udata->f, H5O_ATTR_ID, udata->record->id);
164
165
        /* Set the creation order index for the attribute */
166
0
        attr->shared->crt_idx = udata->record->corder;
167
168
        /* Make callback */
169
0
        if ((udata->found_op)(attr, &took_ownership, udata->found_op_data) < 0)
170
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTOPERATE, FAIL, "attribute found callback failed");
171
0
    } /* end if */
172
173
0
done:
174
    /* Release the space allocated for the attribute */
175
0
    if (attr && !took_ownership)
176
0
        H5O_msg_free(H5O_ATTR_ID, attr);
177
178
0
    FUNC_LEAVE_NOAPI(ret_value)
179
0
} /* end H5A__dense_fh_name_cmp() */
180
181
/*-------------------------------------------------------------------------
182
 * Function:  H5A__dense_btree2_name_store
183
 *
184
 * Purpose: Store user information into native record for v2 B-tree
185
 *
186
 * Return:  Success:  non-negative
187
 *    Failure:  negative
188
 *
189
 *-------------------------------------------------------------------------
190
 */
191
static herr_t
192
H5A__dense_btree2_name_store(void *_nrecord, const void *_udata)
193
0
{
194
0
    const H5A_bt2_ud_ins_t   *udata   = (const H5A_bt2_ud_ins_t *)_udata;
195
0
    H5A_dense_bt2_name_rec_t *nrecord = (H5A_dense_bt2_name_rec_t *)_nrecord;
196
197
0
    FUNC_ENTER_PACKAGE_NOERR
198
199
    /* Copy user information info native record */
200
0
    nrecord->id     = udata->id;
201
0
    nrecord->flags  = udata->common.flags;
202
0
    nrecord->corder = udata->common.corder;
203
0
    nrecord->hash   = udata->common.name_hash;
204
205
0
    FUNC_LEAVE_NOAPI(SUCCEED)
206
0
} /* H5A__dense_btree2_name_store() */
207
208
/*-------------------------------------------------------------------------
209
 * Function:  H5A__dense_btree2_name_compare
210
 *
211
 * Purpose: Compare two native information records, according to some key
212
 *
213
 * Return:  <0 if rec1 < rec2
214
 *              =0 if rec1 == rec2
215
 *              >0 if rec1 > rec2
216
 *
217
 *-------------------------------------------------------------------------
218
 */
219
static herr_t
220
H5A__dense_btree2_name_compare(const void *_bt2_udata, const void *_bt2_rec, int *result)
221
0
{
222
0
    const H5A_bt2_ud_common_t      *bt2_udata = (const H5A_bt2_ud_common_t *)_bt2_udata;
223
0
    const H5A_dense_bt2_name_rec_t *bt2_rec   = (const H5A_dense_bt2_name_rec_t *)_bt2_rec;
224
0
    herr_t                          ret_value = SUCCEED; /* Return value */
225
226
0
    FUNC_ENTER_PACKAGE
227
228
    /* Sanity check */
229
0
    assert(bt2_udata);
230
0
    assert(bt2_rec);
231
232
    /* Check hash value */
233
0
    if (bt2_udata->name_hash < bt2_rec->hash)
234
0
        *result = (-1);
235
0
    else if (bt2_udata->name_hash > bt2_rec->hash)
236
0
        *result = 1;
237
0
    else {
238
0
        H5A_fh_ud_cmp_t fh_udata; /* User data for fractal heap 'op' callback */
239
0
        H5HF_t         *fheap;    /* Fractal heap handle to use for finding object */
240
241
        /* Sanity check */
242
0
        assert(bt2_udata->name_hash == bt2_rec->hash);
243
244
        /* Prepare user data for callback */
245
        /* down */
246
0
        fh_udata.f             = bt2_udata->f;
247
0
        fh_udata.name          = bt2_udata->name;
248
0
        fh_udata.record        = bt2_rec;
249
0
        fh_udata.found_op      = bt2_udata->found_op;
250
0
        fh_udata.found_op_data = bt2_udata->found_op_data;
251
252
        /* up */
253
0
        fh_udata.cmp = 0;
254
255
        /* Check for attribute in shared storage */
256
0
        if (bt2_rec->flags & H5O_MSG_FLAG_SHARED)
257
0
            fheap = bt2_udata->shared_fheap;
258
0
        else
259
0
            fheap = bt2_udata->fheap;
260
0
        assert(fheap);
261
262
        /* Check if the user's attribute and the B-tree's attribute have the same name */
263
0
        if (H5HF_op(fheap, &bt2_rec->id, H5A__dense_fh_name_cmp, &fh_udata) < 0)
264
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
265
266
        /* Callback will set comparison value */
267
0
        *result = fh_udata.cmp;
268
0
    } /* end else */
269
270
0
done:
271
0
    FUNC_LEAVE_NOAPI(ret_value)
272
0
} /* H5A__dense_btree2_name_compare() */
273
274
/*-------------------------------------------------------------------------
275
 * Function:  H5A__dense_btree2_name_encode
276
 *
277
 * Purpose: Encode native information into raw form for storing on disk
278
 *
279
 * Return:  Success:  non-negative
280
 *    Failure:  negative
281
 *
282
 *-------------------------------------------------------------------------
283
 */
284
static herr_t
285
H5A__dense_btree2_name_encode(uint8_t *raw, const void *_nrecord, void H5_ATTR_UNUSED *ctx)
286
0
{
287
0
    const H5A_dense_bt2_name_rec_t *nrecord = (const H5A_dense_bt2_name_rec_t *)_nrecord;
288
289
0
    FUNC_ENTER_PACKAGE_NOERR
290
291
    /* Encode the record's fields */
292
0
    H5MM_memcpy(raw, nrecord->id.id, (size_t)H5O_FHEAP_ID_LEN);
293
0
    raw += H5O_FHEAP_ID_LEN;
294
0
    *raw++ = nrecord->flags;
295
0
    UINT32ENCODE(raw, nrecord->corder);
296
0
    UINT32ENCODE(raw, nrecord->hash);
297
298
0
    FUNC_LEAVE_NOAPI(SUCCEED)
299
0
} /* H5A__dense_btree2_name_encode() */
300
301
/*-------------------------------------------------------------------------
302
 * Function:  H5A__dense_btree2_name_decode
303
 *
304
 * Purpose: Decode raw disk form of record into native form
305
 *
306
 * Return:  Success:  non-negative
307
 *    Failure:  negative
308
 *
309
 *-------------------------------------------------------------------------
310
 */
311
static herr_t
312
H5A__dense_btree2_name_decode(const uint8_t *raw, void *_nrecord, void H5_ATTR_UNUSED *ctx)
313
0
{
314
0
    H5A_dense_bt2_name_rec_t *nrecord = (H5A_dense_bt2_name_rec_t *)_nrecord;
315
316
0
    FUNC_ENTER_PACKAGE_NOERR
317
318
    /* Decode the record's fields */
319
0
    H5MM_memcpy(nrecord->id.id, raw, (size_t)H5O_FHEAP_ID_LEN);
320
0
    raw += H5O_FHEAP_ID_LEN;
321
0
    nrecord->flags = *raw++;
322
0
    UINT32DECODE(raw, nrecord->corder);
323
0
    UINT32DECODE(raw, nrecord->hash);
324
325
0
    FUNC_LEAVE_NOAPI(SUCCEED)
326
0
} /* H5A__dense_btree2_name_decode() */
327
328
/*-------------------------------------------------------------------------
329
 * Function:  H5A__dense_btree2_name_debug
330
 *
331
 * Purpose: Debug native form of record
332
 *
333
 * Return:  Success:  non-negative
334
 *    Failure:  negative
335
 *
336
 *-------------------------------------------------------------------------
337
 */
338
static herr_t
339
H5A__dense_btree2_name_debug(FILE *stream, int indent, int fwidth, const void *_nrecord,
340
                             const void H5_ATTR_UNUSED *_udata)
341
0
{
342
0
    const H5A_dense_bt2_name_rec_t *nrecord = (const H5A_dense_bt2_name_rec_t *)_nrecord;
343
344
0
    FUNC_ENTER_PACKAGE_NOERR
345
346
0
    fprintf(stream, "%*s%-*s {%016" PRIx64 ", %02" PRIx8 ", %u, %08" PRIx32 "}\n", indent, "", fwidth,
347
0
            "Record:", nrecord->id.val, nrecord->flags, (unsigned)nrecord->corder, nrecord->hash);
348
349
0
    FUNC_LEAVE_NOAPI(SUCCEED)
350
0
} /* H5A__dense_btree2_name_debug() */
351
352
/*-------------------------------------------------------------------------
353
 * Function:  H5A__dense_btree2_corder_store
354
 *
355
 * Purpose: Store user information into native record for v2 B-tree
356
 *
357
 * Return:  Success:  non-negative
358
 *    Failure:  negative
359
 *
360
 *-------------------------------------------------------------------------
361
 */
362
static herr_t
363
H5A__dense_btree2_corder_store(void *_nrecord, const void *_udata)
364
0
{
365
0
    const H5A_bt2_ud_ins_t     *udata   = (const H5A_bt2_ud_ins_t *)_udata;
366
0
    H5A_dense_bt2_corder_rec_t *nrecord = (H5A_dense_bt2_corder_rec_t *)_nrecord;
367
368
0
    FUNC_ENTER_PACKAGE_NOERR
369
370
    /* Copy user information info native record */
371
0
    nrecord->id     = udata->id;
372
0
    nrecord->flags  = udata->common.flags;
373
0
    nrecord->corder = udata->common.corder;
374
375
0
    FUNC_LEAVE_NOAPI(SUCCEED)
376
0
} /* H5A__dense_btree2_corder_store() */
377
378
/*-------------------------------------------------------------------------
379
 * Function:  H5A__dense_btree2_corder_compare
380
 *
381
 * Purpose: Compare two native information records, according to some key
382
 *
383
 * Return:  <0 if rec1 < rec2
384
 *              =0 if rec1 == rec2
385
 *              >0 if rec1 > rec2
386
 *
387
 *-------------------------------------------------------------------------
388
 */
389
static herr_t
390
H5A__dense_btree2_corder_compare(const void *_bt2_udata, const void *_bt2_rec, int *result)
391
0
{
392
0
    const H5A_bt2_ud_common_t        *bt2_udata = (const H5A_bt2_ud_common_t *)_bt2_udata;
393
0
    const H5A_dense_bt2_corder_rec_t *bt2_rec   = (const H5A_dense_bt2_corder_rec_t *)_bt2_rec;
394
395
0
    FUNC_ENTER_PACKAGE_NOERR
396
397
    /* Sanity check */
398
0
    assert(bt2_udata);
399
0
    assert(bt2_rec);
400
401
    /* Check creation order value */
402
0
    if (bt2_udata->corder < bt2_rec->corder)
403
0
        *result = -1;
404
0
    else if (bt2_udata->corder > bt2_rec->corder)
405
0
        *result = 1;
406
0
    else
407
0
        *result = 0;
408
409
0
    FUNC_LEAVE_NOAPI(SUCCEED)
410
0
} /* H5A__dense_btree2_corder_compare() */
411
412
/*-------------------------------------------------------------------------
413
 * Function:  H5A__dense_btree2_corder_encode
414
 *
415
 * Purpose: Encode native information into raw form for storing on disk
416
 *
417
 * Return:  Success:  non-negative
418
 *    Failure:  negative
419
 *
420
 *-------------------------------------------------------------------------
421
 */
422
static herr_t
423
H5A__dense_btree2_corder_encode(uint8_t *raw, const void *_nrecord, void H5_ATTR_UNUSED *ctx)
424
0
{
425
0
    const H5A_dense_bt2_corder_rec_t *nrecord = (const H5A_dense_bt2_corder_rec_t *)_nrecord;
426
427
0
    FUNC_ENTER_PACKAGE_NOERR
428
429
    /* Encode the record's fields */
430
0
    H5MM_memcpy(raw, nrecord->id.id, (size_t)H5O_FHEAP_ID_LEN);
431
0
    raw += H5O_FHEAP_ID_LEN;
432
0
    *raw++ = nrecord->flags;
433
0
    UINT32ENCODE(raw, nrecord->corder);
434
435
0
    FUNC_LEAVE_NOAPI(SUCCEED)
436
0
} /* H5A__dense_btree2_corder_encode() */
437
438
/*-------------------------------------------------------------------------
439
 * Function:  H5A__dense_btree2_corder_decode
440
 *
441
 * Purpose: Decode raw disk form of record into native form
442
 *
443
 * Return:  Success:  non-negative
444
 *    Failure:  negative
445
 *
446
 *-------------------------------------------------------------------------
447
 */
448
static herr_t
449
H5A__dense_btree2_corder_decode(const uint8_t *raw, void *_nrecord, void H5_ATTR_UNUSED *ctx)
450
0
{
451
0
    H5A_dense_bt2_corder_rec_t *nrecord = (H5A_dense_bt2_corder_rec_t *)_nrecord;
452
453
0
    FUNC_ENTER_PACKAGE_NOERR
454
455
    /* Decode the record's fields */
456
0
    H5MM_memcpy(nrecord->id.id, raw, (size_t)H5O_FHEAP_ID_LEN);
457
0
    raw += H5O_FHEAP_ID_LEN;
458
0
    nrecord->flags = *raw++;
459
0
    UINT32DECODE(raw, nrecord->corder);
460
461
0
    FUNC_LEAVE_NOAPI(SUCCEED)
462
0
} /* H5A__dense_btree2_corder_decode() */
463
464
/*-------------------------------------------------------------------------
465
 * Function:  H5A__dense_btree2_corder_debug
466
 *
467
 * Purpose: Debug native form of record
468
 *
469
 * Return:  Success:  non-negative
470
 *    Failure:  negative
471
 *
472
 *-------------------------------------------------------------------------
473
 */
474
static herr_t
475
H5A__dense_btree2_corder_debug(FILE *stream, int indent, int fwidth, const void *_nrecord,
476
                               const void H5_ATTR_UNUSED *_udata)
477
0
{
478
0
    const H5A_dense_bt2_corder_rec_t *nrecord = (const H5A_dense_bt2_corder_rec_t *)_nrecord;
479
480
0
    FUNC_ENTER_PACKAGE_NOERR
481
482
0
    fprintf(stream, "%*s%-*s {%016" PRIx64 ", %02" PRIx8 ", %u}\n", indent, "", fwidth,
483
0
            "Record:", nrecord->id.val, nrecord->flags, (unsigned)nrecord->corder);
484
485
0
    FUNC_LEAVE_NOAPI(SUCCEED)
486
0
} /* H5A__dense_btree2_corder_debug() */