Coverage Report

Created: 2026-01-17 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5EAdblock.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:   H5EAdblock.c
16
 *
17
 * Purpose:   Data 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_dblock_t struct */
71
H5FL_DEFINE_STATIC(H5EA_dblock_t);
72
73
/*-------------------------------------------------------------------------
74
 * Function:  H5EA__dblock_alloc
75
 *
76
 * Purpose: Allocate extensible array data block
77
 *
78
 * Return:  Non-NULL pointer to data block on success/NULL on failure
79
 *
80
 *-------------------------------------------------------------------------
81
 */
82
H5EA_dblock_t *
83
H5EA__dblock_alloc(H5EA_hdr_t *hdr, void *parent, size_t nelmts)
84
0
{
85
0
    H5EA_dblock_t *dblock    = NULL; /* Extensible array data block */
86
0
    H5EA_dblock_t *ret_value = NULL;
87
88
0
    FUNC_ENTER_PACKAGE
89
90
    /* Check arguments */
91
0
    assert(hdr);
92
0
    assert(parent);
93
0
    assert(nelmts > 0);
94
95
    /* Allocate memory for the data block */
96
0
    if (NULL == (dblock = H5FL_CALLOC(H5EA_dblock_t)))
97
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL,
98
0
                    "memory allocation failed for extensible array data block");
99
100
    /* Share common array information */
101
0
    if (H5EA__hdr_incr(hdr) < 0)
102
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINC, NULL, "can't increment reference count on shared array header");
103
0
    dblock->hdr = hdr;
104
105
    /* Set non-zero internal fields */
106
0
    dblock->parent = parent;
107
0
    dblock->nelmts = nelmts;
108
109
    /* Check if the data block is not going to be paged */
110
0
    if (nelmts > hdr->dblk_page_nelmts) {
111
        /* Set the # of pages in the direct block */
112
0
        dblock->npages = nelmts / hdr->dblk_page_nelmts;
113
0
        assert(nelmts == (dblock->npages * hdr->dblk_page_nelmts));
114
0
    } /* end if */
115
0
    else {
116
        /* Allocate buffer for elements in data block */
117
0
        if (NULL == (dblock->elmts = H5EA__hdr_alloc_elmts(hdr, nelmts)))
118
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL,
119
0
                        "memory allocation failed for data block element buffer");
120
0
    } /* end else */
121
122
    /* Set the return value */
123
0
    ret_value = dblock;
124
125
0
done:
126
0
    if (!ret_value)
127
0
        if (dblock && H5EA__dblock_dest(dblock) < 0)
128
0
            HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, NULL, "unable to destroy extensible array data block");
129
130
0
    FUNC_LEAVE_NOAPI(ret_value)
131
0
} /* end H5EA__dblock_alloc() */
132
133
/*-------------------------------------------------------------------------
134
 * Function:  H5EA__dblock_create
135
 *
136
 * Purpose: Creates a new extensible array data block in the file
137
 *
138
 * Return:  Valid file address on success/HADDR_UNDEF on failure
139
 *
140
 *-------------------------------------------------------------------------
141
 */
142
haddr_t
143
H5EA__dblock_create(H5EA_hdr_t *hdr, void *parent, bool *stats_changed, hsize_t dblk_off, size_t nelmts)
144
0
{
145
0
    H5EA_dblock_t *dblock = NULL;     /* Extensible array data block */
146
0
    haddr_t        dblock_addr;       /* Extensible array data block address */
147
0
    bool           inserted  = false; /* Whether the header was inserted into cache */
148
0
    haddr_t        ret_value = HADDR_UNDEF;
149
150
0
    FUNC_ENTER_PACKAGE
151
152
    /* Sanity check */
153
0
    assert(hdr);
154
0
    assert(stats_changed);
155
0
    assert(nelmts > 0);
156
157
    /* Allocate the data block */
158
0
    if (NULL == (dblock = H5EA__dblock_alloc(hdr, parent, nelmts)))
159
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, HADDR_UNDEF,
160
0
                    "memory allocation failed for extensible array data block");
161
162
    /* Set size of data block on disk */
163
0
    dblock->size = H5EA_DBLOCK_SIZE(dblock);
164
165
    /* Set offset of block in array's address space */
166
0
    dblock->block_off = dblk_off;
167
168
    /* Allocate space for the data block on disk */
169
0
    if (HADDR_UNDEF == (dblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_DBLOCK, (hsize_t)dblock->size)))
