Coverage Report

Created: 2025-10-12 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5EAiblock.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:   H5EAiblock.c
16
 *
17
 * Purpose:   Index block routines for extensible arrays.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/**********************/
23
/* Module Declaration */
24
/**********************/
25
26
#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
27
28
/***********************/
29
/* Other Packages Used */
30
/***********************/
31
32
/***********/
33
/* Headers */
34
/***********/
35
#include "H5private.h"   /* Generic Functions     */
36
#include "H5Eprivate.h"  /* Error handling        */
37
#include "H5EApkg.h"     /* Extensible Arrays     */
38
#include "H5FLprivate.h" /* Free Lists                           */
39
#include "H5MFprivate.h" /* File memory management    */
40
#include "H5VMprivate.h" /* Vectors and arrays      */
41
42
/****************/
43
/* Local Macros */
44
/****************/
45
46
/******************/
47
/* Local Typedefs */
48
/******************/
49
50
/********************/
51
/* Package Typedefs */
52
/********************/
53
54
/********************/
55
/* Local Prototypes */
56
/********************/
57
58
/*********************/
59
/* Package Variables */
60
/*********************/
61
62
/*****************************/
63
/* Library Private Variables */
64
/*****************************/
65
66
/*******************/
67
/* Local Variables */
68
/*******************/
69
70
/* Declare a free list to manage the H5EA_iblock_t struct */
71
H5FL_DEFINE_STATIC(H5EA_iblock_t);
72
73
/* Declare a free list to manage the index block elements */
74
H5FL_BLK_DEFINE_STATIC(idx_blk_elmt_buf);
75
76
/* Declare a free list to manage the haddr_t sequence information */
77
H5FL_SEQ_DEFINE_STATIC(haddr_t);
78
79
/*-------------------------------------------------------------------------
80
 * Function:  H5EA__iblock_alloc
81
 *
82
 * Purpose: Allocate extensible array index block
83
 *
84
 * Return:  Non-NULL pointer to index block on success/NULL on failure
85
 *
86
 *-------------------------------------------------------------------------
87
 */
88
H5EA_iblock_t *
89
H5EA__iblock_alloc(H5EA_hdr_t *hdr)
90
0
{
91
0
    H5EA_iblock_t *iblock    = NULL; /* Extensible array index block */
92
0
    H5EA_iblock_t *ret_value = NULL;
93
94
0
    FUNC_ENTER_PACKAGE
95
96
    /* Check arguments */
97
0
    assert(hdr);
98
99
    /* Allocate memory for the index block */
100
0
    if (NULL == (iblock = H5FL_CALLOC(H5EA_iblock_t)))
101
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL,
102
0
                    "memory allocation failed for extensible array index block");
103
104
    /* Share common array information */
105
0
    if (H5EA__hdr_incr(hdr) < 0)
106
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINC, NULL, "can't increment reference count on shared array header");
107
0
    iblock->hdr = hdr;
108
109
    /* Set non-zero internal fields */
110
0
    iblock->addr = HADDR_UNDEF;
111
112
    /* Compute information */
113
0
    iblock->nsblks      = H5EA_SBLK_FIRST_IDX(hdr->cparam.sup_blk_min_data_ptrs);
114
0
    iblock->ndblk_addrs = 2 * ((size_t)hdr->cparam.sup_blk_min_data_ptrs - 1);
115
0
    iblock->nsblk_addrs = hdr->nsblks - iblock->nsblks;
116
117
    /* Allocate buffer for elements in index block */
118
0
    if (hdr->cparam.idx_blk_elmts > 0)
119
0
        if (NULL ==
120
0
            (iblock->elmts = H5FL_BLK_MALLOC(
121
0
                 idx_blk_elmt_buf, (size_t)(hdr->cparam.idx_blk_elmts * hdr->cparam.cls->nat_elmt_size))))
122
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL,
123
0
                        "memory allocation failed for index block data element buffer");
124
125
    /* Allocate buffer for data block addresses in index block */
126
0
    if (iblock->ndblk_addrs > 0)
