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