Coverage Report

Created: 2026-10-28 18:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5FS.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 tracking functions.
15
 *
16
 * Note:        (Used to be in the H5HFflist.c file, prior to the date above)
17
 */
18
19
/****************/
20
/* Module Setup */
21
/****************/
22
23
#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
24
25
/***********/
26
/* Headers */
27
/***********/
28
#include "H5private.h"   /* Generic Functions                        */
29
#include "H5ACprivate.h" /* Metadata cache                           */
30
#include "H5Eprivate.h"  /* Error handling                           */
31
#include "H5FLprivate.h" /* Free Lists                               */
32
#include "H5FSpkg.h"     /* File free space                          */
33
#include "H5MFprivate.h" /* File memory management                   */
34
#include "H5MMprivate.h" /* Memory management                        */
35
#include "H5SLprivate.h" /* Skip Lists                               */
36
37
/****************/
38
/* Local Macros */
39
/****************/
40
41
/******************/
42
/* Local Typedefs */
43
/******************/
44
45
/********************/
46
/* Package Typedefs */
47
/********************/
48
49
/********************/
50
/* Local Prototypes */
51
/********************/
52
53
/* Section info routines */
54
static herr_t H5FS__sinfo_free_sect_cb(void *item, void *key, void *op_data);
55
static herr_t H5FS__sinfo_free_node_cb(void *item, void *key, void *op_data);
56
57
/*********************/
58
/* Package Variables */
59
/*********************/
60
61
/* Package initialization variable */
62
bool H5_PKG_INIT_VAR = false;
63
64
/* Declare a free list to manage the H5FS_section_class_t sequence information */
65
H5FL_SEQ_DEFINE(H5FS_section_class_t);
66
67
/* Declare a free list to manage the H5FS_t struct */
68
H5FL_DEFINE(H5FS_t);
69
70
/*****************************/
71
/* Library Private Variables */
72
/*****************************/
73
74
/*******************/
75
/* Local Variables */
76
/*******************/
77
78
/*-------------------------------------------------------------------------
79
 * Function:    H5FS_create
80
 *
81
 * Purpose:     Allocate & initialize file free space info
82
 *
83
 * Return:      Success:    Pointer to free space structure
84
 *              Failure:    NULL
85
 *
86
 *-------------------------------------------------------------------------
87
 */
88
H5FS_t *
89
H5FS_create(H5F_t *f, haddr_t *fs_addr, const H5FS_create_t *fs_create, uint16_t nclasses,
90
            const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold)
91
0
{
92
0
    H5FS_t *fspace    = NULL; /* New free space structure */
93
0
    H5FS_t *ret_value = NULL; /* Return value */
94
95
0
    FUNC_ENTER_NOAPI(NULL)
96
#ifdef H5FS_DEBUG
97
    fprintf(stderr, "%s: Creating free space manager, nclasses = %Zu\n", __func__, nclasses);
98
#endif /* H5FS_DEBUG */
99
100
    /* Check arguments. */
101
0
    assert(fs_create->shrink_percent);
102
0
    assert(fs_create->shrink_percent < fs_create->expand_percent);
103
0
    assert(fs_create->max_sect_size);
104
0
    assert(nclasses == 0 || classes);
105
106
    /*
107
     * Allocate free space structure
108
     */
109
0
    if (NULL == (fspace = H5FS__new(f, nclasses, classes, cls_init_udata)))
110
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list");
111
112
    /* Initialize creation information for free space manager */
113
0
    fspace->client         = fs_create->client;
114
0
    fspace->shrink_percent = fs_create->shrink_percent;
115
0
    fspace->expand_percent = fs_create->expand_percent;
116
0
    fspace->max_sect_addr  = fs_create->max_sect_addr;
117
0
    fspace->max_sect_size  = fs_create->max_sect_size;
118
0
    fspace->swmr_write     = (H5F_INTENT(f) & H5F_ACC_SWMR_WRITE) > 0;
119
120
0
    fspace->alignment   = alignment;
121
0
    fspace->align_thres = threshold;
122
123
    /* Check if the free space tracker is supposed to be persistent */
124
0
    if (fs_addr) {
125
        /* Allocate space for the free space header */
126
0
        if (HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, (hsize_t)fspace->hdr_size)))
127
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "file allocation failed for free space header");
128
129
        /* Cache the new free space header (pinned) */
130
0
        if (H5AC_insert_entry(f, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
131
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, NULL, "can't add free space header to cache");
132
133
        /* Return free space header address to caller, if desired */
134
0
        *fs_addr = fspace->addr;
135
0
    } /* end if */
136
137
    /* Set the reference count to 1, since we inserted the entry in the cache pinned */
138
0
    fspace->rc = 1;
139
140
    /* Set the return value */
141
0
    ret_value = fspace;
142
#ifdef H5FS_DEBUG
143
    fprintf(stderr, "%s: fspace = %p, fspace->addr = %" PRIuHADDR "\n", __func__, (void *)fspace,
144
            fspace->addr);
145
#endif /* H5FS_DEBUG */
146
147
0
done:
148
0
    if (!ret_value && fspace)
149
0
        if (H5FS__hdr_dest(fspace) < 0)
150
0
            HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space header");
151
152
#ifdef H5FS_DEBUG
153
    fprintf(stderr, "%s: Leaving, ret_value = %p\n", __func__, (void *)ret_value);
154
#endif /* H5FS_DEBUG */
155
0
    FUNC_LEAVE_NOAPI(ret_value)
156
0
} /* H5FS_create() */
157
158
/*-------------------------------------------------------------------------
159
 * Function:    H5FS_open
160
 *
161
 * Purpose:     Open an existing file free space info structure on disk
162
 *
163
 * Return:      Success:    Pointer to free space structure
164
 *              Failure:    NULL
165
 *
166
 *-------------------------------------------------------------------------
167
 */
168
H5FS_t *
169
H5FS_open(H5F_t *f, haddr_t fs_addr, uint16_t nclasses, const H5FS_section_class_t *classes[],
170
          void *cls_init_udata, hsize_t alignment, hsize_t threshold)
