/src/hdf5/src/H5FAdblock.c
Line | Count | Source (jump to first uncovered line) |
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 COPYING 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: H5FAdblock.c |
16 | | * |
17 | | * Purpose: Data block routines for fixed arrays. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /**********************/ |
23 | | /* Module Declaration */ |
24 | | /**********************/ |
25 | | |
26 | | #include "H5FAmodule.h" /* This source code file is part of the H5FA 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 "H5FApkg.h" /* Fixed Arrays */ |
38 | | #include "H5FLprivate.h" /* Free Lists */ |
39 | | #include "H5MFprivate.h" /* File memory management */ |
40 | | |
41 | | /****************/ |
42 | | /* Local Macros */ |
43 | | /****************/ |
44 | | |
45 | | /******************/ |
46 | | /* Local Typedefs */ |
47 | | /******************/ |
48 | | |
49 | | /********************/ |
50 | | /* Package Typedefs */ |
51 | | /********************/ |
52 | | |
53 | | /********************/ |
54 | | /* Local Prototypes */ |
55 | | /********************/ |
56 | | |
57 | | /*********************/ |
58 | | /* Package Variables */ |
59 | | /*********************/ |
60 | | |
61 | | /*****************************/ |
62 | | /* Library Private Variables */ |
63 | | /*****************************/ |
64 | | |
65 | | /*******************/ |
66 | | /* Local Variables */ |
67 | | /*******************/ |
68 | | |
69 | | /* Declare a free list to manage the H5FA_dblock_t struct */ |
70 | | H5FL_DEFINE_STATIC(H5FA_dblock_t); |
71 | | |
72 | | /* Declare a free list to manage the chunk elements */ |
73 | | H5FL_BLK_DEFINE(chunk_elmts); |
74 | | |
75 | | /* Declare a free list to manage blocks of 'page init' bitmasks */ |
76 | | H5FL_BLK_DEFINE(fa_page_init); |
77 | | |
78 | | /*------------------------------------------------------------------------- |
79 | | * Function: H5FA__dblock_alloc |
80 | | * |
81 | | * Purpose: Allocate fixed array data block |
82 | | * |
83 | | * Return: Non-NULL pointer to data block on success/NULL on failure |
84 | | * |
85 | | *------------------------------------------------------------------------- |
86 | | */ |
87 | | H5FA_dblock_t * |
88 | | H5FA__dblock_alloc(H5FA_hdr_t *hdr) |
89 | 0 | { |
90 | 0 | H5FA_dblock_t *dblock = NULL; /* fixed array data block */ |
91 | 0 | H5FA_dblock_t *ret_value = NULL; |
92 | |
|
93 | 0 | FUNC_ENTER_PACKAGE |
94 | | |
95 | | /* Check arguments */ |
96 | 0 | assert(hdr); |
97 | 0 | assert(hdr->cparam.nelmts > 0); |
98 | | |
99 | | /* Allocate memory for the data block */ |
100 | 0 | if (NULL == (dblock = H5FL_CALLOC(H5FA_dblock_t))) |
101 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTALLOC, NULL, "memory allocation failed for fixed array data block"); |
102 | | |
103 | | /* Share common array information */ |
104 | 0 | if (H5FA__hdr_incr(hdr) < 0) |
105 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTINC, NULL, "can't increment reference count on shared array header"); |
106 | 0 | dblock->hdr = hdr; |
107 | | |
108 | | /* Set non-zero internal fields */ |
109 | 0 | dblock->dblk_page_nelmts = (size_t)1 << hdr->cparam.max_dblk_page_nelmts_bits; |
110 | | |
111 | | /* Check if this data block should be paged */ |
112 | 0 | if (hdr->cparam.nelmts > dblock->dblk_page_nelmts) { |
113 | | /* Compute number of pages */ |
114 | 0 | hsize_t npages = ((hdr->cparam.nelmts + dblock->dblk_page_nelmts) - 1) / dblock->dblk_page_nelmts; |
115 | | |
116 | | /* Safely assign the number of pages */ |
117 | 0 | H5_CHECKED_ASSIGN(dblock->npages, size_t, npages, hsize_t); |
118 | | |
119 | | /* Sanity check that we have at least 1 page */ |
120 | 0 | assert(dblock->npages > 0); |
121 | | |
122 | | /* Compute size of 'page init' flag array, in bytes */ |
123 | 0 | dblock->dblk_page_init_size = (dblock->npages + 7) / 8; |
124 | 0 | assert(dblock->dblk_page_init_size > 0); |
125 | | |
126 | | /* Allocate space for 'page init' flags */ |
127 | 0 | if (NULL == (dblock->dblk_page_init = H5FL_BLK_CALLOC(fa_page_init, dblock->dblk_page_init_size))) |
128 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTALLOC, NULL, "memory allocation failed for page init bitmask"); |
129 | | |
130 | | /* Compute data block page size */ |
131 | 0 | dblock->dblk_page_size = (dblock->dblk_page_nelmts * hdr->cparam.raw_elmt_size) + H5FA_SIZEOF_CHKSUM; |
132 | | |
133 | | /* Compute the # of elements on last page */ |
134 | 0 | if (0 == hdr->cparam.nelmts % dblock->dblk_page_nelmts) |
135 | 0 | dblock->last_page_nelmts = dblock->dblk_page_nelmts; |
136 | 0 | else |
137 | 0 | dblock->last_page_nelmts = (size_t)(hdr->cparam.nelmts % dblock->dblk_page_nelmts); |
138 | 0 | } /* end if */ |
139 | 0 | else { |
140 | 0 | hsize_t dblk_size = hdr->cparam.nelmts * hdr->cparam.cls->nat_elmt_size; |
141 | | |
142 | | /* Allocate buffer for elements in data block */ |
143 | 0 | H5_CHECK_OVERFLOW(dblk_size, /* From: */ hsize_t, /* To: */ size_t); |
144 | 0 | if (NULL == (dblock->elmts = H5FL_BLK_MALLOC(chunk_elmts, (size_t)dblk_size))) |
145 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTALLOC, NULL, |
146 | 0 | "memory allocation failed for data block element buffer"); |
147 | 0 | } /* end else */ |
148 | | |
149 | | /* Set the return value */ |
150 | 0 | ret_value = dblock; |
151 | |
|
152 | 0 | done: |
153 | 0 | if (!ret_value) |
154 | 0 | if (dblock && H5FA__dblock_dest(dblock) < 0) |
155 | 0 | HDONE_ERROR(H5E_FARRAY, H5E_CANTFREE, NULL, "unable to destroy fixed array data block"); |
156 | |
|
157 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
158 | 0 | } /* end H5FA__dblock_alloc() */ |
159 | | |
160 | | /*------------------------------------------------------------------------- |
161 | | * Function: H5FA__dblock_create |
162 | | * |
163 | | * Purpose: Creates a fixed array data block in the file |
164 | | * |
165 | | * Return: Valid file address on success/HADDR_UNDEF on failure |
166 | | * |
167 | | *------------------------------------------------------------------------- |
168 | | */ |
169 | | haddr_t |
170 | | H5FA__dblock_create(H5FA_hdr_t *hdr, bool *hdr_dirty) |
171 | 0 | { |
172 | 0 | H5FA_dblock_t *dblock = NULL; /* Fixed array data block */ |
173 | 0 | haddr_t dblock_addr; /* Fixed array data block address */ |
174 | 0 | bool inserted = false; /* Whether the header was inserted into cache */ |
175 | 0 | haddr_t ret_value = HADDR_UNDEF; |
176 | |
|
177 | 0 | FUNC_ENTER_PACKAGE |
178 | | |
179 | | /* Sanity check */ |
180 | 0 | assert(hdr); |
181 | 0 | assert(hdr_dirty); |
182 | | |
183 | | /* Allocate the data block */ |
184 | 0 | if (NULL == (dblock = H5FA__dblock_alloc(hdr))) |
185 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTALLOC, HADDR_UNDEF, |
186 | 0 | "memory allocation failed for fixed array data block"); |
187 | | |
188 | | /* Set size of data block on disk */ |
189 | 0 | hdr->stats.dblk_size = dblock->size = H5FA_DBLOCK_SIZE(dblock); |
190 | | |
191 | | /* Allocate space for the data block on disk */ |
192 | 0 | if (HADDR_UNDEF == (dblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_FARRAY_DBLOCK, (hsize_t)dblock->size))) |
193 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTALLOC, HADDR_UNDEF, |
194 | 0 | "file allocation failed for fixed array data block"); |
195 | 0 | dblock->addr = dblock_addr; |
196 | | |
197 | | /* Don't initialize elements if paged */ |
198 | 0 | if (!dblock->npages) |
199 | | /* Clear any elements in data block to fill value */ |
200 | 0 | if ((hdr->cparam.cls->fill)(dblock->elmts, (size_t)hdr->cparam.nelmts) < 0) |
201 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTSET, HADDR_UNDEF, |
202 | 0 | "can't set fixed array data block elements to class's fill value"); |
203 | | |
204 | | /* Cache the new fixed array data block */ |
205 | 0 | if (H5AC_insert_entry(hdr->f, H5AC_FARRAY_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0) |
206 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTINSERT, HADDR_UNDEF, "can't add fixed array data block to cache"); |
207 | 0 | inserted = true; |
208 | | |
209 | | /* Add data block as child of 'top' proxy */ |
210 | 0 | if (hdr->top_proxy) { |
211 | 0 | if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dblock) < 0) |
212 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTSET, HADDR_UNDEF, |
213 | 0 | "unable to add fixed array entry as child of array proxy"); |
214 | 0 | dblock->top_proxy = hdr->top_proxy; |
215 | 0 | } /* end if */ |
216 | | |
217 | | /* Mark the header dirty (for updating statistics) */ |
218 | 0 | *hdr_dirty = true; |
219 | | |
220 | | /* Set address of data block to return */ |
221 | 0 | ret_value = dblock_addr; |
222 | |
|
223 | 0 | done: |
224 | |
|
225 | 0 | if (!H5_addr_defined(ret_value)) |
226 | 0 | if (dblock) { |
227 | | /* Remove from cache, if inserted */ |
228 | 0 | if (inserted) |
229 | 0 | if (H5AC_remove_entry(dblock) < 0) |
230 | 0 | HDONE_ERROR(H5E_FARRAY, H5E_CANTREMOVE, HADDR_UNDEF, |
231 | 0 | "unable to remove fixed array data block from cache"); |
232 | | |
233 | | /* Release data block's disk space */ |
234 | 0 | if (H5_addr_defined(dblock->addr) && |
235 | 0 | H5MF_xfree(hdr->f, H5FD_MEM_FARRAY_DBLOCK, dblock->addr, (hsize_t)dblock->size) < 0) |
236 | 0 | HDONE_ERROR(H5E_FARRAY, H5E_CANTFREE, HADDR_UNDEF, |
237 | 0 | "unable to release fixed array data block"); |
238 | | |
239 | | /* Destroy data block */ |
240 | 0 | if (H5FA__dblock_dest(dblock) < 0) |
241 | 0 | HDONE_ERROR(H5E_FARRAY, H5E_CANTFREE, HADDR_UNDEF, |
242 | 0 | "unable to destroy fixed array data block"); |
243 | 0 | } /* end if */ |
244 | |
|
245 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
246 | 0 | } /* end H5FA__dblock_create() */ |
247 | | |
248 | | /*------------------------------------------------------------------------- |
249 | | * Function: H5FA__dblock_protect |
250 | | * |
251 | | * Purpose: Convenience wrapper around protecting fixed array data block |
252 | | * |
253 | | * Return: Non-NULL pointer to data block on success/NULL on failure |
254 | | * |
255 | | *------------------------------------------------------------------------- |
256 | | */ |
257 | | H5FA_dblock_t * |
258 | | H5FA__dblock_protect(H5FA_hdr_t *hdr, haddr_t dblk_addr, unsigned flags) |
259 | 0 | { |
260 | 0 | H5FA_dblock_t *dblock = NULL; /* Fixed array data block */ |
261 | 0 | H5FA_dblock_cache_ud_t udata; /* Information needed for loading data block */ |
262 | 0 | H5FA_dblock_t *ret_value = NULL; |
263 | |
|
264 | 0 | FUNC_ENTER_PACKAGE |
265 | | |
266 | | /* Sanity check */ |
267 | 0 | assert(hdr); |
268 | 0 | assert(H5_addr_defined(dblk_addr)); |
269 | | |
270 | | /* only the H5AC__READ_ONLY_FLAG flag is permitted */ |
271 | 0 | assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); |
272 | | |
273 | | /* Set up user data */ |
274 | 0 | udata.hdr = hdr; |
275 | 0 | udata.dblk_addr = dblk_addr; |
276 | | |
277 | | /* Protect the data block */ |
278 | 0 | if (NULL == |
279 | 0 | (dblock = (H5FA_dblock_t *)H5AC_protect(hdr->f, H5AC_FARRAY_DBLOCK, dblk_addr, &udata, flags))) |
280 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTPROTECT, NULL, |
281 | 0 | "unable to protect fixed array data block, address = %llu", |
282 | 0 | (unsigned long long)dblk_addr); |
283 | | |
284 | | /* Create top proxy, if it doesn't exist */ |
285 | 0 | if (hdr->top_proxy && NULL == dblock->top_proxy) { |
286 | | /* Add data block as child of 'top' proxy */ |
287 | 0 | if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dblock) < 0) |
288 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTSET, NULL, |
289 | 0 | "unable to add fixed array entry as child of array proxy"); |
290 | 0 | dblock->top_proxy = hdr->top_proxy; |
291 | 0 | } /* end if */ |
292 | | |
293 | | /* Set return value */ |
294 | 0 | ret_value = dblock; |
295 | |
|
296 | 0 | done: |
297 | | /* Clean up on error */ |
298 | 0 | if (!ret_value) |
299 | | /* Release the data block, if it was protected */ |
300 | 0 | if (dblock && |
301 | 0 | H5AC_unprotect(hdr->f, H5AC_FARRAY_DBLOCK, dblock->addr, dblock, H5AC__NO_FLAGS_SET) < 0) |
302 | 0 | HDONE_ERROR(H5E_FARRAY, H5E_CANTUNPROTECT, NULL, |
303 | 0 | "unable to unprotect fixed array data block, address = %llu", |
304 | 0 | (unsigned long long)dblock->addr) |
305 | |
|
306 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
307 | 0 | } /* end H5FA__dblock_protect() */ |
308 | | |
309 | | /*------------------------------------------------------------------------- |
310 | | * Function: H5FA__dblock_unprotect |
311 | | * |
312 | | * Purpose: Convenience wrapper around unprotecting fixed array data block |
313 | | * |
314 | | * Return: SUCCEED/FAIL |
315 | | * |
316 | | *------------------------------------------------------------------------- |
317 | | */ |
318 | | herr_t |
319 | | H5FA__dblock_unprotect(H5FA_dblock_t *dblock, unsigned cache_flags) |
320 | 0 | { |
321 | 0 | herr_t ret_value = SUCCEED; |
322 | |
|
323 | 0 | FUNC_ENTER_PACKAGE |
324 | | |
325 | | /* Sanity check */ |
326 | 0 | assert(dblock); |
327 | | |
328 | | /* Unprotect the data block */ |
329 | 0 | if (H5AC_unprotect(dblock->hdr->f, H5AC_FARRAY_DBLOCK, dblock->addr, dblock, cache_flags) < 0) |
330 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTUNPROTECT, FAIL, |
331 | 0 | "unable to unprotect fixed array data block, address = %llu", |
332 | 0 | (unsigned long long)dblock->addr); |
333 | | |
334 | 0 | done: |
335 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
336 | 0 | } /* end H5FA__dblock_unprotect() */ |
337 | | |
338 | | /*------------------------------------------------------------------------- |
339 | | * Function: H5FA__dblock_delete |
340 | | * |
341 | | * Purpose: Delete a data block |
342 | | * |
343 | | * Return: SUCCEED/FAIL |
344 | | * |
345 | | *------------------------------------------------------------------------- |
346 | | */ |
347 | | herr_t |
348 | | H5FA__dblock_delete(H5FA_hdr_t *hdr, haddr_t dblk_addr) |
349 | 0 | { |
350 | 0 | H5FA_dblock_t *dblock = NULL; /* Pointer to data block */ |
351 | 0 | herr_t ret_value = SUCCEED; |
352 | |
|
353 | 0 | FUNC_ENTER_PACKAGE |
354 | | |
355 | | /* Sanity check */ |
356 | 0 | assert(hdr); |
357 | 0 | assert(H5_addr_defined(dblk_addr)); |
358 | | |
359 | | /* Protect data block */ |
360 | 0 | if (NULL == (dblock = H5FA__dblock_protect(hdr, dblk_addr, H5AC__NO_FLAGS_SET))) |
361 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTPROTECT, FAIL, |
362 | 0 | "unable to protect fixed array data block, address = %llu", |
363 | 0 | (unsigned long long)dblk_addr); |
364 | | |
365 | | /* Check if data block is paged */ |
366 | 0 | if (dblock->npages) { |
367 | 0 | haddr_t dblk_page_addr; /* Address of each data block page */ |
368 | 0 | size_t u; /* Local index variable */ |
369 | | |
370 | | /* Set up initial state */ |
371 | 0 | dblk_page_addr = dblk_addr + H5FA_DBLOCK_PREFIX_SIZE(dblock); |
372 | | |
373 | | /* Iterate over pages in data block */ |
374 | 0 | for (u = 0; u < dblock->npages; u++) { |
375 | | /* Evict the data block page from the metadata cache */ |
376 | | /* (OK to call if it doesn't exist in the cache) */ |
377 | 0 | if (H5AC_expunge_entry(hdr->f, H5AC_FARRAY_DBLK_PAGE, dblk_page_addr, H5AC__NO_FLAGS_SET) < 0) |
378 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTEXPUNGE, FAIL, |
379 | 0 | "unable to remove array data block page from metadata cache"); |
380 | | |
381 | | /* Advance to next page address */ |
382 | 0 | dblk_page_addr += dblock->dblk_page_size; |
383 | 0 | } /* end for */ |
384 | 0 | } /* end if */ |
385 | | |
386 | 0 | done: |
387 | | /* Finished deleting data block in metadata cache */ |
388 | 0 | if (dblock && H5FA__dblock_unprotect(dblock, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | |
389 | 0 | H5AC__FREE_FILE_SPACE_FLAG) < 0) |
390 | 0 | HDONE_ERROR(H5E_FARRAY, H5E_CANTUNPROTECT, FAIL, "unable to release fixed array data block"); |
391 | |
|
392 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
393 | 0 | } /* end H5FA__dblock_delete() */ |
394 | | |
395 | | /*------------------------------------------------------------------------- |
396 | | * Function: H5FA__dblock_dest |
397 | | * |
398 | | * Purpose: Destroys a fixed array data block in memory. |
399 | | * |
400 | | * Return: SUCCEED/FAIL |
401 | | * |
402 | | *------------------------------------------------------------------------- |
403 | | */ |
404 | | herr_t |
405 | | H5FA__dblock_dest(H5FA_dblock_t *dblock) |
406 | 0 | { |
407 | 0 | herr_t ret_value = SUCCEED; |
408 | |
|
409 | 0 | FUNC_ENTER_PACKAGE |
410 | | |
411 | | /* Sanity check */ |
412 | 0 | assert(dblock); |
413 | | |
414 | | /* Check if shared header field has been initialized */ |
415 | 0 | if (dblock->hdr) { |
416 | | /* Check if we've got elements in the data block */ |
417 | 0 | if (dblock->elmts && !dblock->npages) { |
418 | | /* Free buffer for data block elements */ |
419 | 0 | assert(dblock->hdr->cparam.nelmts > 0); |
420 | 0 | dblock->elmts = H5FL_BLK_FREE(chunk_elmts, dblock->elmts); |
421 | 0 | } /* end if */ |
422 | | |
423 | | /* Check if data block is paged */ |
424 | 0 | if (dblock->npages) { |
425 | | /* Free buffer for 'page init' bitmask, if there is one */ |
426 | 0 | assert(dblock->dblk_page_init_size > 0); |
427 | 0 | if (dblock->dblk_page_init) |
428 | 0 | dblock->dblk_page_init = H5FL_BLK_FREE(fa_page_init, dblock->dblk_page_init); |
429 | 0 | } /* end if */ |
430 | | |
431 | | /* Decrement reference count on shared info */ |
432 | 0 | if (H5FA__hdr_decr(dblock->hdr) < 0) |
433 | 0 | HGOTO_ERROR(H5E_FARRAY, H5E_CANTDEC, FAIL, |
434 | 0 | "can't decrement reference count on shared array header"); |
435 | 0 | dblock->hdr = NULL; |
436 | 0 | } /* end if */ |
437 | | |
438 | | /* Sanity check */ |
439 | 0 | assert(NULL == dblock->top_proxy); |
440 | | |
441 | | /* Free the data block itself */ |
442 | 0 | dblock = H5FL_FREE(H5FA_dblock_t, dblock); |
443 | |
|
444 | 0 | done: |
445 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
446 | 0 | } /* end H5FA__dblock_dest() */ |