Coverage Report

Created: 2026-01-08 06:16

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
141
{
185
141
    H5MF_free_section_t *sect;             /* 'Simple' free space section to add */
186
141
    H5MF_free_section_t *ret_value = NULL; /* Return value */
187
188
141
    FUNC_ENTER_PACKAGE
189
190
    /* Check arguments.  */
191
141
    assert(sect_size);
192
193
    /* Create free space section node */
194
141
    if (NULL == (sect = H5FL_MALLOC(H5MF_free_section_t)))
195
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
196
141
                    "memory allocation failed for direct block free list section");
197
198
    /* Set the information passed in */
199
141
    sect->sect_info.addr = sect_off;
200
141
    sect->sect_info.size = sect_size;
201
202
    /* Set the section's class & state */
203
141
    sect->sect_info.type  = ctype;
204
141
    sect->sect_info.state = H5FS_SECT_LIVE;
205
206
    /* Set return value */
207
141
    ret_value = sect;
208
209
141
done:
210
141
    FUNC_LEAVE_NOAPI(ret_value)
211
141
} /* 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
129
{
226
129
    H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; /* File free section */
227
228
129
    FUNC_ENTER_PACKAGE_NOERR
229
230
    /* Check arguments. */
231
129
    assert(sect);
232
233
    /* Release the section */
234
129
    sect = H5FL_FREE(H5MF_free_section_t, sect);
235
236
129
    FUNC_LEAVE_NOAPI(SUCCEED)
237
129
} /* 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
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
93
{
353
93
    const H5MF_free_section_t *sect1     = (const H5MF_free_section_t *)_sect1; /* File free section */
354
93
    const H5MF_free_section_t *sect2     = (const H5MF_free_section_t *)_sect2; /* File free section */
355
93
    htri_t                     ret_value = FAIL;                                /* Return value */
356
357
93
    FUNC_ENTER_PACKAGE_NOERR
358
359
    /* Check arguments. */
360
93
    assert(sect1);
361
93
    assert(sect2);
362
93
    assert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
363
364
    /*
365
     * The library currently doesn't attempt to detect duplicate or overlapping
366
     * free space sections being inserted into the free space managers. Until it
367
     * does so, this assertion must be left out.
368
     */
369
    /* assert(H5_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr)); */
370
371
    /* Check if second section adjoins first section */
372
93
    ret_value = H5_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
373
374
93
    FUNC_LEAVE_NOAPI(ret_value)
375
93
} /* H5MF__sect_simple_can_merge() */
376
377
/*-------------------------------------------------------------------------
378
 * Function:  H5MF__sect_simple_merge
379
 *
380
 * Purpose: Merge two sections of this type
381
 *
382
 * Note:        Second section always merges into first node
383
 *
384
 * Return:  Success:  non-negative
385
 *    Failure:  negative
386
 *
387
 *-------------------------------------------------------------------------
388
 */
389
static herr_t
390
H5MF__sect_simple_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
391
                        void H5_ATTR_UNUSED *_udata)