127
0
        if (NULL == (iblock->dblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->ndblk_addrs)))
128
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL,
129
0
                        "memory allocation failed for index block data block addresses");
130
131
    /* Allocate buffer for super block addresses in index block */
132
0
    if (iblock->nsblk_addrs > 0)
133
0
        if (NULL == (iblock->sblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->nsblk_addrs)))
134
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL,
135
0
                        "memory allocation failed for index block super block addresses");
136
137
    /* Set the return value */
138
0
    ret_value = iblock;
139
140
0
done:
141
0
    if (!ret_value)
142
0
        if (iblock && H5EA__iblock_dest(iblock) < 0)
143
0
            HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, NULL, "unable to destroy extensible array index block");
144
0
    FUNC_LEAVE_NOAPI(ret_value)
145
0
} /* end H5EA__iblock_alloc() */
146
147
/*-------------------------------------------------------------------------
148
 * Function:  H5EA__iblock_create
149
 *
150
 * Purpose: Creates a new extensible array index block in the file
151
 *
152
 * Return:  Valid file address on success/HADDR_UNDEF on failure
153
 *
154
 *-------------------------------------------------------------------------
155
 */
156
haddr_t
157
H5EA__iblock_create(H5EA_hdr_t *hdr, bool *stats_changed)
158
0
{
159
0
    H5EA_iblock_t *iblock = NULL;     /* Extensible array index block */
160
0
    haddr_t        iblock_addr;       /* Extensible array index block address */
161
0
    bool           inserted  = false; /* Whether the header was inserted into cache */
162
0
    haddr_t        ret_value = HADDR_UNDEF;
163
164
0
    FUNC_ENTER_PACKAGE
165
166
    /* Sanity check */
167
0
    assert(hdr);
168
0
    assert(stats_changed);
169
170
    /* Allocate the index block */
171
0
    if (NULL == (iblock = H5EA__iblock_alloc(hdr)))
172
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, HADDR_UNDEF,
173
0
                    "memory allocation failed for extensible array index block");
174
175
    /* Set size of index block on disk */
176
0
    iblock->size = H5EA_IBLOCK_SIZE(iblock);
177
178
    /* Allocate space for the index block on disk */
179
0
    if (HADDR_UNDEF == (iblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_IBLOCK, (hsize_t)iblock->size)))
180
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, HADDR_UNDEF,
181
0
                    "file allocation failed for extensible array index block");
182
0
    iblock->addr = iblock_addr;
183
184
    /* Clear any elements in index block to fill value */
185
0
    if (hdr->cparam.idx_blk_elmts > 0) {
186
        /* Call the class's 'fill' callback */
187
0
        if ((hdr->cparam.cls->fill)(iblock->elmts, (size_t)hdr->cparam.idx_blk_elmts) < 0)
188
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, HADDR_UNDEF,
189
0
                        "can't set extensible array index block elements to class's fill value");
190
0
    } /* end if */
191
192
    /* Reset any data block addresses in the index block */
193
0
    if (iblock->ndblk_addrs > 0) {
194
0
        haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill data block addresses with */
195
196
        /* Set all the data block addresses to "undefined" address value */
197
0
        H5VM_array_fill(iblock->dblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->ndblk_addrs);
198
0
    } /* end if */
199
200
    /* Reset any super block addresses in the index block */
201
0
    if (iblock->nsblk_addrs > 0) {
202
0
        haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill super block addresses with */
203
204
        /* Set all the super block addresses to "undefined" address value */
205
0
        H5VM_array_fill(iblock->sblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->nsblk_addrs);
206
0
    } /* end if */
207
208
    /* Cache the new extensible array index block */
209
0
    if (H5AC_insert_entry(hdr->f, H5AC_EARRAY_IBLOCK, iblock_addr, iblock, H5AC__NO_FLAGS_SET) < 0)
210
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINSERT, HADDR_UNDEF,
211
0
                    "can't add extensible array index block to cache");
212
0
    inserted = true;
213
214
    /* Add index block as child of 'top' proxy */
