/src/hdf5/src/H5EAsblock.c
Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /*------------------------------------------------------------------------- |
14 | | * |
15 | | * Created: H5EAsblock.c |
16 | | * |
17 | | * Purpose: Super block routines for extensible arrays. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /**********************/ |
23 | | /* Module Declaration */ |
24 | | /**********************/ |
25 | | |
26 | | #include "H5EAmodule.h" /* This source code file is part of the H5EA module */ |
27 | | |
28 | | /***********************/ |
29 | | /* Other Packages Used */ |
30 | | /***********************/ |
31 | | |
32 | | /***********/ |
33 | | /* Headers */ |
34 | | /***********/ |
35 | | #include "H5private.h" /* Generic Functions */ |
36 | | #include "H5Eprivate.h" /* Error handling */ |
37 | | #include "H5EApkg.h" /* Extensible Arrays */ |
38 | | #include "H5FLprivate.h" /* Free Lists */ |
39 | | #include "H5MFprivate.h" /* File memory management */ |
40 | | #include "H5VMprivate.h" /* Vectors and arrays */ |
41 | | |
42 | | /****************/ |
43 | | /* Local Macros */ |
44 | | /****************/ |
45 | | |
46 | | /******************/ |
47 | | /* Local Typedefs */ |
48 | | /******************/ |
49 | | |
50 | | /********************/ |
51 | | /* Package Typedefs */ |
52 | | /********************/ |
53 | | |
54 | | /********************/ |
55 | | /* Local Prototypes */ |
56 | | /********************/ |
57 | | |
58 | | /*********************/ |
59 | | /* Package Variables */ |
60 | | /*********************/ |
61 | | |
62 | | /*****************************/ |
63 | | /* Library Private Variables */ |
64 | | /*****************************/ |
65 | | |
66 | | /*******************/ |
67 | | /* Local Variables */ |
68 | | /*******************/ |
69 | | |
70 | | /* Declare a free list to manage the H5EA_iblock_t struct */ |
71 | | H5FL_DEFINE_STATIC(H5EA_sblock_t); |
72 | | |
73 | | /* Declare a free list to manage the haddr_t sequence information */ |
74 | | H5FL_SEQ_DEFINE_STATIC(haddr_t); |
75 | | |
76 | | /* Declare a free list to manage blocks of 'page init' bitmasks */ |
77 | | H5FL_BLK_DEFINE(page_init); |
78 | | |
79 | | /*------------------------------------------------------------------------- |
80 | | * Function: H5EA__sblock_alloc |
81 | | * |
82 | | * Purpose: Allocate extensible array super block |
83 | | * |
84 | | * Return: Non-NULL pointer to super block on success/NULL on failure |
85 | | * |
86 | | *------------------------------------------------------------------------- |
87 | | */ |
88 | | H5EA_sblock_t * |
89 | | H5EA__sblock_alloc(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, unsigned sblk_idx) |
90 | 0 | { |
91 | 0 | H5EA_sblock_t *sblock = NULL; /* Extensible array super block */ |
92 | 0 | H5EA_sblock_t *ret_value = NULL; |
93 | |
|
94 | 0 | FUNC_ENTER_PACKAGE |
95 | | |
96 | | /* Check arguments */ |
97 | 0 | assert(hdr); |
98 | | |
99 | | /* Allocate memory for the index block */ |
100 | 0 | if (NULL == (sblock = H5FL_CALLOC(H5EA_sblock_t))) |
101 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL, |
102 | 0 | "memory allocation failed for extensible array super block"); |
103 | | |
104 | | /* Share common array information */ |
105 | 0 | if (H5EA__hdr_incr(hdr) < 0) |
106 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTINC, NULL, "can't increment reference count on shared array header"); |
107 | 0 | sblock->hdr = hdr; |
108 | | |
109 | | /* Set non-zero internal fields */ |
110 | 0 | sblock->parent = parent; |
111 | 0 | sblock->addr = HADDR_UNDEF; |
112 | | |
113 | | /* Compute/cache information */ |
114 | 0 | sblock->idx = sblk_idx; |
115 | 0 | sblock->ndblks = hdr->sblk_info[sblk_idx].ndblks; |
116 | 0 | assert(sblock->ndblks); |
117 | 0 | sblock->dblk_nelmts = hdr->sblk_info[sblk_idx].dblk_nelmts; |
118 | | |
119 | | /* Allocate buffer for data block addresses in super block */ |
120 | 0 | if (NULL == (sblock->dblk_addrs = H5FL_SEQ_MALLOC(haddr_t, sblock->ndblks))) |
121 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL, |
122 | 0 | "memory allocation failed for super block data block addresses"); |
123 | | |
124 | | /* Check if # of elements in data blocks requires paging */ |
125 | 0 | if (sblock->dblk_nelmts > hdr->dblk_page_nelmts) { |
126 | | /* Compute # of pages in each data block from this super block */ |
127 | 0 | sblock->dblk_npages = sblock->dblk_nelmts / hdr->dblk_page_nelmts; |
128 | | |
129 | | /* Sanity check that we have at least 2 pages in data block */ |
130 | 0 | assert(sblock->dblk_npages > 1); |
131 | | |
132 | | /* Sanity check for integer truncation */ |
133 | 0 | assert((sblock->dblk_npages * hdr->dblk_page_nelmts) == sblock->dblk_nelmts); |
134 | | |
135 | | /* Compute size of buffer for each data block's 'page init' bitmask */ |
136 | 0 | sblock->dblk_page_init_size = ((sblock->dblk_npages) + 7) / 8; |
137 | 0 | assert(sblock->dblk_page_init_size > 0); |
138 | | |
139 | | /* Allocate buffer for all 'page init' bitmasks in super block */ |
140 | 0 | if (NULL == |
141 | 0 | (sblock->page_init = H5FL_BLK_CALLOC(page_init, sblock->ndblks * sblock->dblk_page_init_size))) |
142 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, NULL, |
143 | 0 | "memory allocation failed for super block page init bitmask"); |
144 | | |
145 | | /* Compute data block page size */ |
146 | 0 | sblock->dblk_page_size = (hdr->dblk_page_nelmts * hdr->cparam.raw_elmt_size) + H5EA_SIZEOF_CHKSUM; |
147 | 0 | } /* end if */ |
148 | | |
149 | | /* Set the return value */ |
150 | 0 | ret_value = sblock; |
151 | |
|
152 | 0 | done: |
153 | 0 | if (!ret_value) |
154 | 0 | if (sblock && H5EA__sblock_dest(sblock) < 0) |
155 | 0 | HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, NULL, "unable to destroy extensible array super block"); |
156 | |
|
157 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
158 | 0 | } /* end H5EA__sblock_alloc() */ |
159 | | |
160 | | /*------------------------------------------------------------------------- |
161 | | * Function: H5EA__sblock_create |
162 | | * |
163 | | * Purpose: Creates a new extensible array super block in the file |
164 | | * |
165 | | * Return: Valid file address on success/HADDR_UNDEF on failure |
166 | | * |
167 | | *------------------------------------------------------------------------- |
168 | | */ |
169 | | haddr_t |
170 | | H5EA__sblock_create(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, bool *stats_changed, unsigned sblk_idx) |
171 | 0 | { |
172 | 0 | H5EA_sblock_t *sblock = NULL; /* Extensible array super block */ |
173 | 0 | haddr_t sblock_addr; /* Extensible array super block address */ |
174 | 0 | haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill data block addresses with */ |
175 | 0 | bool inserted = false; /* Whether the header was inserted into cache */ |
176 | 0 | haddr_t ret_value = HADDR_UNDEF; |
177 | |
|
178 | 0 | FUNC_ENTER_PACKAGE |
179 | | |
180 | | /* Sanity check */ |
181 | 0 | assert(hdr); |
182 | 0 | assert(stats_changed); |
183 | | |
184 | | /* Allocate the super block */ |
185 | 0 | if (NULL == (sblock = H5EA__sblock_alloc(hdr, parent, sblk_idx))) |
186 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, HADDR_UNDEF, |
187 | 0 | "memory allocation failed for extensible array super block"); |
188 | | |
189 | | /* Set size of super block on disk */ |
190 | 0 | sblock->size = H5EA_SBLOCK_SIZE(sblock); |
191 | | |
192 | | /* Set offset of block in array's address space */ |
193 | 0 | sblock->block_off = hdr->sblk_info[sblk_idx].start_idx; |
194 | | |
195 | | /* Allocate space for the super block on disk */ |
196 | 0 | if (HADDR_UNDEF == (sblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_SBLOCK, (hsize_t)sblock->size))) |
197 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTALLOC, HADDR_UNDEF, |
198 | 0 | "file allocation failed for extensible array super block"); |
199 | 0 | sblock->addr = sblock_addr; |
200 | | |
201 | | /* Reset data block addresses to "undefined" address value */ |
202 | 0 | H5VM_array_fill(sblock->dblk_addrs, &tmp_addr, sizeof(haddr_t), sblock->ndblks); |
203 | | |
204 | | /* Cache the new extensible array super block */ |
205 | 0 | if (H5AC_insert_entry(hdr->f, H5AC_EARRAY_SBLOCK, sblock_addr, sblock, H5AC__NO_FLAGS_SET) < 0) |
206 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTINSERT, HADDR_UNDEF, |
207 | 0 | "can't add extensible array super block to cache"); |
208 | 0 | inserted = true; |
209 | | |
210 | | /* Add super block as child of 'top' proxy */ |
211 | 0 | if (hdr->top_proxy) { |
212 | 0 | if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, sblock) < 0) |
213 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, HADDR_UNDEF, |
214 | 0 | "unable to add extensible array entry as child of array proxy"); |
215 | 0 | sblock->top_proxy = hdr->top_proxy; |
216 | 0 | } /* end if */ |
217 | | |
218 | | /* Update extensible array super block statistics */ |
219 | 0 | hdr->stats.stored.nsuper_blks++; |
220 | 0 | hdr->stats.stored.super_blk_size += sblock->size; |
221 | | |
222 | | /* Mark the statistics as changed */ |
223 | 0 | *stats_changed = true; |
224 | | |
225 | | /* Set address of super block to return */ |
226 | 0 | ret_value = sblock_addr; |
227 | |
|
228 | 0 | done: |
229 | 0 | if (!H5_addr_defined(ret_value)) |
230 | 0 | if (sblock) { |
231 | | /* Remove from cache, if inserted */ |
232 | 0 | if (inserted) |
233 | 0 | if (H5AC_remove_entry(sblock) < 0) |
234 | 0 | HDONE_ERROR(H5E_EARRAY, H5E_CANTREMOVE, HADDR_UNDEF, |
235 | 0 | "unable to remove extensible array super block from cache"); |
236 | | |
237 | | /* Release super block's disk space */ |
238 | 0 | if (H5_addr_defined(sblock->addr) && |
239 | 0 | H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_SBLOCK, sblock->addr, (hsize_t)sblock->size) < 0) |
240 | 0 | HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, HADDR_UNDEF, |
241 | 0 | "unable to release extensible array super block"); |
242 | | |
243 | | /* Destroy super block */ |
244 | 0 | if (H5EA__sblock_dest(sblock) < 0) |
245 | 0 | HDONE_ERROR(H5E_EARRAY, H5E_CANTFREE, HADDR_UNDEF, |
246 | 0 | "unable to destroy extensible array super block"); |
247 | 0 | } /* end if */ |
248 | |
|
249 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
250 | 0 | } /* end H5EA__sblock_create() */ |
251 | | |
252 | | /*------------------------------------------------------------------------- |
253 | | * Function: H5EA__sblock_protect |
254 | | * |
255 | | * Purpose: Convenience wrapper around protecting extensible array super block |
256 | | * |
257 | | * Return: Non-NULL pointer to data block on success/NULL on failure |
258 | | * |
259 | | *------------------------------------------------------------------------- |
260 | | */ |
261 | | H5EA_sblock_t * |
262 | | H5EA__sblock_protect(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, haddr_t sblk_addr, unsigned sblk_idx, |
263 | | unsigned flags) |
264 | 0 | { |
265 | 0 | H5EA_sblock_t *sblock = NULL; /* Pointer to super block */ |
266 | 0 | H5EA_sblock_cache_ud_t udata; /* Information needed for loading super block */ |
267 | 0 | H5EA_sblock_t *ret_value = NULL; |
268 | |
|
269 | 0 | FUNC_ENTER_PACKAGE |
270 | | |
271 | | /* Sanity check */ |
272 | 0 | assert(hdr); |
273 | 0 | assert(H5_addr_defined(sblk_addr)); |
274 | | |
275 | | /* only the H5AC__READ_ONLY_FLAG may be set */ |
276 | 0 | assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); |
277 | | |
278 | | /* Set up user data */ |
279 | 0 | udata.hdr = hdr; |
280 | 0 | udata.parent = parent; |
281 | 0 | udata.sblk_idx = sblk_idx; |
282 | 0 | udata.sblk_addr = sblk_addr; |
283 | | |
284 | | /* Protect the super block */ |
285 | 0 | if (NULL == |
286 | 0 | (sblock = (H5EA_sblock_t *)H5AC_protect(hdr->f, H5AC_EARRAY_SBLOCK, sblk_addr, &udata, flags))) |
287 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, NULL, |
288 | 0 | "unable to protect extensible array super block, address = %llu", |
289 | 0 | (unsigned long long)sblk_addr); |
290 | | |
291 | | /* Create top proxy, if it doesn't exist */ |
292 | 0 | if (hdr->top_proxy && NULL == sblock->top_proxy) { |
293 | | /* Add super block as child of 'top' proxy */ |
294 | 0 | if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, sblock) < 0) |
295 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTSET, NULL, |
296 | 0 | "unable to add extensible array entry as child of array proxy"); |
297 | 0 | sblock->top_proxy = hdr->top_proxy; |
298 | 0 | } |
299 | | |
300 | | /* Set return value */ |
301 | 0 | ret_value = sblock; |
302 | |
|
303 | 0 | done: |
304 | | /* Clean up on error */ |
305 | 0 | if (!ret_value) { |
306 | | /* Release the super block, if it was protected */ |
307 | 0 | if (sblock && |
308 | 0 | H5AC_unprotect(hdr->f, H5AC_EARRAY_SBLOCK, sblock->addr, sblock, H5AC__NO_FLAGS_SET) < 0) |
309 | 0 | HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, NULL, |
310 | 0 | "unable to unprotect extensible array super block, address = %llu", |
311 | 0 | (unsigned long long)sblock->addr); |
312 | 0 | } |
313 | |
|
314 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
315 | 0 | } /* end H5EA__sblock_protect() */ |
316 | | |
317 | | /*------------------------------------------------------------------------- |
318 | | * Function: H5EA__sblock_unprotect |
319 | | * |
320 | | * Purpose: Convenience wrapper around unprotecting extensible array super block |
321 | | * |
322 | | * Return: Non-negative on success/Negative on failure |
323 | | * |
324 | | *------------------------------------------------------------------------- |
325 | | */ |
326 | | herr_t |
327 | | H5EA__sblock_unprotect(H5EA_sblock_t *sblock, unsigned cache_flags) |
328 | 0 | { |
329 | 0 | herr_t ret_value = SUCCEED; |
330 | |
|
331 | 0 | FUNC_ENTER_PACKAGE |
332 | | |
333 | | /* Sanity check */ |
334 | 0 | assert(sblock); |
335 | | |
336 | | /* Unprotect the super block */ |
337 | 0 | if (H5AC_unprotect(sblock->hdr->f, H5AC_EARRAY_SBLOCK, sblock->addr, sblock, cache_flags) < 0) |
338 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, |
339 | 0 | "unable to unprotect extensible array super block, address = %llu", |
340 | 0 | (unsigned long long)sblock->addr); |
341 | | |
342 | 0 | done: |
343 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
344 | 0 | } /* end H5EA__sblock_unprotect() */ |
345 | | |
346 | | /*------------------------------------------------------------------------- |
347 | | * Function: H5EA__sblock_delete |
348 | | * |
349 | | * Purpose: Delete a super block |
350 | | * |
351 | | * Return: SUCCEED/FAIL |
352 | | * |
353 | | *------------------------------------------------------------------------- |
354 | | */ |
355 | | herr_t |
356 | | H5EA__sblock_delete(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, haddr_t sblk_addr, unsigned sblk_idx) |
357 | 0 | { |
358 | 0 | H5EA_sblock_t *sblock = NULL; /* Pointer to super block */ |
359 | 0 | size_t u; /* Local index variable */ |
360 | 0 | herr_t ret_value = SUCCEED; |
361 | |
|
362 | 0 | FUNC_ENTER_PACKAGE |
363 | | |
364 | | /* Sanity check */ |
365 | 0 | assert(hdr); |
366 | 0 | assert(H5_addr_defined(sblk_addr)); |
367 | | |
368 | | /* Protect super block */ |
369 | 0 | if (NULL == (sblock = H5EA__sblock_protect(hdr, parent, sblk_addr, sblk_idx, H5AC__NO_FLAGS_SET))) |
370 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTPROTECT, FAIL, |
371 | 0 | "unable to protect extensible array super block, address = %llu", |
372 | 0 | (unsigned long long)sblk_addr); |
373 | | |
374 | | /* Iterate over data blocks */ |
375 | 0 | for (u = 0; u < sblock->ndblks; u++) { |
376 | | /* Check for data block existing */ |
377 | 0 | if (H5_addr_defined(sblock->dblk_addrs[u])) { |
378 | | /* Delete data block */ |
379 | 0 | if (H5EA__dblock_delete(hdr, sblock, sblock->dblk_addrs[u], sblock->dblk_nelmts) < 0) |
380 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTDELETE, FAIL, "unable to delete extensible array data block"); |
381 | 0 | sblock->dblk_addrs[u] = HADDR_UNDEF; |
382 | 0 | } /* end if */ |
383 | 0 | } /* end for */ |
384 | | |
385 | 0 | done: |
386 | | /* Finished deleting super block in metadata cache */ |
387 | 0 | if (sblock && H5EA__sblock_unprotect(sblock, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | |
388 | 0 | H5AC__FREE_FILE_SPACE_FLAG) < 0) |
389 | 0 | HDONE_ERROR(H5E_EARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release extensible array super block"); |
390 | |
|
391 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
392 | 0 | } /* end H5EA__sblock_delete() */ |
393 | | |
394 | | /*------------------------------------------------------------------------- |
395 | | * Function: H5EA__sblock_dest |
396 | | * |
397 | | * Purpose: Destroys an extensible array super block in memory. |
398 | | * |
399 | | * Return: Non-negative on success/Negative on failure |
400 | | * |
401 | | *------------------------------------------------------------------------- |
402 | | */ |
403 | | herr_t |
404 | | H5EA__sblock_dest(H5EA_sblock_t *sblock) |
405 | 0 | { |
406 | 0 | herr_t ret_value = SUCCEED; |
407 | |
|
408 | 0 | FUNC_ENTER_PACKAGE |
409 | | |
410 | | /* Sanity check */ |
411 | 0 | assert(sblock); |
412 | 0 | assert(!sblock->has_hdr_depend); |
413 | | |
414 | | /* Check if shared header field has been initialized */ |
415 | 0 | if (sblock->hdr) { |
416 | | /* Free buffer for super block data block addresses, if there are any */ |
417 | 0 | if (sblock->dblk_addrs) |
418 | 0 | sblock->dblk_addrs = H5FL_SEQ_FREE(haddr_t, sblock->dblk_addrs); |
419 | | |
420 | | /* Free buffer for super block 'page init' bitmask, if there is one */ |
421 | 0 | if (sblock->page_init) { |
422 | 0 | assert(sblock->dblk_npages > 0); |
423 | 0 | sblock->page_init = H5FL_BLK_FREE(page_init, sblock->page_init); |
424 | 0 | } /* end if */ |
425 | | |
426 | | /* Decrement reference count on shared info */ |
427 | 0 | if (H5EA__hdr_decr(sblock->hdr) < 0) |
428 | 0 | HGOTO_ERROR(H5E_EARRAY, H5E_CANTDEC, FAIL, |
429 | 0 | "can't decrement reference count on shared array header"); |
430 | 0 | sblock->hdr = NULL; |
431 | 0 | } /* end if */ |
432 | | |
433 | | /* Sanity check */ |
434 | 0 | assert(NULL == sblock->top_proxy); |
435 | | |
436 | | /* Free the super block itself */ |
437 | 0 | sblock = H5FL_FREE(H5EA_sblock_t, sblock); |
438 | |
|
439 | 0 | done: |
440 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
441 | 0 | } /* end H5EA__sblock_dest() */ |