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