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