392
21
{
393
21
    H5MF_free_section_t **sect1     = (H5MF_free_section_t **)_sect1; /* File free section */
394
21
    H5MF_free_section_t  *sect2     = (H5MF_free_section_t *)_sect2;  /* File free section */
395
21
    herr_t                ret_value = SUCCEED;                        /* Return value */
396
397
21
    FUNC_ENTER_PACKAGE
398
399
    /* Check arguments. */
400
21
    assert(sect1);
401
21
    assert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
402
21
    assert(sect2);
403
21
    assert(sect2->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
404
21
    assert(H5_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
405
406
    /* Add second section's size to first section */
407
21
    (*sect1)->sect_info.size += sect2->sect_info.size;
408
409
    /* Get rid of second section */
410
21
    if (H5MF__sect_free((H5FS_section_info_t *)sect2) < 0)
411
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node");
412
413
21
done:
414
21
    FUNC_LEAVE_NOAPI(ret_value)
415
21
} /* H5MF__sect_simple_merge() */
416
417
/*-------------------------------------------------------------------------
418
 * Function:  H5MF__sect_simple_can_shrink
419
 *
420
 * Purpose: Can this section shrink the container?
421
 *
422
 * Return:  Success:  non-negative (true/false)
423
 *    Failure:  negative
424
 *
425
 *-------------------------------------------------------------------------
426
 */
427
static htri_t
428
H5MF__sect_simple_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
429
111
{
430
111
    const H5MF_free_section_t *sect  = (const H5MF_free_section_t *)_sect; /* File free section */
431
111
    H5MF_sect_ud_t            *udata = (H5MF_sect_ud_t *)_udata;           /* User data for callback */
432
111
    haddr_t                    eoa;              /* End of address space in the file */
433
111
    haddr_t                    end;              /* End of section to extend */
434
111
    htri_t                     ret_value = FAIL; /* Return value */
435
436
111
    FUNC_ENTER_PACKAGE
437
438
    /* Check arguments. */
439
111
    assert(sect);
440
111
    assert(udata);
441
111
    assert(udata->f);
442
443
    /* Retrieve the end of the file's address space */
444
111
    if (HADDR_UNDEF == (eoa = H5F_get_eoa(udata->f, udata->alloc_type)))
445
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed");
446
447
    /* Compute address of end of section to check */
448
111
    end = sect->sect_info.addr + sect->sect_info.size;
449
450
    /* Check if the section is exactly at the end of the allocated space in the file */
451
111
    if (H5_addr_eq(end, eoa)) {
452
        /* Set the shrinking type */
453
15
        udata->shrink = H5MF_SHRINK_EOA;
454
#ifdef H5MF_ALLOC_DEBUG_MORE
455
        fprintf(stderr, "%s: section {%" PRIuHADDR ", %" PRIuHSIZE "}, shrinks file, eoa = %" PRIuHADDR "\n",
456
                __func__, sect->sect_info.addr, sect->sect_info.size, eoa);
457
#endif /* H5MF_ALLOC_DEBUG_MORE */
458
459
        /* Indicate shrinking can occur */
460
15
        HGOTO_DONE(true);
461
15
    } /* end if */
462
96
    else {
463
        /* Shrinking can't occur if the 'eoa_shrink_only' flag is set and we're not shrinking the EOA */
464
96
        if (udata->allow_eoa_shrink_only)
465
18
            HGOTO_DONE(false);
466
467
        /* Check if this section is allowed to merge with metadata aggregation block */
468
78
        if (udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_METADATA) {
469
78
            htri_t status; /* Status from aggregator adjoin */
470
471
            /* See if section can absorb the aggregator & vice versa */
472
78
            if ((status = H5MF__aggr_can_absorb(udata->f, &(udata->f->shared->meta_aggr), sect,
473
78
                                                &(udata->shrink))) < 0)
474
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL,
475
78
                            "error merging section with aggregation block");
476
78
            else if (status > 0) {
477
                /* Set the aggregator to operate on */
478
0
                udata->aggr = &(udata->f->shared->meta_aggr);
479
#ifdef H5MF_ALLOC_DEBUG_MORE
480
                fprintf(stderr, "%s: section {%" PRIuHADDR ", %" PRIuHSIZE "}, adjoins metadata aggregator\n",
481
                        __func__, sect->sect_info.addr, sect->sect_info.size);
482
#endif /* H5MF_ALLOC_DEBUG_MORE */
483
484
                /* Indicate shrinking can occur */
485
0
                HGOTO_DONE(true);
486
0
            } /* end if */
487
78
        }     /* end if */
488
489
        /* Check if this section is allowed to merge with small 'raw' aggregation block */
490
78
        if (udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_RAWDATA) {
491
0
            htri_t status; /* Status from aggregator adjoin */
492
493
            /* See if section can absorb the aggregator & vice versa */
494
0
            if ((status = H5MF__aggr_can_absorb(udata->f, &(udata->f->shared->sdata_aggr), sect,
495
0
                                                &(udata->shrink))) < 0)
496
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL,
497
0
                            "error merging section with aggregation block");
498
0
            else if (status > 0) {
499
                /* Set the aggregator to operate on */
500
0
                udata->aggr = &(udata->f->shared->sdata_aggr);
501
#ifdef H5MF_ALLOC_DEBUG_MORE
502
                fprintf(stderr,
503
                        "%s: section {%" PRIuHADDR ", %" PRIuHSIZE "}, adjoins small data aggregator\n",
504
                        __func__, sect->sect_info.addr, sect->sect_info.size);
505
#endif /* H5MF_ALLOC_DEBUG_MORE */
506
507
                /* Indicate shrinking can occur */
508
0
                HGOTO_DONE(true);
509
0
            } /* end if */
510
0
        }     /* end if */
511
78
    }         /* end else */
512
513
    /* Set return value */
514
78
    ret_value = false;
515
516
111
done:
517
111
    FUNC_LEAVE_NOAPI(ret_value)
518
111
} /* H5MF__sect_simple_can_shrink() */
519
520
/*-------------------------------------------------------------------------
521
 * Function:  H5MF__sect_simple_shrink
522
 *
523
 * Purpose: Shrink container with section
524
 *
525
 * Return:  Success:  non-negative
526
 *    Failure:  negative
527
 *
528
 *-------------------------------------------------------------------------
529
 */
