Coverage Report

Created: 2026-01-10 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5EA.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:   H5EA.c
16
 *
17
 * Purpose:   Implements an "extensible array" for storing elements
18
 *                      in an array whose high bounds can extend and shrink.
19
 *
20
 *                      Please see the documentation in:
21
 *                      doc/html/TechNotes/ExtensibleArray.html for a full
22
 *                      description of how they work, etc.
23
 *
24
 *-------------------------------------------------------------------------
25
 */
26
27
/**********************/
28
/* Module Declaration */
29
/**********************/
30
31
#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
32
33
/***********************/
34
/* Other Packages Used */
35
/***********************/
36
37
/***********/
38
/* Headers */
39
/***********/
40
#include "H5private.h"   /* Generic Functions     */
41
#include "H5Eprivate.h"  /* Error handling        */
42
#include "H5EApkg.h"     /* Extensible Arrays     */
43
#include "H5FLprivate.h" /* Free Lists                           */
44
#include "H5MMprivate.h" /* Memory management     */
45
#include "H5VMprivate.h" /* Vector functions      */
46
47
/****************/
48
/* Local Macros */
49
/****************/
50
51
/******************/
52
/* Local Typedefs */
53
/******************/
54
55
/* Typedef for generically unprotecting an object */
56
typedef herr_t (*H5EA__unprotect_func_t)(void *thing, unsigned cache_flags);
57
58
/********************/
59
/* Package Typedefs */
60
/********************/
61
62
/********************/
63
/* Local Prototypes */
64
/********************/
65
66
static herr_t  H5EA__lookup_elmt(const H5EA_t *ea, hsize_t idx, bool will_extend, unsigned thing_acc,
67
                                 void **thing, uint8_t **thing_elmt_buf, hsize_t *thing_elmt_idx,
68
                                 H5EA__unprotect_func_t *thing_unprot_func);
69
static H5EA_t *H5EA__new(H5F_t *f, haddr_t ea_addr, bool from_open, void *ctx_udata);
70
71
/*********************/
72
/* Package Variables */
73
/*********************/
74
75
/* Package initialization variable */
76
bool H5_PKG_INIT_VAR = false;
77
78
/* Extensible array client ID to class mapping */
79
80
/* Remember to add client ID to H5EA_cls_id_t in H5EAprivate.h when adding a new
81
 * client class..
82
 */
83
const H5EA_class_t *const H5EA_client_class_g[] = {
84
    H5EA_CLS_CHUNK,      /* 0 - H5EA_CLS_CHUNK_ID     */
85
    H5EA_CLS_FILT_CHUNK, /* 1 - H5EA_CLS_FILT_CHUNK_ID    */
86
    H5EA_CLS_TEST,       /* ? - H5EA_CLS_TEST_ID      */
87
};
88
89
/*****************************/
90
/* Library Private Variables */
91
/*****************************/
92
93
/*******************/
94
/* Local Variables */
95
/*******************/
96
97
/* Declare a free list to manage the H5EA_t struct */
98
H5FL_DEFINE_STATIC(H5EA_t);
99
100
/* Declare a PQ free list to manage the element */
101
H5FL_BLK_DEFINE_STATIC(ea_native_elmt);
102
103
/*-------------------------------------------------------------------------
104
 * Function:  H5EA__new
105
 *
106
 * Purpose: Allocate and initialize a new extensible array wrapper in memory
107
 *
108
 * Return:  Pointer to earray wrapper success
109
 *              NULL on failure
110
 *
111
 *-------------------------------------------------------------------------
112
 */
113
static H5EA_t *
114
H5EA__new(H5F_t *f, haddr_t ea_addr, bool from_open, void *ctx_udata)
115
0
{
116
0
    H5EA_t     *ea        = NULL; /* Pointer to new extensible array */
117
0
    H5EA_hdr_t *hdr       = NULL; /* The extensible array header information */
118
0
    H5EA_t     *ret_value = NULL;
119
120
0
    FUNC_ENTER_PACKAGE
121
122
    /* Check arguments */
123
0
    assert(f);
124
0
    assert(H5_addr_defined(ea_addr));
125
126
    /* Allocate extensible array wrapper */
127
0
    if (NULL == (ea = H5FL_CALLOC(H5EA_t)))
128
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL, "memory allocation failed for extensible array info");
129
130
    /* Lock the array header into memory */
131
0
    if (NULL == (hdr = H5EA__hdr_protect(f, ea_addr, ctx_udata, H5AC__READ_ONLY_FLAG)))
132
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, NULL, "unable to load extensible array header");
133
134
    /* Check for pending array deletion */
135
0
    if (from_open && hdr->pending_delete)
136
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTOPENOBJ, NULL, "can't open extensible array pending deletion");
137
138
    /* Point extensible array wrapper at header and bump it's ref count */
139
0
    ea->hdr = hdr;
140
0
    if (H5EA__hdr_incr(ea->hdr) < 0)
141
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINC, NULL, "can't increment reference count on shared array header");
142
143
    /* Increment # of files using this array header */
144
0
    if (H5EA__hdr_fuse_incr(ea->hdr) < 0)
145
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINC, NULL,
146
0
                    "can't increment file reference count on shared array header");
147
148
    /* Set file pointer for this array open context */
149
0
    ea->f = f;
150
151
    /* Set the return value */
152
0
    ret_value = ea;
153
154
0
done:
155
156
0
    if (hdr && H5EA__hdr_unprotect(hdr, H5AC__NO_FLAGS_SET) < 0)
157
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, NULL, "unable to release extensible array header");
158
0
    if (!ret_value)
159
0
        if (ea && H5EA_close(ea) < 0)