171
0
{
172
0
    H5FS_t             *fspace = NULL;    /* New free space structure */
173
0
    H5FS_hdr_cache_ud_t cache_udata;      /* User-data for metadata cache callback */
174
0
    H5FS_t             *ret_value = NULL; /* Return value */
175
176
0
    FUNC_ENTER_NOAPI(NULL)
177
#ifdef H5FS_DEBUG
178
    fprintf(stderr, "%s: Opening free space manager, fs_addr = %" PRIuHADDR ", nclasses = %Zu\n", __func__,
179
            fs_addr, nclasses);
180
#endif /* H5FS_DEBUG */
181
182
    /* Check arguments. */
183
0
    assert(H5_addr_defined(fs_addr));
184
0
    assert(nclasses);
185
0
    assert(classes);
186
187
    /* Initialize user data for protecting the free space manager */
188
0
    cache_udata.f              = f;
189
0
    cache_udata.nclasses       = nclasses;
190
0
    cache_udata.classes        = classes;
191
0
    cache_udata.cls_init_udata = cls_init_udata;
192
0
    cache_udata.addr           = fs_addr;
193
194
    /* Protect the free space header */
195
0
    if (NULL ==
196
0
        (fspace = (H5FS_t *)H5AC_protect(f, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
197
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, NULL, "unable to load free space header");
198
#ifdef H5FS_DEBUG
199
    fprintf(stderr, "%s: fspace->sect_addr = %" PRIuHADDR "\n", __func__, fspace->sect_addr);
200
    fprintf(stderr, "%s: fspace->sect_size = %" PRIuHSIZE "\n", __func__, fspace->sect_size);
201
    fprintf(stderr, "%s: fspace->alloc_sect_size = %" PRIuHSIZE "\n", __func__, fspace->alloc_sect_size);
202
    fprintf(stderr, "%s: fspace->sinfo = %p\n", __func__, (void *)fspace->sinfo);
203
    fprintf(stderr, "%s: fspace->rc = %u\n", __func__, fspace->rc);
204
#endif /* H5FS_DEBUG */
205
206
    /* Increment the reference count on the free space manager header */
207
0
    assert(fspace->rc <= 1);
208
0
    if (H5FS__incr(fspace) < 0)
209
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINC, NULL, "unable to increment ref. count on free space header");
210
211
0
    fspace->alignment   = alignment;
212
0
    fspace->align_thres = threshold;
213
214
    /* Unlock free space header */
215
0
    if (H5AC_unprotect(f, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__NO_FLAGS_SET) < 0)
216
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, NULL, "unable to release free space header");
217
218
    /* Set return value */
219
0
    ret_value = fspace;
220
221
0
done:
222
0
    FUNC_LEAVE_NOAPI(ret_value)
223
0
} /* H5FS_open() */
224
225
/*-------------------------------------------------------------------------
226
 * Function:    H5FS_delete
227
 *
228
 * Purpose:     Delete a free space manager on disk
229
 *
230
 * Return:      SUCCEED/FAIL
231
 *
232
 *-------------------------------------------------------------------------
233
 */
234
herr_t
235
H5FS_delete(H5F_t *f, haddr_t fs_addr)
236
0
{
237
0
    H5FS_t             *fspace = NULL;       /* Free space header loaded from file */
238
0
    H5FS_hdr_cache_ud_t cache_udata;         /* User-data for metadata cache callback */
239
0
    herr_t              ret_value = SUCCEED; /* Return value */
240
241
0
    FUNC_ENTER_NOAPI(FAIL)
242
#ifdef H5FS_DEBUG
243
    fprintf(stderr, "%s: Deleting free space manager, fs_addr = %" PRIuHADDR "\n", __func__, fs_addr);
244
#endif /* H5FS_DEBUG */
245
246
    /* Check arguments. */
247
0
    assert(f);
248
0
    assert(H5_addr_defined(fs_addr));
249
250
    /* Initialize user data for protecting the free space manager */
251
    /* (no class information necessary for delete) */
252
0
    cache_udata.f              = f;
253
0
    cache_udata.nclasses       = 0;
254
0
    cache_udata.classes        = NULL;
255
0
    cache_udata.cls_init_udata = NULL;
256
0
    cache_udata.addr           = fs_addr;
257
258
#ifdef H5FS_DEBUG
259
    {
260
        unsigned fspace_status = 0; /* Free space section info's status in the metadata cache */
261
262
        /* Sanity check */
263
        assert(H5_addr_defined(fs_addr));
264
265
        /* Check the free space section info's status in the metadata cache */
266
        if (H5AC_get_entry_status(f, fs_addr, &fspace_status) < 0)
267
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
268
                        "unable to check metadata cache status for free space section info");
269
270
        fprintf(stderr, "%s: fspace_status = %0x: ", __func__, fspace_status);
271
        if (fspace_status) {
272
            bool printed = false;
273
274
            if (fspace_status & H5AC_ES__IN_CACHE) {
275
                fprintf(stderr, "H5AC_ES__IN_CACHE");
276
                printed = true;
277
            } /* end if */
278
            if (fspace_status & H5AC_ES__IS_DIRTY) {
279
                fprintf(stderr, "%sH5AC_ES__IS_DIRTY", (printed ? " | " : ""));
280
                printed = true;
281
            } /* end if */
282
            if (fspace_status & H5AC_ES__IS_PROTECTED) {
283
                fprintf(stderr, "%sH5AC_ES__IS_PROTECTED", (printed ? " | " : ""));
284
                printed = true;
285
            } /* end if */
286
            if (fspace_status & H5AC_ES__IS_PINNED) {
287
                fprintf(stderr, "%sH5AC_ES__IS_PINNED", (printed ? " | " : ""));
288
                printed = true;
289
            } /* end if */
290
            if (fspace_status & H5AC_ES__IS_FLUSH_DEP_PARENT) {
291
                fprintf(stderr, "%sH5AC_ES__IS_FLUSH_DEP_PARENT", (printed ? " | " : ""));
292
                printed = true;
293
            } /* end if */
294
            if (fspace_status & H5AC_ES__IS_FLUSH_DEP_CHILD) {
295
                fprintf(stderr, "%sH5AC_ES__IS_FLUSH_DEP_CHILD", (printed ? " | " : ""));
296
                printed = true;
297
            } /* end if */
298
        }     /* end if */
299
        fprintf(stderr, "\n");
300
    }