530
static herr_t
531
H5MF__sect_simple_shrink(H5FS_section_info_t **_sect, void *_udata)
532
15
{
533
15
    H5MF_free_section_t **sect      = (H5MF_free_section_t **)_sect; /* File free section */
534
15
    H5MF_sect_ud_t       *udata     = (H5MF_sect_ud_t *)_udata;      /* User data for callback */
535
15
    herr_t                ret_value = SUCCEED;                       /* Return value */
536
537
15
    FUNC_ENTER_PACKAGE
538
539
    /* Check arguments. */
540
15
    assert(sect);
541
15
    assert(udata);
542
15
    assert(udata->f);
543
544
    /* Check for shrinking file */
545
15
    if (H5MF_SHRINK_EOA == udata->shrink) {
546
        /* Sanity check */
547
15
        assert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
548
549
        /* Release section's space at EOA */
550
15
        if (H5F__free(udata->f, udata->alloc_type, (*sect)->sect_info.addr, (*sect)->sect_info.size) < 0)
551
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed");
552
15
    } /* end if */
553
0
    else {
554
        /* Sanity check */
555
0
        assert(udata->aggr);
556
557
        /* Absorb the section into the aggregator or vice versa */
558
0
        if (H5MF__aggr_absorb(udata->f, udata->aggr, *sect, udata->allow_sect_absorb) < 0)
559
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL,
560
0
                        "can't absorb section into aggregator or vice versa");
561
0
    } /* end else */
562
563
    /* Check for freeing section */
564
15
    if (udata->shrink != H5MF_SHRINK_SECT_ABSORB_AGGR) {
565
        /* Free section */
566
15
        if (H5MF__sect_free((H5FS_section_info_t *)*sect) < 0)
567
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node");
568
569
        /* Mark section as freed, for free space manager */
570
15
        *sect = NULL;
571
15
    } /* end if */
572
573
15
done:
574
15
    FUNC_LEAVE_NOAPI(ret_value)
575
15
} /* H5MF__sect_simple_shrink() */
576
577
/*
578
 * "small" section callbacks
579
 */
580
581
/*-------------------------------------------------------------------------
582
 * Function:    H5MF__sect_small_add
583
 *
584
 * Purpose:     Perform actions on a small "meta" action before adding it to the free space manager:
585
 *              1) Drop the section if it is at page end and its size <= page end threshold
586
 *              2) Adjust section size to include page end threshold if
587
 *                 (section size + threshold) is at page end
588
 *
589
 * Return:      Success:        non-negative
590
 *              Failure:        negative
591
 *
592
 *-------------------------------------------------------------------------
593
 */