215
0
    if (hdr->top_proxy) {
216
0
        if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, iblock) < 0)
217
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, HADDR_UNDEF,
218
0
                        "unable to add extensible array entry as child of array proxy");
219
0
        iblock->top_proxy = hdr->top_proxy;
220
0
    } /* end if */
221
222
    /* Update extensible array index block statistics */
223
0
    assert(0 == hdr->stats.computed.nindex_blks);
224
0
    assert(0 == hdr->stats.computed.index_blk_size);
225
0
    hdr->stats.computed.nindex_blks    = 1;
226
0
    hdr->stats.computed.index_blk_size = iblock->size;
227
228
    /* Increment count of elements "realized" */
229
0
    hdr->stats.stored.nelmts += hdr->cparam.idx_blk_elmts;
230
231
    /* Mark the statistics as changed */
232
0
    *stats_changed = true;
233
234
    /* Set address of index block to return */
235
0
    ret_value = iblock_addr;
236
237
0
done:
238
0
    if (!H5_addr_defined(ret_value))
239
0
        if (iblock) {
240
            /* Remove from cache, if inserted */
241
0
            if (inserted)
242
0
                if (H5AC_remove_entry(iblock) < 0)
243
0
                    HDONE_ERROR(H5E_EARRAY, H5E_CANTREMOVE, HADDR_UNDEF,
244
0
                                "unable to remove extensible array index block from cache");
245
246
            /* Release index block's disk space */
247
0
            if (H5_addr_defined(iblock->addr) &&
248
0
                H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_IBLOCK, iblock->addr, (hsize_t)iblock->size) < 0)
249
0
                HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, HADDR_UNDEF,
250
0
                            "unable to release file space for extensible array index block");
251
252
            /* Destroy index block */
253
0
            if (H5EA__iblock_dest(iblock) < 0)
254
0
                HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, HADDR_UNDEF,
255
0
                            "unable to destroy extensible array index block");
256
0
        } /* end if */
257
258
0
    FUNC_LEAVE_NOAPI(ret_value)
259
0
} /* end H5EA__iblock_create() */
260
261
/*-------------------------------------------------------------------------
262
 * Function:  H5EA__iblock_protect
263
 *
264
 * Purpose: Convenience wrapper around protecting extensible array index block
265
 *
266
 * Return:  Non-NULL pointer to index block on success/NULL on failure
267
 *
268
 *-------------------------------------------------------------------------
269
 */
270
H5EA_iblock_t *
271
H5EA__iblock_protect(H5EA_hdr_t *hdr, unsigned flags)
272
0
{
273
0
    H5EA_iblock_t *iblock    = NULL; /* Pointer to index block */
274
0
    H5EA_iblock_t *ret_value = NULL;
275
276
0
    FUNC_ENTER_PACKAGE
277
278
    /* Sanity check */
279
0
    assert(hdr);
280
281
    /* only the H5AC__READ_ONLY_FLAG may be set */
282
0
    assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
283
284
    /* Protect the index block */
285
0
    if (NULL ==
286
0
        (iblock = (H5EA_iblock_t *)H5AC_protect(hdr->f, H5AC_EARRAY_IBLOCK, hdr->idx_blk_addr, hdr, flags)))
287
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, NULL,
288
0
                    "unable to protect extensible array index block, address = %llu",
289
0
                    (unsigned long long)hdr->idx_blk_addr);
290
291
    /* Create top proxy, if it doesn't exist */
292
0
    if (hdr->top_proxy && NULL == iblock->top_proxy) {
293
        /* Add index block as child of 'top' proxy */
294
0
        if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, iblock) < 0)
295
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, NULL,
296
0
                        "unable to add extensible array entry as child of array proxy");
297
0
        iblock->top_proxy = hdr->top_proxy;
298
0
    } /* end if */
299
300
    /* Set return value */
301
0
    ret_value = iblock;
302
303
0
done:
304
    /* Clean up on error */
