Coverage Report

Created: 2026-04-12 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5MFaggr.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: Routines for aggregating free space allocations
15
 */
16
17
/****************/
18
/* Module Setup */
19
/****************/
20
21
#define H5F_FRIEND      /*suppress error about including H5Fpkg   */
22
#include "H5MFmodule.h" /* This source code file is part of the H5MF module */
23
24
/***********/
25
/* Headers */
26
/***********/
27
#include "H5private.h"  /* Generic Functions      */
28
#include "H5Eprivate.h" /* Error handling       */
29
#include "H5Fpkg.h"     /* File access        */
30
#include "H5MFpkg.h"    /* File memory management   */
31
32
/****************/
33
/* Local Macros */
34
/****************/
35
36
/******************/
37
/* Local Typedefs */
38
/******************/
39
0
#define EXTEND_THRESHOLD 0.10F
40
41
/********************/
42
/* Package Typedefs */
43
/********************/
44
45
/********************/
46
/* Local Prototypes */
47
/********************/
48
static herr_t  H5MF__aggr_free(H5F_t *f, H5FD_mem_t type, H5F_blk_aggr_t *aggr);
49
static haddr_t H5MF__aggr_alloc(H5F_t *f, H5F_blk_aggr_t *aggr, H5F_blk_aggr_t *other_aggr, H5FD_mem_t type,
50
                                hsize_t size);
51
static herr_t  H5MF__aggr_reset(H5F_t *f, H5F_blk_aggr_t *aggr);
52
static htri_t  H5MF__aggr_can_shrink_eoa(H5F_t *f, H5FD_mem_t type, H5F_blk_aggr_t *aggr);
53
54
/*********************/
55
/* Package Variables */
56
/*********************/
57
58
/*****************************/
59
/* Library Private Variables */
60
/*****************************/
61
62
/*******************/
63
/* Local Variables */
64
/*******************/
65
66
/*-------------------------------------------------------------------------
67
 * Function:    H5MF_aggr_vfd_alloc
68
 *
69
 * Purpose:     Allocate SIZE bytes of file memory via H5MF__aggr_alloc()
70
 *    and return the relative address where that contiguous chunk
71
 *    of file memory exists.
72
 *    The TYPE argument describes the purpose for which the storage
73
 *    is being requested.
74
 *
75
 * Return:      Success:        The file address of new chunk.
76
 *              Failure:        HADDR_UNDEF
77
 *
78
 *-------------------------------------------------------------------------
79
 */
80
haddr_t
81
H5MF_aggr_vfd_alloc(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size)
82
26
{
83
26
    haddr_t ret_value = HADDR_UNDEF; /* Return value */
84
85
26
    FUNC_ENTER_NOAPI(HADDR_UNDEF)
86
#ifdef H5MF_AGGR_DEBUG
87
    fprintf(stderr, "%s: alloc_type = %u, size = %" PRIuHSIZE "\n", __func__, (unsigned)alloc_type, size);
88
#endif /* H5MF_AGGR_DEBUG */
89
90
    /* check arguments */
91
26
    assert(f);
92
26
    assert(f->shared);
93
26
    assert(f->shared->lf);
94
26
    assert(size > 0);
95
96
    /* Couldn't find anything from the free space manager, go allocate some */
97
26
    if (alloc_type != H5FD_MEM_DRAW && alloc_type != H5FD_MEM_GHEAP) {
98
        /* Handle metadata differently from "raw" data */
99
26
        if (HADDR_UNDEF == (ret_value = H5MF__aggr_alloc(f, &(f->shared->meta_aggr), &(f->shared->sdata_aggr),
100
26
                                                         alloc_type, size)))
101
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate metadata");
102
26
    } /* end if */
103
0
    else {
104
        /* Allocate "raw" data: H5FD_MEM_DRAW and H5FD_MEM_GHEAP */
105
0
        if (HADDR_UNDEF == (ret_value = H5MF__aggr_alloc(f, &(f->shared->sdata_aggr), &(f->shared->meta_aggr),
106
0
                                                         H5FD_MEM_DRAW, size)))
107
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate raw data");
108
0
    } /* end else */
109
110
    /* Sanity check for overlapping into file's temporary allocation space */
111
26
    assert(H5_addr_le((ret_value + size), f->shared->tmp_addr));
112
113
26
done:
114
#ifdef H5MF_AGGR_DEBUG
115
    fprintf(stderr, "%s: Leaving: ret_value = %" PRIuHADDR ", size = %" PRIuHSIZE "\n", __func__, ret_value,
116
            size);
117
#endif /* H5MF_AGGR_DEBUG */
118
119
26
    FUNC_LEAVE_NOAPI(ret_value)
120
26
} /* end H5MF_aggr_vfd_alloc() */
121
122
/*-------------------------------------------------------------------------
123
 * Function:    H5MF__aggr_alloc
124
 *
125
 * Purpose:     Try to allocate SIZE bytes of memory from an aggregator
126
 *              block if possible.
127
 *
128
 * Return:      Success:    The format address of the new file memory.
129
 *              Failure:    The undefined address HADDR_UNDEF
130
 *
131
 *-------------------------------------------------------------------------
132
 */