160
0
            HDONE_ERROR(H5E_EARRAY, H5E_CLOSEERROR, NULL, "unable to close extensible array");
161
162
0
    FUNC_LEAVE_NOAPI(ret_value)
163
0
} /* end H5EA__new() */
164
165
/*-------------------------------------------------------------------------
166
 * Function:  H5EA_create
167
 *
168
 * Purpose: Creates a new empty extensible array in the file.
169
 *
170
 * Return:  Pointer to earray wrapper on success
171
 *              NULL on failure
172
 *
173
 *-------------------------------------------------------------------------
174
 */
175
H5EA_t *
176
H5EA_create(H5F_t *f, const H5EA_create_t *cparam, void *ctx_udata)
177
0
{
178
0
    H5EA_t *ea = NULL; /* Pointer to new extensible array */
179
0
    haddr_t ea_addr;   /* Array header address */
180
0
    H5EA_t *ret_value = NULL;
181
182
0
    FUNC_ENTER_NOAPI(NULL)
183
184
    /* Check arguments */
185
0
    assert(f);
186
0
    assert(cparam);
187
188
    /* H5EA interface sanity check */
189
0
    HDcompile_assert(H5EA_NUM_CLS_ID == NELMTS(H5EA_client_class_g));
190
191
    /* Create extensible array header */
192
0
    if (HADDR_UNDEF == (ea_addr = H5EA__hdr_create(f, cparam, ctx_udata)))
193
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINIT, NULL, "can't create extensible array header");
194
195
    /* Allocate and initialize new extensible array wrapper */
196
0
    if (NULL == (ea = H5EA__new(f, ea_addr, false, ctx_udata)))
197
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINIT, NULL,
198
0
                    "allocation and/or initialization failed for extensible array wrapper");
199
200
    /* Set the return value */
201
0
    ret_value = ea;
202
203
0
done:
204
0
    if (!ret_value)
205
0
        if (ea && H5EA_close(ea) < 0)
206
0
            HDONE_ERROR(H5E_EARRAY, H5E_CLOSEERROR, NULL, "unable to close extensible array");
207
208
0
    FUNC_LEAVE_NOAPI(ret_value)
209
0
} /* end H5EA_create() */
210
211
/*-------------------------------------------------------------------------
212
 * Function:  H5EA_open
213
 *
214
 * Purpose: Opens an existing extensible array in the file.
215
 *
216
 * Return:  Pointer to array wrapper on success
217
 *              NULL on failure
218
 *
219
 *-------------------------------------------------------------------------
220
 */
221
H5EA_t *
222
H5EA_open(H5F_t *f, haddr_t ea_addr, void *ctx_udata)
223
0
{
224
0
    H5EA_t *ea        = NULL; /* Pointer to new extensible array wrapper */
225
0
    H5EA_t *ret_value = NULL;
226
227
0
    FUNC_ENTER_NOAPI(NULL)
228
229
    /* Check arguments */
230
0
    assert(f);
231
0
    assert(H5_addr_defined(ea_addr));
232
233
    /* Allocate and initialize new extensible array wrapper */
234
0
    if (NULL == (ea = H5EA__new(f, ea_addr, true, ctx_udata)))
235
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTINIT, NULL,
236
0
                    "allocation and/or initialization failed for extensible array wrapper");
237
238
    /* Set the return value */
239
0
    ret_value = ea;
240
241
0
done:
242
0
    if (!ret_value)
243
0
        if (ea && H5EA_close(ea) < 0)
244
0
            HDONE_ERROR(H5E_EARRAY, H5E_CLOSEERROR, NULL, "unable to close extensible array");
245
246
0
    FUNC_LEAVE_NOAPI(ret_value)
247
0
} /* end H5EA_open() */
248
249
/*-------------------------------------------------------------------------
250
 * Function:  H5EA_get_nelmts
251
 *
252
 * Purpose: Query the current number of elements in array
253
 *
254
 * Return:  SUCCEED/FAIL
255
 *
256
 *-------------------------------------------------------------------------
257
 */
258
herr_t
259
H5EA_get_nelmts(const H5EA_t *ea, hsize_t *nelmts)
260
0
{
261
0
    FUNC_ENTER_NOAPI_NOERR
262
263
    /* Check arguments */
264
0
    assert(ea);
265
0
    assert(nelmts);
266
267
    /* Retrieve the max. index set */
268
0
    *nelmts = ea->hdr->stats.stored.max_idx_set;
269
270
0
    FUNC_LEAVE_NOAPI(SUCCEED)
271
0
} /* end H5EA_get_nelmts() */
272
273
/*-------------------------------------------------------------------------
274
 * Function:  H5EA_get_addr
275
 *
276
 * Purpose: Query the address of the array
277
 *
278
 * Return:  SUCCEED/FAIL
279
 *
280
 *-------------------------------------------------------------------------
281
 */
282
herr_t
283
H5EA_get_addr(const H5EA_t *ea, haddr_t *addr)
284
0
{
285
0
    FUNC_ENTER_NOAPI_NOERR
286
287
    /* Check arguments */
288
0
    assert(ea);
289
0
    assert(ea->hdr);
290
0
    assert(addr);
291
292
    /* Retrieve the address of the extensible array's header */
293
0
    *addr = ea->hdr->addr;
294
295
0
    FUNC_LEAVE_NOAPI(SUCCEED)
296
0
} /* end H5EA_get_addr() */
297
298
/*-------------------------------------------------------------------------
299
 * Function:  H5EA__lookup_elmt
300
 *
301
 * Purpose: Retrieve the metadata object and the element buffer for a
302
 *              given element in the array.
303
 *
304
 * Return:  SUCCEED/FAIL
305
 *
306
 *-------------------------------------------------------------------------
307
 */