301
#endif /* H5FS_DEBUG */
302
303
    /* Protect the free space header */
304
0
    if (NULL ==
305
0
        (fspace = (H5FS_t *)H5AC_protect(f, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
306
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space header");
307
308
    /* Sanity check */
309
0
    assert(fspace->sinfo == NULL);
310
311
    /* Delete serialized section storage, if there are any */
312
#ifdef H5FS_DEBUG
313
    fprintf(stderr, "%s: fspace->sect_addr = %" PRIuHADDR "\n", __func__, fspace->sect_addr);
314
#endif /* H5FS_DEBUG */
315
0
    if (fspace->serial_sect_count > 0) {
316
0
        unsigned sinfo_status = 0; /* Free space section info's status in the metadata cache */
317
318
        /* Sanity check */
319
0
        assert(H5_addr_defined(fspace->sect_addr));
320
0
        assert(fspace->alloc_sect_size > 0);
321
322
        /* Check the free space section info's status in the metadata cache */
323
0
        if (H5AC_get_entry_status(f, fspace->sect_addr, &sinfo_status) < 0)
324
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
325
0
                        "unable to check metadata cache status for free space section info");
326
327
        /* If the free space section info is in the cache, expunge it now */
328
0
        if (sinfo_status & H5AC_ES__IN_CACHE) {
329
            /* Sanity checks on direct block */
330
0
            assert(!(sinfo_status & H5AC_ES__IS_PINNED));
331
0
            assert(!(sinfo_status & H5AC_ES__IS_PROTECTED));
332
333
#ifdef H5FS_DEBUG
334
            fprintf(stderr, "%s: Expunging free space section info from cache\n", __func__);
335
#endif /* H5FS_DEBUG */
336
            /* Evict the free space section info from the metadata cache */
337
            /* (Free file space) */
338
0
            {
339
0
                unsigned cache_flags = H5AC__NO_FLAGS_SET;
340
341
                /* if the indirect block is in real file space, tell
342
                 * the cache to free its file space.
343
                 */
344
0
                if (!H5F_IS_TMP_ADDR(f, fspace->sect_addr))
345
0
                    cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
346
347
0
                if (H5AC_expunge_entry(f, H5AC_FSPACE_SINFO, fspace->sect_addr, cache_flags) < 0)
348
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL,
349
0
                                "unable to remove free space section info from cache");
350
0
            } /* end block */
351
352
#ifdef H5FS_DEBUG
353
            fprintf(stderr, "%s: Done expunging free space section info from cache\n", __func__);
354
#endif    /* H5FS_DEBUG */
355
0
        } /* end if */
356
0
        else {
357
#ifdef H5FS_DEBUG
358
            fprintf(stderr, "%s: Deleting free space section info from file\n", __func__);
359
#endif /* H5FS_DEBUG */
360
            /* Release the space in the file */
361
0
            if (!H5F_IS_TMP_ADDR(f, fspace->sect_addr))
362
0
                if (H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, fspace->sect_addr, fspace->alloc_sect_size) < 0)
363
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space sections");
364
0
        } /* end else */
365
0
    }     /* end if */
366
367
0
done:
368
0
    if (fspace && H5AC_unprotect(f, H5AC_FSPACE_HDR, fs_addr, fspace,
369
0
                                 H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
370
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space header");
371
372
0
    FUNC_LEAVE_NOAPI(ret_value)
373
0
} /* H5FS_delete() */
374
375
/*-------------------------------------------------------------------------
376
 * Function:    H5FS_close
377
 *
378
 * Purpose:     Destroy & deallocate free list structure, serializing sections
379
 *              in the bins
380
 *
381
 * Return:      SUCCEED/FAIL
382
 *
383
 *-------------------------------------------------------------------------
384
 */
385
herr_t
386
H5FS_close(H5F_t *f, H5FS_t *fspace)
387
0
{
388
0
    herr_t ret_value = SUCCEED; /* Return value */
389
390
0
    FUNC_ENTER_NOAPI(FAIL)
391
392
    /* Check arguments. */
393
0
    assert(f);
394
0
    assert(fspace);
395
#ifdef H5FS_DEBUG
396
    fprintf(stderr, "%s: Entering, fspace = %p, fspace->addr = %" PRIuHADDR ", fspace->sinfo = %p\n",
397
            __func__, (void *)fspace, fspace->addr, (void *)fspace->sinfo);
398
#endif /* H5FS_DEBUG */
399
400
    /* Check if section info is valid */
401
    /* (i.e. the header "owns" the section info and it's not in the cache) */
402
0
    if (fspace->sinfo) {
403
#ifdef H5FS_DEBUG
404
        fprintf(stderr,
405
                "%s: fspace->tot_sect_count = %" PRIuHSIZE ", fspace->serial_sect_count = %" PRIuHSIZE
406
                ", fspace->sect_addr = %" PRIuHADDR ", fspace->rc = %u\n",
407
                __func__, fspace->tot_sect_count, fspace->serial_sect_count, fspace->sect_addr, fspace->rc);
408
        fprintf(stderr, "%s: fspace->alloc_sect_size = %" PRIuHSIZE ", fspace->sect_size = %" PRIuHSIZE "\n",
409
                __func__, fspace->alloc_sect_size, fspace->sect_size);
410
#endif /* H5FS_DEBUG */
411
        /* If there are sections to serialize, update them */
412
        /* (if the free space manager is persistent) */
413
0
        if (fspace->serial_sect_count > 0 && H5_addr_defined(fspace->addr)) {
414
#ifdef H5FS_DEBUG
415
            fprintf(stderr, "%s: Real sections to store in file\n", __func__);
416
#endif /* H5FS_DEBUG */
417
0
            if (fspace->sinfo->dirty) {
418
                /* Check if the section info is "floating" */
419
0
                if (!H5_addr_defined(fspace->sect_addr)) {
420
                    /* Sanity check */
421
0
                    assert(fspace->sect_size > 0);
422
423
                    /* Allocate space for the section info in file */
424
0
                    if (H5F_USE_TMP_SPACE(f)) {
425
0
                        if (HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc_tmp(f, fspace->sect_size)))
426
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL,
427
0
                                        "file allocation failed for free space sections");
428
0
                    } /* end if */
429
0
                    else {
430
0
                        if (HADDR_UNDEF ==
431
0
                            (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, fspace->sect_size)))
432
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL,
433
0
                                        "file allocation failed for free space sections");
434
0
                    } /* end if */
435
0
                    fspace->alloc_sect_size = (size_t)fspace->sect_size;
436
437
                    /* Mark free space header as dirty */
438
0
                    if (H5AC_mark_entry_dirty(fspace) < 0)
439
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
440
0
                                    "unable to mark free space header as dirty");
441
0
                } /* end if */
