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