170
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, HADDR_UNDEF,
171
0
                    "file allocation failed for extensible array data block");
172
0
    dblock->addr = dblock_addr;
173
174
    /* Don't initialize elements if paged */
175
0
    if (!dblock->npages)
176
        /* Clear any elements in data block to fill value */
177
0
        if ((hdr->cparam.cls->fill)(dblock->elmts, (size_t)dblock->nelmts) < 0)
178
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, HADDR_UNDEF,
179
0
                        "can't set extensible array data block elements to class's fill value");
180
181
    /* Cache the new extensible array data block */
182
0
    if (H5AC_insert_entry(hdr->f, H5AC_EARRAY_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
183
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINSERT, HADDR_UNDEF,
184
0
                    "can't add extensible array data block to cache");
185
0
    inserted = true;
186
187
    /* Add data block as child of 'top' proxy */
188
0
    if (hdr->top_proxy) {
189
0
        if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dblock) < 0)
190
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, HADDR_UNDEF,
191
0
                        "unable to add extensible array entry as child of array proxy");
192
0
        dblock->top_proxy = hdr->top_proxy;
193
0
    } /* end if */
194
195
    /* Update extensible array data block statistics */
196
0
    hdr->stats.stored.ndata_blks++;
197
0
    hdr->stats.stored.data_blk_size += dblock->size;
198
199
    /* Increment count of elements "realized" */
200
0
    hdr->stats.stored.nelmts += nelmts;
201
202
    /* Mark the statistics as changed */
203
0
    *stats_changed = true;
204
205
    /* Set address of data block to return */
206
0
    ret_value = dblock_addr;
207
208
0
done:
209
0
    if (!H5_addr_defined(ret_value))
210
0
        if (dblock) {
211
            /* Remove from cache, if inserted */
212
0
            if (inserted)
213
0
                if (H5AC_remove_entry(dblock) < 0)
214
0
                    HDONE_ERROR(H5E_EARRAY, H5E_CANTREMOVE, HADDR_UNDEF,
215
0
                                "unable to remove extensible array data block from cache");
216
217
            /* Release data block's disk space */
218
0
            if (H5_addr_defined(dblock->addr) &&
219
0
                H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_DBLOCK, dblock->addr, (hsize_t)dblock->size) < 0)
220
0
                HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, HADDR_UNDEF,
221
0
                            "unable to release extensible array data block");
222
223
            /* Destroy data block */
224
0
            if (H5EA__dblock_dest(dblock) < 0)
225
0
                HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, HADDR_UNDEF,
226
0
                            "unable to destroy extensible array data block");
227
0
        } /* end if */
228
229
0
    FUNC_LEAVE_NOAPI(ret_value)
230
0
} /* end H5EA__dblock_create() */
231
232
/*-------------------------------------------------------------------------
233
 * Function:  H5EA__dblock_sblk_idx
234
 *
235
 * Purpose: Compute the index of the super block where the element is
236
 *              located.
237
 *
238
 * Return:  Super block index on success/Can't fail
239
 *
240
 *-------------------------------------------------------------------------
241
 */
242
unsigned
243
H5EA__dblock_sblk_idx(const H5EA_hdr_t *hdr, hsize_t idx)
244
0
{
245
0
    unsigned sblk_idx = 0; /* Which superblock does this index fall in? */
246
247
0
    FUNC_ENTER_PACKAGE_NOERR
248
249
    /* Sanity check */
250
0
    assert(hdr);
251
0
    assert(idx >= hdr->cparam.idx_blk_elmts);
252
253
    /* Adjust index for elements in index block */
254
0
    idx -= hdr->cparam.idx_blk_elmts;
255
256
    /* Determine the superblock information for the index */
257
0
    H5_CHECK_OVERFLOW(idx, /*From:*/ hsize_t, /*To:*/ uint64_t);
258
0
    sblk_idx = H5VM_log2_gen((uint64_t)((idx / hdr->cparam.data_blk_min_elmts) + 1));
259
260
0
    FUNC_LEAVE_NOAPI(sblk_idx)
261
0
} /* end H5EA__dblock_sblk_idx() */
262
263
/*-------------------------------------------------------------------------
264
 * Function:  H5EA__dblock_protect
265
 *
266
 * Purpose: Convenience wrapper around protecting extensible array data block
267
 *
268
 * Return:  Non-NULL pointer to data block on success/NULL on failure
269
 *
270
 *-------------------------------------------------------------------------
271
 */