594
static herr_t
595
H5MF__sect_small_add(H5FS_section_info_t **_sect, unsigned *flags, void *_udata)
596
70
{
597
70
    H5MF_free_section_t **sect  = (H5MF_free_section_t **)_sect; /* Fractal heap free section */
598
70
    H5MF_sect_ud_t       *udata = (H5MF_sect_ud_t *)_udata;      /* User data for callback */
599
70
    haddr_t               sect_end;
600
70
    hsize_t               rem, prem;
601
70
    herr_t                ret_value = SUCCEED; /* Return value */
602
603
70
    FUNC_ENTER_PACKAGE
604
605
#ifdef H5MF_ALLOC_DEBUG_MORE
606
    fprintf(stderr, "%s: Entering, section {%" PRIuHADDR ", %" PRIuHSIZE "}\n", __func__,
607
            (*sect)->sect_info.addr, (*sect)->sect_info.size);
608
#endif /* H5MF_ALLOC_DEBUG_MORE */
609
610
    /* Do not adjust the section raw data or global heap data */
611
70
    if (udata->alloc_type == H5FD_MEM_DRAW || udata->alloc_type == H5FD_MEM_GHEAP)
612
0
        HGOTO_DONE(ret_value);
613
614
70
    sect_end = (*sect)->sect_info.addr + (*sect)->sect_info.size;
615
70
    if (0 == udata->f->shared->fs_page_size)
616
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_BADVALUE, FAIL, "page size of zero would result in division by zero");
617
70
    rem  = sect_end % udata->f->shared->fs_page_size;
618
70
    prem = udata->f->shared->fs_page_size - rem;
619
620
    /* Drop the section if it is at page end and its size is <= pgend threshold */
621
70
    if (!rem && (*sect)->sect_info.size <= H5F_PGEND_META_THRES(udata->f) &&
622
12
        (*flags & H5FS_ADD_RETURNED_SPACE)) {
623
12
        if (H5MF__sect_free((H5FS_section_info_t *)(*sect)) < 0)
624
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node");
625
12
        *sect = NULL;
626
12
        *flags &= (unsigned)~H5FS_ADD_RETURNED_SPACE;
627
12
        *flags |= H5FS_PAGE_END_NO_ADD;
628
#ifdef H5MF_ALLOC_DEBUG_MORE
629
        fprintf(stderr, "%s: section is dropped\n", __func__);
630
#endif /* H5MF_ALLOC_DEBUG_MORE */
631
12
    }  /* end if */
632
    /* Adjust the section if it is not at page end but its size + prem is at page end */
633
58
    else if (prem <= H5F_PGEND_META_THRES(udata->f)) {
634
6
        (*sect)->sect_info.size += prem;
635
#ifdef H5MF_ALLOC_DEBUG_MORE
636
        fprintf(stderr, "%s: section is adjusted {%" PRIuHADDR ", %" PRIuHSIZE "}\n", __func__,
637
                (*sect)->sect_info.addr, (*sect)->sect_info.size);
638
#endif /* H5MF_ALLOC_DEBUG_MORE */
639
6
    }  /* end if */
640
641
70
done:
642
70
    FUNC_LEAVE_NOAPI(ret_value)
643
70
} /* H5MF__sect_small_add() */
644
645
/*-------------------------------------------------------------------------
646
 * Function:  H5MF__sect_small_can_merge
647
 *
648
 * Purpose: Can two sections of this type merge?
649
 *
650
 * Note: Second section must be "after" first section
651
 *       The "merged" section cannot cross page boundary.
652
 *
653
 * Return:  Success:  non-negative (true/false)
654
 *          Failure:  negative
655
 *
656
 *-------------------------------------------------------------------------
657
 */
