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