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