308
static herr_t
309
H5EA__lookup_elmt(const H5EA_t *ea, hsize_t idx, bool will_extend, unsigned thing_acc, void **thing,
310
                  uint8_t **thing_elmt_buf, hsize_t *thing_elmt_idx,
311
                  H5EA__unprotect_func_t *thing_unprot_func)
312
0
{
313
0
    H5EA_hdr_t       *hdr                = ea->hdr;            /* Header for EA */
314
0
    H5EA_iblock_t    *iblock             = NULL;               /* Pointer to index block for EA */
315
0
    H5EA_sblock_t    *sblock             = NULL;               /* Pointer to super block for EA */
316
0
    H5EA_dblock_t    *dblock             = NULL;               /* Pointer to data block for EA */
317
0
    H5EA_dblk_page_t *dblk_page          = NULL;               /* Pointer to data block page for EA */
318
0
    unsigned          iblock_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting index block */
319
0
    unsigned          sblock_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting super block */
320
0
    bool              stats_changed      = false;              /* Whether array statistics changed */
321
0
    bool              hdr_dirty          = false;              /* Whether the array header changed */
322
0
    herr_t            ret_value          = SUCCEED;
323
324
0
    FUNC_ENTER_PACKAGE
325
326
    /* Check arguments */
327
0
    assert(ea);
328
0
    assert(hdr);
329
0
    assert(thing);
330
0
    assert(thing_elmt_buf);
331
0
    assert(thing_unprot_func);
332
333
    /* only the H5AC__READ_ONLY_FLAG may be set in thing_acc */
334
0
    assert((thing_acc & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
335
336
    /* Set the shared array header's file context for this operation */
337
0
    hdr->f = ea->f;
338
339
    /* Reset the pointers to the 'thing' info */
340
0
    *thing             = NULL;
341
0
    *thing_elmt_buf    = NULL;
342
0
    *thing_elmt_idx    = 0;
343
0
    *thing_unprot_func = (H5EA__unprotect_func_t)NULL;
344
345
    /* Check if we should create the index block */
346
0
    if (!H5_addr_defined(hdr->idx_blk_addr)) {
347
        /* Check if we are allowed to create the thing */
348
0
        if (0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
349
            /* Create the index block */
350
0
            hdr->idx_blk_addr = H5EA__iblock_create(hdr, &stats_changed);
351
0
            if (!H5_addr_defined(hdr->idx_blk_addr))
352
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTCREATE, FAIL, "unable to create index block");
353
0
            hdr_dirty = true;
354
0
        } /* end if */
355
0
        else
356
0
            HGOTO_DONE(SUCCEED);
357
0
    } /* end if */
358
359
    /* Protect index block */
360
0
    if (NULL == (iblock = H5EA__iblock_protect(hdr, thing_acc)))
361
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
362
0
                    "unable to protect extensible array index block, address = %llu",
363
0
                    (unsigned long long)hdr->idx_blk_addr);
364
365
    /* Check if element is in index block */
366
0
    if (idx < hdr->cparam.idx_blk_elmts) {
367
        /* Set 'thing' info to refer to the index block */
368
0
        *thing             = iblock;
369
0
        *thing_elmt_buf    = (uint8_t *)iblock->elmts;
370
0
        *thing_elmt_idx    = idx;
371
0
        *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__iblock_unprotect;
372
0
    } /* end if */
373
0
    else {
374
0
        unsigned sblk_idx; /* Which superblock does this index fall in? */
375
0
        size_t   dblk_idx; /* Data block index */
376
0
        hsize_t  elmt_idx; /* Offset of element in super block */
377
378
        /* Get super block index where element is located */
379
0
        sblk_idx = H5EA__dblock_sblk_idx(hdr, idx);
380
381
        /* Adjust index to offset in super block */
382
0
        elmt_idx = idx - (hdr->cparam.idx_blk_elmts + hdr->sblk_info[sblk_idx].start_idx);
383
384
        /* Check for data block containing element address in the index block */
385
0
        if (sblk_idx < iblock->nsblks) {
386
            /* Compute the data block index in index block */
387
0
            dblk_idx = (size_t)(hdr->sblk_info[sblk_idx].start_dblk +
388
0
                                (elmt_idx / hdr->sblk_info[sblk_idx].dblk_nelmts));
389
0
            assert(dblk_idx < iblock->ndblk_addrs);
390
391
            /* Check if the data block has been allocated on disk yet */
392
0
            if (!H5_addr_defined(iblock->dblk_addrs[dblk_idx])) {
393
                /* Check if we are allowed to create the thing */
394
0
                if (0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
395
0
                    haddr_t dblk_addr;                         /* Address of data block created */
396
0
                    hsize_t dblk_off;                          /* Offset of data block in array */
397
398
                    /* Create data block */
399
0
                    dblk_off = hdr->sblk_info[sblk_idx].start_idx +
400
0
                               (dblk_idx * hdr->sblk_info[sblk_idx].dblk_nelmts);
401
0
                    dblk_addr = H5EA__dblock_create(hdr, iblock, &stats_changed, dblk_off,
402
0
                                                    hdr->sblk_info[sblk_idx].dblk_nelmts);
403
0
                    if (!H5_addr_defined(dblk_addr))
404
0
                        HGOTO_ERROR(H5E_EARRAY, H5E_CANTCREATE, FAIL,
405
0
                                    "unable to create extensible array data block");
406
407
                    /* Set data block address in index block */
408
0
                    iblock->dblk_addrs[dblk_idx] = dblk_addr;
409
0
                    iblock_cache_flags |= H5AC__DIRTIED_FLAG;
410
0
                } /* end if */
411
0
                else
412
0
                    HGOTO_DONE(SUCCEED);
413
0
            } /* end if */
414
415
            /* Protect data block */
416
0
            if (NULL == (dblock = H5EA__dblock_protect(hdr, iblock, iblock->dblk_addrs[dblk_idx],
417
0
                                                       hdr->sblk_info[sblk_idx].dblk_nelmts, thing_acc)))
418
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
419
0
                            "unable to protect extensible array data block, address = %llu",
420
0
                            (unsigned long long)iblock->dblk_addrs[dblk_idx]);
421
422
            /* Adjust index to offset in data block */
423
0
            elmt_idx %= hdr->sblk_info[sblk_idx].dblk_nelmts;
424
425
            /* Check if there is already a dependency on the header */
426
0
            if (will_extend && !dblock->has_hdr_depend) {
427
0
                if (H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblock) < 0)
428
0
                    HGOTO_ERROR(
429
0
                        H5E_EARRAY, H5E_CANTDEPEND, FAIL,
430
0
                        "unable to create flush dependency between data block and header, index = %llu",
431
0
                        (unsigned long long)idx);
432
0
                dblock->has_hdr_depend = true;
433
0
            } /* end if */
434
435
            /* Set 'thing' info to refer to the data block */
436
0
            *thing             = dblock;
437
0
            *thing_elmt_buf    = (uint8_t *)dblock->elmts;
438
0
            *thing_elmt_idx    = elmt_idx;
439
0
            *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblock_unprotect;
440
0
        } /* end if */
