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