Coverage Report

Created: 2026-02-24 12:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5MFsection.c
Line
Count
Source
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
0
{
185
0
    H5MF_free_section_t *sect;             /* 'Simple' free space section to add */
186
0
    H5MF_free_section_t *ret_value = NULL; /* Return value */
187
188
0
    FUNC_ENTER_PACKAGE
189
190
    /* Check arguments.  */
191
0
    assert(sect_size);
192
193
    /* Create free space section node */
194
0
    if (NULL == (sect = H5FL_MALLOC(H5MF_free_section_t)))
195
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
196
0
                    "memory allocation failed for direct block free list section");
197
198
    /* Set the information passed in */
199
0
    sect->sect_info.addr = sect_off;
200
0
    sect->sect_info.size = sect_size;
201
202
    /* Set the section's class & state */
203
0
    sect->sect_info.type  = ctype;
204
0
    sect->sect_info.state = H5FS_SECT_LIVE;
205
206
    /* Set return value */
207
0
    ret_value = sect;
208
209
0
done:
210
0
    FUNC_LEAVE_NOAPI(ret_value)
211
0
} /* 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
0
{
226
0
    H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; /* File free section */
227
228
0
    FUNC_ENTER_PACKAGE_NOERR
229
230
    /* Check arguments. */
231
0
    assert(sect);
232
233
    /* Release the section */
234
0
    sect = H5FL_FREE(H5MF_free_section_t, sect);
235
236
0
    FUNC_LEAVE_NOAPI(SUCCEED)
237
0
} /* 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
0
{
253
0
    H5MF_free_section_t *sect;             /* New section */
254
0
    H5FS_section_info_t *ret_value = NULL; /* Return value */
255
256
0
    FUNC_ENTER_PACKAGE
257
258
    /* Check arguments. */
259
0
    assert(cls);
260
0
    assert(H5_addr_defined(sect_addr));
261
0
    assert(sect_size);
262
263
    /* Create free space section for block */
264
0
    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
0
    ret_value = (H5FS_section_info_t *)sect;
269
270
0
done:
271
0
    FUNC_LEAVE_NOAPI(ret_value)
272
0
} /* 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
0
{
317
0
    H5MF_free_section_t *ret_value = NULL; /* Return value */
318
319
0
    FUNC_ENTER_PACKAGE
320
321
    /* Allocate space for new section */
322
0
    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
0
    sect->addr += frag_size;
327
0
    sect->size -= frag_size;
328
329
0
done:
330
0
    FUNC_LEAVE_NOAPI((H5FS_section_info_t *)ret_value)
331
0
} /* 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
0
{
353
0
    const H5MF_free_section_t *sect1     = (const H5MF_free_section_t *)_sect1; /* File free section */
354
0
    const H5MF_free_section_t *sect2     = (const H5MF_free_section_t *)_sect2; /* File free section */
355
0
    htri_t                     ret_value = FAIL;                                /* Return value */
356
357
0
    FUNC_ENTER_PACKAGE_NOERR
358
359
    /* Check arguments. */
360
0
    assert(sect1);
361
0
    assert(sect2);
362
0
    assert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
363
0
    assert(H5_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
364
365
    /* Check if second section adjoins first section */
366
0
    ret_value = H5_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
367
368
0
    FUNC_LEAVE_NOAPI(ret_value)
369
0
} /* 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
0
{
387
0
    H5MF_free_section_t **sect1     = (H5MF_free_section_t **)_sect1; /* File free section */
388
0
    H5MF_free_section_t  *sect2     = (H5MF_free_section_t *)_sect2;  /* File free section */
389
0
    herr_t                ret_value = SUCCEED;                        /* Return value */
390
391
0
    FUNC_ENTER_PACKAGE
392
393
    /* Check arguments. */
394
0
    assert(sect1);
395
0
    assert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
396
0
    assert(sect2);
397
0
    assert(sect2->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
398
0
    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
0
    (*sect1)->sect_info.size += sect2->sect_info.size;
402
403
    /* Get rid of second section */
404
0
    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
0
done:
408
0
    FUNC_LEAVE_NOAPI(ret_value)
409
0
} /* 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
0
{
424
0
    const H5MF_free_section_t *sect  = (const H5MF_free_section_t *)_sect; /* File free section */
425
0
    H5MF_sect_ud_t            *udata = (H5MF_sect_ud_t *)_udata;           /* User data for callback */
426
0
    haddr_t                    eoa;              /* End of address space in the file */
427
0
    haddr_t                    end;              /* End of section to extend */
428
0
    htri_t                     ret_value = FAIL; /* Return value */
429
430
0
    FUNC_ENTER_PACKAGE
431
432
    /* Check arguments. */
433
0
    assert(sect);
434
0
    assert(udata);
435
0
    assert(udata->f);
436
437
    /* Retrieve the end of the file's address space */
438
0
    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
0
    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
0
    if (H5_addr_eq(end, eoa)) {
446
        /* Set the shrinking type */
447
0
        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
0
        HGOTO_DONE(true);
455
0
    } /* end if */