441
0
        else {
442
0
            size_t sblk_off; /* Offset of super block in index block array of super blocks */
443
444
            /* Calculate offset of super block in index block's array */
445
0
            sblk_off = sblk_idx - iblock->nsblks;
446
447
            /* Check if the super block has been allocated on disk yet */
448
0
            if (!H5_addr_defined(iblock->sblk_addrs[sblk_off])) {
449
                /* Check if we are allowed to create the thing */
450
0
                if (0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
451
0
                    haddr_t sblk_addr;                         /* Address of data block created */
452
453
                    /* Create super block */
454
0
                    sblk_addr = H5EA__sblock_create(hdr, iblock, &stats_changed, sblk_idx);
455
0
                    if (!H5_addr_defined(sblk_addr))
456
0
                        HGOTO_ERROR(H5E_EARRAY, H5E_CANTCREATE, FAIL,
457
0
                                    "unable to create extensible array super block");
458
459
                    /* Set super block address in index block */
460
0
                    iblock->sblk_addrs[sblk_off] = sblk_addr;
461
0
                    iblock_cache_flags |= H5AC__DIRTIED_FLAG;
462
0
                } /* end if */
463
0
                else
464
0
                    HGOTO_DONE(SUCCEED);
465
0
            } /* end if */
466
467
            /* Protect super block */
468
0
            if (NULL == (sblock = H5EA__sblock_protect(hdr, iblock, iblock->sblk_addrs[sblk_off], sblk_idx,
469
0
                                                       thing_acc)))
470
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
471
0
                            "unable to protect extensible array super block, address = %llu",
472
0
                            (unsigned long long)iblock->sblk_addrs[sblk_off]);
473
474
            /* Compute the data block index in super block */
475
0
            dblk_idx = (size_t)(elmt_idx / sblock->dblk_nelmts);
476
0
            assert(dblk_idx < sblock->ndblks);
477
478
            /* Check if the data block has been allocated on disk yet */
479
0
            if (!H5_addr_defined(sblock->dblk_addrs[dblk_idx])) {
480
                /* Check if we are allowed to create the thing */
481
0
                if (0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
482
0
                    haddr_t dblk_addr;                         /* Address of data block created */
483
0
                    hsize_t dblk_off;                          /* Offset of data block in array */
484
485
                    /* Create data block */
486
0
                    dblk_off = hdr->sblk_info[sblk_idx].start_idx +
487
0
                               (dblk_idx * hdr->sblk_info[sblk_idx].dblk_nelmts);
488
0
                    dblk_addr =
489
0
                        H5EA__dblock_create(hdr, sblock, &stats_changed, dblk_off, sblock->dblk_nelmts);
490
0
                    if (!H5_addr_defined(dblk_addr))
491
0
                        HGOTO_ERROR(H5E_EARRAY, H5E_CANTCREATE, FAIL,
492
0
                                    "unable to create extensible array data block");
493
494
                    /* Set data block address in index block */
495
0
                    sblock->dblk_addrs[dblk_idx] = dblk_addr;
496
0
                    sblock_cache_flags |= H5AC__DIRTIED_FLAG;
497
498
                    /* Create flush dependency on header, if extending the array and one doesn't already exist
499
                     */
500
0
                    if (will_extend && !sblock->has_hdr_depend) {
501
0
                        if (H5EA__create_flush_depend((H5AC_info_t *)sblock->hdr, (H5AC_info_t *)sblock) < 0)
502
0
                            HGOTO_ERROR(
503
0
                                H5E_EARRAY, H5E_CANTDEPEND, FAIL,
504
0
                                "unable to create flush dependency between super block and header, address "
505
0
                                "= %llu",
506
0
                                (unsigned long long)sblock->addr);
507
0
                        sblock->has_hdr_depend = true;
508
0
                    } /* end if */
509
0
                }     /* end if */
510
0
                else
511
0
                    HGOTO_DONE(SUCCEED);
512
0
            } /* end if */
513
514
            /* Adjust index to offset in data block */
515
0
            elmt_idx %= sblock->dblk_nelmts;
516
517
            /* Check if the data block is paged */