305
0
    if (!ret_value) {
306
        /* Release the index block, if it was protected */
307
0
        if (iblock &&
308
0
            H5AC_unprotect(hdr->f, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, H5AC__NO_FLAGS_SET) < 0)
309
0
            HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, NULL,
310
0
                        "unable to unprotect extensible array index block, address = %llu",
311
0
                        (unsigned long long)iblock->addr);
312
0
    } /* end if */
313
314
0
    FUNC_LEAVE_NOAPI(ret_value)
315
0
} /* end H5EA__iblock_protect() */
316
317
/*-------------------------------------------------------------------------
318
 * Function:  H5EA__iblock_unprotect
319
 *
320
 * Purpose: Convenience wrapper around unprotecting extensible array index block
321
 *
322
 * Return:  Non-negative on success/Negative on failure
323
 *
324
 *-------------------------------------------------------------------------
325
 */
326
herr_t
327
H5EA__iblock_unprotect(H5EA_iblock_t *iblock, unsigned cache_flags)
328
0
{
329
0
    herr_t ret_value = SUCCEED;
330
331
0
    FUNC_ENTER_PACKAGE
332
333
    /* Sanity check */
334
0
    assert(iblock);
335
336
    /* Unprotect the index block */
337
0
    if (H5AC_unprotect(iblock->hdr->f, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, cache_flags) < 0)
338
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL,
339
0
                    "unable to unprotect extensible array index block, address = %llu",
340
0
                    (unsigned long long)iblock->addr);
341
342
0
done:
343
0
    FUNC_LEAVE_NOAPI(ret_value)
344
0
} /* end H5EA__iblock_unprotect() */
345
346
/*-------------------------------------------------------------------------
347
 * Function:  H5EA__iblock_delete
348
 *
349
 * Purpose: Delete index block
350
 *
351
 * Return:  SUCCEED/FAIL
352
 *
353
 *-------------------------------------------------------------------------
354
 */
355
herr_t
356
H5EA__iblock_delete(H5EA_hdr_t *hdr)
357
0
{
358
0
    H5EA_iblock_t *iblock    = NULL; /* Pointer to index block */
359
0
    herr_t         ret_value = SUCCEED;
360
361
0
    FUNC_ENTER_PACKAGE
362
363
    /* Sanity check */
364
0
    assert(hdr);
365
0
    assert(H5_addr_defined(hdr->idx_blk_addr));
366
367
    /* Protect index block */
368
0
    if (NULL == (iblock = H5EA__iblock_protect(hdr, H5AC__NO_FLAGS_SET)))
369
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
370
0
                    "unable to protect extensible array index block, address = %llu",
371
0
                    (unsigned long long)hdr->idx_blk_addr);
372
373
    /* Check for index block having data block pointers */
374
0
    if (iblock->ndblk_addrs > 0) {
375
0
        unsigned sblk_idx; /* Current super block index */
376
0
        unsigned dblk_idx; /* Current data block index w/in super block */
377
0
        size_t   u;        /* Local index variable */
378
379
        /* Iterate over data blocks */
380
0
        sblk_idx = dblk_idx = 0;
381
0
        for (u = 0; u < iblock->ndblk_addrs; u++) {
382
            /* Check for data block existing */
383
0
            if (H5_addr_defined(iblock->dblk_addrs[u])) {
384
                /* Delete data block */
385
0
                if (H5EA__dblock_delete(hdr, iblock, iblock->dblk_addrs[u],
386
0
                                        hdr->sblk_info[sblk_idx].dblk_nelmts) < 0)
387
0
                    HGOTO_ERROR(H5E_EARRAY, H5E_CANTDELETE, FAIL,
388
0
                                "unable to delete extensible array data block");
389
0
                iblock->dblk_addrs[u] = HADDR_UNDEF;
390
0
            } /* end if */
391
392
            /* Advance to next data block w/in super block */
393
0
            dblk_idx++;
394
395
            /* Check for moving to next super block */
396
0
            if (dblk_idx >= hdr->sblk_info[sblk_idx].ndblks) {
397
0
                sblk_idx++;
398
0
                dblk_idx = 0;
399
0
            } /* end if */
400
0
        }     /* end for */
401
0
    }         /* end if */