442
0
            }     /* end if */
443
0
            else
444
                /* Sanity check that section info has address */
445
0
                assert(H5_addr_defined(fspace->sect_addr));
446
447
            /* Cache the free space section info */
448
0
            if (H5AC_insert_entry(f, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo,
449
0
                                  H5AC__NO_FLAGS_SET) < 0)
450
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache");
451
0
        } /* end if */
452
0
        else {
453
#ifdef H5FS_DEBUG
454
            fprintf(stderr, "%s: NOT storing section info in file\n", __func__);
455
#endif /* H5FS_DEBUG */
456
            /* Check if space for the section info is allocated */
457
0
            if (H5_addr_defined(fspace->sect_addr)) {
458
                /* Sanity check */
459
                /* (section info should only be in the file if the header is */
460
0
                assert(H5_addr_defined(fspace->addr));
461
462
#ifdef H5FS_DEBUG
463
                fprintf(stderr, "%s: Section info allocated though\n", __func__);
464
#endif /* H5FS_DEBUG */
465
                /* Check if the section info is for the free space in the file */
466
                /* (NOTE: This is the "bootstrapping" special case for the
467
                 *      free space manager, to avoid freeing the space for the
468
                 *      section info and re-creating it as a section in the
469
                 *      manager. -QAK)
470
                 */
471
0
                if (fspace->client == H5FS_CLIENT_FILE_ID) {
472
0
                    htri_t status; /* "can absorb" status for section into */
473
474
#ifdef H5FS_DEBUG
475
                    fprintf(stderr, "%s: Section info is for file free space\n", __func__);
476
#endif /* H5FS_DEBUG */
477
                    /* Try to shrink the file or absorb the section info into a block aggregator */
478
0
                    if (H5F_IS_TMP_ADDR(f, fspace->sect_addr)) {
479
#ifdef H5FS_DEBUG
480
                        fprintf(stderr, "%s: Section info in temp. address space went 'go away'\n", __func__);
481
#endif /* H5FS_DEBUG */
482
                        /* Reset section info in header */
483
0
                        fspace->sect_addr       = HADDR_UNDEF;
484
0
                        fspace->alloc_sect_size = 0;
485
486
                        /* Mark free space header as dirty */
487
0
                        if (H5AC_mark_entry_dirty(fspace) < 0)
488
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
489
0
                                        "unable to mark free space header as dirty");
490
0
                    } /* end if */
491
0
                    else {
492
0
                        if ((status = H5MF_try_shrink(f, H5FD_MEM_FSPACE_SINFO, fspace->sect_addr,
493
0
                                                      fspace->alloc_sect_size)) < 0)
494
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL,
495
0
                                        "can't check for absorbing section info");
496
0
                        else if (status == false) {
497
                            /* Section info can't "go away", but it's free.  Allow
498
                             *      header to record it
499
                             */
500
#ifdef H5FS_DEBUG
501
                            fprintf(stderr, "%s: Section info can't 'go away', header will own it\n",
502
                                    __func__);
503
#endif                    /* H5FS_DEBUG */
504
0
                        } /* end if */
505
0
                        else {
506
#ifdef H5FS_DEBUG
507
                            fprintf(stderr, "%s: Section info went 'go away'\n", __func__);
508
#endif /* H5FS_DEBUG */
509
                            /* Reset section info in header */
510
0
                            fspace->sect_addr       = HADDR_UNDEF;
511
0
                            fspace->alloc_sect_size = 0;
512
513
                            /* Mark free space header as dirty */
514
0
                            if (H5AC_mark_entry_dirty(fspace) < 0)
515
0
                                HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
516
0
                                            "unable to mark free space header as dirty");
517
0
                        } /* end else */
518
0
                    }     /* end else */
519
0
                }         /* end if */
520
0
                else {
521
0
                    haddr_t old_sect_addr = fspace->sect_addr; /* Previous location of section info in file */
522
0
                    hsize_t old_alloc_sect_size =
523
0
                        fspace->alloc_sect_size; /* Previous size of section info in file */
524
525
#ifdef H5FS_DEBUG
526
                    fprintf(stderr, "%s: Section info is NOT for file free space\n", __func__);
527
#endif /* H5FS_DEBUG */
528
                    /* Reset section info in header */
529
0
                    fspace->sect_addr       = HADDR_UNDEF;
530
0
                    fspace->alloc_sect_size = 0;
531
532
                    /* Mark free space header as dirty */
533
0
                    if (H5AC_mark_entry_dirty(fspace) < 0)
534
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
535
0
                                    "unable to mark free space header as dirty");
536
537
                    /* Free previous serialized sections disk space */
538
0
                    if (!H5F_IS_TMP_ADDR(f, old_sect_addr)) {
539
0
                        if (H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, old_sect_addr, old_alloc_sect_size) < 0)
540
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections");
541
0
                    } /* end if */
542
0
                }     /* end else */
543
0
            }         /* end if */
544
545
            /* Destroy section info */
546
0
            if (H5FS__sinfo_dest(fspace->sinfo) < 0)
547
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space section info");
548
0
        } /* end else */
549
550
        /* Reset the header's pointer to the section info */
551
0
        fspace->sinfo = NULL;
552
0
    } /* end if */
553
0
    else {
554
        /* Just sanity checks... */
555
0
        if (fspace->serial_sect_count > 0)
556
            /* Sanity check that section info has address */
557
0
            assert(H5_addr_defined(fspace->sect_addr));
558
0
    } /* end else */
