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