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