559
560
    /* Decrement the reference count on the free space manager header */
561
0
    if (H5FS__decr(fspace) < 0)
562
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header");
563
564
0
done:
565
#ifdef H5FS_DEBUG
566
    fprintf(stderr, "%s: Leaving, ret_value = %d, fspace->rc = %u\n", __func__, ret_value, fspace->rc);
567
#endif /* H5FS_DEBUG */
568
0
    FUNC_LEAVE_NOAPI(ret_value)
569
0
} /* H5FS_close() */
570
571
/*-------------------------------------------------------------------------
572
 * Function:  H5FS__new
573
 *
574
 * Purpose:     Create new free space manager structure
575
 *
576
 * Return:      Success:    non-NULL, pointer to new free space manager struct
577
 *              Failure:    NULL
578
 *
579
 *-------------------------------------------------------------------------
580
 */
581
H5FS_t *
582
H5FS__new(const H5F_t *f, uint16_t nclasses, const H5FS_section_class_t *classes[], void *cls_init_udata)
583
0
{
584
0
    H5FS_t *fspace = NULL;    /* Free space manager */
585
0
    size_t  u;                /* Local index variable */
586
0
    H5FS_t *ret_value = NULL; /* Return value */
587
588
0
    FUNC_ENTER_PACKAGE
589
590
    /* Check arguments. */
591
0
    assert(nclasses == 0 || (nclasses > 0 && classes));
592
593
    /*
594
     * Allocate free space structure
595
     */
596
0
    if (NULL == (fspace = H5FL_CALLOC(H5FS_t)))
597
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list");
598
599
    /* Set immutable free list parameters */
600
0
    H5_CHECKED_ASSIGN(fspace->nclasses, uint16_t, nclasses, size_t);
601
0
    if (nclasses > 0) {
602
0
        if (NULL == (fspace->sect_cls = H5FL_SEQ_MALLOC(H5FS_section_class_t, nclasses)))
603
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
604
0
                        "memory allocation failed for free space section class array");
605
606
        /* Initialize the section classes for this free space list */
607
0
        for (u = 0; u < nclasses; u++) {
608
            /* Make certain that section class type can be used as an array index into this array */
609
0
            assert(u == classes[u]->type);
610
611
            /* Copy the class information into the free space manager */
612
0
            H5MM_memcpy(&fspace->sect_cls[u], classes[u], sizeof(H5FS_section_class_t));
613
614
            /* Call the class initialization routine, if there is one */
615
0
            if (fspace->sect_cls[u].init_cls)
616
0
                if ((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0)
617
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "unable to initialize section class");
618
619
            /* Determine maximum class-specific serialization size for each section */
620
0
            if (fspace->sect_cls[u].serial_size > fspace->max_cls_serial_size)
621
0
                fspace->max_cls_serial_size = fspace->sect_cls[u].serial_size;
622
0
        } /* end for */
623
0
    }     /* end if */
624
625
    /* Initialize non-zero information for new free space manager */
626
0
    fspace->addr      = HADDR_UNDEF;
627
0
    fspace->hdr_size  = (size_t)H5FS_HEADER_SIZE(f);
628
0
    fspace->sect_addr = HADDR_UNDEF;
629
630
    /* Set return value */
631
0
    ret_value = fspace;
632
633
0
done:
634
0
    if (!ret_value)
635
0
        if (fspace) {
636
            /* Should probably call the class 'term' callback for all classes
637
             *  that have had their 'init' callback called... -QAK
638
             */
639
0
            if (fspace->sect_cls)
640
0
                fspace->sect_cls =
641
0
                    (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
642
0
            fspace = H5FL_FREE(H5FS_t, fspace);
643
0
        } /* end if */
644
645
0
    FUNC_LEAVE_NOAPI(ret_value)
646
0
} /* H5FS__new() */
647
648
/*-------------------------------------------------------------------------
649
 * Function:    H5FS_size
650
 *
651
 * Purpose:     Collect meta storage info used by the free space manager
652
 *
653
 * Return:      SUCCEED (Can't fail)
654
 *
655
 *-------------------------------------------------------------------------
656
 */
657
herr_t
658
H5FS_size(const H5FS_t *fspace, hsize_t *meta_size)
659
0
{
660
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
661
662
    /*
663
     * Check arguments.
664
     */
665
0
    assert(fspace);
666
0
    assert(meta_size);
667
668
    /* Get the free space size info */
669
0
    *meta_size += fspace->hdr_size + (fspace->sinfo ? fspace->sect_size : fspace->alloc_sect_size);
670
671
0
    FUNC_LEAVE_NOAPI(SUCCEED)
672
0
} /* end H5FS_size() */
673
674
/*-------------------------------------------------------------------------
675
 * Function:    H5FS__incr
676
 *
677
 * Purpose:     Increment reference count on free space header
678
 *
679
 * Return:      SUCCEED/FAIL
680
 *
681
 *-------------------------------------------------------------------------
682
 */
683
herr_t
684
H5FS__incr(H5FS_t *fspace)
685
0
{
686
0
    herr_t ret_value = SUCCEED; /* Return value */
687
688
0
    FUNC_ENTER_PACKAGE
689
#ifdef H5FS_DEBUG
690
    fprintf(stderr, "%s: Entering, fpace->addr = %" PRIuHADDR ", fspace->rc = %u\n", __func__, fspace->addr,
691
            fspace->rc);
692
#endif /* H5FS_DEBUG */
693
694
    /*
695
     * Check arguments.
696
     */
697
0
    assert(fspace);
698
699
    /* Check if we should pin the header in the cache */
700
0
    if (fspace->rc == 0 && H5_addr_defined(fspace->addr))
701
0
        if (H5AC_pin_protected_entry(fspace) < 0)
702
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTPIN, FAIL, "unable to pin free space header");
703
704
    /* Increment reference count on header */
705
0
    fspace->rc++;
706
707
0
done:
708
0
    FUNC_LEAVE_NOAPI(ret_value)