133
static haddr_t
134
H5MF__aggr_alloc(H5F_t *f, H5F_blk_aggr_t *aggr, H5F_blk_aggr_t *other_aggr, H5FD_mem_t type, hsize_t size)
135
26
{
136
26
    haddr_t eoa_frag_addr = HADDR_UNDEF; /* Address of fragment at EOA */
137
26
    hsize_t eoa_frag_size = 0;           /* Size of fragment at EOA */
138
26
    haddr_t eoa           = HADDR_UNDEF; /* Initial EOA for the file */
139
26
    haddr_t ret_value     = HADDR_UNDEF; /* Return value */
140
141
26
    FUNC_ENTER_PACKAGE
142
#ifdef H5MF_AGGR_DEBUG
143
    fprintf(stderr, "%s: type = %u, size = %" PRIuHSIZE "\n", __func__, (unsigned)type, size);
144
#endif /* H5MF_AGGR_DEBUG */
145
146
    /* check args */
147
26
    assert(f);
148
26
    assert(aggr);
149
26
    assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
150
26
           aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
151
26
    assert(other_aggr);
152
26
    assert(other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
153
26
           other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
154
26
    assert(other_aggr->feature_flag != aggr->feature_flag);
155
26
    assert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
156
26
    assert(size > 0);
157
158
    /* Get the EOA for the file */
159
26
    if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, type)))
160
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "Unable to get eoa");
161
162
    /*
163
     * If the aggregation feature is enabled for this file and strategy is not H5F_FILE_SPACE_NONE,
164
     * allocate "generic" space and sub-allocate out of that, if possible.
165
     * Otherwise just allocate through H5F__alloc().
166
     */
167
168
    /*
169
     * Replace the following line with the line in #ifdef REPLACE/#endif.
170
     * The line in #ifdef REPLACE triggers the following problem:
171
     *   test/objcopy.c: test_copy_group_deep() test fails with the family driver
172
     *
173
     * When closing the destination file after H5Ocopy, the library flushes the fractal
174
     * heap direct block via H5HF__cache_dblock_pre_serialize().  While doing so,
175
     * the cache eventually adjusts/evicts ageout entries and ends up flushing out the
176
     * same entry that is being serialized (flush_in_progress).
177
     */
178
26
    if ((f->shared->feature_flags & aggr->feature_flag) &&
179
26
        f->shared->fs_strategy != H5F_FSPACE_STRATEGY_NONE &&
180
26
        (!f->shared->closing || !f->shared->fs_persist)) {
181
#ifdef REPLACE
182
        if ((f->shared->feature_flags & aggr->feature_flag) &&
183
            f->shared->fs_strategy != H5F_FSPACE_STRATEGY_NONE && !f->shared->closing) {
184
#endif
185
14
            haddr_t    aggr_frag_addr = HADDR_UNDEF; /* Address of aggregator fragment */
186
14
            hsize_t    aggr_frag_size = 0;           /* Size of aggregator fragment */
187
14
            hsize_t    alignment;                    /* Alignment of this section */
188
14
            hsize_t    aggr_mis_align = 0;           /* Misalignment of aggregator */
189
14
            H5FD_mem_t alloc_type, other_alloc_type; /* Current aggregator & 'other' aggregator types */
190
191
#ifdef H5MF_AGGR_DEBUG
192
            fprintf(stderr, "%s: aggr = {%" PRIuHADDR ", %" PRIuHSIZE ", %" PRIuHSIZE "}\n", __func__,
193
                    aggr->addr, aggr->tot_size, aggr->size);
194
#endif /* H5MF_AGGR_DEBUG */
195
196
            /* Turn off alignment if allocation < threshold */
197
14
            alignment = H5F_ALIGNMENT(f);
198
14
            if (!((alignment > 1) && (size >= H5F_THRESHOLD(f))))
199
14
                alignment = 0; /* no alignment */
200
201
            /* Generate fragment if aggregator is mis-aligned */
202
14
            if (alignment && H5_addr_gt(aggr->addr, 0) &&
203
0
                (aggr_mis_align = (aggr->addr + H5F_BASE_ADDR(f)) % alignment)) {
204
0
                aggr_frag_addr = aggr->addr;
205
0
                aggr_frag_size = alignment - aggr_mis_align;
206
0
            } /* end if */
207
208
14
            alloc_type =
209
14
                aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW;
210
14
            other_alloc_type =
211
14
                other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW;
212
213
            /* Check if the space requested is larger than the space left in the block */
214
14
            if ((size + aggr_frag_size) > aggr->size) {
215
14
                htri_t extended = false; /* Whether the file was extended */
216
217
                /* Check if the block asked for is too large for 'normal' aggregator block */
218
14
                if (size >= aggr->alloc_size) {
219
0
                    hsize_t ext_size = size + aggr_frag_size;
220
221
                    /* Check for overlapping into file's temporary allocation space */
222
0
                    if (H5_addr_gt((aggr->addr + aggr->size + ext_size), f->shared->tmp_addr))
223
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, HADDR_UNDEF,
224
0
                                    "'normal' file space allocation request will overlap into 'temporary' "
225
0
                                    "file space");
226
227
0
                    if ((aggr->addr > 0) &&
228
0
                        (extended = H5F__try_extend(f, alloc_type, (aggr->addr + aggr->size), ext_size)) < 0)
229
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't extending space");
230
0
                    else if (extended) {
231
                        /* aggr->size is unchanged */
232
0
                        ret_value = aggr->addr + aggr_frag_size;
233
0
                        aggr->addr += ext_size;
234
0
                        aggr->tot_size += ext_size;
235
0
                    }
236
0
                    else {
237
                        /* Release "other" aggregator, if it exists, is at the end of the allocated space,
238
                         * has allocated more than one block and the unallocated space is greater than its
239
                         * allocation block size.
240
                         */
241
0
                        if ((other_aggr->size > 0) &&
242
0
                            (H5_addr_eq((other_aggr->addr + other_aggr->size), eoa)) &&
243
0
                            (other_aggr->tot_size > other_aggr->size) &&
244
0
                            ((other_aggr->tot_size - other_aggr->size) >= other_aggr->alloc_size)) {
245
0
                            if (H5MF__aggr_free(f, other_alloc_type, other_aggr) < 0)
246
0
                                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF,
247
0
                                            "can't free aggregation block");
248
0
                        } /* end if */
249
250
                        /* Allocate space from the VFD (i.e. at the end of the file) */
251
0
                        if (HADDR_UNDEF ==
252
0
                            (ret_value = H5F__alloc(f, alloc_type, size, &eoa_frag_addr, &eoa_frag_size)))
253
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF,
254
0
                                        "can't allocate file space");
255
0
                    } /* end else */
256
0
                }     /* end if */
