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  * Programmer:	Quincey Koziol <koziol@hdfgroup.org>
16  *              Tuesday, January  8, 2008
17  *
18  * Purpose:	Free space section callbacks for file.
19  *
20  */
21 
22 /****************/
23 /* Module Setup */
24 /****************/
25 
26 #define H5F_FRIEND		/*suppress error about including H5Fpkg	  */
27 #include "H5MFmodule.h"         /* This source code file is part of the H5MF module */
28 
29 
30 /***********/
31 /* Headers */
32 /***********/
33 #include "H5private.h"		/* Generic Functions			*/
34 #include "H5Eprivate.h"		/* Error handling		  	*/
35 #include "H5Fpkg.h"             /* File access				*/
36 #include "H5MFpkg.h"		/* File memory management		*/
37 
38 
39 /****************/
40 /* Local Macros */
41 /****************/
42 
43 
44 /******************/
45 /* Local Typedefs */
46 /******************/
47 
48 
49 /********************/
50 /* Package Typedefs */
51 /********************/
52 
53 
54 /********************/
55 /* Local Prototypes */
56 /********************/
57 
58 /* 'simple/small/large' section callbacks */
59 static H5FS_section_info_t *H5MF__sect_deserialize(const H5FS_section_class_t *cls,
60     const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size, unsigned *des_flags);
61 static herr_t H5MF__sect_valid(const H5FS_section_class_t *cls,
62     const H5FS_section_info_t *sect);
63 static H5FS_section_info_t *H5MF__sect_split(H5FS_section_info_t *sect,
64     hsize_t frag_size);
65 
66 
67 /* 'simple' section callbacks */
68 static htri_t H5MF__sect_simple_can_merge(const H5FS_section_info_t *sect1,
69     const H5FS_section_info_t *sect2, void *udata);
70 static herr_t H5MF__sect_simple_merge(H5FS_section_info_t **sect1,
71     H5FS_section_info_t *sect2, void *udata);
72 static htri_t H5MF__sect_simple_can_shrink(const H5FS_section_info_t *_sect,
73     void *udata);
74 static herr_t H5MF__sect_simple_shrink(H5FS_section_info_t **_sect,
75     void *udata);
76 
77 
78 /* 'small' section callbacks */
79 static herr_t H5MF__sect_small_add(H5FS_section_info_t **_sect, unsigned *flags, void *_udata);
80 static htri_t H5MF__sect_small_can_merge(const H5FS_section_info_t *sect1,
81     const H5FS_section_info_t *sect2, void *udata);
82 static herr_t H5MF__sect_small_merge(H5FS_section_info_t **sect1,
83     H5FS_section_info_t *sect2, void *udata);
84 
85 /* 'large' section callbacks */
86 static htri_t H5MF__sect_large_can_merge(const H5FS_section_info_t *sect1,
87     const H5FS_section_info_t *sect2, void *udata);
88 static herr_t H5MF__sect_large_merge(H5FS_section_info_t **sect1,
89     H5FS_section_info_t *sect2, void *udata);
90 static htri_t H5MF__sect_large_can_shrink(const H5FS_section_info_t *_sect,
91     void *udata);
92 static herr_t H5MF__sect_large_shrink(H5FS_section_info_t **_sect,
93     void *udata);
94 
95 /*********************/
96 /* Package Variables */
97 /*********************/
98 
99 /* Class info for "simple" free space sections */
100 H5FS_section_class_t H5MF_FSPACE_SECT_CLS_SIMPLE[1] = {{
101     /* Class variables */
102     H5MF_FSPACE_SECT_SIMPLE,		/* Section type                 */
103     0,					/* Extra serialized size        */
104     H5FS_CLS_MERGE_SYM | H5FS_CLS_ADJUST_OK, /* Class flags                  */
105     NULL,				/* Class private info           */
106 
107     /* Class methods */
108     NULL,				/* Initialize section class     */
109     NULL,				/* Terminate section class      */
110 
111     /* Object methods */
112     NULL,				/* Add section                  */
113     NULL,				/* Serialize section            */
114     H5MF__sect_deserialize,		/* Deserialize section          */
115     H5MF__sect_simple_can_merge,		/* Can sections merge?          */
116     H5MF__sect_simple_merge,		/* Merge sections               */
117     H5MF__sect_simple_can_shrink,	/* Can section shrink container?*/
118     H5MF__sect_simple_shrink,		/* Shrink container w/section   */
119     H5MF__sect_free,			/* Free section                 */
120     H5MF__sect_valid,			/* Check validity of section    */
121     H5MF__sect_split,			/* Split section node for alignment */
122     NULL,				/* Dump debugging for section   */
123 }};
124 
125 /* Class info for "small" free space sections */
126 H5FS_section_class_t H5MF_FSPACE_SECT_CLS_SMALL[1] = {{
127     /* Class variables */
128     H5MF_FSPACE_SECT_SMALL,     /* Section type                 */
129     0,                          /* Extra serialized size        */
130     H5FS_CLS_MERGE_SYM | H5FS_CLS_ADJUST_OK,    /* Class flags                  */
131     NULL,                       /* Class private info           */
132 
133     /* Class methods */
134     NULL,                       /* Initialize section class     */
135     NULL,                       /* Terminate section class      */
136 
137     /* Object methods */
138     H5MF__sect_small_add,        /* Add section                  */
139     NULL,                       /* Serialize section            */
140     H5MF__sect_deserialize,		/* Deserialize section          */
141     H5MF__sect_small_can_merge,  /* Can sections merge?          */
142     H5MF__sect_small_merge,      /* Merge sections               */
143     NULL,		                /* Can section shrink container?*/
144     NULL,		                /* Shrink container w/section   */
145     H5MF__sect_free,             /* Free section                 */
146     H5MF__sect_valid,            /* Check validity of section    */
147     H5MF__sect_split,            /* Split section node for alignment */
148     NULL,                       /* Dump debugging for section   */
149 }};
150 
151 /* Class info for "large" free space sections */
152 H5FS_section_class_t H5MF_FSPACE_SECT_CLS_LARGE[1] = {{
153     /* Class variables */
154     H5MF_FSPACE_SECT_LARGE,		/* Section type                 */
155     0,					/* Extra serialized size        */
156     H5FS_CLS_MERGE_SYM | H5FS_CLS_ADJUST_OK, /* Class flags                  */
157     NULL,				/* Class private info           */
158 
159     /* Class methods */
160     NULL,				/* Initialize section class     */
161     NULL,				/* Terminate section class      */
162 
163     /* Object methods */
164     NULL,				/* Add section                  */
165     NULL,				/* Serialize section            */
166     H5MF__sect_deserialize,		/* Deserialize section          */
167     H5MF__sect_large_can_merge,		/* Can sections merge?          */
168     H5MF__sect_large_merge,		/* Merge sections               */
169     H5MF__sect_large_can_shrink,		/* Can section shrink container?*/
170     H5MF__sect_large_shrink,		/* Shrink container w/section   */
171     H5MF__sect_free,			/* Free section                 */
172     H5MF__sect_valid,			/* Check validity of section    */
173     H5MF__sect_split,			/* Split section node for alignment */
174     NULL,				/* Dump debugging for section   */
175 }};
176 
177 /*****************************/
178 /* Library Private Variables */
179 /*****************************/
180 
181 
182 /*******************/
183 /* Local Variables */
184 /*******************/
185 
186 /* Declare a free list to manage the H5MF_free_section_t struct */
187 H5FL_DEFINE(H5MF_free_section_t);
188 
189 /*
190  * "simple/small/large" section callbacks
191  */
192 
193 
194 /*-------------------------------------------------------------------------
195  * Function:	H5MF__sect_new
196  *
197  * Purpose:	Create a new section of "ctype" and return it to the caller
198  *
199  * Return:	Pointer to new section on success/NULL on failure
200  *
201  * Programmer:	Quincey Koziol
202  *		koziol@hdfgroup.org
203  *		January  8 2008
204  *
205  *-------------------------------------------------------------------------
206  */
207 H5MF_free_section_t *
H5MF__sect_new(unsigned ctype,haddr_t sect_off,hsize_t sect_size)208 H5MF__sect_new(unsigned ctype, haddr_t sect_off, hsize_t sect_size)
209 {
210     H5MF_free_section_t *sect;          /* 'Simple' free space section to add */
211     H5MF_free_section_t *ret_value = NULL;      /* Return value */
212 
213     FUNC_ENTER_PACKAGE
214 
215     /* Check arguments.  */
216     HDassert(sect_size);
217 
218     /* Create free space section node */
219     if(NULL == (sect = H5FL_MALLOC(H5MF_free_section_t)))
220         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for direct block free list section")
221 
222     /* Set the information passed in */
223     sect->sect_info.addr = sect_off;
224     sect->sect_info.size = sect_size;
225 
226     /* Set the section's class & state */
227     sect->sect_info.type = ctype;
228     sect->sect_info.state = H5FS_SECT_LIVE;
229 
230     /* Set return value */
231     ret_value = sect;
232 
233 done:
234     FUNC_LEAVE_NOAPI(ret_value)
235 } /* end H5MF__sect_new() */
236 
237 
238 /*-------------------------------------------------------------------------
239  * Function:	H5MF__sect_free
240  *
241  * Purpose:	Free a 'simple/small/large' section node
242  *
243  * Return:	Success:	non-negative
244  *		Failure:	negative
245  *
246  * Programmer:	Quincey Koziol
247  *              Tuesday, January  8, 2008
248  *
249  *-------------------------------------------------------------------------
250  */
251 herr_t
H5MF__sect_free(H5FS_section_info_t * _sect)252 H5MF__sect_free(H5FS_section_info_t *_sect)
253 {
254     H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect;   /* File free section */
255 
256     FUNC_ENTER_PACKAGE_NOERR
257 
258     /* Check arguments. */
259     HDassert(sect);
260 
261     /* Release the section */
262     sect = H5FL_FREE(H5MF_free_section_t, sect);
263 
264     FUNC_LEAVE_NOAPI(SUCCEED)
265 }   /* H5MF__sect_free() */
266 
267 
268 /*-------------------------------------------------------------------------
269  * Function:	H5MF__sect_deserialize
270  *
271  * Purpose:	Deserialize a buffer into a "live" section
272  *
273  * Return:	Success:	non-negative
274  *		Failure:	negative
275  *
276  * Programmer:	Quincey Koziol
277  *              Tuesday, January  8, 2008
278  *
279  *-------------------------------------------------------------------------
280  */
281 static H5FS_section_info_t *
H5MF__sect_deserialize(const H5FS_section_class_t * cls,const uint8_t H5_ATTR_UNUSED * buf,haddr_t sect_addr,hsize_t sect_size,unsigned H5_ATTR_UNUSED * des_flags)282 H5MF__sect_deserialize(const H5FS_section_class_t *cls,
283     const uint8_t H5_ATTR_UNUSED *buf, haddr_t sect_addr,
284     hsize_t sect_size, unsigned H5_ATTR_UNUSED *des_flags)
285 {
286     H5MF_free_section_t *sect;          /* New section */
287     H5FS_section_info_t *ret_value = NULL;      /* Return value */
288 
289     FUNC_ENTER_STATIC
290 
291     /* Check arguments. */
292     HDassert(cls);
293     HDassert(H5F_addr_defined(sect_addr));
294     HDassert(sect_size);
295 
296     /* Create free space section for block */
297     if(NULL == (sect = H5MF__sect_new(cls->type, sect_addr, sect_size)))
298         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't initialize free space section")
299 
300     /* Set return value */
301     ret_value = (H5FS_section_info_t *)sect;
302 
303 done:
304     FUNC_LEAVE_NOAPI(ret_value)
305 } /* H5MF__sect_deserialize() */
306 
307 
308 /*-------------------------------------------------------------------------
309  * Function:	H5MF__sect_valid
310  *
311  * Purpose:	Check the validity of a section
312  *
313  * Return:	Success:	non-negative
314  *          Failure:	negative
315  *
316  * Programmer:	Quincey Koziol
317  *              Tuesday, January  8, 2008
318  *
319  *-------------------------------------------------------------------------
320  */
321 static herr_t
H5MF__sect_valid(const H5FS_section_class_t H5_ATTR_UNUSED * cls,const H5FS_section_info_t H5_ATTR_UNUSED * _sect)322 H5MF__sect_valid(const H5FS_section_class_t H5_ATTR_UNUSED *cls,
323     const H5FS_section_info_t
324 #ifdef NDEBUG
325     H5_ATTR_UNUSED
326 #endif /* NDEBUG */
327     *_sect)
328 {
329 #ifndef NDEBUG
330     const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect;   /* File free section */
331 #endif /* NDEBUG */
332 
333     FUNC_ENTER_STATIC_NOERR
334 
335     /* Check arguments. */
336     HDassert(sect);
337 
338     FUNC_LEAVE_NOAPI(SUCCEED)
339 }   /* H5MF__sect_valid() */
340 
341 
342 /*-------------------------------------------------------------------------
343  * Function:	H5MF__sect_split
344  *
345  * Purpose:	Split SECT into 2 sections: fragment for alignment & the aligned section
346  *          SECT's addr and size are updated to point to the aligned section
347  *
348  * Return:	Success:	the fragment for aligning sect
349  *          Failure:	null
350  *
351  * Programmer:	Vailin Choi, July 29, 2008
352  *
353  *-------------------------------------------------------------------------
354  */
355 static H5FS_section_info_t *
H5MF__sect_split(H5FS_section_info_t * sect,hsize_t frag_size)356 H5MF__sect_split(H5FS_section_info_t *sect, hsize_t frag_size)
357 {
358     H5MF_free_section_t *ret_value = NULL;      /* Return value */
359 
360     FUNC_ENTER_STATIC
361 
362     /* Allocate space for new section */
363     if(NULL == (ret_value = H5MF__sect_new(sect->type, sect->addr, frag_size)))
364         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't initialize free space section")
365 
366     /* Set new section's info */
367     sect->addr += frag_size;
368     sect->size -= frag_size;
369 
370 done:
371     FUNC_LEAVE_NOAPI((H5FS_section_info_t *)ret_value)
372 } /* end H5MF__sect_split() */
373 
374 /*
375  * "simple" section callbacks
376  */
377 
378 /*-------------------------------------------------------------------------
379  * Function:	H5MF__sect_simple_can_merge
380  *
381  * Purpose:	Can two sections of this type merge?
382  *
383  * Note:        Second section must be "after" first section
384  *
385  * Return:	Success:	non-negative (TRUE/FALSE)
386  *		Failure:	negative
387  *
388  * Programmer:	Quincey Koziol
389  *              Tuesday, January  8, 2008
390  *
391  *-------------------------------------------------------------------------
392  */
393 static htri_t
H5MF__sect_simple_can_merge(const H5FS_section_info_t * _sect1,const H5FS_section_info_t * _sect2,void H5_ATTR_UNUSED * _udata)394 H5MF__sect_simple_can_merge(const H5FS_section_info_t *_sect1,
395     const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
396 {
397     const H5MF_free_section_t *sect1 = (const H5MF_free_section_t *)_sect1;   /* File free section */
398     const H5MF_free_section_t *sect2 = (const H5MF_free_section_t *)_sect2;   /* File free section */
399     htri_t ret_value = FAIL;            /* Return value */
400 
401     FUNC_ENTER_STATIC_NOERR
402 
403     /* Check arguments. */
404     HDassert(sect1);
405     HDassert(sect2);
406     HDassert(sect1->sect_info.type == sect2->sect_info.type);   /* Checks "MERGE_SYM" flag */
407     HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
408 
409     /* Check if second section adjoins first section */
410     ret_value = H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
411 
412     FUNC_LEAVE_NOAPI(ret_value)
413 } /* H5MF__sect_simple_can_merge() */
414 
415 
416 /*-------------------------------------------------------------------------
417  * Function:	H5MF__sect_simple_merge
418  *
419  * Purpose:	Merge two sections of this type
420  *
421  * Note:        Second section always merges into first node
422  *
423  * Return:	Success:	non-negative
424  *		Failure:	negative
425  *
426  * Programmer:	Quincey Koziol
427  *              Tuesday, January  8, 2008
428  *
429  *-------------------------------------------------------------------------
430  */
431 static herr_t
H5MF__sect_simple_merge(H5FS_section_info_t ** _sect1,H5FS_section_info_t * _sect2,void H5_ATTR_UNUSED * _udata)432 H5MF__sect_simple_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
433     void H5_ATTR_UNUSED *_udata)
434 {
435     H5MF_free_section_t **sect1 = (H5MF_free_section_t **)_sect1;   /* File free section */
436     H5MF_free_section_t *sect2 = (H5MF_free_section_t *)_sect2;   /* File free section */
437     herr_t ret_value = SUCCEED;         /* Return value */
438 
439     FUNC_ENTER_STATIC
440 
441     /* Check arguments. */
442     HDassert(sect1);
443     HDassert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
444     HDassert(sect2);
445     HDassert(sect2->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
446     HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
447 
448     /* Add second section's size to first section */
449     (*sect1)->sect_info.size += sect2->sect_info.size;
450 
451     /* Get rid of second section */
452     if(H5MF__sect_free((H5FS_section_info_t *)sect2) < 0)
453         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
454 
455 done:
456     FUNC_LEAVE_NOAPI(ret_value)
457 } /* H5MF__sect_simple_merge() */
458 
459 
460 /*-------------------------------------------------------------------------
461  * Function:	H5MF__sect_simple_can_shrink
462  *
463  * Purpose:	Can this section shrink the container?
464  *
465  * Return:	Success:	non-negative (TRUE/FALSE)
466  *		Failure:	negative
467  *
468  * Programmer:	Quincey Koziol
469  *              Tuesday, January  8, 2008
470  *
471  *-------------------------------------------------------------------------
472  */
473 static htri_t
H5MF__sect_simple_can_shrink(const H5FS_section_info_t * _sect,void * _udata)474 H5MF__sect_simple_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
475 {
476     const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect;   /* File free section */
477     H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata;   /* User data for callback */
478     haddr_t eoa;                /* End of address space in the file */
479     haddr_t end;                /* End of section to extend */
480     htri_t ret_value = FAIL;    /* Return value */
481 
482     FUNC_ENTER_STATIC
483 
484     /* Check arguments. */
485     HDassert(sect);
486     HDassert(udata);
487     HDassert(udata->f);
488 
489     /* Retrieve the end of the file's address space */
490     if(HADDR_UNDEF == (eoa = H5F_get_eoa(udata->f, udata->alloc_type)))
491 	HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
492 
493     /* Compute address of end of section to check */
494     end = sect->sect_info.addr + sect->sect_info.size;
495 
496     /* Check if the section is exactly at the end of the allocated space in the file */
497     if(H5F_addr_eq(end, eoa)) {
498         /* Set the shrinking type */
499         udata->shrink = H5MF_SHRINK_EOA;
500 #ifdef H5MF_ALLOC_DEBUG_MORE
501 HDfprintf(stderr, "%s: section {%a, %Hu}, shrinks file, eoa = %a\n", FUNC, sect->sect_info.addr, sect->sect_info.size, eoa);
502 #endif /* H5MF_ALLOC_DEBUG_MORE */
503 
504         /* Indicate shrinking can occur */
505         HGOTO_DONE(TRUE)
506     } /* end if */
507     else {
508         /* Shrinking can't occur if the 'eoa_shrink_only' flag is set and we're not shrinking the EOA */
509         if(udata->allow_eoa_shrink_only)
510             HGOTO_DONE(FALSE)
511 
512         /* Check if this section is allowed to merge with metadata aggregation block */
513         if(udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_METADATA) {
514             htri_t status;              /* Status from aggregator adjoin */
515 
516             /* See if section can absorb the aggregator & vice versa */
517             if((status = H5MF__aggr_can_absorb(udata->f, &(udata->f->shared->meta_aggr), sect, &(udata->shrink))) < 0)
518                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "error merging section with aggregation block")
519             else if(status > 0) {
520                 /* Set the aggregator to operate on */
521                 udata->aggr = &(udata->f->shared->meta_aggr);
522 #ifdef H5MF_ALLOC_DEBUG_MORE
523 HDfprintf(stderr, "%s: section {%a, %Hu}, adjoins metadata aggregator\n", FUNC, sect->sect_info.addr, sect->sect_info.size);
524 #endif /* H5MF_ALLOC_DEBUG_MORE */
525 
526                 /* Indicate shrinking can occur */
527                 HGOTO_DONE(TRUE)
528             } /* end if */
529         } /* end if */
530 
531         /* Check if this section is allowed to merge with small 'raw' aggregation block */
532         if(udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_RAWDATA) {
533             htri_t status;              /* Status from aggregator adjoin */
534 
535             /* See if section can absorb the aggregator & vice versa */
536             if((status = H5MF__aggr_can_absorb(udata->f, &(udata->f->shared->sdata_aggr), sect, &(udata->shrink))) < 0)
537                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "error merging section with aggregation block")
538             else if(status > 0) {
539                 /* Set the aggregator to operate on */
540                 udata->aggr = &(udata->f->shared->sdata_aggr);
541 #ifdef H5MF_ALLOC_DEBUG_MORE
542 HDfprintf(stderr, "%s: section {%a, %Hu}, adjoins small data aggregator\n", FUNC, sect->sect_info.addr, sect->sect_info.size);
543 #endif /* H5MF_ALLOC_DEBUG_MORE */
544 
545                 /* Indicate shrinking can occur */
546                 HGOTO_DONE(TRUE)
547             } /* end if */
548         } /* end if */
549     } /* end else */
550 
551     /* Set return value */
552     ret_value = FALSE;
553 
554 done:
555     FUNC_LEAVE_NOAPI(ret_value)
556 } /* H5MF__sect_simple_can_shrink() */
557 
558 
559 /*-------------------------------------------------------------------------
560  * Function:	H5MF__sect_simple_shrink
561  *
562  * Purpose:	Shrink container with section
563  *
564  * Return:	Success:	non-negative
565  *		Failure:	negative
566  *
567  * Programmer:	Quincey Koziol
568  *              Tuesday, January  8, 2008
569  *
570  *-------------------------------------------------------------------------
571  */
572 static herr_t
H5MF__sect_simple_shrink(H5FS_section_info_t ** _sect,void * _udata)573 H5MF__sect_simple_shrink(H5FS_section_info_t **_sect, void *_udata)
574 {
575     H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect;   /* File free section */
576     H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata;   /* User data for callback */
577     herr_t ret_value = SUCCEED;         /* Return value */
578 
579     FUNC_ENTER_STATIC
580 
581     /* Check arguments. */
582     HDassert(sect);
583     HDassert(udata);
584     HDassert(udata->f);
585 
586     /* Check for shrinking file */
587     if(H5MF_SHRINK_EOA == udata->shrink) {
588         /* Sanity check */
589         HDassert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
590 
591         /* Release section's space at EOA */
592         if(H5F__free(udata->f, udata->alloc_type, (*sect)->sect_info.addr, (*sect)->sect_info.size) < 0)
593             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed")
594     } /* end if */
595     else {
596         /* Sanity check */
597         HDassert(udata->aggr);
598 
599         /* Absorb the section into the aggregator or vice versa */
600         if(H5MF__aggr_absorb(udata->f, udata->aggr, *sect, udata->allow_sect_absorb) < 0)
601             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't absorb section into aggregator or vice versa")
602     } /* end else */
603 
604     /* Check for freeing section */
605     if(udata->shrink != H5MF_SHRINK_SECT_ABSORB_AGGR) {
606         /* Free section */
607         if(H5MF__sect_free((H5FS_section_info_t *)*sect) < 0)
608             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
609 
610         /* Mark section as freed, for free space manager */
611         *sect = NULL;
612     } /* end if */
613 
614 done:
615     FUNC_LEAVE_NOAPI(ret_value)
616 } /* H5MF__sect_simple_shrink() */
617 
618 /*
619  * "small" section callbacks
620  */
621 
622 
623 /*-------------------------------------------------------------------------
624  * Function:    H5MF__sect_small_add
625  *
626  * Purpose:     Perform actions on a small "meta" action before adding it to the free space manager:
627  *              1) Drop the section if it is at page end and its size <= page end threshold
628  *              2) Adjust section size to include page end threshold if
629  *                 (section size + threshold) is at page end
630  *
631  * Return:      Success:        non-negative
632  *              Failure:        negative
633  *
634  * Programmer:  Vailin Choi; Dec 2012
635  *
636  *-------------------------------------------------------------------------
637  */
638 static herr_t
H5MF__sect_small_add(H5FS_section_info_t ** _sect,unsigned * flags,void * _udata)639 H5MF__sect_small_add(H5FS_section_info_t **_sect, unsigned *flags, void *_udata)
640 {
641     H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect;   /* Fractal heap free section */
642     H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata;   /* User data for callback */
643     haddr_t sect_end;
644     hsize_t rem, prem;
645     herr_t ret_value = SUCCEED;         /* Return value */
646 
647     FUNC_ENTER_STATIC
648 
649 #ifdef H5MF_ALLOC_DEBUG_MORE
650 HDfprintf(stderr, "%s: Entering, section {%a, %Hu}\n", FUNC, (*sect)->sect_info.addr, (*sect)->sect_info.size);
651 #endif /* H5MF_ALLOC_DEBUG_MORE */
652 
653     /* Do not adjust the section raw data or global heap data */
654     if(udata->alloc_type == H5FD_MEM_DRAW || udata->alloc_type == H5FD_MEM_GHEAP)
655         HGOTO_DONE(ret_value);
656 
657     sect_end = (*sect)->sect_info.addr + (*sect)->sect_info.size;
658     rem = sect_end % udata->f->shared->fs_page_size;
659     prem = udata->f->shared->fs_page_size - rem;
660 
661     /* Drop the section if it is at page end and its size is <= pgend threshold */
662     if(!rem && (*sect)->sect_info.size <= H5F_PGEND_META_THRES(udata->f) && (*flags & H5FS_ADD_RETURNED_SPACE)) {
663         if(H5MF__sect_free((H5FS_section_info_t *)(*sect)) < 0)
664             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
665         *sect = NULL;
666         *flags &= (unsigned)~H5FS_ADD_RETURNED_SPACE;
667         *flags |= H5FS_PAGE_END_NO_ADD;
668 #ifdef H5MF_ALLOC_DEBUG_MORE
669 HDfprintf(stderr, "%s: section is dropped\n", FUNC);
670 #endif /* H5MF_ALLOC_DEBUG_MORE */
671     } /* end if */
672     /* Adjust the section if it is not at page end but its size + prem is at page end */
673     else
674         if(prem <= H5F_PGEND_META_THRES(udata->f)) {
675             (*sect)->sect_info.size += prem;
676 #ifdef H5MF_ALLOC_DEBUG_MORE
677 HDfprintf(stderr, "%s: section is adjusted {%a, %Hu}\n", FUNC, (*sect)->sect_info.addr, (*sect)->sect_info.size);
678 #endif /* H5MF_ALLOC_DEBUG_MORE */
679         } /* end if */
680 
681 done:
682     FUNC_LEAVE_NOAPI(ret_value)
683 } /* H5MF__sect_small_add() */
684 
685 
686 /*-------------------------------------------------------------------------
687  * Function:	H5MF__sect_small_can_merge
688  *
689  * Purpose:	Can two sections of this type merge?
690  *
691  * Note: Second section must be "after" first section
692  *       The "merged" section cannot cross page boundary.
693  *
694  * Return:	Success:	non-negative (TRUE/FALSE)
695  *          Failure:	negative
696  *
697  * Programmer:	Vailin Choi; Dec 2012
698  *
699  *-------------------------------------------------------------------------
700  */
701 static htri_t
H5MF__sect_small_can_merge(const H5FS_section_info_t * _sect1,const H5FS_section_info_t * _sect2,void * _udata)702 H5MF__sect_small_can_merge(const H5FS_section_info_t *_sect1,
703     const H5FS_section_info_t *_sect2, void *_udata)
704 {
705     const H5MF_free_section_t *sect1 = (const H5MF_free_section_t *)_sect1;   /* File free section */
706     const H5MF_free_section_t *sect2 = (const H5MF_free_section_t *)_sect2;   /* File free section */
707     H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata;   /* User data for callback */
708     htri_t ret_value = FALSE;                   	/* Return value */
709 
710     FUNC_ENTER_STATIC_NOERR
711 
712     /* Check arguments. */
713     HDassert(sect1);
714     HDassert(sect2);
715     HDassert(sect1->sect_info.type == sect2->sect_info.type);   /* Checks "MERGE_SYM" flag */
716     HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
717 
718     /* Check if second section adjoins first section */
719     ret_value = H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
720     if(ret_value > 0)
721         /* If they are on different pages, couldn't merge */
722         if((sect1->sect_info.addr / udata->f->shared->fs_page_size) != (((sect2->sect_info.addr + sect2->sect_info.size - 1) / udata->f->shared->fs_page_size)))
723 	    ret_value = FALSE;
724 
725 #ifdef H5MF_ALLOC_DEBUG_MORE
726 HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value);
727 #endif /* H5MF_ALLOC_DEBUG_MORE */
728 
729     FUNC_LEAVE_NOAPI(ret_value)
730 } /* H5MF__sect_small_can_merge() */
731 
732 
733 /*-------------------------------------------------------------------------
734  * Function:	H5MF__sect_small_merge
735  *
736  * Purpose:	Merge two sections of this type
737  *
738  * Note: Second section always merges into first node.
739  *       If the size of the "merged" section is equal to file space page size,
740  *       free the section.
741  *
742  * Return:	Success:	non-negative
743  *		Failure:	negative
744  *
745  * Programmer:	Vailin Choi; Dec 2012
746  *
747  *-------------------------------------------------------------------------
748  */
749 static herr_t
H5MF__sect_small_merge(H5FS_section_info_t ** _sect1,H5FS_section_info_t * _sect2,void * _udata)750 H5MF__sect_small_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
751     void *_udata)
752 {
753     H5MF_free_section_t **sect1 = (H5MF_free_section_t **)_sect1;   /* File free section */
754     H5MF_free_section_t *sect2 = (H5MF_free_section_t *)_sect2;   /* File free section */
755     H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata;   /* User data for callback */
756     herr_t ret_value = SUCCEED;         		/* Return value */
757 
758     FUNC_ENTER_STATIC
759 
760     /* Check arguments. */
761     HDassert(sect1);
762     HDassert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SMALL);
763     HDassert(sect2);
764     HDassert(sect2->sect_info.type == H5MF_FSPACE_SECT_SMALL);
765     HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
766 
767     /* Add second section's size to first section */
768     (*sect1)->sect_info.size += sect2->sect_info.size;
769 
770     if((*sect1)->sect_info.size == udata->f->shared->fs_page_size) {
771         if(H5MF_xfree(udata->f, udata->alloc_type, (*sect1)->sect_info.addr, (*sect1)->sect_info.size) < 0)
772             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free merged section")
773 
774         /* Need to free possible metadata page in the PB cache */
775         /* This is in response to the data corruption bug from fheap.c with page buffering + page strategy */
776         /* Note: Large metadata page bypasses the PB cache */
777         /* Note: Update of raw data page (large or small sized) is handled by the PB cache */
778         if(udata->f->shared->page_buf != NULL && udata->alloc_type != H5FD_MEM_DRAW)
779             if(H5PB_remove_entry(udata->f, (*sect1)->sect_info.addr) < 0)
780                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free merged section")
781 
782         if(H5MF__sect_free((H5FS_section_info_t *)(*sect1)) < 0)
783             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
784         *sect1 = NULL;
785     } /* end if */
786 
787     /* Get rid of second section */
788     if(H5MF__sect_free((H5FS_section_info_t *)sect2) < 0)
789         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
790 
791 done:
792     FUNC_LEAVE_NOAPI(ret_value)
793 } /* H5MF__sect_small_merge() */
794 
795 /*
796  * "Large" section callbacks
797  */
798 
799 
800 /*-------------------------------------------------------------------------
801  * Function:	H5MF__sect_large_can_merge (same as H5MF__sect_simple_can_merge)
802  *
803  * Purpose:	Can two sections of this type merge?
804  *
805  * Note: Second section must be "after" first section
806  *
807  * Return:	Success:	non-negative (TRUE/FALSE)
808  *          Failure:	negative
809  *
810  * Programmer:	Vailin Choi; Dec 2012
811  *
812  *-------------------------------------------------------------------------
813  */
814 static htri_t
H5MF__sect_large_can_merge(const H5FS_section_info_t * _sect1,const H5FS_section_info_t * _sect2,void H5_ATTR_UNUSED * _udata)815 H5MF__sect_large_can_merge(const H5FS_section_info_t *_sect1,
816     const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
817 {
818     const H5MF_free_section_t *sect1 = (const H5MF_free_section_t *)_sect1;   	/* File free section */
819     const H5MF_free_section_t *sect2 = (const H5MF_free_section_t *)_sect2;   	/* File free section */
820     htri_t ret_value = FALSE;           /* Return value */
821 
822     FUNC_ENTER_STATIC_NOERR
823 
824     /* Check arguments. */
825     HDassert(sect1);
826     HDassert(sect2);
827     HDassert(sect1->sect_info.type == sect2->sect_info.type);   /* Checks "MERGE_SYM" flag */
828     HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
829 
830     ret_value = H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
831 
832 #ifdef H5MF_ALLOC_DEBUG_MORE
833 HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value);
834 #endif /* H5MF_ALLOC_DEBUG_MORE */
835 
836     FUNC_LEAVE_NOAPI(ret_value)
837 } /* H5MF__sect_large_can_merge() */
838 
839 
840 /*-------------------------------------------------------------------------
841  * Function:	H5MF__sect_large_merge (same as H5MF__sect_simple_merge)
842  *
843  * Purpose:	Merge two sections of this type
844  *
845  * Note: Second section always merges into first node
846  *
847  * Return:	Success:	non-negative
848  *          Failure:	negative
849  *
850  * Programmer:	Vailin Choi; Dec 2012
851  *
852  *-------------------------------------------------------------------------
853  */
854 static herr_t
H5MF__sect_large_merge(H5FS_section_info_t ** _sect1,H5FS_section_info_t * _sect2,void H5_ATTR_UNUSED * _udata)855 H5MF__sect_large_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
856     void H5_ATTR_UNUSED *_udata)
857 {
858     H5MF_free_section_t **sect1 = (H5MF_free_section_t **)_sect1;   /* File free section */
859     H5MF_free_section_t *sect2 = (H5MF_free_section_t *)_sect2;   /* File free section */
860     herr_t ret_value = SUCCEED;         /* Return value */
861 
862     FUNC_ENTER_STATIC
863 
864     /* Check arguments. */
865     HDassert(sect1);
866     HDassert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_LARGE);
867     HDassert(sect2);
868     HDassert(sect2->sect_info.type == H5MF_FSPACE_SECT_LARGE);
869     HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
870 
871     /* Add second section's size to first section */
872     (*sect1)->sect_info.size += sect2->sect_info.size;
873 
874     /* Get rid of second section */
875     if(H5MF__sect_free((H5FS_section_info_t *)sect2) < 0)
876         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
877 
878 done:
879     FUNC_LEAVE_NOAPI(ret_value)
880 } /* H5MF__sect_large_merge() */
881 
882 
883 /*-------------------------------------------------------------------------
884  * Function:	H5MF__sect_large_can_shrink
885  *
886  * Purpose:	Can this section shrink the container?
887  *
888  * Return:	Success:	non-negative (TRUE/FALSE)
889  *          Failure:	negative
890  *
891  * Programmer:	Vailin Choi; Dec 2012
892  *
893  *-------------------------------------------------------------------------
894  */
895 static htri_t
H5MF__sect_large_can_shrink(const H5FS_section_info_t * _sect,void * _udata)896 H5MF__sect_large_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
897 {
898     const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect;   /* File free section */
899     H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata;   /* User data for callback */
900     haddr_t eoa;                /* End of address space in the file */
901     haddr_t end;                /* End of section to extend */
902     htri_t ret_value = FALSE;	/* Return value */
903 
904     FUNC_ENTER_STATIC
905 
906     /* Check arguments. */
907     HDassert(sect);
908     HDassert(sect->sect_info.type == H5MF_FSPACE_SECT_LARGE);
909     HDassert(udata);
910     HDassert(udata->f);
911 
912     /* Retrieve the end of the file's address space */
913     if(HADDR_UNDEF == (eoa = H5FD_get_eoa(udata->f->shared->lf, udata->alloc_type)))
914         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
915 
916     /* Compute address of end of section to check */
917     end = sect->sect_info.addr + sect->sect_info.size;
918 
919     /* Check if the section is exactly at the end of the allocated space in the file */
920     if(H5F_addr_eq(end, eoa) && sect->sect_info.size >= udata->f->shared->fs_page_size) {
921         /* Set the shrinking type */
922         udata->shrink = H5MF_SHRINK_EOA;
923 #ifdef H5MF_ALLOC_DEBUG_MORE
924 HDfprintf(stderr, "%s: section {%a, %Hu}, shrinks file, eoa = %a\n", FUNC, sect->sect_info.addr, sect->sect_info.size, eoa);
925 #endif /* H5MF_ALLOC_DEBUG_MORE */
926 
927         /* Indicate shrinking can occur */
928         HGOTO_DONE(TRUE)
929     } /* end if */
930 
931 done:
932     FUNC_LEAVE_NOAPI(ret_value)
933 } /* H5MF__sect_large_can_shrink() */
934 
935 
936 /*-------------------------------------------------------------------------
937  * Function:	H5MF__sect_large_shrink
938  *
939  * Purpose:     Shrink a large-sized section
940  *
941  * Return:      Success:	non-negative
942  *              Failure:	negative
943  *
944  * Programmer:	Vailin Choi; Dec 2012
945  *
946  *-------------------------------------------------------------------------
947  */
948 static herr_t
H5MF__sect_large_shrink(H5FS_section_info_t ** _sect,void * _udata)949 H5MF__sect_large_shrink(H5FS_section_info_t **_sect, void *_udata)
950 {
951     H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect; /* File free section */
952     H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata;           /* User data for callback */
953     hsize_t frag_size = 0;              /* Fragment size */
954     herr_t ret_value = SUCCEED;         /* Return value */
955 
956     FUNC_ENTER_STATIC
957 
958     /* Check arguments. */
959     HDassert(sect);
960     HDassert((*sect)->sect_info.type == H5MF_FSPACE_SECT_LARGE);
961     HDassert(udata);
962     HDassert(udata->f);
963     HDassert(udata->shrink == H5MF_SHRINK_EOA);
964     HDassert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
965     HDassert(H5F_PAGED_AGGR(udata->f));
966 
967     /* Calculate possible mis-aligned fragment */
968     H5MF_EOA_MISALIGN(udata->f, (*sect)->sect_info.addr, udata->f->shared->fs_page_size, frag_size);
969 
970     /* Free full pages from EOA */
971     /* Retain partial page in the free-space manager so as to keep EOA at page boundary */
972     if(H5F__free(udata->f, udata->alloc_type, (*sect)->sect_info.addr+frag_size, (*sect)->sect_info.size-frag_size) < 0)
973         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed")
974 
975     if(frag_size) /* Adjust section size for the partial page */
976         (*sect)->sect_info.size = frag_size;
977     else {
978         /* Free section */
979         if(H5MF__sect_free((H5FS_section_info_t *)*sect) < 0)
980             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
981 
982         /* Mark section as freed, for free space manager */
983         *sect = NULL;
984     } /* end else */
985 
986 done:
987     FUNC_LEAVE_NOAPI(ret_value)
988 } /* H5MF__sect_large_shrink() */
989 
990