1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://www.hdfgroup.org/licenses. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /*-------------------------------------------------------------------------
15 *
16 * Created: H5HFiblock.c
17 * Apr 10 2006
18 * Quincey Koziol
19 *
20 * Purpose: Indirect block routines for fractal heaps.
21 *
22 *-------------------------------------------------------------------------
23 */
24
25 /****************/
26 /* Module Setup */
27 /****************/
28
29 #include "H5HFmodule.h" /* This source code file is part of the H5HF module */
30
31 /***********/
32 /* Headers */
33 /***********/
34 #include "H5private.h" /* Generic Functions */
35 #include "H5Eprivate.h" /* Error handling */
36 #include "H5Fprivate.h" /* File access */
37 #include "H5HFpkg.h" /* Fractal heaps */
38 #include "H5MFprivate.h" /* File memory management */
39 #include "H5VMprivate.h" /* Vectors and arrays */
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 static herr_t H5HF__iblock_pin(H5HF_indirect_t *iblock);
57 static herr_t H5HF__iblock_unpin(H5HF_indirect_t *iblock);
58 static herr_t H5HF__man_iblock_root_halve(H5HF_indirect_t *root_iblock);
59 static herr_t H5HF__man_iblock_root_revert(H5HF_indirect_t *root_iblock);
60
61 /*********************/
62 /* Package Variables */
63 /*********************/
64
65 /* Declare a free list to manage the H5HF_indirect_t struct */
66 H5FL_DEFINE(H5HF_indirect_t);
67
68 /* Declare a free list to manage the H5HF_indirect_ent_t sequence information */
69 H5FL_SEQ_DEFINE(H5HF_indirect_ent_t);
70
71 /* Declare a free list to manage the H5HF_indirect_filt_ent_t sequence information */
72 H5FL_SEQ_DEFINE(H5HF_indirect_filt_ent_t);
73
74 /* Declare a free list to manage the H5HF_indirect_t * sequence information */
75 H5FL_SEQ_DEFINE(H5HF_indirect_ptr_t);
76
77 /*****************************/
78 /* Library Private Variables */
79 /*****************************/
80
81 /*******************/
82 /* Local Variables */
83 /*******************/
84
85 /*-------------------------------------------------------------------------
86 * Function: H5HF__iblock_pin
87 *
88 * Purpose: Pin an indirect block in memory
89 *
90 * Return: Non-negative on success/Negative on failure
91 *
92 * Programmer: Quincey Koziol
93 * Aug 17 2006
94 *
95 *-------------------------------------------------------------------------
96 */
97 static herr_t
H5HF__iblock_pin(H5HF_indirect_t * iblock)98 H5HF__iblock_pin(H5HF_indirect_t *iblock)
99 {
100 herr_t ret_value = SUCCEED; /* Return value */
101
102 FUNC_ENTER_STATIC
103
104 /* Sanity checks */
105 HDassert(iblock);
106
107 /* Mark block as un-evictable */
108 if (H5AC_pin_protected_entry(iblock) < 0)
109 HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin fractal heap indirect block")
110
111 /* If this indirect block has a parent, update it's child iblock pointer */
112 if (iblock->parent) {
113 H5HF_indirect_t *par_iblock = iblock->parent; /* Parent indirect block */
114 unsigned indir_idx; /* Index in parent's child iblock pointer array */
115
116 /* Sanity check */
117 HDassert(par_iblock->child_iblocks);
118 HDassert(iblock->par_entry >=
119 (iblock->hdr->man_dtable.max_direct_rows * iblock->hdr->man_dtable.cparam.width));
120
121 /* Compute index in parent's child iblock pointer array */
122 indir_idx = iblock->par_entry -
123 (iblock->hdr->man_dtable.max_direct_rows * iblock->hdr->man_dtable.cparam.width);
124
125 /* Set pointer to pinned indirect block in parent */
126 HDassert(par_iblock->child_iblocks[indir_idx] == NULL);
127 par_iblock->child_iblocks[indir_idx] = iblock;
128 } /* end if */
129 else {
130 /* Check for pinning the root indirect block */
131 if (iblock->block_off == 0) {
132 /* Sanity check - shouldn't be recursively pinning root indirect block */
133 HDassert(0 == (iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PINNED));
134
135 /* Check if we should set the root iblock pointer */
136 if (0 == iblock->hdr->root_iblock_flags) {
137 HDassert(NULL == iblock->hdr->root_iblock);
138 iblock->hdr->root_iblock = iblock;
139 } /* end if */
140
141 /* Indicate that the root indirect block is pinned */
142 iblock->hdr->root_iblock_flags |= H5HF_ROOT_IBLOCK_PINNED;
143 } /* end if */
144 } /* end if */
145
146 done:
147 FUNC_LEAVE_NOAPI(ret_value)
148 } /* end H5HF__iblock_pin() */
149
150 /*-------------------------------------------------------------------------
151 * Function: H5HF__iblock_unpin
152 *
153 * Purpose: Unpin an indirect block in the metadata cache
154 *
155 * Return: Non-negative on success/Negative on failure
156 *
157 * Programmer: Quincey Koziol
158 * Aug 17 2006
159 *
160 *-------------------------------------------------------------------------
161 */
162 static herr_t
H5HF__iblock_unpin(H5HF_indirect_t * iblock)163 H5HF__iblock_unpin(H5HF_indirect_t *iblock)
164 {
165 herr_t ret_value = SUCCEED; /* Return value */
166
167 FUNC_ENTER_STATIC
168
169 /* Sanity check */
170 HDassert(iblock);
171
172 /* Mark block as evictable again */
173 if (H5AC_unpin_entry(iblock) < 0)
174 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap indirect block")
175
176 done:
177 FUNC_LEAVE_NOAPI(ret_value)
178 } /* end H5HF__iblock_unpin() */
179
180 /*-------------------------------------------------------------------------
181 * Function: H5HF__iblock_incr
182 *
183 * Purpose: Increment reference count on shared indirect block
184 *
185 * Return: Non-negative on success/Negative on failure
186 *
187 * Programmer: Quincey Koziol
188 * Mar 27 2006
189 *
190 *-------------------------------------------------------------------------
191 */
192 herr_t
H5HF__iblock_incr(H5HF_indirect_t * iblock)193 H5HF__iblock_incr(H5HF_indirect_t *iblock)
194 {
195 herr_t ret_value = SUCCEED; /* Return value */
196
197 FUNC_ENTER_PACKAGE
198
199 /* Sanity checks */
200 HDassert(iblock);
201 HDassert(iblock->block_off == 0 || iblock->parent);
202
203 /* Mark block as un-evictable when a child block is depending on it */
204 if (iblock->rc == 0)
205 if (H5HF__iblock_pin(iblock) < 0)
206 HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin fractal heap indirect block")
207
208 /* Increment reference count on shared indirect block */
209 iblock->rc++;
210
211 done:
212 FUNC_LEAVE_NOAPI(ret_value)
213 } /* end H5HF__iblock_incr() */
214
215 /*-------------------------------------------------------------------------
216 * Function: H5HF__iblock_decr
217 *
218 * Purpose: Decrement reference count on shared indirect block
219 *
220 * Return: Non-negative on success/Negative on failure
221 *
222 * Programmer: Quincey Koziol
223 * Mar 27 2006
224 *
225 *-------------------------------------------------------------------------
226 */
227 herr_t
H5HF__iblock_decr(H5HF_indirect_t * iblock)228 H5HF__iblock_decr(H5HF_indirect_t *iblock)
229 {
230 herr_t ret_value = SUCCEED; /* Return value */
231
232 FUNC_ENTER_PACKAGE
233
234 /* Sanity check */
235 HDassert(iblock);
236
237 /* Decrement reference count on shared indirect block */
238 iblock->rc--;
239
240 /* Check for last reference to block */
241 if (iblock->rc == 0) {
242
243 /* If this indirect block has a parent, reset it's child iblock pointer */
244 if (iblock->parent) {
245 H5HF_indirect_t *par_iblock = iblock->parent; /* Parent indirect block */
246 unsigned indir_idx; /* Index in parent's child iblock pointer array */
247
248 /* Sanity check */
249 HDassert(par_iblock->child_iblocks);
250 HDassert(iblock->par_entry >=
251 (iblock->hdr->man_dtable.max_direct_rows * iblock->hdr->man_dtable.cparam.width));
252
253 /* Compute index in parent's child iblock pointer array */
254 indir_idx = iblock->par_entry -
255 (iblock->hdr->man_dtable.max_direct_rows * iblock->hdr->man_dtable.cparam.width);
256
257 /* Reset pointer to pinned child indirect block in parent */
258 HDassert(par_iblock->child_iblocks[indir_idx]);
259 par_iblock->child_iblocks[indir_idx] = NULL;
260 } /* end if */
261 else {
262 /* Check for root indirect block */
263 if (iblock->block_off == 0) {
264 /* Sanity check - shouldn't be recursively unpinning root indirect block */
265 HDassert(iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PINNED);
266
267 /* Check if we should reset the root iblock pointer */
268 if (H5HF_ROOT_IBLOCK_PINNED == iblock->hdr->root_iblock_flags) {
269 HDassert(NULL != iblock->hdr->root_iblock);
270 iblock->hdr->root_iblock = NULL;
271 } /* end if */
272
273 /* Indicate that the root indirect block is unpinned */
274 iblock->hdr->root_iblock_flags &= (unsigned)(~(H5HF_ROOT_IBLOCK_PINNED));
275 } /* end if */
276 } /* end else */
277
278 /* Check if the block is still in the cache */
279 if (!iblock->removed_from_cache) {
280 /* Unpin the indirect block, making it evictable again */
281 if (H5HF__iblock_unpin(iblock) < 0)
282 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap indirect block")
283 } /* end if */
284 else {
285 /* Destroy the indirect block */
286 if (H5HF__man_iblock_dest(iblock) < 0)
287 HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block")
288 } /* end else */
289 } /* end if */
290
291 done:
292 FUNC_LEAVE_NOAPI(ret_value)
293 } /* end H5HF__iblock_decr() */
294
295 /*-------------------------------------------------------------------------
296 * Function: H5HF__iblock_dirty
297 *
298 * Purpose: Mark indirect block as dirty
299 *
300 * Return: Non-negative on success/Negative on failure
301 *
302 * Programmer: Quincey Koziol
303 * Mar 21 2006
304 *
305 *-------------------------------------------------------------------------
306 */
307 herr_t
H5HF__iblock_dirty(H5HF_indirect_t * iblock)308 H5HF__iblock_dirty(H5HF_indirect_t *iblock)
309 {
310 herr_t ret_value = SUCCEED; /* Return value */
311
312 FUNC_ENTER_PACKAGE
313
314 /* Sanity check */
315 HDassert(iblock);
316
317 /* Mark indirect block as dirty in cache */
318 if (H5AC_mark_entry_dirty(iblock) < 0)
319 HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap indirect block as dirty")
320
321 done:
322 FUNC_LEAVE_NOAPI(ret_value)
323 } /* end H5HF__iblock_dirty() */
324
325 /*-------------------------------------------------------------------------
326 * Function: H5HF__man_iblock_root_create
327 *
328 * Purpose: Create root indirect block
329 *
330 * Return: SUCCEED/FAIL
331 *
332 * Programmer: Quincey Koziol
333 * May 2 2006
334 *
335 *-------------------------------------------------------------------------
336 */
337 herr_t
H5HF__man_iblock_root_create(H5HF_hdr_t * hdr,size_t min_dblock_size)338 H5HF__man_iblock_root_create(H5HF_hdr_t *hdr, size_t min_dblock_size)
339 {
340 H5HF_indirect_t *iblock; /* Pointer to indirect block */
341 haddr_t iblock_addr; /* Indirect block's address */
342 hsize_t acc_dblock_free; /* Accumulated free space in direct blocks */
343 hbool_t have_direct_block; /* Flag to indicate a direct block already exists */
344 hbool_t did_protect; /* Whether we protected the indirect block or not */
345 unsigned nrows; /* Number of rows for root indirect block */
346 unsigned u; /* Local index variable */
347 herr_t ret_value = SUCCEED; /* Return value */
348
349 FUNC_ENTER_PACKAGE
350
351 /* Check for allocating entire root indirect block initially */
352 if (hdr->man_dtable.cparam.start_root_rows == 0)
353 nrows = hdr->man_dtable.max_root_rows;
354 else {
355 unsigned rows_needed; /* Number of rows needed to get to direct block size */
356 unsigned block_row_off; /* Row offset from larger block sizes */
357
358 nrows = hdr->man_dtable.cparam.start_root_rows;
359
360 block_row_off = H5VM_log2_of2((uint32_t)min_dblock_size) -
361 H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size);
362 if (block_row_off > 0)
363 block_row_off++; /* Account for the pair of initial rows of the initial block size */
364 rows_needed = 1 + block_row_off;
365 if (nrows < rows_needed)
366 nrows = rows_needed;
367 } /* end else */
368
369 /* Allocate root indirect block */
370 if (H5HF__man_iblock_create(hdr, NULL, 0, nrows, hdr->man_dtable.max_root_rows, &iblock_addr) < 0)
371 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block")
372
373 /* Move current direct block (used as root) into new indirect block */
374
375 /* Lock new indirect block */
376 if (NULL == (iblock = H5HF__man_iblock_protect(hdr, iblock_addr, nrows, NULL, 0, FALSE,
377 H5AC__NO_FLAGS_SET, &did_protect)))
378 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
379
380 /* Check if there's already a direct block as root) */
381 have_direct_block = H5F_addr_defined(hdr->man_dtable.table_addr);
382 if (have_direct_block) {
383 H5HF_direct_t *dblock; /* Pointer to direct block to query */
384
385 /* Lock first (root) direct block */
386 if (NULL == (dblock = H5HF__man_dblock_protect(hdr, hdr->man_dtable.table_addr,
387 hdr->man_dtable.cparam.start_block_size, NULL, 0,
388 H5AC__NO_FLAGS_SET)))
389 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block")
390
391 /* Attach direct block to new root indirect block */
392 dblock->parent = iblock;
393 dblock->par_entry = 0;
394
395 /* Destroy flush dependency between direct block and header */
396 if (H5AC_destroy_flush_dependency(dblock->fd_parent, dblock) < 0)
397 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
398 dblock->fd_parent = NULL;
399
400 /* Create flush dependency between direct block and new root indirect block */
401 if (H5AC_create_flush_dependency(iblock, dblock) < 0)
402 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
403 dblock->fd_parent = iblock;
404
405 if (H5HF__man_iblock_attach(iblock, 0, hdr->man_dtable.table_addr) < 0)
406 HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL,
407 "can't attach root direct block to parent indirect block")
408
409 /* Check for I/O filters on this heap */
410 if (hdr->filter_len > 0) {
411 /* Set the pipeline filter information from the header */
412 iblock->filt_ents[0].size = hdr->pline_root_direct_size;
413 iblock->filt_ents[0].filter_mask = hdr->pline_root_direct_filter_mask;
414
415 /* Reset the header's pipeline information */
416 hdr->pline_root_direct_size = 0;
417 hdr->pline_root_direct_filter_mask = 0;
418 } /* end if */
419
420 /* Scan free space sections to set any 'parent' pointers to new indirect block */
421 if (H5HF__space_create_root(hdr, iblock) < 0)
422 HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL,
423 "can't set free space section info to new root indirect block")
424
425 /* Unlock first (previously the root) direct block */
426 if (H5AC_unprotect(hdr->f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, dblock,
427 H5AC__NO_FLAGS_SET) < 0)
428 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
429 dblock = NULL;
430 } /* end if */
431
432 /* Start iterator at correct location */
433 if (H5HF__hdr_start_iter(hdr, iblock,
434 (hsize_t)(have_direct_block ? hdr->man_dtable.cparam.start_block_size : 0),
435 have_direct_block) < 0)
436 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize block iterator")
437
438 /* Check for skipping over direct blocks, in order to get to large enough block */
439 if (min_dblock_size > hdr->man_dtable.cparam.start_block_size)
440 /* Add skipped blocks to heap's free space */
441 if (H5HF__hdr_skip_blocks(hdr, iblock, have_direct_block,
442 ((nrows - 1) * hdr->man_dtable.cparam.width) - have_direct_block) < 0)
443 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space")
444
445 /* Mark indirect block as modified */
446 if (H5HF__iblock_dirty(iblock) < 0)
447 HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
448
449 /* Unprotect root indirect block (it's pinned by the iterator though) */
450 if (H5HF__man_iblock_unprotect(iblock, H5AC__DIRTIED_FLAG, did_protect) < 0)
451 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
452 iblock = NULL;
453
454 /* Point heap header at new indirect block */
455 hdr->man_dtable.curr_root_rows = nrows;
456 hdr->man_dtable.table_addr = iblock_addr;
457
458 /* Compute free space in direct blocks referenced from entries in root indirect block */
459 acc_dblock_free = 0;
460 for (u = 0; u < nrows; u++)
461 acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[u] * hdr->man_dtable.cparam.width;
462
463 /* Account for potential initial direct block */
464 if (have_direct_block)
465 acc_dblock_free -= hdr->man_dtable.row_tot_dblock_free[0];
466
467 /* Extend heap to cover new root indirect block */
468 if (H5HF__hdr_adjust_heap(hdr, hdr->man_dtable.row_block_off[nrows], (hssize_t)acc_dblock_free) < 0)
469 HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
470
471 done:
472 FUNC_LEAVE_NOAPI(ret_value)
473 } /* end H5HF__man_iblock_root_create() */
474
475 /*-------------------------------------------------------------------------
476 * Function: H5HF__man_iblock_root_double
477 *
478 * Purpose: Double size of root indirect block
479 *
480 * Return: SUCCEED/FAIL
481 *
482 * Programmer: Quincey Koziol
483 * Apr 17 2006
484 *
485 *-------------------------------------------------------------------------
486 */
487 herr_t
H5HF__man_iblock_root_double(H5HF_hdr_t * hdr,size_t min_dblock_size)488 H5HF__man_iblock_root_double(H5HF_hdr_t *hdr, size_t min_dblock_size)
489 {
490 H5HF_indirect_t *iblock; /* Pointer to root indirect block */
491 haddr_t new_addr; /* New address of indirect block */
492 hsize_t acc_dblock_free; /* Accumulated free space in direct blocks */
493 hsize_t next_size; /* The previous value of the "next size" for the new block iterator */
494 hsize_t old_iblock_size; /* Old size of indirect block */
495 unsigned next_row; /* The next row to allocate block in */
496 unsigned next_entry; /* The previous value of the "next entry" for the new block iterator */
497 unsigned new_next_entry = 0; /* The new value of the "next entry" for the new block iterator */
498 unsigned min_nrows = 0; /* Min. # of direct rows */
499 unsigned old_nrows; /* Old # of rows */
500 unsigned new_nrows; /* New # of rows */
501 hbool_t skip_direct_rows = FALSE; /* Whether we are skipping direct rows */
502 size_t u; /* Local index variable */
503 herr_t ret_value = SUCCEED; /* Return value */
504
505 FUNC_ENTER_PACKAGE
506
507 /* Get "new block" iterator information */
508 if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
509 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
510 next_size = hdr->man_dtable.row_block_size[next_row];
511
512 /* Make certain the iterator is at the root indirect block */
513 HDassert(iblock->parent == NULL);
514 HDassert(iblock->block_off == 0);
515
516 /* Keep this for later */
517 old_nrows = iblock->nrows;
518
519 /* Check for skipping over direct block rows */
520 if (iblock->nrows < hdr->man_dtable.max_direct_rows && min_dblock_size > next_size) {
521 /* Sanity check */
522 HDassert(min_dblock_size > hdr->man_dtable.cparam.start_block_size);
523
524 /* Set flag */
525 skip_direct_rows = TRUE;
526
527 /* Make certain we allocate at least the required row for the block requested */
528 min_nrows = 1 + H5HF__dtable_size_to_row(&hdr->man_dtable, min_dblock_size);
529
530 /* Set the information for the next block, of the appropriate size */
531 new_next_entry = (min_nrows - 1) * hdr->man_dtable.cparam.width;
532 } /* end if */
533
534 /* Compute new # of rows in indirect block */
535 new_nrows = MAX(min_nrows, MIN(2 * iblock->nrows, iblock->max_rows));
536
537 /* Check if the indirect block is NOT currently allocated in temp. file space */
538 /* (temp. file space does not need to be freed) */
539 if (!H5F_IS_TMP_ADDR(hdr->f, iblock->addr))
540 /* Free previous indirect block disk space */
541 if (H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_IBLOCK, iblock->addr, (hsize_t)iblock->size) < 0)
542 HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block file space")
543
544 /* Compute size of buffer needed for new indirect block */
545 iblock->nrows = new_nrows;
546 old_iblock_size = iblock->size;
547 iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows);
548
549 /* Allocate [temporary] space for the new indirect block on disk */
550 if (H5F_USE_TMP_SPACE(hdr->f)) {
551 if (HADDR_UNDEF == (new_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)iblock->size)))
552 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
553 } /* end if */
554 else {
555 if (HADDR_UNDEF == (new_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_IBLOCK, (hsize_t)iblock->size)))
556 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
557 } /* end else */
558
559 /* Resize pinned indirect block in the cache, if its changed size */
560 if (old_iblock_size != iblock->size) {
561 if (H5AC_resize_entry(iblock, (size_t)iblock->size) < 0)
562 HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize fractal heap indirect block")
563 } /* end if */
564
565 /* Move object in cache, if it actually was relocated */
566 if (H5F_addr_ne(iblock->addr, new_addr)) {
567 if (H5AC_move_entry(hdr->f, H5AC_FHEAP_IBLOCK, iblock->addr, new_addr) < 0)
568 HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move fractal heap root indirect block")
569 iblock->addr = new_addr;
570 } /* end if */
571
572 /* Re-allocate child block entry array */
573 if (NULL == (iblock->ents = H5FL_SEQ_REALLOC(H5HF_indirect_ent_t, iblock->ents,
574 (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
575 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for direct entries")
576
577 /* Check for skipping over rows and add free section for skipped rows */
578 if (skip_direct_rows)
579 /* Add skipped blocks to heap's free space */
580 if (H5HF__hdr_skip_blocks(hdr, iblock, next_entry, (new_next_entry - next_entry)) < 0)
581 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space")
582
583 /* Initialize new direct block entries in rows added */
584 acc_dblock_free = 0;
585 for (u = (old_nrows * hdr->man_dtable.cparam.width); u < (iblock->nrows * hdr->man_dtable.cparam.width);
586 u++) {
587 unsigned row = (unsigned)(u / hdr->man_dtable.cparam.width); /* Row for current entry */
588
589 iblock->ents[u].addr = HADDR_UNDEF;
590 acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[row];
591 } /* end for */
592
593 /* Check for needing to re-allocate filtered entry array */
594 if (hdr->filter_len > 0 && old_nrows < hdr->man_dtable.max_direct_rows) {
595 unsigned dir_rows; /* Number of direct rows in this indirect block */
596
597 /* Compute the number of direct rows for this indirect block */
598 dir_rows = MIN(iblock->nrows, hdr->man_dtable.max_direct_rows);
599 HDassert(dir_rows > old_nrows);
600
601 /* Re-allocate filtered direct block entry array */
602 if (NULL == (iblock->filt_ents = H5FL_SEQ_REALLOC(H5HF_indirect_filt_ent_t, iblock->filt_ents,
603 (size_t)(dir_rows * hdr->man_dtable.cparam.width))))
604 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for filtered direct entries")
605
606 /* Initialize new entries allocated */
607 for (u = (old_nrows * hdr->man_dtable.cparam.width); u < (dir_rows * hdr->man_dtable.cparam.width);
608 u++) {
609 iblock->filt_ents[u].size = 0;
610 iblock->filt_ents[u].filter_mask = 0;
611 } /* end for */
612 } /* end if */
613
614 /* Check for needing to re-allocate child iblock pointer array */
615 if (iblock->nrows > hdr->man_dtable.max_direct_rows) {
616 unsigned indir_rows; /* Number of indirect rows in this indirect block */
617 unsigned old_indir_rows; /* Previous number of indirect rows in this indirect block */
618
619 /* Compute the number of direct rows for this indirect block */
620 indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows;
621
622 /* Re-allocate child indirect block array */
623 if (NULL ==
624 (iblock->child_iblocks = H5FL_SEQ_REALLOC(H5HF_indirect_ptr_t, iblock->child_iblocks,
625 (size_t)(indir_rows * hdr->man_dtable.cparam.width))))
626 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for filtered direct entries")
627
628 /* Compute the previous # of indirect rows in this block */
629 if (old_nrows < hdr->man_dtable.max_direct_rows)
630 old_indir_rows = 0;
631 else
632 old_indir_rows = old_nrows - hdr->man_dtable.max_direct_rows;
633
634 /* Initialize new entries allocated */
635 for (u = (old_indir_rows * hdr->man_dtable.cparam.width);
636 u < (indir_rows * hdr->man_dtable.cparam.width); u++)
637 iblock->child_iblocks[u] = NULL;
638 } /* end if */
639
640 /* Mark indirect block as dirty */
641 if (H5HF__iblock_dirty(iblock) < 0)
642 HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
643
644 /* Update other shared header info */
645 hdr->man_dtable.curr_root_rows = new_nrows;
646 hdr->man_dtable.table_addr = new_addr;
647
648 /* Extend heap to cover new root indirect block */
649 if (H5HF__hdr_adjust_heap(hdr, 2 * hdr->man_dtable.row_block_off[new_nrows - 1],
650 (hssize_t)acc_dblock_free) < 0)
651 HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
652
653 done:
654 FUNC_LEAVE_NOAPI(ret_value)
655 } /* end H5HF__man_iblock_root_double() */
656
657 /*-------------------------------------------------------------------------
658 * Function: H5HF__man_iblock_root_halve
659 *
660 * Purpose: Halve size of root indirect block
661 *
662 * Return: SUCCEED/FAIL
663 *
664 * Programmer: Quincey Koziol
665 * Jun 12 2006
666 *
667 *-------------------------------------------------------------------------
668 */
669 static herr_t
H5HF__man_iblock_root_halve(H5HF_indirect_t * iblock)670 H5HF__man_iblock_root_halve(H5HF_indirect_t *iblock)
671 {
672 H5HF_hdr_t *hdr = iblock->hdr; /* Pointer to heap header */
673 haddr_t new_addr; /* New address of indirect block */
674 hsize_t acc_dblock_free; /* Accumulated free space in direct blocks */
675 hsize_t old_size; /* Old size of indirect block */
676 unsigned max_child_row; /* Row for max. child entry */
677 unsigned old_nrows; /* Old # of rows */
678 unsigned new_nrows; /* New # of rows */
679 unsigned u; /* Local index variable */
680 herr_t ret_value = SUCCEED; /* Return value */
681
682 FUNC_ENTER_STATIC
683
684 /* Sanity check */
685 HDassert(iblock);
686 HDassert(iblock->parent == NULL);
687 HDassert(hdr);
688
689 /* Compute maximum row used by child of indirect block */
690 max_child_row = iblock->max_child / hdr->man_dtable.cparam.width;
691
692 /* Compute new # of rows in root indirect block */
693 new_nrows = (unsigned)1 << (1 + H5VM_log2_gen((uint64_t)max_child_row));
694
695 /* Check if the indirect block is NOT currently allocated in temp. file space */
696 /* (temp. file space does not need to be freed) */
697 if (!H5F_IS_TMP_ADDR(hdr->f, iblock->addr))
698 /* Free previous indirect block disk space */
699 if (H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_IBLOCK, iblock->addr, (hsize_t)iblock->size) < 0)
700 HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block file space")
701
702 /* Compute free space in rows to delete */
703 acc_dblock_free = 0;
704 for (u = new_nrows; u < iblock->nrows; u++)
705 acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[u] * hdr->man_dtable.cparam.width;
706
707 /* Compute size of buffer needed for new indirect block */
708 old_nrows = iblock->nrows;
709 iblock->nrows = new_nrows;
710 old_size = iblock->size;
711 iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows);
712
713 /* Allocate [temporary] space for the new indirect block on disk */
714 if (H5F_USE_TMP_SPACE(hdr->f)) {
715 if (HADDR_UNDEF == (new_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)iblock->size)))
716 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
717 } /* end if */
718 else {
719 if (HADDR_UNDEF == (new_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_IBLOCK, (hsize_t)iblock->size)))
720 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
721 } /* end else */
722
723 /* Resize pinned indirect block in the cache, if it has changed size */
724 if (old_size != iblock->size) {
725 if (H5AC_resize_entry(iblock, (size_t)iblock->size) < 0)
726 HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize fractal heap indirect block")
727 } /* end if */
728
729 /* Move object in cache, if it actually was relocated */
730 if (H5F_addr_ne(iblock->addr, new_addr)) {
731 if (H5AC_move_entry(hdr->f, H5AC_FHEAP_IBLOCK, iblock->addr, new_addr) < 0)
732 HGOTO_ERROR(H5E_HEAP, H5E_CANTSPLIT, FAIL, "unable to move fractal heap root indirect block")
733 iblock->addr = new_addr;
734 } /* end if */
735
736 /* Re-allocate child block entry array */
737 if (NULL == (iblock->ents = H5FL_SEQ_REALLOC(H5HF_indirect_ent_t, iblock->ents,
738 (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
739 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct entries")
740
741 /* Check for needing to re-allocate filtered entry array */
742 if (hdr->filter_len > 0 && new_nrows < hdr->man_dtable.max_direct_rows) {
743 /* Re-allocate filtered direct block entry array */
744 if (NULL ==
745 (iblock->filt_ents = H5FL_SEQ_REALLOC(H5HF_indirect_filt_ent_t, iblock->filt_ents,
746 (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
747 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for filtered direct entries")
748 } /* end if */
749
750 /* Check for needing to re-allocate child iblock pointer array */
751 if (old_nrows > hdr->man_dtable.max_direct_rows) {
752 /* Check for shrinking away child iblock pointer array */
753 if (iblock->nrows > hdr->man_dtable.max_direct_rows) {
754 unsigned indir_rows; /* Number of indirect rows in this indirect block */
755
756 /* Compute the number of direct rows for this indirect block */
757 indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows;
758
759 /* Re-allocate child indirect block array */
760 if (NULL == (iblock->child_iblocks =
761 H5FL_SEQ_REALLOC(H5HF_indirect_ptr_t, iblock->child_iblocks,
762 (size_t)(indir_rows * hdr->man_dtable.cparam.width))))
763 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL,
764 "memory allocation failed for filtered direct entries")
765 } /* end if */
766 else
767 iblock->child_iblocks =
768 (H5HF_indirect_ptr_t *)H5FL_SEQ_FREE(H5HF_indirect_ptr_t, iblock->child_iblocks);
769 } /* end if */
770
771 /* Mark indirect block as dirty */
772 if (H5HF__iblock_dirty(iblock) < 0)
773 HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
774
775 /* Update other shared header info */
776 hdr->man_dtable.curr_root_rows = new_nrows;
777 hdr->man_dtable.table_addr = new_addr;
778
779 /* Shrink heap to only cover new root indirect block */
780 if (H5HF__hdr_adjust_heap(hdr, 2 * hdr->man_dtable.row_block_off[new_nrows - 1],
781 -(hssize_t)acc_dblock_free) < 0)
782 HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce space to cover root direct block")
783
784 done:
785 FUNC_LEAVE_NOAPI(ret_value)
786 } /* end H5HF__man_iblock_root_halve() */
787
788 /*-------------------------------------------------------------------------
789 * Function: H5HF__man_iblock_root_revert
790 *
791 * Purpose: Revert root indirect block back to root direct block
792 *
793 * Note: Any sections left pointing to the old root indirect block
794 * will be cleaned up by the free space manager
795 *
796 * Return: SUCCEED/FAIL
797 *
798 * Programmer: Quincey Koziol
799 * May 31 2006
800 *
801 *-------------------------------------------------------------------------
802 */
803 static herr_t
H5HF__man_iblock_root_revert(H5HF_indirect_t * root_iblock)804 H5HF__man_iblock_root_revert(H5HF_indirect_t *root_iblock)
805 {
806 H5HF_hdr_t * hdr; /* Pointer to heap's header */
807 H5HF_direct_t *dblock = NULL; /* Pointer to new root indirect block */
808 haddr_t dblock_addr; /* Direct block's address in the file */
809 size_t dblock_size; /* Direct block's size */
810 herr_t ret_value = SUCCEED; /* Return value */
811
812 FUNC_ENTER_STATIC
813
814 /*
815 * Check arguments.
816 */
817 HDassert(root_iblock);
818
819 /* Set up local convenience variables */
820 hdr = root_iblock->hdr;
821 dblock_addr = root_iblock->ents[0].addr;
822 dblock_size = hdr->man_dtable.cparam.start_block_size;
823
824 /* Get pointer to last direct block */
825 if (NULL == (dblock = H5HF__man_dblock_protect(hdr, dblock_addr, dblock_size, root_iblock, 0,
826 H5AC__NO_FLAGS_SET)))
827 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block")
828 HDassert(dblock->parent == root_iblock);
829 HDassert(dblock->par_entry == 0);
830
831 /* Check for I/O filters on this heap */
832 if (hdr->filter_len > 0) {
833 /* Set the header's pipeline information from the indirect block */
834 hdr->pline_root_direct_size = root_iblock->filt_ents[0].size;
835 hdr->pline_root_direct_filter_mask = root_iblock->filt_ents[0].filter_mask;
836 } /* end if */
837
838 /* Destroy flush dependency between old root iblock and new root direct block */
839 if (H5AC_destroy_flush_dependency(dblock->fd_parent, dblock) < 0)
840 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
841 dblock->fd_parent = NULL;
842
843 /* Detach direct block from parent */
844 if (H5HF__man_iblock_detach(dblock->parent, 0) < 0)
845 HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach direct block from parent indirect block")
846 dblock->parent = NULL;
847 dblock->par_entry = 0;
848
849 /* Create flush dependency between header and new root direct block */
850 if (H5AC_create_flush_dependency(hdr, dblock) < 0)
851 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
852 dblock->fd_parent = hdr;
853
854 /* Point root at direct block */
855 hdr->man_dtable.curr_root_rows = 0;
856 hdr->man_dtable.table_addr = dblock_addr;
857
858 /* Reset 'next block' iterator */
859 if (H5HF__hdr_reset_iter(hdr, (hsize_t)dblock_size) < 0)
860 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator")
861
862 /* Extend heap to just cover first direct block */
863 if (H5HF__hdr_adjust_heap(hdr, (hsize_t)hdr->man_dtable.cparam.start_block_size,
864 (hssize_t)hdr->man_dtable.row_tot_dblock_free[0]) < 0)
865 HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
866
867 /* Scan free space sections to reset any 'parent' pointers */
868 if (H5HF__space_revert_root(hdr) < 0)
869 HGOTO_ERROR(H5E_HEAP, H5E_CANTRESET, FAIL, "can't reset free space section info")
870
871 done:
872 if (dblock && H5AC_unprotect(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
873 HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
874
875 FUNC_LEAVE_NOAPI(ret_value)
876 } /* end H5HF__man_iblock_root_revert() */
877
878 /*-------------------------------------------------------------------------
879 * Function: H5HF__man_iblock_alloc_row
880 *
881 * Purpose: Allocate a "single" section for an object, out of a
882 * "row" section.
883 *
884 * Note: Creates necessary direct & indirect blocks
885 *
886 * Return: Non-negative on success/Negative on failure
887 *
888 * Programmer: Quincey Koziol
889 * July 6 2006
890 *
891 *-------------------------------------------------------------------------
892 */
893 herr_t
H5HF__man_iblock_alloc_row(H5HF_hdr_t * hdr,H5HF_free_section_t ** sec_node)894 H5HF__man_iblock_alloc_row(H5HF_hdr_t *hdr, H5HF_free_section_t **sec_node)
895 {
896 H5HF_indirect_t * iblock = NULL; /* Pointer to indirect block */
897 H5HF_free_section_t *old_sec_node = *sec_node; /* Pointer to old indirect section node */
898 unsigned dblock_entry; /* Entry for direct block */
899 hbool_t iblock_held = FALSE; /* Flag to indicate that indirect block is held */
900 herr_t ret_value = SUCCEED; /* Return value */
901
902 FUNC_ENTER_PACKAGE
903
904 /*
905 * Check arguments.
906 */
907 HDassert(hdr);
908 HDassert(sec_node && old_sec_node);
909 HDassert(old_sec_node->u.row.row < hdr->man_dtable.max_direct_rows);
910
911 /* Check for serialized row section, or serialized / deleted indirect
912 * section under it. */
913 if (old_sec_node->sect_info.state == H5FS_SECT_SERIALIZED ||
914 (H5FS_SECT_SERIALIZED == old_sec_node->u.row.under->sect_info.state) ||
915 (TRUE == old_sec_node->u.row.under->u.indirect.u.iblock->removed_from_cache))
916 /* Revive row and / or indirect section */
917 if (H5HF__sect_row_revive(hdr, old_sec_node) < 0)
918 HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
919
920 /* Get a pointer to the indirect block covering the section */
921 if (NULL == (iblock = H5HF__sect_row_get_iblock(old_sec_node)))
922 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve indirect block for row section")
923
924 /* Hold indirect block in memory, until direct block can point to it */
925 if (H5HF__iblock_incr(iblock) < 0)
926 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
927 iblock_held = TRUE;
928
929 /* Reduce (& possibly re-add) 'row' section */
930 if (H5HF__sect_row_reduce(hdr, old_sec_node, &dblock_entry) < 0)
931 HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce row section node")
932
933 /* Create direct block & single section */
934 if (H5HF__man_dblock_create(hdr, iblock, dblock_entry, NULL, sec_node) < 0)
935 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
936
937 done:
938 /* Release hold on indirect block */
939 if (iblock_held)
940 if (H5HF__iblock_decr(iblock) < 0)
941 HDONE_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL,
942 "can't decrement reference count on shared indirect block")
943
944 FUNC_LEAVE_NOAPI(ret_value)
945 } /* end H5HF__man_iblock_alloc_row() */
946
947 /*-------------------------------------------------------------------------
948 * Function: H5HF__man_iblock_create
949 *
950 * Purpose: Allocate & initialize a managed indirect block
951 *
952 * Return: SUCCEED/FAIL
953 *
954 * Programmer: Quincey Koziol
955 * Mar 6 2006
956 *
957 *-------------------------------------------------------------------------
958 */
959 herr_t
H5HF__man_iblock_create(H5HF_hdr_t * hdr,H5HF_indirect_t * par_iblock,unsigned par_entry,unsigned nrows,unsigned max_rows,haddr_t * addr_p)960 H5HF__man_iblock_create(H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblock, unsigned par_entry, unsigned nrows,
961 unsigned max_rows, haddr_t *addr_p)
962 {
963 H5HF_indirect_t *iblock = NULL; /* Pointer to indirect block */
964 size_t u; /* Local index variable */
965 herr_t ret_value = SUCCEED; /* Return value */
966
967 FUNC_ENTER_PACKAGE
968
969 /*
970 * Check arguments.
971 */
972 HDassert(hdr);
973 HDassert(nrows > 0);
974 HDassert(addr_p);
975
976 /*
977 * Allocate file and memory data structures.
978 */
979 if (NULL == (iblock = H5FL_MALLOC(H5HF_indirect_t)))
980 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
981 "memory allocation failed for fractal heap indirect block")
982
983 /* Reset the metadata cache info for the heap header */
984 HDmemset(&iblock->cache_info, 0, sizeof(H5AC_info_t));
985
986 /* Share common heap information */
987 iblock->hdr = hdr;
988 if (H5HF__hdr_incr(hdr) < 0)
989 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header")
990
991 /* Set info for indirect block */
992 iblock->rc = 0;
993 iblock->nrows = nrows;
994 iblock->max_rows = max_rows;
995 iblock->removed_from_cache = FALSE;
996
997 /* Compute size of buffer needed for indirect block */
998 iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows);
999
1000 /* Allocate child block entry array */
1001 if (NULL == (iblock->ents = H5FL_SEQ_MALLOC(H5HF_indirect_ent_t,
1002 (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
1003 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for block entries")
1004
1005 /* Initialize indirect block entry tables */
1006 for (u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++)
1007 iblock->ents[u].addr = HADDR_UNDEF;
1008
1009 /* Check for I/O filters to apply to this heap */
1010 if (hdr->filter_len > 0) {
1011 unsigned dir_rows; /* Number of direct rows in this indirect block */
1012
1013 /* Compute the number of direct rows for this indirect block */
1014 dir_rows = MIN(iblock->nrows, hdr->man_dtable.max_direct_rows);
1015
1016 /* Allocate & initialize indirect block filtered entry array */
1017 if (NULL == (iblock->filt_ents = H5FL_SEQ_CALLOC(H5HF_indirect_filt_ent_t,
1018 (size_t)(dir_rows * hdr->man_dtable.cparam.width))))
1019 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for block entries")
1020 } /* end if */
1021 else
1022 iblock->filt_ents = NULL;
1023
1024 /* Check if we have any indirect block children */
1025 if (iblock->nrows > hdr->man_dtable.max_direct_rows) {
1026 unsigned indir_rows; /* Number of indirect rows in this indirect block */
1027
1028 /* Compute the number of indirect rows for this indirect block */
1029 indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows;
1030
1031 /* Allocate & initialize child indirect block pointer array */
1032 if (NULL == (iblock->child_iblocks = H5FL_SEQ_CALLOC(
1033 H5HF_indirect_ptr_t, (size_t)(indir_rows * hdr->man_dtable.cparam.width))))
1034 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for block entries")
1035 } /* end if */
1036 else
1037 iblock->child_iblocks = NULL;
1038
1039 /* Allocate [temporary] space for the indirect block on disk */
1040 if (H5F_USE_TMP_SPACE(hdr->f)) {
1041 if (HADDR_UNDEF == (*addr_p = H5MF_alloc_tmp(hdr->f, (hsize_t)iblock->size)))
1042 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
1043 "file allocation failed for fractal heap indirect block")
1044 } /* end if */
1045 else {
1046 if (HADDR_UNDEF == (*addr_p = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_IBLOCK, (hsize_t)iblock->size)))
1047 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
1048 "file allocation failed for fractal heap indirect block")
1049 } /* end else */
1050 iblock->addr = *addr_p;
1051
1052 /* Attach to parent indirect block, if there is one */
1053 iblock->parent = par_iblock;
1054 iblock->par_entry = par_entry;
1055 if (iblock->parent) {
1056 /* Attach new block to parent */
1057 if (H5HF__man_iblock_attach(iblock->parent, par_entry, *addr_p) < 0)
1058 HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL,
1059 "can't attach indirect block to parent indirect block")
1060
1061 /* Compute the indirect block's offset in the heap's address space */
1062 /* (based on parent's block offset) */
1063 iblock->block_off = par_iblock->block_off;
1064 iblock->block_off += hdr->man_dtable.row_block_off[par_entry / hdr->man_dtable.cparam.width];
1065 iblock->block_off += hdr->man_dtable.row_block_size[par_entry / hdr->man_dtable.cparam.width] *
1066 (par_entry % hdr->man_dtable.cparam.width);
1067
1068 /* Set indirect block parent as flush dependency parent */
1069 iblock->fd_parent = par_iblock;
1070 } /* end if */
1071 else {
1072 iblock->block_off = 0; /* Must be the root indirect block... */
1073
1074 /* Set heap header as flush dependency parent */
1075 iblock->fd_parent = hdr;
1076 } /* end else */
1077
1078 /* Update indirect block's statistics */
1079 iblock->nchildren = 0;
1080 iblock->max_child = 0;
1081
1082 /* Cache the new indirect block */
1083 if (H5AC_insert_entry(hdr->f, H5AC_FHEAP_IBLOCK, *addr_p, iblock, H5AC__NO_FLAGS_SET) < 0)
1084 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add fractal heap indirect block to cache")
1085
1086 done:
1087 if (ret_value < 0)
1088 if (iblock)
1089 if (H5HF__man_iblock_dest(iblock) < 0)
1090 HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block")
1091
1092 FUNC_LEAVE_NOAPI(ret_value)
1093 } /* end H5HF__man_iblock_create() */
1094
1095 /*-------------------------------------------------------------------------
1096 * Function: H5HF__man_iblock_protect
1097 *
1098 * Purpose: Convenience wrapper around H5AC_protect on an indirect block
1099 *
1100 * Return: Pointer to indirect block on success, NULL on failure
1101 *
1102 * Programmer: Quincey Koziol
1103 * Apr 17 2006
1104 *
1105 *-------------------------------------------------------------------------
1106 */
1107 H5HF_indirect_t *
H5HF__man_iblock_protect(H5HF_hdr_t * hdr,haddr_t iblock_addr,unsigned iblock_nrows,H5HF_indirect_t * par_iblock,unsigned par_entry,hbool_t must_protect,unsigned flags,hbool_t * did_protect)1108 H5HF__man_iblock_protect(H5HF_hdr_t *hdr, haddr_t iblock_addr, unsigned iblock_nrows,
1109 H5HF_indirect_t *par_iblock, unsigned par_entry, hbool_t must_protect,
1110 unsigned flags, hbool_t *did_protect)
1111 {
1112 H5HF_parent_t par_info; /* Parent info for loading block */
1113 H5HF_indirect_t *iblock = NULL; /* Indirect block from cache */
1114 hbool_t should_protect = FALSE; /* Whether we should protect the indirect block or not */
1115 H5HF_indirect_t *ret_value = NULL; /* Return value */
1116
1117 FUNC_ENTER_PACKAGE
1118
1119 /*
1120 * Check arguments.
1121 */
1122 HDassert(hdr);
1123 HDassert(H5F_addr_defined(iblock_addr));
1124 HDassert(iblock_nrows > 0);
1125 HDassert(did_protect);
1126
1127 /* only H5AC__READ_ONLY_FLAG may appear in flags */
1128 HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
1129
1130 /* Check if we are allowed to use existing pinned iblock pointer */
1131 if (!must_protect) {
1132 /* Check for this block already being pinned */
1133 if (par_iblock) {
1134 unsigned indir_idx; /* Index in parent's child iblock pointer array */
1135
1136 /* Sanity check */
1137 HDassert(par_iblock->child_iblocks);
1138 HDassert(par_entry >= (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width));
1139
1140 /* Compute index in parent's child iblock pointer array */
1141 indir_idx = par_entry - (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width);
1142
1143 /* Check for pointer to pinned indirect block in parent */
1144 if (par_iblock->child_iblocks[indir_idx])
1145 iblock = par_iblock->child_iblocks[indir_idx];
1146 else
1147 should_protect = TRUE;
1148 } /* end if */
1149 else {
1150 /* Check for root indirect block */
1151 if (H5F_addr_eq(iblock_addr, hdr->man_dtable.table_addr)) {
1152 /* Check for valid pointer to pinned indirect block in root */
1153 if (H5HF_ROOT_IBLOCK_PINNED == hdr->root_iblock_flags) {
1154 /* Sanity check */
1155 HDassert(NULL != hdr->root_iblock);
1156
1157 /* Return the pointer to the pinned root indirect block */
1158 iblock = hdr->root_iblock;
1159 } /* end if */
1160 else {
1161 /* Sanity check */
1162 HDassert(NULL == hdr->root_iblock);
1163
1164 should_protect = TRUE;
1165 } /* end else */
1166 } /* end if */
1167 else
1168 should_protect = TRUE;
1169 } /* end else */
1170 } /* end if */
1171
1172 /* Check for protecting indirect block */
1173 if (must_protect || should_protect) {
1174 H5HF_iblock_cache_ud_t cache_udata; /* User-data for callback */
1175
1176 /* Set up parent info */
1177 par_info.hdr = hdr;
1178 par_info.iblock = par_iblock;
1179 par_info.entry = par_entry;
1180
1181 /* Set up user data for protect call */
1182 cache_udata.f = hdr->f;
1183 cache_udata.par_info = &par_info;
1184 cache_udata.nrows = &iblock_nrows;
1185
1186 /* Protect the indirect block */
1187 if (NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(hdr->f, H5AC_FHEAP_IBLOCK, iblock_addr,
1188 &cache_udata, flags)))
1189 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap indirect block")
1190
1191 /* Set the indirect block's address */
1192 iblock->addr = iblock_addr;
1193
1194 /* Check for root indirect block */
1195 if (iblock->block_off == 0) {
1196 /* Sanity check - shouldn't be recursively protecting root indirect block */
1197 HDassert(0 == (hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PROTECTED));
1198
1199 /* Check if we should set the root iblock pointer */
1200 if (0 == hdr->root_iblock_flags) {
1201 HDassert(NULL == hdr->root_iblock);
1202 hdr->root_iblock = iblock;
1203 } /* end if */
1204
1205 /* Indicate that the root indirect block is protected */
1206 hdr->root_iblock_flags |= H5HF_ROOT_IBLOCK_PROTECTED;
1207 } /* end if */
1208
1209 /* Indicate that the indirect block was protected */
1210 *did_protect = TRUE;
1211 } /* end if */
1212 else
1213 /* Indicate that the indirect block was _not_ protected */
1214 *did_protect = FALSE;
1215
1216 /* Set the return value */
1217 ret_value = iblock;
1218
1219 done:
1220 FUNC_LEAVE_NOAPI(ret_value)
1221 } /* end H5HF__man_iblock_protect() */
1222
1223 /*-------------------------------------------------------------------------
1224 * Function: H5HF__man_iblock_unprotect
1225 *
1226 * Purpose: Convenience wrapper around H5AC_unprotect on an indirect block
1227 *
1228 * Return: SUCCEED/FAIL
1229 *
1230 * Programmer: Quincey Koziol
1231 * Aug 17 2006
1232 *
1233 *-------------------------------------------------------------------------
1234 */
1235 herr_t
H5HF__man_iblock_unprotect(H5HF_indirect_t * iblock,unsigned cache_flags,hbool_t did_protect)1236 H5HF__man_iblock_unprotect(H5HF_indirect_t *iblock, unsigned cache_flags, hbool_t did_protect)
1237 {
1238 herr_t ret_value = SUCCEED; /* Return value */
1239
1240 FUNC_ENTER_PACKAGE
1241
1242 /*
1243 * Check arguments.
1244 */
1245 HDassert(iblock);
1246
1247 /* Check if we previously protected this indirect block */
1248 /* (as opposed to using an existing pointer to a pinned child indirect block) */
1249 if (did_protect) {
1250 /* Check for root indirect block */
1251 if (iblock->block_off == 0) {
1252 /* Sanity check - shouldn't be recursively unprotecting root indirect block */
1253 HDassert(iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PROTECTED);
1254
1255 /* Check if we should reset the root iblock pointer */
1256 if (H5HF_ROOT_IBLOCK_PROTECTED == iblock->hdr->root_iblock_flags) {
1257 HDassert(NULL != iblock->hdr->root_iblock);
1258 iblock->hdr->root_iblock = NULL;
1259 } /* end if */
1260
1261 /* Indicate that the root indirect block is unprotected */
1262 iblock->hdr->root_iblock_flags &= (unsigned)(~(H5HF_ROOT_IBLOCK_PROTECTED));
1263 } /* end if */
1264
1265 /* Unprotect the indirect block */
1266 if (H5AC_unprotect(iblock->hdr->f, H5AC_FHEAP_IBLOCK, iblock->addr, iblock, cache_flags) < 0)
1267 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
1268 } /* end if */
1269
1270 done:
1271 FUNC_LEAVE_NOAPI(ret_value)
1272 } /* end H5HF__man_iblock_unprotect() */
1273
1274 /*-------------------------------------------------------------------------
1275 * Function: H5HF__man_iblock_attach
1276 *
1277 * Purpose: Attach a child block (direct or indirect) to an indirect block
1278 *
1279 * Return: SUCCEED/FAIL
1280 *
1281 * Programmer: Quincey Koziol
1282 * May 30 2006
1283 *
1284 *-------------------------------------------------------------------------
1285 */
1286 herr_t
H5HF__man_iblock_attach(H5HF_indirect_t * iblock,unsigned entry,haddr_t child_addr)1287 H5HF__man_iblock_attach(H5HF_indirect_t *iblock, unsigned entry, haddr_t child_addr)
1288 {
1289 herr_t ret_value = SUCCEED; /* Return value */
1290
1291 FUNC_ENTER_PACKAGE
1292
1293 /*
1294 * Check arguments.
1295 */
1296 HDassert(iblock);
1297 HDassert(H5F_addr_defined(child_addr));
1298 HDassert(!H5F_addr_defined(iblock->ents[entry].addr));
1299
1300 /* Increment the reference count on this indirect block */
1301 if (H5HF__iblock_incr(iblock) < 0)
1302 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
1303
1304 /* Point at the child block */
1305 iblock->ents[entry].addr = child_addr;
1306
1307 /* Check for I/O filters on this heap */
1308 if (iblock->hdr->filter_len > 0) {
1309 unsigned row; /* Row for entry */
1310
1311 /* Sanity check */
1312 HDassert(iblock->filt_ents);
1313
1314 /* Compute row for entry */
1315 row = entry / iblock->hdr->man_dtable.cparam.width;
1316
1317 /* If this is a direct block, set its initial size */
1318 if (row < iblock->hdr->man_dtable.max_direct_rows)
1319 iblock->filt_ents[entry].size = iblock->hdr->man_dtable.row_block_size[row];
1320 } /* end if */
1321
1322 /* Check for max. entry used */
1323 if (entry > iblock->max_child)
1324 iblock->max_child = entry;
1325
1326 /* Increment the # of child blocks */
1327 iblock->nchildren++;
1328
1329 /* Mark indirect block as modified */
1330 if (H5HF__iblock_dirty(iblock) < 0)
1331 HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
1332
1333 done:
1334 FUNC_LEAVE_NOAPI(ret_value)
1335 } /* end H5HF__man_iblock_attach() */
1336
1337 /*-------------------------------------------------------------------------
1338 * Function: H5HF__man_iblock_detach
1339 *
1340 * Purpose: Detach a child block (direct or indirect) from an indirect block
1341 *
1342 * Return: SUCCEED/FAIL
1343 *
1344 * Programmer: Quincey Koziol
1345 * May 31 2006
1346 *
1347 *-------------------------------------------------------------------------
1348 */
1349 herr_t
H5HF__man_iblock_detach(H5HF_indirect_t * iblock,unsigned entry)1350 H5HF__man_iblock_detach(H5HF_indirect_t *iblock, unsigned entry)
1351 {
1352 H5HF_hdr_t * hdr; /* Fractal heap header */
1353 H5HF_indirect_t *del_iblock = NULL; /* Pointer to protected indirect block, when deleting */
1354 unsigned row; /* Row for entry */
1355 herr_t ret_value = SUCCEED; /* Return value */
1356
1357 FUNC_ENTER_PACKAGE
1358
1359 /*
1360 * Check arguments.
1361 */
1362 HDassert(iblock);
1363 HDassert(iblock->nchildren);
1364
1365 /* Set up convenience variables */
1366 hdr = iblock->hdr;
1367
1368 /* Reset address of entry */
1369 iblock->ents[entry].addr = HADDR_UNDEF;
1370
1371 /* Compute row for entry */
1372 row = entry / hdr->man_dtable.cparam.width;
1373
1374 /* Check for I/O filters on this heap */
1375 if (hdr->filter_len > 0) {
1376 /* Sanity check */
1377 HDassert(iblock->filt_ents);
1378
1379 /* If this is a direct block, reset its initial size */
1380 if (row < hdr->man_dtable.max_direct_rows) {
1381 iblock->filt_ents[entry].size = 0;
1382 iblock->filt_ents[entry].filter_mask = 0;
1383 } /* end if */
1384 } /* end if */
1385
1386 /* Check for indirect block being detached */
1387 if (row >= hdr->man_dtable.max_direct_rows) {
1388 unsigned indir_idx; /* Index in parent's child iblock pointer array */
1389
1390 /* Sanity check */
1391 HDassert(iblock->child_iblocks);
1392
1393 /* Compute index in child iblock pointer array */
1394 indir_idx = entry - (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width);
1395
1396 /* Sanity check */
1397 HDassert(iblock->child_iblocks[indir_idx]);
1398
1399 /* Reset pointer to child indirect block in parent */
1400 iblock->child_iblocks[indir_idx] = NULL;
1401 } /* end if */
1402
1403 /* Decrement the # of child blocks */
1404 /* (If the number of children drop to 0, the indirect block will be
1405 * removed from the heap when its ref. count drops to zero and the
1406 * metadata cache calls the indirect block destructor)
1407 */
1408 iblock->nchildren--;
1409
1410 /* Reduce the max. entry used, if necessary */
1411 if (entry == iblock->max_child) {
1412 if (iblock->nchildren > 0)
1413 while (!H5F_addr_defined(iblock->ents[iblock->max_child].addr))
1414 iblock->max_child--;
1415 else
1416 iblock->max_child = 0;
1417 } /* end if */
1418
1419 /* If this is the root indirect block handle some special cases */
1420 if (iblock->block_off == 0) {
1421 /* If the number of children drops to 1, and that child is the first
1422 * direct block in the heap, convert the heap back to using a root
1423 * direct block
1424 */
1425 if (iblock->nchildren == 1 && H5F_addr_defined(iblock->ents[0].addr))
1426 if (H5HF__man_iblock_root_revert(iblock) < 0)
1427 HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL,
1428 "can't convert root indirect block back to root direct block")
1429
1430 /* If the indirect block wasn't removed already (by reverting it) */
1431 if (!iblock->removed_from_cache) {
1432 /* Check for reducing size of root indirect block */
1433 if (iblock->nchildren > 0 && hdr->man_dtable.cparam.start_root_rows != 0 &&
1434 entry > iblock->max_child) {
1435 unsigned max_child_row; /* Row for max. child entry */
1436
1437 /* Compute information needed for determining whether to reduce size of root indirect block */
1438 max_child_row = iblock->max_child / hdr->man_dtable.cparam.width;
1439
1440 /* Check if the root indirect block should be reduced */
1441 if (iblock->nrows > 1 && max_child_row <= (iblock->nrows / 2))
1442 if (H5HF__man_iblock_root_halve(iblock) < 0)
1443 HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL,
1444 "can't reduce size of root indirect block")
1445 } /* end if */
1446 } /* end if */
1447 } /* end if */
1448
1449 /* If the indirect block wasn't removed already (by reverting it) */
1450 if (!iblock->removed_from_cache) {
1451 /* Mark indirect block as modified */
1452 if (H5HF__iblock_dirty(iblock) < 0)
1453 HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
1454
1455 /* Check for last child being removed from indirect block */
1456 if (iblock->nchildren == 0) {
1457 hbool_t did_protect = FALSE; /* Whether the indirect block was protected */
1458
1459 /* If this indirect block's refcount is >1, then it's being deleted
1460 * from the fractal heap (since its nchildren == 0), but is still
1461 * referred to from free space sections in the heap (refcount >1).
1462 * Its space in the file needs to be freed now, and it also needs
1463 * to be removed from the metadata cache now, in case the space in
1464 * the file is reused by another piece of metadata that is inserted
1465 * into the cache before the indirect block's entry is evicted
1466 * (having two entries at the same address would be an error, from
1467 * the cache's perspective).
1468 */
1469 /* Lock indirect block for deletion */
1470 if (NULL == (del_iblock = H5HF__man_iblock_protect(hdr, iblock->addr, iblock->nrows,
1471 iblock->parent, iblock->par_entry, TRUE,
1472 H5AC__NO_FLAGS_SET, &did_protect)))
1473 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
1474 HDassert(did_protect == TRUE);
1475
1476 /* Check for deleting root indirect block (and no root direct block) */
1477 if (iblock->block_off == 0 && hdr->man_dtable.curr_root_rows > 0)
1478 /* Reset header information back to "empty heap" state */
1479 if (H5HF__hdr_empty(hdr) < 0)
1480 HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't make heap empty")
1481
1482 /* Detach from parent indirect block */
1483 if (iblock->parent) {
1484 /* Destroy flush dependency between indirect block and parent */
1485 if (H5AC_destroy_flush_dependency(iblock->fd_parent, iblock) < 0)
1486 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
1487 iblock->fd_parent = NULL;
1488
1489 /* Detach from parent indirect block */
1490 if (H5HF__man_iblock_detach(iblock->parent, iblock->par_entry) < 0)
1491 HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach from parent indirect block")
1492 iblock->parent = NULL;
1493 iblock->par_entry = 0;
1494 } /* end if */
1495 } /* end if */
1496 } /* end if */
1497
1498 /* Decrement the reference count on this indirect block if we're not deleting it */
1499 /* (should be after iblock needs to be modified, so that potential 'unpin'
1500 * on this indirect block doesn't invalidate the 'iblock' variable, if it's
1501 * not being deleted)
1502 */
1503 if (H5HF__iblock_decr(iblock) < 0)
1504 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
1505 iblock = NULL;
1506
1507 /* Delete indirect block from cache, if appropriate */
1508 if (del_iblock) {
1509 unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotect */
1510 hbool_t took_ownership = FALSE; /* Flag to indicate that block ownership has transitioned */
1511
1512 /* If the refcount is still >0, unpin the block and take ownership
1513 * from the cache, otherwise let the cache destroy it.
1514 */
1515 if (del_iblock->rc > 0) {
1516 cache_flags |= (H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG);
1517 cache_flags |= H5AC__UNPIN_ENTRY_FLAG;
1518 took_ownership = TRUE;
1519 } /* end if */
1520 else {
1521 /* Entry should be removed from the cache */
1522 cache_flags |= H5AC__DELETED_FLAG;
1523
1524 /* If the indirect block is in real file space, tell
1525 * the cache to free its file space as well.
1526 */
1527 if (!H5F_IS_TMP_ADDR(hdr->f, del_iblock->addr))
1528 cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
1529 } /* end else */
1530
1531 /* Unprotect the indirect block, with appropriate flags */
1532 if (H5HF__man_iblock_unprotect(del_iblock, cache_flags, TRUE) < 0)
1533 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
1534
1535 /* if took ownership, free file space & mark block as removed from cache */
1536 if (took_ownership) {
1537 /* Free indirect block disk space, if it's in real space */
1538 if (!H5F_IS_TMP_ADDR(hdr->f, del_iblock->addr))
1539 if (H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_IBLOCK, del_iblock->addr, (hsize_t)del_iblock->size) <
1540 0)
1541 HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL,
1542 "unable to free fractal heap indirect block file space")
1543 del_iblock->addr = HADDR_UNDEF;
1544
1545 /* Mark block as removed from the cache */
1546 del_iblock->removed_from_cache = TRUE;
1547 } /* end if */
1548 } /* end if */
1549
1550 done:
1551 FUNC_LEAVE_NOAPI(ret_value)
1552 } /* end H5HF__man_iblock_detach() */
1553
1554 /*-------------------------------------------------------------------------
1555 * Function: H5HF__man_iblock_entry_addr
1556 *
1557 * Purpose: Retrieve the address of an indirect block's child
1558 *
1559 * Return: SUCCEED/FAIL
1560 *
1561 * Programmer: Quincey Koziol
1562 * July 10 2006
1563 *
1564 *-------------------------------------------------------------------------
1565 */
1566 herr_t
H5HF__man_iblock_entry_addr(H5HF_indirect_t * iblock,unsigned entry,haddr_t * child_addr)1567 H5HF__man_iblock_entry_addr(H5HF_indirect_t *iblock, unsigned entry, haddr_t *child_addr)
1568 {
1569 FUNC_ENTER_PACKAGE_NOERR
1570
1571 /*
1572 * Check arguments.
1573 */
1574 HDassert(iblock);
1575 HDassert(child_addr);
1576
1577 /* Retrieve address of entry */
1578 *child_addr = iblock->ents[entry].addr;
1579
1580 FUNC_LEAVE_NOAPI(SUCCEED)
1581 } /* end H5HF__man_iblock_entry_addr() */
1582
1583 /*-------------------------------------------------------------------------
1584 * Function: H5HF__man_iblock_delete
1585 *
1586 * Purpose: Delete a managed indirect block
1587 *
1588 * Note: This routine does _not_ modify any indirect block that points
1589 * to this indirect block, it is assumed that the whole heap is
1590 * being deleted in a top-down fashion.
1591 *
1592 * Return: SUCCEED/FAIL
1593 *
1594 * Programmer: Quincey Koziol
1595 * Aug 7 2006
1596 *
1597 *-------------------------------------------------------------------------
1598 */
1599 herr_t
H5HF__man_iblock_delete(H5HF_hdr_t * hdr,haddr_t iblock_addr,unsigned iblock_nrows,H5HF_indirect_t * par_iblock,unsigned par_entry)1600 H5HF__man_iblock_delete(H5HF_hdr_t *hdr, haddr_t iblock_addr, unsigned iblock_nrows,
1601 H5HF_indirect_t *par_iblock, unsigned par_entry)
1602 {
1603 H5HF_indirect_t *iblock; /* Pointer to indirect block */
1604 unsigned row, col; /* Current row & column in indirect block */
1605 unsigned entry; /* Current entry in row */
1606 unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting indirect block */
1607 hbool_t did_protect; /* Whether we protected the indirect block or not */
1608 herr_t ret_value = SUCCEED; /* Return value */
1609
1610 FUNC_ENTER_PACKAGE
1611
1612 /*
1613 * Check arguments.
1614 */
1615 HDassert(hdr);
1616 HDassert(H5F_addr_defined(iblock_addr));
1617 HDassert(iblock_nrows > 0);
1618
1619 /* Lock indirect block */
1620 if (NULL == (iblock = H5HF__man_iblock_protect(hdr, iblock_addr, iblock_nrows, par_iblock, par_entry,
1621 TRUE, H5AC__NO_FLAGS_SET, &did_protect)))
1622 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
1623 HDassert(iblock->nchildren > 0);
1624 HDassert(did_protect == TRUE);
1625
1626 /* Iterate over rows in this indirect block */
1627 entry = 0;
1628 for (row = 0; row < iblock->nrows; row++) {
1629 /* Iterate over entries in this row */
1630 for (col = 0; col < hdr->man_dtable.cparam.width; col++, entry++) {
1631 /* Check for child entry at this position */
1632 if (H5F_addr_defined(iblock->ents[entry].addr)) {
1633 /* Are we in a direct or indirect block row */
1634 if (row < hdr->man_dtable.max_direct_rows) {
1635 hsize_t dblock_size; /* Size of direct block on disk */
1636
1637 /* Check for I/O filters on this heap */
1638 if (hdr->filter_len > 0)
1639 dblock_size = iblock->filt_ents[entry].size;
1640 else
1641 dblock_size = hdr->man_dtable.row_block_size[row];
1642
1643 /* Delete child direct block */
1644 if (H5HF__man_dblock_delete(hdr->f, iblock->ents[entry].addr, dblock_size) < 0)
1645 HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL,
1646 "unable to release fractal heap child direct block")
1647 } /* end if */
1648 else {
1649 hsize_t row_block_size; /* The size of blocks in this row */
1650 unsigned child_nrows; /* Number of rows in new indirect block */
1651
1652 /* Get the row's block size */
1653 row_block_size = (hsize_t)hdr->man_dtable.row_block_size[row];
1654
1655 /* Compute # of rows in next child indirect block to use */
1656 child_nrows = H5HF__dtable_size_to_rows(&hdr->man_dtable, row_block_size);
1657
1658 /* Delete child indirect block */
1659 if (H5HF__man_iblock_delete(hdr, iblock->ents[entry].addr, child_nrows, iblock, entry) <
1660 0)
1661 HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL,
1662 "unable to release fractal heap child indirect block")
1663 } /* end else */
1664 } /* end if */
1665 } /* end for */
1666 } /* end row */
1667
1668 #ifndef NDEBUG
1669 {
1670 unsigned iblock_status = 0; /* Indirect block's status in the metadata cache */
1671
1672 /* Check the indirect block's status in the metadata cache */
1673 if (H5AC_get_entry_status(hdr->f, iblock_addr, &iblock_status) < 0)
1674 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
1675 "unable to check metadata cache status for indirect block")
1676
1677 /* Check if indirect block is pinned */
1678 HDassert(!(iblock_status & H5AC_ES__IS_PINNED));
1679 }
1680 #endif /* NDEBUG */
1681
1682 /* Indicate that the indirect block should be deleted */
1683 cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG;
1684
1685 /* If the indirect block is in real file space, tell
1686 * the cache to free its file space as well.
1687 */
1688 if (!H5F_IS_TMP_ADDR(hdr->f, iblock_addr))
1689 cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
1690
1691 done:
1692 /* Unprotect the indirect block, with appropriate flags */
1693 if (iblock && H5HF__man_iblock_unprotect(iblock, cache_flags, did_protect) < 0)
1694 HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
1695
1696 FUNC_LEAVE_NOAPI(ret_value)
1697 } /* end H5HF__man_iblock_delete() */
1698
1699 /*-------------------------------------------------------------------------
1700 *
1701 * Function: H5HF__man_iblock_size
1702 *
1703 * Purpose: Gather storage used for the indirect block in fractal heap
1704 *
1705 * Return: non-negative on success, negative on error
1706 *
1707 * Programmer: Vailin Choi
1708 * July 12 2007
1709 *-------------------------------------------------------------------------
1710 */
1711 herr_t
H5HF__man_iblock_size(H5F_t * f,H5HF_hdr_t * hdr,haddr_t iblock_addr,unsigned nrows,H5HF_indirect_t * par_iblock,unsigned par_entry,hsize_t * heap_size)1712 H5HF__man_iblock_size(H5F_t *f, H5HF_hdr_t *hdr, haddr_t iblock_addr, unsigned nrows,
1713 H5HF_indirect_t *par_iblock, unsigned par_entry, hsize_t *heap_size)
1714 {
1715 H5HF_indirect_t *iblock = NULL; /* Pointer to indirect block */
1716 hbool_t did_protect; /* Whether we protected the indirect block or not */
1717 herr_t ret_value = SUCCEED; /* Return value */
1718
1719 FUNC_ENTER_PACKAGE
1720
1721 /*
1722 * Check arguments.
1723 */
1724 HDassert(f);
1725 HDassert(hdr);
1726 HDassert(H5F_addr_defined(iblock_addr));
1727 HDassert(heap_size);
1728
1729 /* Protect the indirect block */
1730 if (NULL == (iblock = H5HF__man_iblock_protect(hdr, iblock_addr, nrows, par_iblock, par_entry, FALSE,
1731 H5AC__READ_ONLY_FLAG, &did_protect)))
1732 HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap indirect block")
1733
1734 /* Accumulate size of this indirect block */
1735 *heap_size += iblock->size;
1736
1737 /* Indirect entries in this indirect block */
1738 if (iblock->nrows > hdr->man_dtable.max_direct_rows) {
1739 unsigned first_row_bits; /* Number of bits used bit addresses in first row */
1740 unsigned num_indirect_rows; /* Number of rows of blocks in each indirect block */
1741 unsigned entry; /* Current entry in row */
1742 size_t u; /* Local index variable */
1743
1744 entry = hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width;
1745 first_row_bits = H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size) +
1746 H5VM_log2_of2(hdr->man_dtable.cparam.width);
1747 num_indirect_rows = (H5VM_log2_gen(hdr->man_dtable.row_block_size[hdr->man_dtable.max_direct_rows]) -
1748 first_row_bits) +
1749 1;
1750 for (u = hdr->man_dtable.max_direct_rows; u < iblock->nrows; u++, num_indirect_rows++) {
1751 size_t v; /* Local index variable */
1752
1753 for (v = 0; v < hdr->man_dtable.cparam.width; v++, entry++)
1754 if (H5F_addr_defined(iblock->ents[entry].addr))
1755 if (H5HF__man_iblock_size(f, hdr, iblock->ents[entry].addr, num_indirect_rows, iblock,
1756 entry, heap_size) < 0)
1757 HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL,
1758 "unable to get fractal heap storage info for indirect block")
1759 } /* end for */
1760 } /* end if */
1761
1762 done:
1763 /* Release the indirect block */
1764 if (iblock && H5HF__man_iblock_unprotect(iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
1765 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
1766 iblock = NULL;
1767
1768 FUNC_LEAVE_NOAPI(ret_value)
1769 } /* end H5HF__man_iblock_size() */
1770
1771 /*-------------------------------------------------------------------------
1772 *
1773 * Function: H5HF_man_iblock_parent_info
1774 *
1775 * Purpose: Determine the parent block's offset and entry location
1776 * (within it's parent) of an indirect block, given its offset
1777 * within the heap.
1778 *
1779 * Return: Non-negative on success / Negative on failure
1780 *
1781 * Programmer: Quincey Koziol
1782 * Jan 14 2018
1783 *
1784 *-------------------------------------------------------------------------
1785 */
1786 herr_t
H5HF__man_iblock_parent_info(const H5HF_hdr_t * hdr,hsize_t block_off,hsize_t * ret_par_block_off,unsigned * ret_entry)1787 H5HF__man_iblock_parent_info(const H5HF_hdr_t *hdr, hsize_t block_off, hsize_t *ret_par_block_off,
1788 unsigned *ret_entry)
1789 {
1790 hsize_t par_block_off; /* Offset of parent within heap */
1791 hsize_t prev_par_block_off; /* Offset of previous parent block within heap */
1792 unsigned row, col; /* Row & column for block */
1793 unsigned prev_row = 0, prev_col = 0; /* Previous row & column for block */
1794 herr_t ret_value = SUCCEED; /* Return value */
1795
1796 FUNC_ENTER_PACKAGE
1797
1798 /*
1799 * Check arguments.
1800 */
1801 HDassert(hdr);
1802 HDassert(block_off > 0);
1803 HDassert(ret_entry);
1804
1805 /* Look up row & column for object */
1806 if (H5HF__dtable_lookup(&hdr->man_dtable, block_off, &row, &col) < 0)
1807 HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of block")
1808
1809 /* Sanity check - first lookup must be an indirect block */
1810 HDassert(row >= hdr->man_dtable.max_direct_rows);
1811
1812 /* Traverse down, until a direct block at the offset is found, then
1813 * use previous (i.e. parent's) offset, row, and column.
1814 */
1815 prev_par_block_off = par_block_off = 0;
1816 while (row >= hdr->man_dtable.max_direct_rows) {
1817 /* Retain previous parent block offset */
1818 prev_par_block_off = par_block_off;
1819
1820 /* Compute the new parent indirect block's offset in the heap's address space */
1821 /* (based on previous block offset) */
1822 par_block_off += hdr->man_dtable.row_block_off[row];
1823 par_block_off += hdr->man_dtable.row_block_size[row] * col;
1824
1825 /* Preserve current row & column */
1826 prev_row = row;
1827 prev_col = col;
1828
1829 /* Look up row & column in new indirect block for object */
1830 if (H5HF__dtable_lookup(&hdr->man_dtable, (block_off - par_block_off), &row, &col) < 0)
1831 HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of block")
1832 } /* end while */
1833
1834 /* Sanity check */
1835 HDassert(row == 0);
1836 HDassert(col == 0);
1837
1838 /* Set return parameters */
1839 *ret_par_block_off = prev_par_block_off;
1840 *ret_entry = (prev_row * hdr->man_dtable.cparam.width) + prev_col;
1841
1842 done:
1843 FUNC_LEAVE_NOAPI(ret_value)
1844 } /* end H5HF__man_iblock_par_info() */
1845
1846 /*-------------------------------------------------------------------------
1847 * Function: H5HF__man_iblock_dest
1848 *
1849 * Purpose: Destroys a fractal heap indirect block in memory.
1850 *
1851 * Return: Non-negative on success/Negative on failure
1852 *
1853 * Programmer: Quincey Koziol
1854 * Mar 6 2006
1855 *
1856 *-------------------------------------------------------------------------
1857 */
1858 herr_t
H5HF__man_iblock_dest(H5HF_indirect_t * iblock)1859 H5HF__man_iblock_dest(H5HF_indirect_t *iblock)
1860 {
1861 herr_t ret_value = SUCCEED; /* Return value */
1862
1863 FUNC_ENTER_PACKAGE
1864
1865 /*
1866 * Check arguments.
1867 */
1868 HDassert(iblock);
1869 HDassert(iblock->rc == 0);
1870
1871 /* Decrement reference count on shared info */
1872 HDassert(iblock->hdr);
1873 if (H5HF__hdr_decr(iblock->hdr) < 0)
1874 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
1875 if (iblock->parent)
1876 if (H5HF__iblock_decr(iblock->parent) < 0)
1877 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL,
1878 "can't decrement reference count on shared indirect block")
1879
1880 /* Release entry tables */
1881 if (iblock->ents)
1882 iblock->ents = H5FL_SEQ_FREE(H5HF_indirect_ent_t, iblock->ents);
1883 if (iblock->filt_ents)
1884 iblock->filt_ents = H5FL_SEQ_FREE(H5HF_indirect_filt_ent_t, iblock->filt_ents);
1885 if (iblock->child_iblocks)
1886 iblock->child_iblocks = H5FL_SEQ_FREE(H5HF_indirect_ptr_t, iblock->child_iblocks);
1887
1888 /* Free fractal heap indirect block info */
1889 iblock = H5FL_FREE(H5HF_indirect_t, iblock);
1890
1891 done:
1892 FUNC_LEAVE_NOAPI(ret_value)
1893 } /* end H5HF__man_iblock_dest() */
1894