257
14
                else {
258
14
                    hsize_t ext_size = aggr->alloc_size;
259
260
                    /* Allocate another block */
261
#ifdef H5MF_AGGR_DEBUG
262
                    fprintf(stderr, "%s: Allocating block\n", __func__);
263
#endif /* H5MF_AGGR_DEBUG */
264
265
14
                    if (aggr_frag_size > (ext_size - size))
266
0
                        ext_size += (aggr_frag_size - (ext_size - size));
267
268
                    /* Check for overlapping into file's temporary allocation space */
269
14
                    if (H5_addr_gt((aggr->addr + aggr->size + ext_size), f->shared->tmp_addr))
270
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, HADDR_UNDEF,
271
14
                                    "'normal' file space allocation request will overlap into 'temporary' "
272
14
                                    "file space");
273
274
14
                    if ((aggr->addr > 0) &&
275
0
                        (extended = H5F__try_extend(f, alloc_type, (aggr->addr + aggr->size), ext_size)) < 0)
276
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't extending space");
277
14
                    else if (extended) {
278
0
                        aggr->addr += aggr_frag_size;
279
0
                        aggr->size += (ext_size - aggr_frag_size);
280
0
                        aggr->tot_size += ext_size;
281
0
                    } /* end else-if */
282
14
                    else {
283
14
                        haddr_t new_space; /* Address of new space allocated */
284
285
                        /* Release "other" aggregator, if it exists, is at the end of the allocated space,
286
                         * has allocated more than one block and the unallocated space is greater than its
287
                         * allocation block size.
288
                         */
289
14
                        if ((other_aggr->size > 0) &&
290
0
                            (H5_addr_eq((other_aggr->addr + other_aggr->size), eoa)) &&
291
0
                            (other_aggr->tot_size > other_aggr->size) &&
292
0
                            ((other_aggr->tot_size - other_aggr->size) >= other_aggr->alloc_size)) {
293
0
                            if (H5MF__aggr_free(f, other_alloc_type, other_aggr) < 0)
294
0
                                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF,
295
0
                                            "can't free aggregation block");
296
0
                        } /* end if */
297
298
                        /* Allocate space from the VFD (i.e. at the end of the file) */
299
14
                        if (HADDR_UNDEF == (new_space = H5F__alloc(f, alloc_type, aggr->alloc_size,
300
14
                                                                   &eoa_frag_addr, &eoa_frag_size)))
301
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF,
302
14
                                        "can't allocate file space");
303
304
                        /* Return the unused portion of the block to a free list */
305
14
                        if (aggr->size > 0)
306
0
                            if (H5MF_xfree(f, alloc_type, aggr->addr, aggr->size) < 0)
307
0
                                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF,
308
14
                                            "can't free aggregation block");
309
310
                        /* If the block is not to be aligned, fold the eoa fragment
311
                         * into the newly allocated aggregator, as it could have
312
                         * been allocated in an aligned manner if the aggregator
313
                         * block is larger than the threshold */
314
14
                        if (eoa_frag_size && !alignment) {
315
0
                            assert(eoa_frag_addr + eoa_frag_size == new_space);
316
0
                            aggr->addr     = eoa_frag_addr;
317
0
                            aggr->size     = aggr->alloc_size + eoa_frag_size;
318
0
                            aggr->tot_size = aggr->size;
319
320
                            /* Reset EOA fragment */
321
0
                            eoa_frag_addr = HADDR_UNDEF;
322
0
                            eoa_frag_size = 0;
323
0
                        } /* end if */
324
14
                        else {
325
                            /* Point the aggregator at the newly allocated block */
326
14
                            aggr->addr     = new_space;
327
14
                            aggr->size     = aggr->alloc_size;
328
14
                            aggr->tot_size = aggr->alloc_size;
329
14
                        } /* end else */
330
14
                    }     /* end else */
331
332
                    /* Allocate space out of the metadata block */
333
14
                    ret_value = aggr->addr;
334
14
                    aggr->size -= size;
335
14
                    aggr->addr += size;
336
14
                } /* end else */
337
338
                /* Freeing any possible fragment due to file allocation */
339
14
                if (eoa_frag_size)