658
static htri_t
659
H5MF__sect_small_can_merge(const H5FS_section_info_t *_sect1, const H5FS_section_info_t *_sect2, void *_udata)
660
13
{
661
13
    const H5MF_free_section_t *sect1     = (const H5MF_free_section_t *)_sect1; /* File free section */
662
13
    const H5MF_free_section_t *sect2     = (const H5MF_free_section_t *)_sect2; /* File free section */
663
13
    H5MF_sect_ud_t            *udata     = (H5MF_sect_ud_t *)_udata;            /* User data for callback */
664
13
    htri_t                     ret_value = false;                               /* Return value */
665
666
13
    FUNC_ENTER_PACKAGE_NOERR
667
668
    /* Check arguments. */
669
13
    assert(sect1);
670
13
    assert(sect2);
671
13
    assert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
672
673
    /*
674
     * The library currently doesn't attempt to detect duplicate or overlapping
675
     * free space sections being inserted into the free space managers. Until it
676
     * does so, this assertion must be left out.
677
     */
678
    /* assert(H5_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr)); */
679
680
    /* Check if second section adjoins first section */
681
13
    ret_value = H5_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
682
13
    if (ret_value > 0)
683
        /* If they are on different pages, couldn't merge */
684
6
        if ((sect1->sect_info.addr / udata->f->shared->fs_page_size) !=
685
6
            (((sect2->sect_info.addr + sect2->sect_info.size - 1) / udata->f->shared->fs_page_size)))
686
0
            ret_value = false;
687
688
#ifdef H5MF_ALLOC_DEBUG_MORE
689
    fprintf(stderr, "%s: Leaving: ret_value = %d\n", __func__, ret_value);
690
#endif /* H5MF_ALLOC_DEBUG_MORE */
691
692
13
    FUNC_LEAVE_NOAPI(ret_value)
693
13
} /* H5MF__sect_small_can_merge() */
694
695
/*-------------------------------------------------------------------------
696
 * Function:  H5MF__sect_small_merge
697
 *
698
 * Purpose: Merge two sections of this type
699
 *
700
 * Note: Second section always merges into first node.
701
 *       If the size of the "merged" section is equal to file space page size,
702
 *       free the section.
703
 *
704
 * Return:  Success:  non-negative
705
 *    Failure:  negative
706
 *
707
 *-------------------------------------------------------------------------
708
 */
709
static herr_t
710
H5MF__sect_small_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2, void *_udata)
711
6
{
712
6
    H5MF_free_section_t **sect1     = (H5MF_free_section_t **)_sect1; /* File free section */
713
6
    H5MF_free_section_t  *sect2     = (H5MF_free_section_t *)_sect2;  /* File free section */
714
6
    H5MF_sect_ud_t       *udata     = (H5MF_sect_ud_t *)_udata;       /* User data for callback */
715
6
    herr_t                ret_value = SUCCEED;                        /* Return value */
716
717
6
    FUNC_ENTER_PACKAGE
718
719
    /* Check arguments. */
720
6
    assert(sect1);
721
6
    assert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SMALL);
722
6
    assert(sect2);
723
6
    assert(sect2->sect_info.type == H5MF_FSPACE_SECT_SMALL);
724
6
    assert(H5_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
725
726
    /* Add second section's size to first section */
727
6
    (*sect1)->sect_info.size += sect2->sect_info.size;
728
729
6
    if ((*sect1)->sect_info.size == udata->f->shared->fs_page_size) {
730
6
        if (H5MF_xfree(udata->f, udata->alloc_type, (*sect1)->sect_info.addr, (*sect1)->sect_info.size) < 0)
731
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free merged section");
732
733
        /* Need to free possible metadata page in the PB cache */
734
        /* This is in response to the data corruption bug from fheap.c with page buffering + page strategy */
735
        /* Note: Large metadata page bypasses the PB cache */
736
        /* Note: Update of raw data page (large or small sized) is handled by the PB cache */
737
6
        if (udata->f->shared->page_buf != NULL && udata->alloc_type != H5FD_MEM_DRAW)
738
0
            if (H5PB_remove_entry(udata->f->shared, (*sect1)->sect_info.addr) < 0)
739
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free merged section");
740
741
6
        if (H5MF__sect_free((H5FS_section_info_t *)(*sect1)) < 0)
742
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node");
743
6
        *sect1 = NULL;
744
6
    } /* end if */
745
746
    /* Get rid of second section */
747
6
    if (H5MF__sect_free((H5FS_section_info_t *)sect2) < 0)
748
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node");
749
750
6
done:
751
6
    FUNC_LEAVE_NOAPI(ret_value)
752
6
} /* H5MF__sect_small_merge() */
753
754
/*
755
 * "Large" section callbacks
756
 */
