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: H5HFhdr.c |
16 | | * |
17 | | * Purpose: Heap header routines for fractal heaps. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #include "H5HFmodule.h" /* This source code file is part of the H5HF module */ |
27 | | |
28 | | /***********/ |
29 | | /* Headers */ |
30 | | /***********/ |
31 | | #include "H5private.h" /* Generic Functions */ |
32 | | #include "H5Eprivate.h" /* Error handling */ |
33 | | #include "H5FLprivate.h" /* Free Lists */ |
34 | | #include "H5HFpkg.h" /* Fractal heaps */ |
35 | | #include "H5MFprivate.h" /* File memory management */ |
36 | | #include "H5MMprivate.h" /* Memory management */ |
37 | | #include "H5VMprivate.h" /* Vectors and arrays */ |
38 | | |
39 | | /****************/ |
40 | | /* Local Macros */ |
41 | | /****************/ |
42 | | |
43 | | #ifndef NDEBUG |
44 | | /* Limit on the size of the max. direct block size */ |
45 | | /* (This is limited to 32-bits currently, because I think it's unlikely to |
46 | | * need to be larger, the 32-bit limit for H5VM_log2_of2(n), and |
47 | | * some offsets/sizes are encoded with a maximum of 32-bits - QAK) |
48 | | */ |
49 | | #define H5HF_MAX_DIRECT_SIZE_LIMIT ((hsize_t)2 * 1024 * 1024 * 1024) |
50 | | |
51 | | /* Limit on the width of the doubling table */ |
52 | | /* (This is limited to 16-bits currently, because I think it's unlikely to |
53 | | * need to be larger, and its encoded with a maximum of 16-bits - QAK) |
54 | | */ |
55 | | #define H5HF_WIDTH_LIMIT (64 * 1024) |
56 | | #endif /* NDEBUG */ |
57 | | |
58 | | /******************/ |
59 | | /* Local Typedefs */ |
60 | | /******************/ |
61 | | |
62 | | /********************/ |
63 | | /* Package Typedefs */ |
64 | | /********************/ |
65 | | |
66 | | /********************/ |
67 | | /* Local Prototypes */ |
68 | | /********************/ |
69 | | |
70 | | /*********************/ |
71 | | /* Package Variables */ |
72 | | /*********************/ |
73 | | |
74 | | /* Declare a free list to manage the H5HF_hdr_t struct */ |
75 | | H5FL_DEFINE_STATIC(H5HF_hdr_t); |
76 | | |
77 | | /*****************************/ |
78 | | /* Library Private Variables */ |
79 | | /*****************************/ |
80 | | |
81 | | /*******************/ |
82 | | /* Local Variables */ |
83 | | /*******************/ |
84 | | |
85 | | /*------------------------------------------------------------------------- |
86 | | * Function: H5HF__hdr_alloc |
87 | | * |
88 | | * Purpose: Allocate shared fractal heap header |
89 | | * |
90 | | * Return: Non-negative on success/Negative on failure |
91 | | * |
92 | | *------------------------------------------------------------------------- |
93 | | */ |
94 | | H5HF_hdr_t * |
95 | | H5HF__hdr_alloc(H5F_t *f) |
96 | 0 | { |
97 | 0 | H5HF_hdr_t *hdr = NULL; /* Shared fractal heap header */ |
98 | 0 | H5HF_hdr_t *ret_value = NULL; /* Return value */ |
99 | |
|
100 | 0 | FUNC_ENTER_PACKAGE |
101 | | |
102 | | /* |
103 | | * Check arguments. |
104 | | */ |
105 | 0 | assert(f); |
106 | | |
107 | | /* Allocate space for the shared information */ |
108 | 0 | if (NULL == (hdr = H5FL_CALLOC(H5HF_hdr_t))) |
109 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "allocation failed for fractal heap shared header"); |
110 | | |
111 | | /* Set the internal parameters for the heap */ |
112 | 0 | hdr->f = f; |
113 | 0 | hdr->sizeof_size = H5F_SIZEOF_SIZE(f); |
114 | 0 | hdr->sizeof_addr = H5F_SIZEOF_ADDR(f); |
115 | | |
116 | | /* Set the return value */ |
117 | 0 | ret_value = hdr; |
118 | |
|
119 | 0 | done: |
120 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
121 | 0 | } /* end H5HF__hdr_alloc() */ |
122 | | |
123 | | /*------------------------------------------------------------------------- |
124 | | * Function: H5HF_hdr_free_space |
125 | | * |
126 | | * Purpose: Compute direct block free space, for indirect blocks of |
127 | | * different sizes. |
128 | | * |
129 | | * Return: Non-negative on success/Negative on failure |
130 | | * |
131 | | *------------------------------------------------------------------------- |
132 | | */ |
133 | | static herr_t |
134 | | H5HF__hdr_compute_free_space(H5HF_hdr_t *hdr, unsigned iblock_row) |
135 | 0 | { |
136 | 0 | hsize_t acc_heap_size; /* Accumumated heap space */ |
137 | 0 | hsize_t iblock_size; /* Size of indirect block to calculate for */ |
138 | 0 | hsize_t acc_dblock_free; /* Accumumated direct block free space */ |
139 | 0 | size_t max_dblock_free; /* Max. direct block free space */ |
140 | 0 | unsigned curr_row; /* Current row in block */ |
141 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
142 | |
|
143 | 0 | FUNC_ENTER_PACKAGE_NOERR |
144 | | |
145 | | /* |
146 | | * Check arguments. |
147 | | */ |
148 | 0 | assert(hdr); |
149 | 0 | assert(iblock_row >= hdr->man_dtable.max_direct_rows); |
150 | | |
151 | | /* Set the free space in direct blocks */ |
152 | 0 | acc_heap_size = 0; |
153 | 0 | acc_dblock_free = 0; |
154 | 0 | max_dblock_free = 0; |
155 | 0 | iblock_size = hdr->man_dtable.row_block_size[iblock_row]; |
156 | 0 | curr_row = 0; |
157 | 0 | while (acc_heap_size < iblock_size) { |
158 | 0 | acc_heap_size += hdr->man_dtable.row_block_size[curr_row] * hdr->man_dtable.cparam.width; |
159 | 0 | acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[curr_row] * hdr->man_dtable.cparam.width; |
160 | 0 | if (hdr->man_dtable.row_max_dblock_free[curr_row] > max_dblock_free) |
161 | 0 | max_dblock_free = hdr->man_dtable.row_max_dblock_free[curr_row]; |
162 | 0 | curr_row++; |
163 | 0 | } /* end while */ |
164 | | |
165 | | /* Set direct block free space values for indirect block */ |
166 | 0 | hdr->man_dtable.row_tot_dblock_free[iblock_row] = acc_dblock_free; |
167 | 0 | hdr->man_dtable.row_max_dblock_free[iblock_row] = max_dblock_free; |
168 | |
|
169 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
170 | 0 | } /* end H5HF__hdr_compute_free_space() */ |
171 | | |
172 | | /*------------------------------------------------------------------------- |
173 | | * Function: H5HF__hdr_finish_init_phase1 |
174 | | * |
175 | | * Purpose: First phase to finish initializing info in shared heap header |
176 | | * |
177 | | * Return: Non-negative on success/Negative on failure |
178 | | * |
179 | | *------------------------------------------------------------------------- |
180 | | */ |
181 | | herr_t |
182 | | H5HF__hdr_finish_init_phase1(H5HF_hdr_t *hdr) |
183 | 0 | { |
184 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
185 | |
|
186 | 0 | FUNC_ENTER_PACKAGE |
187 | | |
188 | | /* |
189 | | * Check arguments. |
190 | | */ |
191 | 0 | assert(hdr); |
192 | | |
193 | | /* Compute/cache some values */ |
194 | 0 | hdr->heap_off_size = (uint8_t)H5HF_SIZEOF_OFFSET_BITS(hdr->man_dtable.cparam.max_index); |
195 | 0 | if (H5HF__dtable_init(&hdr->man_dtable) < 0) |
196 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize doubling table info"); |
197 | | |
198 | | /* Set the size of heap IDs */ |
199 | 0 | hdr->heap_len_size = |
200 | 0 | (uint8_t)MIN(hdr->man_dtable.max_dir_blk_off_size, H5VM_limit_enc_size((uint64_t)hdr->max_man_size)); |
201 | |
|
202 | 0 | done: |
203 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
204 | 0 | } /* end H5HF__hdr_finish_init_phase1() */ |
205 | | |
206 | | /*------------------------------------------------------------------------- |
207 | | * Function: H5HF__hdr_finish_init_phase2 |
208 | | * |
209 | | * Purpose: Second phase to finish initializing info in shared heap header |
210 | | * |
211 | | * Return: Non-negative on success/Negative on failure |
212 | | * |
213 | | *------------------------------------------------------------------------- |
214 | | */ |
215 | | herr_t |
216 | | H5HF__hdr_finish_init_phase2(H5HF_hdr_t *hdr) |
217 | 0 | { |
218 | 0 | unsigned u; /* Local index variable */ |
219 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
220 | |
|
221 | 0 | FUNC_ENTER_PACKAGE |
222 | | |
223 | | /* |
224 | | * Check arguments. |
225 | | */ |
226 | 0 | assert(hdr); |
227 | | |
228 | | /* Set the free space in direct blocks */ |
229 | 0 | for (u = 0; u < hdr->man_dtable.max_root_rows; u++) { |
230 | 0 | if (u < hdr->man_dtable.max_direct_rows) { |
231 | 0 | hdr->man_dtable.row_tot_dblock_free[u] = |
232 | 0 | hdr->man_dtable.row_block_size[u] - H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); |
233 | 0 | H5_CHECKED_ASSIGN(hdr->man_dtable.row_max_dblock_free[u], size_t, |
234 | 0 | hdr->man_dtable.row_tot_dblock_free[u], hsize_t); |
235 | 0 | } /* end if */ |
236 | 0 | else if (H5HF__hdr_compute_free_space(hdr, u) < 0) |
237 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, |
238 | 0 | "can't initialize direct block free space for indirect block"); |
239 | 0 | } /* end for */ |
240 | | |
241 | | /* Initialize the block iterator for searching for free space */ |
242 | 0 | if (H5HF__man_iter_init(&hdr->next_block) < 0) |
243 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize space search block iterator"); |
244 | | |
245 | | /* Initialize the information for tracking 'huge' objects */ |
246 | 0 | if (H5HF__huge_init(hdr) < 0) |
247 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize info for tracking huge objects"); |
248 | | |
249 | | /* Initialize the information for tracking 'tiny' objects */ |
250 | 0 | if (H5HF__tiny_init(hdr) < 0) |
251 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize info for tracking tiny objects"); |
252 | | |
253 | 0 | done: |
254 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
255 | 0 | } /* end H5HF__hdr_finish_init_phase2() */ |
256 | | |
257 | | /*------------------------------------------------------------------------- |
258 | | * Function: H5HF__hdr_finish_init |
259 | | * |
260 | | * Purpose: Finish initializing info in shared heap header |
261 | | * |
262 | | * Return: Non-negative on success/Negative on failure |
263 | | * |
264 | | *------------------------------------------------------------------------- |
265 | | */ |
266 | | herr_t |
267 | | H5HF__hdr_finish_init(H5HF_hdr_t *hdr) |
268 | 0 | { |
269 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
270 | |
|
271 | 0 | FUNC_ENTER_PACKAGE |
272 | | |
273 | | /* |
274 | | * Check arguments. |
275 | | */ |
276 | 0 | assert(hdr); |
277 | | |
278 | | /* First phase of header final initialization */ |
279 | 0 | if (H5HF__hdr_finish_init_phase1(hdr) < 0) |
280 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't finish phase #1 of header final initialization"); |
281 | | |
282 | | /* Second phase of header final initialization */ |
283 | 0 | if (H5HF__hdr_finish_init_phase2(hdr) < 0) |
284 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't finish phase #2 of header final initialization"); |
285 | | |
286 | 0 | done: |
287 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
288 | 0 | } /* end H5HF__hdr_finish_init() */ |
289 | | |
290 | | /*------------------------------------------------------------------------- |
291 | | * Function: H5HF__hdr_create |
292 | | * |
293 | | * Purpose: Create new fractal heap header |
294 | | * |
295 | | * Return: Non-negative on success/Negative on failure |
296 | | * |
297 | | *------------------------------------------------------------------------- |
298 | | */ |
299 | | haddr_t |
300 | | H5HF__hdr_create(H5F_t *f, const H5HF_create_t *cparam) |
301 | 0 | { |
302 | 0 | H5HF_hdr_t *hdr = NULL; /* The new fractal heap header information */ |
303 | 0 | size_t dblock_overhead; /* Direct block's overhead */ |
304 | 0 | haddr_t ret_value = HADDR_UNDEF; /* Return value */ |
305 | |
|
306 | 0 | FUNC_ENTER_PACKAGE |
307 | | |
308 | | /* |
309 | | * Check arguments. |
310 | | */ |
311 | 0 | assert(f); |
312 | 0 | assert(cparam); |
313 | |
|
314 | | #ifndef NDEBUG |
315 | | /* Check for valid parameters */ |
316 | | if (cparam->managed.width == 0) |
317 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width must be greater than zero"); |
318 | | if (cparam->managed.width > H5HF_WIDTH_LIMIT) |
319 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width too large"); |
320 | | if (!POWER_OF_TWO(cparam->managed.width)) |
321 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width not power of two"); |
322 | | if (cparam->managed.start_block_size == 0) |
323 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "starting block size must be greater than zero"); |
324 | | if (!POWER_OF_TWO(cparam->managed.start_block_size)) |
325 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "starting block size not power of two"); |
326 | | if (cparam->managed.max_direct_size == 0) |
327 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size must be greater than zero"); |
328 | | if (cparam->managed.max_direct_size > H5HF_MAX_DIRECT_SIZE_LIMIT) |
329 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size too large"); |
330 | | if (!POWER_OF_TWO(cparam->managed.max_direct_size)) |
331 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size not power of two"); |
332 | | if (cparam->managed.max_direct_size < cparam->max_man_size) |
333 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, |
334 | | "max. direct block size not large enough to hold all managed blocks"); |
335 | | if (cparam->managed.max_index == 0) |
336 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. heap size must be greater than zero"); |
337 | | #endif /* NDEBUG */ |
338 | | |
339 | | /* Allocate & basic initialization for the shared header */ |
340 | 0 | if (NULL == (hdr = H5HF__hdr_alloc(f))) |
341 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "can't allocate space for shared heap info"); |
342 | | |
343 | | #ifndef NDEBUG |
344 | | if (cparam->managed.max_index > (unsigned)(8 * hdr->sizeof_size)) |
345 | | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. heap size too large for file"); |
346 | | #endif /* NDEBUG */ |
347 | | |
348 | | /* Set the creation parameters for the heap */ |
349 | 0 | hdr->max_man_size = cparam->max_man_size; |
350 | 0 | hdr->checksum_dblocks = cparam->checksum_dblocks; |
351 | 0 | H5MM_memcpy(&(hdr->man_dtable.cparam), &(cparam->managed), sizeof(H5HF_dtable_cparam_t)); |
352 | | |
353 | | /* Set root table address to indicate that the heap is empty currently */ |
354 | 0 | hdr->man_dtable.table_addr = HADDR_UNDEF; |
355 | | |
356 | | /* Set free list header address to indicate that the heap is empty currently */ |
357 | 0 | hdr->fs_addr = HADDR_UNDEF; |
358 | | |
359 | | /* Set "huge" object tracker v2 B-tree address to indicate that there aren't any yet */ |
360 | 0 | hdr->huge_bt2_addr = HADDR_UNDEF; |
361 | | |
362 | | /* First phase of header final initialization */ |
363 | | /* (doesn't need ID length set up) */ |
364 | 0 | if (H5HF__hdr_finish_init_phase1(hdr) < 0) |
365 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, |
366 | 0 | "can't finish phase #1 of header final initialization"); |
367 | | |
368 | | /* Copy any I/O filter pipeline */ |
369 | | /* (This code is not in the "finish init phase" routines because those |
370 | | * routines are also called from the cache 'load' callback, and the filter |
371 | | * length is already set in that case (its stored in the header on disk)) |
372 | | */ |
373 | 0 | if (cparam->pline.nused > 0) { |
374 | | /* Check if the filters in the DCPL can be applied to this dataset */ |
375 | 0 | if (H5Z_can_apply_direct(&(cparam->pline)) < 0) |
376 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "I/O filters can't operate on this heap"); |
377 | | |
378 | | /* Mark the filters as checked */ |
379 | 0 | hdr->checked_filters = true; |
380 | | |
381 | | /* Make the "set local" filter callbacks for this dataset */ |
382 | 0 | if (H5Z_set_local_direct(&(cparam->pline)) < 0) |
383 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to set local filter parameters"); |
384 | | |
385 | | /* Copy the I/O filter pipeline from the creation parameters to the header */ |
386 | 0 | if (NULL == H5O_msg_copy(H5O_PLINE_ID, &(cparam->pline), &(hdr->pline))) |
387 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTCOPY, HADDR_UNDEF, "can't copy I/O filter pipeline"); |
388 | | |
389 | | /* Set the version for the I/O pipeline message */ |
390 | 0 | if (H5O_pline_set_version(hdr->f, &(hdr->pline)) < 0) |
391 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, HADDR_UNDEF, "can't set version of I/O filter pipeline"); |
392 | | |
393 | | /* Compute the I/O filters' encoded size */ |
394 | 0 | if (0 == (hdr->filter_len = (unsigned)H5O_msg_raw_size(hdr->f, H5O_PLINE_ID, false, &(hdr->pline)))) |
395 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGETSIZE, HADDR_UNDEF, "can't get I/O filter pipeline size"); |
396 | | |
397 | | /* Compute size of header on disk */ |
398 | | hdr->heap_size = H5HF_HEADER_SIZE(hdr) /* Base header size */ |
399 | 0 | + hdr->sizeof_size /* Size of size for filtered root direct block */ |
400 | 0 | + 4 /* Size of filter mask for filtered root direct block */ |
401 | 0 | + hdr->filter_len; /* Size of encoded I/O filter info */ |
402 | 0 | } /* end if */ |
403 | 0 | else { |
404 | | /* Set size of header on disk */ |
405 | 0 | hdr->heap_size = H5HF_HEADER_SIZE(hdr); |
406 | | |
407 | | /* Mark filters as checked, for performance reasons */ |
408 | 0 | hdr->checked_filters = true; |
409 | 0 | } /* end else */ |
410 | | |
411 | | /* Set the length of IDs in the heap */ |
412 | | /* (This code is not in the "finish init phase" routines because those |
413 | | * routines are also called from the cache 'load' callback, and the ID |
414 | | * length is already set in that case (its stored in the header on disk)) |
415 | | */ |
416 | 0 | switch (cparam->id_len) { |
417 | 0 | case 0: /* Set the length of heap IDs to just enough to hold the offset & length of 'normal' objects |
418 | | in the heap */ |
419 | 0 | hdr->id_len = (unsigned)1 + hdr->heap_off_size + hdr->heap_len_size; |
420 | 0 | break; |
421 | | |
422 | 0 | case 1: /* Set the length of heap IDs to just enough to hold the information needed to directly access |
423 | | 'huge' objects in the heap */ |
424 | 0 | if (hdr->filter_len > 0) |
425 | 0 | hdr->id_len = (unsigned)1 /* ID flags */ |
426 | 0 | + hdr->sizeof_addr /* Address of filtered object */ |
427 | 0 | + hdr->sizeof_size /* Length of filtered object */ |
428 | 0 | + 4 /* Filter mask for filtered object */ |
429 | 0 | + hdr->sizeof_size; /* Size of de-filtered object in memory */ |
430 | 0 | else |
431 | 0 | hdr->id_len = (unsigned)1 /* ID flags */ |
432 | 0 | + hdr->sizeof_addr /* Address of object */ |
433 | 0 | + hdr->sizeof_size; /* Length of object */ |
434 | 0 | break; |
435 | | |
436 | 0 | default: /* Use the requested size for the heap ID */ |
437 | | /* Check boundaries */ |
438 | 0 | if (cparam->id_len < (1 + hdr->heap_off_size + hdr->heap_len_size)) |
439 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, HADDR_UNDEF, |
440 | 0 | "ID length not large enough to hold object IDs"); |
441 | 0 | else if (cparam->id_len > H5HF_MAX_ID_LEN) |
442 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, HADDR_UNDEF, |
443 | 0 | "ID length too large to store tiny object lengths"); |
444 | | |
445 | | /* Use the requested size for the heap ID */ |
446 | 0 | hdr->id_len = cparam->id_len; |
447 | 0 | break; |
448 | 0 | } /* end switch */ |
449 | | |
450 | | /* Second phase of header final initialization */ |
451 | | /* (needs ID and filter lengths set up) */ |
452 | 0 | if (H5HF__hdr_finish_init_phase2(hdr) < 0) |
453 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, |
454 | 0 | "can't finish phase #2 of header final initialization"); |
455 | | |
456 | | /* Extra checking for possible gap between max. direct block size minus |
457 | | * overhead and "huge" object size */ |
458 | 0 | dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); |
459 | 0 | if ((cparam->managed.max_direct_size - dblock_overhead) < cparam->max_man_size) |
460 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, |
461 | 0 | "max. direct block size not large enough to hold all managed blocks"); |
462 | | |
463 | | /* Allocate space for the header on disk */ |
464 | 0 | if (HADDR_UNDEF == (hdr->heap_addr = H5MF_alloc(f, H5FD_MEM_FHEAP_HDR, (hsize_t)hdr->heap_size))) |
465 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for fractal heap header"); |
466 | | |
467 | | /* Cache the new fractal heap header */ |
468 | 0 | if (H5AC_insert_entry(f, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, H5AC__NO_FLAGS_SET) < 0) |
469 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, HADDR_UNDEF, "can't add fractal heap header to cache"); |
470 | | |
471 | | /* Set address of heap header to return */ |
472 | 0 | ret_value = hdr->heap_addr; |
473 | |
|
474 | 0 | done: |
475 | 0 | if (!H5_addr_defined(ret_value) && hdr) |
476 | 0 | if (H5HF__hdr_free(hdr) < 0) |
477 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, HADDR_UNDEF, "unable to release fractal heap header"); |
478 | |
|
479 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
480 | 0 | } /* end H5HF__hdr_create() */ |
481 | | |
482 | | /*------------------------------------------------------------------------- |
483 | | * Function: H5HF__hdr_protect |
484 | | * |
485 | | * Purpose: Convenience wrapper around H5AC_protect on an indirect block |
486 | | * |
487 | | * Return: Pointer to indirect block on success, NULL on failure |
488 | | * |
489 | | *------------------------------------------------------------------------- |
490 | | */ |
491 | | H5HF_hdr_t * |
492 | | H5HF__hdr_protect(H5F_t *f, haddr_t addr, unsigned flags) |
493 | 0 | { |
494 | 0 | H5HF_hdr_cache_ud_t cache_udata; /* User-data for callback */ |
495 | 0 | H5HF_hdr_t *hdr; /* Fractal heap header */ |
496 | 0 | H5HF_hdr_t *ret_value = NULL; /* Return value */ |
497 | |
|
498 | 0 | FUNC_ENTER_PACKAGE |
499 | | |
500 | | /* Check arguments */ |
501 | 0 | assert(f); |
502 | 0 | assert(H5_addr_defined(addr)); |
503 | | |
504 | | /* only H5AC__READ_ONLY_FLAG may appear in flags */ |
505 | 0 | assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); |
506 | | |
507 | | /* Set up userdata for protect call */ |
508 | 0 | cache_udata.f = f; |
509 | | |
510 | | /* Lock the heap header into memory */ |
511 | 0 | if (NULL == (hdr = (H5HF_hdr_t *)H5AC_protect(f, H5AC_FHEAP_HDR, addr, &cache_udata, flags))) |
512 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header"); |
513 | | |
514 | | /* Set the header's address */ |
515 | 0 | hdr->heap_addr = addr; |
516 | | |
517 | | /* Update header's file pointer */ |
518 | 0 | hdr->f = f; |
519 | | |
520 | | /* Set the return value */ |
521 | 0 | ret_value = hdr; |
522 | |
|
523 | 0 | done: |
524 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
525 | 0 | } /* end H5HF__hdr_protect() */ |
526 | | |
527 | | /*------------------------------------------------------------------------- |
528 | | * Function: H5HF__hdr_incr |
529 | | * |
530 | | * Purpose: Increment component reference count on shared heap header |
531 | | * |
532 | | * Return: Non-negative on success/Negative on failure |
533 | | * |
534 | | *------------------------------------------------------------------------- |
535 | | */ |
536 | | herr_t |
537 | | H5HF__hdr_incr(H5HF_hdr_t *hdr) |
538 | 0 | { |
539 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
540 | |
|
541 | 0 | FUNC_ENTER_PACKAGE |
542 | | |
543 | | /* Sanity check */ |
544 | 0 | assert(hdr); |
545 | | |
546 | | /* Mark header as un-evictable when a block is depending on it */ |
547 | 0 | if (hdr->rc == 0) |
548 | 0 | if (H5AC_pin_protected_entry(hdr) < 0) |
549 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin fractal heap header"); |
550 | | |
551 | | /* Increment reference count on shared header */ |
552 | 0 | hdr->rc++; |
553 | |
|
554 | 0 | done: |
555 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
556 | 0 | } /* end H5HF__hdr_incr() */ |
557 | | |
558 | | /*------------------------------------------------------------------------- |
559 | | * Function: H5HF__hdr_decr |
560 | | * |
561 | | * Purpose: Decrement component reference count on shared heap header |
562 | | * |
563 | | * Return: Non-negative on success/Negative on failure |
564 | | * |
565 | | *------------------------------------------------------------------------- |
566 | | */ |
567 | | herr_t |
568 | | H5HF__hdr_decr(H5HF_hdr_t *hdr) |
569 | 0 | { |
570 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
571 | |
|
572 | 0 | FUNC_ENTER_PACKAGE |
573 | | |
574 | | /* Sanity check */ |
575 | 0 | assert(hdr); |
576 | 0 | assert(hdr->rc); |
577 | | |
578 | | /* Decrement reference count on shared header */ |
579 | 0 | hdr->rc--; |
580 | | |
581 | | /* Mark header as evictable again when no child blocks depend on it */ |
582 | 0 | if (hdr->rc == 0) { |
583 | 0 | assert(hdr->file_rc == 0); |
584 | 0 | if (H5AC_unpin_entry(hdr) < 0) |
585 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap header"); |
586 | 0 | } /* end if */ |
587 | | |
588 | 0 | done: |
589 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
590 | 0 | } /* end H5HF__hdr_decr() */ |
591 | | |
592 | | /*------------------------------------------------------------------------- |
593 | | * Function: H5HF__hdr_fuse_incr |
594 | | * |
595 | | * Purpose: Increment file reference count on shared heap header |
596 | | * |
597 | | * Return: Non-negative on success/Negative on failure |
598 | | * |
599 | | *------------------------------------------------------------------------- |
600 | | */ |
601 | | herr_t |
602 | | H5HF__hdr_fuse_incr(H5HF_hdr_t *hdr) |
603 | 0 | { |
604 | 0 | FUNC_ENTER_PACKAGE_NOERR |
605 | | |
606 | | /* Sanity check */ |
607 | 0 | assert(hdr); |
608 | | |
609 | | /* Increment file reference count on shared header */ |
610 | 0 | hdr->file_rc++; |
611 | |
|
612 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
613 | 0 | } /* end H5HF__hdr_fuse_incr() */ |
614 | | |
615 | | /*------------------------------------------------------------------------- |
616 | | * Function: H5HF__hdr_fuse_decr |
617 | | * |
618 | | * Purpose: Decrement file reference count on shared heap header |
619 | | * |
620 | | * Return: Non-negative on success/Negative on failure |
621 | | * |
622 | | *------------------------------------------------------------------------- |
623 | | */ |
624 | | size_t |
625 | | H5HF__hdr_fuse_decr(H5HF_hdr_t *hdr) |
626 | 0 | { |
627 | 0 | FUNC_ENTER_PACKAGE_NOERR |
628 | | |
629 | | /* Sanity check */ |
630 | 0 | assert(hdr); |
631 | 0 | assert(hdr->file_rc); |
632 | | |
633 | | /* Decrement file reference count on shared header */ |
634 | 0 | hdr->file_rc--; |
635 | |
|
636 | 0 | FUNC_LEAVE_NOAPI(hdr->file_rc) |
637 | 0 | } /* end H5HF__hdr_fuse_decr() */ |
638 | | |
639 | | /*------------------------------------------------------------------------- |
640 | | * Function: H5HF__hdr_dirty |
641 | | * |
642 | | * Purpose: Mark heap header as dirty |
643 | | * |
644 | | * Return: Non-negative on success/Negative on failure |
645 | | * |
646 | | *------------------------------------------------------------------------- |
647 | | */ |
648 | | herr_t |
649 | | H5HF__hdr_dirty(H5HF_hdr_t *hdr) |
650 | 0 | { |
651 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
652 | |
|
653 | 0 | FUNC_ENTER_PACKAGE |
654 | | |
655 | | /* Sanity check */ |
656 | 0 | assert(hdr); |
657 | | |
658 | | /* Resize pinned header in cache if I/O filter is present. */ |
659 | 0 | if (hdr->filter_len > 0) |
660 | 0 | if (H5AC_resize_entry(hdr, (size_t)hdr->heap_size) < 0) |
661 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize fractal heap header"); |
662 | | |
663 | | /* Mark header as dirty in cache */ |
664 | 0 | if (H5AC_mark_entry_dirty(hdr) < 0) |
665 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap header as dirty"); |
666 | | |
667 | 0 | done: |
668 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
669 | 0 | } /* end H5HF__hdr_dirty() */ |
670 | | |
671 | | /*------------------------------------------------------------------------- |
672 | | * Function: H5HF__hdr_adj_free |
673 | | * |
674 | | * Purpose: Adjust the free space for a heap |
675 | | * |
676 | | * Return: SUCCEED/FAIL |
677 | | * |
678 | | *------------------------------------------------------------------------- |
679 | | */ |
680 | | herr_t |
681 | | H5HF__hdr_adj_free(H5HF_hdr_t *hdr, ssize_t amt) |
682 | 0 | { |
683 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
684 | |
|
685 | 0 | FUNC_ENTER_PACKAGE |
686 | | |
687 | | /* |
688 | | * Check arguments. |
689 | | */ |
690 | 0 | assert(hdr); |
691 | | |
692 | | /* Update heap header */ |
693 | 0 | assert(amt > 0 || hdr->total_man_free >= (hsize_t)-amt); |
694 | 0 | hdr->total_man_free = (hsize_t)((hssize_t)hdr->total_man_free + amt); |
695 | | |
696 | | /* Mark heap header as modified */ |
697 | 0 | if (H5HF__hdr_dirty(hdr) < 0) |
698 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty"); |
699 | | |
700 | 0 | done: |
701 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
702 | 0 | } /* end H5HF__hdr_adj_free() */ |
703 | | |
704 | | /*------------------------------------------------------------------------- |
705 | | * Function: H5HF__hdr_adjust_heap |
706 | | * |
707 | | * Purpose: Adjust heap space |
708 | | * |
709 | | * Return: Non-negative on success/Negative on failure |
710 | | * |
711 | | *------------------------------------------------------------------------- |
712 | | */ |
713 | | herr_t |
714 | | H5HF__hdr_adjust_heap(H5HF_hdr_t *hdr, hsize_t new_size, hssize_t extra_free) |
715 | 0 | { |
716 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
717 | |
|
718 | 0 | FUNC_ENTER_PACKAGE |
719 | | |
720 | | /* |
721 | | * Check arguments. |
722 | | */ |
723 | 0 | assert(hdr); |
724 | | |
725 | | /* Set the total managed space in heap */ |
726 | 0 | hdr->man_size = new_size; |
727 | | |
728 | | /* Adjust the free space in direct blocks */ |
729 | 0 | assert(extra_free > 0 || hdr->total_man_free >= (hsize_t)-extra_free); |
730 | 0 | hdr->total_man_free = (hsize_t)((hssize_t)hdr->total_man_free + extra_free); |
731 | | |
732 | | /* Mark heap header as modified */ |
733 | 0 | if (H5HF__hdr_dirty(hdr) < 0) |
734 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty"); |
735 | | |
736 | 0 | done: |
737 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
738 | 0 | } /* end H5HF__hdr_adjust_heap() */ |
739 | | |
740 | | /*------------------------------------------------------------------------- |
741 | | * Function: H5HF__hdr_inc_alloc |
742 | | * |
743 | | * Purpose: Increase allocated size of heap |
744 | | * |
745 | | * Return: Non-negative on success/Negative on failure |
746 | | * |
747 | | *------------------------------------------------------------------------- |
748 | | */ |
749 | | herr_t |
750 | | H5HF__hdr_inc_alloc(H5HF_hdr_t *hdr, size_t alloc_size) |
751 | 0 | { |
752 | 0 | FUNC_ENTER_PACKAGE_NOERR |
753 | | |
754 | | /* |
755 | | * Check arguments. |
756 | | */ |
757 | 0 | assert(hdr); |
758 | 0 | assert(alloc_size); |
759 | | |
760 | | /* Update the "allocated" size within the heap */ |
761 | 0 | hdr->man_alloc_size += alloc_size; |
762 | |
|
763 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
764 | 0 | } /* end H5HF__hdr_inc_alloc() */ |
765 | | |
766 | | /*------------------------------------------------------------------------- |
767 | | * Function: H5HF__hdr_start_iter |
768 | | * |
769 | | * Purpose: Start "next block" iterator at an offset/entry in the heap |
770 | | * |
771 | | * Return: Non-negative on success/Negative on failure |
772 | | * |
773 | | *------------------------------------------------------------------------- |
774 | | */ |
775 | | herr_t |
776 | | H5HF__hdr_start_iter(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, hsize_t curr_off, unsigned curr_entry) |
777 | 0 | { |
778 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
779 | |
|
780 | 0 | FUNC_ENTER_PACKAGE |
781 | | |
782 | | /* |
783 | | * Check arguments. |
784 | | */ |
785 | 0 | assert(hdr); |
786 | 0 | assert(iblock); |
787 | | |
788 | | /* Set up "next block" iterator at correct location */ |
789 | 0 | if (H5HF__man_iter_start_entry(hdr, &hdr->next_block, iblock, curr_entry) < 0) |
790 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize block iterator"); |
791 | | |
792 | | /* Set the offset of the iterator in the heap */ |
793 | 0 | hdr->man_iter_off = curr_off; |
794 | |
|
795 | 0 | done: |
796 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
797 | 0 | } /* end H5HF__hdr_start_iter() */ |
798 | | |
799 | | /*------------------------------------------------------------------------- |
800 | | * Function: H5HF__hdr_reset_iter |
801 | | * |
802 | | * Purpose: Reset "next block" iterator |
803 | | * |
804 | | * Return: Non-negative on success/Negative on failure |
805 | | * |
806 | | *------------------------------------------------------------------------- |
807 | | */ |
808 | | herr_t |
809 | | H5HF__hdr_reset_iter(H5HF_hdr_t *hdr, hsize_t curr_off) |
810 | 0 | { |
811 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
812 | |
|
813 | 0 | FUNC_ENTER_PACKAGE |
814 | | |
815 | | /* |
816 | | * Check arguments. |
817 | | */ |
818 | 0 | assert(hdr); |
819 | | |
820 | | /* Reset "next block" iterator */ |
821 | 0 | if (H5HF__man_iter_reset(&hdr->next_block) < 0) |
822 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator"); |
823 | | |
824 | | /* Set the offset of the iterator in the heap */ |
825 | 0 | hdr->man_iter_off = curr_off; |
826 | |
|
827 | 0 | done: |
828 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
829 | 0 | } /* end H5HF__hdr_reset_iter() */ |
830 | | |
831 | | /*------------------------------------------------------------------------- |
832 | | * Function: H5HF__hdr_skip_blocks |
833 | | * |
834 | | * Purpose: Add skipped direct blocks to free space for heap |
835 | | * |
836 | | * Return: SUCCEED/FAIL |
837 | | * |
838 | | *------------------------------------------------------------------------- |
839 | | */ |
840 | | herr_t |
841 | | H5HF__hdr_skip_blocks(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, unsigned start_entry, unsigned nentries) |
842 | 0 | { |
843 | 0 | unsigned row, col; /* Row & column of entry */ |
844 | 0 | hsize_t sect_size; /* Size of section in heap space */ |
845 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
846 | |
|
847 | 0 | FUNC_ENTER_PACKAGE |
848 | | |
849 | | /* |
850 | | * Check arguments. |
851 | | */ |
852 | 0 | assert(hdr); |
853 | 0 | assert(iblock); |
854 | 0 | assert(nentries); |
855 | | |
856 | | /* Compute the span within the heap to skip */ |
857 | 0 | row = start_entry / hdr->man_dtable.cparam.width; |
858 | 0 | col = start_entry % hdr->man_dtable.cparam.width; |
859 | 0 | sect_size = H5HF__dtable_span_size(&hdr->man_dtable, row, col, nentries); |
860 | 0 | assert(sect_size > 0); |
861 | | |
862 | | /* Advance the new block iterator */ |
863 | 0 | if (H5HF__hdr_inc_iter(hdr, sect_size, nentries) < 0) |
864 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size"); |
865 | | |
866 | | /* Add 'indirect' section for blocks skipped in this row */ |
867 | 0 | if (H5HF__sect_indirect_add(hdr, iblock, start_entry, nentries) < 0) |
868 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, |
869 | 0 | "can't create indirect section for indirect block's free space"); |
870 | | |
871 | 0 | done: |
872 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
873 | 0 | } /* end H5HF__hdr_skip_blocks() */ |
874 | | |
875 | | /*------------------------------------------------------------------------- |
876 | | * Function: H5HF__hdr_update_iter |
877 | | * |
878 | | * Purpose: Update state of heap to account for current iterator |
879 | | * position. |
880 | | * |
881 | | * Note: Creates necessary indirect blocks |
882 | | * |
883 | | * Return: Non-negative on success/Negative on failure |
884 | | * |
885 | | *------------------------------------------------------------------------- |
886 | | */ |
887 | | herr_t |
888 | | H5HF__hdr_update_iter(H5HF_hdr_t *hdr, size_t min_dblock_size) |
889 | 0 | { |
890 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
891 | |
|
892 | 0 | FUNC_ENTER_PACKAGE |
893 | | |
894 | | /* |
895 | | * Check arguments. |
896 | | */ |
897 | 0 | assert(hdr); |
898 | 0 | assert(min_dblock_size > 0); |
899 | | |
900 | | /* Check for creating first indirect block */ |
901 | 0 | if (hdr->man_dtable.curr_root_rows == 0) { |
902 | 0 | if (H5HF__man_iblock_root_create(hdr, min_dblock_size) < 0) |
903 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to create root indirect block"); |
904 | 0 | } /* end if */ |
905 | 0 | else { |
906 | 0 | H5HF_indirect_t *iblock; /* Pointer to indirect block */ |
907 | 0 | bool walked_up, walked_down; /* Condition variables for finding direct block location */ |
908 | 0 | unsigned next_row; /* Iterator's next block row */ |
909 | 0 | unsigned next_entry; /* Iterator's next block entry */ |
910 | 0 | unsigned min_dblock_row; /* Minimum row for direct block size request */ |
911 | | |
912 | | /* Compute min. row for direct block requested */ |
913 | 0 | min_dblock_row = H5HF__dtable_size_to_row(&hdr->man_dtable, min_dblock_size); |
914 | | |
915 | | /* Initialize block iterator, if necessary */ |
916 | 0 | if (!H5HF__man_iter_ready(&hdr->next_block)) { |
917 | | /* Start iterator with previous offset of iterator */ |
918 | 0 | if (H5HF__man_iter_start_offset(hdr, &hdr->next_block, hdr->man_iter_off) < 0) |
919 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location"); |
920 | 0 | } /* end if */ |
921 | | |
922 | | /* Get information about current iterator location */ |
923 | 0 | if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) |
924 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location"); |
925 | | |
926 | | /* Check for skipping over blocks in the current block */ |
927 | 0 | if (min_dblock_row > next_row && next_row < iblock->nrows) { |
928 | 0 | unsigned min_entry; /* Min entry for direct block requested */ |
929 | 0 | unsigned skip_entries; /* Number of entries to skip in the current block */ |
930 | | |
931 | | /* Compute the number of entries to skip in the current block */ |
932 | 0 | min_entry = min_dblock_row * hdr->man_dtable.cparam.width; |
933 | 0 | if (min_dblock_row >= iblock->nrows) |
934 | 0 | skip_entries = (iblock->nrows * hdr->man_dtable.cparam.width) - next_entry; |
935 | 0 | else |
936 | 0 | skip_entries = min_entry - next_entry; |
937 | | |
938 | | /* Add skipped direct blocks to heap's free space */ |
939 | 0 | if (H5HF__hdr_skip_blocks(hdr, iblock, next_entry, skip_entries) < 0) |
940 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space"); |
941 | | |
942 | | /* Get information about new iterator location */ |
943 | 0 | if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) |
944 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, |
945 | 0 | "unable to retrieve current block iterator location"); |
946 | 0 | } /* end if */ |
947 | | |
948 | 0 | do { |
949 | | /* Reset conditions for leaving loop */ |
950 | 0 | walked_up = walked_down = false; |
951 | | |
952 | | /* Check for walking off end of indirect block */ |
953 | | /* (walk up iterator) */ |
954 | 0 | while (next_row >= iblock->nrows) { |
955 | | /* Check for needing to expand root indirect block */ |
956 | 0 | if (iblock->parent == NULL) { |
957 | 0 | if (H5HF__man_iblock_root_double(hdr, min_dblock_size) < 0) |
958 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to double root indirect block"); |
959 | 0 | } /* end if */ |
960 | 0 | else { |
961 | | /* Move iterator up one level */ |
962 | 0 | if (H5HF__man_iter_up(&hdr->next_block) < 0) |
963 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, |
964 | 0 | "unable to advance current block iterator location"); |
965 | | |
966 | | /* Increment location of next block at this level */ |
967 | 0 | if (H5HF__man_iter_next(hdr, &hdr->next_block, 1) < 0) |
968 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't advance fractal heap block location"); |
969 | 0 | } /* end else */ |
970 | | |
971 | | /* Get information about new iterator location */ |
972 | 0 | if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) |
973 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, |
974 | 0 | "unable to retrieve current block iterator location"); |
975 | | |
976 | | /* Indicate that we walked up */ |
977 | 0 | walked_up = true; |
978 | 0 | } /* end while */ |
979 | | |
980 | | /* Check for walking into child indirect block */ |
981 | | /* (walk down iterator) */ |
982 | 0 | if (next_row >= hdr->man_dtable.max_direct_rows) { |
983 | 0 | unsigned child_nrows; /* Number of rows in new indirect block */ |
984 | |
|
985 | 0 | assert(!H5_addr_defined(iblock->ents[next_entry].addr)); |
986 | | |
987 | | /* Compute # of rows in next child indirect block to use */ |
988 | 0 | child_nrows = |
989 | 0 | H5HF__dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[next_row]); |
990 | | |
991 | | /* Check for skipping over indirect blocks */ |
992 | | /* (that don't have direct blocks large enough to hold direct block size requested) */ |
993 | 0 | if (hdr->man_dtable.row_block_size[child_nrows - 1] < min_dblock_size) { |
994 | 0 | unsigned child_rows_needed; /* Number of rows needed to hold direct block */ |
995 | 0 | unsigned child_entry; /* Entry of child indirect block */ |
996 | | |
997 | | /* Compute # of rows needed in child indirect block */ |
998 | 0 | child_rows_needed = (H5VM_log2_of2((uint32_t)min_dblock_size) - |
999 | 0 | H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size)) + |
1000 | 0 | 2; |
1001 | 0 | assert(child_rows_needed > child_nrows); |
1002 | 0 | child_entry = |
1003 | 0 | (next_row + (child_rows_needed - child_nrows)) * hdr->man_dtable.cparam.width; |
1004 | 0 | if (child_entry > (iblock->nrows * hdr->man_dtable.cparam.width)) |
1005 | 0 | child_entry = iblock->nrows * hdr->man_dtable.cparam.width; |
1006 | | |
1007 | | /* Add skipped indirect blocks to heap's free space */ |
1008 | 0 | if (H5HF__hdr_skip_blocks(hdr, iblock, next_entry, (child_entry - next_entry)) < 0) |
1009 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, |
1010 | 0 | "can't add skipped blocks to heap's free space"); |
1011 | 0 | } /* end if */ |
1012 | 0 | else { |
1013 | 0 | H5HF_indirect_t *new_iblock; /* Pointer to new indirect block */ |
1014 | 0 | bool did_protect; /* Whether we protected the indirect block or not */ |
1015 | 0 | haddr_t new_iblock_addr; /* New indirect block's address */ |
1016 | | |
1017 | | /* Allocate new indirect block */ |
1018 | 0 | if (H5HF__man_iblock_create(hdr, iblock, next_entry, child_nrows, child_nrows, |
1019 | 0 | &new_iblock_addr) < 0) |
1020 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, |
1021 | 0 | "can't allocate fractal heap indirect block"); |
1022 | | |
1023 | | /* Lock new indirect block */ |
1024 | 0 | if (NULL == (new_iblock = H5HF__man_iblock_protect(hdr, new_iblock_addr, child_nrows, |
1025 | 0 | iblock, next_entry, false, |
1026 | 0 | H5AC__NO_FLAGS_SET, &did_protect))) |
1027 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, |
1028 | 0 | "unable to protect fractal heap indirect block"); |
1029 | | |
1030 | | /* Move iterator down one level (pins indirect block) */ |
1031 | 0 | if (H5HF__man_iter_down(&hdr->next_block, new_iblock) < 0) |
1032 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, |
1033 | 0 | "unable to advance current block iterator location"); |
1034 | | |
1035 | | /* Check for skipping over rows and add free section for skipped rows */ |
1036 | 0 | if (min_dblock_size > hdr->man_dtable.cparam.start_block_size) { |
1037 | 0 | unsigned new_entry; /* Entry of direct block which is large enough */ |
1038 | | |
1039 | | /* Compute entry for direct block size requested */ |
1040 | 0 | new_entry = hdr->man_dtable.cparam.width * min_dblock_row; |
1041 | | |
1042 | | /* Add skipped blocks to heap's free space */ |
1043 | 0 | if (H5HF__hdr_skip_blocks(hdr, new_iblock, 0, new_entry) < 0) |
1044 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, |
1045 | 0 | "can't add skipped blocks to heap's free space"); |
1046 | 0 | } /* end if */ |
1047 | | |
1048 | | /* Unprotect child indirect block */ |
1049 | 0 | if (H5HF__man_iblock_unprotect(new_iblock, H5AC__NO_FLAGS_SET, did_protect) < 0) |
1050 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, |
1051 | 0 | "unable to release fractal heap indirect block"); |
1052 | 0 | } /* end else */ |
1053 | | |
1054 | | /* Get information about new iterator location */ |
1055 | 0 | if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) |
1056 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, |
1057 | 0 | "unable to retrieve current block iterator location"); |
1058 | | |
1059 | | /* Indicate that we walked down */ |
1060 | 0 | walked_down = true; |
1061 | 0 | } /* end if */ |
1062 | 0 | } while (walked_down || walked_up); |
1063 | 0 | } /* end else */ |
1064 | | |
1065 | 0 | done: |
1066 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1067 | 0 | } /* end H5HF__hdr_update_iter() */ |
1068 | | |
1069 | | /*------------------------------------------------------------------------- |
1070 | | * Function: H5HF__hdr_inc_iter |
1071 | | * |
1072 | | * Purpose: Advance "next block" iterator |
1073 | | * |
1074 | | * Return: Non-negative on success/Negative on failure |
1075 | | * |
1076 | | *------------------------------------------------------------------------- |
1077 | | */ |
1078 | | herr_t |
1079 | | H5HF__hdr_inc_iter(H5HF_hdr_t *hdr, hsize_t adv_size, unsigned nentries) |
1080 | 0 | { |
1081 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1082 | |
|
1083 | 0 | FUNC_ENTER_PACKAGE |
1084 | | |
1085 | | /* |
1086 | | * Check arguments. |
1087 | | */ |
1088 | 0 | assert(hdr); |
1089 | 0 | assert(nentries); |
1090 | | |
1091 | | /* Advance the iterator for the current location within the indirect block */ |
1092 | 0 | if (hdr->next_block.curr) |
1093 | 0 | if (H5HF__man_iter_next(hdr, &hdr->next_block, nentries) < 0) |
1094 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location"); |
1095 | | |
1096 | | /* Increment the offset of the iterator in the heap */ |
1097 | 0 | hdr->man_iter_off += adv_size; |
1098 | |
|
1099 | 0 | done: |
1100 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1101 | 0 | } /* end H5HF__hdr_inc_iter() */ |
1102 | | |
1103 | | /*------------------------------------------------------------------------- |
1104 | | * Function: H5HF__hdr_reverse_iter |
1105 | | * |
1106 | | * Purpose: Walk "next block" iterator backwards until the correct |
1107 | | * location to allocate next block from is found |
1108 | | * |
1109 | | * Return: Non-negative on success/Negative on failure |
1110 | | * |
1111 | | *------------------------------------------------------------------------- |
1112 | | */ |
1113 | | herr_t |
1114 | | H5HF__hdr_reverse_iter(H5HF_hdr_t *hdr, haddr_t dblock_addr) |
1115 | 0 | { |
1116 | 0 | H5HF_indirect_t *iblock; /* Indirect block where iterator is located */ |
1117 | 0 | unsigned curr_entry; /* Current entry for iterator */ |
1118 | 0 | bool walked_down; /* Loop flag */ |
1119 | 0 | bool walked_up; /* Loop flag */ |
1120 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1121 | |
|
1122 | 0 | FUNC_ENTER_PACKAGE |
1123 | | |
1124 | | /* |
1125 | | * Check arguments. |
1126 | | */ |
1127 | 0 | assert(hdr); |
1128 | | |
1129 | | /* Initialize block iterator, if necessary */ |
1130 | 0 | if (!H5HF__man_iter_ready(&hdr->next_block)) |
1131 | | /* Start iterator with previous offset of iterator */ |
1132 | 0 | if (H5HF__man_iter_start_offset(hdr, &hdr->next_block, hdr->man_iter_off) < 0) |
1133 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location"); |
1134 | | |
1135 | | /* Walk backwards through heap, looking for direct block to place iterator after */ |
1136 | | |
1137 | | /* Get information about current iterator location */ |
1138 | 0 | if (H5HF__man_iter_curr(&hdr->next_block, NULL, NULL, &curr_entry, &iblock) < 0) |
1139 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator information"); |
1140 | | |
1141 | | /* Move current iterator position backwards once */ |
1142 | 0 | curr_entry--; |
1143 | | |
1144 | | /* Search backwards in the heap address space for direct block to latch onto */ |
1145 | 0 | do { |
1146 | 0 | int tmp_entry; /* Temp. entry for iterator (use signed value to detect errors) */ |
1147 | | |
1148 | | /* Reset loop flags */ |
1149 | 0 | walked_down = false; |
1150 | 0 | walked_up = false; |
1151 | | |
1152 | | /* Walk backwards through entries, until we find one that has a child */ |
1153 | | /* (Skip direct block that will be deleted, if we find it) */ |
1154 | 0 | tmp_entry = (int)curr_entry; |
1155 | 0 | while (tmp_entry >= 0 && (H5_addr_eq(iblock->ents[tmp_entry].addr, dblock_addr) || |
1156 | 0 | !H5_addr_defined(iblock->ents[tmp_entry].addr))) |
1157 | 0 | tmp_entry--; |
1158 | | /* Check for no earlier blocks in this indirect block */ |
1159 | 0 | if (tmp_entry < 0) { |
1160 | | /* Check for parent of current indirect block */ |
1161 | 0 | if (iblock->parent) { |
1162 | | /* Move iterator to parent of current block */ |
1163 | 0 | if (H5HF__man_iter_up(&hdr->next_block) < 0) |
1164 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, |
1165 | 0 | "unable to move current block iterator location up"); |
1166 | | |
1167 | | /* Get information about current iterator location */ |
1168 | 0 | if (H5HF__man_iter_curr(&hdr->next_block, NULL, NULL, &curr_entry, &iblock) < 0) |
1169 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, |
1170 | 0 | "unable to retrieve current block iterator information"); |
1171 | | |
1172 | | /* Move current iterator position backwards once */ |
1173 | 0 | curr_entry--; |
1174 | | |
1175 | | /* Note that we walked up */ |
1176 | 0 | walked_up = true; |
1177 | 0 | } /* end if */ |
1178 | 0 | else { |
1179 | | /* Reset iterator offset */ |
1180 | 0 | hdr->man_iter_off = 0; |
1181 | | |
1182 | | /* Reset 'next block' iterator */ |
1183 | 0 | if (H5HF__man_iter_reset(&hdr->next_block) < 0) |
1184 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator"); |
1185 | 0 | } /* end else */ |
1186 | 0 | } /* end if */ |
1187 | 0 | else { |
1188 | 0 | unsigned row; /* Row for entry */ |
1189 | |
|
1190 | 0 | curr_entry = (unsigned)tmp_entry; |
1191 | | |
1192 | | /* Check if entry is for a direct block */ |
1193 | 0 | row = curr_entry / hdr->man_dtable.cparam.width; |
1194 | 0 | if (row < hdr->man_dtable.max_direct_rows) { |
1195 | | /* Increment entry to empty location */ |
1196 | 0 | curr_entry++; |
1197 | | |
1198 | | /* Set the current location of the iterator to next entry after the existing direct block */ |
1199 | 0 | if (H5HF__man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0) |
1200 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location"); |
1201 | | |
1202 | | /* Update iterator offset */ |
1203 | 0 | hdr->man_iter_off = iblock->block_off; |
1204 | 0 | hdr->man_iter_off += hdr->man_dtable.row_block_off[curr_entry / hdr->man_dtable.cparam.width]; |
1205 | 0 | hdr->man_iter_off += |
1206 | 0 | hdr->man_dtable.row_block_size[curr_entry / hdr->man_dtable.cparam.width] * |
1207 | 0 | (curr_entry % hdr->man_dtable.cparam.width); |
1208 | 0 | } /* end if */ |
1209 | 0 | else { |
1210 | 0 | H5HF_indirect_t *child_iblock; /* Pointer to child indirect block */ |
1211 | 0 | bool did_protect; /* Whether we protected the indirect block or not */ |
1212 | 0 | unsigned child_nrows; /* # of rows in child block */ |
1213 | | |
1214 | | /* Compute # of rows in next child indirect block to use */ |
1215 | 0 | child_nrows = |
1216 | 0 | H5HF__dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[row]); |
1217 | | |
1218 | | /* Lock child indirect block */ |
1219 | 0 | if (NULL == (child_iblock = H5HF__man_iblock_protect(hdr, iblock->ents[curr_entry].addr, |
1220 | 0 | child_nrows, iblock, curr_entry, false, |
1221 | 0 | H5AC__NO_FLAGS_SET, &did_protect))) |
1222 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, |
1223 | 0 | "unable to protect fractal heap indirect block"); |
1224 | | |
1225 | | /* Set the current location of the iterator */ |
1226 | 0 | if (H5HF__man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0) |
1227 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location"); |
1228 | | |
1229 | | /* Walk down into child indirect block (pins child block) */ |
1230 | 0 | if (H5HF__man_iter_down(&hdr->next_block, child_iblock) < 0) |
1231 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, |
1232 | 0 | "unable to advance current block iterator location"); |
1233 | | |
1234 | | /* Update iterator location */ |
1235 | 0 | iblock = child_iblock; |
1236 | 0 | curr_entry = (child_iblock->nrows * hdr->man_dtable.cparam.width) - 1; |
1237 | | |
1238 | | /* Unprotect child indirect block */ |
1239 | 0 | if (H5HF__man_iblock_unprotect(child_iblock, H5AC__NO_FLAGS_SET, did_protect) < 0) |
1240 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, |
1241 | 0 | "unable to release fractal heap indirect block"); |
1242 | | |
1243 | | /* Note that we walked down */ |
1244 | 0 | walked_down = true; |
1245 | 0 | } /* end else */ |
1246 | 0 | } /* end else */ |
1247 | 0 | } while (walked_down || walked_up); |
1248 | | |
1249 | 0 | done: |
1250 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1251 | 0 | } /* end H5HF__hdr_reverse_iter() */ |
1252 | | |
1253 | | /*------------------------------------------------------------------------- |
1254 | | * Function: H5HF__hdr_empty |
1255 | | * |
1256 | | * Purpose: Reset heap header to 'empty heap' state |
1257 | | * |
1258 | | * Return: Non-negative on success/Negative on failure |
1259 | | * |
1260 | | *------------------------------------------------------------------------- |
1261 | | */ |
1262 | | herr_t |
1263 | | H5HF__hdr_empty(H5HF_hdr_t *hdr) |
1264 | 0 | { |
1265 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1266 | |
|
1267 | 0 | FUNC_ENTER_PACKAGE |
1268 | | |
1269 | | /* Sanity check */ |
1270 | 0 | assert(hdr); |
1271 | | |
1272 | | /* Reset block iterator, if necessary */ |
1273 | 0 | if (H5HF__man_iter_ready(&hdr->next_block)) |
1274 | 0 | if (H5HF__man_iter_reset(&hdr->next_block) < 0) |
1275 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator"); |
1276 | | |
1277 | | /* Shrink managed heap size */ |
1278 | 0 | hdr->man_size = 0; |
1279 | 0 | hdr->man_alloc_size = 0; |
1280 | | |
1281 | | /* Reset root pointer information */ |
1282 | 0 | hdr->man_dtable.curr_root_rows = 0; |
1283 | 0 | hdr->man_dtable.table_addr = HADDR_UNDEF; |
1284 | | |
1285 | | /* Reset the 'next block' iterator location */ |
1286 | 0 | hdr->man_iter_off = 0; |
1287 | | |
1288 | | /* Reset the free space in direct blocks */ |
1289 | 0 | hdr->total_man_free = 0; |
1290 | | |
1291 | | /* Mark heap header as modified */ |
1292 | 0 | if (H5HF__hdr_dirty(hdr) < 0) |
1293 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty"); |
1294 | | |
1295 | 0 | done: |
1296 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1297 | 0 | } /* end H5HF__hdr_empty() */ |
1298 | | |
1299 | | /*------------------------------------------------------------------------- |
1300 | | * Function: H5HF__hdr_free |
1301 | | * |
1302 | | * Purpose: Free shared fractal heap header |
1303 | | * |
1304 | | * Return: Non-negative on success/Negative on failure |
1305 | | * |
1306 | | *------------------------------------------------------------------------- |
1307 | | */ |
1308 | | herr_t |
1309 | | H5HF__hdr_free(H5HF_hdr_t *hdr) |
1310 | 0 | { |
1311 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1312 | |
|
1313 | 0 | FUNC_ENTER_PACKAGE |
1314 | | |
1315 | | /* |
1316 | | * Check arguments. |
1317 | | */ |
1318 | 0 | assert(hdr); |
1319 | | |
1320 | | /* Free the block size lookup table for the doubling table */ |
1321 | 0 | if (H5HF__dtable_dest(&hdr->man_dtable) < 0) |
1322 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap doubling table"); |
1323 | | |
1324 | | /* Release any I/O pipeline filter information */ |
1325 | 0 | if (hdr->pline.nused) |
1326 | 0 | if (H5O_msg_reset(H5O_PLINE_ID, &(hdr->pline)) < 0) |
1327 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to reset I/O pipeline message"); |
1328 | | |
1329 | | /* Free the shared info itself */ |
1330 | 0 | hdr = H5FL_FREE(H5HF_hdr_t, hdr); |
1331 | |
|
1332 | 0 | done: |
1333 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1334 | 0 | } /* end H5HF__hdr_free() */ |
1335 | | |
1336 | | /*------------------------------------------------------------------------- |
1337 | | * Function: H5HF__hdr_delete |
1338 | | * |
1339 | | * Purpose: Delete a fractal heap, starting with the header |
1340 | | * |
1341 | | * Return: SUCCEED/FAIL |
1342 | | * |
1343 | | *------------------------------------------------------------------------- |
1344 | | */ |
1345 | | herr_t |
1346 | | H5HF__hdr_delete(H5HF_hdr_t *hdr) |
1347 | 0 | { |
1348 | 0 | unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap header */ |
1349 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1350 | |
|
1351 | 0 | FUNC_ENTER_PACKAGE |
1352 | | |
1353 | | /* |
1354 | | * Check arguments. |
1355 | | */ |
1356 | 0 | assert(hdr); |
1357 | 0 | assert(!hdr->file_rc); |
1358 | |
|
1359 | | #ifndef NDEBUG |
1360 | | { |
1361 | | unsigned hdr_status = 0; /* Heap header's status in the metadata cache */ |
1362 | | |
1363 | | /* Check the heap header's status in the metadata cache */ |
1364 | | if (H5AC_get_entry_status(hdr->f, hdr->heap_addr, &hdr_status) < 0) |
1365 | | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for heap header"); |
1366 | | |
1367 | | /* Sanity checks on heap header */ |
1368 | | assert(hdr_status & H5AC_ES__IN_CACHE); |
1369 | | assert(hdr_status & H5AC_ES__IS_PROTECTED); |
1370 | | } /* end block */ |
1371 | | #endif /* NDEBUG */ |
1372 | | |
1373 | | /* Check for free space manager for heap */ |
1374 | | /* (must occur before attempting to delete the heap, so indirect blocks |
1375 | | * will get unpinned) |
1376 | | */ |
1377 | 0 | if (H5_addr_defined(hdr->fs_addr)) |
1378 | | /* Delete free space manager for heap */ |
1379 | 0 | if (H5HF__space_delete(hdr) < 0) |
1380 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap free space manager"); |
1381 | | |
1382 | | /* Check for root direct/indirect block */ |
1383 | 0 | if (H5_addr_defined(hdr->man_dtable.table_addr)) { |
1384 | 0 | if (hdr->man_dtable.curr_root_rows == 0) { |
1385 | 0 | hsize_t dblock_size; /* Size of direct block on disk */ |
1386 | | |
1387 | | /* Check for I/O filters on this heap */ |
1388 | 0 | if (hdr->filter_len > 0) { |
1389 | | /* Set the dblock's size */ |
1390 | 0 | dblock_size = hdr->pline_root_direct_size; |
1391 | | |
1392 | | /* Reset the header's pipeline information */ |
1393 | 0 | hdr->pline_root_direct_size = 0; |
1394 | 0 | hdr->pline_root_direct_filter_mask = 0; |
1395 | 0 | } /* end if */ |
1396 | 0 | else |
1397 | 0 | dblock_size = hdr->man_dtable.cparam.start_block_size; |
1398 | | |
1399 | | /* Delete root direct block */ |
1400 | 0 | if (H5HF__man_dblock_delete(hdr->f, hdr->man_dtable.table_addr, dblock_size) < 0) |
1401 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root direct block"); |
1402 | 0 | } /* end if */ |
1403 | 0 | else { |
1404 | | /* Delete root indirect block */ |
1405 | 0 | if (H5HF__man_iblock_delete(hdr, hdr->man_dtable.table_addr, hdr->man_dtable.curr_root_rows, NULL, |
1406 | 0 | 0) < 0) |
1407 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, |
1408 | 0 | "unable to release fractal heap root indirect block"); |
1409 | 0 | } /* end else */ |
1410 | 0 | } /* end if */ |
1411 | | |
1412 | | /* Check for 'huge' objects in heap */ |
1413 | 0 | if (H5_addr_defined(hdr->huge_bt2_addr)) { |
1414 | | /* Delete huge objects in heap and their tracker */ |
1415 | 0 | if (H5HF__huge_delete(hdr) < 0) |
1416 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, |
1417 | 0 | "unable to release fractal heap 'huge' objects and tracker"); |
1418 | 0 | } /* end if */ |
1419 | | |
1420 | | /* Indicate that the heap header should be deleted & file space freed */ |
1421 | 0 | cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; |
1422 | |
|
1423 | 0 | done: |
1424 | | /* Unprotect the header with appropriate flags */ |
1425 | 0 | if (H5AC_unprotect(hdr->f, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, cache_flags) < 0) |
1426 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header"); |
1427 | |
|
1428 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1429 | 0 | } /* end H5HF__hdr_delete() */ |