709
0
} /* end H5FS__incr() */
710
711
/*-------------------------------------------------------------------------
712
 * Function:    H5FS__decr
713
 *
714
 * Purpose:     Decrement reference count on free space header
715
 *
716
 * Return:      SUCCEED/FAIL
717
 *
718
 *-------------------------------------------------------------------------
719
 */
720
herr_t
721
H5FS__decr(H5FS_t *fspace)
722
0
{
723
0
    herr_t ret_value = SUCCEED; /* Return value */
724
725
0
    FUNC_ENTER_PACKAGE
726
#ifdef H5FS_DEBUG
727
    fprintf(stderr, "%s: Entering, fpace->addr = %" PRIuHADDR ", fspace->rc = %u\n", __func__, fspace->addr,
728
            fspace->rc);
729
#endif /* H5FS_DEBUG */
730
731
    /*
732
     * Check arguments.
733
     */
734
0
    assert(fspace);
735
736
    /* Decrement reference count on header */
737
0
    fspace->rc--;
738
739
    /* Check if we should unpin the header in the cache */
740
0
    if (fspace->rc == 0) {
741
0
        if (H5_addr_defined(fspace->addr)) {
742
0
            if (H5AC_unpin_entry(fspace) < 0)
743
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin free space header");
744
0
        } /* end if */
745
0
        else {
746
0
            if (H5FS__hdr_dest(fspace) < 0)
747
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space header");
748
0
        } /* end else */
749
0
    }     /* end if */
750
751
0
done:
752
0
    FUNC_LEAVE_NOAPI(ret_value)
753
0
} /* end H5FS__decr() */
754
755
/*-------------------------------------------------------------------------
756
 * Function:    H5FS__dirty
757
 *
758
 * Purpose:     Mark free space header as dirty
759
 *
760
 * Return:      SUCCEED/FAIL
761
 *
762
 *-------------------------------------------------------------------------
763
 */
764
herr_t
765
H5FS__dirty(H5FS_t *fspace)
766
0
{
767
0
    herr_t ret_value = SUCCEED; /* Return value */
768
769
0
    FUNC_ENTER_PACKAGE
770
771
    /* Sanity check */
772
0
    assert(fspace);
773
774
    /* Check if the free space manager is persistent */
775
0
    if (H5_addr_defined(fspace->addr))
776
        /* Mark header as dirty in cache */
777
0
        if (H5AC_mark_entry_dirty(fspace) < 0)
778
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty");
779
780
0
done:
781
0
    FUNC_LEAVE_NOAPI(ret_value)
782
0
} /* end H5FS__dirty() */
783
784
/*-------------------------------------------------------------------------
785
 * Function:    H5FS_alloc_hdr()
786
 *
787
 * Purpose:     Allocate space for the free-space manager header
788
 *
789
 * Return:      SUCCEED/FAIL
790
 *
791
 *-------------------------------------------------------------------------
792
 */
793
herr_t
794
H5FS_alloc_hdr(H5F_t *f, H5FS_t *fspace, haddr_t *fs_addr)
795
0
{
796
0
    herr_t ret_value = SUCCEED; /* Return value */
797
798
0
    FUNC_ENTER_NOAPI(FAIL)
799
800
    /* Check arguments. */
801
0
    assert(f);
802
0
    assert(fspace);
803
804
0
    if (!H5_addr_defined(fspace->addr)) {
805
        /* Allocate space for the free space header */
806
0
        if (HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, (hsize_t)H5FS_HEADER_SIZE(f))))
807
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for free space header");
808
809
        /* Cache the new free space header (pinned) */
810
0
        if (H5AC_insert_entry(f, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
811
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space header to cache");
812
0
    } /* end if */
813
814
0
    if (fs_addr)
815
0
        *fs_addr = fspace->addr;
816
817
0
done:
818
0
    FUNC_LEAVE_NOAPI(ret_value)
819
0
} /* H5FS_alloc_hdr() */
820
821
/*-------------------------------------------------------------------------
822
 * Function:    H5FS_alloc_sect()
823
 *
824
 * Purpose:     Allocate space for the free-space manager section info header
825
 *
826
 * Return:      SUCCEED/FAIL
827
 *
828
 *-------------------------------------------------------------------------
829
 */
830
herr_t
831
H5FS_alloc_sect(H5F_t *f, H5FS_t *fspace)
832
0
{
833
0
    herr_t ret_value = SUCCEED; /* Return value */
834
835
0
    FUNC_ENTER_NOAPI(FAIL)
836
837
    /* Check arguments. */
838
0
    assert(f);
839
0
    assert(fspace);
840
841
0
    if (!H5_addr_defined(fspace->sect_addr) && fspace->sinfo && fspace->serial_sect_count > 0) {
842
0
        if (HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, fspace->sect_size)))
843
0
            HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for section info");
844
0
        fspace->alloc_sect_size = fspace->sect_size;
845
846
        /* Mark free-space header as dirty */
847
0
        if (H5FS__dirty(fspace) < 0)
848
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty");
849
850
        /* Cache the free-space section info */
851
0
        if (H5AC_insert_entry(f, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
852
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache");
853
854
        /* Since space has been allocated for the section info and the sinfo
855
         * has been inserted into the cache, relinquish ownership (i.e. float)
856
         * the section info.
857
         */
858
0
        fspace->sinfo = NULL;
859
0
    } /* end if */
860
861
0
done:
862
0
    FUNC_LEAVE_NOAPI(ret_value)
863
0
} /* H5FS_alloc_sect() */
864
865
/*-------------------------------------------------------------------------
866
 * Function:    H5FS_free()
867
 *
868
 * Purpose:     Free space for free-space manager header and section info header
869
 *
870
 * Return:      SUCCEED/FAIL
871
 *
872
 *-------------------------------------------------------------------------
873
 */
