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  * Programmer:  Quincey Koziol <koziol@hdfgroup.org>
16  *              Monday, May  1, 2006
17  *
18  * Purpose:     Free space section routines for fractal heaps
19  *
20  */
21 
22 /****************/
23 /* Module Setup */
24 /****************/
25 
26 #include "H5HFmodule.h"         /* This source code file is part of the H5HF module */
27 
28 
29 /***********/
30 /* Headers */
31 /***********/
32 #include "H5private.h"		/* Generic Functions			*/
33 #include "H5Eprivate.h"		/* Error handling		  	*/
34 #include "H5HFpkg.h"		/* Fractal heaps			*/
35 #include "H5MMprivate.h"	/* Memory management			*/
36 #include "H5VMprivate.h"		/* Vectors and arrays 			*/
37 
38 /****************/
39 /* Local Macros */
40 /****************/
41 
42 /* Size of serialized indirect section information */
43 #define H5HF_SECT_INDIRECT_SERIAL_SIZE(h) (                                   \
44     (unsigned)(h)->heap_off_size  /* Indirect block's offset in "heap space" */         \
45         + (unsigned)2             /* Row */                                             \
46         + (unsigned)2             /* Column */                                          \
47         + (unsigned)2             /* # of entries */                                    \
48     )
49 
50 
51 /******************/
52 /* Local Typedefs */
53 /******************/
54 
55 /* Typedef for "class private" information for sections */
56 typedef struct {
57     H5HF_hdr_t *hdr;            /* Pointer to fractal heap header */
58 } H5HF_sect_private_t;
59 
60 
61 /********************/
62 /* Package Typedefs */
63 /********************/
64 
65 
66 /********************/
67 /* Local Prototypes */
68 /********************/
69 
70 /* Shared routines */
71 static herr_t H5HF_sect_init_cls(H5FS_section_class_t *cls,
72     H5HF_hdr_t *hdr);
73 static herr_t H5HF_sect_term_cls(H5FS_section_class_t *cls);
74 static H5HF_free_section_t *H5HF_sect_node_new(unsigned sect_type,
75     haddr_t sect_addr, hsize_t sect_size, H5FS_section_state_t state);
76 static herr_t H5HF_sect_node_free(H5HF_free_section_t *sect,
77     H5HF_indirect_t *parent);
78 
79 /* 'single' section routines */
80 static herr_t H5HF__sect_single_locate_parent(H5HF_hdr_t *hdr, hbool_t refresh,
81     H5HF_free_section_t *sect);
82 static herr_t H5HF__sect_single_full_dblock(H5HF_hdr_t *hdr, H5HF_free_section_t *sect);
83 
84 /* 'single' section callbacks */
85 static herr_t H5HF__sect_single_add(H5FS_section_info_t **sect, unsigned *flags,
86     void *udata);
87 static H5FS_section_info_t *H5HF__sect_single_deserialize(const H5FS_section_class_t *cls,
88     const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
89     unsigned *des_flags);
90 static htri_t H5HF__sect_single_can_merge(const H5FS_section_info_t *sect1,
91     const H5FS_section_info_t *sect2, void *udata);
92 static herr_t H5HF__sect_single_merge(H5FS_section_info_t **sect1,
93     H5FS_section_info_t *sect2, void *udata);
94 static htri_t H5HF__sect_single_can_shrink(const H5FS_section_info_t *sect,
95     void *udata);
96 static herr_t H5HF__sect_single_shrink(H5FS_section_info_t **_sect,
97     void *udata);
98 static herr_t H5HF__sect_single_valid(const H5FS_section_class_t *cls,
99     const H5FS_section_info_t *sect);
100 
101 /* 'row' section routines */
102 static H5HF_free_section_t *H5HF_sect_row_create(haddr_t sect_off,
103     hsize_t sect_size, hbool_t is_first, unsigned row, unsigned col,
104     unsigned nentries, H5HF_free_section_t *under_sect);
105 static herr_t H5HF__sect_row_first(H5HF_hdr_t *hdr, H5HF_free_section_t *sect);
106 static herr_t H5HF__sect_row_parent_removed(H5HF_free_section_t *sect);
107 static herr_t H5HF_sect_row_from_single(H5HF_hdr_t *hdr,
108     H5HF_free_section_t *sect, H5HF_direct_t *dblock);
109 static herr_t H5HF__sect_row_free_real(H5HF_free_section_t *sect);
110 
111 /* 'row' section callbacks */
112 static herr_t H5HF__sect_row_init_cls(H5FS_section_class_t *cls, void *udata);
113 static herr_t H5HF__sect_row_term_cls(H5FS_section_class_t *cls);
114 static herr_t H5HF__sect_row_serialize(const H5FS_section_class_t *cls,
115     const H5FS_section_info_t *sect, uint8_t *buf);
116 static H5FS_section_info_t *H5HF__sect_row_deserialize(const H5FS_section_class_t *cls,
117     const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
118     unsigned *des_flags);
119 static htri_t H5HF__sect_row_can_merge(const H5FS_section_info_t *sect1,
120     const H5FS_section_info_t *sect2, void *udata);
121 static herr_t H5HF__sect_row_merge(H5FS_section_info_t **sect1,
122     H5FS_section_info_t *sect2, void *udata);
123 static htri_t H5HF__sect_row_can_shrink(const H5FS_section_info_t *sect,
124     void *udata);
125 static herr_t H5HF__sect_row_shrink(H5FS_section_info_t **sect,
126     void *udata);
127 static herr_t H5HF__sect_row_free(H5FS_section_info_t *sect);
128 static herr_t H5HF__sect_row_valid(const H5FS_section_class_t *cls,
129     const H5FS_section_info_t *sect);
130 static herr_t H5HF__sect_row_debug(const H5FS_section_info_t *sect,
131     FILE *stream, int indent, int fwidth);
132 
133 /* 'indirect' section routines */
134 static H5HF_free_section_t *H5HF_sect_indirect_new(H5HF_hdr_t *hdr,
135     haddr_t sect_off, hsize_t sect_size,
136     H5HF_indirect_t *iblock, hsize_t iblock_off,
137     unsigned row, unsigned col, unsigned nentries);
138 static herr_t H5HF__sect_indirect_init_rows(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
139     hbool_t first_child, H5HF_free_section_t **first_row_sect,
140     unsigned space_flags, unsigned start_row, unsigned start_col,
141     unsigned end_row, unsigned end_col);
142 static H5HF_free_section_t *H5HF_sect_indirect_for_row(H5HF_hdr_t *hdr,
143     H5HF_indirect_t *iblock, H5HF_free_section_t *row_sect);
144 static herr_t H5HF_sect_indirect_decr(H5HF_free_section_t *sect);
145 static herr_t H5HF__sect_indirect_revive_row(H5HF_hdr_t *hdr,
146     H5HF_free_section_t *sect);
147 static herr_t H5HF__sect_indirect_revive(H5HF_hdr_t *hdr,
148     H5HF_free_section_t *sect, H5HF_indirect_t *sect_iblock);
149 static herr_t H5HF__sect_indirect_reduce_row(H5HF_hdr_t *hdr,
150     H5HF_free_section_t *row_sect, hbool_t *alloc_from_start);
151 static herr_t H5HF__sect_indirect_reduce(H5HF_hdr_t *hdr,
152     H5HF_free_section_t *sect, unsigned child_entry);
153 static herr_t H5HF__sect_indirect_first(H5HF_hdr_t *hdr,
154     H5HF_free_section_t *sect);
155 static hbool_t H5HF_sect_indirect_is_first(H5HF_free_section_t *sect);
156 static H5HF_indirect_t * H5HF_sect_indirect_get_iblock(H5HF_free_section_t *sect);
157 static hsize_t H5HF_sect_indirect_iblock_off(const H5HF_free_section_t *sect);
158 static H5HF_free_section_t * H5HF_sect_indirect_top(H5HF_free_section_t *sect);
159 static herr_t H5HF__sect_indirect_merge_row(H5HF_hdr_t *hdr,
160     H5HF_free_section_t *sect1, H5HF_free_section_t *sect2);
161 static herr_t H5HF__sect_indirect_build_parent(H5HF_hdr_t *hdr, H5HF_free_section_t *sect);
162 static herr_t H5HF__sect_indirect_shrink(H5HF_hdr_t *hdr,
163     H5HF_free_section_t *sect);
164 static herr_t H5HF_sect_indirect_serialize(H5HF_hdr_t *hdr,
165     const H5HF_free_section_t *sect, uint8_t *buf);
166 static H5FS_section_info_t *H5HF__sect_indirect_deserialize(H5HF_hdr_t *hdr,
167     const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size, unsigned *des_flags);
168 static herr_t H5HF_sect_indirect_free(H5HF_free_section_t *sect);
169 static herr_t H5HF_sect_indirect_valid(const H5HF_hdr_t *hdr,
170     const H5HF_free_section_t *sect);
171 static herr_t H5HF_sect_indirect_debug(const H5HF_free_section_t *sect,
172     FILE *stream, int indent, int fwidth);
173 
174 /* 'indirect' section callbacks */
175 static herr_t H5HF_sect_indirect_init_cls(H5FS_section_class_t *cls, void *udata);
176 static herr_t H5HF_sect_indirect_term_cls(H5FS_section_class_t *cls);
177 
178 
179 /*********************/
180 /* Package Variables */
181 /*********************/
182 
183 /* Class info for "single" free space sections */
184 H5FS_section_class_t H5HF_FSPACE_SECT_CLS_SINGLE[1] = {{
185     /* Class variables */
186     H5HF_FSPACE_SECT_SINGLE,		/* Section type                 */
187     0,					/* Extra serialized size        */
188     H5FS_CLS_MERGE_SYM,			/* Class flags                  */
189     NULL,				/* Class private info           */
190 
191     /* Class methods */
192     NULL,				/* Initialize section class     */
193     NULL,				/* Terminate section class      */
194 
195     /* Object methods */
196     H5HF__sect_single_add,		/* Add section                  */
197     NULL,				/* Serialize section            */
198     H5HF__sect_single_deserialize,	/* Deserialize section          */
199     H5HF__sect_single_can_merge,	/* Can sections merge?          */
200     H5HF__sect_single_merge,		/* Merge sections               */
201     H5HF__sect_single_can_shrink,	/* Can section shrink container?*/
202     H5HF__sect_single_shrink,		/* Shrink container w/section   */
203     H5HF__sect_single_free,		/* Free section                 */
204     H5HF__sect_single_valid,		/* Check validity of section    */
205     NULL,				/* Split section node for alignment */
206     NULL,				/* Dump debugging for section   */
207 }};
208 
209 /* Class info for "first row" free space sections */
210 /* (Same as "normal" row sections, except they also act as a proxy for the
211  *      underlying indirect section
212  */
213 H5FS_section_class_t H5HF_FSPACE_SECT_CLS_FIRST_ROW[1] = {{
214     /* Class variables */
215     H5HF_FSPACE_SECT_FIRST_ROW,		/* Section type                 */
216     0,					/* Extra serialized size        */
217     H5FS_CLS_MERGE_SYM,			/* Class flags                  */
218     NULL,				/* Class private info           */
219 
220     /* Class methods */
221     H5HF__sect_row_init_cls,		/* Initialize section class     */
222     H5HF__sect_row_term_cls,		/* Terminate section class      */
223 
224     /* Object methods */
225     NULL,				/* Add section                  */
226     H5HF__sect_row_serialize,		/* Serialize section            */
227     H5HF__sect_row_deserialize,		/* Deserialize section          */
228     H5HF__sect_row_can_merge,		/* Can sections merge?          */
229     H5HF__sect_row_merge,		/* Merge sections               */
230     H5HF__sect_row_can_shrink,		/* Can section shrink container?*/
231     H5HF__sect_row_shrink,		/* Shrink container w/section   */
232     H5HF__sect_row_free,		/* Free section                 */
233     H5HF__sect_row_valid,		/* Check validity of section    */
234     NULL,				/* Split section node for alignment */
235     H5HF__sect_row_debug,		/* Dump debugging for section   */
236 }};
237 
238 /* Class info for "normal row" free space sections */
239 H5FS_section_class_t H5HF_FSPACE_SECT_CLS_NORMAL_ROW[1] = {{
240     /* Class variables */
241     H5HF_FSPACE_SECT_NORMAL_ROW,	/* Section type                 */
242     0,					/* Extra serialized size        */
243     H5FS_CLS_MERGE_SYM|H5FS_CLS_SEPAR_OBJ|H5FS_CLS_GHOST_OBJ,	/* Class flags                  */
244     NULL,				/* Class private info           */
245 
246     /* Class methods */
247     H5HF__sect_row_init_cls,		/* Initialize section class     */
248     H5HF__sect_row_term_cls,		/* Terminate section class      */
249 
250     /* Object methods */
251     NULL,				/* Add section                  */
252     NULL,				/* Serialize section            */
253     NULL,				/* Deserialize section          */
254     NULL,				/* Can sections merge?          */
255     NULL,				/* Merge sections               */
256     NULL,				/* Can section shrink container?*/
257     NULL,				/* Shrink container w/section   */
258     H5HF__sect_row_free,		/* Free section                 */
259     H5HF__sect_row_valid,		/* Check validity of section    */
260     NULL,				/* Split section node for alignment */
261     H5HF__sect_row_debug,		/* Dump debugging for section   */
262 }};
263 
264 /* Class info for "indirect" free space sections */
265 /* (No object callbacks necessary - objects of this class should never be in
266  *      section manager)
267  */
268 H5FS_section_class_t H5HF_FSPACE_SECT_CLS_INDIRECT[1] = {{
269     /* Class variables */
270     H5HF_FSPACE_SECT_INDIRECT,		/* Section type                 */
271     0,					/* Extra serialized size        */
272     H5FS_CLS_MERGE_SYM|H5FS_CLS_GHOST_OBJ,			/* Class flags                  */
273     NULL,				/* Class private info           */
274 
275     /* Class methods */
276     H5HF_sect_indirect_init_cls,	/* Initialize section class     */
277     H5HF_sect_indirect_term_cls,	/* Terminate section class      */
278 
279     /* Object methods */
280     NULL,				/* Add section                  */
281     NULL,				/* Serialize section            */
282     NULL,				/* Deserialize section          */
283     NULL,				/* Can sections merge?          */
284     NULL,				/* Merge sections               */
285     NULL,				/* Can section shrink container?*/
286     NULL,				/* Shrink container w/section   */
287     NULL,				/* Free section                 */
288     NULL,				/* Check validity of section    */
289     NULL,				/* Split section node for alignment */
290     NULL,				/* Dump debugging for section   */
291 }};
292 
293 /* Declare a free list to manage the H5HF_free_section_t struct */
294 H5FL_DEFINE(H5HF_free_section_t);
295 
296 
297 /*****************************/
298 /* Library Private Variables */
299 /*****************************/
300 
301 
302 /*******************/
303 /* Local Variables */
304 /*******************/
305 
306 
307 
308 /*-------------------------------------------------------------------------
309  * Function:	H5HF_sect_init_cls
310  *
311  * Purpose:	Initialize the common class structure
312  *
313  * Return:	Success:	non-negative
314  *		Failure:	negative
315  *
316  * Programmer:	Quincey Koziol
317  *              Tuesday, July 25, 2006
318  *
319  *-------------------------------------------------------------------------
320  */
321 static herr_t
H5HF_sect_init_cls(H5FS_section_class_t * cls,H5HF_hdr_t * hdr)322 H5HF_sect_init_cls(H5FS_section_class_t *cls, H5HF_hdr_t *hdr)
323 {
324     H5HF_sect_private_t *cls_prvt;      /* Pointer to class private info */
325     herr_t ret_value = SUCCEED;         /* Return value */
326 
327     FUNC_ENTER_NOAPI_NOINIT
328 
329     /* Check arguments. */
330     HDassert(cls);
331     HDassert(!cls->cls_private);
332 
333     /* Allocate & initialize the class-private (i.e. private shared) information
334      * for this type of section
335      */
336     if(NULL == (cls_prvt = (H5HF_sect_private_t *)H5MM_malloc(sizeof(H5HF_sect_private_t))))
337 	HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
338     cls_prvt->hdr = hdr;
339     cls->cls_private = cls_prvt;
340 
341     /* Increment reference count on heap header */
342     if(H5HF_hdr_incr(hdr) < 0)
343         HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header")
344 
345 done:
346     FUNC_LEAVE_NOAPI(ret_value)
347 } /* H5HF_sect_init_cls() */
348 
349 
350 /*-------------------------------------------------------------------------
351  * Function:	H5HF_sect_term_cls
352  *
353  * Purpose:	Terminate the common class structure
354  *
355  * Return:	Success:	non-negative
356  *		Failure:	negative
357  *
358  * Programmer:	Quincey Koziol
359  *              Tuesday, July 25, 2006
360  *
361  *-------------------------------------------------------------------------
362  */
363 static herr_t
H5HF_sect_term_cls(H5FS_section_class_t * cls)364 H5HF_sect_term_cls(H5FS_section_class_t *cls)
365 {
366     H5HF_sect_private_t *cls_prvt;      /* Pointer to class private info */
367     herr_t ret_value = SUCCEED;         /* Return value */
368 
369     FUNC_ENTER_NOAPI_NOINIT
370 
371     /* Check arguments. */
372     HDassert(cls);
373 
374     /* Get pointer to class private info */
375     cls_prvt = (H5HF_sect_private_t *)cls->cls_private;
376 
377     /* Decrement reference count on heap header */
378     if(H5HF_hdr_decr(cls_prvt->hdr) < 0)
379         HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
380 
381     /* Free the class private information */
382     cls->cls_private = H5MM_xfree(cls_prvt);
383 
384 done:
385     FUNC_LEAVE_NOAPI(ret_value)
386 } /* H5HF_sect_term_cls() */
387 
388 
389 /*-------------------------------------------------------------------------
390  * Function:	H5HF_sect_node_new
391  *
392  * Purpose:	Allocate a free space section node of a particular type
393  *
394  * Return:	Success:	non-negative
395  *
396  *		Failure:	negative
397  *
398  * Programmer:	Quincey Koziol
399  *              Saturday, May 13, 2006
400  *
401  *-------------------------------------------------------------------------
402  */
403 static H5HF_free_section_t *
H5HF_sect_node_new(unsigned sect_type,haddr_t sect_addr,hsize_t sect_size,H5FS_section_state_t sect_state)404 H5HF_sect_node_new(unsigned sect_type, haddr_t sect_addr, hsize_t sect_size,
405     H5FS_section_state_t sect_state)
406 {
407     H5HF_free_section_t *new_sect;              /* New section */
408     H5HF_free_section_t *ret_value = NULL;      /* Return value */
409 
410     FUNC_ENTER_NOAPI_NOINIT
411 
412     /* Check arguments. */
413     HDassert(H5F_addr_defined(sect_addr));
414 
415     /* Create free list section node */
416     if(NULL == (new_sect = H5FL_MALLOC(H5HF_free_section_t)))
417         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for direct block free list section")
418 
419     /* Set the information passed in */
420     new_sect->sect_info.addr = sect_addr;
421     new_sect->sect_info.size = sect_size;
422 
423     /* Set the section's class & state */
424     new_sect->sect_info.type = sect_type;
425     new_sect->sect_info.state = sect_state;
426 
427     /* Set return value */
428     ret_value = new_sect;
429 
430 done:
431     FUNC_LEAVE_NOAPI(ret_value)
432 } /* H5HF_sect_node_new() */
433 
434 
435 /*-------------------------------------------------------------------------
436  * Function:	H5HF_sect_node_free
437  *
438  * Purpose:	Free a section node
439  *
440  * Return:	Success:	non-negative
441  *
442  *		Failure:	negative
443  *
444  * Programmer:	Quincey Koziol
445  *              Wednesday, May 17, 2006
446  *
447  *-------------------------------------------------------------------------
448  */
449 static herr_t
H5HF_sect_node_free(H5HF_free_section_t * sect,H5HF_indirect_t * iblock)450 H5HF_sect_node_free(H5HF_free_section_t *sect, H5HF_indirect_t *iblock)
451 {
452     herr_t ret_value = SUCCEED;               /* Return value */
453 
454     FUNC_ENTER_NOAPI_NOINIT
455 
456     HDassert(sect);
457 
458     /* Release indirect block, if there was one */
459     if(iblock)
460         if(H5HF__iblock_decr(iblock) < 0)
461             HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on section's indirect block")
462 
463     /* Release the section */
464     sect = H5FL_FREE(H5HF_free_section_t, sect);
465 
466 done:
467     FUNC_LEAVE_NOAPI(ret_value)
468 }   /* H5HF_sect_node_free() */
469 
470 
471 /*-------------------------------------------------------------------------
472  * Function:	H5HF_sect_single_new
473  *
474  * Purpose:	Create a new 'single' section and return it to the caller
475  *
476  * Return:	Pointer to new section on success/NULL on failure
477  *
478  * Programmer:	Quincey Koziol
479  *		koziol@ncsa.uiuc.edu
480  *		May 30 2006
481  *
482  *-------------------------------------------------------------------------
483  */
484 H5HF_free_section_t *
H5HF_sect_single_new(hsize_t sect_off,size_t sect_size,H5HF_indirect_t * parent,unsigned par_entry)485 H5HF_sect_single_new(hsize_t sect_off, size_t sect_size,
486     H5HF_indirect_t *parent, unsigned par_entry)
487 {
488     H5HF_free_section_t *sect = NULL;   /* 'Single' free space section to add */
489     H5HF_free_section_t *ret_value = NULL;      /* Return value */
490 
491     FUNC_ENTER_NOAPI_NOINIT
492 
493     /*
494      * Check arguments.
495      */
496     HDassert(sect_size);
497 
498     /* Create free space section node */
499     if(NULL == (sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_SINGLE, sect_off, (hsize_t)sect_size, H5FS_SECT_LIVE)))
500         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for single section")
501 
502     /* Set the 'single' specific fields */
503     sect->u.single.parent = parent;
504     if(sect->u.single.parent) {
505         if(H5HF_iblock_incr(sect->u.single.parent) < 0)
506             HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block")
507     } /* end if */
508     sect->u.single.par_entry = par_entry;
509 
510     /* Set return value */
511     ret_value = sect;
512 
513 done:
514     if(!ret_value && sect) {
515         /* Release the section */
516         sect = H5FL_FREE(H5HF_free_section_t, sect);
517     } /* end if */
518 
519     FUNC_LEAVE_NOAPI(ret_value)
520 } /* end H5HF_sect_single_new() */
521 
522 
523 /*-------------------------------------------------------------------------
524  * Function:	H5HF__sect_single_locate_parent
525  *
526  * Purpose:	Locate the parent indirect block for a single section
527  *
528  * Return:	Non-negative on success/Negative on failure
529  *
530  * Programmer:	Quincey Koziol
531  *		koziol@hdfgroup.org
532  *		October 24 2006
533  *
534  *-------------------------------------------------------------------------
535  */
536 static herr_t
H5HF__sect_single_locate_parent(H5HF_hdr_t * hdr,hbool_t refresh,H5HF_free_section_t * sect)537 H5HF__sect_single_locate_parent(H5HF_hdr_t *hdr, hbool_t refresh,
538     H5HF_free_section_t *sect)
539 {
540     H5HF_indirect_t *sec_iblock;        /* Pointer to section indirect block */
541     unsigned sec_entry;                 /* Entry within section indirect block */
542     hbool_t did_protect;                /* Whether we protected the indirect block or not */
543     herr_t ret_value = SUCCEED;         /* Return value */
544 
545     FUNC_ENTER_STATIC
546 
547     /*
548      * Check arguments.
549      */
550     HDassert(hdr);
551     HDassert(hdr->man_dtable.curr_root_rows > 0);
552     HDassert(sect);
553 
554     /* Look up indirect block containing direct blocks for range */
555     if(H5HF__man_dblock_locate(hdr, sect->sect_info.addr, &sec_iblock, &sec_entry, &did_protect, H5AC__READ_ONLY_FLAG) < 0)
556         HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section")
557 
558     /* Increment reference count on indirect block that free section is in */
559     if(H5HF_iblock_incr(sec_iblock) < 0)
560         HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
561 
562     /* Check for refreshing existing parent information */
563     if(refresh) {
564         if(sect->u.single.parent) {
565             /* Release hold on previous parent indirect block */
566             if(H5HF__iblock_decr(sect->u.single.parent) < 0)
567                 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on section's indirect block")
568         } /* end if */
569     } /* end if */
570 
571     /* Set the information for the section */
572     sect->u.single.parent = sec_iblock;
573     sect->u.single.par_entry = sec_entry;
574 
575     /* Unlock indirect block */
576     if(H5HF__man_iblock_unprotect(sec_iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
577         HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
578     sec_iblock = NULL;
579 
580 done:
581     FUNC_LEAVE_NOAPI(ret_value)
582 } /* end H5HF__sect_single_locate_parent() */
583 
584 
585 /*-------------------------------------------------------------------------
586  * Function:    H5HF__sect_single_revive
587  *
588  * Purpose:     Update the memory information for a 'single' free section
589  *
590  * Return:      SUCCEED/FAIL
591  *
592  * Programmer:  Quincey Koziol
593  *              koziol@hdfgroup.org
594  *              May  8 2006
595  *
596  *-------------------------------------------------------------------------
597  */
598 herr_t
H5HF__sect_single_revive(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)599 H5HF__sect_single_revive(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
600 {
601     herr_t ret_value = SUCCEED;         /* Return value */
602 
603     FUNC_ENTER_PACKAGE
604 
605     /*
606      * Check arguments.
607      */
608     HDassert(hdr);
609     HDassert(sect);
610     HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED);
611 
612     /* Check for root direct block */
613     if(hdr->man_dtable.curr_root_rows == 0) {
614         /* Set the information for the section */
615         HDassert(H5F_addr_defined(hdr->man_dtable.table_addr));
616         sect->u.single.parent = NULL;
617         sect->u.single.par_entry = 0;
618     } /* end if */
619     else {
620         /* Look up indirect block information for section */
621         if(H5HF__sect_single_locate_parent(hdr, FALSE, sect) < 0)
622             HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get section's parent info")
623     } /* end else */
624 
625     /* Section is "live" now */
626     sect->sect_info.state = H5FS_SECT_LIVE;
627 
628 done:
629     FUNC_LEAVE_NOAPI(ret_value)
630 } /* end H5HF__sect_single_revive() */
631 
632 
633 /*-------------------------------------------------------------------------
634  * Function:    H5HF_sect_single_dblock_info
635  *
636  * Purpose:     Retrieve the direct block information for a single section
637  *
638  * Return:      SUCCEED/FAIL
639  *
640  * Programmer:  Quincey Koziol
641  *              koziol@hdfgroup.org
642  *              October 24 2006
643  *
644  *-------------------------------------------------------------------------
645  */
646 herr_t
H5HF_sect_single_dblock_info(H5HF_hdr_t * hdr,const H5HF_free_section_t * sect,haddr_t * dblock_addr,size_t * dblock_size)647 H5HF_sect_single_dblock_info(H5HF_hdr_t *hdr, const H5HF_free_section_t *sect,
648     haddr_t *dblock_addr, size_t *dblock_size)
649 {
650     FUNC_ENTER_NOAPI_NOERR
651 
652     /*
653      * Check arguments.
654      */
655     HDassert(hdr);
656     HDassert(sect);
657     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
658     HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
659     HDassert(dblock_addr);
660     HDassert(dblock_size);
661 
662     /* Check for root direct block */
663     if(hdr->man_dtable.curr_root_rows == 0) {
664         /* Retrieve direct block info from heap header */
665         HDassert(H5F_addr_defined(hdr->man_dtable.table_addr));
666         *dblock_addr =  hdr->man_dtable.table_addr;
667         *dblock_size =  hdr->man_dtable.cparam.start_block_size;
668     } /* end if */
669     else {
670         /* Retrieve direct block info from parent indirect block */
671         *dblock_addr =  sect->u.single.parent->ents[sect->u.single.par_entry].addr;
672         *dblock_size =  hdr->man_dtable.row_block_size[sect->u.single.par_entry / hdr->man_dtable.cparam.width];
673     } /* end else */
674 
675     FUNC_LEAVE_NOAPI(SUCCEED)
676 } /* end H5HF_sect_single_dblock_info() */
677 
678 
679 /*-------------------------------------------------------------------------
680  * Function:	H5HF__sect_single_reduce
681  *
682  * Purpose:	Reduce the size of a single section (possibly freeing it)
683  *              and re-add it back to the free space manager for the heap
684  *              (if it hasn't been freed)
685  *
686  * Return:	Non-negative on success/Negative on failure
687  *
688  * Programmer:	Quincey Koziol
689  *		koziol@ncsa.uiuc.edu
690  *		May 31 2006
691  *
692  *-------------------------------------------------------------------------
693  */
694 herr_t
H5HF__sect_single_reduce(H5HF_hdr_t * hdr,H5HF_free_section_t * sect,size_t amt)695 H5HF__sect_single_reduce(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
696     size_t amt)
697 {
698     herr_t ret_value = SUCCEED;         /* Return value */
699 
700     FUNC_ENTER_PACKAGE
701 
702     /*
703      * Check arguments.
704      */
705     HDassert(hdr);
706     HDassert(sect);
707     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
708     HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
709 
710     /* Check for eliminating the section */
711     if(sect->sect_info.size == amt) {
712         /* Free single section */
713         if(H5HF__sect_single_free((H5FS_section_info_t *)sect) < 0)
714             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free single section node")
715     } /* end if */
716     else {
717         /* Adjust information for section */
718         sect->sect_info.addr += amt;
719         sect->sect_info.size -= amt;
720 
721         /* Re-insert section node into heap's free space */
722         if(H5HF__space_add(hdr, sect, 0) < 0)
723             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add single section to free space manager")
724     } /* end else */
725 
726 done:
727     FUNC_LEAVE_NOAPI(ret_value)
728 } /* end H5HF__sect_single_reduce() */
729 
730 
731 /*-------------------------------------------------------------------------
732  * Function:	H5HF__sect_single_full_dblock
733  *
734  * Purpose:	Checks if a single section covers the entire direct block
735  *              that it resides in, and converts it to a row section if so
736  *
737  * Note:        Does not convert a single section to a row section if the
738  *              single section is for a root direct block
739  *
740  * Return:	Success:	non-negative
741  *		Failure:	negative
742  *
743  * Programmer:	Quincey Koziol
744  *              Thursday, July 27, 2006
745  *
746  *-------------------------------------------------------------------------
747  */
748 static herr_t
H5HF__sect_single_full_dblock(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)749 H5HF__sect_single_full_dblock(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
750 {
751     haddr_t dblock_addr;                /* Section's direct block's address */
752     size_t dblock_size;                 /* Section's direct block's size */
753     size_t dblock_overhead;             /* Direct block's overhead */
754     herr_t ret_value = SUCCEED;         /* Return value */
755 
756     FUNC_ENTER_PACKAGE
757 
758     /* Check arguments. */
759     HDassert(sect);
760     HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
761     HDassert(hdr);
762 
763     /* Retrieve direct block address from section */
764     if(H5HF_sect_single_dblock_info(hdr, sect, &dblock_addr, &dblock_size) < 0)
765         HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve direct block information")
766 
767     /* Check for section occupying entire direct block */
768     /* (and not the root direct block) */
769     dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
770     if((dblock_size - dblock_overhead) == sect->sect_info.size &&
771             hdr->man_dtable.curr_root_rows > 0) {
772         H5HF_direct_t *dblock;          /* Pointer to direct block for section */
773         hbool_t parent_removed;         /* Whether the direct block parent was removed from the file */
774 
775         if(NULL == (dblock = H5HF__man_dblock_protect(hdr, dblock_addr, dblock_size, sect->u.single.parent, sect->u.single.par_entry, H5AC__NO_FLAGS_SET)))
776             HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block")
777         HDassert(H5F_addr_eq(dblock->block_off + dblock_overhead, sect->sect_info.addr));
778 
779         /* Convert 'single' section into 'row' section */
780         if(H5HF_sect_row_from_single(hdr, sect, dblock) < 0)
781             HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't convert single section into row section")
782 
783         /* Destroy direct block */
784         if(H5HF__man_dblock_destroy(hdr, dblock, dblock_addr, &parent_removed) < 0)
785             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block")
786         dblock = NULL;
787 
788         /* If the parent for this direct block was removed and the indirect
789          *      section is still "live", switch it to the "serialized" state.
790          */
791         if(parent_removed && H5FS_SECT_LIVE == sect->u.row.under->sect_info.state)
792             if(H5HF__sect_row_parent_removed(sect) < 0)
793                 HGOTO_ERROR(H5E_HEAP, H5E_CANTUPDATE, FAIL, "can't update section info")
794     } /* end if */
795 
796 done:
797     FUNC_LEAVE_NOAPI(ret_value)
798 } /* H5HF__sect_single_full_dblock() */
799 
800 
801 /*-------------------------------------------------------------------------
802  * Function:	H5HF__sect_single_add
803  *
804  * Purpose:	Perform any actions on section as it is added to free space
805  *              manager
806  *
807  * Return:	Success:	non-negative
808  *		Failure:	negative
809  *
810  * Programmer:	Quincey Koziol
811  *              Thursday, July 27, 2006
812  *
813  *-------------------------------------------------------------------------
814  */
815 static herr_t
H5HF__sect_single_add(H5FS_section_info_t ** _sect,unsigned * flags,void * _udata)816 H5HF__sect_single_add(H5FS_section_info_t **_sect, unsigned *flags, void *_udata)
817 {
818     herr_t ret_value = SUCCEED;         /* Return value */
819 
820     FUNC_ENTER_STATIC
821 
822     /* Don't need to check section if we are deserializing, because it should
823      *  have already been checked when it was first added
824      */
825     if(!(*flags & H5FS_ADD_DESERIALIZING)) {
826         H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect;   /* Fractal heap free section */
827         H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata;   /* User callback data */
828         H5HF_hdr_t *hdr = udata->hdr;       /* Fractal heap header */
829 
830         /* Sanity check */
831         HDassert(sect);
832         HDassert(hdr);
833 
834         /* Check if single section covers entire direct block it's in */
835         /* (converts to row section possibly) */
836         if(H5HF__sect_single_full_dblock(hdr, (*sect)) < 0)
837             HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't check/convert single section")
838 
839         /* Set the "returned space" flag if the single section was changed
840          *      into a row section, so the "merging & shrinking" algorithm
841          *      gets executed in the free space manager
842          */
843         if((*sect)->sect_info.type != H5HF_FSPACE_SECT_SINGLE)
844             *flags |= H5FS_ADD_RETURNED_SPACE;
845     } /* end if */
846 
847 done:
848     FUNC_LEAVE_NOAPI(ret_value)
849 } /* H5HF__sect_single_add() */
850 
851 
852 /*-------------------------------------------------------------------------
853  * Function:	H5HF__sect_single_deserialize
854  *
855  * Purpose:	Deserialize a buffer into a "live" single section
856  *
857  * Return:	Success:	non-negative
858  *		Failure:	negative
859  *
860  * Programmer:	Quincey Koziol
861  *              Monday, May  1, 2006
862  *
863  *-------------------------------------------------------------------------
864  */
865 static H5FS_section_info_t *
H5HF__sect_single_deserialize(const H5FS_section_class_t H5_ATTR_UNUSED * cls,const uint8_t H5_ATTR_UNUSED * buf,haddr_t sect_addr,hsize_t sect_size,unsigned H5_ATTR_UNUSED * des_flags)866 H5HF__sect_single_deserialize(const H5FS_section_class_t H5_ATTR_UNUSED *cls,
867     const uint8_t H5_ATTR_UNUSED *buf, haddr_t sect_addr,
868     hsize_t sect_size, unsigned H5_ATTR_UNUSED *des_flags)
869 {
870     H5HF_free_section_t *new_sect;      /* New section */
871     H5FS_section_info_t *ret_value = NULL;      /* Return value */
872 
873     FUNC_ENTER_STATIC
874 
875     /* Check arguments. */
876     HDassert(H5F_addr_defined(sect_addr));
877     HDassert(sect_size);
878 
879     /* Create free list section node */
880     if(NULL == (new_sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_SINGLE, sect_addr, sect_size, H5FS_SECT_SERIALIZED)))
881         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "allocation failed for direct block free list section")
882 
883     /* Set return value */
884     ret_value = (H5FS_section_info_t *)new_sect;
885 
886 done:
887     FUNC_LEAVE_NOAPI(ret_value)
888 } /* H5HF__sect_single_deserialize() */
889 
890 
891 /*-------------------------------------------------------------------------
892  * Function:	H5HF__sect_single_can_merge
893  *
894  * Purpose:	Can two sections of this type merge?
895  *
896  * Note:        Second section must be "after" first section
897  *
898  * Return:	Success:	non-negative (TRUE/FALSE)
899  *
900  *		Failure:	negative
901  *
902  * Programmer:	Quincey Koziol
903  *              Wednesday, May 17, 2006
904  *
905  *-------------------------------------------------------------------------
906  */
907 static htri_t
H5HF__sect_single_can_merge(const H5FS_section_info_t * _sect1,const H5FS_section_info_t * _sect2,void H5_ATTR_UNUSED * _udata)908 H5HF__sect_single_can_merge(const H5FS_section_info_t *_sect1,
909     const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
910 {
911     const H5HF_free_section_t *sect1 = (const H5HF_free_section_t *)_sect1;   /* Fractal heap free section */
912     const H5HF_free_section_t *sect2 = (const H5HF_free_section_t *)_sect2;   /* Fractal heap free section */
913     htri_t ret_value = FALSE;           /* Return value */
914 
915     FUNC_ENTER_STATIC_NOERR
916 
917     /* Check arguments. */
918     HDassert(sect1);
919     HDassert(sect2);
920     HDassert(sect1->sect_info.type == sect2->sect_info.type);   /* Checks "MERGE_SYM" flag */
921     HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
922 
923     /* Check if second section adjoins first section */
924     /* (This can only occur within a direct block, due to the direct block
925      *  overhead at the beginning of a block, so no need to check if sections
926      *  are actually within the same direct block)
927      */
928     if(H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr))
929         HGOTO_DONE(TRUE)
930 
931 done:
932     FUNC_LEAVE_NOAPI(ret_value)
933 } /* H5HF__sect_single_can_merge() */
934 
935 
936 /*-------------------------------------------------------------------------
937  * Function:	H5HF__sect_single_merge
938  *
939  * Purpose:	Merge two sections of this type
940  *
941  * Note:        Second section always merges into first node
942  *
943  * Return:	Success:	non-negative
944  *
945  *		Failure:	negative
946  *
947  * Programmer:	Quincey Koziol
948  *              Wednesday, May 17, 2006
949  *
950  *-------------------------------------------------------------------------
951  */
952 static herr_t
H5HF__sect_single_merge(H5FS_section_info_t ** _sect1,H5FS_section_info_t * _sect2,void * _udata)953 H5HF__sect_single_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
954     void *_udata)
955 {
956     H5HF_free_section_t **sect1 = (H5HF_free_section_t **)_sect1;   /* Fractal heap free section */
957     H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2;   /* Fractal heap free section */
958     H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata;   /* User callback data */
959     H5HF_hdr_t *hdr = udata->hdr;       /* Fractal heap header */
960     herr_t ret_value = SUCCEED;         /* Return value */
961 
962     FUNC_ENTER_STATIC
963 
964     /* Check arguments. */
965     HDassert(sect1);
966     HDassert((*sect1)->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
967     HDassert(sect2);
968     HDassert(sect2->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
969     HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
970 
971     /* Add second section's size to first section */
972     (*sect1)->sect_info.size += sect2->sect_info.size;
973 
974     /* Get rid of second section */
975     if(H5HF__sect_single_free((H5FS_section_info_t *)sect2) < 0)
976         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
977 
978     /* Check to see if we should revive first section */
979     if((*sect1)->sect_info.state != H5FS_SECT_LIVE)
980         if(H5HF__sect_single_revive(hdr, (*sect1)) < 0)
981             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section")
982 
983     /* Check if single section covers entire direct block it's in */
984     /* (converts to row section possibly) */
985     if(H5HF__sect_single_full_dblock(hdr, (*sect1)) < 0)
986         HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't check/convert single section")
987 
988 done:
989     FUNC_LEAVE_NOAPI(ret_value)
990 } /* H5HF__sect_single_merge() */
991 
992 
993 /*-------------------------------------------------------------------------
994  * Function:	H5HF__sect_single_can_shrink
995  *
996  * Purpose:	Can this section shrink the container?
997  *
998  * Note:        This isn't actually shrinking the heap (since that's already
999  *              been done) as much as it's cleaning up _after_ the heap
1000  *              shrink.
1001  *
1002  * Return:	Success:	non-negative (TRUE/FALSE)
1003  *
1004  *		Failure:	negative
1005  *
1006  * Programmer:	Quincey Koziol
1007  *              Monday, June  5, 2006
1008  *
1009  *-------------------------------------------------------------------------
1010  */
1011 static htri_t
H5HF__sect_single_can_shrink(const H5FS_section_info_t * _sect,void * _udata)1012 H5HF__sect_single_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
1013 {
1014     const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect;   /* Fractal heap free section */
1015     H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata;   /* User callback data */
1016     H5HF_hdr_t *hdr = udata->hdr;       /* Fractal heap header */
1017     htri_t ret_value = FALSE;           /* Return value */
1018 
1019     FUNC_ENTER_STATIC_NOERR
1020 
1021     /* Check arguments. */
1022     HDassert(sect);
1023 
1024     /* Check for section occupying entire root direct block */
1025     /* (We shouldn't ever have a single section that occupies an entire
1026      *      direct block, unless it's in the root direct block (because it
1027      *      would have been converted into a row section, if there was an
1028      *      indirect block that covered it)
1029      */
1030     if(hdr->man_dtable.curr_root_rows == 0) {
1031         size_t dblock_size;                 /* Section's direct block's size */
1032         size_t dblock_overhead;             /* Direct block's overhead */
1033 
1034         dblock_size = hdr->man_dtable.cparam.start_block_size;
1035         dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
1036         if((dblock_size - dblock_overhead) == sect->sect_info.size)
1037             HGOTO_DONE(TRUE)
1038     } /* end if */
1039     else {
1040         /* We shouldn't have a situation where the 'next block' iterator
1041          *      is moved before a direct block that still has objects within it.
1042          */
1043         HDassert(hdr->man_iter_off > sect->sect_info.addr);
1044         HGOTO_DONE(FALSE)
1045     } /* end else */
1046 
1047 done:
1048     FUNC_LEAVE_NOAPI(ret_value)
1049 } /* H5HF__sect_single_can_shrink() */
1050 
1051 
1052 /*-------------------------------------------------------------------------
1053  * Function:	H5HF__sect_single_shrink
1054  *
1055  * Purpose:	Shrink container with section
1056  *
1057  * Return:	Success:	non-negative
1058  *
1059  *		Failure:	negative
1060  *
1061  * Programmer:	Quincey Koziol
1062  *              Monday, July 17, 2006
1063  *
1064  *-------------------------------------------------------------------------
1065  */
1066 static herr_t
H5HF__sect_single_shrink(H5FS_section_info_t ** _sect,void * _udata)1067 H5HF__sect_single_shrink(H5FS_section_info_t **_sect, void *_udata)
1068 {
1069     H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect;   /* Fractal heap free section */
1070     H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata;   /* User callback data */
1071     H5HF_hdr_t *hdr = udata->hdr;       /* Fractal heap header */
1072     H5HF_direct_t *dblock;              /* Pointer to direct block for section */
1073     haddr_t dblock_addr;                /* Section's direct block's address */
1074     size_t dblock_size;                 /* Section's direct block's size */
1075     herr_t ret_value = SUCCEED;         /* Return value */
1076 
1077     FUNC_ENTER_STATIC
1078 
1079     /* Check arguments. */
1080     HDassert(sect);
1081     HDassert(*sect);
1082     HDassert((*sect)->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
1083 
1084     /* Check to see if we should revive section */
1085     if((*sect)->sect_info.state != H5FS_SECT_LIVE)
1086         if(H5HF__sect_single_revive(hdr, (*sect)) < 0)
1087             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section")
1088 
1089     /* Retrieve direct block address from section */
1090     if(H5HF_sect_single_dblock_info(hdr, (*sect), &dblock_addr, &dblock_size) < 0)
1091         HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve direct block information")
1092 
1093     /* Protect the direct block for the section */
1094     /* (should be a root direct block) */
1095     HDassert(dblock_addr == hdr->man_dtable.table_addr);
1096     if(NULL == (dblock = H5HF__man_dblock_protect(hdr, dblock_addr, dblock_size, (*sect)->u.single.parent, (*sect)->u.single.par_entry, H5AC__NO_FLAGS_SET)))
1097         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block")
1098     HDassert(H5F_addr_eq(dblock->block_off + dblock_size, (*sect)->sect_info.addr + (*sect)->sect_info.size));
1099 
1100     /* Get rid of section */
1101     if(H5HF__sect_single_free((H5FS_section_info_t *)*sect) < 0)
1102         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
1103 
1104     /* Destroy direct block */
1105     if(H5HF__man_dblock_destroy(hdr, dblock, dblock_addr, NULL) < 0)
1106         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block")
1107     dblock = NULL;
1108 
1109     /* Indicate that the section has been released */
1110     *sect = NULL;
1111 
1112 done:
1113     FUNC_LEAVE_NOAPI(ret_value)
1114 } /* H5HF__sect_single_shrink() */
1115 
1116 
1117 /*-------------------------------------------------------------------------
1118  * Function:	H5HF__sect_single_free
1119  *
1120  * Purpose:	Free a 'single' section node
1121  *
1122  * Return:	Success:	non-negative
1123  *
1124  *		Failure:	negative
1125  *
1126  * Programmer:	Quincey Koziol
1127  *              Wednesday, May 17, 2006
1128  *
1129  *-------------------------------------------------------------------------
1130  */
1131 herr_t
H5HF__sect_single_free(H5FS_section_info_t * _sect)1132 H5HF__sect_single_free(H5FS_section_info_t *_sect)
1133 {
1134     H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect;   /* Pointer to section to free */
1135     H5HF_indirect_t *parent = NULL;     /* Parent indirect block for section */
1136     herr_t ret_value = SUCCEED;         /* Return value */
1137 
1138     FUNC_ENTER_PACKAGE
1139 
1140     /* Check arguments. */
1141     HDassert(sect);
1142 
1143     /* Check for live reference to an indirect block */
1144     if(sect->sect_info.state == H5FS_SECT_LIVE) {
1145         /* Get parent indirect block, if there was one */
1146         if(sect->u.single.parent)
1147             parent = sect->u.single.parent;
1148     } /* end if */
1149 
1150     /* Release the section */
1151     if(H5HF_sect_node_free(sect, parent) < 0)
1152         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
1153 
1154 done:
1155     FUNC_LEAVE_NOAPI(ret_value)
1156 }   /* H5HF__sect_single_free() */
1157 
1158 
1159 /*-------------------------------------------------------------------------
1160  * Function:	H5HF__sect_single_valid
1161  *
1162  * Purpose:	Check the validity of a section
1163  *
1164  * Return:	Success:	non-negative
1165  *		Failure:	negative
1166  *
1167  * Programmer:	Quincey Koziol
1168  *              Friday, July 21, 2006
1169  *
1170  *-------------------------------------------------------------------------
1171  */
1172 static herr_t
H5HF__sect_single_valid(const H5FS_section_class_t H5_ATTR_UNUSED * cls,const H5FS_section_info_t * _sect)1173 H5HF__sect_single_valid(const H5FS_section_class_t H5_ATTR_UNUSED *cls, const H5FS_section_info_t *_sect)
1174 {
1175     const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect;   /* Pointer to section to check */
1176 
1177     FUNC_ENTER_STATIC_NOERR
1178 
1179     /* Check arguments. */
1180     HDassert(sect);
1181 
1182     if(sect->sect_info.state == H5FS_SECT_LIVE) {
1183         /* Check if this section is not in a direct block that is the root direct block */
1184         /* (not enough information to check on a single section in a root direct block) */
1185         if(sect->u.single.parent != NULL) {
1186             H5HF_indirect_t *iblock;    /* Indirect block that section's direct block resides in */
1187             haddr_t dblock_addr;        /* Direct block address */
1188             size_t dblock_size;         /* Direct block size */
1189             size_t dblock_overhead;     /* Direct block's overhead */
1190             unsigned dblock_status = 0; /* Direct block's status in the metadata cache */
1191             herr_t status;              /* Generic status value */
1192 
1193             /* Sanity check settings for section's direct block's parent */
1194             iblock = sect->u.single.parent;
1195             HDassert(H5F_addr_defined(iblock->ents[sect->u.single.par_entry].addr));
1196 
1197             /* Retrieve direct block address from section */
1198             status = H5HF_sect_single_dblock_info(iblock->hdr, (const H5HF_free_section_t *)sect, &dblock_addr, &dblock_size);
1199             HDassert(status >= 0);
1200             HDassert(H5F_addr_eq(iblock->ents[sect->u.single.par_entry].addr, dblock_addr));
1201             HDassert(dblock_size > 0);
1202 
1203             /* Check if the section is actually within the heap */
1204             HDassert(sect->sect_info.addr < iblock->hdr->man_iter_off);
1205 
1206             /* Check that the direct block has been merged correctly */
1207             dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(iblock->hdr);
1208             HDassert((sect->sect_info.size + dblock_overhead) < dblock_size);
1209 
1210             /* Check the direct block's status in the metadata cache */
1211             status = H5AC_get_entry_status(iblock->hdr->f, dblock_addr, &dblock_status);
1212             HDassert(status >= 0);
1213 
1214             /* If the direct block for the section isn't already protected,
1215              *  protect it here in order to check single section's sanity
1216              *  against it.
1217              */
1218             if(!(dblock_status & H5AC_ES__IS_PROTECTED)) {
1219                 H5HF_direct_t *dblock;      /* Direct block for section */
1220 
1221                 /* Protect the direct block for the section */
1222                 dblock = H5HF__man_dblock_protect(iblock->hdr, dblock_addr, dblock_size, iblock, sect->u.single.par_entry, H5AC__READ_ONLY_FLAG);
1223                 HDassert(dblock);
1224 
1225                 /* Sanity check settings for section */
1226                 HDassert(dblock_size == dblock->size);
1227                 HDassert(dblock->size > sect->sect_info.size);
1228                 HDassert(H5F_addr_lt(dblock->block_off, sect->sect_info.addr));
1229                 HDassert(H5F_addr_ge((dblock->block_off + dblock->size), (sect->sect_info.addr + sect->sect_info.size)));
1230 
1231                 /* Release direct block */
1232                 status = H5AC_unprotect(iblock->hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET);
1233                 HDassert(status >= 0);
1234             } /* end if */
1235         } /* end if */
1236     } /* end if */
1237 
1238     FUNC_LEAVE_NOAPI(SUCCEED)
1239 }   /* H5HF__sect_single_valid() */
1240 
1241 
1242 /*-------------------------------------------------------------------------
1243  * Function:	H5HF_sect_row_create
1244  *
1245  * Purpose:	Create a new 'row' section
1246  *
1247  * Return:	Success:	pointer to new section
1248  *
1249  *		Failure:	NULL
1250  *
1251  * Programmer:	Quincey Koziol
1252  *              Thursday, July  6, 2006
1253  *
1254  *-------------------------------------------------------------------------
1255  */
1256 static H5HF_free_section_t *
H5HF_sect_row_create(haddr_t sect_off,hsize_t sect_size,hbool_t is_first,unsigned row,unsigned col,unsigned nentries,H5HF_free_section_t * under_sect)1257 H5HF_sect_row_create(haddr_t sect_off, hsize_t sect_size, hbool_t is_first,
1258     unsigned row, unsigned col, unsigned nentries, H5HF_free_section_t *under_sect)
1259 {
1260     H5HF_free_section_t *sect = NULL;   /* 'Row' section created */
1261     H5HF_free_section_t *ret_value = NULL;      /* Return value */
1262 
1263     FUNC_ENTER_NOAPI_NOINIT
1264 
1265     /* Check arguments. */
1266     HDassert(sect_size);
1267     HDassert(nentries);
1268     HDassert(under_sect);
1269 
1270     /* Create 'row' free space section node */
1271     /* ("inherits" underlying indirect section's state) */
1272     if(NULL == (sect = H5HF_sect_node_new((unsigned)(is_first ? H5HF_FSPACE_SECT_FIRST_ROW : H5HF_FSPACE_SECT_NORMAL_ROW), sect_off, sect_size, under_sect->sect_info.state)))
1273         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for row section")
1274 
1275     /* Set the 'row' specific fields */
1276     sect->u.row.under = under_sect;
1277     sect->u.row.row = row;
1278     sect->u.row.col = col;
1279     sect->u.row.num_entries = nentries;
1280     sect->u.row.checked_out = FALSE;
1281 
1282     /* Set return value */
1283     ret_value = sect;
1284 
1285 done:
1286     FUNC_LEAVE_NOAPI(ret_value)
1287 } /* H5HF_sect_row_create() */
1288 
1289 
1290 /*-------------------------------------------------------------------------
1291  * Function:	H5HF_sect_row_from_single
1292  *
1293  * Purpose:	Convert a 'single' section into a 'row' section
1294  *
1295  * Return:	Non-negative on success/Negative on failure
1296  *
1297  * Programmer:	Quincey Koziol
1298  *		koziol@ncsa.uiuc.edu
1299  *		July  6 2006
1300  *
1301  *-------------------------------------------------------------------------
1302  */
1303 static herr_t
H5HF_sect_row_from_single(H5HF_hdr_t * hdr,H5HF_free_section_t * sect,H5HF_direct_t * dblock)1304 H5HF_sect_row_from_single(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
1305     H5HF_direct_t *dblock)
1306 {
1307     herr_t ret_value = SUCCEED;         /* Return value */
1308 
1309     FUNC_ENTER_NOAPI_NOINIT
1310 
1311     /*
1312      * Check arguments.
1313      */
1314     HDassert(hdr);
1315     HDassert(sect);
1316     HDassert(dblock);
1317 
1318     /* Convert 'single' section information to 'row' section info */
1319     sect->sect_info.addr = dblock->block_off;
1320     sect->sect_info.type = H5HF_FSPACE_SECT_FIRST_ROW;
1321     sect->u.row.row = dblock->par_entry / hdr->man_dtable.cparam.width;
1322     sect->u.row.col = dblock->par_entry % hdr->man_dtable.cparam.width;
1323     sect->u.row.num_entries = 1;
1324     sect->u.row.checked_out = FALSE;
1325 
1326     /* Create indirect section that underlies the row section */
1327     if(NULL == (sect->u.row.under = H5HF_sect_indirect_for_row(hdr, dblock->parent, sect)))
1328         HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "serializing row section not supported yet")
1329 
1330     /* Release single section's hold on underlying indirect block */
1331     if(H5HF__iblock_decr(dblock->parent) < 0)
1332         HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
1333 
1334 done:
1335     FUNC_LEAVE_NOAPI(ret_value)
1336 } /* end H5HF_sect_row_from_single() */
1337 
1338 
1339 /*-------------------------------------------------------------------------
1340  * Function:	H5HF__sect_row_revive
1341  *
1342  * Purpose:	Update the memory information for a 'row' free section
1343  *
1344  * Return:	Non-negative on success/Negative on failure
1345  *
1346  * Programmer:	Quincey Koziol
1347  *		koziol@ncsa.uiuc.edu
1348  *		July  6 2006
1349  *
1350  *-------------------------------------------------------------------------
1351  */
1352 herr_t
H5HF__sect_row_revive(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)1353 H5HF__sect_row_revive(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
1354 {
1355     herr_t ret_value = SUCCEED;         /* Return value */
1356 
1357     FUNC_ENTER_PACKAGE
1358 
1359     /*
1360      * Check arguments.
1361      */
1362     HDassert(hdr);
1363     HDassert(sect);
1364     HDassert(sect->u.row.under);
1365 
1366     /* If the indirect section's iblock has been removed from the cache, but the
1367      * section is still marked as "live", switch it to the "serialized" state.
1368      */
1369     if((H5FS_SECT_LIVE == sect->u.row.under->sect_info.state)
1370             && (TRUE == sect->u.row.under->u.indirect.u.iblock->removed_from_cache))
1371         if(H5HF__sect_row_parent_removed(sect) < 0)
1372             HGOTO_ERROR(H5E_HEAP, H5E_CANTUPDATE, FAIL, "can't update section info")
1373 
1374     /* Pass along "revive" request to underlying indirect section */
1375     /* (which will mark this section as "live") */
1376     if(H5HF__sect_indirect_revive_row(hdr, sect->u.row.under) < 0)
1377         HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
1378     HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
1379 
1380 done:
1381     FUNC_LEAVE_NOAPI(ret_value)
1382 } /* end H5HF__sect_row_revive() */
1383 
1384 
1385 /*-------------------------------------------------------------------------
1386  * Function:	H5HF__sect_row_reduce
1387  *
1388  * Purpose:	Reduce the size of a row section (possibly freeing it)
1389  *              and re-add it back to the free space manager for the heap
1390  *              (if it hasn't been freed)
1391  *
1392  * Return:	Non-negative on success/Negative on failure
1393  *
1394  * Programmer:	Quincey Koziol
1395  *		koziol@ncsa.uiuc.edu
1396  *		July  6 2006
1397  *
1398  *-------------------------------------------------------------------------
1399  */
1400 herr_t
H5HF__sect_row_reduce(H5HF_hdr_t * hdr,H5HF_free_section_t * sect,unsigned * entry_p)1401 H5HF__sect_row_reduce(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
1402     unsigned *entry_p)
1403 {
1404     hbool_t alloc_from_start;           /* Whether to allocate from the end of the row */
1405     herr_t ret_value = SUCCEED;         /* Return value */
1406 
1407     FUNC_ENTER_PACKAGE
1408 
1409     /*
1410      * Check arguments.
1411      */
1412     HDassert(hdr);
1413     HDassert(sect);
1414     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW ||
1415             sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
1416     HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
1417     HDassert(entry_p);
1418 
1419     /* Mark the row as checked out from the free space manager */
1420     HDassert(sect->u.row.checked_out == FALSE);
1421     sect->u.row.checked_out = TRUE;
1422 
1423     /* Forward row section to indirect routines, to handle reducing underlying indirect section */
1424     alloc_from_start = FALSE;
1425     if(H5HF__sect_indirect_reduce_row(hdr, sect, &alloc_from_start) < 0)
1426         HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce underlying section")
1427 
1428     /* Determine entry allocated */
1429     *entry_p = (sect->u.row.row * hdr->man_dtable.cparam.width) + sect->u.row.col;
1430     if(!alloc_from_start)
1431         *entry_p += (sect->u.row.num_entries - 1);
1432 
1433     /* Check for eliminating the section */
1434     if(sect->u.row.num_entries == 1) {
1435         /* Free row section */
1436         if(H5HF__sect_row_free((H5FS_section_info_t *)sect) < 0)
1437             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free row section node")
1438     } /* end if */
1439     else {
1440         /* Check whether to allocate from the beginning or end of the row */
1441         if(alloc_from_start) {
1442             /* Adjust section start */
1443             sect->sect_info.addr += hdr->man_dtable.row_block_size[sect->u.row.row];
1444             sect->u.row.col++;
1445         } /* end else */
1446 
1447         /* Adjust span of blocks covered */
1448         sect->u.row.num_entries--;
1449 
1450         /* Check the row back in */
1451         sect->u.row.checked_out = FALSE;
1452 
1453         /* Add 'row' section back to free space list */
1454         if(H5HF__space_add(hdr, sect, 0) < 0)
1455             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add indirect section to free space manager")
1456     } /* end else */
1457 
1458 done:
1459     FUNC_LEAVE_NOAPI(ret_value)
1460 } /* end H5HF__sect_row_reduce() */
1461 
1462 
1463 /*-------------------------------------------------------------------------
1464  * Function:	H5HF__sect_row_first
1465  *
1466  * Purpose:	Make row a "first row"
1467  *
1468  * Return:	Non-negative on success/Negative on failure
1469  *
1470  * Programmer:	Quincey Koziol
1471  *		koziol@ncsa.uiuc.edu
1472  *		July 10 2006
1473  *
1474  *-------------------------------------------------------------------------
1475  */
1476 static herr_t
H5HF__sect_row_first(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)1477 H5HF__sect_row_first(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
1478 {
1479     herr_t ret_value = SUCCEED;         /* Return value */
1480 
1481     FUNC_ENTER_STATIC
1482 
1483     /* Sanity check */
1484     HDassert(hdr);
1485     HDassert(sect);
1486     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
1487 
1488     /* If the row is already checked out from the free space manager, just
1489      *  change it's class directly and the free space manager will adjust when
1490      *  it is checked back in.
1491      */
1492     if(sect->u.row.checked_out)
1493         sect->sect_info.type = H5HF_FSPACE_SECT_FIRST_ROW;
1494     else
1495         /* Change row section to be the "first row" */
1496         if(H5HF__space_sect_change_class(hdr, sect, H5HF_FSPACE_SECT_FIRST_ROW) < 0)
1497             HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "can't set row section to be first row")
1498 
1499 done:
1500     FUNC_LEAVE_NOAPI(ret_value)
1501 } /* end H5HF__sect_row_first() */
1502 
1503 
1504 /*-------------------------------------------------------------------------
1505  * Function:	H5HF_sect_row_get_iblock
1506  *
1507  * Purpose:	Retrieve the indirect block for a row section
1508  *
1509  * Return:	Pointer to indirect block on success/NULL on failure
1510  *
1511  * Programmer:	Quincey Koziol
1512  *		koziol@ncsa.uiuc.edu
1513  *		July  9 2006
1514  *
1515  *-------------------------------------------------------------------------
1516  */
1517 H5HF_indirect_t *
H5HF_sect_row_get_iblock(H5HF_free_section_t * sect)1518 H5HF_sect_row_get_iblock(H5HF_free_section_t *sect)
1519 {
1520     H5HF_indirect_t *ret_value = NULL;          /* Return value */
1521 
1522     FUNC_ENTER_NOAPI_NOINIT_NOERR
1523 
1524     /*
1525      * Check arguments.
1526      */
1527     HDassert(sect);
1528     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW ||
1529             sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
1530     HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
1531 
1532     ret_value = H5HF_sect_indirect_get_iblock(sect->u.row.under);
1533 
1534     FUNC_LEAVE_NOAPI(ret_value)
1535 } /* end H5HF_sect_row_get_iblock() */
1536 
1537 
1538 /*-------------------------------------------------------------------------
1539  * Function:	H5HF__sect_row_parent_removed
1540  *
1541  * Purpose:	Update the information for a row and its parent indirect
1542  *              when an indirect block is removed from the metadata cache.
1543  *
1544  * Return:	Non-negative on success / Negative on failure
1545  *
1546  * Programmer:	Quincey Koziol
1547  *		koziol@lbl.gov
1548  *		February 4 2018
1549  *
1550  *-------------------------------------------------------------------------
1551  */
1552 static herr_t
H5HF__sect_row_parent_removed(H5HF_free_section_t * sect)1553 H5HF__sect_row_parent_removed(H5HF_free_section_t *sect)
1554 {
1555     hsize_t tmp_iblock_off;             /* Indirect block offset for row */
1556     unsigned u;                         /* Local index value */
1557     herr_t ret_value = SUCCEED;         /* Return value */
1558 
1559     FUNC_ENTER_STATIC
1560 
1561     /* Check arguments */
1562     HDassert(sect);
1563 
1564     /* Get a copy of the indirect block's offset before decrementing refcount on it */
1565     tmp_iblock_off = sect->u.row.under->u.indirect.u.iblock->block_off;
1566 
1567     /* Decrement the refcount on the indirect block, since serialized sections don't hold a reference */
1568     if(H5HF__iblock_decr(sect->u.row.under->u.indirect.u.iblock) < 0)
1569         HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
1570 
1571     /* Switch indirect block info to serialized form */
1572     /* (Overwrites iblock pointer in the indirect section) */
1573     sect->u.row.under->u.indirect.u.iblock_off = tmp_iblock_off;
1574     sect->u.row.under->u.indirect.iblock_entries = 0;
1575 
1576     /* Loop over derived row sections and mark them all as 'live' now */
1577     for(u = 0; u < sect->u.row.under->u.indirect.dir_nrows; u++)
1578         sect->u.row.under->u.indirect.dir_rows[u]->sect_info.state = H5FS_SECT_SERIALIZED;
1579 
1580     /* Mark the indirect section as serialized now */
1581     sect->u.row.under->sect_info.state = H5FS_SECT_SERIALIZED;
1582 
1583     /* Mark the row section as serialized now */
1584     sect->sect_info.state = H5FS_SECT_SERIALIZED;
1585 
1586 done:
1587     FUNC_LEAVE_NOAPI(ret_value)
1588 } /* end H5HF__sect_row_parent_removed() */
1589 
1590 
1591 /*-------------------------------------------------------------------------
1592  * Function:	H5HF__sect_row_init_cls
1593  *
1594  * Purpose:	Initialize the "row" section class structure
1595  *
1596  * Note:	Since 'row' sections are proxies for 'indirect' sections, this
1597  *              routine forwards call to 'indirect' class initialization
1598  *
1599  * Return:	Success:	non-negative
1600  *
1601  *		Failure:	negative
1602  *
1603  * Programmer:	Quincey Koziol
1604  *              Monday, July  6, 2006
1605  *
1606  *-------------------------------------------------------------------------
1607  */
1608 static herr_t
H5HF__sect_row_init_cls(H5FS_section_class_t * cls,void * _udata)1609 H5HF__sect_row_init_cls(H5FS_section_class_t *cls, void *_udata)
1610 {
1611     H5HF_hdr_t *hdr = (H5HF_hdr_t *)_udata; /* Fractal heap header */
1612     herr_t ret_value = SUCCEED;         /* Return value */
1613 
1614     FUNC_ENTER_STATIC
1615 
1616     /* Check arguments. */
1617     HDassert(cls);
1618     HDassert(hdr);
1619 
1620     /* Call common class initialization */
1621     if(H5HF_sect_init_cls(cls, hdr) < 0)
1622 	HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize common section class")
1623 
1624     /* First row sections actually are proxies for indirection sections on disk */
1625     if(cls->type == H5HF_FSPACE_SECT_FIRST_ROW)
1626         cls->serial_size = H5HF_SECT_INDIRECT_SERIAL_SIZE(hdr);
1627     else
1628         cls->serial_size = 0;
1629 
1630 done:
1631     FUNC_LEAVE_NOAPI(ret_value)
1632 } /* H5HF__sect_row_init_cls() */
1633 
1634 
1635 /*-------------------------------------------------------------------------
1636  * Function:	H5HF__sect_row_term_cls
1637  *
1638  * Purpose:	Terminate the "row" section class structure
1639  *
1640  * Note:	Since 'row' sections are proxies for 'indirect' sections, this
1641  *              routine forwards call to 'indirect' class termination
1642  *
1643  * Return:	Success:	non-negative
1644  *
1645  *		Failure:	negative
1646  *
1647  * Programmer:	Quincey Koziol
1648  *              Monday, July  6, 2006
1649  *
1650  *-------------------------------------------------------------------------
1651  */
1652 static herr_t
H5HF__sect_row_term_cls(H5FS_section_class_t * cls)1653 H5HF__sect_row_term_cls(H5FS_section_class_t *cls)
1654 {
1655     herr_t ret_value = SUCCEED;         /* Return value */
1656 
1657     FUNC_ENTER_STATIC
1658 
1659     /* Check arguments. */
1660     HDassert(cls);
1661 
1662     /* Call common class termination */
1663     if(H5HF_sect_term_cls(cls) < 0)
1664 	HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't terminate common section class")
1665 
1666 done:
1667     FUNC_LEAVE_NOAPI(ret_value)
1668 } /* H5HF__sect_row_term_cls() */
1669 
1670 
1671 /*-------------------------------------------------------------------------
1672  * Function:	H5HF__sect_row_serialize
1673  *
1674  * Purpose:	Serialize a "live" row section into a buffer
1675  *
1676  * Return:	Success:	non-negative
1677  *
1678  *		Failure:	negative
1679  *
1680  * Programmer:	Quincey Koziol
1681  *              Thursday, July  6, 2006
1682  *
1683  *-------------------------------------------------------------------------
1684  */
1685 static herr_t
H5HF__sect_row_serialize(const H5FS_section_class_t * cls,const H5FS_section_info_t * _sect,uint8_t * buf)1686 H5HF__sect_row_serialize(const H5FS_section_class_t *cls,
1687     const H5FS_section_info_t *_sect, uint8_t *buf)
1688 {
1689     H5HF_hdr_t *hdr;                    /* Fractal heap header */
1690     const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect;
1691     herr_t ret_value = SUCCEED;         /* Return value */
1692 
1693     FUNC_ENTER_STATIC
1694 
1695     /* Check arguments. */
1696     HDassert(cls);
1697     HDassert(buf);
1698     HDassert(sect);
1699     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
1700     HDassert(sect->sect_info.addr == sect->u.row.under->sect_info.addr);
1701 
1702     /* Forward to indirect routine to serialize underlying section */
1703     hdr = ((H5HF_sect_private_t *)(cls->cls_private))->hdr;
1704     if(H5HF_sect_indirect_serialize(hdr, sect->u.row.under, buf) < 0)
1705         HGOTO_ERROR(H5E_HEAP, H5E_CANTSERIALIZE, FAIL, "can't serialize row section's underlying indirect section")
1706 
1707 done:
1708     FUNC_LEAVE_NOAPI(ret_value)
1709 } /* H5HF__sect_row_serialize() */
1710 
1711 
1712 /*-------------------------------------------------------------------------
1713  * Function:	H5HF__sect_row_deserialize
1714  *
1715  * Purpose:	Deserialize a buffer into a "live" row section
1716  *
1717  * Note:        Actually this routine just forwards to the 'indirect'
1718  *              deserialize routine, which creates the row section.
1719  *
1720  * Return:	Success:	non-negative
1721  *
1722  *		Failure:	negative
1723  *
1724  * Programmer:	Quincey Koziol
1725  *              Saturday, July 15, 2006
1726  *
1727  *-------------------------------------------------------------------------
1728  */
1729 static H5FS_section_info_t *
H5HF__sect_row_deserialize(const H5FS_section_class_t * cls,const uint8_t * buf,haddr_t sect_addr,hsize_t sect_size,unsigned * des_flags)1730 H5HF__sect_row_deserialize(const H5FS_section_class_t *cls, const uint8_t *buf,
1731     haddr_t sect_addr, hsize_t sect_size, unsigned *des_flags)
1732 {
1733     H5HF_hdr_t *hdr;                    /* Fractal heap header */
1734     H5FS_section_info_t *ret_value = NULL;      /* Return value */
1735 
1736     FUNC_ENTER_STATIC
1737 
1738     /* Check arguments. */
1739     HDassert(cls);
1740     HDassert(buf);
1741     HDassert(H5F_addr_defined(sect_addr));
1742     HDassert(sect_size);
1743 
1744     /* Forward to indirect routine to deserialize underlying section */
1745     hdr = ((H5HF_sect_private_t *)(cls->cls_private))->hdr;
1746     if(NULL ==  (ret_value = H5HF__sect_indirect_deserialize(hdr, buf, sect_addr, sect_size, des_flags)))
1747         HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't deserialize row section's underlying indirect section")
1748 
1749 done:
1750     FUNC_LEAVE_NOAPI(ret_value)
1751 } /* H5HF__sect_row_deserialize() */
1752 
1753 
1754 /*-------------------------------------------------------------------------
1755  * Function:	H5HF__sect_row_can_merge
1756  *
1757  * Purpose:	Can two sections of this type merge?
1758  *
1759  * Note:        Second section must be "after" first section
1760  *
1761  * Return:	Success:	non-negative (TRUE/FALSE)
1762  *
1763  *		Failure:	negative
1764  *
1765  * Programmer:	Quincey Koziol
1766  *              Thursday, July  6, 2006
1767  *
1768  *-------------------------------------------------------------------------
1769  */
1770 static htri_t
H5HF__sect_row_can_merge(const H5FS_section_info_t * _sect1,const H5FS_section_info_t * _sect2,void H5_ATTR_UNUSED * _udata)1771 H5HF__sect_row_can_merge(const H5FS_section_info_t *_sect1,
1772     const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
1773 {
1774     const H5HF_free_section_t *sect1 = (const H5HF_free_section_t *)_sect1;   /* Fractal heap free section */
1775     const H5HF_free_section_t *sect2 = (const H5HF_free_section_t *)_sect2;   /* Fractal heap free section */
1776     H5HF_free_section_t *top_indir_sect1, *top_indir_sect2; /* Top indirect section for each row */
1777     htri_t ret_value = FALSE;           /* Return value */
1778 
1779     FUNC_ENTER_STATIC_NOERR
1780 
1781     /* Check arguments. */
1782     HDassert(sect1);
1783     HDassert(sect1->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
1784     HDassert(sect2);
1785     HDassert(sect1->sect_info.type == sect2->sect_info.type);   /* Checks "MERGE_SYM" flag */
1786     HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
1787 
1788     /* Get the top indirect section underlying each row */
1789     top_indir_sect1 = H5HF_sect_indirect_top(sect1->u.row.under);
1790     HDassert(top_indir_sect1);
1791     top_indir_sect2 = H5HF_sect_indirect_top(sect2->u.row.under);
1792     HDassert(top_indir_sect2);
1793 
1794     /* Check if second section shares the same underlying indirect block as
1795      *  the first section, but doesn't already have same underlying indirect
1796      *  section.
1797      */
1798     if(top_indir_sect1 != top_indir_sect2) {
1799         if(H5HF_sect_indirect_iblock_off(sect1->u.row.under) == H5HF_sect_indirect_iblock_off(sect2->u.row.under)) {
1800             /* Check if second section adjoins first section */
1801             if(H5F_addr_eq((top_indir_sect1->sect_info.addr + top_indir_sect1->u.indirect.span_size), top_indir_sect2->sect_info.addr))
1802                 HGOTO_DONE(TRUE)
1803         } /* end if */
1804     } /* end if */
1805 
1806 done:
1807     FUNC_LEAVE_NOAPI(ret_value)
1808 } /* H5HF__sect_row_can_merge() */
1809 
1810 
1811 /*-------------------------------------------------------------------------
1812  * Function:	H5HF__sect_row_merge
1813  *
1814  * Purpose:	Merge two sections of this type
1815  *
1816  * Note:        Second section always merges into first node
1817  *
1818  * Return:	Success:	non-negative
1819  *
1820  *		Failure:	negative
1821  *
1822  * Programmer:	Quincey Koziol
1823  *              Thursday, July  6, 2006
1824  *
1825  *-------------------------------------------------------------------------
1826  */
1827 static herr_t
H5HF__sect_row_merge(H5FS_section_info_t ** _sect1,H5FS_section_info_t * _sect2,void * _udata)1828 H5HF__sect_row_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
1829     void *_udata)
1830 {
1831     H5HF_free_section_t **sect1 = (H5HF_free_section_t **)_sect1;   /* Fractal heap free section */
1832     H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2;   /* Fractal heap free section */
1833     H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata;   /* User callback data */
1834     H5HF_hdr_t *hdr = udata->hdr;       /* Fractal heap header */
1835     herr_t ret_value = SUCCEED;         /* Return value */
1836 
1837     FUNC_ENTER_STATIC
1838 
1839     /* Check arguments. */
1840     HDassert(sect1);
1841     HDassert((*sect1)->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
1842     HDassert(sect2);
1843     HDassert(sect2->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
1844 
1845     /* Check if second section is past end of "next block" iterator */
1846     if(sect2->sect_info.addr >= hdr->man_iter_off) {
1847         H5HF_free_section_t *top_indir_sect;    /* Top indirect section for row */
1848 
1849         /* Get the top indirect section underlying second row section */
1850         top_indir_sect = H5HF_sect_indirect_top(sect2->u.row.under);
1851 
1852         /* Shrink away underlying indirect section */
1853         if(H5HF__sect_indirect_shrink(hdr, top_indir_sect) < 0)
1854             HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't shrink underlying indirect section")
1855     } /* end if */
1856     else
1857         /* Merge rows' underlying indirect sections together */
1858         if(H5HF__sect_indirect_merge_row(hdr, (*sect1), sect2) < 0)
1859             HGOTO_ERROR(H5E_HEAP, H5E_CANTMERGE, FAIL, "can't merge underlying indirect sections")
1860 
1861 done:
1862     FUNC_LEAVE_NOAPI(ret_value)
1863 } /* H5HF__sect_row_merge() */
1864 
1865 
1866 /*-------------------------------------------------------------------------
1867  * Function:	H5HF__sect_row_can_shrink
1868  *
1869  * Purpose:	Can this section shrink the container?
1870  *
1871  * Note:        This isn't actually shrinking the heap (since that's already
1872  *              been done) as much as it's cleaning up _after_ the heap
1873  *              shrink.
1874  *
1875  * Return:	Success:	non-negative (TRUE/FALSE)
1876  *
1877  *		Failure:	negative
1878  *
1879  * Programmer:	Quincey Koziol
1880  *              Thursday, July  6, 2006
1881  *
1882  *-------------------------------------------------------------------------
1883  */
1884 static htri_t
H5HF__sect_row_can_shrink(const H5FS_section_info_t * _sect,void H5_ATTR_UNUSED * _udata)1885 H5HF__sect_row_can_shrink(const H5FS_section_info_t *_sect, void H5_ATTR_UNUSED *_udata)
1886 {
1887     const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect;   /* Fractal heap free section */
1888     H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata;   /* User callback data */
1889     H5HF_hdr_t *hdr = udata->hdr;       /* Fractal heap header */
1890     htri_t ret_value = FALSE;           /* Return value */
1891 
1892     FUNC_ENTER_STATIC_NOERR
1893 
1894     /* Check arguments. */
1895     HDassert(sect);
1896     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
1897 
1898     /* Check if section is past end of "next block" iterator */
1899     if(sect->sect_info.addr >= hdr->man_iter_off)
1900         HGOTO_DONE(TRUE)
1901 
1902 done:
1903     FUNC_LEAVE_NOAPI(ret_value)
1904 } /* H5HF__sect_row_can_shrink() */
1905 
1906 
1907 /*-------------------------------------------------------------------------
1908  * Function:	H5HF__sect_row_shrink
1909  *
1910  * Purpose:	Shrink container with section
1911  *
1912  * Return:	Success:	non-negative
1913  *
1914  *		Failure:	negative
1915  *
1916  * Programmer:	Quincey Koziol
1917  *              Thursday, July  6, 2006
1918  *
1919  *-------------------------------------------------------------------------
1920  */
1921 static herr_t
H5HF__sect_row_shrink(H5FS_section_info_t ** _sect,void * _udata)1922 H5HF__sect_row_shrink(H5FS_section_info_t **_sect, void *_udata)
1923 {
1924     H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect;   /* Fractal heap free section */
1925     H5HF_free_section_t *top_indir_sect; /* Top indirect section for row */
1926     H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata;   /* User callback data */
1927     H5HF_hdr_t *hdr = udata->hdr;       /* Fractal heap header */
1928     herr_t ret_value = SUCCEED;         /* Return value */
1929 
1930     FUNC_ENTER_STATIC
1931 
1932     /* Check arguments. */
1933     HDassert(sect);
1934     HDassert(*sect);
1935     HDassert((*sect)->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
1936 
1937     /* Get the top indirect section underlying each row */
1938     top_indir_sect = H5HF_sect_indirect_top((*sect)->u.row.under);
1939 
1940     /* Shrink away underlying indirect section */
1941     if(H5HF__sect_indirect_shrink(hdr, top_indir_sect) < 0)
1942         HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't shrink underlying indirect section")
1943 
1944     /* Indicate that the section has been released */
1945     *sect = NULL;
1946 
1947 done:
1948     FUNC_LEAVE_NOAPI(ret_value)
1949 } /* H5HF__sect_row_shrink() */
1950 
1951 
1952 /*-------------------------------------------------------------------------
1953  * Function:	H5HF__sect_row_free_real
1954  *
1955  * Purpose:	Free a 'row' section node
1956  *
1957  * Return:	Success:	non-negative
1958  *
1959  *		Failure:	negative
1960  *
1961  * Programmer:	Quincey Koziol
1962  *              Thursday, July  6, 2006
1963  *
1964  *-------------------------------------------------------------------------
1965  */
1966 static herr_t
H5HF__sect_row_free_real(H5HF_free_section_t * sect)1967 H5HF__sect_row_free_real(H5HF_free_section_t *sect)
1968 {
1969     herr_t ret_value = SUCCEED;               /* Return value */
1970 
1971     FUNC_ENTER_STATIC
1972 
1973     HDassert(sect);
1974 
1975     /* Release the section */
1976     if(H5HF_sect_node_free(sect, NULL) < 0)
1977         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
1978 
1979 done:
1980     FUNC_LEAVE_NOAPI(ret_value)
1981 }   /* H5HF__sect_row_free_real() */
1982 
1983 
1984 /*-------------------------------------------------------------------------
1985  * Function:	H5HF__sect_row_free
1986  *
1987  * Purpose:	Free a 'row' section node
1988  *
1989  * Return:	Success:	non-negative
1990  *
1991  *		Failure:	negative
1992  *
1993  * Programmer:	Quincey Koziol
1994  *              Thursday, July  6, 2006
1995  *
1996  *-------------------------------------------------------------------------
1997  */
1998 static herr_t
H5HF__sect_row_free(H5FS_section_info_t * _sect)1999 H5HF__sect_row_free(H5FS_section_info_t *_sect)
2000 {
2001     H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect;   /* Pointer to section to free */
2002     herr_t ret_value = SUCCEED;               /* Return value */
2003 
2004     FUNC_ENTER_STATIC
2005 
2006     HDassert(sect);
2007     HDassert(sect->u.row.under);
2008 
2009     /* Decrement the ref. count on the row section's underlying indirect section */
2010     if(H5HF_sect_indirect_decr(sect->u.row.under) < 0)
2011         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't detach section node")
2012 
2013     /* Release the section */
2014     if(H5HF__sect_row_free_real(sect) < 0)
2015         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
2016 
2017 done:
2018     FUNC_LEAVE_NOAPI(ret_value)
2019 }   /* H5HF__sect_row_free() */
2020 
2021 
2022 /*-------------------------------------------------------------------------
2023  * Function:	H5HF__sect_row_valid
2024  *
2025  * Purpose:	Check the validity of a section
2026  *
2027  * Return:	Success:	non-negative
2028  *		Failure:	negative
2029  *
2030  * Programmer:	Quincey Koziol
2031  *              Friday, July 21, 2006
2032  *
2033  *-------------------------------------------------------------------------
2034  */
2035 static herr_t
H5HF__sect_row_valid(const H5FS_section_class_t * cls,const H5FS_section_info_t * _sect)2036 H5HF__sect_row_valid(const H5FS_section_class_t *cls, const H5FS_section_info_t *_sect)
2037 {
2038     H5HF_sect_private_t *cls_prvt;    /* Pointer to class private info */
2039     const H5HF_hdr_t *hdr;      /* Fractal heap header */
2040     const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect;   /* Pointer to section to check */
2041     const H5HF_free_section_t *indir_sect;   /* Pointer to underlying indirect section */
2042     unsigned indir_idx;         /* Index of row in underlying indirect section's row array */
2043 
2044     FUNC_ENTER_STATIC_NOERR
2045 
2046     /* Basic sanity check */
2047     HDassert(cls);
2048     HDassert(sect);
2049 
2050     /* Retrieve class private information */
2051     cls_prvt = (H5HF_sect_private_t *)cls->cls_private;
2052     hdr = cls_prvt->hdr;
2053 
2054     /* Sanity checking on the row */
2055     HDassert(sect->u.row.under);
2056     HDassert(sect->u.row.num_entries);
2057     HDassert(sect->u.row.checked_out == FALSE);
2058     indir_sect = sect->u.row.under;
2059     indir_idx = sect->u.row.row - indir_sect->u.indirect.row;
2060     HDassert(indir_sect->u.indirect.dir_rows[indir_idx] == sect);
2061 
2062     /* Check if the section is actually within the heap */
2063     HDassert(sect->sect_info.addr < hdr->man_iter_off);
2064 
2065     /* Different checking for different kinds of rows */
2066     if(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW) {
2067         H5HF_free_section_t *top_indir_sect;    /* Top indirect section for row */
2068 
2069         /* Some extra sanity checks on the row */
2070         HDassert(sect->u.row.row == indir_sect->u.indirect.row);
2071 
2072         /* Get the top indirect section underlying row */
2073         top_indir_sect = H5HF_sect_indirect_top(sect->u.row.under);
2074 
2075         /* Check that the row's underlying indirect section is valid */
2076         H5HF_sect_indirect_valid(hdr, top_indir_sect);
2077     } /* end if */
2078 
2079     FUNC_LEAVE_NOAPI(SUCCEED)
2080 }   /* H5HF__sect_row_valid() */
2081 
2082 
2083 /*-------------------------------------------------------------------------
2084  * Function:	H5HF__sect_row_debug
2085  *
2086  * Purpose:	Dump debugging information about an row free space section
2087  *
2088  * Return:	Success:	non-negative
2089  *		Failure:	negative
2090  *
2091  * Programmer:	Quincey Koziol
2092  *              Tuesday, July 25, 2006
2093  *
2094  *-------------------------------------------------------------------------
2095  */
2096 static herr_t
H5HF__sect_row_debug(const H5FS_section_info_t * _sect,FILE * stream,int indent,int fwidth)2097 H5HF__sect_row_debug(const H5FS_section_info_t *_sect,
2098     FILE *stream, int indent, int fwidth)
2099 {
2100     const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect;       /* Section to dump info */
2101 
2102     FUNC_ENTER_STATIC_NOERR
2103 
2104     /* Check arguments. */
2105     HDassert(sect);
2106 
2107     /* Print indirect section information */
2108     HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
2109 	      "Row:",
2110 	      sect->u.row.row);
2111     HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
2112 	      "Column:",
2113 	      sect->u.row.col);
2114     HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
2115 	      "Number of entries:",
2116 	      sect->u.row.num_entries);
2117 
2118     /* If this is a first row section display information about underlying indirect section */
2119     if(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW) {
2120         /* Print indirect section header */
2121         HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth,
2122                   "Underlying indirect section:");
2123 
2124         H5HF_sect_indirect_debug(sect->u.row.under, stream, indent + 3, MAX(0, fwidth - 3));
2125     } /* end if */
2126 
2127     FUNC_LEAVE_NOAPI(SUCCEED)
2128 } /* H5HF__sect_row_debug() */
2129 
2130 
2131 /*-------------------------------------------------------------------------
2132  * Function:	H5HF_sect_indirect_iblock_off
2133  *
2134  * Purpose:	Get the offset of the indirect block for the section
2135  *
2136  * Return:	Offset of indirect block in "heap space" (can't fail)
2137  *
2138  * Programmer:	Quincey Koziol
2139  *		koziol@ncsa.uiuc.edu
2140  *		July  6 2006
2141  *
2142  *-------------------------------------------------------------------------
2143  */
2144 static hsize_t
H5HF_sect_indirect_iblock_off(const H5HF_free_section_t * sect)2145 H5HF_sect_indirect_iblock_off(const H5HF_free_section_t *sect)
2146 {
2147     hsize_t ret_value = 0;      /* Return value */
2148 
2149     FUNC_ENTER_NOAPI_NOINIT_NOERR
2150 
2151     /*
2152      * Check arguments.
2153      */
2154     HDassert(sect);
2155 
2156     ret_value = sect->sect_info.state == H5FS_SECT_LIVE ?  sect->u.indirect.u.iblock->block_off : sect->u.indirect.u.iblock_off;
2157 
2158     FUNC_LEAVE_NOAPI(ret_value)
2159 } /* end H5HF_sect_indirect_iblock_off() */
2160 
2161 
2162 /*-------------------------------------------------------------------------
2163  * Function:	H5HF_sect_indirect_top
2164  *
2165  * Purpose:	Get the "top" indirect section
2166  *
2167  * Return:	Pointer to the top indirect section (can't fail)
2168  *
2169  * Programmer:	Quincey Koziol
2170  *		koziol@ncsa.uiuc.edu
2171  *		July  6 2006
2172  *
2173  *-------------------------------------------------------------------------
2174  */
2175 static H5HF_free_section_t *
H5HF_sect_indirect_top(H5HF_free_section_t * sect)2176 H5HF_sect_indirect_top(H5HF_free_section_t *sect)
2177 {
2178     H5HF_free_section_t *ret_value = NULL;      /* Return value */
2179 
2180     FUNC_ENTER_NOAPI_NOINIT_NOERR
2181 
2182     /*
2183      * Check arguments.
2184      */
2185     HDassert(sect);
2186 
2187     if(sect->u.indirect.parent)
2188         ret_value = H5HF_sect_indirect_top(sect->u.indirect.parent);
2189     else
2190         ret_value = sect;
2191 
2192     FUNC_LEAVE_NOAPI(ret_value)
2193 } /* end H5HF_sect_indirect_top() */
2194 
2195 
2196 /*-------------------------------------------------------------------------
2197  * Function:	H5HF_sect_indirect_init_cls
2198  *
2199  * Purpose:	Initialize the "indirect" class structure
2200  *
2201  * Return:	Success:	non-negative
2202  *
2203  *		Failure:	negative
2204  *
2205  * Programmer:	Quincey Koziol
2206  *              Monday, July  3, 2006
2207  *
2208  *-------------------------------------------------------------------------
2209  */
2210 static herr_t
H5HF_sect_indirect_init_cls(H5FS_section_class_t * cls,void * _udata)2211 H5HF_sect_indirect_init_cls(H5FS_section_class_t *cls, void *_udata)
2212 {
2213     H5HF_hdr_t *hdr = (H5HF_hdr_t *)_udata; /* Fractal heap header */
2214     herr_t ret_value = SUCCEED;         /* Return value */
2215 
2216     FUNC_ENTER_NOAPI_NOINIT
2217 
2218     /* Check arguments. */
2219     HDassert(cls);
2220     HDassert(hdr);
2221 
2222     /* Call to common class initialization */
2223     if(H5HF_sect_init_cls(cls, hdr) < 0)
2224 	HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize common section class")
2225 
2226     /* Set the size of all serialized objects of this class of sections */
2227     cls->serial_size = H5HF_SECT_INDIRECT_SERIAL_SIZE(hdr);
2228 
2229 done:
2230     FUNC_LEAVE_NOAPI(ret_value)
2231 } /* H5HF_sect_indirect_init_cls() */
2232 
2233 
2234 /*-------------------------------------------------------------------------
2235  * Function:	H5HF_sect_indirect_term_cls
2236  *
2237  * Purpose:	Terminate the "indirect" class structure
2238  *
2239  * Return:	Success:	non-negative
2240  *
2241  *		Failure:	negative
2242  *
2243  * Programmer:	Quincey Koziol
2244  *              Monday, July  3, 2006
2245  *
2246  *-------------------------------------------------------------------------
2247  */
2248 static herr_t
H5HF_sect_indirect_term_cls(H5FS_section_class_t * cls)2249 H5HF_sect_indirect_term_cls(H5FS_section_class_t *cls)
2250 {
2251     herr_t ret_value = SUCCEED;         /* Return value */
2252 
2253     FUNC_ENTER_NOAPI_NOINIT
2254 
2255     /* Check arguments. */
2256     HDassert(cls);
2257 
2258     /* Call common class termination */
2259     if(H5HF_sect_term_cls(cls) < 0)
2260 	HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't terminate common section class")
2261 
2262 done:
2263     FUNC_LEAVE_NOAPI(ret_value)
2264 } /* H5HF_sect_indirect_term_cls() */
2265 
2266 
2267 /*-------------------------------------------------------------------------
2268  * Function:	H5HF_sect_indirect_new
2269  *
2270  * Purpose:	Create a new 'indirect' section for other routines to finish
2271  *              initializing.
2272  *
2273  * Return:	Non-negative on success/Negative on failure
2274  *
2275  * Programmer:	Quincey Koziol
2276  *		koziol@ncsa.uiuc.edu
2277  *		July  6 2006
2278  *
2279  *-------------------------------------------------------------------------
2280  */
2281 static H5HF_free_section_t *
H5HF_sect_indirect_new(H5HF_hdr_t * hdr,haddr_t sect_off,hsize_t sect_size,H5HF_indirect_t * iblock,hsize_t iblock_off,unsigned row,unsigned col,unsigned nentries)2282 H5HF_sect_indirect_new(H5HF_hdr_t *hdr, haddr_t sect_off, hsize_t sect_size,
2283     H5HF_indirect_t *iblock, hsize_t iblock_off, unsigned row, unsigned col,
2284     unsigned nentries)
2285 {
2286     H5HF_free_section_t *sect = NULL;   /* 'Indirect' free space section to add */
2287     H5HF_free_section_t *ret_value = NULL;      /* Return value */
2288 
2289     FUNC_ENTER_NOAPI_NOINIT
2290 
2291     /*
2292      * Check arguments.
2293      */
2294     HDassert(hdr);
2295     HDassert(nentries);
2296 
2297     /* Create free space section node */
2298     if(NULL == (sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_INDIRECT, sect_off,
2299             sect_size, (iblock ? H5FS_SECT_LIVE : H5FS_SECT_SERIALIZED))))
2300         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for indirect section")
2301 
2302     /* Set the 'indirect' specific fields */
2303     if(iblock) {
2304         sect->u.indirect.u.iblock = iblock;
2305         sect->u.indirect.iblock_entries = hdr->man_dtable.cparam.width *
2306                 sect->u.indirect.u.iblock->max_rows;
2307         if(H5HF_iblock_incr(sect->u.indirect.u.iblock) < 0)
2308             HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block")
2309     } /* end if */
2310     else {
2311         sect->u.indirect.u.iblock_off = iblock_off;
2312         sect->u.indirect.iblock_entries = 0;
2313     } /* end else */
2314     sect->u.indirect.row = row;
2315     sect->u.indirect.col = col;
2316     sect->u.indirect.num_entries = nentries;
2317 
2318     /* Compute span size of indirect section */
2319     sect->u.indirect.span_size = H5HF_dtable_span_size(&hdr->man_dtable,
2320             row, col, nentries);
2321     HDassert(sect->u.indirect.span_size > 0);
2322 
2323     /* This indirect section doesn't (currently) have a parent */
2324     sect->u.indirect.parent = NULL;
2325     sect->u.indirect.par_entry = 0;
2326 
2327     /* Set return value */
2328     ret_value = sect;
2329 
2330 done:
2331     if(!ret_value && sect) {
2332         /* Release the section */
2333         sect = H5FL_FREE(H5HF_free_section_t, sect);
2334     } /* end if */
2335 
2336     FUNC_LEAVE_NOAPI(ret_value)
2337 } /* end H5HF_sect_indirect_new() */
2338 
2339 
2340 /*-------------------------------------------------------------------------
2341  * Function:	H5HF_sect_indirect_for_row
2342  *
2343  * Purpose:	Create the underlying indirect section for a new row section
2344  *
2345  * Return:	Non-negative on success/Negative on failure
2346  *
2347  * Programmer:	Quincey Koziol
2348  *		koziol@ncsa.uiuc.edu
2349  *		July  6 2006
2350  *
2351  *-------------------------------------------------------------------------
2352  */
2353 static H5HF_free_section_t *
H5HF_sect_indirect_for_row(H5HF_hdr_t * hdr,H5HF_indirect_t * iblock,H5HF_free_section_t * row_sect)2354 H5HF_sect_indirect_for_row(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock,
2355     H5HF_free_section_t *row_sect)
2356 {
2357     H5HF_free_section_t *sect = NULL;   /* 'Indirect' free space section to add */
2358     H5HF_free_section_t *ret_value = NULL;      /* Return value */
2359 
2360     FUNC_ENTER_NOAPI_NOINIT
2361 
2362     /*
2363      * Check arguments.
2364      */
2365     HDassert(hdr);
2366     HDassert(iblock);
2367     HDassert(row_sect);
2368     HDassert(row_sect->u.row.row < hdr->man_dtable.max_direct_rows);
2369 
2370     /* Create free space section node */
2371     if(NULL == (sect = H5HF_sect_indirect_new(hdr, row_sect->sect_info.addr,
2372             row_sect->sect_info.size, iblock, iblock->block_off,
2373             row_sect->u.row.row, row_sect->u.row.col, row_sect->u.row.num_entries)))
2374         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't create indirect section")
2375 
2376     /* Set # of direct rows covered */
2377     sect->u.indirect.dir_nrows = 1;
2378 
2379     /* Allocate space for the derived row sections */
2380     if(NULL == (sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *))))
2381         HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "allocation failed for row section pointer array")
2382 
2383     /* Atatch the new row section to indirect section */
2384     sect->u.indirect.dir_rows[0] = row_sect;
2385     sect->u.indirect.rc = 1;
2386 
2387     /* No indirect rows in current section */
2388     sect->u.indirect.indir_nents = 0;
2389     sect->u.indirect.indir_ents = NULL;
2390 
2391     /* Set return value */
2392     ret_value = sect;
2393 
2394 done:
2395     if(!ret_value && sect)
2396         if(H5HF_sect_indirect_free(sect) < 0)
2397             HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "can't free indirect section node")
2398 
2399     FUNC_LEAVE_NOAPI(ret_value)
2400 } /* end H5HF_sect_indirect_for_row() */
2401 
2402 
2403 /*-------------------------------------------------------------------------
2404  * Function:	H5HF__sect_indirect_init_rows
2405  *
2406  * Purpose:	Initialize the derived row sections for a newly created
2407  *              indirect section
2408  *
2409  * Return:	Non-negative on success/Negative on failure
2410  *
2411  * Programmer:	Quincey Koziol
2412  *		koziol@ncsa.uiuc.edu
2413  *		July  6 2006
2414  *
2415  *-------------------------------------------------------------------------
2416  */
2417 static herr_t
H5HF__sect_indirect_init_rows(H5HF_hdr_t * hdr,H5HF_free_section_t * sect,hbool_t first_child,H5HF_free_section_t ** first_row_sect,unsigned space_flags,unsigned start_row,unsigned start_col,unsigned end_row,unsigned end_col)2418 H5HF__sect_indirect_init_rows(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
2419     hbool_t first_child, H5HF_free_section_t **first_row_sect,
2420     unsigned space_flags, unsigned start_row, unsigned start_col,
2421     unsigned end_row, unsigned end_col)
2422 {
2423     hsize_t curr_off;                   /* Offset of new section in "heap space" */
2424     size_t dblock_overhead;             /* Direct block's overhead */
2425     unsigned row_entries;               /* # of entries in row */
2426     unsigned row_col;                   /* Column within current row */
2427     unsigned curr_entry;                /* Current entry within indirect section */
2428     unsigned curr_indir_entry;          /* Current indirect entry within indirect section */
2429     unsigned curr_row;                  /* Current row within indirect section */
2430     unsigned dir_nrows;                 /* # of direct rows in indirect section */
2431     unsigned u;                         /* Local index variable */
2432     herr_t ret_value = SUCCEED;         /* Return value */
2433 
2434     FUNC_ENTER_STATIC
2435 
2436     /*
2437      * Check arguments.
2438      */
2439     HDassert(sect);
2440     HDassert(sect->u.indirect.span_size > 0);
2441 
2442     /* Reset reference count for indirect section */
2443     /* (Also reset the direct & indirect row pointers */
2444     sect->u.indirect.rc = 0;
2445     sect->u.indirect.dir_rows = NULL;
2446     sect->u.indirect.indir_ents = NULL;
2447 
2448     /* Set up direct block information, if necessary */
2449     if(start_row < hdr->man_dtable.max_direct_rows) {
2450         unsigned max_direct_row;            /* Max. direct row covered */
2451 
2452         /* Compute max. direct row covered by indirect section */
2453         max_direct_row = MIN(end_row, (hdr->man_dtable.max_direct_rows - 1));
2454 
2455         /* Compute # of direct rows covered */
2456         dir_nrows = (max_direct_row - start_row) + 1;
2457 
2458         /* Don't set the of direct rows in section yet, so sanity
2459          * checking works (enabled in free section manager, with H5FS_DEBUG
2460          * macro) correctly.
2461          */
2462         sect->u.indirect.dir_nrows = 0;
2463 
2464         /* Allocate space for the derived row sections */
2465         if(NULL == (sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * dir_nrows)))
2466             HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for row section pointer array")
2467     } /* end if */
2468     else {
2469         /* No rows of direct blocks covered, reset direct row information */
2470         dir_nrows = 0;
2471         sect->u.indirect.dir_nrows = 0;
2472     } /* end else */
2473 
2474     /* Set up indirect block information, if necessary */
2475     if(end_row >= hdr->man_dtable.max_direct_rows) {
2476         unsigned indirect_start_row;    /* Row to start indirect entries on */
2477         unsigned indirect_start_col;    /* Column to start indirect entries on */
2478         unsigned indirect_start_entry;  /* Index of starting indirect entry */
2479         unsigned indirect_end_entry;    /* Index of ending indirect entry */
2480 
2481         /* Compute starting indirect entry */
2482         if(start_row < hdr->man_dtable.max_direct_rows) {
2483             indirect_start_row = hdr->man_dtable.max_direct_rows;
2484             indirect_start_col = 0;
2485         } /* end if */
2486         else {
2487             indirect_start_row = start_row;
2488             indirect_start_col = start_col;
2489         } /* end else */
2490         indirect_start_entry = (indirect_start_row * hdr->man_dtable.cparam.width)
2491             + indirect_start_col;
2492 
2493         /* Compute ending indirect entry */
2494         indirect_end_entry = (end_row * hdr->man_dtable.cparam.width) + end_col;
2495 
2496         /* Compute # of indirect entries covered */
2497         sect->u.indirect.indir_nents = (indirect_end_entry - indirect_start_entry) + 1;
2498 
2499         /* Allocate space for the child indirect sections */
2500         if(NULL == (sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * sect->u.indirect.indir_nents)))
2501             HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for indirect section pointer array")
2502     } /* end if */
2503     else {
2504         /* No indirect block entries covered, reset indirect row information */
2505         sect->u.indirect.indir_nents = 0;
2506     } /* end else */
2507 
2508     /* Set up initial row information */
2509     if(start_row == end_row)
2510         row_entries = (end_col - start_col) + 1;
2511     else
2512         row_entries = hdr->man_dtable.cparam.width - start_col;
2513     row_col = start_col;
2514 
2515     /* Loop over creating the sections covered by this indirect section */
2516     curr_off = sect->sect_info.addr;
2517     curr_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
2518     curr_row = 0;
2519     curr_indir_entry = 0;
2520     dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
2521     for(u = start_row; u <= end_row; u++, curr_row++) {
2522         if(u < hdr->man_dtable.max_direct_rows) {
2523             H5HF_free_section_t *row_sect = NULL;   /* 'Row' free space section to add */
2524 
2525             /* Create 'row' free space section node */
2526             if(NULL == (row_sect = H5HF_sect_row_create(curr_off,
2527                     (hdr->man_dtable.row_block_size[u] - dblock_overhead), first_child, u, row_col,
2528                     row_entries, sect)))
2529                 HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "creation failed for child row section")
2530 
2531             /* Add new row section to array for indirect section */
2532             sect->u.indirect.dir_rows[curr_row] = row_sect;
2533 
2534             /* Check to see if we should grab the first row section instead of adding it immediately */
2535             if(first_row_sect)
2536                 *first_row_sect = row_sect;
2537             else
2538                 /* Add new row section to free space manager for the heap */
2539                 if(H5HF__space_add(hdr, row_sect, space_flags) < 0)
2540                     HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add row section to free space")
2541 
2542             /* Increment reference count for underlying indirect section */
2543             sect->u.indirect.rc++;
2544 
2545             /* Advance the offset to the next section */
2546             curr_off += row_entries * hdr->man_dtable.row_block_size[u];
2547 
2548             /* Advance the current entry to the next row*/
2549             curr_entry += row_entries;
2550 
2551             /* Reset the 'first child' parameters */
2552             first_child = FALSE;
2553             first_row_sect = NULL;
2554         } /* end if */
2555         else {
2556             H5HF_indirect_t *child_iblock;      /* Child indirect block */
2557             H5HF_free_section_t *child_sect;    /* Child 'indirect' section to add */
2558             unsigned child_nrows;               /* Number of child rows in indirect blocks for this row */
2559             unsigned child_nentries;            /* Number of child entries in indirect blocks for this row */
2560             unsigned v;         /* Local index variable */
2561 
2562             /* Compute info about row's indirect blocks for child section */
2563             child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[u]);
2564             child_nentries = child_nrows * hdr->man_dtable.cparam.width;
2565 
2566             /* Add an indirect section for each indirect block in the row */
2567             for(v = 0; v < row_entries; v++) {
2568                 hbool_t did_protect;            /* Whether we protected the indirect block or not */
2569 
2570                 /* Try to get the child section's indirect block, if it's available */
2571                 if(sect->sect_info.state == H5FS_SECT_LIVE) {
2572                     haddr_t child_iblock_addr;          /* Child indirect block's address on disk */
2573 
2574                     /* Get the address of the child indirect block */
2575                     if(H5HF_man_iblock_entry_addr(sect->u.indirect.u.iblock, curr_entry, &child_iblock_addr) < 0)
2576                         HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve child indirect block's address")
2577 
2578                     /* If the child indirect block's address is defined, protect it */
2579                     if(H5F_addr_defined(child_iblock_addr)) {
2580                         if(NULL == (child_iblock = H5HF__man_iblock_protect(hdr, child_iblock_addr, child_nrows, sect->u.indirect.u.iblock, curr_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect)))
2581                             HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
2582                     } /* end if */
2583                     else
2584                         child_iblock = NULL;
2585                 } /* end if */
2586                 else
2587                     child_iblock = NULL;
2588 
2589                 /* Create free space section node */
2590                 if(NULL == (child_sect = H5HF_sect_indirect_new(hdr, curr_off, (hsize_t)0,
2591                         child_iblock, curr_off, 0, 0, child_nentries)))
2592                     HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
2593 
2594                 /* Initialize rows for new indirect section */
2595                 if(H5HF__sect_indirect_init_rows(hdr, child_sect,
2596                         first_child, first_row_sect, space_flags, 0, 0,
2597                         (child_nrows - 1), (hdr->man_dtable.cparam.width - 1)) < 0)
2598                     HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize indirect section")
2599 
2600                 /* If we have a valid child indirect block, release it now */
2601                 /* (will be pinned, if rows reference it) */
2602                 if(child_iblock)
2603                     if(H5HF__man_iblock_unprotect(child_iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
2604                         HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
2605 
2606                 /* Attach child section to this section */
2607                 child_sect->u.indirect.parent = sect;
2608                 child_sect->u.indirect.par_entry = curr_entry;
2609                 sect->u.indirect.indir_ents[curr_indir_entry] = child_sect;
2610                 sect->u.indirect.rc++;
2611 
2612                 /* Advance the offset for the next section */
2613                 curr_off += hdr->man_dtable.row_block_size[u];
2614 
2615                 /* Advance to the next entry */
2616                 curr_entry++;
2617                 curr_indir_entry++;
2618 
2619                 /* Reset the 'first child' parameters */
2620                 first_child = FALSE;
2621                 first_row_sect = NULL;
2622             } /* end for */
2623         } /* end else */
2624 
2625         /* Compute the # of entries for the next row */
2626         if(u < (end_row - 1))
2627             row_entries = hdr->man_dtable.cparam.width;
2628         else
2629             row_entries = end_col + 1;
2630 
2631         /* Reset column for all other rows */
2632         row_col = 0;
2633     } /* end for */
2634 
2635     /* Set the final # of direct rows in section */
2636     sect->u.indirect.dir_nrows = dir_nrows;
2637 
2638     /* Make certain we've tracked the section's dependents correctly */
2639     HDassert(sect->u.indirect.rc ==
2640             (sect->u.indirect.indir_nents + sect->u.indirect.dir_nrows));
2641 
2642 done:
2643     if(ret_value < 0) {
2644         if(sect->u.indirect.indir_ents)
2645             H5MM_xfree(sect->u.indirect.indir_ents);
2646         if(sect->u.indirect.dir_rows)
2647             H5MM_xfree(sect->u.indirect.dir_rows);
2648     } /* end if */
2649 
2650     FUNC_LEAVE_NOAPI(ret_value)
2651 } /* end H5HF__sect_indirect_init_rows() */
2652 
2653 
2654 /*-------------------------------------------------------------------------
2655  * Function:	H5HF__sect_indirect_add
2656  *
2657  * Purpose:	Add a new 'indirect' section to the free space manager for this
2658  *              heap
2659  *
2660  * Return:	Non-negative on success/Negative on failure
2661  *
2662  * Programmer:	Quincey Koziol
2663  *		koziol@ncsa.uiuc.edu
2664  *		July  3 2006
2665  *
2666  *-------------------------------------------------------------------------
2667  */
2668 herr_t
H5HF__sect_indirect_add(H5HF_hdr_t * hdr,H5HF_indirect_t * iblock,unsigned start_entry,unsigned nentries)2669 H5HF__sect_indirect_add(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock,
2670     unsigned start_entry, unsigned nentries)
2671 {
2672     H5HF_free_section_t *sect = NULL;   /* 'Indirect' free space section to add */
2673     H5HF_free_section_t *first_row_sect = NULL;   /* First row section in new indirect section */
2674     hsize_t sect_off;                   /* Offset of section in heap space */
2675     unsigned start_row;                 /* Start row in indirect block */
2676     unsigned start_col;                 /* Start column in indirect block */
2677     unsigned end_entry;                 /* End entry in indirect block */
2678     unsigned end_row;                   /* End row in indirect block */
2679     unsigned end_col;                   /* End column in indirect block */
2680     unsigned u;                         /* Local index variable */
2681     herr_t ret_value = SUCCEED;         /* Return value */
2682 
2683     FUNC_ENTER_PACKAGE
2684 
2685     /*
2686      * Check arguments.
2687      */
2688     HDassert(hdr);
2689     HDassert(iblock);
2690     HDassert(nentries);
2691 
2692     /* Compute starting column & row */
2693     start_row = start_entry / hdr->man_dtable.cparam.width;
2694     start_col = start_entry % hdr->man_dtable.cparam.width;
2695 
2696     /* Compute end column & row */
2697     end_entry = (start_entry + nentries) - 1;
2698     end_row = end_entry / hdr->man_dtable.cparam.width;
2699     end_col = end_entry % hdr->man_dtable.cparam.width;
2700 
2701     /* Initialize information for rows skipped over */
2702     sect_off = iblock->block_off;
2703     for(u = 0; u < start_row; u++)
2704         sect_off += hdr->man_dtable.row_block_size[u] * hdr->man_dtable.cparam.width;
2705     sect_off += hdr->man_dtable.row_block_size[start_row] * start_col;
2706 
2707     /* Create free space section node */
2708     if(NULL == (sect = H5HF_sect_indirect_new(hdr, sect_off, (hsize_t)0, iblock,
2709             iblock->block_off, start_row, start_col, nentries)))
2710         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
2711 
2712     /* Initialize rows for new indirect section */
2713     if(H5HF__sect_indirect_init_rows(hdr, sect, TRUE, &first_row_sect,
2714             H5FS_ADD_SKIP_VALID, start_row, start_col, end_row, end_col) < 0)
2715         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize indirect section")
2716     HDassert(first_row_sect);
2717 
2718     /* Now that underlying indirect section is consistent, add first row
2719      *  section to free space manager for the heap
2720      */
2721     if(H5HF__space_add(hdr, first_row_sect, H5FS_ADD_RETURNED_SPACE) < 0)
2722         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add row section to free space")
2723 
2724 done:
2725     if(ret_value < 0 && sect)
2726         if(H5HF_sect_indirect_free(sect) < 0)
2727             HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
2728 
2729     FUNC_LEAVE_NOAPI(ret_value)
2730 } /* end H5HF__sect_indirect_add() */
2731 
2732 
2733 /*-------------------------------------------------------------------------
2734  * Function:	H5HF_sect_indirect_decr
2735  *
2736  * Purpose:	Decrement ref. count on indirect section
2737  *
2738  * Return:	Non-negative on success/Negative on failure
2739  *
2740  * Programmer:	Quincey Koziol
2741  *		koziol@ncsa.uiuc.edu
2742  *		July  6 2006
2743  *
2744  *-------------------------------------------------------------------------
2745  */
2746 static herr_t
H5HF_sect_indirect_decr(H5HF_free_section_t * sect)2747 H5HF_sect_indirect_decr(H5HF_free_section_t *sect)
2748 {
2749     herr_t ret_value = SUCCEED;         /* Return value */
2750 
2751     FUNC_ENTER_NOAPI_NOINIT
2752 
2753     /*
2754      * Check arguments.
2755      */
2756     HDassert(sect);
2757     HDassert(sect->u.indirect.rc);
2758 
2759     /* Decrement ref. count for indirect section */
2760     sect->u.indirect.rc--;
2761 
2762     /* If the indirect section's ref. count drops to zero, free the section */
2763     if(sect->u.indirect.rc == 0) {
2764         H5HF_free_section_t *par_sect;          /* Parent indirect section */
2765 
2766         /* Preserve pointer to parent indirect section when freeing this section */
2767         par_sect = sect->u.indirect.parent;
2768 
2769         /* Free indirect section */
2770         if(H5HF_sect_indirect_free(sect) < 0)
2771             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
2772 
2773         /* Decrement ref. count on indirect section's parent */
2774         if(par_sect)
2775             if(H5HF_sect_indirect_decr(par_sect) < 0)
2776                 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't decrement ref. count on parent indirect section")
2777     } /* end if */
2778 
2779 done:
2780     FUNC_LEAVE_NOAPI(ret_value)
2781 } /* end H5HF_sect_indirect_decr() */
2782 
2783 
2784 /*-------------------------------------------------------------------------
2785  * Function:	H5HF__sect_indirect_revive_row
2786  *
2787  * Purpose:	Update the memory information for a 'indirect' free section
2788  *
2789  * Return:	Non-negative on success/Negative on failure
2790  *
2791  * Programmer:	Quincey Koziol
2792  *		koziol@ncsa.uiuc.edu
2793  *		July  3 2006
2794  *
2795  *-------------------------------------------------------------------------
2796  */
2797 static herr_t
H5HF__sect_indirect_revive_row(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)2798 H5HF__sect_indirect_revive_row(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
2799 {
2800     H5HF_indirect_t *sec_iblock;        /* Pointer to section indirect block */
2801     hbool_t did_protect;                /* Whether we protected the indirect block or not */
2802     herr_t ret_value = SUCCEED;         /* Return value */
2803 
2804     FUNC_ENTER_STATIC
2805 
2806     /*
2807      * Check arguments.
2808      */
2809     HDassert(hdr);
2810     HDassert(sect);
2811     HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED);
2812 
2813     /* Look up indirect block containing indirect blocks for section */
2814     if(H5HF__man_dblock_locate(hdr, sect->sect_info.addr, &sec_iblock, NULL, &did_protect, H5AC__READ_ONLY_FLAG) < 0)
2815         HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section")
2816 
2817     /* Review the section */
2818     if(H5HF__sect_indirect_revive(hdr, sect, sec_iblock) < 0)
2819         HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
2820 
2821 done:
2822     /* Unlock indirect block */
2823     if(sec_iblock && H5HF__man_iblock_unprotect(sec_iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
2824         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
2825 
2826     FUNC_LEAVE_NOAPI(ret_value)
2827 } /* end H5HF__sect_indirect_revive_row() */
2828 
2829 
2830 /*-------------------------------------------------------------------------
2831  * Function:	H5HF__sect_indirect_revive
2832  *
2833  * Purpose:	Update the memory information for a 'indirect' free section
2834  *
2835  * Return:	Non-negative on success/Negative on failure
2836  *
2837  * Programmer:	Quincey Koziol
2838  *		koziol@ncsa.uiuc.edu
2839  *		July 10 2006
2840  *
2841  *-------------------------------------------------------------------------
2842  */
2843 static herr_t
H5HF__sect_indirect_revive(H5HF_hdr_t * hdr,H5HF_free_section_t * sect,H5HF_indirect_t * sect_iblock)2844 H5HF__sect_indirect_revive(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
2845     H5HF_indirect_t *sect_iblock)
2846 {
2847     unsigned u;                         /* Local index variable */
2848     herr_t ret_value = SUCCEED;         /* Return value */
2849 
2850     FUNC_ENTER_STATIC
2851 
2852     /*
2853      * Check arguments.
2854      */
2855     HDassert(hdr);
2856     HDassert(sect);
2857     HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED);
2858     HDassert(sect_iblock);
2859 
2860     /* Increment reference count on indirect block that free section is in */
2861     if(H5HF_iblock_incr(sect_iblock) < 0)
2862         HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
2863 
2864     /* Set the pointer to the section's indirect block */
2865     sect->u.indirect.u.iblock = sect_iblock;
2866 
2867     /* Set the number of entries in the indirect block */
2868     sect->u.indirect.iblock_entries = hdr->man_dtable.cparam.width *
2869             sect->u.indirect.u.iblock->max_rows;
2870 
2871     /* Section is "live" now */
2872     sect->sect_info.state = H5FS_SECT_LIVE;
2873 
2874     /* Loop over derived row sections and mark them all as 'live' now */
2875     for(u = 0; u < sect->u.indirect.dir_nrows; u++)
2876         sect->u.indirect.dir_rows[u]->sect_info.state = H5FS_SECT_LIVE;
2877 
2878     /* Revive parent indirect section, if there is one */
2879     if(sect->u.indirect.parent && sect->u.indirect.parent->sect_info.state == H5FS_SECT_SERIALIZED)
2880         if(H5HF__sect_indirect_revive(hdr, sect->u.indirect.parent, sect->u.indirect.u.iblock->parent) < 0)
2881             HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
2882 
2883 done:
2884     FUNC_LEAVE_NOAPI(ret_value)
2885 } /* end H5HF__sect_indirect_revive() */
2886 
2887 
2888 /*-------------------------------------------------------------------------
2889  * Function:	H5HF__sect_indirect_reduce_row
2890  *
2891  * Purpose:	Remove a block from an indirect section (possibly freeing it)
2892  *              and re-add it back to the free space manager for the heap
2893  *              (if it hasn't been freed)
2894  *
2895  * Return:	Non-negative on success/Negative on failure
2896  *
2897  * Programmer:	Quincey Koziol
2898  *		koziol@ncsa.uiuc.edu
2899  *		July 10 2006
2900  *
2901  *-------------------------------------------------------------------------
2902  */
2903 static herr_t
H5HF__sect_indirect_reduce_row(H5HF_hdr_t * hdr,H5HF_free_section_t * row_sect,hbool_t * alloc_from_start)2904 H5HF__sect_indirect_reduce_row(H5HF_hdr_t *hdr, H5HF_free_section_t *row_sect,
2905     hbool_t *alloc_from_start)
2906 {
2907     H5HF_free_section_t *sect;          /* Indirect section underlying row section */
2908     unsigned row_start_entry;           /* Entry for first block covered in row section */
2909     unsigned row_end_entry;             /* Entry for last block covered in row section */
2910     unsigned row_entry;                 /* Entry to allocate in row section */
2911     unsigned start_entry;               /* Entry for first block covered */
2912     unsigned start_row;                 /* Start row in indirect block */
2913     unsigned start_col;                 /* Start column in indirect block */
2914     unsigned end_entry;                 /* Entry for last block covered */
2915     unsigned end_row;                   /* End row in indirect block */
2916     H5HF_free_section_t *peer_sect = NULL; /* Peer indirect section */
2917     herr_t ret_value = SUCCEED;         /* Return value */
2918 
2919     FUNC_ENTER_STATIC
2920 
2921     /*
2922      * Check arguments.
2923      */
2924     HDassert(hdr);
2925     HDassert(row_sect);
2926 
2927     /* Compute starting & ending information for row section */
2928     row_start_entry = (row_sect->u.row.row * hdr->man_dtable.cparam.width) + row_sect->u.row.col;
2929     row_end_entry = (row_start_entry + row_sect->u.row.num_entries) - 1;
2930 
2931     /* Compute starting & ending information for indirect section */
2932     sect = row_sect->u.row.under;
2933     start_row = sect->u.indirect.row;
2934     start_col = sect->u.indirect.col;
2935     start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
2936     end_entry = (start_entry + sect->u.indirect.num_entries) - 1;
2937     end_row = end_entry / hdr->man_dtable.cparam.width;
2938 
2939     /* Additional sanity check */
2940     HDassert(sect->u.indirect.span_size > 0);
2941     HDassert(sect->u.indirect.iblock_entries > 0);
2942     HDassert(sect->u.indirect.dir_nrows > 0);
2943     HDassert(sect->u.indirect.dir_rows);
2944     HDassert(sect->u.indirect.dir_rows[(row_sect->u.row.row - start_row)] == row_sect);
2945 
2946     /* Check if we should allocate from end of indirect section */
2947     if(row_end_entry == end_entry && start_row != end_row) {
2948         *alloc_from_start = FALSE;
2949         row_entry = row_end_entry;
2950     } /* end if */
2951     else {
2952         *alloc_from_start = TRUE;
2953         row_entry = row_start_entry;
2954     } /* end else */
2955 
2956     /* Check if we have a parent section to be detached from */
2957     if(sect->u.indirect.parent) {
2958         hbool_t is_first;       /* Flag to indicate that this section is the first section in hierarchy */
2959 
2960         /* Check if this section is the first section */
2961         is_first = H5HF_sect_indirect_is_first(sect);
2962 
2963         /* Remove this indirect section from parent indirect section */
2964         if(H5HF__sect_indirect_reduce(hdr, sect->u.indirect.parent, sect->u.indirect.par_entry) < 0)
2965             HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce parent indirect section")
2966         sect->u.indirect.parent = NULL;
2967         sect->u.indirect.par_entry = 0;
2968 
2969         /* If we weren't the first section, set "first row" for this indirect section */
2970         if(!is_first)
2971             if(H5HF__sect_indirect_first(hdr, sect) < 0)
2972                 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for indirect section")
2973     } /* end if */
2974 
2975     /* Adjust indirect section's span size */
2976     sect->u.indirect.span_size -= row_sect->sect_info.size;
2977 
2978     /* Check how to adjust section for allocated entry */
2979     if(sect->u.indirect.num_entries > 1) {
2980         if(row_entry == start_entry) {
2981             /* Adjust section start */
2982             sect->sect_info.addr += hdr->man_dtable.row_block_size[sect->u.indirect.row];
2983 
2984             /* Adjust block coordinates of span */
2985             sect->u.indirect.col++;
2986             if(sect->u.indirect.col == hdr->man_dtable.cparam.width) {
2987                 HDassert(row_sect->u.row.num_entries == 1);
2988 
2989                 /* Adjust section's span information */
2990                 sect->u.indirect.row++;
2991                 sect->u.indirect.col = 0;
2992 
2993                 /* Adjust direct row information */
2994                 sect->u.indirect.dir_nrows--;
2995 
2996                 /* Adjust direct row sections for indirect section */
2997                 if(sect->u.indirect.dir_nrows > 0) {
2998                     HDassert(sect->u.indirect.dir_rows);
2999                     HDmemmove(&sect->u.indirect.dir_rows[0],
3000                             &sect->u.indirect.dir_rows[1],
3001                             sect->u.indirect.dir_nrows * sizeof(H5HF_free_section_t *));
3002                     HDassert(sect->u.indirect.dir_rows[0]);
3003 
3004                     /* Make new "first row" in indirect section */
3005                     if(row_sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW)
3006                         if(H5HF__sect_row_first(hdr, sect->u.indirect.dir_rows[0]) < 0)
3007                             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for indirect section")
3008                 } /* end if */
3009                 else {
3010                     /* Sanity check */
3011                     HDassert(sect->u.indirect.indir_nents > 0);
3012                     HDassert(sect->u.indirect.indir_ents);
3013 
3014                     /* Eliminate direct rows for this section */
3015                     sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.dir_rows);
3016 
3017                     /* Make new "first row" in indirect section */
3018                     if(row_sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW)
3019                         if(H5HF__sect_indirect_first(hdr, sect->u.indirect.indir_ents[0]) < 0)
3020                             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for child indirect section")
3021                 } /* end else */
3022             } /* end if */
3023 
3024             /* Adjust number of entries covered */
3025             sect->u.indirect.num_entries--;
3026         } /* end if */
3027         else if(row_entry == end_entry) {
3028             unsigned new_end_row;       /* New end row for entries */
3029 
3030             /* Sanity check */
3031             HDassert(sect->u.indirect.indir_nents == 0);
3032             HDassert(sect->u.indirect.indir_ents == NULL);
3033 
3034             /* Adjust number of entries covered */
3035             sect->u.indirect.num_entries--;
3036 
3037             /* Check for eliminating a direct row */
3038             new_end_row = ((start_entry + sect->u.indirect.num_entries) - 1) / hdr->man_dtable.cparam.width;
3039             HDassert(new_end_row <= end_row);
3040             if(new_end_row < end_row) {
3041                 HDassert(new_end_row == (end_row - 1));
3042                 sect->u.indirect.dir_nrows--;
3043             } /* end if */
3044         } /* end if */
3045         else {
3046             H5HF_indirect_t *iblock;    /* Pointer to indirect block for this section */
3047             hsize_t iblock_off;         /* Section's indirect block's offset in "heap space" */
3048             unsigned peer_nentries;     /* Number of entries in new peer indirect section */
3049             unsigned peer_dir_nrows;    /* Number of direct rows in new peer indirect section */
3050             unsigned new_start_row;     /* New starting row for current indirect section */
3051             unsigned u;                 /* Local index variable */
3052 
3053             /* Sanity checks */
3054             HDassert(row_sect->u.row.col == 0);
3055             HDassert(row_sect->u.row.row > 0);
3056             HDassert(row_sect->u.row.row < hdr->man_dtable.max_direct_rows);
3057             HDassert(row_sect->u.row.num_entries == hdr->man_dtable.cparam.width);
3058             HDassert(row_sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
3059 
3060             /* Compute basic information about peer & current indirect sections */
3061             new_start_row = row_sect->u.row.row;
3062             peer_nentries = row_entry - start_entry;
3063             peer_dir_nrows = new_start_row - start_row;
3064 
3065             /* Get indirect block information for peer */
3066             if(sect->sect_info.state == H5FS_SECT_LIVE) {
3067                 iblock = sect->u.indirect.u.iblock;
3068                 iblock_off = sect->u.indirect.u.iblock->block_off;
3069             } /* end if */
3070             else {
3071                 iblock = NULL;
3072                 iblock_off = sect->u.indirect.u.iblock_off;
3073             } /* end else */
3074 
3075             /* Create peer indirect section */
3076             if(NULL == (peer_sect = H5HF_sect_indirect_new(hdr, sect->sect_info.addr,
3077                     sect->sect_info.size, iblock, iblock_off, start_row, start_col,
3078                     peer_nentries)))
3079                 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
3080 
3081             /* Set up direct row & indirect entry information for peer section */
3082             peer_sect->u.indirect.indir_nents = 0;
3083             peer_sect->u.indirect.indir_ents = NULL;
3084             peer_sect->u.indirect.dir_nrows = peer_dir_nrows;
3085             if(NULL == (peer_sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * peer_dir_nrows)))
3086                 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "allocation failed for row section pointer array")
3087 
3088             /* Transfer row sections between current & peer sections */
3089             HDmemcpy(&peer_sect->u.indirect.dir_rows[0],
3090                 &sect->u.indirect.dir_rows[0],
3091                 (sizeof(H5HF_free_section_t *) * peer_dir_nrows));
3092             HDmemmove(&sect->u.indirect.dir_rows[0],
3093                 &sect->u.indirect.dir_rows[peer_dir_nrows],
3094                 (sizeof(H5HF_free_section_t *) * (sect->u.indirect.dir_nrows - peer_dir_nrows)));
3095             sect->u.indirect.dir_nrows -= peer_dir_nrows;
3096             HDassert(row_sect == sect->u.indirect.dir_rows[0]);
3097 
3098             /* Re-target transferred row sections to point to new underlying indirect section */
3099             for(u = 0; u < peer_dir_nrows; u++)
3100                 peer_sect->u.indirect.dir_rows[u]->u.row.under = peer_sect;
3101 
3102             /* Change first row section in indirect section to be the "first row" */
3103             /* (But we don't have to tell the free space manager about it,
3104              *  because the row section is "checked out" from the free space
3105              * manager currently.
3106              */
3107             row_sect->sect_info.type = H5HF_FSPACE_SECT_FIRST_ROW;
3108 
3109             /* Adjust reference counts for current & peer sections */
3110             peer_sect->u.indirect.rc = peer_dir_nrows;
3111             sect->u.indirect.rc -= peer_dir_nrows;
3112 
3113             /* Transfer/update cached information about indirect block */
3114             peer_sect->u.indirect.iblock_entries = sect->u.indirect.iblock_entries;
3115             peer_sect->u.indirect.span_size = row_sect->sect_info.addr - peer_sect->sect_info.addr;
3116 
3117             /* Update information for current section */
3118             sect->sect_info.addr = row_sect->sect_info.addr + hdr->man_dtable.row_block_size[new_start_row];
3119             sect->u.indirect.span_size -= peer_sect->u.indirect.span_size; /* (span for row section has already been removed) */
3120             sect->u.indirect.row = new_start_row;
3121             sect->u.indirect.col = row_sect->u.row.col + 1;
3122             sect->u.indirect.num_entries -= (peer_nentries + 1); /* Transferred entries, plus the entry allocated out of the row */
3123 
3124             /* Make certain we've tracked the sections' dependents correctly */
3125             HDassert(sect->u.indirect.rc ==
3126                     (sect->u.indirect.indir_nents + sect->u.indirect.dir_nrows));
3127             HDassert(peer_sect->u.indirect.rc ==
3128                     (peer_sect->u.indirect.indir_nents + peer_sect->u.indirect.dir_nrows));
3129 
3130             /* Reset the peer_sect variable, to indicate that it has been hooked into the data structures correctly and shouldn't be freed */
3131             peer_sect = NULL;
3132         } /* end else */
3133     } /* end if */
3134     else {
3135         /* Decrement count of entries & rows */
3136         sect->u.indirect.num_entries--;
3137         sect->u.indirect.dir_nrows--;
3138         HDassert(sect->u.indirect.dir_nrows == 0);
3139 
3140         /* Eliminate direct rows for this section */
3141         sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.dir_rows);
3142     } /* end else */
3143 
3144 done:
3145     /* Free allocated peer_sect.  Note that this is necessary for all failures until peer_sect is linked
3146      * into the main free space structures (via the direct blocks), and the reference count is updated. */
3147     if(peer_sect) {
3148         /* Sanity check - we should only be here if an error occurred */
3149         HDassert(ret_value < 0);
3150 
3151         if(H5HF_sect_indirect_free(peer_sect) < 0)
3152             HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
3153     } /* end if */
3154 
3155     FUNC_LEAVE_NOAPI(ret_value)
3156 } /* end H5HF__sect_indirect_reduce_row() */
3157 
3158 
3159 /*-------------------------------------------------------------------------
3160  * Function:	H5HF__sect_indirect_reduce
3161  *
3162  * Purpose:	Reduce the size of a indirect section (possibly freeing it)
3163  *              and re-add it back to the free space manager for the heap
3164  *              (if it hasn't been freed)
3165  *
3166  * Return:	Non-negative on success/Negative on failure
3167  *
3168  * Programmer:	Quincey Koziol
3169  *		koziol@ncsa.uiuc.edu
3170  *		July 10 2006
3171  *
3172  *-------------------------------------------------------------------------
3173  */
3174 static herr_t
H5HF__sect_indirect_reduce(H5HF_hdr_t * hdr,H5HF_free_section_t * sect,unsigned child_entry)3175 H5HF__sect_indirect_reduce(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
3176     unsigned child_entry)
3177 {
3178     unsigned start_entry;               /* Entry for first block covered */
3179     unsigned start_row;                 /* Start row in indirect block */
3180     unsigned start_col;                 /* Start column in indirect block */
3181     unsigned end_entry;                 /* Entry for last block covered */
3182     unsigned end_row;                   /* End row in indirect block */
3183     H5HF_free_section_t *peer_sect = NULL; /* Peer indirect section */
3184     herr_t ret_value = SUCCEED;         /* Return value */
3185 
3186     FUNC_ENTER_STATIC
3187 
3188     /*
3189      * Check arguments.
3190      */
3191     HDassert(hdr);
3192     HDassert(sect);
3193     HDassert(sect->u.indirect.span_size > 0);
3194     HDassert(sect->u.indirect.iblock_entries > 0);
3195 
3196     /* Compute starting & ending information for indirect section */
3197     start_row = sect->u.indirect.row;
3198     start_col = sect->u.indirect.col;
3199     start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
3200     end_entry = (start_entry + sect->u.indirect.num_entries) - 1;
3201     end_row = end_entry / hdr->man_dtable.cparam.width;
3202 
3203     /* Check how to adjust section for allocated entry */
3204     if(sect->u.indirect.num_entries > 1) {
3205         /* Check if we have a parent section to be detached from */
3206         if(sect->u.indirect.parent) {
3207             hbool_t is_first;       /* Flag to indicate that this section is the first section in hierarchy */
3208 
3209             /* Check if this section is the first section */
3210             is_first = H5HF_sect_indirect_is_first(sect);
3211 
3212             /* Reduce parent indirect section */
3213             if(H5HF__sect_indirect_reduce(hdr, sect->u.indirect.parent, sect->u.indirect.par_entry) < 0)
3214                 HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce parent indirect section")
3215             sect->u.indirect.parent = NULL;
3216             sect->u.indirect.par_entry = 0;
3217 
3218             /* If we weren't the first section, set "first row" for this indirect section */
3219             if(!is_first)
3220                 if(H5HF__sect_indirect_first(hdr, sect) < 0)
3221                     HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for indirect section")
3222         } /* end if */
3223 
3224         /* Check if we can allocate from start of indirect section */
3225         if(child_entry == start_entry) {
3226             /* Sanity check */
3227             HDassert(sect->u.indirect.dir_nrows == 0);
3228             HDassert(sect->u.indirect.dir_rows == NULL);
3229             HDassert(sect->u.indirect.indir_nents > 0);
3230             HDassert(sect->u.indirect.indir_ents);
3231 
3232             /* Adjust section start */
3233             sect->sect_info.addr += hdr->man_dtable.row_block_size[start_row];
3234 
3235             /* Adjust span of blocks covered */
3236             sect->u.indirect.col++;
3237             if(sect->u.indirect.col == hdr->man_dtable.cparam.width) {
3238                 sect->u.indirect.row++;
3239                 sect->u.indirect.col = 0;
3240             } /* end if */
3241             sect->u.indirect.num_entries--;
3242             sect->u.indirect.span_size -= hdr->man_dtable.row_block_size[start_row];
3243 
3244             /* Adjust indirect entry information */
3245             sect->u.indirect.indir_nents--;
3246             HDmemmove(&sect->u.indirect.indir_ents[0],
3247                     &sect->u.indirect.indir_ents[1],
3248                     sect->u.indirect.indir_nents * sizeof(H5HF_free_section_t *));
3249             HDassert(sect->u.indirect.indir_ents[0]);
3250 
3251             /* Make new "first row" in new first indirect child section */
3252             if(H5HF__sect_indirect_first(hdr, sect->u.indirect.indir_ents[0]) < 0)
3253                 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for child indirect section")
3254         } /* end if */
3255         else if(child_entry == end_entry) {
3256             /* Sanity check */
3257             HDassert(sect->u.indirect.indir_nents > 0);
3258             HDassert(sect->u.indirect.indir_ents);
3259 
3260             /* Adjust span of blocks covered */
3261             sect->u.indirect.num_entries--;
3262             sect->u.indirect.span_size -= hdr->man_dtable.row_block_size[end_row];
3263 
3264             /* Adjust indirect entry information */
3265             sect->u.indirect.indir_nents--;
3266             if(sect->u.indirect.indir_nents == 0)
3267                 sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
3268         } /* end if */
3269         else {
3270             H5HF_indirect_t *iblock;    /* Pointer to indirect block for this section */
3271             hsize_t iblock_off;         /* Section's indirect block's offset in "heap space" */
3272             haddr_t peer_sect_addr;     /* Address of new peer section in "heap space" */
3273             unsigned peer_nentries;     /* Number of entries in new peer indirect section */
3274             unsigned peer_start_row;    /* Starting row for new peer indirect section */
3275             unsigned peer_start_col;    /* Starting column for new peer indirect section */
3276             unsigned child_row;         /* Row where child entry is located */
3277             unsigned new_nentries;      /* New number of entries for current indirect section */
3278             unsigned u;                 /* Local index variable */
3279 
3280             /* Sanity check */
3281             HDassert(sect->u.indirect.indir_nents > 0);
3282             HDassert(sect->u.indirect.indir_ents);
3283 
3284             /* Compute basic information about peer & current indirect sections */
3285             peer_nentries = end_entry - child_entry;
3286             peer_start_row = (child_entry + 1) / hdr->man_dtable.cparam.width;
3287             peer_start_col = (child_entry + 1) % hdr->man_dtable.cparam.width;
3288             child_row = child_entry / hdr->man_dtable.cparam.width;
3289             new_nentries = sect->u.indirect.num_entries - (peer_nentries + 1);
3290             HDassert(child_row >= hdr->man_dtable.max_direct_rows);
3291 
3292             /* Get indirect block information for peer */
3293             if(sect->sect_info.state == H5FS_SECT_LIVE) {
3294                 iblock = sect->u.indirect.u.iblock;
3295                 iblock_off = sect->u.indirect.u.iblock->block_off;
3296             } /* end if */
3297             else {
3298                 iblock = NULL;
3299                 iblock_off = sect->u.indirect.u.iblock_off;
3300             } /* end else */
3301 
3302             /* Update the number of entries in current section & calculate it's span size */
3303             /* (Will use this to compute the section address for the peer section */
3304             sect->u.indirect.num_entries = new_nentries;
3305             sect->u.indirect.span_size = H5HF_dtable_span_size(&hdr->man_dtable,
3306                     sect->u.indirect.row, sect->u.indirect.col, new_nentries);
3307             HDassert(sect->u.indirect.span_size > 0);
3308 
3309             /* Compute address of peer indirect section */
3310             peer_sect_addr = sect->sect_info.addr;
3311             peer_sect_addr += sect->u.indirect.span_size;
3312             peer_sect_addr += hdr->man_dtable.row_block_size[child_row];
3313 
3314             /* Create peer indirect section */
3315             if(NULL == (peer_sect = H5HF_sect_indirect_new(hdr, peer_sect_addr,
3316                     sect->sect_info.size, iblock, iblock_off, peer_start_row,
3317                     peer_start_col, peer_nentries)))
3318                 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
3319 
3320             /* Set up direct row & indirect entry information for peer section */
3321             peer_sect->u.indirect.dir_nrows = 0;
3322             peer_sect->u.indirect.dir_rows = NULL;
3323             peer_sect->u.indirect.indir_nents = peer_nentries;
3324             if(NULL == (peer_sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * peer_nentries)))
3325                 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "allocation failed for indirect section pointer array")
3326 
3327             /* Transfer child indirect sections between current & peer sections */
3328             HDmemcpy(&peer_sect->u.indirect.indir_ents[0],
3329                 &sect->u.indirect.indir_ents[sect->u.indirect.indir_nents - peer_nentries],
3330                 (sizeof(H5HF_free_section_t *) * peer_nentries));
3331             sect->u.indirect.indir_nents -= (peer_nentries + 1); /* Transferred blocks, plus child entry */
3332 
3333             /* Eliminate indirect entries for this section, if appropriate */
3334             if(sect->u.indirect.indir_nents == 0)
3335                 sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
3336 
3337             /* Re-target transferred row sections to point to new underlying indirect section */
3338             for(u = 0; u < peer_nentries; u++)
3339                 peer_sect->u.indirect.indir_ents[u]->u.indirect.parent = peer_sect;
3340 
3341             /* Adjust reference counts for current & peer sections */
3342             peer_sect->u.indirect.rc = peer_nentries;
3343             sect->u.indirect.rc -= peer_nentries;
3344 
3345             /* Transfer cached information about indirect block */
3346             peer_sect->u.indirect.iblock_entries = sect->u.indirect.iblock_entries;
3347 
3348             /* Make certain we've tracked the sections' dependents correctly */
3349             /* (Note modified on current section's ref. count, since we haven't
3350              *  detached the child section yet)
3351              */
3352             HDassert((sect->u.indirect.rc - 1) ==
3353                     (sect->u.indirect.indir_nents + sect->u.indirect.dir_nrows));
3354             HDassert(peer_sect->u.indirect.rc ==
3355                     (peer_sect->u.indirect.indir_nents + peer_sect->u.indirect.dir_nrows));
3356 
3357             /* Make new "first row" in peer section */
3358             if(H5HF__sect_indirect_first(hdr, peer_sect->u.indirect.indir_ents[0]) < 0)
3359                 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for peer indirect section")
3360 
3361             /* Reset the peer_sect variable, to indicate that it has been hooked into the data structures correctly and shouldn't be freed */
3362             peer_sect = NULL;
3363         } /* end else */
3364     } /* end if */
3365     else {
3366         /* Decrement count of entries & indirect entries */
3367         sect->u.indirect.num_entries--;
3368         sect->u.indirect.indir_nents--;
3369         HDassert(sect->u.indirect.indir_nents == 0);
3370 
3371         /* Eliminate indirect entries for this section */
3372         sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
3373     } /* end else */
3374 
3375     /* Decrement # of sections which depend on this row */
3376     /* (Must be last as section can be freed) */
3377     if(H5HF_sect_indirect_decr(sect) < 0)
3378         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't decrement section's ref. count ")
3379 
3380 done:
3381     /* Free allocated peer_sect.  Note that this is necessary for all failures until peer_sect is linked
3382      * into the main free space structures (via the direct blocks), and the reference count is updated. */
3383     if(peer_sect) {
3384         /* Sanity check - we should only be here if an error occurred */
3385         HDassert(ret_value < 0);
3386 
3387         if(H5HF_sect_indirect_free(peer_sect) < 0)
3388             HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
3389     } /* end if */
3390 
3391     FUNC_LEAVE_NOAPI(ret_value)
3392 } /* end H5HF__sect_indirect_reduce() */
3393 
3394 
3395 /*-------------------------------------------------------------------------
3396  * Function:	H5HF_sect_indirect_is_first
3397  *
3398  * Purpose:	Check if indirect section is first in all parents
3399  *
3400  * Return:	Non-negative (TRUE/FALSE) on success/<can't fail>
3401  *
3402  * Programmer:	Quincey Koziol
3403  *		koziol@ncsa.uiuc.edu
3404  *		July 17 2006
3405  *
3406  *-------------------------------------------------------------------------
3407  */
3408 static hbool_t
H5HF_sect_indirect_is_first(H5HF_free_section_t * sect)3409 H5HF_sect_indirect_is_first(H5HF_free_section_t *sect)
3410 {
3411     hbool_t ret_value = FALSE;         /* Return value */
3412 
3413     FUNC_ENTER_NOAPI_NOINIT_NOERR
3414 
3415     /* Sanity check */
3416     HDassert(sect);
3417 
3418     /* Recurse to parent */
3419     if(sect->u.indirect.parent) {
3420         if(sect->sect_info.addr == sect->u.indirect.parent->sect_info.addr)
3421             ret_value = H5HF_sect_indirect_is_first(sect->u.indirect.parent);
3422     } /* end if */
3423     else
3424         ret_value = TRUE;
3425 
3426     FUNC_LEAVE_NOAPI(ret_value)
3427 } /* end H5HF_sect_indirect_is_first() */
3428 
3429 
3430 /*-------------------------------------------------------------------------
3431  * Function:	H5HF__sect_indirect_first
3432  *
3433  * Purpose:	Make new 'first row' for indirect section
3434  *
3435  * Return:	Non-negative on success/Negative on failure
3436  *
3437  * Programmer:	Quincey Koziol
3438  *		koziol@ncsa.uiuc.edu
3439  *		July 10 2006
3440  *
3441  *-------------------------------------------------------------------------
3442  */
3443 static herr_t
H5HF__sect_indirect_first(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)3444 H5HF__sect_indirect_first(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
3445 {
3446     herr_t ret_value = SUCCEED;         /* Return value */
3447 
3448     FUNC_ENTER_STATIC
3449 
3450     /* Sanity check */
3451     HDassert(hdr);
3452     HDassert(sect);
3453 
3454     /* Check if this indirect section has direct block rows */
3455     if(sect->u.indirect.dir_nrows > 0) {
3456         /* Sanity checks */
3457         HDassert(sect->u.indirect.row == 0);
3458         HDassert(sect->u.indirect.col == 0);
3459         HDassert(sect->u.indirect.dir_rows);
3460         HDassert(sect->u.indirect.dir_rows[0]);
3461 
3462         /* Change first row section in indirect section to be the "first row" */
3463         if(H5HF__sect_row_first(hdr, sect->u.indirect.dir_rows[0]) < 0)
3464             HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "can't set row section to be first row")
3465     } /* end if */
3466     else {
3467         /* Sanity checks */
3468         HDassert(sect->u.indirect.indir_nents > 0);
3469         HDassert(sect->u.indirect.indir_ents);
3470         HDassert(sect->u.indirect.indir_ents[0]);
3471 
3472         /* Forward to first child indirect section */
3473         if(H5HF__sect_indirect_first(hdr, sect->u.indirect.indir_ents[0]) < 0)
3474             HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "can't set child indirect section to be first row")
3475     } /* end else */
3476 
3477 done:
3478     FUNC_LEAVE_NOAPI(ret_value)
3479 } /* end H5HF__sect_indirect_first() */
3480 
3481 
3482 /*-------------------------------------------------------------------------
3483  * Function:	H5HF_sect_indirect_get_iblock
3484  *
3485  * Purpose:	Retrieve the indirect block for a indirect section
3486  *
3487  * Return:	Pointer to indirect block on success/NULL on failure
3488  *
3489  * Programmer:	Quincey Koziol
3490  *		koziol@ncsa.uiuc.edu
3491  *		July  9 2006
3492  *
3493  *-------------------------------------------------------------------------
3494  */
3495 static H5HF_indirect_t *
H5HF_sect_indirect_get_iblock(H5HF_free_section_t * sect)3496 H5HF_sect_indirect_get_iblock(H5HF_free_section_t *sect)
3497 {
3498     FUNC_ENTER_NOAPI_NOINIT_NOERR
3499 
3500     /*
3501      * Check arguments.
3502      */
3503     HDassert(sect);
3504     HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_INDIRECT);
3505     HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
3506 
3507     FUNC_LEAVE_NOAPI(sect->u.indirect.u.iblock)
3508 } /* end H5HF_sect_indirect_get_iblock() */
3509 
3510 
3511 /*-------------------------------------------------------------------------
3512  * Function:	H5HF__sect_indirect_merge_row
3513  *
3514  * Purpose:	Merge two sections of this type
3515  *
3516  * Note:        Second section always merges into first node
3517  *
3518  * Return:	Success:	non-negative
3519  *
3520  *		Failure:	negative
3521  *
3522  * Programmer:	Quincey Koziol
3523  *              Tuesday, July 18, 2006
3524  *
3525  *-------------------------------------------------------------------------
3526  */
3527 static herr_t
H5HF__sect_indirect_merge_row(H5HF_hdr_t * hdr,H5HF_free_section_t * row_sect1,H5HF_free_section_t * row_sect2)3528 H5HF__sect_indirect_merge_row(H5HF_hdr_t *hdr, H5HF_free_section_t *row_sect1,
3529     H5HF_free_section_t *row_sect2)
3530 {
3531     H5HF_free_section_t *sect1, *sect2; /* Indirect sections underlying row sections */
3532     unsigned start_entry1;              /* Start entry for section #1 */
3533     unsigned start_row1, start_col1;    /* Starting row & column for section #1 */
3534     unsigned end_entry1;                /* End entry for section #1 */
3535     unsigned end_row1;                  /* Ending row for section #1 */
3536     unsigned start_row2;                /* Starting row for section #2 */
3537     hbool_t merged_rows;                /* Flag to indicate that rows was merged together */
3538     unsigned u;                         /* Local index variable */
3539     herr_t ret_value = SUCCEED;         /* Return value */
3540 
3541     FUNC_ENTER_STATIC
3542 
3543     /* Sanity check parameters */
3544     HDassert(hdr);
3545     HDassert(row_sect1);
3546     HDassert(row_sect1->u.row.under);
3547     HDassert(row_sect2);
3548     HDassert(row_sect2->u.row.under);
3549     HDassert(row_sect2->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
3550 
3551     /* Set up indirect section information */
3552     sect1 = H5HF_sect_indirect_top(row_sect1->u.row.under);
3553     HDassert(sect1);
3554     sect2 = H5HF_sect_indirect_top(row_sect2->u.row.under);
3555     HDassert(sect2);
3556 
3557     /* Sanity check some assumptions about the indirect sections */
3558     HDassert(sect1->u.indirect.span_size > 0);
3559     HDassert(sect2->u.indirect.span_size > 0);
3560 
3561     /* Set up span information */
3562     start_row1 = sect1->u.indirect.row;
3563     start_col1 = sect1->u.indirect.col;
3564     start_entry1 = (start_row1 * hdr->man_dtable.cparam.width) + start_col1;
3565     end_entry1 = (start_entry1 + sect1->u.indirect.num_entries) - 1;
3566     end_row1 = end_entry1 / hdr->man_dtable.cparam.width;
3567     start_row2 = sect2->u.indirect.row;
3568 
3569     /* Check for direct sections in second section */
3570     /* (second indirect section can be parent of indirect section for second
3571      *          row, and thus have no row sections of it's own)
3572      */
3573     if(sect2->u.indirect.dir_nrows > 0) {
3574         hsize_t sect1_iblock_off, sect2_iblock_off;     /* Offset of indirect block underlying row section */
3575         unsigned new_dir_nrows1;        /* New value for number of direct rows in first section */
3576         unsigned src_row2;              /* Source row for copying from second section */
3577         unsigned nrows_moved2;          /* Number of rows to move from second section to first */
3578 
3579         /* Sanity check child row assumptions */
3580         /* (second indirect section should be at top of equal or deeper
3581          *      hier. of row/indirect sections, so if second indirect section
3582          *      has child row sections, first indirect section _must_ have
3583          *      them also)
3584          */
3585         HDassert(sect1->u.indirect.dir_nrows > 0);
3586         HDassert(sect1->u.indirect.dir_rows);
3587 
3588         /* Get the offsets for the indirect blocks under the rows */
3589         if(H5FS_SECT_LIVE == row_sect1->u.row.under->sect_info.state)
3590             sect1_iblock_off = row_sect1->u.row.under->u.indirect.u.iblock->block_off;
3591         else
3592             sect1_iblock_off = row_sect1->u.row.under->u.indirect.u.iblock_off;
3593         if(H5FS_SECT_LIVE == row_sect2->u.row.under->sect_info.state)
3594             sect2_iblock_off = row_sect2->u.row.under->u.indirect.u.iblock->block_off;
3595         else
3596             sect2_iblock_off = row_sect2->u.row.under->u.indirect.u.iblock_off;
3597 
3598         /* Check for sections sharing a row in the same underlying indirect block */
3599         if(sect1_iblock_off == sect2_iblock_off && end_row1 == start_row2) {
3600             H5HF_free_section_t *last_row_sect1;        /* Last row in first indirect section */
3601 
3602             /* Locate the last row section in first indirect section, if we don't already have it */
3603             if(row_sect1->u.row.row != end_row1)
3604                 last_row_sect1 = sect1->u.indirect.dir_rows[sect1->u.indirect.dir_nrows - 1];
3605             else
3606                 last_row_sect1 = row_sect1;
3607             HDassert(last_row_sect1);
3608             HDassert(last_row_sect1->u.row.row == end_row1);
3609 
3610             /* Adjust info for first row section, to absorb second row section */
3611             HDassert((last_row_sect1->u.row.col + last_row_sect1->u.row.num_entries) == row_sect2->u.row.col);
3612             last_row_sect1->u.row.num_entries += row_sect2->u.row.num_entries;
3613 
3614             /* Set up parameters for transfer of rows */
3615             src_row2 = 1;
3616             nrows_moved2 = sect2->u.indirect.dir_nrows - 1;
3617             new_dir_nrows1 = (sect1->u.indirect.dir_nrows + sect2->u.indirect.dir_nrows) - 1;
3618 
3619             /* Indicate that the rows were merged */
3620             merged_rows = TRUE;
3621         } /* end if */
3622         else {
3623 
3624             /* Set up parameters for transfer of rows */
3625             src_row2  = 0;
3626             nrows_moved2 = sect2->u.indirect.dir_nrows;
3627             new_dir_nrows1 = sect1->u.indirect.dir_nrows + sect2->u.indirect.dir_nrows;
3628 
3629             /* Indicate that the rows were _not_ merged */
3630             merged_rows = FALSE;
3631         } /* end else */
3632 
3633         /* Check if we need to move additional rows */
3634         if(nrows_moved2 > 0) {
3635             H5HF_free_section_t **new_dir_rows;         /* Pointer to new array of direct row pointers */
3636 
3637             /* Extend the first section's row array */
3638             if(NULL == (new_dir_rows = (H5HF_free_section_t **)H5MM_realloc(sect1->u.indirect.dir_rows, sizeof(H5HF_free_section_t *) * new_dir_nrows1)))
3639                 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for row section pointer array")
3640             sect1->u.indirect.dir_rows = new_dir_rows;
3641 
3642             /* Transfer the second section's rows to first section */
3643             HDmemcpy(&sect1->u.indirect.dir_rows[sect1->u.indirect.dir_nrows],
3644                 &sect2->u.indirect.dir_rows[src_row2],
3645                 (sizeof(H5HF_free_section_t *) * nrows_moved2));
3646 
3647             /* Re-target the row sections moved from second section */
3648             for(u = sect1->u.indirect.dir_nrows; u < new_dir_nrows1; u++)
3649                 sect1->u.indirect.dir_rows[u]->u.row.under = sect1;
3650 
3651             /* Adjust reference counts to account for transferred rows */
3652             sect1->u.indirect.rc += nrows_moved2;
3653             sect2->u.indirect.rc -= nrows_moved2;
3654 
3655             /* Update information for first section */
3656             sect1->u.indirect.dir_nrows = new_dir_nrows1;
3657         } /* end if */
3658     } /* end if */
3659     else
3660         /* Indicate that the rows were _not_ merged */
3661         merged_rows = FALSE;
3662 
3663     /* Check for indirect sections in second section */
3664     if(sect2->u.indirect.indir_nents > 0) {
3665         unsigned new_indir_nents1;      /* New value for number of indirect entries in first section */
3666 
3667         /* Some sanity checks on second indirect section */
3668         HDassert(sect2->u.indirect.rc > 0);
3669         HDassert(sect2->u.indirect.indir_nents > 0);
3670         HDassert(sect2->u.indirect.indir_ents);
3671 
3672         /* Set up parameters for transfer of entries */
3673         new_indir_nents1 = sect1->u.indirect.indir_nents + sect2->u.indirect.indir_nents;
3674 
3675         /* Check if first section can just take over second section's memory buffer */
3676         if(sect1->u.indirect.indir_ents == NULL) {
3677             sect1->u.indirect.indir_ents = sect2->u.indirect.indir_ents;
3678             sect2->u.indirect.indir_ents = NULL;
3679         } /* end if */
3680         else {
3681             H5HF_free_section_t **new_indir_ents;       /* Pointer to new array of indirect entries */
3682 
3683             /* Extend the first section's entry array */
3684             if(NULL == (new_indir_ents = (H5HF_free_section_t **)H5MM_realloc(sect1->u.indirect.indir_ents, sizeof(H5HF_free_section_t *) * new_indir_nents1)))
3685                 HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for row section pointer array")
3686             sect1->u.indirect.indir_ents = new_indir_ents;
3687 
3688             /* Transfer the second section's entries to first section */
3689             HDmemcpy(&sect1->u.indirect.indir_ents[sect1->u.indirect.indir_nents],
3690                 &sect2->u.indirect.indir_ents[0],
3691                 (sizeof(H5HF_free_section_t *) * sect2->u.indirect.indir_nents));
3692         } /* end else */
3693 
3694         /* Re-target the child indirect sections moved from second section */
3695         for(u = sect1->u.indirect.indir_nents; u < new_indir_nents1; u++)
3696             sect1->u.indirect.indir_ents[u]->u.indirect.parent = sect1;
3697 
3698         /* Adjust reference counts for transferred child indirect sections */
3699         sect1->u.indirect.rc += sect2->u.indirect.indir_nents;
3700         sect2->u.indirect.rc -= sect2->u.indirect.indir_nents;
3701 
3702         /* Update information for first section */
3703         sect1->u.indirect.indir_nents = new_indir_nents1;
3704     } /* end if */
3705 
3706     /* Update information for first section */
3707     sect1->u.indirect.num_entries += sect2->u.indirect.num_entries;
3708     sect1->u.indirect.span_size += sect2->u.indirect.span_size;
3709 
3710     /* Make certain we've tracked the first section's dependents correctly */
3711     HDassert(sect1->u.indirect.rc ==
3712             (sect1->u.indirect.indir_nents + sect1->u.indirect.dir_nrows));
3713 
3714     /* Wrap up, freeing or re-inserting second row section */
3715     /* (want this to be after the first indirect section is consistent again) */
3716     if(merged_rows) {
3717         /* Release second row section */
3718         /* (indirectly releases second indirect section, since all of it's
3719          *  other dependents are gone)
3720          */
3721         HDassert(sect2->u.indirect.rc == 1);
3722         if(H5HF__sect_row_free((H5FS_section_info_t *)row_sect2) < 0)
3723             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free row section")
3724     } /* end if */
3725     else {
3726         /* Decrement ref. count on second indirect section's parent */
3727         HDassert(sect2->u.indirect.rc == 0);
3728         if(sect2->u.indirect.parent)
3729             if(H5HF_sect_indirect_decr(sect2->u.indirect.parent) < 0)
3730                 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't decrement ref. count on parent indirect section")
3731 
3732         /* Free second indirect section */
3733         if(H5HF_sect_indirect_free(sect2) < 0)
3734             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
3735 
3736         /* Re-add the second section's first row */
3737         /* (it's already been added to first indirect section, but it's been removed
3738          *  from the free space manager and needs to be re-added)
3739         */
3740         row_sect2->sect_info.type = H5HF_FSPACE_SECT_NORMAL_ROW;
3741         if(H5HF__space_add(hdr, row_sect2, H5FS_ADD_SKIP_VALID) < 0)
3742             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add second row section to free space")
3743     } /* end else */
3744 
3745     /* Check if we can create parent indirect section for first section */
3746     /* (i.e. merged indirect sections cover an entire indirect block) */
3747     if(sect1->u.indirect.iblock_entries == sect1->u.indirect.num_entries) {
3748         /* Build parent section for fully populated indirect section */
3749         HDassert(sect1->u.indirect.parent == NULL);
3750         if(H5HF__sect_indirect_build_parent(hdr, sect1) < 0)
3751             HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "can't create parent for full indirect section")
3752     } /* end if */
3753 
3754 done:
3755     FUNC_LEAVE_NOAPI(ret_value)
3756 } /* end H5HF__sect_indirect_merge_row() */
3757 
3758 
3759 /*-------------------------------------------------------------------------
3760  * Function:	H5HF__sect_indirect_build_parent
3761  *
3762  * Purpose:	Build a parent indirect section for a full indirect section
3763  *
3764  * Return:	Success:	non-negative
3765  *		Failure:	negative
3766  *
3767  * Programmer:	Quincey Koziol
3768  *              Friday, July 21, 2006
3769  *
3770  *-------------------------------------------------------------------------
3771  */
3772 static herr_t
H5HF__sect_indirect_build_parent(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)3773 H5HF__sect_indirect_build_parent(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
3774 {
3775     H5HF_indirect_t *par_iblock;        /* Indirect block for parent section */
3776     H5HF_free_section_t *par_sect = NULL; /* Parent indirect section */
3777     hsize_t par_block_off;              /* Offset of parent's block */
3778     unsigned par_row, par_col;          /* Row & column in parent indirect section */
3779     unsigned par_entry;                 /* Entry within parent indirect section */
3780     herr_t ret_value = SUCCEED;         /* Return value */
3781 
3782     FUNC_ENTER_STATIC
3783 
3784     /* Sanity check parameters */
3785     HDassert(hdr);
3786     HDassert(sect);
3787     HDassert(H5FS_SECT_LIVE == sect->sect_info.state);
3788     HDassert(sect->u.indirect.span_size > 0);
3789     HDassert(sect->u.indirect.iblock_entries > 0);
3790     HDassert(sect->u.indirect.iblock_entries == sect->u.indirect.num_entries);
3791     HDassert(sect->u.indirect.u.iblock);
3792     HDassert(sect->u.indirect.parent == NULL);
3793 
3794     /* Get information for creating parent indirect section */
3795     if(sect->u.indirect.u.iblock->parent) {
3796         par_entry = sect->u.indirect.u.iblock->par_entry;
3797         par_iblock = sect->u.indirect.u.iblock->parent;
3798         par_block_off = par_iblock->block_off;
3799     } /* end if */
3800     else {
3801         /* Retrieve the information for the parent block */
3802         if(H5HF__man_iblock_parent_info(hdr, sect->sect_info.addr, &par_block_off, &par_entry) < 0)
3803             HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get block entry")
3804         par_iblock = NULL;
3805     } /* end else */
3806 
3807     /* Compute row & column for block in parent */
3808     par_row = par_entry / hdr->man_dtable.cparam.width;
3809     par_col = par_entry % hdr->man_dtable.cparam.width;
3810     HDassert(par_row >= hdr->man_dtable.max_direct_rows);
3811 
3812     /* Create parent indirect section */
3813     if(NULL == (par_sect = H5HF_sect_indirect_new(hdr, sect->sect_info.addr,
3814             sect->sect_info.size, par_iblock, par_block_off,
3815             par_row, par_col, 1)))
3816         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
3817 
3818     /* No rows of direct blocks covered in parent, reset direct row information */
3819     par_sect->u.indirect.dir_nrows = 0;
3820     par_sect->u.indirect.dir_rows = NULL;
3821 
3822     /* Allocate space for the child indirect sections */
3823     par_sect->u.indirect.indir_nents = 1;
3824     if(NULL == (par_sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *))))
3825         HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for indirect section pointer array")
3826 
3827     /* Attach sections together */
3828     sect->u.indirect.parent = par_sect;
3829     sect->u.indirect.par_entry = par_entry;
3830     par_sect->u.indirect.indir_ents[0] = sect;
3831     par_sect->u.indirect.rc = 1;
3832 
3833 done:
3834     if(ret_value < 0)
3835         if(par_sect && H5HF_sect_indirect_free(par_sect) < 0)
3836             HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
3837 
3838     FUNC_LEAVE_NOAPI(ret_value)
3839 } /* end H5HF__sect_indirect_build_parent() */
3840 
3841 
3842 /*-------------------------------------------------------------------------
3843  * Function:	H5HF__sect_indirect_shrink
3844  *
3845  * Purpose:	"Shrink" container w/section
3846  *
3847  * Return:	Success:	non-negative
3848  *		Failure:	negative
3849  *
3850  * Programmer:	Quincey Koziol
3851  *              Monday, July 24, 2006
3852  *
3853  *-------------------------------------------------------------------------
3854  */
3855 static herr_t
H5HF__sect_indirect_shrink(H5HF_hdr_t * hdr,H5HF_free_section_t * sect)3856 H5HF__sect_indirect_shrink(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
3857 {
3858     unsigned u;                         /* Local index variable */
3859     herr_t ret_value = SUCCEED;         /* Return value */
3860 
3861     FUNC_ENTER_STATIC
3862 
3863     /* Sanity check parameters */
3864     HDassert(hdr);
3865     HDassert(sect);
3866 
3867     /* Sanity check some assumptions about the indirect section */
3868     HDassert(sect->u.indirect.dir_nrows > 0 || sect->u.indirect.indir_nents > 0);
3869 
3870     /* Walk through direct rows, freeing them */
3871     for(u = 0; u < sect->u.indirect.dir_nrows; u++) {
3872         /* Remove the normal rows from free space manager */
3873         if(sect->u.indirect.dir_rows[u]->sect_info.type != H5HF_FSPACE_SECT_FIRST_ROW) {
3874             HDassert(sect->u.indirect.dir_rows[u]->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
3875             if(H5HF__space_remove(hdr, sect->u.indirect.dir_rows[u]) < 0)
3876                 HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove section from heap free space")
3877         } /* end if */
3878 
3879         /* Release the row section */
3880         if(H5HF__sect_row_free_real(sect->u.indirect.dir_rows[u]) < 0)
3881             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free child section node")
3882     } /* end for */
3883 
3884     /* Walk through indirect entries, freeing them (recursively) */
3885     for(u = 0; u < sect->u.indirect.indir_nents; u++)
3886         if(H5HF__sect_indirect_shrink(hdr, sect->u.indirect.indir_ents[u]) < 0)
3887             HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free child section node")
3888 
3889     /* Free the indirect section itself */
3890     if(H5HF_sect_indirect_free(sect) < 0)
3891         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
3892 
3893 done:
3894     FUNC_LEAVE_NOAPI(ret_value)
3895 } /* end H5HF__sect_indirect_shrink() */
3896 
3897 
3898 /*-------------------------------------------------------------------------
3899  * Function:	H5HF_sect_indirect_serialize
3900  *
3901  * Purpose:	Serialize a "live" indirect section into a buffer
3902  *
3903  * Return:	Success:	non-negative
3904  *
3905  *		Failure:	negative
3906  *
3907  * Programmer:	Quincey Koziol
3908  *              Monday, July  3, 2006
3909  *
3910  *-------------------------------------------------------------------------
3911  */
3912 static herr_t
H5HF_sect_indirect_serialize(H5HF_hdr_t * hdr,const H5HF_free_section_t * sect,uint8_t * buf)3913 H5HF_sect_indirect_serialize(H5HF_hdr_t *hdr, const H5HF_free_section_t *sect,
3914     uint8_t *buf)
3915 {
3916     herr_t ret_value = SUCCEED;         /* Return value */
3917 
3918     FUNC_ENTER_NOAPI_NOINIT
3919 
3920     /* Check arguments. */
3921     HDassert(hdr);
3922     HDassert(sect);
3923     HDassert(buf);
3924 
3925     /* Check if this indirect section has a parent & forward if this section is first */
3926     if(sect->u.indirect.parent) {
3927         if(sect->sect_info.addr == sect->u.indirect.parent->sect_info.addr)
3928             if(H5HF_sect_indirect_serialize(hdr, sect->u.indirect.parent, buf) < 0)
3929                 HGOTO_ERROR(H5E_HEAP, H5E_CANTSERIALIZE, FAIL, "can't serialize indirect section's parent indirect section")
3930     } /* end if */
3931     else {
3932         /* Indirect range's indirect block's block offset */
3933         if(sect->sect_info.state == H5FS_SECT_LIVE) {
3934             HDassert(sect->u.indirect.u.iblock);
3935             UINT64ENCODE_VAR(buf, sect->u.indirect.u.iblock->block_off, hdr->heap_off_size);
3936         } /* end if */
3937         else
3938             UINT64ENCODE_VAR(buf, sect->u.indirect.u.iblock_off, hdr->heap_off_size);
3939 
3940         /* Indirect range's row */
3941         UINT16ENCODE(buf, sect->u.indirect.row);
3942 
3943         /* Indirect range's column */
3944         UINT16ENCODE(buf, sect->u.indirect.col);
3945 
3946         /* Indirect range's # of entries */
3947         UINT16ENCODE(buf, sect->u.indirect.num_entries);
3948     } /* end else */
3949 
3950 done:
3951     FUNC_LEAVE_NOAPI(ret_value)
3952 } /* H5HF_sect_indirect_serialize() */
3953 
3954 
3955 /*-------------------------------------------------------------------------
3956  * Function:	H5HF__sect_indirect_deserialize
3957  *
3958  * Purpose:	Deserialize a buffer into a "live" indirect section
3959  *
3960  * Return:	Success:	non-negative
3961  *		Failure:	negative
3962  *
3963  * Programmer:	Quincey Koziol
3964  *              Monday, July  3, 2006
3965  *
3966  *-------------------------------------------------------------------------
3967  */
3968 static H5FS_section_info_t *
H5HF__sect_indirect_deserialize(H5HF_hdr_t * hdr,const uint8_t * buf,haddr_t sect_addr,hsize_t sect_size,unsigned * des_flags)3969 H5HF__sect_indirect_deserialize(H5HF_hdr_t *hdr, const uint8_t *buf,
3970     haddr_t sect_addr, hsize_t sect_size, unsigned *des_flags)
3971 {
3972     H5HF_free_section_t *new_sect;      /* New indirect section */
3973     hsize_t iblock_off;                 /* Indirect block's offset */
3974     unsigned start_row;                 /* Indirect section's start row */
3975     unsigned start_col;                 /* Indirect section's start column */
3976     unsigned nentries;                  /* Indirect section's number of entries */
3977     unsigned start_entry;               /* Start entry in indirect block */
3978     unsigned end_entry;                 /* End entry in indirect block */
3979     unsigned end_row;                   /* End row in indirect block */
3980     unsigned end_col;                   /* End column in indirect block */
3981     H5FS_section_info_t *ret_value = NULL;      /* Return value */
3982 
3983     FUNC_ENTER_STATIC
3984 
3985     /* Check arguments. */
3986     HDassert(hdr);
3987     HDassert(buf);
3988     HDassert(H5F_addr_defined(sect_addr));
3989     HDassert(sect_size);
3990 
3991     /* Indirect range's indirect block's block offset */
3992     UINT64DECODE_VAR(buf, iblock_off, hdr->heap_off_size);
3993 
3994     /* Indirect section's row */
3995     UINT16DECODE(buf, start_row);
3996 
3997     /* Indirect section's column */
3998     UINT16DECODE(buf, start_col);
3999 
4000     /* Indirect section's # of entries */
4001     UINT16DECODE(buf, nentries);
4002 
4003     /* Create free space section node */
4004     if(NULL == (new_sect = H5HF_sect_indirect_new(hdr, sect_addr, sect_size,
4005             NULL, iblock_off, start_row, start_col, nentries)))
4006         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't create indirect section")
4007 
4008     /* Compute start entry */
4009     start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
4010 
4011     /* Compute end column & row */
4012     end_entry = (start_entry + nentries) - 1;
4013     end_row = end_entry / hdr->man_dtable.cparam.width;
4014     end_col = end_entry % hdr->man_dtable.cparam.width;
4015 
4016     /* Initialize rows for new indirect section */
4017     if(H5HF__sect_indirect_init_rows(hdr, new_sect, TRUE, NULL,
4018             H5FS_ADD_DESERIALIZING, new_sect->u.indirect.row, new_sect->u.indirect.col,
4019             end_row, end_col) < 0)
4020         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize indirect section")
4021 
4022     /* Indicate that this section shouldn't be added to free space manager's list */
4023     *des_flags |= H5FS_DESERIALIZE_NO_ADD;
4024 
4025     /* Set return value */
4026     ret_value = (H5FS_section_info_t *)new_sect;
4027 
4028 done:
4029     FUNC_LEAVE_NOAPI(ret_value)
4030 } /* H5HF__sect_indirect_deserialize() */
4031 
4032 
4033 /*-------------------------------------------------------------------------
4034  * Function:	H5HF_sect_indirect_free
4035  *
4036  * Purpose:	Free a 'indirect' section node
4037  *
4038  * Return:	Success:	non-negative
4039  *
4040  *		Failure:	negative
4041  *
4042  * Programmer:	Quincey Koziol
4043  *              Monday, July  3, 2006
4044  *
4045  *-------------------------------------------------------------------------
4046  */
4047 static herr_t
H5HF_sect_indirect_free(H5HF_free_section_t * sect)4048 H5HF_sect_indirect_free(H5HF_free_section_t *sect)
4049 {
4050     H5HF_indirect_t *iblock = NULL;     /* Indirect block for section */
4051     herr_t ret_value = SUCCEED;         /* Return value */
4052 
4053     FUNC_ENTER_NOAPI_NOINIT
4054 
4055     HDassert(sect);
4056 
4057     /* Release the memory for tracking direct rows */
4058     sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.dir_rows);
4059 
4060     /* Release the memory for tracking indirect entries */
4061     sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
4062 
4063     /* Check for live reference to an indirect block */
4064     if(sect->sect_info.state == H5FS_SECT_LIVE) {
4065         /* Get indirect block, if there was one */
4066         if(sect->u.indirect.u.iblock)
4067             iblock = sect->u.indirect.u.iblock;
4068     } /* end if */
4069 
4070     /* Release the sections */
4071     if(H5HF_sect_node_free(sect, iblock) < 0)
4072         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
4073 
4074 done:
4075     FUNC_LEAVE_NOAPI(ret_value)
4076 }   /* H5HF_sect_indirect_free() */
4077 
4078 
4079 /*-------------------------------------------------------------------------
4080  * Function:	H5HF_sect_indirect_valid
4081  *
4082  * Purpose:	Check the validity of a section
4083  *
4084  * Return:	Success:	non-negative
4085  *		Failure:	negative
4086  *
4087  * Programmer:	Quincey Koziol
4088  *              Friday, July 21, 2006
4089  *
4090  *-------------------------------------------------------------------------
4091  */
4092 static herr_t
H5HF_sect_indirect_valid(const H5HF_hdr_t * hdr,const H5HF_free_section_t * sect)4093 H5HF_sect_indirect_valid(const H5HF_hdr_t *hdr, const H5HF_free_section_t *sect)
4094 {
4095     unsigned start_row;         /* Row for first block covered */
4096     unsigned start_col;         /* Column for first block covered */
4097     unsigned start_entry;       /* Entry for first block covered */
4098     unsigned end_row;           /* Row for last block covered */
4099     unsigned end_entry;         /* Entry for last block covered */
4100     unsigned u;                 /* Local index variable */
4101 
4102     FUNC_ENTER_NOAPI_NOINIT_NOERR
4103 
4104     /* Sanity check arguments */
4105     HDassert(hdr);
4106     HDassert(sect);
4107 
4108     /* Compute starting entry, column & row */
4109     start_row = sect->u.indirect.row;
4110     start_col = sect->u.indirect.col;
4111     start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
4112 
4113     /* Compute ending entry, column & row */
4114     end_entry = (start_entry + sect->u.indirect.num_entries) - 1;
4115     end_row = end_entry / hdr->man_dtable.cparam.width;
4116 
4117     /* Sanity check any direct rows */
4118     if(sect->u.indirect.dir_nrows > 0) {
4119         unsigned dir_nrows;         /* Number of direct rows in section */
4120         unsigned max_dir_row;       /* Maximum direct row in section */
4121 
4122         /* Check for indirect rows in section */
4123         if(end_row >= hdr->man_dtable.max_direct_rows)
4124             max_dir_row = hdr->man_dtable.max_direct_rows - 1;
4125         else
4126             max_dir_row = end_row;
4127 
4128         /* Iterate over direct rows, checking pointer references */
4129         dir_nrows = (max_dir_row - start_row) + 1;
4130         HDassert(dir_nrows == sect->u.indirect.dir_nrows);
4131         for(u = 0; u < dir_nrows; u++) {
4132             const H5HF_free_section_t *tmp_row_sect;    /* Pointer to row section */
4133 
4134             tmp_row_sect = sect->u.indirect.dir_rows[u];
4135             HDassert(tmp_row_sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW
4136                     || tmp_row_sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
4137             HDassert(tmp_row_sect->u.row.under == sect);
4138             HDassert(tmp_row_sect->u.row.row == (start_row + u));
4139             if(u > 0) {
4140                 const H5HF_free_section_t *tmp_row_sect2;    /* Pointer to row section */
4141 
4142                 tmp_row_sect2 = sect->u.indirect.dir_rows[u - 1];
4143                 HDassert(tmp_row_sect2->u.row.row < tmp_row_sect->u.row.row);
4144                 HDassert(H5F_addr_lt(tmp_row_sect2->sect_info.addr, tmp_row_sect->sect_info.addr));
4145                 HDassert(tmp_row_sect2->sect_info.size <= tmp_row_sect->sect_info.size);
4146             } /* end if */
4147         } /* end for */
4148     } /* end if */
4149 
4150     /* Sanity check any indirect entries */
4151     if(sect->u.indirect.indir_nents > 0) {
4152         /* Basic sanity checks */
4153         if(sect->sect_info.state == H5FS_SECT_LIVE) {
4154             HDassert(sect->u.indirect.iblock_entries);
4155             HDassert(sect->u.indirect.indir_nents <= sect->u.indirect.iblock_entries);
4156         } /* end if */
4157         HDassert(sect->u.indirect.indir_ents);
4158 
4159         /* Sanity check each child indirect section */
4160         for(u = 0; u < sect->u.indirect.indir_nents; u++) {
4161             const H5HF_free_section_t *tmp_child_sect;    /* Pointer to child indirect section */
4162 
4163             tmp_child_sect = sect->u.indirect.indir_ents[u];
4164             HDassert(tmp_child_sect->sect_info.type == H5HF_FSPACE_SECT_INDIRECT);
4165             HDassert(tmp_child_sect->u.indirect.parent == sect);
4166             if(u > 0) {
4167                 const H5HF_free_section_t *tmp_child_sect2;    /* Pointer to child indirect section */
4168 
4169                 tmp_child_sect2 = sect->u.indirect.indir_ents[u - 1];
4170                 HDassert(H5F_addr_lt(tmp_child_sect2->sect_info.addr, tmp_child_sect->sect_info.addr));
4171             } /* end if */
4172 
4173             /* Recursively check child indirect section */
4174             H5HF_sect_indirect_valid(hdr, tmp_child_sect);
4175         } /* end for */
4176     } /* end if */
4177 
4178     FUNC_LEAVE_NOAPI(SUCCEED)
4179 }   /* H5HF_sect_indirect_valid() */
4180 
4181 
4182 /*-------------------------------------------------------------------------
4183  * Function:	H5HF_sect_indirect_debug
4184  *
4185  * Purpose:	Dump debugging information about an indirect free space section
4186  *
4187  * Return:	Success:	non-negative
4188  *
4189  *		Failure:	negative
4190  *
4191  * Programmer:	Quincey Koziol
4192  *              Monday, July  3, 2006
4193  *
4194  *-------------------------------------------------------------------------
4195  */
4196 static herr_t
H5HF_sect_indirect_debug(const H5HF_free_section_t * sect,FILE * stream,int indent,int fwidth)4197 H5HF_sect_indirect_debug(const H5HF_free_section_t *sect,
4198     FILE *stream, int indent, int fwidth)
4199 {
4200     FUNC_ENTER_NOAPI_NOINIT_NOERR
4201 
4202     /* Check arguments. */
4203     HDassert(sect);
4204 
4205     /* Print indirect section information */
4206     HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
4207 	      "Row:",
4208 	      sect->u.indirect.row);
4209     HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
4210 	      "Column:",
4211 	      sect->u.indirect.col);
4212     HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
4213 	      "Number of entries:",
4214 	      sect->u.indirect.num_entries);
4215 
4216     FUNC_LEAVE_NOAPI(SUCCEED)
4217 } /* H5HF_sect_indirect_debug() */
4218 
4219