518
0
            if (sblock->dblk_npages) {
519
0
                haddr_t dblk_page_addr; /* Address of data block page */
520
0
                size_t  page_idx;       /* Index of page within data block */
521
0
                size_t  page_init_idx;  /* Index of 'page init' bit */
522
523
                /* Compute page index */
524
0
                page_idx = (size_t)elmt_idx / hdr->dblk_page_nelmts;
525
526
                /* Compute 'page init' index */
527
0
                page_init_idx = (dblk_idx * sblock->dblk_npages) + page_idx;
528
529
                /* Adjust index to offset in data block page */
530
0
                elmt_idx %= hdr->dblk_page_nelmts;
531
532
                /* Compute data block page address */
533
0
                dblk_page_addr = sblock->dblk_addrs[dblk_idx] + H5EA_DBLOCK_PREFIX_SIZE(sblock) +
534
0
                                 (page_idx * sblock->dblk_page_size);
535
536
                /* Check if page has been initialized yet */
537
0
                if (!H5VM_bit_get(sblock->page_init, page_init_idx)) {
538
                    /* Check if we are allowed to create the thing */
539
0
                    if (0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
540
                        /* Create the data block page */
541
0
                        if (H5EA__dblk_page_create(hdr, sblock, dblk_page_addr) < 0)
542
0
                            HGOTO_ERROR(H5E_EARRAY, H5E_CANTCREATE, FAIL, "unable to create data block page");
543
544
                        /* Mark data block page as initialized in super block */
545
0
                        H5VM_bit_set(sblock->page_init, page_init_idx, true);
546
0
                        sblock_cache_flags |= H5AC__DIRTIED_FLAG;
547
0
                    } /* end if */
548
0
                    else
549
0
                        HGOTO_DONE(SUCCEED);
550
0
                } /* end if */
551
552
                /* Protect data block page */
553
0
                if (NULL == (dblk_page = H5EA__dblk_page_protect(hdr, sblock, dblk_page_addr, thing_acc)))
554
0
                    HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
555
0
                                "unable to protect extensible array data block page, address = %llu",
556
0
                                (unsigned long long)dblk_page_addr);
557
558
                /* Check if there is already a dependency on the header */
559
0
                if (will_extend && !dblk_page->has_hdr_depend) {
560
0
                    if (H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblk_page) < 0)
561
0
                        HGOTO_ERROR(H5E_EARRAY, H5E_CANTDEPEND, FAIL,
562
0
                                    "unable to create flush dependency between data block page and header, "
563
0
                                    "index = %llu",
564
0
                                    (unsigned long long)idx);
565
0
                    dblk_page->has_hdr_depend = true;
566
0
                } /* end if */
567
568
                /* Set 'thing' info to refer to the data block page */
569
0
                *thing             = dblk_page;
570
0
                *thing_elmt_buf    = (uint8_t *)dblk_page->elmts;
571
0
                *thing_elmt_idx    = elmt_idx;
572
0
                *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblk_page_unprotect;
573
0
            } /* end if */
574
0
            else {
575
                /* Protect data block */
576
0
                if (NULL == (dblock = H5EA__dblock_protect(hdr, sblock, sblock->dblk_addrs[dblk_idx],
577
0
                                                           sblock->dblk_nelmts, thing_acc)))
578
0
                    HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
579
0
                                "unable to protect extensible array data block, address = %llu",
580
0
                                (unsigned long long)sblock->dblk_addrs[dblk_idx]);
581
582
                /* Check if there is already a dependency on the header */
583
0
                if (will_extend && !dblock->has_hdr_depend) {
584
0
                    if (H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblock) < 0)
585
0
                        HGOTO_ERROR(
586
0
                            H5E_EARRAY, H5E_CANTDEPEND, FAIL,
587
0
                            "unable to create flush dependency between data block and header, index = %llu",
588
0
                            (unsigned long long)idx);
589
0
                    dblock->has_hdr_depend = true;
590
0
                } /* end if */
591
592
                /* Set 'thing' info to refer to the data block */
593
0
                *thing             = dblock;
594
0
                *thing_elmt_buf    = (uint8_t *)dblock->elmts;
595
0
                *thing_elmt_idx    = elmt_idx;
596
0
                *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblock_unprotect;
597
0
            } /* end else */
598
0
        }     /* end else */
599
0
    }         /* end else */
600
601
    /* Sanity checks */
602
0
    assert(*thing != NULL);
603
0
    assert(*thing_unprot_func != NULL);
604
605
0
done:
606
    /* Reset 'thing' info on error */
607
0
    if (ret_value < 0) {
608
0
        *thing             = NULL;
609
0
        *thing_elmt_buf    = NULL;
610
0
        *thing_elmt_idx    = 0;
611
0
        *thing_unprot_func = (H5EA__unprotect_func_t)NULL;
612
0
    } /* end if */
613
614
    /* Check for updating array statistics */
615
0
    if (stats_changed)
616
0
        hdr_dirty = true;
617
618
    /* Check for header modified */
619
0
    if (hdr_dirty)
620
0
        if (H5EA__hdr_modified(hdr) < 0)
621
0
            HDONE_ERROR(H5E_EARRAY, H5E_CANTMARKDIRTY, FAIL,
622
0
                        "unable to mark extensible array header as modified");
623
624
    /* Release resources */
625
0
    if (iblock && *thing != iblock && H5EA__iblock_unprotect(iblock, iblock_cache_flags) < 0)
626
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array index block");
627
    /* (Note: super blocks don't contain elements, so don't have a '*thing != sblock' check) */
628
0
    if (sblock && H5EA__sblock_unprotect(sblock, sblock_cache_flags) < 0)
629
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array super block");
630
0
    if (dblock && *thing != dblock && H5EA__dblock_unprotect(dblock, H5AC__NO_FLAGS_SET) < 0)
