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