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