757
758
/*-------------------------------------------------------------------------
759
 * Function:  H5MF__sect_large_can_merge (same as H5MF__sect_simple_can_merge)
760
 *
761
 * Purpose: Can two sections of this type merge?
762
 *
763
 * Note: Second section must be "after" first section
764
 *
765
 * Return:  Success:  non-negative (true/false)
766
 *          Failure:  negative
767
 *
768
 *-------------------------------------------------------------------------
769
 */
770
static htri_t
771
H5MF__sect_large_can_merge(const H5FS_section_info_t *_sect1, const H5FS_section_info_t *_sect2,
772
                           void H5_ATTR_UNUSED *_udata)
773
6
{
774
6
    const H5MF_free_section_t *sect1     = (const H5MF_free_section_t *)_sect1; /* File free section */
775
6
    const H5MF_free_section_t *sect2     = (const H5MF_free_section_t *)_sect2; /* File free section */
776
6
    htri_t                     ret_value = false;                               /* Return value */
777
778
6
    FUNC_ENTER_PACKAGE_NOERR
779
780
    /* Check arguments. */
781
6
    assert(sect1);
782
6
    assert(sect2);
783
6
    assert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
784
785
    /*
786
     * The library currently doesn't attempt to detect duplicate or overlapping
787
     * free space sections being inserted into the free space managers. Until it
788
     * does so, this assertion must be left out.
789
     */
790
    /* assert(H5_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr)); */
791
792
6
    ret_value = H5_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
793
794
#ifdef H5MF_ALLOC_DEBUG_MORE
795
    fprintf(stderr, "%s: Leaving: ret_value = %d\n", __func__, ret_value);
796
#endif /* H5MF_ALLOC_DEBUG_MORE */
797
798
6
    FUNC_LEAVE_NOAPI(ret_value)
799
6
} /* H5MF__sect_large_can_merge() */
800
801
/*-------------------------------------------------------------------------
802
 * Function:  H5MF__sect_large_merge (same as H5MF__sect_simple_merge)
803
 *
804
 * Purpose: Merge two sections of this type
805
 *
806
 * Note: Second section always merges into first node
807
 *
808
 * Return:  Success:  non-negative
809
 *          Failure:  negative
810
 *
811
 *-------------------------------------------------------------------------
812
 */
813
static herr_t
814
H5MF__sect_large_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
815
0
{
816
0
    H5MF_free_section_t **sect1     = (H5MF_free_section_t **)_sect1; /* File free section */
817
0
    H5MF_free_section_t  *sect2     = (H5MF_free_section_t *)_sect2;  /* File free section */
818
0
    herr_t                ret_value = SUCCEED;                        /* Return value */
819
820
0
    FUNC_ENTER_PACKAGE
821
822
    /* Check arguments. */
823
0
    assert(sect1);
824
0
    assert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_LARGE);
825
0
    assert(sect2);
826
0
    assert(sect2->sect_info.type == H5MF_FSPACE_SECT_LARGE);
827
0
    assert(H5_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
828
829
    /* Add second section's size to first section */
830
0
    (*sect1)->sect_info.size += sect2->sect_info.size;
831
832
    /* Get rid of second section */
833
0
    if (H5MF__sect_free((H5FS_section_info_t *)sect2) < 0)
834
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node");
835
836
0
done:
837
0
    FUNC_LEAVE_NOAPI(ret_value)
838
0
} /* H5MF__sect_large_merge() */
839
840
/*-------------------------------------------------------------------------
841
 * Function:  H5MF__sect_large_can_shrink
842
 *
843
 * Purpose: Can this section shrink the container?
844
 *
845
 * Return:  Success:  non-negative (true/false)
846
 *          Failure:  negative
847
 *
848
 *-------------------------------------------------------------------------
849
 */