340
0
                    if (H5MF_xfree(f, alloc_type, eoa_frag_addr, eoa_frag_size) < 0)
341
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free eoa fragment");
342
343
                /* Freeing any possible fragment due to alignment in the block after extension */
344
14
                if (extended && aggr_frag_size)
345
0
                    if (H5MF_xfree(f, alloc_type, aggr_frag_addr, aggr_frag_size) < 0)
346
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF,
347
14
                                    "can't free aggregation fragment");
348
14
            } /* end if */
349
0
            else {
350
                /* Allocate space out of the block */
351
0
                ret_value = aggr->addr + aggr_frag_size;
352
0
                aggr->size -= (size + aggr_frag_size);
353
0
                aggr->addr += (size + aggr_frag_size);
354
355
                /* free any possible fragment */
356
0
                if (aggr_frag_size)
357
0
                    if (H5MF_xfree(f, alloc_type, aggr_frag_addr, aggr_frag_size) < 0)
358
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF,
359
0
                                    "can't free aggregation fragment");
360
0
            } /* end else */
361
14
        }     /* end if */
362
12
        else {
363
            /* Allocate data from the file */
364
12
            if (HADDR_UNDEF == (ret_value = H5F__alloc(f, type, size, &eoa_frag_addr, &eoa_frag_size)))
365
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space");
366
367
            /* Check if fragment was generated */
368
12
            if (eoa_frag_size)
369
                /* Put fragment on the free list */
370
0
                if (H5MF_xfree(f, type, eoa_frag_addr, eoa_frag_size) < 0)
371
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free eoa fragment");
372
12
        } /* end else */
373
374
        /* Sanity check for overlapping into file's temporary allocation space */
375
26
        assert(H5_addr_le((ret_value + size), f->shared->tmp_addr));
376
377
        /* Post-condition sanity check */
378
26
        if (H5F_ALIGNMENT(f) && size >= H5F_THRESHOLD(f))
379
26
            assert(!((ret_value + H5FD_get_base_addr(f->shared->lf)) % H5F_ALIGNMENT(f)));
380
381
26
done:
382
#ifdef H5MF_AGGR_DEBUG
383
        fprintf(stderr, "%s: ret_value = %" PRIuHADDR "\n", __func__, ret_value);
384
#endif /* H5MF_AGGR_DEBUG */
385
26
        FUNC_LEAVE_NOAPI(ret_value)
386
26
    } /* end H5MF__aggr_alloc() */
387
388
    /*-------------------------------------------------------------------------
389
     * Function:    H5MF__aggr_try_extend
390
     *
391
     * Purpose: Check if a block is inside an aggregator block and extend it
392
     *              if possible.
393
     *
394
     * Note:
395
     *          When the block to be extended adjoins the aggregator--
396
     *        1) When the aggregator is at end of file:
397
     *           A) If the request is below the threshold, extend the block into the aggregator
398
     *           B) If the request is above the threshold,
399
     *          a) extend the aggregator by aggr->alloc_size or the extended amount
400
     *          b) extend the block into the aggregator
401
     *        2) When the aggregator is not at end of file:
402
     *           Extended the block into the aggregator if it has enough space to satisfy the request
403
     *
404
     * Return:  Success:  true(1)  - Block was extended
405
     *                              false(0) - Block could not be extended
406
     *    Failure:  FAIL
407
     *
408
     *-------------------------------------------------------------------------
409
     */
410
    htri_t H5MF__aggr_try_extend(H5F_t * f, H5F_blk_aggr_t * aggr, H5FD_mem_t type, haddr_t blk_end,
411
                                 hsize_t extra_requested)
412
19
    {
413
19
        htri_t ret_value = false; /* Return value */
414
415
19
        FUNC_ENTER_PACKAGE
416
417
        /* Check args */
418
19
        assert(f);
419
19
        assert(aggr);
420
19
        assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
421
19
               aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
422
423
        /* Check if this aggregator is active */
424
19
        if (f->shared->feature_flags & aggr->feature_flag) {
425
            /*
426
             * If the block being tested adjoins the beginning of the aggregator
427
             *      block, check if the aggregator can accommodate the extension.
428
             */
429
19
            if (H5_addr_eq(blk_end, aggr->addr)) {
430
0
                haddr_t eoa; /* EOA for the file */
431
432
                /* Get the EOA for the file */
433
0
                if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, type)))
434
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa");
435
436
                /* If the aggregator is at the end of file: */
437
0
                if (H5_addr_eq(eoa, aggr->addr + aggr->size)) {
438
                    /* If extra_requested is below percentage threshold, extend block into the aggregator. */
439
0
                    if (extra_requested <= (hsize_t)(EXTEND_THRESHOLD * (float)aggr->size)) {
440
0
                        aggr->size -= extra_requested;
441
0
                        aggr->addr += extra_requested;
442
443
                        /* Indicate success */
444
0
                        HGOTO_DONE(true);
445
0
                    } /* end if */
446
                    /*
447
                     * If extra_requested is above percentage threshold:
448
                     * 1) "bubble" up the aggregator by aggr->alloc_size or extra_requested
449
                     * 2) extend the block into the aggregator
450
                     */
451
0
                    else {
452
0
                        hsize_t extra =
453
0
                            (extra_requested < aggr->alloc_size) ? aggr->alloc_size : extra_requested;
454
455
0
                        if ((ret_value = H5F__try_extend(f, type, (aggr->addr + aggr->size), extra)) < 0)
456
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file");
457
0
                        else if (ret_value == true) {
458
                            /* Shift the aggregator block by the extra requested */
459
                            /* (allocates the space for the extra_requested) */
460
0
                            aggr->addr += extra_requested;
461
462
                            /* Add extra to the aggregator's total allocated amount */
463
0
                            aggr->tot_size += extra;
464
465
                            /* Account for any space added to the aggregator */
466
                            /* (either 0 (if extra_requested > aggr->alloc_size) or
467
                             *      (aggr->alloc_size - extra_requested) -QAK
468
                             */
469
0
                            aggr->size += extra;
470
0
                            aggr->size -= extra_requested;
471
0
                        } /* end else-if */
472
0
                    }     /* end else */
473
0
                }         /* end if */
