Coverage Report

Created: 2025-06-22 07:10

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