631
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array data block");
632
0
    if (dblk_page && *thing != dblk_page && H5EA__dblk_page_unprotect(dblk_page, H5AC__NO_FLAGS_SET) < 0)
633
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL,
634
0
                    "unable to release extensible array data block page");
635
636
0
    FUNC_LEAVE_NOAPI(ret_value)
637
0
} /* end H5EA__lookup_elmt() */
638
639
/*-------------------------------------------------------------------------
640
 * Function:  H5EA_set
641
 *
642
 * Purpose: Set an element of an extensible array
643
 *
644
 * Return:  SUCCEED/FAIL
645
 *
646
 *-------------------------------------------------------------------------
647
 */
648
herr_t
649
H5EA_set(const H5EA_t *ea, hsize_t idx, const void *elmt)
650
0
{
651
0
    H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */
652
0
    void    *thing = NULL; /* Pointer to the array metadata containing the array index we are interested in */
653
0
    uint8_t *thing_elmt_buf; /* Pointer to the element buffer for the array metadata */
654
0
    hsize_t  thing_elmt_idx; /* Index of the element in the element buffer for the array metadata */
655
0
    H5EA__unprotect_func_t thing_unprot_func; /* Function pointer for unprotecting the array metadata */
656
0
    bool                   will_extend; /* Flag indicating if setting the element will extend the array */
657
0
    unsigned               thing_cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting array metadata */
658
0
    herr_t                 ret_value         = SUCCEED;
659
660
0
    FUNC_ENTER_NOAPI(FAIL)
661
662
    /* Check arguments */
663
0
    assert(ea);
664
0
    assert(hdr);
665
666
    /* Set the shared array header's file context for this operation */
667
0
    hdr->f = ea->f;
668
669
    /* Look up the array metadata containing the element we want to set */
670
0
    will_extend = (idx >= hdr->stats.stored.max_idx_set);
671
0
    if (H5EA__lookup_elmt(ea, idx, will_extend, H5AC__NO_FLAGS_SET, &thing, &thing_elmt_buf, &thing_elmt_idx,
672
0
                          &thing_unprot_func) < 0)
673
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL, "unable to protect array metadata");
674
675
    /* Sanity check */
676
0
    assert(thing);
677
0
    assert(thing_elmt_buf);
678
0
    assert(thing_unprot_func);
679
680
    /* Set element in thing's element buffer */
681
0
    H5MM_memcpy(thing_elmt_buf + (hdr->cparam.cls->nat_elmt_size * thing_elmt_idx), elmt,
682
0
                hdr->cparam.cls->nat_elmt_size);
683
0
    thing_cache_flags |= H5AC__DIRTIED_FLAG;
684
685
    /* Update max. element set in array, if appropriate */
686
0
    if (will_extend) {
687
        /* Update the max index for the array */
688
0
        hdr->stats.stored.max_idx_set = idx + 1;
689
0
        if (H5EA__hdr_modified(hdr) < 0)
690
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTMARKDIRTY, FAIL,
691
0
                        "unable to mark extensible array header as modified");
692
0
    }
693
694
0
done:
695
    /* Release resources */
696
0
    if (thing && (thing_unprot_func)(thing, thing_cache_flags) < 0)
697
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array metadata");
698
699
0
    FUNC_LEAVE_NOAPI(ret_value)
700
0
} /* end H5EA_set() */
701
702
/*-------------------------------------------------------------------------
703
 * Function:  H5EA_get
704
 *
705
 * Purpose: Get an element of an extensible array
706
 *
707
 * Return:  SUCCEED/FAIL
708
 *
709
 *-------------------------------------------------------------------------
710
 */
711
herr_t
712
H5EA_get(const H5EA_t *ea, hsize_t idx, void *elmt)
713
0
{
714
0
    H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */
715
0
    void *thing = NULL; /* Pointer to the array metadata containing the array index we are interested in */
716
0
    H5EA__unprotect_func_t thing_unprot_func =
717
0
        NULL; /* Function pointer for unprotecting the array metadata */
718
0
    herr_t ret_value = SUCCEED;
719
720
0
    FUNC_ENTER_NOAPI(FAIL)
721
722
    /* Check arguments */
723
0
    assert(ea);
724
0
    assert(hdr);
725
726
    /* Check for element beyond max. element in array */
727
0
    if (idx >= hdr->stats.stored.max_idx_set) {
728
        /* Call the class's 'fill' callback */
729
0
        if ((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0)
730
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, FAIL, "can't set element to class's fill value");
731
0
    } /* end if */
732
0
    else {
733
0
        uint8_t *thing_elmt_buf; /* Pointer to the element buffer for the array metadata */
734
0
        hsize_t  thing_elmt_idx; /* Index of the element in the element buffer for the array metadata */
735
736
        /* Set the shared array header's file context for this operation */
737
0
        hdr->f = ea->f;
738
739
        /* Look up the array metadata containing the element we want to set */
740
0
        if (H5EA__lookup_elmt(ea, idx, false, H5AC__READ_ONLY_FLAG, &thing, &thing_elmt_buf, &thing_elmt_idx,
741
0
                              &thing_unprot_func) < 0)
742
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL, "unable to protect array metadata");
743
744
        /* Check if the thing holding the element has been created yet */
745
0
        if (NULL == thing) {
746
            /* Call the class's 'fill' callback */
747
0
            if ((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0)
748
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, FAIL, "can't set element to class's fill value");
749
0
        } /* end if */
750
0
        else
751
            /* Get element from thing's element buffer */
752
0
            H5MM_memcpy(elmt, thing_elmt_buf + (hdr->cparam.cls->nat_elmt_size * thing_elmt_idx),
753
0
                        hdr->cparam.cls->nat_elmt_size);
754
0
    } /* end else */