874
herr_t
875
H5FS_free(H5F_t *f, H5FS_t *fspace, bool free_file_space)
876
0
{
877
0
    haddr_t  saved_addr;          /* Previous address of item */
878
0
    unsigned cache_flags;         /* Flags for unprotecting cache entries */
879
0
    herr_t   ret_value = SUCCEED; /* Return value */
880
881
0
    FUNC_ENTER_NOAPI(FAIL)
882
883
    /* Check arguments. */
884
0
    assert(f);
885
0
    assert(fspace);
886
887
0
    cache_flags = H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG;
888
889
    /* Free space for section info */
890
0
    if (H5_addr_defined(fspace->sect_addr)) {
891
0
        hsize_t  saved_size;       /* Size of previous section info */
892
0
        unsigned sinfo_status = 0; /* Section info cache status */
893
894
        /* Check whether free-space manager section info is in cache or not */
895
0
        if (H5AC_get_entry_status(f, fspace->sect_addr, &sinfo_status) < 0)
896
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL,
897
0
                        "unable to check metadata cache status for free-space section info");
898
899
        /* Load free-space manager section info */
900
0
        if (sinfo_status & H5AC_ES__IN_CACHE || !fspace->sinfo) {
901
0
            H5FS_sinfo_cache_ud_t cache_udata; /* User-data for cache callback */
902
903
            /* Protect the free space sections */
904
0
            cache_udata.f      = f;
905
0
            cache_udata.fspace = fspace;
906
0
            if (NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, H5AC_FSPACE_SINFO, fspace->sect_addr,
907
0
                                                                      &cache_udata, H5AC__READ_ONLY_FLAG)))
908
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info");
909
910
            /* Unload and release ownership of the free-space manager section info */
911
0
            if (H5AC_unprotect(f, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, cache_flags) < 0)
912
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info");
913
0
        } /* end if */
914
915
0
        saved_addr = fspace->sect_addr;
916
0
        saved_size = fspace->alloc_sect_size;
917
918
0
        fspace->sect_addr       = HADDR_UNDEF;
919
0
        fspace->alloc_sect_size = 0;
920
921
        /* Free space for the free-space manager section info */
922
0
        if (!H5F_IS_TMP_ADDR(f, saved_addr)) {
923
0
            if (free_file_space && H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, saved_addr, saved_size) < 0)
924
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space sections");
925
0
        } /* end if */
926
927
        /* Mark free-space manager header as dirty */
928
0
        if (H5FS__dirty(fspace) < 0)
929
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty");
930
0
    } /* end if */
931
932
    /* Free space for header */
933
0
    if (H5_addr_defined(fspace->addr)) {
934
0
        unsigned hdr_status = 0; /* Header entry status */
935
936
        /* Check whether free-space manager header is in cache or not */
937
0
        if (H5AC_get_entry_status(f, fspace->addr, &hdr_status) < 0)
938
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL,
939
0
                        "unable to check metadata cache status for free-space section info");
940
941
0
        if (hdr_status & H5AC_ES__IN_CACHE) {
942
0
            H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
943
944
            /* Protect the free-space manager header */
945
            /* (no class information necessary since it's in the cache) */
946
0
            cache_udata.f              = f;
947
0
            cache_udata.nclasses       = 0;
948
0
            cache_udata.classes        = NULL;
949
0
            cache_udata.cls_init_udata = NULL;
950
0
            if (NULL == (fspace = (H5FS_t *)H5AC_protect(f, H5AC_FSPACE_HDR, fspace->addr, &cache_udata,
951
0
                                                         H5AC__READ_ONLY_FLAG)))
952
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info");
953
954
            /* Unpin the free-space manager header */
955
0
            if (H5AC_unpin_entry(fspace) < 0)
956
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap header");
957
958
            /* Unload and release ownership of the free-space header */
959
0
            if (H5AC_unprotect(f, H5AC_FSPACE_HDR, fspace->addr, fspace, cache_flags) < 0)
960
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info");
961
0
        } /* end if */
962
963
0
        saved_addr   = fspace->addr;
964
0
        fspace->addr = HADDR_UNDEF;
965
966
        /* Free space for the free-space manager header */
967
0
        if (free_file_space &&
968
0
            H5MF_xfree(f, H5FD_MEM_FSPACE_HDR, saved_addr, (hsize_t)H5FS_HEADER_SIZE(f)) < 0)
969
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space header");
970
0
    } /* end if */
971
972
0
done:
973
0
    FUNC_LEAVE_NOAPI(ret_value)
974
0
} /* H5FS_free() */
975
976
/*-------------------------------------------------------------------------
977
 * Function:    H5FS__hdr_dest
978
 *
979
 * Purpose:     Destroys a free space header in memory.
980
 *
981
 * Return:      SUCCEED/FAIL
982
 *
983
 *-------------------------------------------------------------------------
984
 */
985
herr_t
986
H5FS__hdr_dest(H5FS_t *fspace)
987
0
{
988
0
    unsigned u;                   /* Local index variable */
989
0
    herr_t   ret_value = SUCCEED; /* Return value */
990
991
0
    FUNC_ENTER_PACKAGE
992
993
    /*
994
     * Check arguments.
995
     */
996
0
    assert(fspace);
997
998
    /* Terminate the section classes for this free space list */
999
0
    for (u = 0; u < fspace->nclasses; u++) {
1000
        /* Call the class termination routine, if there is one */
1001
0
        if (fspace->sect_cls[u].term_cls)
1002
0
            if ((fspace->sect_cls[u].term_cls)(&fspace->sect_cls[u]) < 0)
1003
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "unable to finalize section class");
1004
0
    } /* end for */
1005
1006
    /* Release the memory for the free space section classes */
1007
0
    if (fspace->sect_cls)
1008
0
        fspace->sect_cls = (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
1009
1010
    /* Free free space info */
1011
0
    fspace = H5FL_FREE(H5FS_t, fspace);
1012
1013
0
done:
1014
0
    FUNC_LEAVE_NOAPI(ret_value)
1015
0
} /* end H5FS__hdr_dest() */
1016
1017
/*-------------------------------------------------------------------------
1018
 * Function:    H5FS__sinfo_free_sect_cb
1019
 *
1020
 * Purpose:     Free a size-tracking node for a bin
1021
 *
1022
 * Return:      SUCCEED (Can't fail)
1023
 *
1024
 *-------------------------------------------------------------------------
1025
 */