456
0
    else {
457
        /* Shrinking can't occur if the 'eoa_shrink_only' flag is set and we're not shrinking the EOA */
458
0
        if (udata->allow_eoa_shrink_only)
459
0
            HGOTO_DONE(false);
460
461
        /* Check if this section is allowed to merge with metadata aggregation block */
462
0
        if (udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_METADATA) {
463
0
            htri_t status; /* Status from aggregator adjoin */
464
465
            /* See if section can absorb the aggregator & vice versa */
466
0
            if ((status = H5MF__aggr_can_absorb(udata->f, &(udata->f->shared->meta_aggr), sect,
467
0
                                                &(udata->shrink))) < 0)
468
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL,
469
0
                            "error merging section with aggregation block");
470
0
            else if (status > 0) {
471
                /* Set the aggregator to operate on */
472
0
                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
0
                HGOTO_DONE(true);
480
0
            } /* end if */
481
0
        }     /* end if */
482
483
        /* Check if this section is allowed to merge with small 'raw' aggregation block */
484
0
        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
0
    }         /* end else */
506
507
    /* Set return value */
508
0
    ret_value = false;
509
510
0
done:
511
0
    FUNC_LEAVE_NOAPI(ret_value)
512
0
} /* 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
0
{
527
0
    H5MF_free_section_t **sect      = (H5MF_free_section_t **)_sect; /* File free section */
528
0
    H5MF_sect_ud_t       *udata     = (H5MF_sect_ud_t *)_udata;      /* User data for callback */
529
0
    herr_t                ret_value = SUCCEED;                       /* Return value */
530
531
0
    FUNC_ENTER_PACKAGE
532
533
    /* Check arguments. */
534
0
    assert(sect);
535
0
    assert(udata);
536
0
    assert(udata->f);
537
538
    /* Check for shrinking file */
539
0
    if (H5MF_SHRINK_EOA == udata->shrink) {
540
        /* Sanity check */
541
0
        assert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
542
543
        /* Release section's space at EOA */
544
0
        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
0
    } /* end if */
547
0
    else {
548
        /* Sanity check */
549
0
        assert(udata->aggr);
550
551
        /* Absorb the section into the aggregator or vice versa */
552
0
        if (H5MF__aggr_absorb(udata->f, udata->aggr, *sect, udata->allow_sect_absorb) < 0)
553
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL,
554
0
                        "can't absorb section into aggregator or vice versa");
555
0
    } /* end else */
556
557
    /* Check for freeing section */
558
0
    if (udata->shrink != H5MF_SHRINK_SECT_ABSORB_AGGR) {
559
        /* Free section */
560
0
        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
0
        *sect = NULL;
565
0
    } /* end if */
566
567
0
done:
568
0
    FUNC_LEAVE_NOAPI(ret_value)
569
0
} /* 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
0
{
591
0
    H5MF_free_section_t **sect  = (H5MF_free_section_t **)_sect; /* Fractal heap free section */
592
0
    H5MF_sect_ud_t       *udata = (H5MF_sect_ud_t *)_udata;      /* User data for callback */
593
0
    haddr_t               sect_end;
594
0
    hsize_t               rem, prem;
595
0
    herr_t                ret_value = SUCCEED; /* Return value */
596
597
0
    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
0
    if (udata->alloc_type == H5FD_MEM_DRAW || udata->alloc_type == H5FD_MEM_GHEAP)
606
0
        HGOTO_DONE(ret_value);
607
608
0
    sect_end = (*sect)->sect_info.addr + (*sect)->sect_info.size;
609
0
    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
0
    rem  = sect_end % udata->f->shared->fs_page_size;
612
0
    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
0
    if (!rem && (*sect)->sect_info.size <= H5F_PGEND_META_THRES(udata->f) &&
616
0
        (*flags & H5FS_ADD_RETURNED_SPACE)) {
617
0
        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
0
        *sect = NULL;
620
0
        *flags &= (unsigned)~H5FS_ADD_RETURNED_SPACE;
621
0
        *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
0
    }  /* end if */
626
    /* Adjust the section if it is not at page end but its size + prem is at page end */
627
0
    else if (prem <= H5F_PGEND_META_THRES(udata->f)) {
628
0
        (*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
0
    }  /* end if */
634
635
0
done:
636
0
    FUNC_LEAVE_NOAPI(ret_value)
637
0
} /* 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
0
{
655
0
    const H5MF_free_section_t *sect1     = (const H5MF_free_section_t *)_sect1; /* File free section */
656
0
    const H5MF_free_section_t *sect2     = (const H5MF_free_section_t *)_sect2; /* File free section */
657
0
    H5MF_sect_ud_t            *udata     = (H5MF_sect_ud_t *)_udata;            /* User data for callback */
658
0
    htri_t                     ret_value = false;                               /* Return value */
659
660
0
    FUNC_ENTER_PACKAGE_NOERR
661
662
    /* Check arguments. */
663
0
    assert(sect1);
664
0
    assert(sect2);
665
0
    assert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