402
403
    /* Check for index block having data block pointers (not yet) */
404
0
    if (iblock->nsblk_addrs > 0) {
405
0
        size_t u; /* Local index variable */
406
407
        /* Iterate over super blocks */
408
0
        for (u = 0; u < iblock->nsblk_addrs; u++) {
409
            /* Check for data block existing */
410
0
            if (H5_addr_defined(iblock->sblk_addrs[u])) {
411
                /* Delete super block */
412
0
                if (H5EA__sblock_delete(hdr, iblock, iblock->sblk_addrs[u], (unsigned)(u + iblock->nsblks)) <
413
0
                    0)
414
0
                    HGOTO_ERROR(H5E_EARRAY, H5E_CANTDELETE, FAIL,
415
0
                                "unable to delete extensible array super block");
416
0
                iblock->sblk_addrs[u] = HADDR_UNDEF;
417
0
            }
418
0
        }
419
0
    }
420
421
0
done:
422
    /* Finished deleting index block in metadata cache */
423
0
    if (iblock && H5EA__iblock_unprotect(iblock, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG |
424
0
                                                     H5AC__FREE_FILE_SPACE_FLAG) < 0)
425
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array index block");
426
427
0
    FUNC_LEAVE_NOAPI(ret_value)
428
0
} /* end H5EA__iblock_delete() */
429
430
/*-------------------------------------------------------------------------
431
 * Function:  H5EA__iblock_dest
432
 *
433
 * Purpose: Destroys an extensible array index block in memory.
434
 *
435
 * Return:  Non-negative on success/Negative on failure
436
 *
437
 *-------------------------------------------------------------------------
438
 */
439
herr_t
440
H5EA__iblock_dest(H5EA_iblock_t *iblock)
441
0
{
442
0
    herr_t ret_value = SUCCEED;
443
444
0
    FUNC_ENTER_PACKAGE
445
446
    /* Sanity check */
447
0
    assert(iblock);
448
449
    /* Check if shared header field has been initialized */
450
0
    if (iblock->hdr) {
451
        /* Check if we've got elements in the index block */
452
0
        if (iblock->elmts) {
453
            /* Free buffer for index block elements */
454
0
            assert(iblock->hdr->cparam.idx_blk_elmts > 0);
455
0
            iblock->elmts = H5FL_BLK_FREE(idx_blk_elmt_buf, iblock->elmts);
456
0
        } /* end if */
457
458
        /* Check if we've got data block addresses in the index block */
459
0
        if (iblock->dblk_addrs) {
460
            /* Free buffer for index block data block addresses */
461
0
            assert(iblock->ndblk_addrs > 0);
462
0
            iblock->dblk_addrs  = H5FL_SEQ_FREE(haddr_t, iblock->dblk_addrs);
463
0
            iblock->ndblk_addrs = 0;
464
0
        } /* end if */
465
466
        /* Check if we've got super block addresses in the index block */
467
0
        if (iblock->sblk_addrs) {
468
            /* Free buffer for index block super block addresses */
469
0
            assert(iblock->nsblk_addrs > 0);
470
0
            iblock->sblk_addrs  = H5FL_SEQ_FREE(haddr_t, iblock->sblk_addrs);
471
0
            iblock->nsblk_addrs = 0;
472
0
        } /* end if */
473
474
        /* Decrement reference count on shared info */
475
0
        if (H5EA__hdr_decr(iblock->hdr) < 0)
476
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTDEC, FAIL,
477
0
                        "can't decrement reference count on shared array header");
478
0
        iblock->hdr = NULL;
479
0
    } /* end if */
480
481
    /* Sanity check */
482
0
    assert(NULL == iblock->top_proxy);
483
484
    /* Free the index block itself */
485
0
    iblock = H5FL_FREE(H5EA_iblock_t, iblock);
486
487
0
done:
488
0
    FUNC_LEAVE_NOAPI(ret_value)
489
0
} /* end H5EA__iblock_dest() */