755
756
0
done:
757
    /* Release thing */
758
0
    if (thing && (thing_unprot_func)(thing, H5AC__NO_FLAGS_SET) < 0)
759
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array metadata");
760
761
0
    FUNC_LEAVE_NOAPI(ret_value)
762
0
} /* end H5EA_get() */
763
764
/*-------------------------------------------------------------------------
765
 * Function:  H5EA_depend
766
 *
767
 * Purpose: Make a child flush dependency between the extensible array
768
 *              and another piece of metadata in the file.
769
 *
770
 * Return:  SUCCEED/FAIL
771
 *
772
 *-------------------------------------------------------------------------
773
 */
774
herr_t
775
H5EA_depend(H5EA_t *ea, H5AC_proxy_entry_t *parent)
776
0
{
777
0
    H5EA_hdr_t *hdr       = ea->hdr; /* Header for EA */
778
0
    herr_t      ret_value = SUCCEED;
779
780
0
    FUNC_ENTER_NOAPI(FAIL)
781
782
    /* Check arguments */
783
0
    assert(ea);
784
0
    assert(hdr);
785
0
    assert(parent);
786
787
    /*
788
     * Check to see if a flush dependency between the extensible array
789
     * and another data structure in the file has already been set up.
790
     * If it hasn't, do so now.
791
     */
792
0
    if (NULL == hdr->parent) {
793
        /* Sanity check */
794
0
        assert(hdr->top_proxy);
795
796
        /* Set the shared array header's file context for this operation */
797
0
        hdr->f = ea->f;
798
799
        /* Add the extensible array as a child of the parent (proxy) */
800
0
        if (H5AC_proxy_entry_add_child(parent, hdr->f, hdr->top_proxy) < 0)
801
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, FAIL, "unable to add extensible array as child of proxy");
802
0
        hdr->parent = parent;
803
0
    }
804
805
0
done:
806
0
    FUNC_LEAVE_NOAPI(ret_value)
807
0
} /* end H5EA_depend() */
808
809
/*-------------------------------------------------------------------------
810
 * Function:  H5EA_close
811
 *
812
 * Purpose: Close an extensible array
813
 *
814
 * Return:  SUCCEED/FAIL
815
 *
816
 *-------------------------------------------------------------------------
817
 */
818
herr_t
819
H5EA_close(H5EA_t *ea)
820
0
{
821
0
    bool    pending_delete = false;       /* Whether the array is pending deletion */
822
0
    haddr_t ea_addr        = HADDR_UNDEF; /* Address of array (for deletion) */
823
0
    herr_t  ret_value      = SUCCEED;
824
825
0
    FUNC_ENTER_NOAPI(FAIL)
826
827
    /* Check arguments */
828
0
    assert(ea);
829
830
    /* Close the header, if it was set */
831
0
    if (ea->hdr) {
832
        /* Decrement file reference & check if this is the last open extensible array using the shared array
833
         * header */
834
0
        if (0 == H5EA__hdr_fuse_decr(ea->hdr)) {
835
            /* Set the shared array header's file context for this operation */
836
0
            ea->hdr->f = ea->f;
837
838
            /* Shut down anything that can't be put in the header's 'flush' callback */
839
840
            /* Check for pending array deletion */
841
0
            if (ea->hdr->pending_delete) {
842
                /* Set local info, so array deletion can occur after decrementing the
843
                 *  header's ref count
844
                 */
845
0
                pending_delete = true;
846
0
                ea_addr        = ea->hdr->addr;
847
0
            } /* end if */
848
0
        }     /* end if */
849
850
        /* Check for pending array deletion */
851
0
        if (pending_delete) {
852
0
            H5EA_hdr_t *hdr; /* Another pointer to extensible array header */
853
854
#ifndef NDEBUG
855
            {
856
                unsigned hdr_status = 0; /* Header's status in the metadata cache */
857
858
                /* Check the header's status in the metadata cache */
859
                if (H5AC_get_entry_status(ea->f, ea_addr, &hdr_status) < 0)
860
                    HGOTO_ERROR(H5E_EARRAY, H5E_CANTGET, FAIL,
861
                                "unable to check metadata cache status for extensible array header");
862
863
                /* Sanity checks on header */
864
                assert(hdr_status & H5AC_ES__IN_CACHE);
865
                assert(hdr_status & H5AC_ES__IS_PINNED);
866
                assert(!(hdr_status & H5AC_ES__IS_PROTECTED));
867
            }
868
#endif /* NDEBUG */
869
870
            /* Lock the array header into memory */
871
            /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */
872
0
            if (NULL == (hdr = H5EA__hdr_protect(ea->f, ea_addr, NULL, H5AC__NO_FLAGS_SET)))
873
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTLOAD, FAIL, "unable to load extensible array header");
874
875
            /* Set the shared array header's file context for this operation */
876
0
            hdr->f = ea->f;
877
878
            /* Decrement the reference count on the array header */
879
            /* (don't put in H5EA_hdr_fuse_decr() as the array header may be evicted
880
             *  immediately -QAK)
881
             */
882
0
            if (H5EA__hdr_decr(ea->hdr) < 0)
883
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTDEC, FAIL,
884
0
                            "can't decrement reference count on shared array header");
885
886
            /* Delete array, starting with header (unprotects header) */
887
0
            if (H5EA__hdr_delete(hdr) < 0)
888
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTDELETE, FAIL, "unable to delete extensible array");
889
0
        } /* end if */