850
static htri_t
851
H5MF__sect_large_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
852
44
{
853
44
    const H5MF_free_section_t *sect  = (const H5MF_free_section_t *)_sect; /* File free section */
854
44
    H5MF_sect_ud_t            *udata = (H5MF_sect_ud_t *)_udata;           /* User data for callback */
855
44
    haddr_t                    eoa;               /* End of address space in the file */
856
44
    haddr_t                    end;               /* End of section to extend */
857
44
    htri_t                     ret_value = false; /* Return value */
858
859
44
    FUNC_ENTER_PACKAGE
860
861
    /* Check arguments. */
862
44
    assert(sect);
863
44
    assert(sect->sect_info.type == H5MF_FSPACE_SECT_LARGE);
864
44
    assert(udata);
865
44
    assert(udata->f);
866
867
    /* Retrieve the end of the file's address space */
868
44
    if (HADDR_UNDEF == (eoa = H5FD_get_eoa(udata->f->shared->lf, udata->alloc_type)))
869
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed");
870
871
    /* Compute address of end of section to check */
872
44
    end = sect->sect_info.addr + sect->sect_info.size;
873
874
    /* Check if the section is exactly at the end of the allocated space in the file */
875
44
    if (H5_addr_eq(end, eoa) && sect->sect_info.size >= udata->f->shared->fs_page_size) {
876
        /* Set the shrinking type */
877
6
        udata->shrink = H5MF_SHRINK_EOA;
878
#ifdef H5MF_ALLOC_DEBUG_MORE
879
        fprintf(stderr, "%s: section {%" PRIuHADDR ", %" PRIuHSIZE "}, shrinks file, eoa = %" PRIuHADDR "\n",
880
                __func__, sect->sect_info.addr, sect->sect_info.size, eoa);
881
#endif /* H5MF_ALLOC_DEBUG_MORE */
882
883
        /* Indicate shrinking can occur */
884
6
        HGOTO_DONE(true);
885
6
    } /* end if */
886
887
44
done:
888
44
    FUNC_LEAVE_NOAPI(ret_value)
889
44
} /* H5MF__sect_large_can_shrink() */
890
891
/*-------------------------------------------------------------------------
892
 * Function:  H5MF__sect_large_shrink
893
 *
894
 * Purpose:     Shrink a large-sized section
895
 *
896
 * Return:      Success:  non-negative
897
 *              Failure:  negative
898
 *
899
 *-------------------------------------------------------------------------
900
 */
901
static herr_t
902
H5MF__sect_large_shrink(H5FS_section_info_t **_sect, void *_udata)
903
6
{
904
6
    H5MF_free_section_t **sect      = (H5MF_free_section_t **)_sect; /* File free section */
905
6
    H5MF_sect_ud_t       *udata     = (H5MF_sect_ud_t *)_udata;      /* User data for callback */
906
6
    hsize_t               frag_size = 0;                             /* Fragment size */
907
6
    herr_t                ret_value = SUCCEED;                       /* Return value */
908
909
6
    FUNC_ENTER_PACKAGE
910
911
    /* Check arguments. */
912
6
    assert(sect);
913
6
    assert((*sect)->sect_info.type == H5MF_FSPACE_SECT_LARGE);
914
6
    assert(udata);
915
6
    assert(udata->f);
916
6
    assert(udata->shrink == H5MF_SHRINK_EOA);
917
6
    assert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
918
6
    assert(H5F_PAGED_AGGR(udata->f));
919
920
    /* Calculate possible mis-aligned fragment */
921
6
    H5MF_EOA_MISALIGN(udata->f, (*sect)->sect_info.addr, udata->f->shared->fs_page_size, frag_size);
922
923
    /* Free full pages from EOA */
924
    /* Retain partial page in the free-space manager so as to keep EOA at page boundary */
925
6
    if (H5F__free(udata->f, udata->alloc_type, (*sect)->sect_info.addr + frag_size,
926
6
                  (*sect)->sect_info.size - frag_size) < 0)
927
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed");
928
929
6
    if (frag_size) /* Adjust section size for the partial page */
930
0
        (*sect)->sect_info.size = frag_size;
931
6
    else {
932
        /* Free section */
933
6
        if (H5MF__sect_free((H5FS_section_info_t *)*sect) < 0)
934
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node");
935
936
        /* Mark section as freed, for free space manager */
937
6
        *sect = NULL;
938
6
    } /* end else */
939
940
6
done:
941
6
    FUNC_LEAVE_NOAPI(ret_value)
942
6
} /* H5MF__sect_large_shrink() */