272
H5EA_dblock_t *
273
H5EA__dblock_protect(H5EA_hdr_t *hdr, void *parent, haddr_t dblk_addr, size_t dblk_nelmts, unsigned flags)
274
0
{
275
0
    H5EA_dblock_t         *dblock; /* Extensible array data block */
276
0
    H5EA_dblock_cache_ud_t udata;  /* Information needed for loading data block */
277
0
    H5EA_dblock_t         *ret_value = NULL;
278
279
0
    FUNC_ENTER_PACKAGE
280
281
    /* Sanity check */
282
0
    assert(hdr);
283
0
    assert(H5_addr_defined(dblk_addr));
284
0
    assert(dblk_nelmts);
285
286
    /* only the H5AC__READ_ONLY_FLAG may be set */
287
0
    assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
288
289
    /* Set up user data */
290
0
    udata.hdr       = hdr;
291
0
    udata.parent    = parent;
292
0
    udata.nelmts    = dblk_nelmts;
293
0
    udata.dblk_addr = dblk_addr;
294
295
    /* Protect the data block */
296
0
    if (NULL ==
297
0
        (dblock = (H5EA_dblock_t *)H5AC_protect(hdr->f, H5AC_EARRAY_DBLOCK, dblk_addr, &udata, flags)))
298
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, NULL,
299
0
                    "unable to protect extensible array data block, address = %llu",
300
0
                    (unsigned long long)dblk_addr);
301
302
    /* Create top proxy, if it doesn't exist */
303
0
    if (hdr->top_proxy && NULL == dblock->top_proxy) {
304
        /* Add data block as child of 'top' proxy */
305
0
        if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dblock) < 0)
306
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, NULL,
307
0
                        "unable to add extensible array entry as child of array proxy");
308
0
        dblock->top_proxy = hdr->top_proxy;
309
0
    }
310
311
    /* Set return value */
312
0
    ret_value = dblock;
313
314
0
done:
315
316
    /* Clean up on error */
317
0
    if (!ret_value) {
318
        /* Release the data block, if it was protected */
319
0
        if (dblock &&
320
0
            H5AC_unprotect(hdr->f, H5AC_EARRAY_DBLOCK, dblock->addr, dblock, H5AC__NO_FLAGS_SET) < 0)
321
0
            HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, NULL,
322
0
                        "unable to unprotect extensible array data block, address = %llu",
323
0
                        (unsigned long long)dblock->addr);
324
0
    }
325
326
0
    FUNC_LEAVE_NOAPI(ret_value)
327
0
} /* end H5EA__dblock_protect() */
328
329
/*-------------------------------------------------------------------------
330
 * Function:  H5EA__dblock_unprotect
331
 *
332
 * Purpose: Convenience wrapper around unprotecting extensible array data block
333
 *
334
 * Return:  Non-negative on success/Negative on failure
335
 *
336
 *-------------------------------------------------------------------------
337
 */
338
herr_t
339
H5EA__dblock_unprotect(H5EA_dblock_t *dblock, unsigned cache_flags)
340
0
{
341
0
    herr_t ret_value = SUCCEED;
342
343
0
    FUNC_ENTER_PACKAGE
344
345
    /* Sanity check */
346
0
    assert(dblock);
347
348
    /* Unprotect the data block */
349
0
    if (H5AC_unprotect(dblock->hdr->f, H5AC_EARRAY_DBLOCK, dblock->addr, dblock, cache_flags) < 0)
350
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL,
351
0
                    "unable to unprotect extensible array data block, address = %llu",
352
0
                    (unsigned long long)dblock->addr);
353
354
0
done:
355
356
0
    FUNC_LEAVE_NOAPI(ret_value)
357
0
} /* end H5EA__dblock_unprotect() */
358
359
/*-------------------------------------------------------------------------
360
 * Function:  H5EA__dblock_delete
361
 *
362
 * Purpose: Delete a data block
363
 *
364
 * Return:  SUCCEED/FAIL
365
 *
366
 *-------------------------------------------------------------------------
367
 */