474
0
                else {
475
                    /* The aggregator is not at end of file */
476
                    /* Check if aggregator has enough internal space to satisfy the extension. */
477
0
                    if (aggr->size >= extra_requested) {
478
                        /* Extend block into aggregator */
479
0
                        aggr->size -= extra_requested;
480
0
                        aggr->addr += extra_requested;
481
482
                        /* Indicate success */
483
0
                        HGOTO_DONE(true);
484
0
                    } /* end if */
485
0
                }     /* end else */
486
0
            }         /* end if */
487
19
        }             /* end if */
488
489
19
done:
490
19
        FUNC_LEAVE_NOAPI(ret_value)
491
19
    } /* end H5MF__aggr_try_extend() */
492
493
    /*-------------------------------------------------------------------------
494
     * Function:    H5MF__aggr_can_absorb
495
     *
496
     * Purpose: Check if a section adjoins an aggregator block and one can
497
     *              absorb the other.
498
     *
499
     * Return:  Success:  true(1)  - Section or aggregator can be absorbed
500
     *                              false(0) - Section and aggregator can not be absorbed
501
     *    Failure:  FAIL
502
     *
503
     *-------------------------------------------------------------------------
504
     */
505
    htri_t H5MF__aggr_can_absorb(const H5F_t *f, const H5F_blk_aggr_t *aggr, const H5MF_free_section_t *sect,
506
                                 H5MF_shrink_type_t *shrink)
507
58
    {
508
58
        htri_t ret_value = false; /* Return value */
509
510
58
        FUNC_ENTER_PACKAGE_NOERR
511
512
        /* Check args */
513
58
        assert(f);
514
58
        assert(aggr);
515
58
        assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
516
58
               aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
517
58
        assert(sect);
518
58
        assert(shrink);
519
520
        /* Check if this aggregator is active */
521
58
        if (f->shared->feature_flags & aggr->feature_flag) {
522
            /* Check if the block adjoins the beginning or end of the aggregator */
523
58
            if (H5_addr_eq((sect->sect_info.addr + sect->sect_info.size), aggr->addr) ||
524
58
                H5_addr_eq((aggr->addr + aggr->size), sect->sect_info.addr)) {
525
#ifdef H5MF_AGGR_DEBUG
526
                fprintf(stderr,
527
                        "%s: section {%" PRIuHADDR ", %" PRIuHSIZE "} adjoins aggr = {%" PRIuHADDR
528
                        ", %" PRIuHSIZE "}\n",
529
                        "H5MF__aggr_can_absorb", sect->sect_info.addr, sect->sect_info.size, aggr->addr,
530
                        aggr->size);
531
#endif /* H5MF_AGGR_DEBUG */
532
                /* Check if aggregator would get too large and should be absorbed into section */
533
0
                if ((aggr->size + sect->sect_info.size) >= aggr->alloc_size)
534
0
                    *shrink = H5MF_SHRINK_SECT_ABSORB_AGGR;
535
0
                else
536
0
                    *shrink = H5MF_SHRINK_AGGR_ABSORB_SECT;
537
538
                /* Indicate success */
539
0
                HGOTO_DONE(true);
540
0
            } /* end if */
541
58
        }     /* end if */
542
543
58
done:
544
58
        FUNC_LEAVE_NOAPI(ret_value)
545
58
    } /* end H5MF__aggr_can_absorb() */
546
547
    /*-------------------------------------------------------------------------
548
     * Function:    H5MF__aggr_absorb
549
     *
550
     * Purpose: Absorb a free space section into an aggregator block or
551
     *              vice versa.
552
     *
553
     * Return:      Success:        Non-negative
554
     *              Failure:        Negative
555
     *
556
     *-------------------------------------------------------------------------
557
     */
558
    herr_t H5MF__aggr_absorb(const H5F_t H5_ATTR_UNUSED *f, H5F_blk_aggr_t *aggr, H5MF_free_section_t *sect,
559
                             bool allow_sect_absorb)
