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