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