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