890
0
        else {
891
            /* Decrement the reference count on the array header */
892
            /* (don't put in H5EA_hdr_fuse_decr() as the array header may be evicted
893
             *  immediately -QAK)
894
             */
895
0
            if (H5EA__hdr_decr(ea->hdr) < 0)
896
0
                HGOTO_ERROR(H5E_EARRAY, H5E_CANTDEC, FAIL,
897
0
                            "can't decrement reference count on shared array header");
898
0
        } /* end else */
899
0
    }     /* end if */
900
901
    /* Release the extensible array wrapper */
902
0
    ea = (H5EA_t *)H5FL_FREE(H5EA_t, ea);
903
904
0
done:
905
0
    FUNC_LEAVE_NOAPI(ret_value)
906
0
} /* end H5EA_close() */
907
908
/*-------------------------------------------------------------------------
909
 * Function:  H5EA_delete
910
 *
911
 * Purpose: Delete an extensible array
912
 *
913
 * Return:  SUCCEED/FAIL
914
 *
915
 *-------------------------------------------------------------------------
916
 */
917
herr_t
918
H5EA_delete(H5F_t *f, haddr_t ea_addr, void *ctx_udata)
919
0
{
920
0
    H5EA_hdr_t *hdr       = NULL; /* The fractal heap header information */
921
0
    herr_t      ret_value = SUCCEED;
922
923
0
    FUNC_ENTER_NOAPI(FAIL)
924
925
    /* Check arguments */
926
0
    assert(f);
927
0
    assert(H5_addr_defined(ea_addr));
928
929
    /* Lock the array header into memory */
930
0
    if (NULL == (hdr = H5EA__hdr_protect(f, ea_addr, ctx_udata, H5AC__NO_FLAGS_SET)))
931
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL,
932
0
                    "unable to protect extensible array header, address = %llu", (unsigned long long)ea_addr);
933
934
    /* Check for files using shared array header */
935
0
    if (hdr->file_rc)
936
0
        hdr->pending_delete = true;
937
0
    else {
938
        /* Set the shared array header's file context for this operation */
939
0
        hdr->f = f;
940
941
        /* Delete array now, starting with header (unprotects header) */
942
0
        if (H5EA__hdr_delete(hdr) < 0)
943
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTDELETE, FAIL, "unable to delete extensible array");
944
0
        hdr = NULL;
945
0
    }
946
947
0
done:
948
    /* Unprotect the header if an error occurred */
949
0
    if (hdr && H5EA__hdr_unprotect(hdr, H5AC__NO_FLAGS_SET) < 0)
950
0
        HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array header");
951
952
0
    FUNC_LEAVE_NOAPI(ret_value)
953
0
} /* end H5EA_delete() */
954
955
/*-------------------------------------------------------------------------
956
 * Function:    H5EA_iterate
957
 *
958
 * Purpose: Iterate over the elements of an extensible array
959
 *    (copied and modified from FA_iterate() in H5FA.c)
960
 *
961
 * Return:      H5_ITER_CONT/H5_ITER_ERROR
962
 *
963
 *-------------------------------------------------------------------------
964
 */
965
int
966
H5EA_iterate(H5EA_t *ea, H5EA_operator_t op, void *udata)
967
0
{
968
0
    uint8_t *elmt = NULL;
969
0
    hsize_t  u;
970
0
    int      ret_value = H5_ITER_CONT;
971
972
0
    FUNC_ENTER_NOAPI(H5_ITER_ERROR)
973
974
    /* Check arguments */
975
0
    assert(ea);
976
0
    assert(op);
977
0
    assert(udata);
978
979
    /* Allocate space for a native array element */
980
0
    if (NULL == (elmt = H5FL_BLK_MALLOC(ea_native_elmt, ea->hdr->cparam.cls->nat_elmt_size)))
981
0
        HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, H5_ITER_ERROR,
982
0
                    "memory allocation failed for extensible array element");
983
984
    /* Iterate over all elements in array */
985
0
    for (u = 0; u < ea->hdr->stats.stored.max_idx_set && ret_value == H5_ITER_CONT; u++) {
986
        /* Get array element */
987
0
        if (H5EA_get(ea, u, elmt) < 0)
988
0
            HGOTO_ERROR(H5E_EARRAY, H5E_CANTGET, H5_ITER_ERROR, "unable to delete fixed array");
989
990
        /* Make callback */
991
0
        if ((ret_value = (*op)(u, elmt, udata)) < 0) {
992
0
            HERROR(H5E_EARRAY, H5E_BADITER, "iteration callback error");
993
0
            break;
994
0
        }
995
0
    }
996
997
0
done:
998
0
    if (elmt)
999
0
        elmt = H5FL_BLK_FREE(ea_native_elmt, elmt);
1000
1001
0
    FUNC_LEAVE_NOAPI(ret_value)
1002
0
} /* end H5EA_iterate() */
1003
1004
/*-------------------------------------------------------------------------
1005
 * Function:    H5EA_patch_file
1006
 *
1007
 * Purpose:     Patch the top-level file pointer contained in ea
1008
 *              to point to idx_info->f if they are different.
1009
 *              This is possible because the file pointer in ea can be
1010
 *              closed out if ea remains open.
1011
 *
1012
 * Return:      SUCCEED
1013
 *
1014
 *-------------------------------------------------------------------------
1015
 */
1016
herr_t
1017
H5EA_patch_file(H5EA_t *ea, H5F_t *f)
1018
0
{
1019
0
    FUNC_ENTER_NOAPI_NOERR
1020
1021
    /* Check arguments */
1022
0
    assert(ea);
1023
0
    assert(f);
1024
1025
0
    if (ea->f != f || ea->hdr->f != f)
1026
0
        ea->f = ea->hdr->f = f;
1027
1028
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1029
0
} /* end H5EA_patch_file() */