560
0
    {
561
0
        FUNC_ENTER_PACKAGE_NOERR
562
563
        /* Check args */
564
0
        assert(f);
565
0
        assert(aggr);
566
0
        assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
567
0
               aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
568
0
        assert(f->shared->feature_flags & aggr->feature_flag);
569
0
        assert(sect);
570
571
        /* Check if aggregator would get too large and should be absorbed into section */
572
0
        if ((aggr->size + sect->sect_info.size) >= aggr->alloc_size && allow_sect_absorb) {
573
            /* Check if the section adjoins the beginning or end of the aggregator */
574
0
            if (H5_addr_eq((sect->sect_info.addr + sect->sect_info.size), aggr->addr)) {
575
#ifdef H5MF_AGGR_DEBUG
576
                fprintf(stderr,
577
                        "%s: aggr {%" PRIuHADDR ", %" PRIuHSIZE "} adjoins front of section = {%" PRIuHADDR
578
                        ", %" PRIuHSIZE "}\n",
579
                        "H5MF__aggr_absorb", aggr->addr, aggr->size, sect->sect_info.addr,
580
                        sect->sect_info.size);
581
#endif /* H5MF_AGGR_DEBUG */
582
                /* Absorb aggregator onto end of section */
583
0
                sect->sect_info.size += aggr->size;
584
0
            } /* end if */
585
0
            else {
586
                /* Sanity check */
587
0
                assert(H5_addr_eq((aggr->addr + aggr->size), sect->sect_info.addr));
588
589
#ifdef H5MF_AGGR_DEBUG
590
                fprintf(stderr,
591
                        "%s: aggr {%" PRIuHADDR ", %" PRIuHSIZE "} adjoins end of section = {%" PRIuHADDR
592
                        ", %" PRIuHSIZE "}\n",
593
                        "H5MF__aggr_absorb", aggr->addr, aggr->size, sect->sect_info.addr,
594
                        sect->sect_info.size);
595
#endif /* H5MF_AGGR_DEBUG */
596
                /* Absorb aggregator onto beginning of section */
597
0
                sect->sect_info.addr -= aggr->size;
598
0
                sect->sect_info.size += aggr->size;
599
0
            } /* end if */
600
601
            /* Reset aggregator */
602
0
            aggr->tot_size = 0;
603
0
            aggr->addr     = 0;
604
0
            aggr->size     = 0;
605
0
        } /* end if */
606
0
        else {
607
            /* Check if the section adjoins the beginning or end of the aggregator */
608
0
            if (H5_addr_eq((sect->sect_info.addr + sect->sect_info.size), aggr->addr)) {
609
#ifdef H5MF_AGGR_DEBUG
610
                fprintf(stderr,
611
                        "%s: section {%" PRIuHADDR ", %" PRIuHSIZE "} adjoins front of aggr = {%" PRIuHADDR
612
                        ", %" PRIuHSIZE "}\n",
613
                        "H5MF__aggr_absorb", sect->sect_info.addr, sect->sect_info.size, aggr->addr,
614
                        aggr->size);
615
#endif /* H5MF_AGGR_DEBUG */
616
                /* Absorb section onto front of aggregator */
617
0
                aggr->addr -= sect->sect_info.size;
618
0
                aggr->size += sect->sect_info.size;
619
620
                /* Sections absorbed onto front of aggregator count against the total
621
                 * amount of space aggregated together.
622
                 */
623
0
                aggr->tot_size -= MIN(aggr->tot_size, sect->sect_info.size);
624
0
            } /* end if */
625
0
            else {
626
                /* Sanity check */
627
0
                assert(H5_addr_eq((aggr->addr + aggr->size), sect->sect_info.addr));
628
629
#ifdef H5MF_AGGR_DEBUG
630
                fprintf(stderr,
631
                        "%s: section {%" PRIuHADDR ", %" PRIuHSIZE "} adjoins end of aggr = {%" PRIuHADDR
632
                        ", %" PRIuHSIZE "}\n",
633
                        "H5MF__aggr_absorb", sect->sect_info.addr, sect->sect_info.size, aggr->addr,
634
                        aggr->size);
635
#endif /* H5MF_AGGR_DEBUG */
636
                /* Absorb section onto end of aggregator */
637
0
                aggr->size += sect->sect_info.size;
638
0
            } /* end if */
639
            /* Sanity check */
640
0
            assert(!allow_sect_absorb || (aggr->size < aggr->alloc_size));
641
0
        } /* end else */
642
643
0
        FUNC_LEAVE_NOAPI(SUCCEED)
644
0
    } /* end H5MF__aggr_absorb() */
645
646
    /*-------------------------------------------------------------------------
647
     * Function:    H5MF__aggr_query
648
     *
649
     * Purpose:     Query a block aggregator's current address & size info
650
     *
651
     * Return:      Success:        Non-negative
652
     *              Failure:        Negative
653
     *
654
     *-------------------------------------------------------------------------
655
     */
656
    herr_t H5MF__aggr_query(const H5F_t *f, const H5F_blk_aggr_t *aggr, haddr_t *addr, hsize_t *size)
657
2.14k
    {
658
2.14k
        FUNC_ENTER_PACKAGE_NOERR
659
660
        /* Check args */
661
2.14k
        assert(f);
662
2.14k
        assert(aggr);
663
2.14k
        assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
664
2.14k
               aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
665
666
        /* Check if this aggregator is active */
667
2.14k
        if (f->shared->feature_flags & aggr->feature_flag) {
668
2.14k
            if (addr)
669
2.14k
                *addr = aggr->addr;
670
2.14k
            if (size)
671
2.14k
                *size = aggr->size;
672
2.14k
        } /* end if */
673
674
2.14k
        FUNC_LEAVE_NOAPI(SUCCEED)
675
2.14k
    } /* end H5MF__aggr_query() */
