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:             H5MF.c
19  *                      Jul 11 1997
20  *                      Robb Matzke <matzke@llnl.gov>
21  *
22  * Purpose:             File memory management functions.
23  *
24  *-------------------------------------------------------------------------
25  */
26 
27 /****************/
28 /* Module Setup */
29 /****************/
30 
31 #define H5F_PACKAGE		/*suppress error about including H5Fpkg	  */
32 #define H5MF_PACKAGE		/*suppress error about including H5MFpkg  */
33 
34 
35 /***********/
36 /* Headers */
37 /***********/
38 #include "H5private.h"		/* Generic Functions			*/
39 #include "H5Eprivate.h"		/* Error handling		  	*/
40 #include "H5Fpkg.h"             /* File access				*/
41 #include "H5MFpkg.h"		/* File memory management		*/
42 #include "H5VMprivate.h"		/* Vectors and arrays 			*/
43 
44 
45 /****************/
46 /* Local Macros */
47 /****************/
48 
49 #define H5MF_FSPACE_SHRINK      80              /* Percent of "normal" size to shrink serialized free space size */
50 #define H5MF_FSPACE_EXPAND      120             /* Percent of "normal" size to expand serialized free space size */
51 
52 /* Map an allocation request type to a free list */
53 #define H5MF_ALLOC_TO_FS_TYPE(F, T)      ((H5FD_MEM_DEFAULT == (F)->shared->fs_type_map[T]) \
54     ? (T) : (F)->shared->fs_type_map[T])
55 
56 
57 /******************/
58 /* Local Typedefs */
59 /******************/
60 
61 /* Enum for kind of free space section+aggregator merging allowed for a file */
62 typedef enum {
63     H5MF_AGGR_MERGE_SEPARATE,           /* Everything in separate free list */
64     H5MF_AGGR_MERGE_DICHOTOMY,          /* Metadata in one free list and raw data in another */
65     H5MF_AGGR_MERGE_TOGETHER            /* Metadata & raw data in one free list */
66 } H5MF_aggr_merge_t;
67 
68 
69 /********************/
70 /* Package Typedefs */
71 /********************/
72 
73 
74 /********************/
75 /* Local Prototypes */
76 /********************/
77 
78 /* Allocator routines */
79 static herr_t H5MF_alloc_create(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type);
80 static herr_t H5MF_alloc_close(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type);
81 
82 
83 /*********************/
84 /* Package Variables */
85 /*********************/
86 
87 
88 /*****************************/
89 /* Library Private Variables */
90 /*****************************/
91 
92 
93 /*******************/
94 /* Local Variables */
95 /*******************/
96 
97 
98 /*-------------------------------------------------------------------------
99  * Function:    H5MF_init_merge_flags
100  *
101  * Purpose:     Initialize the free space section+aggregator merge flags
102  *              for the file.
103  *
104  * Return:	SUCCEED/FAIL
105  *
106  * Programmer:  Quincey Koziol
107  *              Friday, February  1, 2008
108  *
109  *-------------------------------------------------------------------------
110  */
111 herr_t
H5MF_init_merge_flags(H5F_t * f)112 H5MF_init_merge_flags(H5F_t *f)
113 {
114     H5MF_aggr_merge_t mapping_type;     /* Type of free list mapping */
115     H5FD_mem_t type;                    /* Memory type for iteration */
116     hbool_t all_same;                   /* Whether all the types map to the same value */
117     herr_t ret_value = SUCCEED;        	/* Return value */
118 
119     FUNC_ENTER_NOAPI(FAIL)
120 
121     /* check args */
122     HDassert(f);
123     HDassert(f->shared);
124     HDassert(f->shared->lf);
125 
126     /* Iterate over all the free space types to determine if sections of that type
127      *  can merge with the metadata or small 'raw' data aggregator
128      */
129     all_same = TRUE;
130     for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
131         /* Check for any different type mappings */
132         if(f->shared->fs_type_map[type] != f->shared->fs_type_map[H5FD_MEM_DEFAULT]) {
133             all_same = FALSE;
134             break;
135         } /* end if */
136 
137     /* Check for all allocation types mapping to the same free list type */
138     if(all_same) {
139         if(f->shared->fs_type_map[H5FD_MEM_DEFAULT] == H5FD_MEM_DEFAULT)
140             mapping_type = H5MF_AGGR_MERGE_SEPARATE;
141         else
142             mapping_type = H5MF_AGGR_MERGE_TOGETHER;
143     } /* end if */
144     else {
145         /* Check for raw data mapping into same list as metadata */
146         if(f->shared->fs_type_map[H5FD_MEM_DRAW] == f->shared->fs_type_map[H5FD_MEM_SUPER])
147             mapping_type = H5MF_AGGR_MERGE_SEPARATE;
148         else {
149             hbool_t all_metadata_same;              /* Whether all metadata go in same free list */
150 
151             /* One or more allocation type don't map to the same free list type */
152             /* Check if all the metadata allocation types map to the same type */
153             all_metadata_same = TRUE;
154             for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
155                 /* Skip checking raw data free list mapping */
156                 /* (global heap is treated as raw data) */
157                 if(type != H5FD_MEM_DRAW && type != H5FD_MEM_GHEAP) {
158                     /* Check for any different type mappings */
159                     if(f->shared->fs_type_map[type] != f->shared->fs_type_map[H5FD_MEM_SUPER]) {
160                         all_metadata_same = FALSE;
161                         break;
162                     } /* end if */
163                 } /* end if */
164 
165             /* Check for all metadata on same free list */
166             if(all_metadata_same)
167                 mapping_type = H5MF_AGGR_MERGE_DICHOTOMY;
168             else
169                 mapping_type = H5MF_AGGR_MERGE_SEPARATE;
170         } /* end else */
171     } /* end else */
172 
173     /* Based on mapping type, initialize merging flags for each free list type */
174     switch(mapping_type) {
175         case H5MF_AGGR_MERGE_SEPARATE:
176             /* Don't merge any metadata together */
177             HDmemset(f->shared->fs_aggr_merge, 0, sizeof(f->shared->fs_aggr_merge));
178 
179             /* Check if merging raw data should be allowed */
180             /* (treat global heaps as raw data) */
181             if(H5FD_MEM_DRAW == f->shared->fs_type_map[H5FD_MEM_DRAW] ||
182                     H5FD_MEM_DEFAULT == f->shared->fs_type_map[H5FD_MEM_DRAW]) {
183                 f->shared->fs_aggr_merge[H5FD_MEM_DRAW] = H5F_FS_MERGE_RAWDATA;
184                 f->shared->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA;
185 	    } /* end if */
186             break;
187 
188         case H5MF_AGGR_MERGE_DICHOTOMY:
189             /* Merge all metadata together (but not raw data) */
190             HDmemset(f->shared->fs_aggr_merge, H5F_FS_MERGE_METADATA, sizeof(f->shared->fs_aggr_merge));
191 
192             /* Allow merging raw data allocations together */
193             /* (treat global heaps as raw data) */
194             f->shared->fs_aggr_merge[H5FD_MEM_DRAW] = H5F_FS_MERGE_RAWDATA;
195             f->shared->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA;
196             break;
197 
198         case H5MF_AGGR_MERGE_TOGETHER:
199             /* Merge all allocation types together */
200             HDmemset(f->shared->fs_aggr_merge, (H5F_FS_MERGE_METADATA | H5F_FS_MERGE_RAWDATA), sizeof(f->shared->fs_aggr_merge));
201             break;
202 
203         default:
204             HGOTO_ERROR(H5E_RESOURCE, H5E_BADVALUE, FAIL, "invalid mapping type")
205     } /* end switch */
206 
207 done:
208     FUNC_LEAVE_NOAPI(ret_value)
209 } /* end H5MF_init_merge_flags() */
210 
211 
212 /*-------------------------------------------------------------------------
213  * Function:	H5MF_alloc_open
214  *
215  * Purpose:	Open an existing free space manager of TYPE for file by
216  *		creating a free-space structure
217  *
218  * Return:	Success:	non-negative
219  *		Failure:	negative
220  *
221  * Programmer:	Quincey Koziol
222  *		koziol@hdfgroup.org
223  *		Jan  8 2008
224  *
225  *-------------------------------------------------------------------------
226  */
227 herr_t
H5MF_alloc_open(H5F_t * f,hid_t dxpl_id,H5FD_mem_t type)228 H5MF_alloc_open(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type)
229 {
230     const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for file */
231         H5MF_FSPACE_SECT_CLS_SIMPLE};
232     herr_t ret_value = SUCCEED;         /* Return value */
233 
234     FUNC_ENTER_NOAPI_NOINIT
235 
236     /*
237      * Check arguments.
238      */
239     HDassert(f);
240     HDassert(f->shared);
241     HDassert(type != H5FD_MEM_NOLIST);
242     HDassert(H5F_addr_defined(f->shared->fs_addr[type]));
243     HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED);
244 
245     /* Open an existing free space structure for the file */
246     if(NULL == (f->shared->fs_man[type] = H5FS_open(f, dxpl_id, f->shared->fs_addr[type],
247 	    NELMTS(classes), classes, f, f->shared->alignment, f->shared->threshold)))
248 	HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info")
249 
250     /* Set the state for the free space manager to "open", if it is now */
251     if(f->shared->fs_man[type])
252         f->shared->fs_state[type] = H5F_FS_STATE_OPEN;
253 
254 done:
255     FUNC_LEAVE_NOAPI(ret_value)
256 } /* end H5MF_alloc_open() */
257 
258 
259 /*-------------------------------------------------------------------------
260  * Function:	H5MF_alloc_create
261  *
262  * Purpose:	Create free space manager of TYPE for the file by creating
263  *		a free-space structure
264  *
265  * Return:	Success:	non-negative
266  *		Failure:	negative
267  *
268  * Programmer:	Quincey Koziol
269  *		koziol@hdfgroup.org
270  *		Jan  8 2008
271  *
272  *-------------------------------------------------------------------------
273  */
274 static herr_t
H5MF_alloc_create(H5F_t * f,hid_t dxpl_id,H5FD_mem_t type)275 H5MF_alloc_create(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type)
276 {
277     const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for file */
278         H5MF_FSPACE_SECT_CLS_SIMPLE};
279     herr_t ret_value = SUCCEED;         /* Return value */
280     H5FS_create_t fs_create; 		/* Free space creation parameters */
281 
282     FUNC_ENTER_NOAPI_NOINIT
283 
284     /*
285      * Check arguments.
286      */
287     HDassert(f);
288     HDassert(f->shared);
289     HDassert(type != H5FD_MEM_NOLIST);
290     HDassert(!H5F_addr_defined(f->shared->fs_addr[type]));
291     HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED);
292 
293     /* Set the free space creation parameters */
294     fs_create.client = H5FS_CLIENT_FILE_ID;
295     fs_create.shrink_percent = H5MF_FSPACE_SHRINK;
296     fs_create.expand_percent = H5MF_FSPACE_EXPAND;
297     fs_create.max_sect_addr = 1 + H5VM_log2_gen((uint64_t)f->shared->maxaddr);
298     fs_create.max_sect_size = f->shared->maxaddr;
299 
300     if(NULL == (f->shared->fs_man[type] = H5FS_create(f, dxpl_id, NULL,
301 	    &fs_create, NELMTS(classes), classes, f, f->shared->alignment, f->shared->threshold)))
302 	HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info")
303 
304 
305     /* Set the state for the free space manager to "open", if it is now */
306     if(f->shared->fs_man[type])
307         f->shared->fs_state[type] = H5F_FS_STATE_OPEN;
308 
309 done:
310     FUNC_LEAVE_NOAPI(ret_value)
311 } /* end H5MF_alloc_create() */
312 
313 
314 /*-------------------------------------------------------------------------
315  * Function:	H5MF_alloc_start
316  *
317  * Purpose:	Open or create a free space manager of a given type
318  *
319  * Return:	Success:	non-negative
320  *		Failure:	negative
321  *
322  * Programmer:	Quincey Koziol
323  *		koziol@hdfgroup.org
324  *		Jan  8 2008
325  *
326  *-------------------------------------------------------------------------
327  */
328 herr_t
H5MF_alloc_start(H5F_t * f,hid_t dxpl_id,H5FD_mem_t type)329 H5MF_alloc_start(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type)
330 {
331     herr_t ret_value = SUCCEED;         /* Return value */
332 
333     FUNC_ENTER_NOAPI_NOINIT
334 
335     /*
336      * Check arguments.
337      */
338     HDassert(f);
339     HDassert(f->shared);
340     HDassert(type != H5FD_MEM_NOLIST);
341 
342     /* Check if the free space manager exists already */
343     if(H5F_addr_defined(f->shared->fs_addr[type])) {
344         /* Open existing free space manager */
345         if(H5MF_alloc_open(f, dxpl_id, type) < 0)
346             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, FAIL, "can't initialize file free space")
347     } /* end if */
348     else {
349         /* Create new free space manager */
350         if(H5MF_alloc_create(f, dxpl_id, type) < 0)
351             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCREATE, FAIL, "can't initialize file free space")
352     } /* end else */
353 
354 done:
355     FUNC_LEAVE_NOAPI(ret_value)
356 } /* end H5MF_alloc_start() */
357 
358 
359 /*-------------------------------------------------------------------------
360  * Function:    H5MF_alloc_close
361  *
362  * Purpose:     Close an existing free space manager of TYPE for file
363  *
364  * Return:      Success:        non-negative
365  *              Failure:        negative
366  *
367  * Programmer: Vailin Choi; July 1st, 2009
368  *
369  *-------------------------------------------------------------------------
370  */
371 static herr_t
H5MF_alloc_close(H5F_t * f,hid_t dxpl_id,H5FD_mem_t type)372 H5MF_alloc_close(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type)
373 {
374     herr_t ret_value = SUCCEED;         /* Return value */
375 
376     FUNC_ENTER_NOAPI_NOINIT
377 
378     /*
379      * Check arguments.
380      */
381     HDassert(f);
382     HDassert(f->shared);
383     HDassert(type != H5FD_MEM_NOLIST);
384     HDassert(f->shared->fs_man[type]);
385     HDassert(f->shared->fs_state[type] != H5F_FS_STATE_CLOSED);
386 
387     /* Close an existing free space structure for the file */
388     if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0)
389         HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release free space info")
390     f->shared->fs_man[type] = NULL;
391     f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
392 
393 done:
394     FUNC_LEAVE_NOAPI(ret_value)
395 } /* end H5MF_alloc_close() */
396 
397 
398 /*-------------------------------------------------------------------------
399  * Function:    H5MF_alloc
400  *
401  * Purpose:     Allocate SIZE bytes of file memory and return the relative
402  *		address where that contiguous chunk of file memory exists.
403  *		The TYPE argument describes the purpose for which the storage
404  *		is being requested.
405  *
406  * Return:      Success:        The file address of new chunk.
407  *              Failure:        HADDR_UNDEF
408  *
409  * Programmer:  Robb Matzke
410  *              matzke@llnl.gov
411  *              Jul 11 1997
412  *
413  *-------------------------------------------------------------------------
414  */
415 haddr_t
H5MF_alloc(H5F_t * f,H5FD_mem_t alloc_type,hid_t dxpl_id,hsize_t size)416 H5MF_alloc(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size)
417 {
418     H5FD_mem_t  fs_type;                /* Free space type (mapped from allocation type) */
419     haddr_t	ret_value;              /* Return value */
420 
421     FUNC_ENTER_NOAPI(HADDR_UNDEF)
422 #ifdef H5MF_ALLOC_DEBUG
423 HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_type, size);
424 #endif /* H5MF_ALLOC_DEBUG */
425 
426     /* check arguments */
427     HDassert(f);
428     HDassert(f->shared);
429     HDassert(f->shared->lf);
430     HDassert(size > 0);
431 
432     /* Get free space type from allocation type */
433     fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type);
434 
435     /* Check if we are using the free space manager for this file */
436     if(H5F_HAVE_FREE_SPACE_MANAGER(f)) {
437         /* Check if the free space manager for the file has been initialized */
438         if(!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type]))
439             if(H5MF_alloc_open(f, dxpl_id, fs_type) < 0)
440                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, HADDR_UNDEF, "can't initialize file free space")
441 
442         /* Search for large enough space in the free space manager */
443         if(f->shared->fs_man[fs_type]) {
444             H5MF_free_section_t *node;      /* Free space section pointer */
445             htri_t node_found = FALSE;      /* Whether an existing free list node was found */
446 
447             /* Try to get a section from the free space manager */
448             if((node_found = H5FS_sect_find(f, dxpl_id, f->shared->fs_man[fs_type], size, (H5FS_section_info_t **)&node)) < 0)
449                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating free space in file")
450 #ifdef H5MF_ALLOC_DEBUG_MORE
451 HDfprintf(stderr, "%s: Check 1.5, node_found = %t\n", FUNC, node_found);
452 #endif /* H5MF_ALLOC_DEBUG_MORE */
453 
454             /* Check for actually finding section */
455             if(node_found) {
456                 /* Sanity check */
457                 HDassert(node);
458 
459                 /* Retrieve return value */
460                 ret_value = node->sect_info.addr;
461 
462                 /* Check for eliminating the section */
463                 if(node->sect_info.size == size) {
464 #ifdef H5MF_ALLOC_DEBUG_MORE
465 HDfprintf(stderr, "%s: Check 1.6, freeing node\n", FUNC);
466 #endif /* H5MF_ALLOC_DEBUG_MORE */
467                     /* Free section node */
468                     if(H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0)
469                         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, HADDR_UNDEF, "can't free simple section node")
470                 } /* end if */
471                 else {
472                     H5MF_sect_ud_t udata;               /* User data for callback */
473 
474                     /* Adjust information for section */
475                     node->sect_info.addr += size;
476                     node->sect_info.size -= size;
477 
478                     /* Construct user data for callbacks */
479                     udata.f = f;
480                     udata.dxpl_id = dxpl_id;
481                     udata.alloc_type = alloc_type;
482                     udata.allow_sect_absorb = TRUE;
483 		    udata.allow_eoa_shrink_only = FALSE;
484 
485 #ifdef H5MF_ALLOC_DEBUG_MORE
486 HDfprintf(stderr, "%s: Check 1.7, re-adding node, node->sect_info.size = %Hu\n", FUNC, node->sect_info.size);
487 #endif /* H5MF_ALLOC_DEBUG_MORE */
488                     /* Re-insert section node into file's free space */
489                     if(H5FS_sect_add(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0)
490                         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't re-add section to file free space")
491                 } /* end else */
492 
493                 /* Leave now */
494                 HGOTO_DONE(ret_value)
495             } /* end if */
496         } /* end if */
497 #ifdef H5MF_ALLOC_DEBUG_MORE
498 HDfprintf(stderr, "%s: Check 2.0\n", FUNC);
499 #endif /* H5MF_ALLOC_DEBUG_MORE */
500     } /* end if */
501 
502     /* Allocate from the metadata aggregator (or the VFD) */
503     if(HADDR_UNDEF == (ret_value = H5MF_aggr_vfd_alloc(f, alloc_type, dxpl_id, size)))
504 	HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from aggr/vfd")
505 
506 done:
507 #ifdef H5MF_ALLOC_DEBUG
508 HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", FUNC, ret_value, size);
509 #endif /* H5MF_ALLOC_DEBUG */
510 #ifdef H5MF_ALLOC_DEBUG_DUMP
511 H5MF_sects_dump(f, dxpl_id, stderr);
512 #endif /* H5MF_ALLOC_DEBUG_DUMP */
513 
514     FUNC_LEAVE_NOAPI(ret_value)
515 } /* end H5MF_alloc() */
516 
517 
518 /*-------------------------------------------------------------------------
519  * Function:    H5MF_alloc_tmp
520  *
521  * Purpose:     Allocate temporary space in the file
522  *
523  * Note:	The address returned is non-overlapping with any other address
524  *		in the file and suitable for insertion into the metadata
525  *		cache.
526  *
527  *		The address is _not_ suitable for actual file I/O and will
528  *		cause an error if it is so used.
529  *
530  *		The space allocated with this routine should _not_ be freed,
531  *		it should just be abandoned.  Calling H5MF_xfree() with space
532  *              from this routine will cause an error.
533  *
534  * Return:      Success:        Temporary file address
535  *              Failure:        HADDR_UNDEF
536  *
537  * Programmer:  Quincey Koziol
538  *              Thursday, June  4, 2009
539  *
540  *-------------------------------------------------------------------------
541  */
542 haddr_t
H5MF_alloc_tmp(H5F_t * f,hsize_t size)543 H5MF_alloc_tmp(H5F_t *f, hsize_t size)
544 {
545     haddr_t eoa;                /* End of allocated space in the file */
546     haddr_t ret_value;          /* Return value */
547 
548     FUNC_ENTER_NOAPI(HADDR_UNDEF)
549 #ifdef H5MF_ALLOC_DEBUG
550 HDfprintf(stderr, "%s: size = %Hu\n", FUNC, size);
551 #endif /* H5MF_ALLOC_DEBUG */
552 
553     /* check args */
554     HDassert(f);
555     HDassert(f->shared);
556     HDassert(f->shared->lf);
557     HDassert(size > 0);
558 
559     /* Retrieve the 'eoa' for the file */
560     if(HADDR_UNDEF == (eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
561 	HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed")
562 
563     /* Compute value to return */
564     ret_value = f->shared->tmp_addr - size;
565 
566     /* Check for overlap into the actual allocated space in the file */
567     if(H5F_addr_le(ret_value, eoa))
568 	HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed")
569 
570     /* Adjust temporary address allocator in the file */
571     f->shared->tmp_addr = ret_value;
572 
573 done:
574     FUNC_LEAVE_NOAPI(ret_value)
575 } /* end H5MF_alloc_tmp() */
576 
577 
578 /*-------------------------------------------------------------------------
579  * Function:    H5MF_xfree
580  *
581  * Purpose:     Frees part of a file, making that part of the file
582  *              available for reuse.
583  *
584  * Return:      Non-negative on success/Negative on failure
585  *
586  * Programmer:  Robb Matzke
587  *              matzke@llnl.gov
588  *              Jul 17 1997
589  *
590  *-------------------------------------------------------------------------
591  */
592 herr_t
H5MF_xfree(H5F_t * f,H5FD_mem_t alloc_type,hid_t dxpl_id,haddr_t addr,hsize_t size)593 H5MF_xfree(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr,
594     hsize_t size)
595 {
596     H5MF_free_section_t *node = NULL;   /* Free space section pointer */
597     H5MF_sect_ud_t udata;               /* User data for callback */
598     H5FD_mem_t fs_type;                 /* Free space type (mapped from allocation type) */
599     herr_t ret_value = SUCCEED;         /* Return value */
600 
601     FUNC_ENTER_NOAPI(FAIL)
602 #ifdef H5MF_ALLOC_DEBUG
603 HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size);
604 #endif /* H5MF_ALLOC_DEBUG */
605 
606     /* check arguments */
607     HDassert(f);
608     if(!H5F_addr_defined(addr) || 0 == size)
609         HGOTO_DONE(SUCCEED);
610     HDassert(addr != 0);        /* Can't deallocate the superblock :-) */
611 
612     /* Check for attempting to free space that's a 'temporary' file address */
613     if(H5F_addr_le(f->shared->tmp_addr, addr))
614         HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "attempting to free temporary file space")
615 
616     /* Check if the space to free intersects with the file's metadata accumulator */
617     if(H5F_accum_free(f, dxpl_id, alloc_type, addr, size) < 0)
618         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't check free space intersection w/metadata accumulator")
619 
620     /* Get free space type from allocation type */
621     fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type);
622 #ifdef H5MF_ALLOC_DEBUG_MORE
623 HDfprintf(stderr, "%s: fs_type = %u\n", FUNC, (unsigned)fs_type);
624 #endif /* H5MF_ALLOC_DEBUG_MORE */
625 
626     /* Check if the free space manager for the file has been initialized */
627     if(!f->shared->fs_man[fs_type]) {
628         /* If there's no free space manager for objects of this type,
629          *  see if we can avoid creating one by checking if the freed
630          *  space is at the end of the file
631          */
632 #ifdef H5MF_ALLOC_DEBUG_MORE
633 HDfprintf(stderr, "%s: f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)fs_type, f->shared->fs_addr[fs_type]);
634 #endif /* H5MF_ALLOC_DEBUG_MORE */
635         if(!H5F_addr_defined(f->shared->fs_addr[fs_type])) {
636             htri_t status;          /* "can absorb" status for section into */
637 
638 #ifdef H5MF_ALLOC_DEBUG_MORE
639 HDfprintf(stderr, "%s: Trying to avoid starting up free space manager\n", FUNC);
640 #endif /* H5MF_ALLOC_DEBUG_MORE */
641             /* Try to shrink the file or absorb the block into a block aggregator */
642             if((status = H5MF_try_shrink(f, alloc_type, dxpl_id, addr, size)) < 0)
643                 HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for absorbing block")
644             else if(status > 0)
645                 /* Indicate success */
646                 HGOTO_DONE(SUCCEED)
647         } /* end if */
648 
649         /* If we are deleting the free space manager, leave now, to avoid
650          *  [re-]starting it.
651 	 * or if file space strategy type is not using a free space manager
652 	 *   (H5F_FILE_SPACE_AGGR_VFD or H5F_FILE_SPACE_VFD), drop free space
653          *   section on the floor.
654          *
655          * Note: this drops the space to free on the floor...
656          *
657          */
658         if(f->shared->fs_state[fs_type] == H5F_FS_STATE_DELETING ||
659 	        !H5F_HAVE_FREE_SPACE_MANAGER(f)) {
660 #ifdef H5MF_ALLOC_DEBUG_MORE
661 HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", FUNC, addr, size);
662 #endif /* H5MF_ALLOC_DEBUG_MORE */
663             HGOTO_DONE(SUCCEED)
664         } /* end if */
665 
666         /* There's either already a free space manager, or the freed
667          *  space isn't at the end of the file, so start up (or create)
668          *  the file space manager
669          */
670         if(H5MF_alloc_start(f, dxpl_id, fs_type) < 0)
671             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
672     } /* end if */
673     HDassert(f->shared->fs_man[fs_type]);
674 
675     /* Create free space section for block */
676     if(NULL == (node = H5MF_sect_simple_new(addr, size)))
677         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
678 
679     /* Construct user data for callbacks */
680     udata.f = f;
681     udata.dxpl_id = dxpl_id;
682     udata.alloc_type = alloc_type;
683     udata.allow_sect_absorb = TRUE;
684     udata.allow_eoa_shrink_only = FALSE;
685 
686     /* Add to the free space for the file */
687 #ifdef H5MF_ALLOC_DEBUG_MORE
688 HDfprintf(stderr, "%s: Before H5FS_sect_add()\n", FUNC);
689 #endif /* H5MF_ALLOC_DEBUG_MORE */
690     if(H5FS_sect_add(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0)
691         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't add section to file free space")
692     node = NULL;
693 #ifdef H5MF_ALLOC_DEBUG_MORE
694 HDfprintf(stderr, "%s: After H5FS_sect_add()\n", FUNC);
695 #endif /* H5MF_ALLOC_DEBUG_MORE */
696 
697 done:
698     /* Release section node, if allocated and not added to section list or merged */
699     if(node)
700         if(H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0)
701             HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
702 
703 #ifdef H5MF_ALLOC_DEBUG
704 HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
705 #endif /* H5MF_ALLOC_DEBUG */
706 #ifdef H5MF_ALLOC_DEBUG_DUMP
707 H5MF_sects_dump(f, dxpl_id, stderr);
708 #endif /* H5MF_ALLOC_DEBUG_DUMP */
709     FUNC_LEAVE_NOAPI(ret_value)
710 } /* end H5MF_xfree() */
711 
712 
713 /*-------------------------------------------------------------------------
714  * Function:	H5MF_try_extend
715  *
716  * Purpose:	Extend a block in the file if possible.
717  *
718  * Return:	Success:	TRUE(1)  - Block was extended
719  *                              FALSE(0) - Block could not be extended
720  * 		Failure:	FAIL
721  *
722  * Programmer:	Quincey Koziol
723  *              Friday, June 11, 2004
724  *
725  *-------------------------------------------------------------------------
726  */
727 htri_t
H5MF_try_extend(H5F_t * f,hid_t dxpl_id,H5FD_mem_t alloc_type,haddr_t addr,hsize_t size,hsize_t extra_requested)728 H5MF_try_extend(H5F_t *f, hid_t dxpl_id, H5FD_mem_t alloc_type, haddr_t addr,
729     hsize_t size, hsize_t extra_requested)
730 {
731     haddr_t     end;            /* End of block to extend */
732     H5FD_mem_t  map_type;       /* Mapped type */
733     htri_t	ret_value;      /* Return value */
734 
735     FUNC_ENTER_NOAPI(FAIL)
736 #ifdef H5MF_ALLOC_DEBUG
737 HDfprintf(stderr, "%s: Entering: alloc_type = %u, addr = %a, size = %Hu, extra_requested = %Hu\n", FUNC, (unsigned)alloc_type, addr, size, extra_requested);
738 #endif /* H5MF_ALLOC_DEBUG */
739 
740     /* Sanity check */
741     HDassert(f);
742     HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
743 
744     /* Set mapped type, treating global heap as raw data */
745     map_type = (alloc_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : alloc_type;
746 
747     /* Compute end of block to extend */
748     end = addr + size;
749 
750     /* Check if the block is exactly at the end of the file */
751     if((ret_value = H5FD_try_extend(f->shared->lf, map_type, f, end, extra_requested)) < 0)
752         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file")
753     else if(ret_value == FALSE) {
754         H5F_blk_aggr_t *aggr;   /* Aggregator to use */
755 
756         /* Check for test block able to extend aggregation block */
757         aggr = (map_type == H5FD_MEM_DRAW) ?  &(f->shared->sdata_aggr) : &(f->shared->meta_aggr);
758         if((ret_value = H5MF_aggr_try_extend(f, aggr, map_type, end, extra_requested)) < 0)
759             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending aggregation block")
760         else if(ret_value == FALSE) {
761             H5FD_mem_t  fs_type;                /* Free space type (mapped from allocation type) */
762 
763             /* Get free space type from allocation type */
764             fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type);
765 
766             /* Check if the free space for the file has been initialized */
767             if(!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type]))
768                 if(H5MF_alloc_open(f, dxpl_id, fs_type) < 0)
769                     HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
770 
771             /* Check for test block able to block in free space manager */
772             if(f->shared->fs_man[fs_type])
773                 if((ret_value = H5FS_sect_try_extend(f, dxpl_id, f->shared->fs_man[fs_type], addr, size, extra_requested)) < 0)
774                     HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending block in free space manager")
775         } /* end if */
776     } /* end if */
777 
778 done:
779 #ifdef H5MF_ALLOC_DEBUG
780 HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value);
781 #endif /* H5MF_ALLOC_DEBUG */
782 #ifdef H5MF_ALLOC_DEBUG_DUMP
783 H5MF_sects_dump(f, dxpl_id, stderr);
784 #endif /* H5MF_ALLOC_DEBUG_DUMP */
785 
786     FUNC_LEAVE_NOAPI(ret_value)
787 } /* end H5MF_try_extend() */
788 
789 
790 /*-------------------------------------------------------------------------
791  * Function:    H5MF_get_freespace
792  *
793  * Purpose:     Retrieve the amount of free space in a file.
794  *
795  * Return:      Success:        Amount of free space in file
796  *              Failure:        Negative
797  *
798  * Programmer:  Quincey Koziol
799  *              Monday, October  6, 2003
800  *
801  * Modifications:
802  *      Vailin Choi; July 2012
803  *      As the default free-list mapping is changed to H5FD_FLMAP_DICHOTOMY,
804  *      checks are added to account for the last section of each free-space manager
805  *      and the remaining space in the two aggregators are at EOF.
806  *-------------------------------------------------------------------------
807  */
808 herr_t
H5MF_get_freespace(H5F_t * f,hid_t dxpl_id,hsize_t * tot_space,hsize_t * meta_size)809 H5MF_get_freespace(H5F_t *f, hid_t dxpl_id, hsize_t *tot_space, hsize_t *meta_size)
810 {
811     haddr_t eoa;                /* End of allocated space in the file */
812     haddr_t ma_addr = HADDR_UNDEF;    /* Base "metadata aggregator" address */
813     hsize_t ma_size = 0;        /* Size of "metadata aggregator" */
814     haddr_t sda_addr = HADDR_UNDEF;    /* Base "small data aggregator" address */
815     hsize_t sda_size = 0;       /* Size of "small data aggregator" */
816     hsize_t tot_fs_size = 0;    /* Amount of all free space managed */
817     hsize_t tot_meta_size = 0;  /* Amount of metadata for free space managers */
818     H5FD_mem_t type;            /* Memory type for iteration */
819     H5FD_mem_t fs_started[H5FD_MEM_NTYPES]; /* Indicate whether the free-space manager has been started */
820     hbool_t eoa_shrank;		/* Whether an EOA shrink occurs */
821     herr_t ret_value = SUCCEED; /* Return value */
822 
823     FUNC_ENTER_NOAPI(FAIL)
824 
825     /* check args */
826     HDassert(f);
827     HDassert(f->shared);
828     HDassert(f->shared->lf);
829 
830     /* Retrieve the 'eoa' for the file */
831     if(HADDR_UNDEF == (eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
832 	HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
833 
834     /* Retrieve metadata aggregator info, if available */
835     if(H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0)
836         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats")
837 
838     /* Retrieve 'small data' aggregator info, if available */
839     if(H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0)
840         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats")
841 
842     /* Iterate over all the free space types that have managers and get each free list's space */
843     for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
844 
845 	fs_started[type] = FALSE;
846 
847 	/* Check if the free space for the file has been initialized */
848         if(!f->shared->fs_man[type] && H5F_addr_defined(f->shared->fs_addr[type])) {
849             if(H5MF_alloc_open(f, dxpl_id, type) < 0)
850                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
851             HDassert(f->shared->fs_man[type]);
852             fs_started[type] = TRUE;
853         } /* end if */
854 
855 	/* Check if there's free space of this type */
856         if(f->shared->fs_man[type]) {
857             hsize_t type_fs_size = 0;    /* Amount of free space managed for each type */
858             hsize_t type_meta_size = 0;  /* Amount of free space metadata for each type */
859 
860             /* Retrieve free space size from free space manager */
861             if(H5FS_sect_stats(f->shared->fs_man[type], &type_fs_size, NULL) < 0)
862                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats")
863             if(H5FS_size(f, f->shared->fs_man[type], &type_meta_size) < 0)
864                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space metadata stats")
865 
866             /* Increment total free space for types */
867             tot_fs_size += type_fs_size;
868             tot_meta_size += type_meta_size;
869 	} /* end if */
870     } /* end for */
871 
872     /* Iterate until no more EOA shrink occurs */
873     do {
874 	eoa_shrank = FALSE;
875 
876 	/* Check the last section of each free-space manager */
877 	for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
878 	    haddr_t sect_addr = HADDR_UNDEF;
879 	    hsize_t sect_size = 0;
880 
881 	    if(f->shared->fs_man[type]) {
882 		if(H5FS_sect_query_last_sect(f->shared->fs_man[type], &sect_addr, &sect_size) < 0)
883 		    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query last section on merge list")
884 
885 		/* Deduct space from previous accumulation if the section is at EOA */
886 		if(H5F_addr_eq(sect_addr + sect_size, eoa)) {
887 		    eoa = sect_addr;
888 		    eoa_shrank = TRUE;
889 		    tot_fs_size -= sect_size;
890 		} /* end if */
891 	    } /* end if */
892 	} /* end for */
893 
894 	/* Check the metadata and raw data aggregators */
895 	if(ma_size > 0 && H5F_addr_eq(ma_addr + ma_size, eoa)) {
896 	    eoa = ma_addr;
897 	    eoa_shrank = TRUE;
898 	    ma_size = 0;
899 	} /* end if */
900 	if(sda_size > 0 && H5F_addr_eq(sda_addr + sda_size, eoa)) {
901 	    eoa = sda_addr;
902 	    eoa_shrank = TRUE;
903 	    sda_size = 0;
904 	} /* end if */
905     } while(eoa_shrank);
906 
907     /* Close the free-space managers if they were opened earlier in this routine */
908     for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
909 	if(fs_started[type])
910             if(H5MF_alloc_close(f, dxpl_id, type) < 0)
911                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space")
912     } /* end for */
913 
914     /* Set the value(s) to return */
915     /* (The metadata & small data aggregators count as free space now, since they aren't at EOA) */
916     if(tot_space)
917 	*tot_space = tot_fs_size + ma_size + sda_size;
918     if(meta_size)
919 	*meta_size = tot_meta_size;
920 
921 done:
922     FUNC_LEAVE_NOAPI(ret_value)
923 } /* end H5MF_get_freespace() */
924 
925 
926 /*-------------------------------------------------------------------------
927  * Function:    H5MF_try_shrink
928  *
929  * Purpose:     Try to shrink the size of a file with a block or absorb it
930  *              into a block aggregator.
931  *
932  * Return:      Non-negative on success/Negative on failure
933  *
934  * Programmer:  Quincey Koziol
935  *              koziol@hdfgroup.org
936  *              Feb 14 2008
937  *
938  *-------------------------------------------------------------------------
939  */
940 htri_t
H5MF_try_shrink(H5F_t * f,H5FD_mem_t alloc_type,hid_t dxpl_id,haddr_t addr,hsize_t size)941 H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr,
942     hsize_t size)
943 {
944     H5MF_free_section_t *node = NULL;   /* Free space section pointer */
945     H5MF_sect_ud_t udata;               /* User data for callback */
946     htri_t ret_value;                   /* Return value */
947 
948     FUNC_ENTER_NOAPI(FAIL)
949 #ifdef H5MF_ALLOC_DEBUG
950 HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size);
951 #endif /* H5MF_ALLOC_DEBUG */
952 
953     /* check arguments */
954     HDassert(f);
955     HDassert(f->shared);
956     HDassert(f->shared->lf);
957     HDassert(H5F_addr_defined(addr));
958     HDassert(size > 0);
959 
960     /* Create free space section for block */
961     if(NULL == (node = H5MF_sect_simple_new(addr, size)))
962         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
963 
964     /* Construct user data for callbacks */
965     udata.f = f;
966     udata.dxpl_id = dxpl_id;
967     udata.alloc_type = alloc_type;
968     udata.allow_sect_absorb = FALSE;    /* Force section to be absorbed into aggregator */
969     udata.allow_eoa_shrink_only = FALSE;
970 
971     /* Call the "can shrink" callback for the section */
972     if((ret_value = H5MF_sect_simple_can_shrink((const H5FS_section_info_t *)node, &udata)) < 0)
973         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check if section can shrink container")
974     else if(ret_value > 0) {
975         /* Shrink or absorb the section */
976         if(H5MF_sect_simple_shrink((H5FS_section_info_t **)&node, &udata) < 0)
977             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container")
978     } /* end if */
979 
980 done:
981     /* Free section node allocated */
982     if(node && H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0)
983         HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
984 
985 #ifdef H5MF_ALLOC_DEBUG
986 HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
987 #endif /* H5MF_ALLOC_DEBUG */
988     FUNC_LEAVE_NOAPI(ret_value)
989 } /* end H5MF_try_shrink() */
990 
991 
992 /*-------------------------------------------------------------------------
993  * Function:    H5MF_close_shrink_eoa
994  *
995  * Purpose:     Shrink the EOA while closing
996  *
997  * Return:	SUCCEED/FAIL
998  *
999  * Programmer:  Quincey Koziol
1000  *              Saturday, July 7, 2012
1001  *
1002  *-------------------------------------------------------------------------
1003  */
1004 static herr_t
H5MF_close_shrink_eoa(H5F_t * f,hid_t dxpl_id)1005 H5MF_close_shrink_eoa(H5F_t *f, hid_t dxpl_id)
1006 {
1007     H5FD_mem_t type;            /* Memory type for iteration */
1008     hbool_t eoa_shrank;		/* Whether an EOA shrink occurs */
1009     htri_t status;		/* Status value */
1010     H5MF_sect_ud_t udata;	/* User data for callback */
1011     herr_t ret_value = SUCCEED;	/* Return value */
1012 
1013     FUNC_ENTER_NOAPI_NOINIT
1014 
1015     /* check args */
1016     HDassert(f);
1017     HDassert(f->shared);
1018 
1019     /* Construct user data for callbacks */
1020     udata.f = f;
1021     udata.dxpl_id = dxpl_id;
1022     udata.allow_sect_absorb = FALSE;
1023     udata.allow_eoa_shrink_only = TRUE;
1024 
1025     /* Iterate until no more EOA shrinking occurs */
1026     do {
1027 	eoa_shrank = FALSE;
1028 
1029 	/* Check the last section of each free-space manager */
1030 	for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
1031 	    if(f->shared->fs_man[type]) {
1032 		udata.alloc_type = type;
1033 		if((status = H5FS_sect_try_shrink_eoa(f, dxpl_id, f->shared->fs_man[type], &udata)) < 0)
1034 		    HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
1035 		else if(status > 0)
1036 		    eoa_shrank = TRUE;
1037 	    } /* end if */
1038 	} /* end for */
1039 
1040 	/* check the two aggregators */
1041 	if((status = H5MF_aggrs_try_shrink_eoa(f, dxpl_id)) < 0)
1042 	    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
1043 	else if(status > 0)
1044 	    eoa_shrank = TRUE;
1045     } while(eoa_shrank);
1046 
1047 done:
1048     FUNC_LEAVE_NOAPI(ret_value)
1049 } /* end H5MF_close_shrink_eoa() */
1050 
1051 
1052 /*-------------------------------------------------------------------------
1053  * Function:    H5MF_close
1054  *
1055  * Purpose:     Close the free space tracker(s) for a file
1056  *
1057  * Return:	SUCCEED/FAIL
1058  *
1059  * Programmer:  Quincey Koziol
1060  *              Tuesday, January 22, 2008
1061  *
1062  * Modifications:
1063  *      Vailin Choi; July 2012
1064  *      As the default free-list mapping is changed to H5FD_FLMAP_DICHOTOMY,
1065  *      modifications are needed to shrink EOA if the last section of each free-space manager
1066  *      and the remaining space in the two aggregators are at EOA.
1067 
1068  *-------------------------------------------------------------------------
1069  */
1070 herr_t
H5MF_close(H5F_t * f,hid_t dxpl_id)1071 H5MF_close(H5F_t *f, hid_t dxpl_id)
1072 {
1073     H5FD_mem_t type;                    /* Memory type for iteration */
1074     herr_t ret_value = SUCCEED;         /* Return value */
1075 
1076     FUNC_ENTER_NOAPI(FAIL)
1077 #ifdef H5MF_ALLOC_DEBUG
1078 HDfprintf(stderr, "%s: Entering\n", FUNC);
1079 #endif /* H5MF_ALLOC_DEBUG */
1080 
1081     /* check args */
1082     HDassert(f);
1083     HDassert(f->shared);
1084     HDassert(f->shared->lf);
1085 
1086     /* Free the space in aggregators */
1087     /* (for space not at EOF, it may be put into free space managers) */
1088     if(H5MF_free_aggrs(f, dxpl_id) < 0)
1089         HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators")
1090 
1091     /* Trying shrinking the EOA for the file */
1092     if(H5MF_close_shrink_eoa(f, dxpl_id) < 0)
1093         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
1094 
1095     /* Iterate over all the free space types that have managers and get each free list's space */
1096     for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
1097 #ifdef H5MF_ALLOC_DEBUG_MORE
1098 HDfprintf(stderr, "%s: Check 1.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]);
1099 #endif /* H5MF_ALLOC_DEBUG_MORE */
1100         /* If the free space manager for this type is open, close it */
1101         if(f->shared->fs_man[type]) {
1102 #ifdef H5MF_ALLOC_DEBUG_MORE
1103 HDfprintf(stderr, "%s: Before closing free space manager\n", FUNC);
1104 #endif /* H5MF_ALLOC_DEBUG_MORE */
1105             if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0)
1106                 HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release free space info")
1107             f->shared->fs_man[type] = NULL;
1108             f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
1109         } /* end if */
1110 #ifdef H5MF_ALLOC_DEBUG_MORE
1111 HDfprintf(stderr, "%s: Check 2.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]);
1112 #endif /* H5MF_ALLOC_DEBUG_MORE */
1113 
1114         /* If there is free space manager info for this type, delete it */
1115         /* (XXX: Make this optional when free space for a file can be persistant) */
1116         if(H5F_addr_defined(f->shared->fs_addr[type])) {
1117             haddr_t tmp_fs_addr;            /* Temporary holder for free space manager address */
1118 
1119             /* Put address into temporary variable and reset it */
1120             /* (Avoids loopback in file space freeing routine) */
1121             tmp_fs_addr = f->shared->fs_addr[type];
1122             f->shared->fs_addr[type] = HADDR_UNDEF;
1123 
1124             /* Shift to "deleting" state, to make certain we don't track any
1125              *  file space freed as a result of deleting the free space manager.
1126              */
1127             f->shared->fs_state[type] = H5F_FS_STATE_DELETING;
1128 
1129 #ifdef H5MF_ALLOC_DEBUG_MORE
1130 HDfprintf(stderr, "%s: Before deleting free space manager\n", FUNC);
1131 #endif /* H5MF_ALLOC_DEBUG_MORE */
1132             /* Delete free space manager for this type */
1133 	    if(H5FS_delete(f, dxpl_id, tmp_fs_addr) < 0)
1134 		HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't delete free space manager")
1135 
1136             /* Shift [back] to closed state */
1137             HDassert(f->shared->fs_state[type] == H5F_FS_STATE_DELETING);
1138             f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
1139 
1140             /* Sanity check that the free space manager for this type wasn't started up again */
1141             HDassert(!H5F_addr_defined(f->shared->fs_addr[type]));
1142         } /* end if */
1143     } /* end for */
1144 
1145     /* Free the space in aggregators (again) */
1146     /* (in case any free space information re-started them) */
1147     if(H5MF_free_aggrs(f, dxpl_id) < 0)
1148         HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators")
1149 
1150     /* Trying shrinking the EOA for the file */
1151     /* (in case any free space is now at the EOA) */
1152     if(H5MF_close_shrink_eoa(f, dxpl_id) < 0)
1153         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
1154 
1155 done:
1156 #ifdef H5MF_ALLOC_DEBUG
1157 HDfprintf(stderr, "%s: Leaving\n", FUNC);
1158 #endif /* H5MF_ALLOC_DEBUG */
1159     FUNC_LEAVE_NOAPI(ret_value)
1160 } /* end H5MF_close() */
1161 
1162