1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the files COPYING and Copyright.html.  COPYING can be found at the root   *
9  * of the source code distribution tree; Copyright.html can be found at the  *
10  * root level of an installed copy of the electronic HDF5 document set and   *
11  * is linked from the top-level documents page.  It can also be found at     *
12  * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
13  * access to either file, you may request a copy from help@hdfgroup.org.     *
14  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /*
17  * Programmer:	Quincey Koziol <koziol@ncsa.uiuc.edu>
18  *              Tuesday, May  2, 2006
19  *
20  * Purpose:	Free space tracking functions.
21  *
22  * Note:	(Used to be in the H5HFflist.c file, prior to the date above)
23  *
24  */
25 
26 /****************/
27 /* Module Setup */
28 /****************/
29 
30 #define H5FS_PACKAGE		/*suppress error about including H5FSpkg  */
31 
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h"		/* Generic Functions			*/
36 #include "H5ACprivate.h"        /* Metadata cache                       */
37 #include "H5Eprivate.h"		/* Error handling		  	*/
38 #include "H5FSpkg.h"		/* File free space			*/
39 #include "H5MFprivate.h"	/* File memory management		*/
40 
41 /****************/
42 /* Local Macros */
43 /****************/
44 
45 
46 /******************/
47 /* Local Typedefs */
48 /******************/
49 
50 
51 /********************/
52 /* Package Typedefs */
53 /********************/
54 
55 
56 /********************/
57 /* Local Prototypes */
58 /********************/
59 
60 /* Section info routines */
61 static herr_t H5FS_sinfo_free_sect_cb(void *item, void *key, void *op_data);
62 static herr_t H5FS_sinfo_free_node_cb(void *item, void *key, void *op_data);
63 
64 
65 /*********************/
66 /* Package Variables */
67 /*********************/
68 
69 /* Declare a free list to manage the H5FS_section_class_t sequence information */
70 H5FL_SEQ_DEFINE(H5FS_section_class_t);
71 
72 /* Declare a free list to manage the H5FS_t struct */
73 H5FL_DEFINE(H5FS_t);
74 
75 
76 /*****************************/
77 /* Library Private Variables */
78 /*****************************/
79 
80 
81 /*******************/
82 /* Local Variables */
83 /*******************/
84 
85 
86 
87 /*-------------------------------------------------------------------------
88  * Function:	H5FS_create
89  *
90  * Purpose:	Allocate & initialize file free space info
91  *
92  * Return:	Success:	Pointer to free space structure
93  *
94  *		Failure:	NULL
95  *
96  * Programmer:	Quincey Koziol
97  *              Tuesday, March  7, 2006
98  *
99  * Modifications:
100  *	Vailin Choi, July 29th, 2008
101  *	  Add two more parameters for handling alignment: alignment & threshhold
102  *
103  *-------------------------------------------------------------------------
104  */
105 H5FS_t *
H5FS_create(H5F_t * f,hid_t dxpl_id,haddr_t * fs_addr,const H5FS_create_t * fs_create,size_t nclasses,const H5FS_section_class_t * classes[],void * cls_init_udata,hsize_t alignment,hsize_t threshold)106 H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr, const H5FS_create_t *fs_create,
107     size_t nclasses, const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold)
108 {
109     H5FS_t *fspace = NULL;      /* New free space structure */
110     H5FS_t *ret_value;          /* Return value */
111 
112     FUNC_ENTER_NOAPI(NULL)
113 #ifdef H5FS_DEBUG
114 HDfprintf(stderr, "%s: Creating free space manager, nclasses = %Zu\n", FUNC, nclasses);
115 #endif /* H5FS_DEBUG */
116 
117     /* Check arguments. */
118     HDassert(fs_create->shrink_percent);
119     HDassert(fs_create->shrink_percent < fs_create->expand_percent);
120     HDassert(fs_create->max_sect_size);
121     HDassert(nclasses == 0 || classes);
122 
123     /*
124      * Allocate free space structure
125      */
126     if(NULL == (fspace = H5FS_new(f, nclasses, classes, cls_init_udata)))
127 	HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list")
128 
129     /* Initialize creation information for free space manager */
130     fspace->client = fs_create->client;
131     fspace->shrink_percent = fs_create->shrink_percent;
132     fspace->expand_percent = fs_create->expand_percent;
133     fspace->max_sect_addr = fs_create->max_sect_addr;
134     fspace->max_sect_size = fs_create->max_sect_size;
135 
136     fspace->alignment = alignment;
137     fspace->threshold = threshold;
138 
139     /* Check if the free space tracker is supposed to be persistant */
140     if(fs_addr) {
141         /* Allocate space for the free space header */
142         if(HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, dxpl_id, (hsize_t)fspace->hdr_size)))
143             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "file allocation failed for free space header")
144 
145         /* Cache the new free space header (pinned) */
146         if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
147             HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, NULL, "can't add free space header to cache")
148 
149         /* Return free space header address to caller, if desired */
150         *fs_addr = fspace->addr;
151     } /* end if */
152 
153     /* Set the reference count to 1, since we inserted the entry in the cache pinned */
154     fspace->rc = 1;
155 
156     /* Set the return value */
157     ret_value = fspace;
158 #ifdef H5FS_DEBUG
159 HDfprintf(stderr, "%s: fspace = %p, fspace->addr = %a\n", FUNC, fspace, fspace->addr);
160 #endif /* H5FS_DEBUG */
161 
162 done:
163     if(!ret_value && fspace)
164         if(H5FS_hdr_dest(fspace) < 0)
165             HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space header")
166 
167 #ifdef H5FS_DEBUG
168 HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
169 #endif /* H5FS_DEBUG */
170     FUNC_LEAVE_NOAPI(ret_value)
171 } /* H5FS_create() */
172 
173 
174 /*-------------------------------------------------------------------------
175  * Function:	H5FS_open
176  *
177  * Purpose:	Open an existing file free space info structure on disk
178  *
179  * Return:	Success:	Pointer to free space structure
180  *
181  *		Failure:	NULL
182  *
183  * Programmer:	Quincey Koziol
184  *              Tuesday, May  2, 2006
185  *
186  * Modfications:
187  *
188  *	Vailin Choi, July 29th, 2008
189  *	  Add two more parameters for handling alignment: alignment & threshhold
190  *
191  *-------------------------------------------------------------------------
192  */
193 H5FS_t *
H5FS_open(H5F_t * f,hid_t dxpl_id,haddr_t fs_addr,size_t nclasses,const H5FS_section_class_t * classes[],void * cls_init_udata,hsize_t alignment,hsize_t threshold)194 H5FS_open(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr, size_t nclasses,
195     const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold)
196 {
197     H5FS_t *fspace = NULL;      /* New free space structure */
198     H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
199     H5FS_t *ret_value;          /* Return value */
200 
201     FUNC_ENTER_NOAPI(NULL)
202 #ifdef H5FS_DEBUG
203 HDfprintf(stderr, "%s: Opening free space manager, fs_addr = %a, nclasses = %Zu\n", FUNC, fs_addr, nclasses);
204 #endif /* H5FS_DEBUG */
205 
206     /* Check arguments. */
207     HDassert(H5F_addr_defined(fs_addr));
208     HDassert(nclasses);
209     HDassert(classes);
210 
211     /* Initialize user data for protecting the free space manager */
212     cache_udata.f = f;
213     cache_udata.nclasses = nclasses;
214     cache_udata.classes = classes;
215     cache_udata.cls_init_udata = cls_init_udata;
216     cache_udata.addr = fs_addr;
217 
218     /* Protect the free space header */
219     if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC_READ)))
220         HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, NULL, "unable to load free space header")
221 #ifdef H5FS_DEBUG
222 HDfprintf(stderr, "%s: fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
223 HDfprintf(stderr, "%s: fspace->sect_size = %Hu\n", FUNC, fspace->sect_size);
224 HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu\n", FUNC, fspace->alloc_sect_size);
225 HDfprintf(stderr, "%s: fspace->sinfo = %p\n", FUNC, fspace->sinfo);
226 HDfprintf(stderr, "%s: fspace->rc = %u\n", FUNC, fspace->rc);
227 #endif /* H5FS_DEBUG */
228 
229     /* Increment the reference count on the free space manager header */
230     HDassert(fspace->rc <= 1);
231     if(H5FS_incr(fspace) < 0)
232         HGOTO_ERROR(H5E_FSPACE, H5E_CANTINC, NULL, "unable to increment ref. count on free space header")
233 
234     fspace->alignment = alignment;
235     fspace->threshold = threshold;
236 
237     /* Unlock free space header */
238     if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__NO_FLAGS_SET) < 0)
239         HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, NULL, "unable to release free space header")
240 
241     /* Set return value */
242     ret_value = fspace;
243 
244 done:
245     FUNC_LEAVE_NOAPI(ret_value)
246 } /* H5FS_open() */
247 
248 
249 /*-------------------------------------------------------------------------
250  * Function:	H5FS_delete
251  *
252  * Purpose:	Delete a free space manager on disk
253  *
254  * Return:	Success:	non-negative
255  *
256  *		Failure:	negative
257  *
258  * Programmer:	Quincey Koziol
259  *              Tuesday, May 30, 2006
260  *
261  *-------------------------------------------------------------------------
262  */
263 herr_t
H5FS_delete(H5F_t * f,hid_t dxpl_id,haddr_t fs_addr)264 H5FS_delete(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr)
265 {
266     H5FS_t *fspace = NULL;              /* Free space header loaded from file */
267     H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
268     herr_t ret_value = SUCCEED;         /* Return value */
269 
270     FUNC_ENTER_NOAPI(FAIL)
271 #ifdef H5FS_DEBUG
272 HDfprintf(stderr, "%s: Deleting free space manager, fs_addr = %a\n", FUNC, fs_addr);
273 #endif /* H5FS_DEBUG */
274 
275     /* Check arguments. */
276     HDassert(f);
277     HDassert(H5F_addr_defined(fs_addr));
278 
279     /* Initialize user data for protecting the free space manager */
280     /* (no class information necessary for delete) */
281     cache_udata.f = f;
282     cache_udata.nclasses = 0;
283     cache_udata.classes = NULL;
284     cache_udata.cls_init_udata = NULL;
285     cache_udata.addr = fs_addr;
286 
287     /* Protect the free space header */
288     if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC_WRITE)))
289         HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space header")
290 
291     /* Sanity check */
292     HDassert(fspace->sinfo == NULL);
293 
294     /* Delete serialized section storage, if there are any */
295 #ifdef H5FS_DEBUG
296 HDfprintf(stderr, "%s: fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
297 #endif /* H5FS_DEBUG */
298     if(fspace->serial_sect_count > 0) {
299         unsigned sinfo_status = 0;      /* Free space section info's status in the metadata cache */
300 
301         /* Sanity check */
302         HDassert(H5F_addr_defined(fspace->sect_addr));
303         HDassert(fspace->alloc_sect_size > 0);
304 
305         /* Check the free space section info's status in the metadata cache */
306         if(H5AC_get_entry_status(f, fspace->sect_addr, &sinfo_status) < 0)
307             HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for free space section info")
308 
309         /* If the free space section info is in the cache, expunge it now */
310         if(sinfo_status & H5AC_ES__IN_CACHE) {
311             /* Sanity checks on direct block */
312             HDassert(!(sinfo_status & H5AC_ES__IS_PINNED));
313             HDassert(!(sinfo_status & H5AC_ES__IS_PROTECTED));
314 
315 #ifdef H5FS_DEBUG
316 HDfprintf(stderr, "%s: Expunging free space section info from cache\n", FUNC);
317 #endif /* H5FS_DEBUG */
318             /* Evict the free space section info from the metadata cache */
319             /* (Free file space) */
320             if(H5AC_expunge_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, H5AC__FREE_FILE_SPACE_FLAG) < 0)
321                 HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove free space section info from cache")
322 #ifdef H5FS_DEBUG
323 HDfprintf(stderr, "%s: Done expunging free space section info from cache\n", FUNC);
324 #endif /* H5FS_DEBUG */
325         } /* end if */
326         else {
327             /* Release the space in the file */
328             if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_addr, fspace->alloc_sect_size) < 0)
329                 HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space sections")
330         } /* end else */
331     } /* end if */
332 
333 done:
334     if(fspace && H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
335         HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space header")
336 
337     FUNC_LEAVE_NOAPI(ret_value)
338 } /* H5FS_delete() */
339 
340 
341 /*-------------------------------------------------------------------------
342  * Function:	H5FS_close
343  *
344  * Purpose:	Destroy & deallocate free list structure, serializing sections
345  *              in the bins
346  *
347  * Return:	Success:	non-negative
348  *
349  *		Failure:	negative
350  *
351  * Programmer:	Quincey Koziol
352  *              Tuesday, March  7, 2006
353  *
354  *-------------------------------------------------------------------------
355  */
356 herr_t
H5FS_close(H5F_t * f,hid_t dxpl_id,H5FS_t * fspace)357 H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace)
358 {
359     herr_t ret_value = SUCCEED;         /* Return value */
360 
361     FUNC_ENTER_NOAPI(FAIL)
362 
363     /* Check arguments. */
364     HDassert(f);
365     HDassert(fspace);
366 #ifdef H5FS_DEBUG
367 HDfprintf(stderr, "%s: Entering, fspace = %p, fspace->addr = %a, fspace->sinfo = %p\n", FUNC, fspace, fspace->addr, fspace->sinfo);
368 #endif /* H5FS_DEBUG */
369 
370     /* Check if section info is valid */
371     /* (i.e. the header "owns" the section info and it's not in the cache) */
372     if(fspace->sinfo) {
373 #ifdef H5FS_DEBUG
374 HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu, fspace->serial_sect_count = %Hu, fspace->sect_addr = %a, fspace->rc = %u\n", FUNC, fspace->tot_sect_count, fspace->serial_sect_count, fspace->sect_addr, fspace->rc);
375 HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n", FUNC, fspace->alloc_sect_size, fspace->sect_size);
376 #endif /* H5FS_DEBUG */
377         /* If there are sections to serialize, update them */
378         /* (if the free space manager is persistant) */
379         if(fspace->serial_sect_count > 0 && H5F_addr_defined(fspace->addr)) {
380 #ifdef H5FS_DEBUG
381 HDfprintf(stderr, "%s: Real sections to store in file\n", FUNC);
382 #endif /* H5FS_DEBUG */
383             if(fspace->sinfo->dirty) {
384                 /* Check if the section info is "floating" */
385                 if(!H5F_addr_defined(fspace->sect_addr)) {
386                     /* Sanity check */
387                     HDassert(fspace->sect_size > 0);
388 
389                     /* Allocate space for the section info in file */
390                     if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
391                         HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
392                     fspace->alloc_sect_size = (size_t)fspace->sect_size;
393 
394                     /* Mark free space header as dirty */
395                     if(H5AC_mark_entry_dirty(fspace) < 0)
396                         HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
397                 } /* end if */
398             } /* end if */
399 	    else
400 		/* Sanity check that section info has address */
401 		HDassert(H5F_addr_defined(fspace->sect_addr));
402 
403             /* Cache the free space section info */
404             if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
405                 HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache")
406         } /* end if */
407         else {
408 #ifdef H5FS_DEBUG
409 HDfprintf(stderr, "%s: NOT storing section info in file\n", FUNC);
410 #endif /* H5FS_DEBUG */
411             /* Check if space for the section info is allocated */
412             if(H5F_addr_defined(fspace->sect_addr)) {
413                 /* Sanity check */
414                 /* (section info should only be in the file if the header is */
415                 HDassert(H5F_addr_defined(fspace->addr));
416 
417 #ifdef H5FS_DEBUG
418 HDfprintf(stderr, "%s: Section info allocated though\n", FUNC);
419 #endif /* H5FS_DEBUG */
420                 /* Check if the section info is for the free space in the file */
421                 /* (NOTE: This is the "bootstrapping" special case for the
422                  *      free space manager, to avoid freeing the space for the
423                  *      section info and re-creating it as a section in the
424                  *      manager. -QAK)
425                  */
426                 if(fspace->client == H5FS_CLIENT_FILE_ID) {
427                     htri_t status;          /* "can absorb" status for section into */
428 
429 #ifdef H5FS_DEBUG
430 HDfprintf(stderr, "%s: Section info is for file free space\n", FUNC);
431 #endif /* H5FS_DEBUG */
432                     /* Try to shrink the file or absorb the section info into a block aggregator */
433                     if((status = H5MF_try_shrink(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_addr, fspace->alloc_sect_size)) < 0)
434                         HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for absorbing section info")
435                     else if(status == FALSE) {
436                         /* Section info can't "go away", but it's free.  Allow
437                          *      header to record it
438                          */
439 #ifdef H5FS_DEBUG
440 HDfprintf(stderr, "%s: Section info can't 'go away', header will own it\n", FUNC);
441 #endif /* H5FS_DEBUG */
442                     } /* end if */
443                     else {
444 #ifdef H5FS_DEBUG
445 HDfprintf(stderr, "%s: Section info went 'go away'\n", FUNC);
446 #endif /* H5FS_DEBUG */
447                         /* Reset section info in header */
448                         fspace->sect_addr = HADDR_UNDEF;
449                         fspace->alloc_sect_size = 0;
450 
451                         /* Mark free space header as dirty */
452                         if(H5AC_mark_entry_dirty(fspace) < 0)
453                             HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
454                     } /* end else */
455                 } /* end if */
456                 else {
457                     haddr_t old_sect_addr = fspace->sect_addr;   /* Previous location of section info in file */
458                     hsize_t old_alloc_sect_size = fspace->alloc_sect_size;       /* Previous size of section info in file */
459 
460 #ifdef H5FS_DEBUG
461 HDfprintf(stderr, "%s: Section info is NOT for file free space\n", FUNC);
462 #endif /* H5FS_DEBUG */
463                     /* Reset section info in header */
464                     fspace->sect_addr = HADDR_UNDEF;
465                     fspace->alloc_sect_size = 0;
466 
467                     /* Mark free space header as dirty */
468                     if(H5AC_mark_entry_dirty(fspace) < 0)
469                         HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
470 
471                     /* Free previous serialized sections disk space */
472                     if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, old_sect_addr, old_alloc_sect_size) < 0)
473                         HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections")
474                 } /* end if */
475             } /* end else */
476 
477             /* Destroy section info */
478             if(H5FS_sinfo_dest(fspace->sinfo) < 0)
479                 HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space section info")
480         } /* end else */
481 
482         /* Reset the header's pointer to the section info */
483         fspace->sinfo = NULL;
484     } /* end if */
485     else {
486         /* Just sanity checks... */
487         if(fspace->serial_sect_count > 0)
488             /* Sanity check that section info has address */
489             HDassert(H5F_addr_defined(fspace->sect_addr));
490         else
491             /* Sanity check that section info doesn't have address */
492             HDassert(!H5F_addr_defined(fspace->sect_addr));
493     } /* end else */
494 
495     /* Decrement the reference count on the free space manager header */
496     if(H5FS_decr(fspace) < 0)
497         HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header")
498 
499 done:
500 #ifdef H5FS_DEBUG
501 HDfprintf(stderr, "%s: Leaving, ret_value = %d, fspace->rc = %u\n", FUNC, ret_value, fspace->rc);
502 #endif /* H5FS_DEBUG */
503     FUNC_LEAVE_NOAPI(ret_value)
504 } /* H5FS_close() */
505 
506 
507 /*-------------------------------------------------------------------------
508  * Function:	H5FS_new
509  *
510  * Purpose:	Create new free space manager structure
511  *
512  * Return:	Success:	non-NULL, pointer to new free space manager struct
513  *		Failure:	NULL
514  *
515  * Programmer:	Quincey Koziol
516  *              Monday, July 31, 2006
517  *
518  *-------------------------------------------------------------------------
519  */
520 H5FS_t *
H5FS_new(const H5F_t * f,size_t nclasses,const H5FS_section_class_t * classes[],void * cls_init_udata)521 H5FS_new(const H5F_t *f, size_t nclasses, const H5FS_section_class_t *classes[],
522     void *cls_init_udata)
523 {
524     H5FS_t *fspace = NULL;      /* Free space manager */
525     size_t u;                   /* Local index variable */
526     H5FS_t *ret_value;          /* Return value */
527 
528     FUNC_ENTER_NOAPI_NOINIT
529 
530     /* Check arguments. */
531     HDassert(nclasses == 0 || (nclasses > 0 && classes));
532 
533     /*
534      * Allocate free space structure
535      */
536     if(NULL == (fspace = H5FL_CALLOC(H5FS_t)))
537 	HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list")
538 
539     /* Set immutable free list parameters */
540     fspace->nclasses = nclasses;
541     if(nclasses > 0) {
542         if(NULL == (fspace->sect_cls = H5FL_SEQ_MALLOC(H5FS_section_class_t, nclasses)))
543             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space section class array")
544 
545         /* Initialize the section classes for this free space list */
546         for(u = 0; u < nclasses; u++) {
547             /* Make certain that section class type can be used as an array index into this array */
548             HDassert(u == classes[u]->type);
549 
550             /* Copy the class information into the free space manager */
551             HDmemcpy(&fspace->sect_cls[u], classes[u], sizeof(H5FS_section_class_t));
552 
553             /* Call the class initialization routine, if there is one */
554             if(fspace->sect_cls[u].init_cls)
555                 if((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0)
556                     HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "unable to initialize section class")
557 
558             /* Determine maximum class-specific serialization size for each section */
559             if(fspace->sect_cls[u].serial_size > fspace->max_cls_serial_size)
560                 fspace->max_cls_serial_size = fspace->sect_cls[u].serial_size;
561         } /* end for */
562     } /* end if */
563 
564     /* Initialize non-zero information for new free space manager */
565     fspace->addr = HADDR_UNDEF;
566     fspace->hdr_size = H5FS_HEADER_SIZE(f);
567     fspace->sect_addr = HADDR_UNDEF;
568 
569     /* Set return value */
570     ret_value = fspace;
571 
572 done:
573     if(!ret_value)
574         if(fspace) {
575             /* Should probably call the class 'term' callback for all classes
576              *  that have had their 'init' callback called... -QAK
577              */
578             if(fspace->sect_cls)
579                 fspace->sect_cls = (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
580             fspace = H5FL_FREE(H5FS_t, fspace);
581         } /* end if */
582 
583     FUNC_LEAVE_NOAPI(ret_value)
584 } /* H5FS_new() */
585 
586 
587 /*-------------------------------------------------------------------------
588  * Function:    H5FS_size
589  *
590  * Purpose:     Collect meta storage info used by the free space manager
591  *
592  * Return:      Success:        non-negative
593  *              Failure:        negative
594  *
595  * Programmer:  Vailin Choi
596  *              June 19, 2007
597  *
598  *-------------------------------------------------------------------------
599  */
600 herr_t
H5FS_size(const H5F_t * f,const H5FS_t * fspace,hsize_t * meta_size)601 H5FS_size(const H5F_t *f, const H5FS_t *fspace, hsize_t *meta_size)
602 {
603     FUNC_ENTER_NOAPI_NOINIT_NOERR
604 
605     /*
606      * Check arguments.
607      */
608     HDassert(f);
609     HDassert(fspace);
610     HDassert(meta_size);
611 
612     /* Get the free space size info */
613     *meta_size += fspace->hdr_size + (fspace->sinfo ? fspace->sect_size : fspace->alloc_sect_size);
614 
615     FUNC_LEAVE_NOAPI(SUCCEED)
616 } /* end H5FS_size() */
617 
618 
619 /*-------------------------------------------------------------------------
620  * Function:    H5FS_incr
621  *
622  * Purpose:     Increment reference count on free space header
623  *
624  * Return:      Success:        non-negative
625  *              Failure:        negative
626  *
627  * Programmer:  Quincey Koziol
628  *              February  7, 2008
629  *
630  *-------------------------------------------------------------------------
631  */
632 herr_t
H5FS_incr(H5FS_t * fspace)633 H5FS_incr(H5FS_t *fspace)
634 {
635     herr_t ret_value = SUCCEED;         /* Return value */
636 
637     FUNC_ENTER_NOAPI(FAIL)
638 #ifdef H5FS_DEBUG
639 HDfprintf(stderr, "%s: Entering, fpace->addr = %a, fspace->rc = %u\n", FUNC, fspace->addr, fspace->rc);
640 #endif /* H5FS_DEBUG */
641 
642     /*
643      * Check arguments.
644      */
645     HDassert(fspace);
646 
647     /* Check if we should pin the header in the cache */
648     if(fspace->rc == 0 && H5F_addr_defined(fspace->addr))
649         if(H5AC_pin_protected_entry(fspace) < 0)
650             HGOTO_ERROR(H5E_FSPACE, H5E_CANTPIN, FAIL, "unable to pin free space header")
651 
652     /* Increment reference count on header */
653     fspace->rc++;
654 
655 done:
656     FUNC_LEAVE_NOAPI(ret_value)
657 } /* end H5FS_incr() */
658 
659 
660 /*-------------------------------------------------------------------------
661  * Function:    H5FS_decr
662  *
663  * Purpose:     Decrement reference count on free space header
664  *
665  * Return:      Success:        non-negative
666  *              Failure:        negative
667  *
668  * Programmer:  Quincey Koziol
669  *              February  7, 2008
670  *
671  *-------------------------------------------------------------------------
672  */
673 herr_t
H5FS_decr(H5FS_t * fspace)674 H5FS_decr(H5FS_t *fspace)
675 {
676     herr_t ret_value = SUCCEED;         /* Return value */
677 
678     FUNC_ENTER_NOAPI(FAIL)
679 #ifdef H5FS_DEBUG
680 HDfprintf(stderr, "%s: Entering, fpace->addr = %a, fspace->rc = %u\n", FUNC, fspace->addr, fspace->rc);
681 #endif /* H5FS_DEBUG */
682 
683     /*
684      * Check arguments.
685      */
686     HDassert(fspace);
687 
688     /* Decrement reference count on header */
689     fspace->rc--;
690 
691     /* Check if we should unpin the header in the cache */
692     if(fspace->rc == 0) {
693         if(H5F_addr_defined(fspace->addr)) {
694             if(H5AC_unpin_entry(fspace) < 0)
695                 HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin free space header")
696         } /* end if */
697         else {
698             if(H5FS_hdr_dest(fspace) < 0)
699                 HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space header")
700         } /* end else */
701     } /* end if */
702 
703 done:
704     FUNC_LEAVE_NOAPI(ret_value)
705 } /* end H5FS_decr() */
706 
707 
708 /*-------------------------------------------------------------------------
709  * Function:	H5FS_dirty
710  *
711  * Purpose:	Mark free space header as dirty
712  *
713  * Return:	Non-negative on success/Negative on failure
714  *
715  * Programmer:	Quincey Koziol
716  *		koziol@hdfgroup.org
717  *		Feb 14 2008
718  *
719  *-------------------------------------------------------------------------
720  */
721 herr_t
H5FS_dirty(H5FS_t * fspace)722 H5FS_dirty(H5FS_t *fspace)
723 {
724     herr_t ret_value = SUCCEED;         /* Return value */
725 
726     FUNC_ENTER_NOAPI_NOINIT
727 #ifdef QAK
728 HDfprintf(stderr, "%s: Marking free space header as dirty\n", FUNC);
729 #endif /* QAK */
730 
731     /* Sanity check */
732     HDassert(fspace);
733 
734     /* Check if the free space manager is persistant */
735     if(H5F_addr_defined(fspace->addr))
736         /* Mark header as dirty in cache */
737         if(H5AC_mark_entry_dirty(fspace) < 0)
738             HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
739 
740 done:
741     FUNC_LEAVE_NOAPI(ret_value)
742 } /* end H5FS_dirty() */
743 
744 
745 /*-------------------------------------------------------------------------
746  * Function:	H5FS_hdr_dest
747  *
748  * Purpose:	Destroys a free space header in memory.
749  *
750  * Return:	Non-negative on success/Negative on failure
751  *
752  * Programmer:	Quincey Koziol
753  *		koziol@ncsa.uiuc.edu
754  *		May  2 2006
755  *
756  *-------------------------------------------------------------------------
757  */
758 herr_t
H5FS_hdr_dest(H5FS_t * fspace)759 H5FS_hdr_dest(H5FS_t *fspace)
760 {
761     unsigned u;                 /* Local index variable */
762     herr_t ret_value = SUCCEED; /* Return value */
763 
764     FUNC_ENTER_NOAPI_NOINIT
765 
766     /*
767      * Check arguments.
768      */
769     HDassert(fspace);
770 
771     /* Terminate the section classes for this free space list */
772     for(u = 0; u < fspace->nclasses ; u++) {
773         /* Call the class termination routine, if there is one */
774         if(fspace->sect_cls[u].term_cls)
775             if((fspace->sect_cls[u].term_cls)(&fspace->sect_cls[u]) < 0)
776                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "unable to finalize section class")
777     } /* end for */
778 
779     /* Release the memory for the free space section classes */
780     if(fspace->sect_cls)
781         fspace->sect_cls = (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
782 
783     /* Free free space info */
784     fspace = H5FL_FREE(H5FS_t, fspace);
785 
786 done:
787     FUNC_LEAVE_NOAPI(ret_value)
788 } /* end H5FS_hdr_dest() */
789 
790 
791 /*-------------------------------------------------------------------------
792  * Function:	H5FS_sinfo_free_sect_cb
793  *
794  * Purpose:	Free a size-tracking node for a bin
795  *
796  * Return:	Success:	non-negative
797  *		Failure:	negative
798  *
799  * Programmer:	Quincey Koziol
800  *              Saturday, March 11, 2006
801  *
802  *-------------------------------------------------------------------------
803  */
804 static herr_t
H5FS_sinfo_free_sect_cb(void * _sect,void UNUSED * key,void * op_data)805 H5FS_sinfo_free_sect_cb(void *_sect, void UNUSED *key, void *op_data)
806 {
807     H5FS_section_info_t *sect = (H5FS_section_info_t *)_sect;   /* Section to free */
808     const H5FS_sinfo_t *sinfo = (const H5FS_sinfo_t *)op_data;     /* Free space manager for section */
809 
810     FUNC_ENTER_NOAPI_NOINIT_NOERR
811 
812     HDassert(sect);
813     HDassert(sinfo);
814 
815     /* Call the section's class 'free' method on the section */
816     (*sinfo->fspace->sect_cls[sect->type].free)(sect);
817 
818     FUNC_LEAVE_NOAPI(0)
819 }   /* H5FS_sinfo_free_sect_cb() */
820 
821 
822 /*-------------------------------------------------------------------------
823  * Function:	H5FS_sinfo_free_node_cb
824  *
825  * Purpose:	Free a size-tracking node for a bin
826  *
827  * Return:	Success:	non-negative
828  *
829  *		Failure:	negative
830  *
831  * Programmer:	Quincey Koziol
832  *              Saturday, March 11, 2006
833  *
834  *-------------------------------------------------------------------------
835  */
836 static herr_t
H5FS_sinfo_free_node_cb(void * item,void UNUSED * key,void * op_data)837 H5FS_sinfo_free_node_cb(void *item, void UNUSED *key, void *op_data)
838 {
839     H5FS_node_t *fspace_node = (H5FS_node_t *)item;       /* Temporary pointer to free space list node */
840 
841     FUNC_ENTER_NOAPI_NOINIT_NOERR
842 
843     HDassert(fspace_node);
844     HDassert(op_data);
845 
846     /* Release the skip list for sections of this size */
847     H5SL_destroy(fspace_node->sect_list, H5FS_sinfo_free_sect_cb, op_data);
848 
849     /* Release free space list node */
850     fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
851 
852     FUNC_LEAVE_NOAPI(0)
853 }   /* H5FS_sinfo_free_node_cb() */
854 
855 
856 /*-------------------------------------------------------------------------
857  * Function:	H5FS_sinfo_dest
858  *
859  * Purpose:	Destroys a free space section info in memory.
860  *
861  * Return:	Non-negative on success/Negative on failure
862  *
863  * Programmer:	Quincey Koziol
864  *		koziol@ncsa.uiuc.edu
865  *		July 31 2006
866  *
867  *-------------------------------------------------------------------------
868  */
869 herr_t
H5FS_sinfo_dest(H5FS_sinfo_t * sinfo)870 H5FS_sinfo_dest(H5FS_sinfo_t *sinfo)
871 {
872     unsigned u;                 /* Local index variable */
873     herr_t ret_value = SUCCEED; /* Return value */
874 
875     FUNC_ENTER_NOAPI_NOINIT
876 
877     /*
878      * Check arguments.
879      */
880     HDassert(sinfo);
881     HDassert(sinfo->fspace);
882     HDassert(sinfo->bins);
883 
884     /* Clear out lists of nodes */
885     for(u = 0; u < sinfo->nbins; u++)
886         if(sinfo->bins[u].bin_list) {
887             H5SL_destroy(sinfo->bins[u].bin_list, H5FS_sinfo_free_node_cb, sinfo);
888             sinfo->bins[u].bin_list = NULL;
889         } /* end if */
890 
891     /* Release bins for skip lists */
892     sinfo->bins = H5FL_SEQ_FREE(H5FS_bin_t, sinfo->bins);
893 
894     /* Release skip list for merging sections */
895     if(sinfo->merge_list)
896         if(H5SL_close(sinfo->merge_list) < 0)
897             HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy section merging skip list")
898 
899     /* Decrement the reference count on free space header */
900     /* (make certain this is last action with section info, to allow for header
901      *  disappearing immediately)
902      */
903     sinfo->fspace->sinfo = NULL;
904     if(H5FS_decr(sinfo->fspace) < 0)
905         HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header")
906     sinfo->fspace = NULL;
907 
908     /* Release free space section info */
909     sinfo = H5FL_FREE(H5FS_sinfo_t, sinfo);
910 
911 done:
912     FUNC_LEAVE_NOAPI(ret_value)
913 } /* end H5FS_sinfo_dest() */
914 
915 #ifdef H5FS_DEBUG_ASSERT
916 
917 /*-------------------------------------------------------------------------
918  * Function:	H5FS_assert
919  *
920  * Purpose:	Verify that the free space manager is mostly sane
921  *
922  * Return:	Non-negative on success, negative on failure
923  *
924  * Programmer:	Quincey Koziol
925  *		koziol@hdfgroup.org
926  *		Jul 17 2006
927  *
928  *-------------------------------------------------------------------------
929  */
930 herr_t
H5FS_assert(const H5FS_t * fspace)931 H5FS_assert(const H5FS_t *fspace)
932 {
933     FUNC_ENTER_NOAPI_NOINIT_NOERR
934 #ifndef QAK
935 HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", "H5FS_assert", fspace->tot_sect_count);
936 #endif /* QAK */
937 
938     /* Checks for section info, if it's available */
939     if(fspace->sinfo) {
940         /* Sanity check sections */
941         H5FS_sect_assert(fspace);
942 
943         /* General assumptions about the section size counts */
944         HDassert(fspace->sinfo->tot_size_count >= fspace->sinfo->serial_size_count);
945         HDassert(fspace->sinfo->tot_size_count >= fspace->sinfo->ghost_size_count);
946     } /* end if */
947 
948     /* General assumptions about the section counts */
949     HDassert(fspace->tot_sect_count >= fspace->serial_sect_count);
950     HDassert(fspace->tot_sect_count >= fspace->ghost_sect_count);
951     HDassert(fspace->tot_sect_count == (fspace->serial_sect_count + fspace->ghost_sect_count));
952 #ifdef QAK
953     HDassert(fspace->serial_sect_count > 0 || fspace->ghost_sect_count == 0);
954 #endif /* QAK */
955 
956     FUNC_LEAVE_NOAPI(SUCCEED)
957 } /* end H5FS_assert() */
958 #endif /* H5FS_DEBUG_ASSERT */
959