676
677
    /*-------------------------------------------------------------------------
678
     * Function:    H5MF__aggr_reset
679
     *
680
     * Purpose:     Reset a block aggregator, returning any space back to file
681
     *
682
     * Return:      Success:        Non-negative
683
     *              Failure:        Negative
684
     *
685
     *-------------------------------------------------------------------------
686
     */
687
    static herr_t H5MF__aggr_reset(H5F_t * f, H5F_blk_aggr_t * aggr)
688
2.14k
    {
689
2.14k
        H5FD_mem_t alloc_type;          /* Type of file memory to work with */
690
2.14k
        herr_t     ret_value = SUCCEED; /* Return value */
691
692
2.14k
        FUNC_ENTER_PACKAGE
693
694
        /* Check args */
695
2.14k
        assert(f);
696
2.14k
        assert(aggr);
697
2.14k
        assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
698
2.14k
               aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
699
700
        /* Set the type of memory in the file */
701
2.14k
        alloc_type = (aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA
702
2.14k
                          ? H5FD_MEM_DEFAULT
703
2.14k
                          : H5FD_MEM_DRAW); /* Type of file memory to work with */
704
705
        /* Check if this aggregator is active */
706
2.14k
        if (f->shared->feature_flags & aggr->feature_flag) {
707
2.14k
            haddr_t tmp_addr; /* Temporary holder for aggregator address */
708
2.14k
            hsize_t tmp_size; /* Temporary holder for aggregator size */
709
710
            /* Retain aggregator info */
711
2.14k
            tmp_addr = aggr->addr;
712
2.14k
            tmp_size = aggr->size;
713
#ifdef H5MF_AGGR_DEBUG
714
            fprintf(stderr, "%s: tmp_addr = %" PRIuHADDR ", tmp_size = %" PRIuHSIZE "\n", __func__, tmp_addr,
715
                    tmp_size);
716
#endif /* H5MF_AGGR_DEBUG */
717
718
            /* Reset aggregator block information */
719
2.14k
            aggr->tot_size = 0;
720
2.14k
            aggr->addr     = 0;
721
2.14k
            aggr->size     = 0;
722
723
            /* Return the unused portion of the metadata block to the file */
724
2.14k
            if (tmp_size > 0 && (H5F_INTENT(f) & H5F_ACC_RDWR))
725
14
                if (H5MF_xfree(f, alloc_type, tmp_addr, tmp_size) < 0)
726
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't release aggregator's free space");
727
2.14k
        } /* end if */
728
729
2.14k
done:
730
2.14k
        FUNC_LEAVE_NOAPI(ret_value)
731
2.14k
    } /* end H5MF__aggr_reset() */
732
733
    /*-------------------------------------------------------------------------
734
     * Function:    H5MF_free_aggrs
735
     *
736
     * Purpose:     Reset a metadata & small block aggregators, returning any space
737
     *    back to file
738
     *
739
     * Return:      Success:        Non-negative
740
     *              Failure:        Negative
741
     *
742
     *-------------------------------------------------------------------------
743
     */
744
    herr_t H5MF_free_aggrs(H5F_t * f)
745
1.07k
    {
746
1.07k
        H5F_blk_aggr_t *first_aggr;              /* First aggregator to reset */
747
1.07k
        H5F_blk_aggr_t *second_aggr;             /* Second aggregator to reset */
748
1.07k
        haddr_t         ma_addr   = HADDR_UNDEF; /* Base "metadata aggregator" address */
749
1.07k
        hsize_t         ma_size   = 0;           /* Size of "metadata aggregator" */
750
1.07k
        haddr_t         sda_addr  = HADDR_UNDEF; /* Base "small data aggregator" address */
751
1.07k
        hsize_t         sda_size  = 0;           /* Size of "small data aggregator" */
752
1.07k
        herr_t          ret_value = SUCCEED;     /* Return value */
753
754
1.07k
        FUNC_ENTER_NOAPI(FAIL)
755
756
        /* Check args */
757
1.07k
        assert(f);
758
1.07k
        assert(f->shared);
759
1.07k
        assert(f->shared->lf);
760
761
        /* Retrieve metadata aggregator info, if available */
762
1.07k
        if (H5MF__aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0)
763
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats");
764
765
        /* Retrieve 'small data' aggregator info, if available */
766
1.07k
        if (H5MF__aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0)
767
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats");
768
769
        /* Make certain we release the aggregator that's later in the file first */
770
        /* (so the file shrinks properly) */
771
1.07k
        if (H5_addr_defined(ma_addr) && H5_addr_defined(sda_addr)) {
772
1.07k
            if (H5_addr_lt(ma_addr, sda_addr)) {
773
0
                first_aggr  = &(f->shared->sdata_aggr);
774
0
                second_aggr = &(f->shared->meta_aggr);
775
0
            } /* end if */
776
1.07k
            else {
777
1.07k
                first_aggr  = &(f->shared->meta_aggr);
778
1.07k
                second_aggr = &(f->shared->sdata_aggr);
779
1.07k
            } /* end else */
780
1.07k
        }     /* end if */
781
0
        else {
782
0
            first_aggr  = &(f->shared->meta_aggr);
783
0
            second_aggr = &(f->shared->sdata_aggr);
784
0
        } /* end else */
785
786
        /* Release the unused portion of the metadata and "small data" blocks back
787
         * to the free lists in the file.
788
         */
789
1.07k
        if (H5MF__aggr_reset(f, first_aggr) < 0)
790
0
            HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't reset metadata block");
791
1.07k
        if (H5MF__aggr_reset(f, second_aggr) < 0)
792
0
            HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't reset 'small data' block");
793
1.07k
done:
794
1.07k
        FUNC_LEAVE_NOAPI(ret_value)
795
1.07k
    } /* end H5MF_free_aggrs() */
