1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /*-------------------------------------------------------------------------
15 *
16 * Created: H5HFspace.c
17 * May 2 2006
18 * Quincey Koziol <koziol@ncsa.uiuc.edu>
19 *
20 * Purpose: Space allocation routines for fractal heaps.
21 *
22 *-------------------------------------------------------------------------
23 */
24
25 /****************/
26 /* Module Setup */
27 /****************/
28
29 #include "H5HFmodule.h" /* This source code file is part of the H5HF module */
30
31
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h" /* Generic Functions */
36 #include "H5Eprivate.h" /* Error handling */
37 #include "H5HFpkg.h" /* Fractal heaps */
38
39
40 /****************/
41 /* Local Macros */
42 /****************/
43
44 #define H5HF_FSPACE_SHRINK 80 /* Percent of "normal" size to shrink serialized free space size */
45 #define H5HF_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */
46 #define H5HF_FSPACE_THRHD_DEF 1 /* Default: no alignment threshold */
47 #define H5HF_FSPACE_ALIGN_DEF 1 /* Default: no alignment */
48
49 /******************/
50 /* Local Typedefs */
51 /******************/
52
53
54 /********************/
55 /* Package Typedefs */
56 /********************/
57
58
59 /********************/
60 /* Local Prototypes */
61 /********************/
62
63
64 /*********************/
65 /* Package Variables */
66 /*********************/
67
68
69 /*****************************/
70 /* Library Private Variables */
71 /*****************************/
72
73
74 /*******************/
75 /* Local Variables */
76 /*******************/
77
78
79
80 /*-------------------------------------------------------------------------
81 * Function: H5HF__space_start
82 *
83 * Purpose: "Start up" free space for heap - open existing free space
84 * structure if one exists, otherwise create a new free space
85 * structure
86 *
87 * Return: Success: non-negative
88 *
89 * Failure: negative
90 *
91 * Programmer: Quincey Koziol
92 * koziol@ncsa.uiuc.edu
93 * May 2 2006
94 *
95 *-------------------------------------------------------------------------
96 */
97 herr_t
H5HF__space_start(H5HF_hdr_t * hdr,hbool_t may_create)98 H5HF__space_start(H5HF_hdr_t *hdr, hbool_t may_create)
99 {
100 const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for fractal heap */
101 H5HF_FSPACE_SECT_CLS_SINGLE,
102 H5HF_FSPACE_SECT_CLS_FIRST_ROW,
103 H5HF_FSPACE_SECT_CLS_NORMAL_ROW,
104 H5HF_FSPACE_SECT_CLS_INDIRECT};
105 herr_t ret_value = SUCCEED; /* Return value */
106
107 FUNC_ENTER_PACKAGE
108
109 /*
110 * Check arguments.
111 */
112 HDassert(hdr);
113
114 /* Check for creating free space info for the heap */
115 if(H5F_addr_defined(hdr->fs_addr)) {
116 /* Open an existing free space structure for the heap */
117 if(NULL == (hdr->fspace = H5FS_open(hdr->f, hdr->fs_addr,
118 NELMTS(classes), classes, hdr, (hsize_t)H5HF_FSPACE_THRHD_DEF, (hsize_t)H5HF_FSPACE_ALIGN_DEF)))
119 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info")
120 } /* end if */
121 else {
122 /* Check if we are allowed to create the free space manager */
123 if(may_create) {
124 H5FS_create_t fs_create; /* Free space creation parameters */
125
126 /* Set the free space creation parameters */
127 fs_create.client = H5FS_CLIENT_FHEAP_ID;
128 fs_create.shrink_percent = H5HF_FSPACE_SHRINK;
129 fs_create.expand_percent = H5HF_FSPACE_EXPAND;
130 fs_create.max_sect_size = hdr->man_dtable.cparam.max_direct_size;
131 fs_create.max_sect_addr = hdr->man_dtable.cparam.max_index;
132
133 /* Create the free space structure for the heap */
134 if(NULL == (hdr->fspace = H5FS_create(hdr->f, &hdr->fs_addr,
135 &fs_create, NELMTS(classes), classes, hdr, (hsize_t)H5HF_FSPACE_THRHD_DEF, (hsize_t)H5HF_FSPACE_ALIGN_DEF)))
136 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info")
137 HDassert(H5F_addr_defined(hdr->fs_addr));
138 } /* end if */
139 } /* end else */
140
141 done:
142 FUNC_LEAVE_NOAPI(ret_value)
143 } /* end H5HF__space_start() */
144
145
146 /*-------------------------------------------------------------------------
147 * Function: H5HF__space_add
148 *
149 * Purpose: Add a section to the free space for the heap
150 *
151 * Return: Success: non-negative
152 *
153 * Failure: negative
154 *
155 * Programmer: Quincey Koziol
156 * koziol@ncsa.uiuc.edu
157 * May 15 2006
158 *
159 *-------------------------------------------------------------------------
160 */
161 herr_t
H5HF__space_add(H5HF_hdr_t * hdr,H5HF_free_section_t * node,unsigned flags)162 H5HF__space_add(H5HF_hdr_t *hdr, H5HF_free_section_t *node, unsigned flags)
163 {
164 H5HF_sect_add_ud_t udata; /* User data for free space manager 'add' */
165 herr_t ret_value = SUCCEED; /* Return value */
166
167 FUNC_ENTER_PACKAGE
168
169 /*
170 * Check arguments.
171 */
172 HDassert(hdr);
173 HDassert(node);
174
175 /* Check if the free space for the heap has been initialized */
176 if(!hdr->fspace)
177 if(H5HF__space_start(hdr, TRUE) < 0)
178 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
179
180 /* Construct user data */
181 udata.hdr = hdr;
182
183 /* Add to the free space for the heap */
184 if(H5FS_sect_add(hdr->f, hdr->fspace, (H5FS_section_info_t *)node, flags, &udata) < 0)
185 HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't add section to heap free space")
186
187 done:
188 FUNC_LEAVE_NOAPI(ret_value)
189 } /* end H5HF__space_add() */
190
191
192 /*-------------------------------------------------------------------------
193 * Function: H5HF__space_find
194 *
195 * Purpose: Attempt to find space in a fractal heap
196 *
197 * Return: Success: non-negative
198 * Failure: negative
199 *
200 * Programmer: Quincey Koziol
201 * koziol@ncsa.uiuc.edu
202 * May 2 2006
203 *
204 *-------------------------------------------------------------------------
205 */
206 htri_t
H5HF__space_find(H5HF_hdr_t * hdr,hsize_t request,H5HF_free_section_t ** node)207 H5HF__space_find(H5HF_hdr_t *hdr, hsize_t request, H5HF_free_section_t **node)
208 {
209 htri_t node_found = FALSE; /* Whether an existing free list node was found */
210 htri_t ret_value = FAIL; /* Return value */
211
212 FUNC_ENTER_PACKAGE
213
214 /*
215 * Check arguments.
216 */
217 HDassert(hdr);
218 HDassert(request);
219 HDassert(node);
220
221 /* Check if the free space for the heap has been initialized */
222 if(!hdr->fspace)
223 if(H5HF__space_start(hdr, FALSE) < 0)
224 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
225
226 /* Search for free space in the heap */
227 if(hdr->fspace)
228 if((node_found = H5FS_sect_find(hdr->f, hdr->fspace, request, (H5FS_section_info_t **)node)) < 0)
229 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't locate free space in fractal heap")
230
231 /* Set return value */
232 ret_value = node_found;
233
234 done:
235 FUNC_LEAVE_NOAPI(ret_value)
236 } /* end H5HF__space_find() */
237
238
239 /*-------------------------------------------------------------------------
240 * Function: H5HF_space_revert_root_cb
241 *
242 * Purpose: Callback routine from iterator, to reset 'parent' pointers in
243 * sections, when the heap is changing from having a root indirect
244 * block to a direct block.
245 *
246 * Return: Success: non-negative
247 * Failure: negative
248 *
249 * Programmer: Quincey Koziol
250 * koziol@hdfgroup.org
251 * Feb 24 2012
252 *
253 *-------------------------------------------------------------------------
254 */
255 static herr_t
H5HF_space_revert_root_cb(H5FS_section_info_t * _sect,void H5_ATTR_UNUSED * _udata)256 H5HF_space_revert_root_cb(H5FS_section_info_t *_sect, void H5_ATTR_UNUSED *_udata)
257 {
258 H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Section to dump info */
259 herr_t ret_value = SUCCEED; /* Return value */
260
261 FUNC_ENTER_NOAPI_NOINIT
262
263 /*
264 * Check arguments.
265 */
266 HDassert(sect);
267
268 /* Only modify "live" single blocks... */
269 if(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE && sect->sect_info.state == H5FS_SECT_LIVE) {
270 /* Release hold on previous indirect block (we must have one) */
271 HDassert(sect->u.single.parent);
272 if(H5HF__iblock_decr(sect->u.single.parent) < 0)
273 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on section's indirect block")
274
275 /* Reset parent information */
276 sect->u.single.parent = NULL;
277 sect->u.single.par_entry = 0;
278 } /* end if */
279
280 done:
281 FUNC_LEAVE_NOAPI(ret_value)
282 } /* end H5HF_space_revert_root_cb() */
283
284
285 /*-------------------------------------------------------------------------
286 * Function: H5HF__space_revert_root
287 *
288 * Purpose: Reset 'parent' pointers in sections, when the heap is
289 * changing from having a root indirect block to a direct block.
290 *
291 * Return: Success: non-negative
292 * Failure: negative
293 *
294 * Programmer: Quincey Koziol
295 * koziol@hdfgroup.org
296 * Feb 23 2012
297 *
298 *-------------------------------------------------------------------------
299 */
300 herr_t
H5HF__space_revert_root(const H5HF_hdr_t * hdr)301 H5HF__space_revert_root(const H5HF_hdr_t *hdr)
302 {
303 herr_t ret_value = SUCCEED; /* Return value */
304
305 FUNC_ENTER_PACKAGE
306
307 /*
308 * Check arguments.
309 */
310 HDassert(hdr);
311
312 /* Only need to scan the sections if the free space has been initialized */
313 if(hdr->fspace)
314 /* Iterate over all sections, resetting the parent pointers in 'single' sections */
315 if(H5FS_sect_iterate(hdr->f, hdr->fspace, H5HF_space_revert_root_cb, NULL) < 0)
316 HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over sections to reset parent pointers")
317
318 done:
319 FUNC_LEAVE_NOAPI(ret_value)
320 } /* end H5HF__space_revert_root() */
321
322
323 /*-------------------------------------------------------------------------
324 * Function: H5HF_space_create_root_cb
325 *
326 * Purpose: Callback routine from iterator, to set 'parent' pointers in
327 * sections to newly created root indirect block, when the heap
328 * is changing from having a root direct block to an indirect block.
329 *
330 * Return: Success: non-negative
331 * Failure: negative
332 *
333 * Programmer: Quincey Koziol
334 * koziol@hdfgroup.org
335 * Feb 24 2012
336 *
337 *-------------------------------------------------------------------------
338 */
339 static herr_t
H5HF_space_create_root_cb(H5FS_section_info_t * _sect,void * _udata)340 H5HF_space_create_root_cb(H5FS_section_info_t *_sect, void *_udata)
341 {
342 H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Section to dump info */
343 H5HF_indirect_t *root_iblock = (H5HF_indirect_t *)_udata; /* User data for callback */
344 herr_t ret_value = SUCCEED; /* Return value */
345
346 FUNC_ENTER_NOAPI_NOINIT
347
348 /*
349 * Check arguments.
350 */
351 HDassert(sect);
352 HDassert(root_iblock);
353
354 /* Sanity check sections */
355 /* (If we are switching from a direct block for the root block of the heap, */
356 /* there should only be 'single' type sections. -QAK) */
357 HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
358
359 /* Increment ref. count on new root indirect block */
360 if(H5HF_iblock_incr(root_iblock) < 0)
361 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on section's indirect block")
362
363 /* Set parent info ("live" section must _NOT_ have a parent right now) */
364 if(sect->sect_info.state == H5FS_SECT_SERIALIZED)
365 sect->sect_info.state = H5FS_SECT_LIVE; /* Mark "live" now */
366 else
367 HDassert(!sect->u.single.parent);
368 sect->u.single.parent = root_iblock;
369 sect->u.single.par_entry = 0;
370
371 done:
372 FUNC_LEAVE_NOAPI(ret_value)
373 } /* end H5HF_space_create_root_cb() */
374
375
376 /*-------------------------------------------------------------------------
377 * Function: H5HF__space_create_root
378 *
379 * Purpose: Set 'parent' pointers in sections to new indirect block, when
380 * the heap is changing from having a root direct block to a
381 * indirect block.
382 *
383 * Return: Success: non-negative
384 * Failure: negative
385 *
386 * Programmer: Quincey Koziol
387 * koziol@hdfgroup.org
388 * Feb 24 2012
389 *
390 *-------------------------------------------------------------------------
391 */
392 herr_t
H5HF__space_create_root(const H5HF_hdr_t * hdr,H5HF_indirect_t * root_iblock)393 H5HF__space_create_root(const H5HF_hdr_t *hdr, H5HF_indirect_t *root_iblock)
394 {
395 herr_t ret_value = SUCCEED; /* Return value */
396
397 FUNC_ENTER_PACKAGE
398
399 /*
400 * Check arguments.
401 */
402 HDassert(hdr);
403 HDassert(root_iblock);
404
405 /* Only need to scan the sections if the free space has been initialized */
406 if(hdr->fspace)
407 /* Iterate over all sections, seting the parent pointers in 'single' sections to the new indirect block */
408 if(H5FS_sect_iterate(hdr->f, hdr->fspace, H5HF_space_create_root_cb, root_iblock) < 0)
409 HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over sections to set parent pointers")
410
411 done:
412 FUNC_LEAVE_NOAPI(ret_value)
413 } /* end H5HF__space_create_root() */
414
415
416 /*-------------------------------------------------------------------------
417 * Function: H5HF__space_size
418 *
419 * Purpose: Query the size of the heap's free space info on disk
420 *
421 * Return: Success: non-negative
422 * Failure: negative
423 *
424 * Programmer: Quincey Koziol
425 * koziol@hdfgroup.org
426 * August 14 2007
427 *
428 *-------------------------------------------------------------------------
429 */
430 herr_t
H5HF__space_size(H5HF_hdr_t * hdr,hsize_t * fs_size)431 H5HF__space_size(H5HF_hdr_t *hdr, hsize_t *fs_size)
432 {
433 herr_t ret_value = SUCCEED; /* Return value */
434
435 FUNC_ENTER_PACKAGE
436
437 /*
438 * Check arguments.
439 */
440 HDassert(hdr);
441 HDassert(fs_size);
442
443 /* Check if the free space for the heap has been initialized */
444 if(!hdr->fspace)
445 if(H5HF__space_start(hdr, FALSE) < 0)
446 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
447
448 /* Get free space metadata size */
449 if(hdr->fspace) {
450 if(H5FS_size(hdr->f, hdr->fspace, fs_size) < 0)
451 HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't retrieve FS meta storage info")
452 } /* end if */
453 else
454 *fs_size = 0;
455
456 done:
457 FUNC_LEAVE_NOAPI(ret_value)
458 } /* end H5HF__space_size() */
459
460
461 /*-------------------------------------------------------------------------
462 * Function: H5HF__space_remove
463 *
464 * Purpose: Remove a section from the free space for the heap
465 *
466 * Return: Success: non-negative
467 * Failure: negative
468 *
469 * Programmer: Quincey Koziol
470 * koziol@ncsa.uiuc.edu
471 * July 24 2006
472 *
473 *-------------------------------------------------------------------------
474 */
475 herr_t
H5HF__space_remove(H5HF_hdr_t * hdr,H5HF_free_section_t * node)476 H5HF__space_remove(H5HF_hdr_t *hdr, H5HF_free_section_t *node)
477 {
478 herr_t ret_value = SUCCEED; /* Return value */
479
480 FUNC_ENTER_PACKAGE
481
482 /*
483 * Check arguments.
484 */
485 HDassert(hdr);
486 HDassert(hdr->fspace);
487 HDassert(node);
488
489 /* Remove from the free space for the heap */
490 if(H5FS_sect_remove(hdr->f, hdr->fspace, (H5FS_section_info_t *)node) < 0)
491 HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove section from heap free space")
492
493 done:
494 FUNC_LEAVE_NOAPI(ret_value)
495 } /* end H5HF__space_remove() */
496
497
498 /*-------------------------------------------------------------------------
499 * Function: H5HF__space_close
500 *
501 * Purpose: Close the free space for the heap
502 *
503 * Return: Success: non-negative
504 *
505 * Failure: negative
506 *
507 * Programmer: Quincey Koziol
508 * koziol@ncsa.uiuc.edu
509 * May 2 2006
510 *
511 *-------------------------------------------------------------------------
512 */
513 herr_t
H5HF__space_close(H5HF_hdr_t * hdr)514 H5HF__space_close(H5HF_hdr_t *hdr)
515 {
516 herr_t ret_value = SUCCEED; /* Return value */
517
518 FUNC_ENTER_PACKAGE
519
520 /*
521 * Check arguments.
522 */
523 HDassert(hdr);
524
525 /* Check if the free space was ever opened */
526 if(hdr->fspace) {
527 hsize_t nsects; /* Number of sections for this heap */
528
529 /* Retrieve the number of sections for this heap */
530 if(H5FS_sect_stats(hdr->fspace, NULL, &nsects) < 0)
531 HGOTO_ERROR(H5E_HEAP, H5E_CANTCOUNT, FAIL, "can't query free space section count")
532 #ifdef QAK
533 HDfprintf(stderr, "%s: nsects = %Hu\n", FUNC, nsects);
534 #endif /* QAK */
535
536 /* Close the free space for the heap */
537 if(H5FS_close(hdr->f, hdr->fspace) < 0)
538 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info")
539 hdr->fspace = NULL;
540
541 /* Check if we can delete the free space manager for this heap */
542 if(!nsects) {
543 if(H5FS_delete(hdr->f, hdr->fs_addr) < 0)
544 HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "can't delete free space info")
545 hdr->fs_addr = HADDR_UNDEF;
546 } /* end if */
547 } /* end if */
548
549 done:
550 FUNC_LEAVE_NOAPI(ret_value)
551 } /* end H5HF__space_close() */
552
553
554 /*-------------------------------------------------------------------------
555 * Function: H5HF__space_delete
556 *
557 * Purpose: Delete the free space manager for the heap
558 *
559 * Return: Success: non-negative
560 * Failure: negative
561 *
562 * Programmer: Quincey Koziol
563 * koziol@ncsa.uiuc.edu
564 * Aug 7 2006
565 *
566 *-------------------------------------------------------------------------
567 */
568 herr_t
H5HF__space_delete(H5HF_hdr_t * hdr)569 H5HF__space_delete(H5HF_hdr_t *hdr)
570 {
571 herr_t ret_value = SUCCEED; /* Return value */
572
573 FUNC_ENTER_PACKAGE
574
575 /*
576 * Check arguments.
577 */
578 HDassert(hdr);
579
580 /* Delete the free space manager */
581 if(H5FS_delete(hdr->f, hdr->fs_addr) < 0)
582 HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "can't delete to free space manager")
583
584 done:
585 FUNC_LEAVE_NOAPI(ret_value)
586 } /* end H5HF__space_delete() */
587
588
589 /*-------------------------------------------------------------------------
590 * Function: H5HF__space_sect_change_class
591 *
592 * Purpose: Change a section's class
593 *
594 * Return: Success: non-negative
595 *
596 * Failure: negative
597 *
598 * Programmer: Quincey Koziol
599 * koziol@ncsa.uiuc.edu
600 * July 10 2006
601 *
602 *-------------------------------------------------------------------------
603 */
604 herr_t
H5HF__space_sect_change_class(H5HF_hdr_t * hdr,H5HF_free_section_t * sect,uint16_t new_class)605 H5HF__space_sect_change_class(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
606 uint16_t new_class)
607 {
608 herr_t ret_value = SUCCEED; /* Return value */
609
610 FUNC_ENTER_PACKAGE
611 #ifdef QAK
612 HDfprintf(stderr, "%s: Called\n", FUNC);
613 #endif /* QAK */
614
615 /*
616 * Check arguments.
617 */
618 HDassert(hdr);
619 HDassert(hdr->fspace);
620 HDassert(sect);
621
622 /* Notify the free space manager that a section has changed class */
623 if(H5FS_sect_change_class(hdr->f, hdr->fspace, (H5FS_section_info_t *)sect, new_class) < 0)
624 HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, FAIL, "can't modify class of free space section")
625
626 done:
627 FUNC_LEAVE_NOAPI(ret_value)
628 } /* end H5HF__space_sect_change_class() */
629
630