1026
static herr_t
1027
H5FS__sinfo_free_sect_cb(void *_sect, void H5_ATTR_UNUSED *key, void *op_data)
1028
0
{
1029
0
    H5FS_section_info_t *sect  = (H5FS_section_info_t *)_sect;  /* Section to free */
1030
0
    const H5FS_sinfo_t  *sinfo = (const H5FS_sinfo_t *)op_data; /* Free space manager for section */
1031
1032
0
    FUNC_ENTER_PACKAGE_NOERR
1033
1034
0
    assert(sect);
1035
0
    assert(sinfo);
1036
1037
    /* Call the section's class 'free' method on the section */
1038
0
    (*sinfo->fspace->sect_cls[sect->type].free)(sect);
1039
1040
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1041
0
} /* H5FS__sinfo_free_sect_cb() */
1042
1043
/*-------------------------------------------------------------------------
1044
 * Function:    H5FS__sinfo_free_node_cb
1045
 *
1046
 * Purpose:     Free a size-tracking node for a bin
1047
 *
1048
 * Return:      SUCCEED (Can't fail)
1049
 *
1050
 *-------------------------------------------------------------------------
1051
 */
1052
static herr_t
1053
H5FS__sinfo_free_node_cb(void *item, void H5_ATTR_UNUSED *key, void *op_data)
1054
0
{
1055
0
    H5FS_node_t *fspace_node = (H5FS_node_t *)item; /* Temporary pointer to free space list node */
1056
1057
0
    FUNC_ENTER_PACKAGE_NOERR
1058
1059
0
    assert(fspace_node);
1060
0
    assert(op_data);
1061
1062
    /* Release the skip list for sections of this size */
1063
0
    H5SL_destroy(fspace_node->sect_list, H5FS__sinfo_free_sect_cb, op_data);
1064
1065
    /* Release free space list node */
1066
0
    fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
1067
1068
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1069
0
} /* H5FS__sinfo_free_node_cb() */
1070
1071
/*-------------------------------------------------------------------------
1072
 * Function:    H5FS__sinfo_dest
1073
 *
1074
 * Purpose:     Destroys a free space section info in memory.
1075
 *
1076
 * Return:      SUCCEED/FAIL
1077
 *
1078
 *-------------------------------------------------------------------------
1079
 */
1080
herr_t
1081
H5FS__sinfo_dest(H5FS_sinfo_t *sinfo)
1082
0
{
1083
0
    unsigned u;                   /* Local index variable */
1084
0
    herr_t   ret_value = SUCCEED; /* Return value */
1085
1086
0
    FUNC_ENTER_PACKAGE
1087
1088
    /*
1089
     * Check arguments.
1090
     */
1091
0
    assert(sinfo);
1092
0
    assert(sinfo->fspace);
1093
0
    assert(sinfo->bins);
1094
1095
    /* Clear out lists of nodes */
1096
0
    for (u = 0; u < sinfo->nbins; u++)
1097
0
        if (sinfo->bins[u].bin_list) {
1098
0
            H5SL_destroy(sinfo->bins[u].bin_list, H5FS__sinfo_free_node_cb, sinfo);
1099
0
            sinfo->bins[u].bin_list = NULL;
1100
0
        } /* end if */
1101
1102
    /* Release bins for skip lists */
1103
0
    sinfo->bins = H5FL_SEQ_FREE(H5FS_bin_t, sinfo->bins);
1104
1105
    /* Release skip list for merging sections */
1106
0
    if (sinfo->merge_list)
1107
0
        if (H5SL_close(sinfo->merge_list) < 0)
1108
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy section merging skip list");
1109
1110
    /* Decrement the reference count on free space header */
1111
    /* (make certain this is last action with section info, to allow for header
1112
     *  disappearing immediately)
1113
     */
1114
0
    sinfo->fspace->sinfo = NULL;
1115
0
    if (H5FS__decr(sinfo->fspace) < 0)
1116
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header");
1117
0
    sinfo->fspace = NULL;
1118
1119
    /* Release free space section info */
1120
0
    sinfo = H5FL_FREE(H5FS_sinfo_t, sinfo);
1121
1122
0
done:
1123
0
    FUNC_LEAVE_NOAPI(ret_value)
1124
0
} /* end H5FS__sinfo_dest() */
1125
1126
herr_t
1127
H5FS_get_sect_count(const H5FS_t *frsp, hsize_t *tot_sect_count)
1128
0
{
1129
0
    herr_t ret_value = SUCCEED; /* Return value */
1130
1131
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1132
1133
    /* Check arguments. */
1134
0
    assert(frsp);
1135
0
    assert(tot_sect_count);
1136
1137
    /* Report statistics for free space */
1138
0
    *tot_sect_count = frsp->serial_sect_count;
1139
1140
0
    FUNC_LEAVE_NOAPI(ret_value)
1141
0
}
1142
1143
#ifdef H5FS_DEBUG_ASSERT
1144
1145
/*-------------------------------------------------------------------------
1146
 * Function:    H5FS__assert
1147
 *
1148
 * Purpose:     Verify that the free space manager is mostly sane
1149
 *
1150
 * Return:      void
1151
 *
1152
 *-------------------------------------------------------------------------
1153
 */
1154
void
1155
H5FS__assert(const H5FS_t *fspace)
1156
{
1157
    FUNC_ENTER_PACKAGE_NOERR
1158
1159
    /* Checks for section info, if it's available */
1160
    if (fspace->sinfo) {
1161
        /* Sanity check sections */
1162
        H5FS__sect_assert(fspace);
1163
1164
        /* General assumptions about the section size counts */
1165
        assert(fspace->sinfo->tot_size_count >= fspace->sinfo->serial_size_count);
1166
        assert(fspace->sinfo->tot_size_count >= fspace->sinfo->ghost_size_count);
1167
    } /* end if */
1168
1169
    /* General assumptions about the section counts */
1170
    assert(fspace->tot_sect_count >= fspace->serial_sect_count);
1171
    assert(fspace->tot_sect_count >= fspace->ghost_sect_count);
1172
    assert(fspace->tot_sect_count == (fspace->serial_sect_count + fspace->ghost_sect_count));
1173
1174
    FUNC_LEAVE_NOAPI_VOID
1175
} /* end H5FS__assert() */
1176
#endif /* H5FS_DEBUG_ASSERT */