368
herr_t
369
H5EA__dblock_delete(H5EA_hdr_t *hdr, void *parent, haddr_t dblk_addr, size_t dblk_nelmts)
370
0
{
371
0
    H5EA_dblock_t *dblock    = NULL; /* Pointer to data block */
372
0
    herr_t         ret_value = SUCCEED;
373
374
0
    FUNC_ENTER_PACKAGE
375
376
    /* Sanity check */
377
0
    assert(hdr);
378
0
    assert(parent);
379
0
    assert(H5_addr_defined(dblk_addr));
380
0
    assert(dblk_nelmts > 0);
381
382
    /* Protect data block */
383
0
    if (NULL == (dblock = H5EA__dblock_protect(hdr, parent, dblk_addr, dblk_nelmts, H5AC__NO_FLAGS_SET)))
384
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
385
0
                    "unable to protect extensible array data block, address = %llu",
386
0
                    (unsigned long long)dblk_addr);
387
388
    /* Check if this is a paged data block */
389
0
    if (dblk_nelmts > hdr->dblk_page_nelmts) {
390
0
        size_t  npages = dblk_nelmts / hdr->dblk_page_nelmts; /* Number of pages in data block */
391
0
        haddr_t dblk_page_addr;                               /* Address of each data block page */
392
0
        size_t  dblk_page_size;                               /* Size of each data block page */
393
0
        size_t  u;                                            /* Local index variable */
394
395
        /* Set up initial state */
396
0
        dblk_page_addr = dblk_addr + H5EA_DBLOCK_PREFIX_SIZE(dblock);
397
0
        dblk_page_size = (hdr->dblk_page_nelmts * hdr->cparam.raw_elmt_size) + H5EA_SIZEOF_CHKSUM;
398
399
        /* Iterate over pages in data block */
400
0
        for (u = 0; u < npages; u++) {
401
            /* Evict the data block page from the metadata cache */
402
            /* (OK to call if it doesn't exist in the cache) */
403
0
            if (H5AC_expunge_entry(hdr->f, H5AC_EARRAY_DBLK_PAGE, dblk_page_addr, H5AC__NO_FLAGS_SET) < 0)
404
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTEXPUNGE, FAIL,
405
0
                            "unable to remove array data block page from metadata cache");
406
407
            /* Advance to next page address */
408
0
            dblk_page_addr += dblk_page_size;
409
0
        } /* end for */
410
0
    }     /* end if */
411
412
0
done:
413
    /* Finished deleting data block in metadata cache */
414
0
    if (dblock && H5EA__dblock_unprotect(dblock, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG |
415
0
                                                     H5AC__FREE_FILE_SPACE_FLAG) < 0)
416
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array data block");
417
418
0
    FUNC_LEAVE_NOAPI(ret_value)
419
0
} /* end H5EA__dblock_delete() */
420
421
/*-------------------------------------------------------------------------
422
 * Function:  H5EA__dblock_dest
423
 *
424
 * Purpose: Destroys an extensible array data block in memory.
425
 *
426
 * Return:  Non-negative on success/Negative on failure
427
 *
428
 *-------------------------------------------------------------------------
429
 */
430
herr_t
431
H5EA__dblock_dest(H5EA_dblock_t *dblock)
432
0
{
433
0
    herr_t ret_value = SUCCEED;
434
435
0
    FUNC_ENTER_PACKAGE
436
437
    /* Sanity check */
438
0
    assert(dblock);
439
0
    assert(!dblock->has_hdr_depend);
440
441
    /* Check if shared header field has been initialized */
442
0
    if (dblock->hdr) {
443
        /* Check if we've got elements in the data block */
444
0
        if (dblock->elmts && !dblock->npages) {
445
            /* Free buffer for data block elements */
446
0
            assert(dblock->nelmts > 0);
447
0
            if (H5EA__hdr_free_elmts(dblock->hdr, dblock->nelmts, dblock->elmts) < 0)
448
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTFREE, FAIL,
449
0
                            "unable to free extensible array data block element buffer");
450
0
            dblock->elmts  = NULL;
451
0
            dblock->nelmts = 0;
452
0
        } /* end if */
453
454
        /* Decrement reference count on shared info */
455
0
        if (H5EA__hdr_decr(dblock->hdr) < 0)
456
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTDEC, FAIL,
457
0
                        "can't decrement reference count on shared array header");
458
0
        dblock->hdr = NULL;
459
0
    } /* end if */
460
461
    /* Sanity check */
462
0
    assert(NULL == dblock->top_proxy);
463
464
    /* Free the data block itself */
465
0
    dblock = H5FL_FREE(H5EA_dblock_t, dblock);
466
467
0
done:
468
0
    FUNC_LEAVE_NOAPI(ret_value)
469
0
} /* end H5EA__dblock_dest() */