796
797
    /*-------------------------------------------------------------------------
798
     * Function:    H5MF__aggr_can_shrink_eoa
799
     *
800
     * Purpose:     Check if the remaining space in the aggregator is at EOA
801
     *
802
     * Return:      Success:        non-negative (true/false)
803
     *              Failure:        negative
804
     *
805
     *-------------------------------------------------------------------------
806
     */
807
    static htri_t H5MF__aggr_can_shrink_eoa(H5F_t * f, H5FD_mem_t type, H5F_blk_aggr_t * aggr)
808
1.10k
    {
809
1.10k
        haddr_t eoa       = HADDR_UNDEF; /* EOA for the file */
810
1.10k
        htri_t  ret_value = false;       /* Return value */
811
812
1.10k
        FUNC_ENTER_PACKAGE
813
814
        /* Sanity check */
815
1.10k
        assert(f);
816
1.10k
        assert(aggr);
817
1.10k
        assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
818
1.10k
               aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
819
820
        /* Get the EOA for the file */
821
1.10k
        if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, type)))
822
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa");
823
824
        /* Check if the aggregator is at EOA */
825
1.10k
        if (aggr->size > 0 && H5_addr_defined(aggr->addr))
826
0
            ret_value = H5_addr_eq(eoa, aggr->addr + aggr->size);
827
828
1.10k
done:
829
1.10k
        FUNC_LEAVE_NOAPI(ret_value)
830
1.10k
    } /* H5MF__aggr_can_shrink_eoa() */
831
832
    /*-------------------------------------------------------------------------
833
     * Function:    H5MF__aggr_free
834
     *
835
     * Purpose:     Free the aggregator's space in the file.
836
     *
837
     * Note:        Does _not_ put the space on a free list
838
     *
839
     * Return:      Success:        Non-negative
840
     *              Failure:        Negative
841
     *
842
     *-------------------------------------------------------------------------
843
     */
844
    static herr_t H5MF__aggr_free(H5F_t * f, H5FD_mem_t type, H5F_blk_aggr_t * aggr)
845
0
    {
846
0
        herr_t ret_value = SUCCEED; /* Return value */
847
848
0
        FUNC_ENTER_PACKAGE
849
850
        /* Sanity check */
851
0
        assert(f);
852
0
        assert(f->shared->lf);
853
0
        assert(aggr);
854
0
        assert(H5_addr_defined(aggr->addr));
855
0
        assert(aggr->size > 0);
856
0
        assert(H5F_INTENT(f) & H5F_ACC_RDWR);
857
0
        assert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ||
858
0
               aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
859
0
        assert(f->shared->feature_flags & aggr->feature_flag);
860
861
        /* Free the remaining space at EOA in the aggregator */
862
0
        if (H5F__free(f, type, aggr->addr, aggr->size) < 0)
863
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregation block");
864
865
        /* Reset the aggregator */
866
0
        aggr->tot_size = 0;
867
0
        aggr->addr     = HADDR_UNDEF;
868
0
        aggr->size     = 0;
869
870
0
done:
871
0
        FUNC_LEAVE_NOAPI(ret_value)
872
0
    } /* H5MF__aggr_free() */
873
874
    /*-------------------------------------------------------------------------
875
     * Function:    H5MF__aggrs_try_shrink_eoa
876
     *
877
     * Purpose:     Check the metadata & small block aggregators to see if
878
     *    EOA shrink is possible; if so, shrink each aggregator
879
     *
880
     * Return:      Success:        Non-negative
881
     *              Failure:        Negative
882
     *
883
     *-------------------------------------------------------------------------
884
     */
885
    htri_t H5MF__aggrs_try_shrink_eoa(H5F_t * f)
886
550
    {
887
550
        htri_t ma_status;        /* Whether the metadata aggregator can shrink the EOA */
888
550
        htri_t sda_status;       /* Whether the small data aggregator can shrink the EOA */
889
550
        htri_t ret_value = FAIL; /* Return value */
890
891
550
        FUNC_ENTER_PACKAGE
892
893
        /* Check args */
894
550
        assert(f);
895
550
        assert(f->shared);
896
897
550
        if ((ma_status = H5MF__aggr_can_shrink_eoa(f, H5FD_MEM_DEFAULT, &(f->shared->meta_aggr))) < 0)
898
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats");
899
550
        if (ma_status > 0)
900
0
            if (H5MF__aggr_free(f, H5FD_MEM_DEFAULT, &(f->shared->meta_aggr)) < 0)
901
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa");
902
903
550
        if ((sda_status = H5MF__aggr_can_shrink_eoa(f, H5FD_MEM_DRAW, &(f->shared->sdata_aggr))) < 0)
904
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats");
905
550
        if (sda_status > 0)
906
0
            if (H5MF__aggr_free(f, H5FD_MEM_DRAW, &(f->shared->sdata_aggr)) < 0)
907
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa");
908
909
550
        ret_value = (ma_status || sda_status);
910
911
550
done:
912
550
        FUNC_LEAVE_NOAPI(ret_value)
913
550
    } /* end H5MF__aggrs_try_shrink_eoa() */