666
0
    assert(H5_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
667
668
    /* Check if second section adjoins first section */
669
0
    ret_value = H5_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
670
0
    if (ret_value > 0)
671
        /* If they are on different pages, couldn't merge */
672
0
        if ((sect1->sect_info.addr / udata->f->shared->fs_page_size) !=
673
0
            (((sect2->sect_info.addr + sect2->sect_info.size - 1) / udata->f->shared->fs_page_size)))
674
0
            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
0
    FUNC_LEAVE_NOAPI(ret_value)
681
0
} /* 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
0
{
700
0
    H5MF_free_section_t **sect1     = (H5MF_free_section_t **)_sect1; /* File free section */
701
0
    H5MF_free_section_t  *sect2     = (H5MF_free_section_t *)_sect2;  /* File free section */
702
0
    H5MF_sect_ud_t       *udata     = (H5MF_sect_ud_t *)_udata;       /* User data for callback */
703
0
    herr_t                ret_value = SUCCEED;                        /* Return value */
704
705
0
    FUNC_ENTER_PACKAGE
706
707
    /* Check arguments. */
708
0
    assert(sect1);
709
0
    assert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SMALL);
710
0
    assert(sect2);
711
0
    assert(sect2->sect_info.type == H5MF_FSPACE_SECT_SMALL);
712
0
    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
0
    (*sect1)->sect_info.size += sect2->sect_info.size;
716
717
0
    if ((*sect1)->sect_info.size == udata->f->shared->fs_page_size) {
718
0
        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
0
        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
0
        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
0
        *sect1 = NULL;
732
0
    } /* end if */
733
734
    /* Get rid of second section */
735
0
    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
0
done:
739
0
    FUNC_LEAVE_NOAPI(ret_value)
740
0
} /* 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
0
{
762
0
    const H5MF_free_section_t *sect1     = (const H5MF_free_section_t *)_sect1; /* File free section */
763
0
    const H5MF_free_section_t *sect2     = (const H5MF_free_section_t *)_sect2; /* File free section */
764
0
    htri_t                     ret_value = false;                               /* Return value */
765
766
0
    FUNC_ENTER_PACKAGE_NOERR
767
768
    /* Check arguments. */
769
0
    assert(sect1);
770
0
    assert(sect2);
771
0
    assert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
772
0
    assert(H5_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
773
774
0
    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
0
    FUNC_LEAVE_NOAPI(ret_value)
781
0
} /* 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
0
{
835
0
    const H5MF_free_section_t *sect  = (const H5MF_free_section_t *)_sect; /* File free section */
836
0
    H5MF_sect_ud_t            *udata = (H5MF_sect_ud_t *)_udata;           /* User data for callback */
837
0
    haddr_t                    eoa;               /* End of address space in the file */
838
0
    haddr_t                    end;               /* End of section to extend */
839
0
    htri_t                     ret_value = false; /* Return value */
840
841
0
    FUNC_ENTER_PACKAGE
842
843
    /* Check arguments. */
844
0
    assert(sect);
845
0
    assert(sect->sect_info.type == H5MF_FSPACE_SECT_LARGE);
846
0
    assert(udata);
847
0
    assert(udata->f);
848
849
    /* Retrieve the end of the file's address space */
850
0
    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
0
    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
0
    if (H5_addr_eq(end, eoa) && sect->sect_info.size >= udata->f->shared->fs_page_size) {
858
        /* Set the shrinking type */
859
0
        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
0
        HGOTO_DONE(true);
867
0
    } /* end if */
868
869
0
done:
870
0
    FUNC_LEAVE_NOAPI(ret_value)
871
0
} /* 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
0
{
886
0
    H5MF_free_section_t **sect      = (H5MF_free_section_t **)_sect; /* File free section */
887
0
    H5MF_sect_ud_t       *udata     = (H5MF_sect_ud_t *)_udata;      /* User data for callback */
888
0
    hsize_t               frag_size = 0;                             /* Fragment size */
889
0
    herr_t                ret_value = SUCCEED;                       /* Return value */
890
891
0
    FUNC_ENTER_PACKAGE
892
893
    /* Check arguments. */
894
0
    assert(sect);
895
0
    assert((*sect)->sect_info.type == H5MF_FSPACE_SECT_LARGE);
896
0
    assert(udata);
897
0
    assert(udata->f);
898
0
    assert(udata->shrink == H5MF_SHRINK_EOA);
899
0
    assert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
900
0
    assert(H5F_PAGED_AGGR(udata->f));
901
902
    /* Calculate possible mis-aligned fragment */
903
0
    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
0
    if (H5F__free(udata->f, udata->alloc_type, (*sect)->sect_info.addr + frag_size,
908
0
                  (*sect)->sect_info.size - frag_size) < 0)
909
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed");
910
911
0
    if (frag_size) /* Adjust section size for the partial page */
912
0
        (*sect)->sect_info.size = frag_size;
913
0
    else {
914
        /* Free section */
915
0
        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
0
        *sect = NULL;
920
0
    } /* end else */
921
922
0
done:
923
0
    FUNC_LEAVE_NOAPI(ret_value)
924
0
} /* H5MF__sect_large_shrink() */