Coverage Report

Created: 2026-03-04 00:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5FSsection.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
 */
17
18
/****************/
19
/* Module Setup */
20
/****************/
21
22
#define H5F_FRIEND /*suppress error about including H5Fpkg   */
23
24
#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
25
26
/***********/
27
/* Headers */
28
/***********/
29
#include "H5private.h"   /* Generic Functions     */
30
#include "H5Eprivate.h"  /* Error handling        */
31
#include "H5Fpkg.h"      /* File access                          */
32
#include "H5FLprivate.h" /* Free Lists                               */
33
#include "H5FSpkg.h"     /* File free space     */
34
#include "H5MFprivate.h" /* File memory management    */
35
#include "H5SLprivate.h" /* Skip Lists                               */
36
#include "H5VMprivate.h" /* Vectors and arrays      */
37
38
/****************/
39
/* Local Macros */
40
/****************/
41
42
/******************/
43
/* Local Typedefs */
44
/******************/
45
46
/* User data for skip list iterator callback for iterating over section size nodes */
47
typedef struct {
48
    H5FS_t         *fspace;  /* Free space manager info */
49
    H5FS_operator_t op;      /* Operator for the iteration */
50
    void           *op_data; /* Information to pass to the operator */
51
} H5FS_iter_ud_t;
52
53
/********************/
54
/* Package Typedefs */
55
/********************/
56
57
/********************/
58
/* Local Prototypes */
59
/********************/
60
static herr_t H5FS__sect_increase(H5FS_t *fspace, const H5FS_section_class_t *cls, unsigned flags);
61
static herr_t H5FS__sect_decrease(H5FS_t *fspace, const H5FS_section_class_t *cls);
62
static herr_t H5FS__size_node_decr(H5FS_sinfo_t *sinfo, unsigned bin, H5FS_node_t *fspace_node,
63
                                   const H5FS_section_class_t *cls);
64
static herr_t H5FS__sect_unlink_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls,
65
                                     H5FS_section_info_t *sect);
66
static herr_t H5FS__sect_unlink_rest(H5FS_t *fspace, const H5FS_section_class_t *cls,
67
                                     H5FS_section_info_t *sect);
68
static herr_t H5FS__sect_remove_real(H5FS_t *fspace, H5FS_section_info_t *sect);
69
static herr_t H5FS__sect_link_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls,
70
                                   H5FS_section_info_t *sect);
71
static herr_t H5FS__sect_link_rest(H5FS_t *fspace, const H5FS_section_class_t *cls, H5FS_section_info_t *sect,
72
                                   unsigned flags);
73
static herr_t H5FS__sect_link(H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags);
74
static herr_t H5FS__sect_merge(H5FS_t *fspace, H5FS_section_info_t **sect, void *op_data);
75
static htri_t H5FS__sect_find_node(H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node);
76
static herr_t H5FS__sect_serialize_size(H5FS_t *fspace);
77
78
/*********************/
79
/* Package Variables */
80
/*********************/
81
82
/* Declare a free list to manage the H5FS_node_t struct */
83
H5FL_DEFINE(H5FS_node_t);
84
85
/* Declare a free list to manage the H5FS_bin_t sequence information */
86
H5FL_SEQ_DEFINE(H5FS_bin_t);
87
88
/* Declare a free list to manage the H5FS_sinfo_t struct */
89
H5FL_DEFINE(H5FS_sinfo_t);
90
91
/*****************************/
92
/* Library Private Variables */
93
/*****************************/
94
95
/*******************/
96
/* Local Variables */
97
/*******************/
98
99
/*-------------------------------------------------------------------------
100
 * Function:    H5FS__sinfo_new
101
 *
102
 * Purpose:     Create new section info structure
103
 *
104
 * Return:      Success:    non-NULL, pointer to new section info struct
105
 *              Failure:    NULL
106
 *
107
 *-------------------------------------------------------------------------
108
 */
109
H5FS_sinfo_t *
110
H5FS__sinfo_new(H5F_t *f, H5FS_t *fspace)
111
0
{
112
0
    H5FS_sinfo_t *sinfo     = NULL; /* Section information struct created */
113
0
    H5FS_sinfo_t *ret_value = NULL; /* Return value */
114
115
0
    FUNC_ENTER_PACKAGE
116
117
    /* Check arguments. */
118
0
    assert(f);
119
0
    assert(fspace);
120
#ifdef H5FS_SINFO_DEBUG
121
    fprintf(stderr, "%s: fspace->addr = %" PRIuHADDR "\n", __func__, fspace->addr);
122
#endif /* H5FS_SINFO_DEBUG */
123
124
    /* Allocate the free space header */
125
0
    if (NULL == (sinfo = H5FL_CALLOC(H5FS_sinfo_t)))
126
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
127
128
    /* Set non-zero values */
129
0
    sinfo->nbins            = H5VM_log2_gen(fspace->max_sect_size);
130
0
    sinfo->sect_prefix_size = H5FS_SINFO_PREFIX_SIZE(f);
131
0
    sinfo->sect_off_size    = (fspace->max_sect_addr + 7) / 8;
132
0
    sinfo->sect_len_size    = H5VM_limit_enc_size((uint64_t)fspace->max_sect_size);
133
#ifdef H5FS_SINFO_DEBUG
134
    fprintf(stderr, "%s: fspace->max_sect_size = %" PRIuHSIZE "\n", __func__, fspace->max_sect_size);
135
    fprintf(stderr, "%s: fspace->max_sect_addr = %u\n", __func__, fspace->max_sect_addr);
136
    fprintf(stderr, "%s: sinfo->nbins = %u\n", __func__, sinfo->nbins);
137
    fprintf(stderr, "%s: sinfo->sect_off_size = %u, sinfo->sect_len_size = %u\n", __func__,
138
            sinfo->sect_off_size, sinfo->sect_len_size);
139
#endif /* H5FS_SINFO_DEBUG */
140
141
    /* Allocate space for the section size bins */
142
0
    if (NULL == (sinfo->bins = H5FL_SEQ_CALLOC(H5FS_bin_t, (size_t)sinfo->nbins)))
143
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
144
0
                    "memory allocation failed for free space section bin array");
145
146
    /* Increment the reference count on the free space manager header */
147
0
    if (H5FS__incr(fspace) < 0)
148
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINC, NULL, "unable to increment ref. count on free space header");
149
0
    sinfo->fspace = fspace;
150
151
    /* Link free space manager to section info */
152
    /* (for deserializing sections) */
153
0
    assert(fspace->sinfo == NULL);
154
0
    fspace->sinfo = sinfo;
155
156
    /* Set return value */
157
0
    ret_value = sinfo;
158
159
0
done:
160
0
    if (ret_value == NULL && sinfo) {
161
        /* Release bins for skip lists */
162
0
        if (sinfo->bins)
163
0
            sinfo->bins = H5FL_SEQ_FREE(H5FS_bin_t, sinfo->bins);
164
165
        /* Release free space section info */
166
0
        sinfo = H5FL_FREE(H5FS_sinfo_t, sinfo);
167
0
    } /* end if */
168
169
0
    FUNC_LEAVE_NOAPI(ret_value)
170
0
} /* H5FS__sinfo_new() */
171
172
/*-------------------------------------------------------------------------
173
 * Function:    H5FS__sinfo_lock
174
 *
175
 * Purpose:     Make certain the section info for the free space manager is
176
 *              in memory.
177
 *
178
 *              Either uses existing section info owned by the free space
179
 *              header, loads section info from disk, or creates new section
180
 *              info
181
 *
182
 * Return:      SUCCEED/FAIL
183
 *
184
 *-------------------------------------------------------------------------
185
 */
186
static herr_t
187
H5FS__sinfo_lock(H5F_t *f, H5FS_t *fspace, unsigned accmode)
188
0
{
189
0
    H5FS_sinfo_cache_ud_t cache_udata;         /* User-data for cache callback */
190
0
    herr_t                ret_value = SUCCEED; /* Return value */
191
192
0
    FUNC_ENTER_PACKAGE
193
194
#ifdef H5FS_SINFO_DEBUG
195
    fprintf(stderr,
196
            "%s: Called, fspace->addr = %" PRIuHADDR ", fspace->sinfo = %p, fspace->sect_addr = %" PRIuHADDR
197
            "\n",
198
            __func__, fspace->addr, (void *)fspace->sinfo, fspace->sect_addr);
199
    fprintf(stderr, "%s: fspace->alloc_sect_size = %" PRIuHSIZE ", fspace->sect_size = %" PRIuHSIZE "\n",
200
            __func__, fspace->alloc_sect_size, fspace->sect_size);
201
#endif /* H5FS_SINFO_DEBUG */
202
203
    /* Check arguments. */
204
0
    assert(f);
205
0
    assert(fspace);
206
207
    /* only H5AC__READ_ONLY_FLAG may appear in accmode */
208
0
    assert((accmode & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
209
210
    /* If the free space header doesn't already "own" the section info, load
211
     *  section info or create it
212
     */
213
0
    if (fspace->sinfo) {
214
        /* Check if the section info was protected & we want a different access mode */
215
216
        /* only H5AC__READ_ONLY_FLAG may appear in fspace->sinfo_accmode */
217
0
        assert(((fspace->sinfo_accmode) & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
218
219
0
        if (fspace->sinfo_protected && accmode != fspace->sinfo_accmode) {
220
            /* Check if we need to switch from read-only access to read-write */
221
0
            if (0 == (accmode & (unsigned)(~H5AC__READ_ONLY_FLAG))) {
222
                /* Unprotect the read-only section info */
223
0
                if (H5AC_unprotect(f, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo,
224
0
                                   H5AC__NO_FLAGS_SET) < 0)
225
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL,
226
0
                                "unable to release free space section info");
227
228
                /* Re-protect the section info with read-write access */
229
0
                cache_udata.f      = f;
230
0
                cache_udata.fspace = fspace;
231
0
                if (NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(
232
0
                                 f, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
233
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to load free space sections");
234
235
                /* Switch the access mode we have */
236
0
                fspace->sinfo_accmode = H5AC__NO_FLAGS_SET;
237
0
            } /* end if */
238
0
        }     /* end if */
239
0
    }         /* end if */
240
0
    else {
241
        /* If the section address is defined, load it from the file */
242
0
        if (H5_addr_defined(fspace->sect_addr)) {
243
            /* Sanity check */
244
0
            assert(fspace->sinfo_protected == false);
245
0
            assert(H5_addr_defined(fspace->addr));
246
247
#ifdef H5FS_SINFO_DEBUG
248
            fprintf(stderr, "%s: Reading in existing sections, fspace->sect_addr = %" PRIuHADDR "\n",
249
                    __func__, fspace->sect_addr);
250
#endif /* H5FS_SINFO_DEBUG */
251
            /* Protect the free space sections */
252
0
            cache_udata.f      = f;
253
0
            cache_udata.fspace = fspace;
254
0
            if (NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, H5AC_FSPACE_SINFO, fspace->sect_addr,
255
0
                                                                      &cache_udata, accmode)))
256
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to load free space sections");
257
258
            /* Remember that we protected the section info & the access mode */
259
0
            fspace->sinfo_protected = true;
260
0
            fspace->sinfo_accmode   = accmode;
261
0
        } /* end if */
262
0
        else {
263
#ifdef H5FS_SINFO_DEBUG
264
            fprintf(stderr, "%s: Creating new section info\n", __func__);
265
#endif /* H5FS_SINFO_DEBUG */
266
            /* Sanity check */
267
0
            assert(fspace->tot_sect_count == 0);
268
0
            assert(fspace->serial_sect_count == 0);
269
0
            assert(fspace->ghost_sect_count == 0);
270
271
            /* Allocate and initialize free space section info */
272
0
            if (NULL == (fspace->sinfo = H5FS__sinfo_new(f, fspace)))
273
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create section info");
274
275
            /* Set initial size of section info to 0 */
276
0
            fspace->sect_size = fspace->alloc_sect_size = 0;
277
0
        } /* end if */
278
0
    }     /* end if */
279
0
    assert(fspace->rc == 2);
280
281
    /* Increment the section info lock count */
282
0
    fspace->sinfo_lock_count++;
283
284
0
done:
285
#ifdef H5FS_SINFO_DEBUG
286
    fprintf(stderr,
287
            "%s: Leaving, fspace->addr = %" PRIuHADDR ", fspace->sinfo = %p, fspace->sect_addr = %" PRIuHADDR
288
            "\n",
289
            __func__, fspace->addr, (void *)fspace->sinfo, fspace->sect_addr);
290
    fprintf(stderr, "%s: fspace->alloc_sect_size = %" PRIuHSIZE ", fspace->sect_size = %" PRIuHSIZE "\n",
291
            __func__, fspace->alloc_sect_size, fspace->sect_size);
292
#endif /* H5FS_SINFO_DEBUG */
293
0
    FUNC_LEAVE_NOAPI(ret_value)
294
0
} /* H5FS__sinfo_lock() */
295
296
/*-------------------------------------------------------------------------
297
 * Function:    H5FS__sinfo_unlock
298
 *
299
 * Purpose:     Release the section info, either giving ownership back to
300
 *              the cache or letting the free space header keep it.
301
 *
302
 *              Add the fix in this routine to resolve the potential infinite loop
303
 *              problem when allocating file space for the meta data of the
304
 *              self-referential free-space managers at file closing.
305
 *
306
 *              On file close or flushing, when the section info is modified
307
 *              and protected/unprotected, does not allow the section info size
308
 *              to shrink:
309
 *              --if the current allocated section info size in fspace->sect_size is
310
 *                larger than the previous section info size in fpsace->alloc_sect_size,
311
 *                 release the section info
312
 *              --Otherwise, set the fspace->sect_size to be the same as
313
 *                fpsace->alloc_sect_size.  This means fspace->sect_size may be larger
314
 *                than what is actually needed.
315
 *
316
 * Return:      SUCCEED/FAIL
317
 *
318
 *-------------------------------------------------------------------------
319
 */
320
static herr_t
321
H5FS__sinfo_unlock(H5F_t *f, H5FS_t *fspace, bool modified)
322
0
{
323
0
    herr_t ret_value = SUCCEED; /* Return value */
324
325
0
    FUNC_ENTER_PACKAGE
326
#ifdef H5FS_SINFO_DEBUG
327
    fprintf(stderr,
328
            "%s: Called, modified = %d, fspace->addr = %" PRIuHADDR ", fspace->sect_addr = %" PRIuHADDR "\n",
329
            __func__, modified, fspace->addr, fspace->sect_addr);
330
    fprintf(stderr,
331
            "%s: fspace->sinfo_lock_count = %u, fspace->sinfo_modified = %d, fspace->sinfo_protected = %d\n",
332
            __func__, fspace->sinfo_lock_count, fspace->sinfo_modified, fspace->sinfo_protected);
333
    fprintf(stderr, "%s: fspace->alloc_sect_size = %" PRIuHSIZE ", fspace->sect_size = %" PRIuHSIZE "\n",
334
            __func__, fspace->alloc_sect_size, fspace->sect_size);
335
#endif /* H5FS_SINFO_DEBUG */
336
337
    /* Check arguments. */
338
0
    assert(f);
339
0
    assert(fspace);
340
0
    assert(fspace->rc == 2);
341
0
    assert(fspace->sinfo);
342
343
    /* Check if we modified any section */
344
0
    if (modified) {
345
        /* Check if the section info was protected with a different access mode */
346
0
        if (fspace->sinfo_protected && (0 != ((fspace->sinfo_accmode) & H5AC__READ_ONLY_FLAG)))
347
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTDIRTY, FAIL, "attempt to modify read-only section info");
348
349
        /* If we modified the section info, mark it dirty */
350
0
        fspace->sinfo->dirty = true;
351
352
        /* Remember that the section info was modified while locked */
353
0
        fspace->sinfo_modified = true;
354
355
        /* Assume that the modification will affect the statistics in the header
356
         *  and mark that dirty also
357
         */
358
0
        if (H5FS__dirty(fspace) < 0)
359
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty");
360
0
    } /* end if */
361
362
    /* Decrement the lock count on the section info */
363
0
    fspace->sinfo_lock_count--;
364
365
    /* Check if section info lock count dropped to zero */
366
0
    if (fspace->sinfo_lock_count == 0) {
367
0
        bool release_sinfo_space = false; /* Flag to indicate section info space in file should be released */
368
0
        bool closing_or_flushing = f->shared->closing; /* Is closing or flushing in progress */
369
370
        /* Check whether cache-flush is in progress if closing is not. */
371
0
        if (!closing_or_flushing &&
372
0
            H5AC_get_cache_flush_in_progress(f->shared->cache, &closing_or_flushing) < 0)
373
0
            HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get flush_in_progress");
374
375
        /* Check if we actually protected the section info */
376
0
        if (fspace->sinfo_protected) {
377
0
            unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap */
378
379
            /* Sanity check */
380
0
            assert(H5_addr_defined(fspace->addr));
381
382
            /* Check if we've made new changes to the section info while locked */
383
0
            if (fspace->sinfo_modified) {
384
                /* Note that we've modified the section info */
385
0
                cache_flags |= H5AC__DIRTIED_FLAG;
386
387
                /* On file close or flushing, does not allow section info to shrink in size */
388
0
                if (closing_or_flushing) {
389
0
                    if (fspace->sect_size > fspace->alloc_sect_size)
390
0
                        cache_flags |= H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG;
391
0
                    else
392
0
                        fspace->sect_size = fspace->alloc_sect_size;
393
394
                    /* Check if the section info size in the file has changed */
395
0
                }
396
0
                else if (fspace->sect_size != fspace->alloc_sect_size)
397
0
                    cache_flags |= H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG;
398
399
0
            } /* end if */
400
401
            /* Sanity check */
402
0
            assert(H5_addr_defined(fspace->sect_addr));
403
404
            /* Unprotect section info in cache */
405
            /* (Possibly dirty) */
406
            /* (Possibly taking ownership from the cache) */
407
#ifdef H5FS_SINFO_DEBUG
408
            fprintf(stderr, "%s: Unprotecting section info, cache_flags = %u\n", __func__, cache_flags);
409
#endif /* H5FS_SINFO_DEBUG */
410
0
            if (H5AC_unprotect(f, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, cache_flags) < 0)
411
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info");
412
413
            /* Reset the protected flag on the section info */
414
0
            fspace->sinfo_protected = false;
415
416
            /* Check if header is taking ownership of section info */
417
0
            if ((cache_flags & H5AC__TAKE_OWNERSHIP_FLAG)) {
418
#ifdef H5FS_SINFO_DEBUG
419
                fprintf(stderr, "%s: Taking ownership of section info\n", __func__);
420
#endif /* H5FS_SINFO_DEBUG */
421
                /* Set flag to release section info space in file */
422
0
                release_sinfo_space = true;
423
0
            } /* end if */
424
0
            else {
425
#ifdef H5FS_SINFO_DEBUG
426
                fprintf(stderr, "%s: Relinquishing section info ownership\n", __func__);
427
#endif /* H5FS_SINFO_DEBUG */
428
                /* Free space header relinquished ownership of section info */
429
0
                fspace->sinfo = NULL;
430
0
            } /* end else */
431
0
        }     /* end if */
432
0
        else {
433
            /* Check if the section info was modified */
434
0
            if (fspace->sinfo_modified) {
435
                /* Check if we need to release section info in the file */
436
0
                if (H5_addr_defined(fspace->sect_addr)) {
437
                    /* Set flag to release section info space in file */
438
                    /* On file close or flushing, only need to release section info with size
439
                       bigger than previous section */
440
0
                    if (closing_or_flushing) {
441
0
                        if (fspace->sect_size > fspace->alloc_sect_size)
442
0
                            release_sinfo_space = true;
443
0
                        else
444
0
                            fspace->sect_size = fspace->alloc_sect_size;
445
0
                    }
446
0
                    else
447
0
                        release_sinfo_space = true;
448
0
                }
449
0
                else
450
0
                    assert(fspace->alloc_sect_size == 0);
451
452
0
            } /* end if */
453
0
            else {
454
                /* Sanity checks... */
455
0
                if (H5_addr_defined(fspace->sect_addr))
456
0
                    assert(fspace->alloc_sect_size == fspace->sect_size);
457
0
                else
458
0
                    assert(fspace->alloc_sect_size == 0);
459
0
            } /* end else */
460
0
        }     /* end else */
461
462
        /* Reset the "section info modified" flag */
463
0
        fspace->sinfo_modified = false;
464
465
        /* Check if header needs to release section info in the file */
466
0
        if (release_sinfo_space) {
467
0
            haddr_t old_sect_addr       = fspace->sect_addr; /* Previous location of section info in file */
468
0
            hsize_t old_alloc_sect_size = fspace->alloc_sect_size; /* Previous size of section info in file */
469
470
            /* Sanity check */
471
0
            assert(H5_addr_defined(fspace->addr));
472
473
            /* Reset section info in header */
474
0
            fspace->sect_addr       = HADDR_UNDEF;
475
0
            fspace->alloc_sect_size = 0;
476
477
            /* If we haven't already marked the header dirty, do so now */
478
0
            if (!modified)
479
0
                if (H5FS__dirty(fspace) < 0)
480
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
481
0
                                "unable to mark free space header as dirty");
482
483
#ifdef H5FS_SINFO_DEBUG
484
            fprintf(stderr,
485
                    "%s: Freeing section info on disk, old_sect_addr = %" PRIuHADDR
486
                    ", old_alloc_sect_size = %" PRIuHSIZE "\n",
487
                    __func__, old_sect_addr, old_alloc_sect_size);
488
#endif /* H5FS_SINFO_DEBUG */
489
            /* Release space for section info in file */
490
0
            if (!H5F_IS_TMP_ADDR(f, old_sect_addr))
491
0
                if (H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, old_sect_addr, old_alloc_sect_size) < 0)
492
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections");
493
0
        } /* end if */
494
0
    }     /* end if */
495
496
0
done:
497
#ifdef H5FS_SINFO_DEBUG
498
    fprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value);
499
#endif /* H5FS_SINFO_DEBUG */
500
0
    FUNC_LEAVE_NOAPI(ret_value)
501
0
} /* H5FS__sinfo_unlock() */
502
503
/*-------------------------------------------------------------------------
504
 * Function:    H5FS__sect_serialize_size
505
 *
506
 * Purpose:     Determine serialized size of all sections in free space manager
507
 *
508
 * Return:      SUCCEED/FAIL
509
 *
510
 *-------------------------------------------------------------------------
511
 */
512
static herr_t
513
H5FS__sect_serialize_size(H5FS_t *fspace)
514
0
{
515
0
    FUNC_ENTER_PACKAGE_NOERR
516
517
    /* Check arguments. */
518
0
    assert(fspace);
519
520
    /* Compute the size of the buffer required to serialize all the sections */
521
0
    if (fspace->serial_sect_count > 0) {
522
0
        size_t sect_buf_size; /* Section buffer size */
523
524
        /* Serialized sections prefix */
525
0
        sect_buf_size = fspace->sinfo->sect_prefix_size;
526
527
        /* Count for each differently sized serializable section */
528
0
        sect_buf_size +=
529
0
            fspace->sinfo->serial_size_count * H5VM_limit_enc_size((uint64_t)fspace->serial_sect_count);
530
531
        /* Size for each differently sized serializable section */
532
0
        sect_buf_size += fspace->sinfo->serial_size_count * fspace->sinfo->sect_len_size;
533
534
        /* Offsets of each section in address space */
535
0
        sect_buf_size += fspace->serial_sect_count * fspace->sinfo->sect_off_size;
536
537
        /* Class of each section */
538
0
        sect_buf_size += fspace->serial_sect_count * 1 /* byte */;
539
540
        /* Extra space required to serialize each section */
541
0
        sect_buf_size += fspace->sinfo->serial_size;
542
543
        /* Update section size in header */
544
0
        fspace->sect_size = sect_buf_size;
545
0
    } /* end if */
546
0
    else
547
        /* Reset section size in header */
548
0
        fspace->sect_size = fspace->sinfo->sect_prefix_size;
549
550
0
    FUNC_LEAVE_NOAPI(SUCCEED)
551
0
} /* H5FS__sect_serialize_size() */
552
553
/*-------------------------------------------------------------------------
554
 * Function:    H5FS__sect_increase
555
 *
556
 * Purpose:     Increase the size of the serialized free space section info
557
 *              on disk
558
 *
559
 * Return:      SUCCEED/FAIL
560
 *
561
 *-------------------------------------------------------------------------
562
 */
563
static herr_t
564
H5FS__sect_increase(H5FS_t *fspace, const H5FS_section_class_t *cls, unsigned flags)
565
0
{
566
0
    herr_t ret_value = SUCCEED; /* Return value */
567
568
0
    FUNC_ENTER_PACKAGE
569
570
    /* Check arguments. */
571
0
    assert(fspace);
572
0
    assert(fspace->sinfo);
573
0
    assert(cls);
574
575
    /* Increment total # of sections on free space list */
576
0
    fspace->tot_sect_count++;
577
578
    /* Check for serializable or 'ghost' section */
579
0
    if (cls->flags & H5FS_CLS_GHOST_OBJ) {
580
        /* Sanity check */
581
0
        assert(cls->serial_size == 0);
582
583
        /* Increment # of ghost sections */
584
0
        fspace->ghost_sect_count++;
585
0
    } /* end if */
586
0
    else {
587
        /* Increment # of serializable sections */
588
0
        fspace->serial_sect_count++;
589
590
        /* Increment amount of space required to serialize all sections */
591
0
        fspace->sinfo->serial_size += cls->serial_size;
592
593
        /* Update the free space sections' serialized size */
594
        /* (if we're not deserializing the sections from disk) */
595
0
        if (!(flags & H5FS_ADD_DESERIALIZING)) {
596
0
            if (H5FS__sect_serialize_size(fspace) < 0)
597
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL,
598
0
                            "can't adjust free space section size on disk");
599
0
        } /* end if */
600
0
    }     /* end else */
601
602
0
done:
603
0
    FUNC_LEAVE_NOAPI(ret_value)
604
0
} /* H5FS__sect_increase() */
605
606
/*-------------------------------------------------------------------------
607
 * Function:    H5FS__sect_decrease
608
 *
609
 * Purpose:     Decrease the size of the serialized free space section info
610
 *              on disk
611
 *
612
 * Return:      SUCCEED/FAIL
613
 *
614
 *-------------------------------------------------------------------------
615
 */
616
static herr_t
617
H5FS__sect_decrease(H5FS_t *fspace, const H5FS_section_class_t *cls)
618
0
{
619
0
    herr_t ret_value = SUCCEED; /* Return value */
620
621
0
    FUNC_ENTER_PACKAGE
622
623
    /* Check arguments. */
624
0
    assert(fspace);
625
0
    assert(fspace->sinfo);
626
0
    assert(cls);
627
628
    /* Decrement total # of sections in free space manager */
629
0
    fspace->tot_sect_count--;
630
631
    /* Check for serializable or 'ghost' section */
632
0
    if (cls->flags & H5FS_CLS_GHOST_OBJ) {
633
        /* Sanity check */
634
0
        assert(cls->serial_size == 0);
635
636
        /* Decrement # of ghost sections */
637
0
        fspace->ghost_sect_count--;
638
0
    } /* end if */
639
0
    else {
640
        /* Decrement # of serializable sections */
641
0
        fspace->serial_sect_count--;
642
643
        /* Decrement amount of space required to serialize all sections */
644
0
        fspace->sinfo->serial_size -= cls->serial_size;
645
646
        /* Update the free space sections' serialized size */
647
0
        if (H5FS__sect_serialize_size(fspace) < 0)
648
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk");
649
0
    } /* end else */
650
651
0
done:
652
0
    FUNC_LEAVE_NOAPI(ret_value)
653
0
} /* H5FS__sect_decrease() */
654
655
/*-------------------------------------------------------------------------
656
 * Function:    H5FS__size_node_decr
657
 *
658
 * Purpose:     Decrement the number of sections of a particular size
659
 *
660
 * Return:      SUCCEED/FAIL
661
 *
662
 *-------------------------------------------------------------------------
663
 */
664
static herr_t
665
H5FS__size_node_decr(H5FS_sinfo_t *sinfo, unsigned bin, H5FS_node_t *fspace_node,
666
                     const H5FS_section_class_t *cls)
667
0
{
668
0
    herr_t ret_value = SUCCEED; /* Return value */
669
670
0
    FUNC_ENTER_PACKAGE
671
672
    /* Check arguments. */
673
0
    assert(sinfo);
674
0
    assert(fspace_node);
675
0
    assert(cls);
676
677
    /* Decrement the # of sections in this bin */
678
    /* (Different from the # of items in the bin's skiplist, since each node on
679
     *  the bin's skiplist is also a skiplist...)
680
     */
681
0
    sinfo->bins[bin].tot_sect_count--;
682
683
    /* Check for 'ghost' or 'serializable' section */
684
0
    if (cls->flags & H5FS_CLS_GHOST_OBJ) {
685
        /* Decrement node's ghost section count */
686
0
        fspace_node->ghost_count--;
687
688
        /* Decrement bin's ghost section count */
689
0
        sinfo->bins[bin].ghost_sect_count--;
690
691
        /* If the node has no more ghost sections, decrement number of ghost section sizes managed */
692
0
        if (fspace_node->ghost_count == 0)
693
0
            sinfo->ghost_size_count--;
694
0
    } /* end if */
695
0
    else {
696
        /* Decrement node's serializable section count */
697
0
        fspace_node->serial_count--;
698
699
        /* Decrement bin's serializable section count */
700
0
        sinfo->bins[bin].serial_sect_count--;
701
702
        /* If the node has no more serializable sections, decrement number of serializable section sizes
703
         * managed */
704
0
        if (fspace_node->serial_count == 0)
705
0
            sinfo->serial_size_count--;
706
0
    } /* end else */
707
708
    /* Check for no more nodes on list of that size */
709
0
    if (H5SL_count(fspace_node->sect_list) == 0) {
710
0
        H5FS_node_t *tmp_fspace_node; /* Free space list size node */
711
712
        /* Sanity checks */
713
0
        assert(fspace_node->ghost_count == 0);
714
0
        assert(fspace_node->serial_count == 0);
715
716
        /* Remove size tracking list from bin */
717
0
        tmp_fspace_node = (H5FS_node_t *)H5SL_remove(sinfo->bins[bin].bin_list, &fspace_node->sect_size);
718
0
        if (tmp_fspace_node == NULL || tmp_fspace_node != fspace_node)
719
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space node from skip list");
720
721
        /* Destroy skip list for size tracking node */
722
0
        if (H5SL_close(fspace_node->sect_list) < 0)
723
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy size tracking node's skip list");
724
725
        /* Release free space list node */
726
0
        fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
727
728
        /* Decrement total number of section sizes managed */
729
0
        sinfo->tot_size_count--;
730
0
    } /* end if */
731
732
0
done:
733
0
    FUNC_LEAVE_NOAPI(ret_value)
734
0
} /* H5FS__size_node_decr() */
735
736
/*-------------------------------------------------------------------------
737
 * Function:    H5FS__sect_unlink_size
738
 *
739
 * Purpose:     Remove a section node from size tracking data structures for
740
 *              a free space manager
741
 *
742
 * Return:      SUCCEED/FAIL
743
 *
744
 *-------------------------------------------------------------------------
745
 */
746
static herr_t
747
H5FS__sect_unlink_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls, H5FS_section_info_t *sect)
748
0
{
749
0
    H5FS_node_t         *fspace_node;         /* Free list size node */
750
0
    H5FS_section_info_t *tmp_sect_node;       /* Temporary section node */
751
0
    unsigned             bin;                 /* Bin to put the free space section in */
752
0
    herr_t               ret_value = SUCCEED; /* Return value */
753
754
0
    FUNC_ENTER_PACKAGE
755
756
    /* Check arguments. */
757
0
    assert(sinfo);
758
0
    assert(sinfo->bins);
759
0
    assert(sect);
760
0
    assert(cls);
761
762
    /* Determine correct bin which holds items of at least the section's size */
763
0
    bin = H5VM_log2_gen(sect->size);
764
0
    assert(bin < sinfo->nbins);
765
0
    if (sinfo->bins[bin].bin_list == NULL)
766
0
        HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "node's bin is empty?");
767
768
    /* Find space node for section's size */
769
0
    if ((fspace_node = (H5FS_node_t *)H5SL_search(sinfo->bins[bin].bin_list, &sect->size)) == NULL)
770
0
        HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section size node");
771
772
    /* Remove the section's node from the list */
773
0
    tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace_node->sect_list, &sect->addr);
774
0
    if (tmp_sect_node == NULL || tmp_sect_node != sect)
775
0
        HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list");
776
777
    /* Decrement # of sections in section size node */
778
0
    if (H5FS__size_node_decr(sinfo, bin, fspace_node, cls) < 0)
779
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space size node from skip list");
780
781
0
done:
782
0
    FUNC_LEAVE_NOAPI(ret_value)
783
0
} /* H5FS__sect_unlink_size() */
784
785
/*-------------------------------------------------------------------------
786
 * Function:    H5FS__sect_unlink_rest
787
 *
788
 * Purpose:     Finish unlinking a section from the rest of the free space
789
 *              manager's data structures, after the section has been removed
790
 *              from the size tracking data structures
791
 *
792
 * Return:      SUCCEED/FAIL
793
 *
794
 *-------------------------------------------------------------------------
795
 */
796
static herr_t
797
H5FS__sect_unlink_rest(H5FS_t *fspace, const H5FS_section_class_t *cls, H5FS_section_info_t *sect)
798
0
{
799
0
    herr_t ret_value = SUCCEED; /* Return value */
800
801
0
    FUNC_ENTER_PACKAGE
802
803
    /* Check arguments. */
804
0
    assert(fspace);
805
0
    assert(fspace->sinfo);
806
0
    assert(cls);
807
0
    assert(sect);
808
809
    /* Remove node from merge list, if it was entered there */
810
0
    if (!(cls->flags & H5FS_CLS_SEPAR_OBJ)) {
811
0
        H5FS_section_info_t *tmp_sect_node; /* Temporary section node */
812
813
0
        tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace->sinfo->merge_list, &sect->addr);
814
0
        if (tmp_sect_node == NULL || tmp_sect_node != sect)
815
0
            HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list");
816
0
    } /* end if */
817
818
    /* Update section info & check if we need less room for the serialized free space sections */
819
0
    if (H5FS__sect_decrease(fspace, cls) < 0)
820
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk");
821
822
    /* Decrement amount of free space managed */
823
0
    fspace->tot_space -= sect->size;
824
825
0
done:
826
0
    FUNC_LEAVE_NOAPI(ret_value)
827
0
} /* H5FS__sect_unlink_rest() */
828
829
/*-------------------------------------------------------------------------
830
 * Function:    H5FS__sect_remove_real
831
 *
832
 * Purpose:     Remove a section from the free space manager
833
 *
834
 * Return:      SUCCEED/FAIL
835
 *
836
 *-------------------------------------------------------------------------
837
 */
838
static herr_t
839
H5FS__sect_remove_real(H5FS_t *fspace, H5FS_section_info_t *sect)
840
0
{
841
0
    const H5FS_section_class_t *cls;                 /* Class of section */
842
0
    herr_t                      ret_value = SUCCEED; /* Return value */
843
844
0
    FUNC_ENTER_PACKAGE
845
846
    /* Check arguments. */
847
0
    assert(fspace);
848
0
    assert(fspace->sinfo);
849
0
    assert(sect);
850
851
    /* Get section's class */
852
0
    cls = &fspace->sect_cls[sect->type];
853
854
    /* Remove node from size tracked data structures */
855
0
    if (H5FS__sect_unlink_size(fspace->sinfo, cls, sect) < 0)
856
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
857
0
                    "can't remove section from size tracking data structures");
858
859
    /* Update rest of free space manager data structures for node removal */
860
0
    if (H5FS__sect_unlink_rest(fspace, cls, sect) < 0)
861
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
862
0
                    "can't remove section from non-size tracking data structures");
863
864
0
done:
865
0
    FUNC_LEAVE_NOAPI(ret_value)
866
0
} /* H5FS__sect_remove_real() */
867
868
/*-------------------------------------------------------------------------
869
 * Function:    H5FS_sect_remove
870
 *
871
 * Purpose:     Remove a section from the free space manager
872
 *
873
 * Return:      SUCCEED/FAIL
874
 *
875
 *-------------------------------------------------------------------------
876
 */
877
herr_t
878
H5FS_sect_remove(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect)
879
0
{
880
0
    bool   sinfo_valid = false;   /* Whether the section info is valid */
881
0
    herr_t ret_value   = SUCCEED; /* Return value */
882
883
0
    FUNC_ENTER_NOAPI_NOINIT
884
885
    /* Check arguments. */
886
0
    assert(f);
887
0
    assert(fspace);
888
0
    assert(sect);
889
890
    /* Get a pointer to the section info */
891
0
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
892
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
893
0
    sinfo_valid = true;
894
895
    /* Perform actual section removal */
896
0
    if (H5FS__sect_remove_real(fspace, sect) < 0)
897
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove section");
898
899
0
done:
900
    /* Release the section info */
901
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, true) < 0)
902
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
903
904
0
    FUNC_LEAVE_NOAPI(ret_value)
905
0
} /* H5FS_sect_remove() */
906
907
/*-------------------------------------------------------------------------
908
 * Function:    H5FS__sect_link_size
909
 *
910
 * Purpose:     Add a section of free space to the free list bins
911
 *
912
 * Return:      SUCCEED/FAIL
913
 *
914
 *-------------------------------------------------------------------------
915
 */
916
static herr_t
917
H5FS__sect_link_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls, H5FS_section_info_t *sect)
918
0
{
919
0
    H5FS_node_t *fspace_node       = NULL;  /* Pointer to free space node of the correct size */
920
0
    bool         fspace_node_alloc = false; /* Whether the free space node was allocated */
921
0
    unsigned     bin;                       /* Bin to put the free space section in */
922
0
    herr_t       ret_value = SUCCEED;       /* Return value */
923
924
0
    FUNC_ENTER_PACKAGE
925
926
    /* Check arguments. */
927
0
    assert(sinfo);
928
0
    assert(sect);
929
0
    assert(H5_addr_defined(sect->addr));
930
0
    assert(sect->size);
931
932
    /* Determine correct bin which holds items of the section's size */
933
0
    bin = H5VM_log2_gen(sect->size);
934
0
    assert(bin < sinfo->nbins);
935
0
    if (sinfo->bins[bin].bin_list == NULL) {
936
0
        if (NULL == (sinfo->bins[bin].bin_list = H5SL_create(H5SL_TYPE_HSIZE, NULL)))
937
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for free space nodes");
938
0
    } /* end if */
939
0
    else
940
        /* Check for node list of the correct size already */
941
0
        fspace_node = (H5FS_node_t *)H5SL_search(sinfo->bins[bin].bin_list, &sect->size);
942
943
    /* Check if we need to create a new skip list for nodes of this size */
944
0
    if (fspace_node == NULL) {
945
        /* Allocate new free list size node */
946
0
        if (NULL == (fspace_node = H5FL_MALLOC(H5FS_node_t)))
947
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for free space node");
948
0
        fspace_node_alloc = true;
949
950
        /* Initialize the free list size node */
951
0
        fspace_node->sect_size    = sect->size;
952
0
        fspace_node->serial_count = fspace_node->ghost_count = 0;
953
0
        if (NULL == (fspace_node->sect_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
954
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for free space nodes");
955
956
        /* Insert new free space size node into bin's list */
957
0
        if (H5SL_insert(sinfo->bins[bin].bin_list, fspace_node, &fspace_node->sect_size) < 0)
958
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into skip list");
959
0
        fspace_node_alloc = false; /* (owned by the bin skip list now, don't need to free on error) */
960
961
        /* Increment number of section sizes */
962
0
        sinfo->tot_size_count++;
963
0
    } /* end if */
964
965
    /* Increment # of section in bin */
966
    /* (Different from the # of items in the bin's skiplist, since each node on
967
     *  the bin's skiplist is also a skiplist...)
968
     */
969
0
    sinfo->bins[bin].tot_sect_count++;
970
0
    if (cls->flags & H5FS_CLS_GHOST_OBJ) {
971
0
        sinfo->bins[bin].ghost_sect_count++;
972
0
        fspace_node->ghost_count++;
973
974
        /* Check for first ghost section in node */
975
0
        if (fspace_node->ghost_count == 1)
976
0
            sinfo->ghost_size_count++;
977
0
    } /* end if */
978
0
    else {
979
0
        sinfo->bins[bin].serial_sect_count++;
980
0
        fspace_node->serial_count++;
981
982
        /* Check for first serializable section in node */
983
0
        if (fspace_node->serial_count == 1)
984
0
            sinfo->serial_size_count++;
985
0
    } /* end else */
986
987
    /* Insert free space node into correct skip list */
988
0
    if (H5SL_insert(fspace_node->sect_list, sect, &sect->addr) < 0)
989
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into skip list");
990
991
0
done:
992
0
    if (ret_value < 0)
993
0
        if (fspace_node && fspace_node_alloc) {
994
0
            if (fspace_node->sect_list && H5SL_close(fspace_node->sect_list) < 0)
995
0
                HDONE_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL,
996
0
                            "can't destroy size free space node's skip list");
997
0
            fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
998
0
        } /* end if */
999
1000
0
    FUNC_LEAVE_NOAPI(ret_value)
1001
0
} /* H5FS__sect_link_size() */
1002
1003
/*-------------------------------------------------------------------------
1004
 * Function:    H5FS__sect_link_rest
1005
 *
1006
 * Purpose:     Link a section into the rest of the non-size tracking
1007
 *              free space manager data structures
1008
 *
1009
 * Return:      SUCCEED/FAIL
1010
 *
1011
 *-------------------------------------------------------------------------
1012
 */
1013
static herr_t
1014
H5FS__sect_link_rest(H5FS_t *fspace, const H5FS_section_class_t *cls, H5FS_section_info_t *sect,
1015
                     unsigned flags)
1016
0
{
1017
0
    herr_t ret_value = SUCCEED; /* Return value */
1018
1019
0
    FUNC_ENTER_PACKAGE
1020
1021
    /* Check arguments. */
1022
0
    assert(fspace);
1023
0
    assert(fspace->sinfo);
1024
0
    assert(sect);
1025
1026
    /* Add section to the address-ordered list of sections, if allowed */
1027
0
    if (!(cls->flags & H5FS_CLS_SEPAR_OBJ)) {
1028
0
        if (fspace->sinfo->merge_list == NULL)
1029
0
            if (NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
1030
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL,
1031
0
                            "can't create skip list for merging free space sections");
1032
0
        if (H5SL_insert(fspace->sinfo->merge_list, sect, &sect->addr) < 0)
1033
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1034
0
                        "can't insert free space node into merging skip list");
1035
0
    } /* end if */
1036
1037
    /* Update section info & check if we need more room for the serialized free space sections */
1038
0
    if (H5FS__sect_increase(fspace, cls, flags) < 0)
1039
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk");
1040
1041
    /* Increment amount of free space managed */
1042
0
    fspace->tot_space += sect->size;
1043
1044
0
done:
1045
0
    FUNC_LEAVE_NOAPI(ret_value)
1046
0
} /* H5FS__sect_link_rest() */
1047
1048
/*-------------------------------------------------------------------------
1049
 * Function:    H5FS__sect_link
1050
 *
1051
 * Purpose:     Link a section into the internal data structures
1052
 *
1053
 * Return:      SUCCEED/FAIL
1054
 *
1055
 *-------------------------------------------------------------------------
1056
 */
1057
static herr_t
1058
H5FS__sect_link(H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags)
1059
0
{
1060
0
    const H5FS_section_class_t *cls;                   /* Class of section */
1061
0
    bool                        linked_sect = false;   /* Was the section linked in? */
1062
0
    herr_t                      ret_value   = SUCCEED; /* Return value */
1063
1064
0
    FUNC_ENTER_PACKAGE
1065
1066
    /* Check arguments. */
1067
0
    assert(fspace);
1068
0
    assert(fspace->sinfo);
1069
0
    assert(sect);
1070
1071
    /* Get section's class */
1072
0
    cls = &fspace->sect_cls[sect->type];
1073
1074
    /* Add section to size tracked data structures */
1075
0
    if (H5FS__sect_link_size(fspace->sinfo, cls, sect) < 0)
1076
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to size tracking data structures");
1077
0
    linked_sect = true;
1078
1079
    /* Update rest of free space manager data structures for section addition */
1080
0
    if (H5FS__sect_link_rest(fspace, cls, sect, flags) < 0)
1081
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1082
0
                    "can't add section to non-size tracking data structures");
1083
1084
0
done:
1085
0
    if (ret_value < 0) {
1086
0
        if (linked_sect && H5FS__sect_unlink_size(fspace->sinfo, cls, sect) < 0)
1087
0
            HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
1088
0
                        "can't remove section from size tracking data structures");
1089
0
    }
1090
1091
0
    FUNC_LEAVE_NOAPI(ret_value)
1092
0
} /* H5FS__sect_link() */
1093
1094
/*-------------------------------------------------------------------------
1095
 * Function:    H5FS__sect_merge
1096
 *
1097
 * Purpose:     Attempt to merge a returned free space section with existing
1098
 *              free space.
1099
 *
1100
 * Return:      SUCCEED/FAIL
1101
 *
1102
 *-------------------------------------------------------------------------
1103
 */
1104
static herr_t
1105
H5FS__sect_merge(H5FS_t *fspace, H5FS_section_info_t **sect, void *op_data)
1106
0
{
1107
0
    H5FS_section_class_t *sect_cls;            /* Section's class */
1108
0
    bool                  modified;            /* Flag to indicate merge or shrink occurred */
1109
0
    bool                  remove_sect = false; /* Whether a section should be removed before shrinking */
1110
0
    htri_t                status;              /* Status value */
1111
0
    herr_t                ret_value = SUCCEED; /* Return value */
1112
1113
0
    FUNC_ENTER_PACKAGE
1114
1115
    /* Check arguments. */
1116
0
    assert(fspace);
1117
0
    assert(*sect);
1118
0
    assert(H5_addr_defined((*sect)->addr));
1119
0
    assert((*sect)->size);
1120
1121
    /* Loop until no more merging */
1122
0
    if (fspace->sinfo->merge_list) {
1123
0
        do {
1124
0
            H5SL_node_t *less_sect_node;           /* Skip list node for section less than new section */
1125
0
            H5SL_node_t *greater_sect_node = NULL; /* Skip list node for section greater than new section */
1126
0
            H5FS_section_info_t  *tmp_sect;        /* Temporary free space section */
1127
0
            H5FS_section_class_t *tmp_sect_cls;    /* Temporary section's class */
1128
0
            bool greater_sect_node_valid = false;  /* Indicate if 'greater than' section node is valid */
1129
1130
            /* Reset 'modification occurred' flag */
1131
0
            modified = false;
1132
1133
            /* Look for neighboring section before new section */
1134
0
            less_sect_node = H5SL_below(fspace->sinfo->merge_list, &(*sect)->addr);
1135
1136
            /* Check for node before new node able to merge with new node */
1137
0
            if (less_sect_node) {
1138
                /* Check for node greater than section */
1139
0
                greater_sect_node       = H5SL_next(less_sect_node);
1140
0
                greater_sect_node_valid = true;
1141
1142
                /* Get section for 'less than' skip list node */
1143
0
                tmp_sect = (H5FS_section_info_t *)H5SL_item(less_sect_node);
1144
1145
                /* Get classes for right & left sections */
1146
0
                tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
1147
0
                sect_cls     = &fspace->sect_cls[(*sect)->type];
1148
1149
                /* Check if sections of the left most class can merge with sections
1150
                 *  of another class & whether the sections are the same type,
1151
                 *  then check for 'can merge' callback
1152
                 */
1153
0
                if ((!(tmp_sect_cls->flags & H5FS_CLS_MERGE_SYM) || (tmp_sect->type == (*sect)->type)) &&
1154
0
                    tmp_sect_cls->can_merge) {
1155
                    /* Determine if the sections can merge */
1156
0
                    if ((status = (*tmp_sect_cls->can_merge)(tmp_sect, *sect, op_data)) < 0)
1157
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections");
1158
0
                    if (status > 0) {
1159
                        /* Sanity check */
1160
0
                        assert(tmp_sect_cls->merge);
1161
1162
                        /* Remove 'less than' node from data structures */
1163
0
                        if (H5FS__sect_remove_real(fspace, tmp_sect) < 0)
1164
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1165
0
                                        "can't remove section from internal data structures");
1166
1167
                        /* Merge the two sections together */
1168
0
                        if ((*tmp_sect_cls->merge)(&tmp_sect, *sect, op_data) < 0)
1169
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections");
1170
1171
                        /* Retarget section pointer to 'less than' node that was merged into */
1172
0
                        *sect = tmp_sect;
1173
0
                        if (*sect == NULL)
1174
0
                            HGOTO_DONE(ret_value);
1175
1176
                        /* Indicate successful merge occurred */
1177
0
                        modified = true;
1178
0
                    } /* end if */
1179
0
                }     /* end if */
1180
0
            }         /* end if */
1181
1182
            /* Look for section after new (or merged) section, if not already determined */
1183
0
            if (!greater_sect_node_valid)
1184
0
                greater_sect_node = H5SL_above(fspace->sinfo->merge_list, &(*sect)->addr);
1185
1186
            /* Check for node after new node able to merge with new node */
1187
0
            if (greater_sect_node) {
1188
                /* Get section for 'greater than' skip list node */
1189
0
                tmp_sect = (H5FS_section_info_t *)H5SL_item(greater_sect_node);
1190
1191
                /* Get classes for right & left sections */
1192
0
                sect_cls     = &fspace->sect_cls[(*sect)->type];
1193
0
                tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
1194
1195
                /* Check if sections of the left most class can merge with sections
1196
                 *  of another class & whether the sections are the same type,
1197
                 *  then check for 'can merge' callback
1198
                 */
1199
0
                if ((!(sect_cls->flags & H5FS_CLS_MERGE_SYM) || ((*sect)->type == tmp_sect->type)) &&
1200
0
                    sect_cls->can_merge) {
1201
1202
                    /* Determine if the sections can merge */
1203
0
                    if ((status = (*sect_cls->can_merge)(*sect, tmp_sect, op_data)) < 0)
1204
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections");
1205
0
                    if (status > 0) {
1206
                        /* Sanity check */
1207
0
                        assert(sect_cls->merge);
1208
1209
                        /* Remove 'greater than' node from data structures */
1210
0
                        if (H5FS__sect_remove_real(fspace, tmp_sect) < 0)
1211
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1212
0
                                        "can't remove section from internal data structures");
1213
1214
                        /* Merge the two sections together */
1215
0
                        if ((*sect_cls->merge)(sect, tmp_sect, op_data) < 0)
1216
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections");
1217
1218
                        /* It's possible that the merge caused the section to be deleted (particularly in the
1219
                         * paged allocation case) */
1220
0
                        if (*sect == NULL)
1221
0
                            HGOTO_DONE(ret_value);
1222
1223
                        /* Indicate successful merge occurred */
1224
0
                        modified = true;
1225
0
                    } /* end if */
1226
0
                }     /* end if */
1227
0
            }         /* end if */
1228
0
        } while (modified);
1229
0
    } /* end if */
1230
0
    assert(*sect);
1231
1232
    /* Loop until no more shrinking */
1233
0
    do {
1234
        /* Reset 'modification occurred' flag */
1235
0
        modified = false;
1236
1237
        /* Check for (possibly merged) section able to shrink the size of the container */
1238
0
        sect_cls = &fspace->sect_cls[(*sect)->type];
1239
0
        if (sect_cls->can_shrink) {
1240
0
            if ((status = (*sect_cls->can_shrink)(*sect, op_data)) < 0)
1241
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking container");
1242
0
            if (status > 0) {
1243
                /* Remove SECT from free-space manager */
1244
                /* (only possible to happen on second+ pass through loop) */
1245
0
                if (remove_sect) {
1246
0
                    if (H5FS__sect_remove_real(fspace, *sect) < 0)
1247
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1248
0
                                    "can't remove section from internal data structures");
1249
0
                    remove_sect = false;
1250
0
                } /* end if */
1251
1252
                /* Shrink the container */
1253
                /* (callback can indicate that it has discarded the section by setting *sect to NULL) */
1254
0
                assert(sect_cls->shrink);
1255
0
                if ((*sect_cls->shrink)(sect, op_data) < 0)
1256
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't shrink free space container");
1257
1258
                /* If this section was shrunk away, we may need to shrink another section */
1259
0
                if (*sect == NULL) {
1260
                    /* Check for sections on merge list */
1261
0
                    if (fspace->sinfo->merge_list) {
1262
0
                        H5SL_node_t *last_node; /* Last node in merge list */
1263
1264
                        /* Check for last node in the merge list */
1265
0
                        if (NULL != (last_node = H5SL_last(fspace->sinfo->merge_list))) {
1266
                            /* Get the pointer to the last section, from the last node */
1267
0
                            *sect = (H5FS_section_info_t *)H5SL_item(last_node);
1268
0
                            assert(*sect);
1269
1270
                            /* Indicate that this section needs to be removed if it causes a shrink */
1271
0
                            remove_sect = true;
1272
0
                        } /* end if */
1273
0
                    }     /* end if */
1274
0
                }         /* end if */
1275
1276
                /* Indicate successful merge occurred */
1277
0
                modified = true;
1278
0
            } /* end if */
1279
0
        }     /* end if */
1280
0
    } while (modified && *sect);
1281
1282
    /* Check for section that was shrunk away and next section not shrinking */
1283
0
    if (remove_sect && (*sect != NULL))
1284
0
        *sect = NULL;
1285
1286
0
done:
1287
0
    FUNC_LEAVE_NOAPI(ret_value)
1288
0
} /* H5FS__sect_merge() */
1289
1290
/*-------------------------------------------------------------------------
1291
 * Function:    H5FS_sect_add
1292
 *
1293
 * Purpose:     Add a section of free space to the free list
1294
 *
1295
 * Return:      SUCCEED/FAIL
1296
 *
1297
 *-------------------------------------------------------------------------
1298
 */
1299
herr_t
1300
H5FS_sect_add(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags, void *op_data)
1301
0
{
1302
0
    H5FS_section_class_t *cls;                      /* Section's class */
1303
0
    bool                  sinfo_valid    = false;   /* Whether the section info is valid */
1304
0
    bool                  sinfo_modified = false;   /* Whether the section info was modified */
1305
0
    herr_t                ret_value      = SUCCEED; /* Return value */
1306
1307
0
    FUNC_ENTER_NOAPI(FAIL)
1308
1309
#ifdef H5FS_SINFO_DEBUG
1310
    fprintf(stderr, "%s: *sect = {%" PRIuHADDR ", %" PRIuHSIZE ", %u, %s}\n", __func__, sect->addr,
1311
            sect->size, sect->type,
1312
            (sect->state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED"));
1313
#endif /* H5FS_SINFO_DEBUG */
1314
1315
    /* Check arguments. */
1316
0
    assert(fspace);
1317
0
    assert(sect);
1318
0
    assert(H5_addr_defined(sect->addr));
1319
0
    assert(sect->size);
1320
1321
    /* Get a pointer to the section info */
1322
0
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1323
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1324
0
    sinfo_valid = true;
1325
1326
    /* Call "add" section class callback, if there is one */
1327
0
    cls = &fspace->sect_cls[sect->type];
1328
0
    if (cls->add)
1329
0
        if ((*cls->add)(&sect, &flags, op_data) < 0)
1330
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "'add' section class callback failed");
1331
1332
    /* Check for merging returned space with existing section node */
1333
0
    if (flags & H5FS_ADD_RETURNED_SPACE) {
1334
#ifdef H5FS_SINFO_DEBUG
1335
        fprintf(stderr, "%s: Returning space\n", __func__);
1336
#endif /* H5FS_SINFO_DEBUG */
1337
1338
        /* Attempt to merge returned section with existing sections */
1339
0
        if (H5FS__sect_merge(fspace, &sect, op_data) < 0)
1340
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections");
1341
0
    } /* end if */
1342
1343
    /* Add new (possibly merged) node to free sections data structures */
1344
    /* (If section has been completely merged or shrunk away, 'sect' will
1345
     *  be NULL at this point - QAK)
1346
     */
1347
0
    if (sect)
1348
0
        if (H5FS__sect_link(fspace, sect, flags) < 0)
1349
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list");
1350
1351
#ifdef H5FS_SINFO_DEBUG
1352
    fprintf(stderr, "%s: fspace->tot_space = %" PRIuHSIZE "\n", __func__, fspace->tot_space);
1353
#endif /* H5FS_SINFO_DEBUG */
1354
    /* Mark free space sections as changed */
1355
    /* (if adding sections while deserializing sections, don't set the flag) */
1356
0
    if (!(flags & (H5FS_ADD_DESERIALIZING | H5FS_PAGE_END_NO_ADD)))
1357
0
        sinfo_modified = true;
1358
1359
0
done:
1360
    /* Release the section info */
1361
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1362
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1363
1364
#ifdef H5FS_DEBUG_ASSERT
1365
    if (!(flags & (H5FS_ADD_DESERIALIZING | H5FS_ADD_SKIP_VALID)))
1366
        H5FS__assert(fspace);
1367
#endif /* H5FS_DEBUG_ASSERT */
1368
#ifdef H5FS_SINFO_DEBUG
1369
    fprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value);
1370
#endif /* H5FS_SINFO_DEBUG */
1371
0
    FUNC_LEAVE_NOAPI(ret_value)
1372
0
} /* H5FS_sect_add() */
1373
1374
/*-------------------------------------------------------------------------
1375
 * Function:    H5FS_sect_try_extend
1376
 *
1377
 * Purpose:     Try to extend a block using space from a section on the free list
1378
 *
1379
 * Return:      SUCCEED/FAIL
1380
 *
1381
 *-------------------------------------------------------------------------
1382
 */
1383
htri_t
1384
H5FS_sect_try_extend(H5F_t *f, H5FS_t *fspace, haddr_t addr, hsize_t size, hsize_t extra_requested,
1385
                     unsigned flags, void *op_data)
1386
0
{
1387
0
    bool   sinfo_valid    = false; /* Whether the section info is valid */
1388
0
    bool   sinfo_modified = false; /* Whether the section info was modified */
1389
0
    htri_t ret_value      = false; /* Return value */
1390
1391
0
    FUNC_ENTER_NOAPI(FAIL)
1392
1393
#ifdef H5FS_SINFO_DEBUG
1394
    fprintf(stderr, "%s: addr = %" PRIuHADDR ", size = %" PRIuHSIZE ", extra_requested = %" PRIuHSIZE "\n",
1395
            __func__, addr, size, extra_requested);
1396
#endif /* H5FS_SINFO_DEBUG */
1397
1398
    /* Check arguments. */
1399
0
    assert(f);
1400
0
    assert(fspace);
1401
0
    assert(H5_addr_defined(addr));
1402
0
    assert(size > 0);
1403
0
    assert(extra_requested > 0);
1404
1405
    /* Check for any sections on free space list */
1406
#ifdef H5FS_SINFO_DEBUG
1407
    fprintf(stderr, "%s: fspace->tot_sect_count = %" PRIuHSIZE "\n", __func__, fspace->tot_sect_count);
1408
    fprintf(stderr, "%s: fspace->serial_sect_count = %" PRIuHSIZE "\n", __func__, fspace->serial_sect_count);
1409
    fprintf(stderr, "%s: fspace->ghost_sect_count = %" PRIuHSIZE "\n", __func__, fspace->ghost_sect_count);
1410
#endif /* H5FS_SINFO_DEBUG */
1411
0
    if (fspace->tot_sect_count > 0) {
1412
0
        H5FS_section_info_t *sect; /* Temporary free space section */
1413
1414
        /* Get a pointer to the section info */
1415
0
        if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1416
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1417
0
        sinfo_valid = true;
1418
1419
        /*
1420
1421
        Pseudo-code for algorithm:
1422
1423
        _section_ = <Get pointer to section with address > _region.addr_>
1424
        if(_section_)
1425
            if(_section_ adjoins _region_ && _section.size_ >= _extra_requested_)
1426
                <remove section from data structures>
1427
                if(_section.size_ > _extra_requested_)
1428
                    if(<can adjust _section_>)
1429
                        <adjust _section_ by _extra_requested_>
1430
                        <add adjusted section back to data structures>
1431
                    else
1432
                        <re-add UNadjusted section back to data structures>
1433
                        <error>
1434
                <mark free space sections as changed in metadata cache>
1435
1436
        */
1437
        /* Look for a section after block to extend */
1438
0
        if ((sect = (H5FS_section_info_t *)H5SL_greater(fspace->sinfo->merge_list, &addr))) {
1439
            /* Check if this section adjoins the block and is large enough to
1440
             *  fulfill extension request.
1441
             *
1442
             * (Note: we assume that the section is fully merged with any
1443
             *  possible neighboring nodes and is not at the end of the file
1444
             *  (or it would have been eliminated), etc)
1445
             */
1446
0
            if (sect->size >= extra_requested && (addr + size) == sect->addr) {
1447
0
                H5FS_section_class_t *cls; /* Section's class */
1448
1449
                /* Remove section from data structures */
1450
0
                if (H5FS__sect_remove_real(fspace, sect) < 0)
1451
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1452
0
                                "can't remove section from internal data structures");
1453
1454
                /* Get class for section */
1455
0
                cls = &fspace->sect_cls[sect->type];
1456
1457
                /* Check for the section needing to be adjusted and re-added */
1458
                /* (Note: we should probably add a can_adjust/adjust callback
1459
                 *      to the section class structure, but we don't need it
1460
                 *      for the current usage, so I've deferred messing with
1461
                 *      it. - QAK - 2008/01/08)
1462
                 */
1463
0
                if (sect->size > extra_requested) {
1464
                    /* Sanity check (for now) */
1465
0
                    assert(cls->flags & H5FS_CLS_ADJUST_OK);
1466
1467
                    /* Adjust section by amount requested */
1468
0
                    sect->addr += extra_requested;
1469
0
                    sect->size -= extra_requested;
1470
0
                    if (cls->add)
1471
0
                        if ((*cls->add)(&sect, &flags, op_data) < 0)
1472
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1473
0
                                        "'add' section class callback failed");
1474
1475
                    /* Re-adding the section could cause it to disappear (particularly when paging) */
1476
0
                    if (sect) {
1477
                        /* Re-add adjusted section to free sections data structures */
1478
0
                        if (H5FS__sect_link(fspace, sect, 0) < 0)
1479
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1480
0
                                        "can't insert free space section into skip list");
1481
0
                    } /* end if */
1482
0
                }     /* end if */
1483
0
                else {
1484
                    /* Sanity check */
1485
0
                    assert(sect->size == extra_requested);
1486
1487
                    /* Exact match, so just free section */
1488
0
                    if ((*cls->free)(sect) < 0)
1489
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't free section");
1490
0
                } /* end else */
1491
1492
                /* Note that we modified the section info */
1493
0
                sinfo_modified = true;
1494
1495
                /* Indicate success */
1496
0
                HGOTO_DONE(true);
1497
0
            } /* end if */
1498
0
        }     /* end if */
1499
0
    }         /* end if */
1500
1501
0
done:
1502
    /* Release the section info */
1503
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1504
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1505
1506
0
    FUNC_LEAVE_NOAPI(ret_value)
1507
0
} /* H5FS_sect_try_extend() */
1508
1509
/*-------------------------------------------------------------------------
1510
 * Function:    H5FS_sect_try_merge
1511
 *
1512
 * Purpose:     Try to merge/shrink a block
1513
 *
1514
 * Return:      true:       merged/shrunk
1515
 *              false:      not merged/not shrunk
1516
 *              Failure:    negative
1517
 *
1518
 *-------------------------------------------------------------------------
1519
 */
1520
htri_t
1521
H5FS_sect_try_merge(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags, void *op_data)
1522
0
{
1523
0
    bool    sinfo_valid    = false; /* Whether the section info is valid */
1524
0
    bool    sinfo_modified = false; /* Whether the section info was modified */
1525
0
    hsize_t saved_fs_size;          /* Copy of the free-space section size */
1526
0
    htri_t  ret_value = false;      /* Return value */
1527
1528
0
    FUNC_ENTER_NOAPI(FAIL)
1529
1530
    /* Check arguments. */
1531
0
    assert(f);
1532
0
    assert(fspace);
1533
0
    assert(sect);
1534
0
    assert(H5_addr_defined(sect->addr));
1535
0
    assert(sect->size);
1536
1537
    /* Get a pointer to the section info */
1538
0
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1539
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1540
0
    sinfo_valid   = true;
1541
0
    saved_fs_size = sect->size;
1542
1543
    /* Attempt to merge/shrink section with existing sections */
1544
0
    if (H5FS__sect_merge(fspace, &sect, op_data) < 0)
1545
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections");
1546
1547
    /* Check if section is shrunk and/or merged away completely */
1548
0
    if (!sect) {
1549
0
        sinfo_modified = true;
1550
0
        HGOTO_DONE(true);
1551
0
    } /* end if */
1552
0
    else {
1553
        /* Check if section is merged */
1554
0
        if (sect->size != saved_fs_size) {
1555
0
            if (H5FS__sect_link(fspace, sect, flags) < 0)
1556
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1557
0
                            "can't insert free space section into skip list");
1558
0
            sinfo_modified = true;
1559
0
            HGOTO_DONE(true);
1560
0
        } /* end if */
1561
0
    }     /* end else */
1562
1563
0
done:
1564
    /* Release the section info */
1565
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1566
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1567
1568
0
    FUNC_LEAVE_NOAPI(ret_value)
1569
0
} /* H5FS_sect_try_merge() */
1570
1571
/*-------------------------------------------------------------------------
1572
 * Function:    H5FS__sect_find_node
1573
 *
1574
 * Purpose:     Locate a section of free space (in existing free space list
1575
 *              bins) that is large enough to fulfill request.
1576
 *
1577
 * Return:      SUCCEED/FAIL
1578
 *
1579
 *-------------------------------------------------------------------------
1580
 */
1581
static htri_t
1582
H5FS__sect_find_node(H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node)
1583
0
{
1584
0
    H5FS_node_t *fspace_node;       /* Free list size node */
1585
0
    unsigned     bin;               /* Bin to put the free space section in */
1586
0
    htri_t       ret_value = false; /* Return value */
1587
1588
0
    H5SL_node_t                *curr_size_node = NULL;
1589
0
    const H5FS_section_class_t *cls; /* Class of section */
1590
0
    hsize_t                     alignment;
1591
1592
0
    FUNC_ENTER_PACKAGE
1593
1594
    /* Check arguments. */
1595
0
    assert(fspace);
1596
0
    assert(fspace->sinfo);
1597
0
    assert(fspace->sinfo->bins);
1598
0
    assert(request > 0);
1599
0
    assert(node);
1600
1601
    /* Determine correct bin which holds items of at least the section's size */
1602
0
    bin = H5VM_log2_gen(request);
1603
0
    assert(bin < fspace->sinfo->nbins);
1604
0
    alignment = fspace->alignment;
1605
0
    if (!((alignment > 1) && (request >= fspace->align_thres)))
1606
0
        alignment = 0; /* no alignment */
1607
1608
0
    do {
1609
        /* Check if there's any sections in this bin */
1610
0
        if (fspace->sinfo->bins[bin].bin_list) {
1611
1612
0
            if (!alignment) { /* no alignment */
1613
                /* Find the first free space section that is large enough to fulfill request */
1614
                /* (Since the bins use skip lists to track the sizes of the address-ordered
1615
                 *  lists, this is actually a "best fit" algorithm)
1616
                 */
1617
                /* Look for large enough free space section in this bin */
1618
0
                if ((fspace_node =
1619
0
                         (H5FS_node_t *)H5SL_greater(fspace->sinfo->bins[bin].bin_list, &request))) {
1620
                    /* Take first node off of the list (ie. node w/lowest address) */
1621
0
                    if (NULL == (*node = (H5FS_section_info_t *)H5SL_remove_first(fspace_node->sect_list)))
1622
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1623
0
                                    "can't remove free space node from skip list");
1624
1625
                    /* Get section's class */
1626
0
                    cls = &fspace->sect_cls[(*node)->type];
1627
                    /* Decrement # of sections in section size node */
1628
0
                    if (H5FS__size_node_decr(fspace->sinfo, bin, fspace_node, cls) < 0)
1629
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1630
0
                                    "can't remove free space size node from skip list");
1631
0
                    if (H5FS__sect_unlink_rest(fspace, cls, *node) < 0)
1632
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
1633
0
                                    "can't remove section from non-size tracking data structures");
1634
                    /* Indicate that we found a node for the request */
1635
0
                    HGOTO_DONE(true);
1636
0
                }  /* end if */
1637
0
            }      /* end if */
1638
0
            else { /* alignment is set */
1639
                /* get the first node of a certain size in this bin */
1640
0
                curr_size_node = H5SL_first(fspace->sinfo->bins[bin].bin_list);
1641
0
                while (curr_size_node != NULL) {
1642
0
                    H5FS_node_t *curr_fspace_node = NULL;
1643
0
                    H5SL_node_t *curr_sect_node   = NULL;
1644
1645
                    /* Get the free space node for free space sections of the same size */
1646
0
                    curr_fspace_node = (H5FS_node_t *)H5SL_item(curr_size_node);
1647
1648
                    /* Get the Skip list which holds  pointers to actual free list sections */
1649
0
                    curr_sect_node = (H5SL_node_t *)H5SL_first(curr_fspace_node->sect_list);
1650
1651
0
                    while (curr_sect_node != NULL) {
1652
0
                        H5FS_section_info_t *curr_sect = NULL;
1653
0
                        hsize_t              mis_align = 0, frag_size = 0;
1654
0
                        H5FS_section_info_t *split_sect = NULL;
1655
1656
                        /* Get section node */
1657
0
                        curr_sect = (H5FS_section_info_t *)H5SL_item(curr_sect_node);
1658
1659
0
                        assert(H5_addr_defined(curr_sect->addr));
1660
0
                        assert(curr_fspace_node->sect_size == curr_sect->size);
1661
1662
0
                        cls = &fspace->sect_cls[curr_sect->type];
1663
1664
0
                        assert(alignment);
1665
0
                        assert(cls);
1666
1667
0
                        if ((mis_align = curr_sect->addr % alignment))
1668
0
                            frag_size = alignment - mis_align;
1669
1670
0
                        if ((curr_sect->size >= (request + frag_size)) && (cls->split)) {
1671
                            /* remove the section with aligned address */
1672
0
                            if (NULL == (*node = (H5FS_section_info_t *)H5SL_remove(
1673
0
                                             curr_fspace_node->sect_list, &curr_sect->addr)))
1674
0
                                HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1675
0
                                            "can't remove free space node from skip list");
1676
                            /* Decrement # of sections in section size node */
1677
0
                            if (H5FS__size_node_decr(fspace->sinfo, bin, curr_fspace_node, cls) < 0)
1678
0
                                HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1679
0
                                            "can't remove free space size node from skip list");
1680
1681
0
                            if (H5FS__sect_unlink_rest(fspace, cls, *node) < 0)
1682
0
                                HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
1683
0
                                            "can't remove section from non-size tracking data structures");
1684
1685
                            /*
1686
                             * The split() callback splits NODE into 2 sections:
1687
                             *  split_sect is the unused fragment for aligning NODE
1688
                             *  NODE's addr & size are updated to point to the remaining aligned section
1689
                             * split_sect is re-added to free-space
1690
                             */
1691
0
                            if (mis_align) {
1692
0
                                split_sect = cls->split(*node, frag_size);
1693
0
                                if ((H5FS__sect_link(fspace, split_sect, 0) < 0))
1694
0
                                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1695
0
                                                "can't insert free space section into skip list");
1696
                                /* sanity check */
1697
0
                                assert(split_sect->addr < (*node)->addr);
1698
0
                                assert(request <= (*node)->size);
1699
0
                            } /* end if */
1700
                            /* Indicate that we found a node for the request */
1701
0
                            HGOTO_DONE(true);
1702
0
                        } /* end if */
1703
1704
                        /* Get the next section node in the list */
1705
0
                        curr_sect_node = H5SL_next(curr_sect_node);
1706
0
                    } /* end while of curr_sect_node */
1707
1708
                    /* Get the next size node in the bin */
1709
0
                    curr_size_node = H5SL_next(curr_size_node);
1710
0
                } /* end while of curr_size_node */
1711
0
            }     /* else of alignment */
1712
0
        }         /* if bin_list */
1713
        /* Advance to next larger bin */
1714
0
        bin++;
1715
0
    } while (bin < fspace->sinfo->nbins);
1716
1717
0
done:
1718
0
    FUNC_LEAVE_NOAPI(ret_value)
1719
0
} /* H5FS__sect_find_node() */
1720
1721
/*-------------------------------------------------------------------------
1722
 * Function:    H5FS_sect_find
1723
 *
1724
 * Purpose:     Locate a section of free space (in existing free space list) that
1725
 *              is large enough to fulfill request.
1726
 *
1727
 * Return:      SUCCEED/FAIL
1728
 *
1729
 *-------------------------------------------------------------------------
1730
 */
1731
htri_t
1732
H5FS_sect_find(H5F_t *f, H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node)
1733
0
{
1734
0
    bool   sinfo_valid    = false; /* Whether the section info is valid */
1735
0
    bool   sinfo_modified = false; /* Whether the section info was modified */
1736
0
    htri_t ret_value      = false; /* Return value */
1737
1738
0
    FUNC_ENTER_NOAPI(FAIL)
1739
1740
    /* Check arguments. */
1741
0
    assert(fspace);
1742
0
    assert(fspace->nclasses);
1743
0
    assert(request);
1744
0
    assert(node);
1745
1746
    /* Check for any sections on free space list */
1747
0
    if (fspace->tot_sect_count > 0) {
1748
        /* Get a pointer to the section info */
1749
0
        if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1750
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1751
0
        sinfo_valid = true;
1752
1753
        /* Look for node in bins */
1754
0
        if ((ret_value = H5FS__sect_find_node(fspace, request, node)) < 0)
1755
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from bins");
1756
1757
        /* Decrement # of sections on free list, if we found an object */
1758
0
        if (ret_value > 0) {
1759
            /* Note that we've modified the section info */
1760
0
            sinfo_modified = true;
1761
0
        } /* end if */
1762
0
    }     /* end if */
1763
1764
0
done:
1765
    /* Release the section info */
1766
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1767
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1768
1769
#ifdef H5FS_DEBUG_ASSERT
1770
    H5FS__assert(fspace);
1771
#endif /* H5FS_DEBUG_ASSERT */
1772
0
    FUNC_LEAVE_NOAPI(ret_value)
1773
0
} /* H5FS_sect_find() */
1774
1775
/*-------------------------------------------------------------------------
1776
 * Function:    H5FS__iterate_sect_cb
1777
 *
1778
 * Purpose:     Skip list iterator callback to iterate over free space sections
1779
 *              of a particular size
1780
 *
1781
 * Return:      SUCCEED/FAIL
1782
 *
1783
 *-------------------------------------------------------------------------
1784
 */
1785
static herr_t
1786
H5FS__iterate_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
1787
0
{
1788
0
    H5FS_section_info_t *sect_info = (H5FS_section_info_t *)_item; /* Free space section to work on */
1789
0
    H5FS_iter_ud_t      *udata     = (H5FS_iter_ud_t *)_udata;     /* Callback info */
1790
0
    herr_t               ret_value = SUCCEED;                      /* Return value */
1791
1792
0
    FUNC_ENTER_PACKAGE
1793
1794
    /* Check arguments. */
1795
0
    assert(sect_info);
1796
0
    assert(udata->fspace);
1797
0
    assert(udata->op);
1798
1799
    /* Make callback for this section */
1800
0
    if ((*udata->op)(sect_info, udata->op_data) < 0)
1801
0
        HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "iteration callback failed");
1802
1803
0
done:
1804
0
    FUNC_LEAVE_NOAPI(ret_value)
1805
0
} /* H5FS__iterate_sect_cb() */
1806
1807
/*-------------------------------------------------------------------------
1808
 * Function:    H5FS__iterate_node_cb
1809
 *
1810
 * Purpose:     Skip list iterator callback to iterate over free space sections
1811
 *              in a bin
1812
 *
1813
 * Return:      SUCCEED/FAIL
1814
 *
1815
 *-------------------------------------------------------------------------
1816
 */
1817
static herr_t
1818
H5FS__iterate_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
1819
0
{
1820
0
    H5FS_node_t    *fspace_node = (H5FS_node_t *)_item;     /* Free space size node to work on */
1821
0
    H5FS_iter_ud_t *udata       = (H5FS_iter_ud_t *)_udata; /* Callback info */
1822
0
    herr_t          ret_value   = SUCCEED;                  /* Return value */
1823
1824
0
    FUNC_ENTER_PACKAGE
1825
1826
    /* Check arguments. */
1827
0
    assert(fspace_node);
1828
0
    assert(udata->fspace);
1829
0
    assert(udata->op);
1830
1831
    /* Iterate through all the sections of this size */
1832
0
    assert(fspace_node->sect_list);
1833
0
    if (H5SL_iterate(fspace_node->sect_list, H5FS__iterate_sect_cb, udata) < 0)
1834
0
        HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section nodes");
1835
1836
0
done:
1837
0
    FUNC_LEAVE_NOAPI(ret_value)
1838
0
} /* H5FS__iterate_node_cb() */
1839
1840
/*-------------------------------------------------------------------------
1841
 * Function:    H5FS_sect_iterate
1842
 *
1843
 * Purpose:     Iterate over all the sections managed
1844
 *
1845
 * Return:      SUCCEED/FAIL
1846
 *
1847
 *-------------------------------------------------------------------------
1848
 */
1849
herr_t
1850
H5FS_sect_iterate(H5F_t *f, H5FS_t *fspace, H5FS_operator_t op, void *op_data)
1851
0
{
1852
0
    H5FS_iter_ud_t udata;                 /* User data for callbacks */
1853
0
    bool           sinfo_valid = false;   /* Whether the section info is valid */
1854
0
    herr_t         ret_value   = SUCCEED; /* Return value */
1855
1856
0
    FUNC_ENTER_NOAPI_NOINIT
1857
1858
    /* Check arguments. */
1859
0
    assert(fspace);
1860
0
    assert(op);
1861
1862
    /* Set up user data for iterator */
1863
0
    udata.fspace  = fspace;
1864
0
    udata.op      = op;
1865
0
    udata.op_data = op_data;
1866
1867
    /* Iterate over sections, if there are any */
1868
0
    if (fspace->tot_sect_count) {
1869
0
        unsigned bin; /* Current bin we are on */
1870
1871
        /* Get a pointer to the section info */
1872
0
        if (H5FS__sinfo_lock(f, fspace, H5AC__READ_ONLY_FLAG) < 0)
1873
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1874
0
        sinfo_valid = true;
1875
1876
        /* Iterate over all the bins */
1877
0
        for (bin = 0; bin < fspace->sinfo->nbins; bin++) {
1878
            /* Check if there are any sections in this bin */
1879
0
            if (fspace->sinfo->bins[bin].bin_list) {
1880
                /* Iterate over list of section size nodes for bin */
1881
0
                if (H5SL_iterate(fspace->sinfo->bins[bin].bin_list, H5FS__iterate_node_cb, &udata) < 0)
1882
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section size nodes");
1883
0
            } /* end if */
1884
0
        }     /* end for */
1885
0
    }         /* end if */
1886
1887
0
done:
1888
    /* Release the section info */
1889
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, false) < 0)
1890
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1891
1892
0
    FUNC_LEAVE_NOAPI(ret_value)
1893
0
} /* H5FS_sect_iterate() */
1894
1895
/*-------------------------------------------------------------------------
1896
 * Function:    H5FS_sect_stats
1897
 *
1898
 * Purpose:     Retrieve info about the sections managed
1899
 *
1900
 * Return:      SUCCEED/FAIL
1901
 *
1902
 *-------------------------------------------------------------------------
1903
 */
1904
herr_t
1905
H5FS_sect_stats(const H5FS_t *fspace, hsize_t *tot_space, hsize_t *nsects)
1906
0
{
1907
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1908
1909
    /* Check arguments. */
1910
0
    assert(fspace);
1911
1912
    /* Get the stats desired */
1913
0
    if (tot_space)
1914
0
        *tot_space = fspace->tot_space;
1915
0
    if (nsects)
1916
0
        *nsects = fspace->tot_sect_count;
1917
1918
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1919
0
} /* H5FS_sect_stats() */
1920
1921
/*-------------------------------------------------------------------------
1922
 * Function:    H5FS_sect_change_class
1923
 *
1924
 * Purpose:     Make appropriate adjustments to internal data structures when
1925
 *              a section changes class
1926
 *
1927
 * Return:      SUCCEED/FAIL
1928
 *
1929
 *-------------------------------------------------------------------------
1930
 */
1931
herr_t
1932
H5FS_sect_change_class(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, uint16_t new_class)
1933
0
{
1934
0
    const H5FS_section_class_t *old_cls;               /* Old class of section */
1935
0
    const H5FS_section_class_t *new_cls;               /* New class of section */
1936
0
    unsigned                    old_class;             /* Old class ID of section */
1937
0
    bool                        sinfo_valid = false;   /* Whether the section info is valid */
1938
0
    herr_t                      ret_value   = SUCCEED; /* Return value */
1939
1940
0
    FUNC_ENTER_NOAPI_NOINIT
1941
1942
    /* Check arguments. */
1943
0
    assert(fspace);
1944
0
    assert(sect);
1945
0
    assert(sect->type < fspace->nclasses);
1946
0
    assert(new_class < fspace->nclasses);
1947
1948
    /* Get a pointer to the section info */
1949
0
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1950
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1951
0
    sinfo_valid = true;
1952
1953
    /* Get class info */
1954
0
    old_class = sect->type;
1955
0
    old_cls   = &fspace->sect_cls[sect->type];
1956
0
    new_cls   = &fspace->sect_cls[new_class];
1957
1958
    /* Check if the section's class change will affect the # of serializable or ghost sections */
1959
0
    if ((old_cls->flags & H5FS_CLS_GHOST_OBJ) != (new_cls->flags & H5FS_CLS_GHOST_OBJ)) {
1960
0
        H5FS_node_t *fspace_node; /* Free list size node */
1961
0
        unsigned     bin;         /* Bin to put the free space section in */
1962
0
        bool         to_ghost;    /* Flag if the section is changing to a ghost section */
1963
1964
        /* Determine if this section is becoming a ghost or is becoming serializable */
1965
0
        if (old_cls->flags & H5FS_CLS_GHOST_OBJ)
1966
0
            to_ghost = false;
1967
0
        else
1968
0
            to_ghost = true;
1969
1970
        /* Sanity check */
1971
0
        assert(fspace->sinfo->bins);
1972
1973
        /* Determine correct bin which holds items of at least the section's size */
1974
0
        bin = H5VM_log2_gen(sect->size);
1975
0
        assert(bin < fspace->sinfo->nbins);
1976
0
        assert(fspace->sinfo->bins[bin].bin_list);
1977
1978
        /* Get space node for section's size */
1979
0
        fspace_node = (H5FS_node_t *)H5SL_search(fspace->sinfo->bins[bin].bin_list, &sect->size);
1980
0
        assert(fspace_node);
1981
1982
        /* Adjust serializable/ghost counts */
1983
0
        if (to_ghost) {
1984
            /* Adjust global section count totals */
1985
0
            fspace->serial_sect_count--;
1986
0
            fspace->ghost_sect_count++;
1987
1988
            /* Adjust bin's section count totals */
1989
0
            fspace->sinfo->bins[bin].serial_sect_count--;
1990
0
            fspace->sinfo->bins[bin].ghost_sect_count++;
1991
1992
            /* Adjust section size node's section count totals */
1993
0
            fspace_node->serial_count--;
1994
0
            fspace_node->ghost_count++;
1995
1996
            /* Check if we switched a section size node's status */
1997
0
            if (fspace_node->serial_count == 0)
1998
0
                fspace->sinfo->serial_size_count--;
1999
0
            if (fspace_node->ghost_count == 1)
2000
0
                fspace->sinfo->ghost_size_count++;
2001
0
        } /* end if */
2002
0
        else {
2003
            /* Adjust global section count totals */
2004
0
            fspace->serial_sect_count++;
2005
0
            fspace->ghost_sect_count--;
2006
2007
            /* Adjust bin's section count totals */
2008
0
            fspace->sinfo->bins[bin].serial_sect_count++;
2009
0
            fspace->sinfo->bins[bin].ghost_sect_count--;
2010
2011
            /* Adjust section size node's section count totals */
2012
0
            fspace_node->serial_count++;
2013
0
            fspace_node->ghost_count--;
2014
2015
            /* Check if we switched a section size node's status */
2016
0
            if (fspace_node->serial_count == 1)
2017
0
                fspace->sinfo->serial_size_count++;
2018
0
            if (fspace_node->ghost_count == 0)
2019
0
                fspace->sinfo->ghost_size_count--;
2020
0
        } /* end else */
2021
0
    }     /* end if */
2022
2023
    /* Check if the section's class change will affect the mergeable list */
2024
0
    if ((old_cls->flags & H5FS_CLS_SEPAR_OBJ) != (new_cls->flags & H5FS_CLS_SEPAR_OBJ)) {
2025
0
        bool to_mergable; /* Flag if the section is changing to a mergeable section */
2026
2027
        /* Determine if this section is becoming mergeable or is becoming separate */
2028
0
        if (old_cls->flags & H5FS_CLS_SEPAR_OBJ)
2029
0
            to_mergable = true;
2030
0
        else
2031
0
            to_mergable = false;
2032
2033
        /* Add or remove section from merge list, as appropriate */
2034
0
        if (to_mergable) {
2035
0
            if (fspace->sinfo->merge_list == NULL)
2036
0
                if (NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
2037
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL,
2038
0
                                "can't create skip list for merging free space sections");
2039
0
            if (H5SL_insert(fspace->sinfo->merge_list, sect, &sect->addr) < 0)
2040
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
2041
0
                            "can't insert free space node into merging skip list");
2042
0
        } /* end if */
2043
0
        else {
2044
0
            H5FS_section_info_t *tmp_sect_node; /* Temporary section node */
2045
2046
0
            tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace->sinfo->merge_list, &sect->addr);
2047
0
            if (tmp_sect_node == NULL || tmp_sect_node != sect)
2048
0
                HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list");
2049
0
        } /* end else */
2050
0
    }     /* end if */
2051
2052
    /* Change the section's class */
2053
0
    sect->type = new_class;
2054
2055
    /* Change the serialized size of sections */
2056
0
    fspace->sinfo->serial_size -= fspace->sect_cls[old_class].serial_size;
2057
0
    fspace->sinfo->serial_size += fspace->sect_cls[new_class].serial_size;
2058
2059
    /* Update current space used for free space sections */
2060
0
    if (H5FS__sect_serialize_size(fspace) < 0)
2061
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk");
2062
2063
0
done:
2064
    /* Release the section info */
2065
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, true) < 0)
2066
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
2067
2068
0
    FUNC_LEAVE_NOAPI(ret_value)
2069
0
} /* H5FS_sect_change_class() */
2070
2071
#ifdef H5FS_DEBUG_ASSERT
2072
2073
/*-------------------------------------------------------------------------
2074
 * Function:    H5FS__sect_assert
2075
 *
2076
 * Purpose:     Verify that the sections managed are mostly sane
2077
 *
2078
 * Return:      void
2079
 *
2080
 *-------------------------------------------------------------------------
2081
 */
2082
void
2083
H5FS__sect_assert(const H5FS_t *fspace)
2084
{
2085
    hsize_t separate_obj; /* The number of separate objects managed */
2086
2087
    FUNC_ENTER_PACKAGE_NOERR
2088
2089
    /* Initialize state */
2090
    separate_obj = 0;
2091
2092
    /* Check for bins to work on */
2093
    if (fspace->sinfo->bins) {
2094
        hsize_t  acc_tot_sect_count;    /* Accumulated total section count from bins */
2095
        hsize_t  acc_serial_sect_count; /* Accumulated serializable section count from bins */
2096
        hsize_t  acc_ghost_sect_count;  /* Accumulated ghost section count from bins */
2097
        size_t   acc_tot_size_count;    /* Accumulated total section size count from bins */
2098
        size_t   acc_serial_size_count; /* Accumulated serializable section size count from bins */
2099
        size_t   acc_ghost_size_count;  /* Accumulated ghost section size count from bins */
2100
        unsigned u;                     /* Local index variable */
2101
2102
        /* Walk through all sections in bins */
2103
        acc_tot_sect_count    = 0;
2104
        acc_serial_sect_count = 0;
2105
        acc_ghost_sect_count  = 0;
2106
        acc_tot_size_count    = 0;
2107
        acc_serial_size_count = 0;
2108
        acc_ghost_size_count  = 0;
2109
        for (u = 0; u < fspace->sinfo->nbins; u++) {
2110
            acc_tot_sect_count += fspace->sinfo->bins[u].tot_sect_count;
2111
            acc_serial_sect_count += fspace->sinfo->bins[u].serial_sect_count;
2112
            acc_ghost_sect_count += fspace->sinfo->bins[u].ghost_sect_count;
2113
            if (fspace->sinfo->bins[u].bin_list) {
2114
                H5SL_node_t *curr_size_node;   /* Current section size node in skip list */
2115
                size_t       bin_serial_count; /* # of serializable sections in this bin */
2116
                size_t       bin_ghost_count;  /* # of ghost sections in this bin */
2117
2118
                acc_tot_size_count += H5SL_count(fspace->sinfo->bins[u].bin_list);
2119
2120
                /* Walk through the sections in this bin */
2121
                curr_size_node   = H5SL_first(fspace->sinfo->bins[u].bin_list);
2122
                bin_serial_count = 0;
2123
                bin_ghost_count  = 0;
2124
                while (curr_size_node != NULL) {
2125
                    H5FS_node_t *fspace_node;       /* Section size node */
2126
                    H5SL_node_t *curr_sect_node;    /* Current section node in skip list */
2127
                    size_t       size_serial_count; /* # of serializable sections of this size */
2128
                    size_t       size_ghost_count;  /* # of ghost sections of this size */
2129
2130
                    /* Get section size node */
2131
                    fspace_node = (H5FS_node_t *)H5SL_item(curr_size_node);
2132
2133
                    /* Check sections on list */
2134
                    curr_sect_node    = H5SL_first(fspace_node->sect_list);
2135
                    size_serial_count = 0;
2136
                    size_ghost_count  = 0;
2137
                    while (curr_sect_node != NULL) {
2138
                        H5FS_section_class_t *cls;  /* Class of section */
2139
                        H5FS_section_info_t  *sect; /* Section */
2140
2141
                        /* Get section node & it's class */
2142
                        sect = (H5FS_section_info_t *)H5SL_item(curr_sect_node);
2143
                        cls  = &fspace->sect_cls[sect->type];
2144
2145
                        /* Sanity check section */
2146
                        assert(H5_addr_defined(sect->addr));
2147
                        assert(fspace_node->sect_size == sect->size);
2148
                        if (cls->valid)
2149
                            (*cls->valid)(cls, sect);
2150
2151
                        /* Add to correct count */
2152
                        if (cls->flags & H5FS_CLS_GHOST_OBJ)
2153
                            size_ghost_count++;
2154
                        else
2155
                            size_serial_count++;
2156
2157
                        /* Count node, if separate */
2158
                        if (cls->flags & H5FS_CLS_SEPAR_OBJ)
2159
                            separate_obj++;
2160
2161
                        /* Get the next section node in the list */
2162
                        curr_sect_node = H5SL_next(curr_sect_node);
2163
                    } /* end while */
2164
2165
                    /* Check the number of serializable & ghost sections of this size */
2166
                    assert(fspace_node->serial_count == size_serial_count);
2167
                    assert(fspace_node->ghost_count == size_ghost_count);
2168
2169
                    /* Add to global count of serializable & ghost section sizes */
2170
                    if (fspace_node->serial_count > 0)
2171
                        acc_serial_size_count++;
2172
                    if (fspace_node->ghost_count > 0)
2173
                        acc_ghost_size_count++;
2174
2175
                    /* Add to bin's serializable & ghost counts */
2176
                    bin_serial_count += size_serial_count;
2177
                    bin_ghost_count += size_ghost_count;
2178
2179
                    /* Get the next section size node in the list */
2180
                    curr_size_node = H5SL_next(curr_size_node);
2181
                } /* end while */
2182
2183
                /* Check the number of serializable & ghost sections in this bin */
2184
                assert(fspace->sinfo->bins[u].tot_sect_count == (bin_serial_count + bin_ghost_count));
2185
                assert(fspace->sinfo->bins[u].serial_sect_count == bin_serial_count);
2186
                assert(fspace->sinfo->bins[u].ghost_sect_count == bin_ghost_count);
2187
            } /* end if */
2188
        }     /* end for */
2189
2190
        /* Check counts from bins vs. global counts */
2191
        assert(fspace->sinfo->tot_size_count == acc_tot_size_count);
2192
        assert(fspace->sinfo->serial_size_count == acc_serial_size_count);
2193
        assert(fspace->sinfo->ghost_size_count == acc_ghost_size_count);
2194
        assert(fspace->tot_sect_count == acc_tot_sect_count);
2195
        assert(fspace->serial_sect_count == acc_serial_sect_count);
2196
        assert(fspace->ghost_sect_count == acc_ghost_sect_count);
2197
    } /* end if */
2198
    else {
2199
        /* Check counts are zero */
2200
        assert(fspace->tot_sect_count == 0);
2201
        assert(fspace->serial_sect_count == 0);
2202
        assert(fspace->ghost_sect_count == 0);
2203
    } /* end else */
2204
2205
    /* Make certain that the number of sections on the address list is correct */
2206
    if (fspace->sinfo->merge_list)
2207
        assert(fspace->tot_sect_count == (separate_obj + H5SL_count(fspace->sinfo->merge_list)));
2208
2209
    FUNC_LEAVE_NOAPI_VOID
2210
} /* end H5FS__sect_assert() */
2211
#endif /* H5FS_DEBUG_ASSERT */
2212
2213
/*-------------------------------------------------------------------------
2214
 * Function:    H5FS_sect_try_shrink_eoa
2215
 *
2216
 * Purpose:     To shrink the last section on the merge list if the section
2217
 *              is at EOF.
2218
 *
2219
 * Return:      true/false/FAIL
2220
 *
2221
 *-------------------------------------------------------------------------
2222
 */
2223
htri_t
2224
H5FS_sect_try_shrink_eoa(H5F_t *f, H5FS_t *fspace, void *op_data)
2225
0
{
2226
0
    bool   sinfo_valid     = false; /* Whether the section info is valid */
2227
0
    bool   section_removed = false; /* Whether a section was removed */
2228
0
    htri_t ret_value       = false; /* Return value */
2229
2230
0
    FUNC_ENTER_NOAPI(FAIL)
2231
2232
    /* Check arguments. */
2233
0
    assert(fspace);
2234
2235
0
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
2236
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
2237
0
    sinfo_valid = true;
2238
2239
0
    if (fspace->sinfo && fspace->sinfo->merge_list) {
2240
0
        H5SL_node_t *last_node; /* Last node in merge list */
2241
2242
        /* Check for last node in the merge list */
2243
0
        if (NULL != (last_node = H5SL_last(fspace->sinfo->merge_list))) {
2244
0
            H5FS_section_info_t  *tmp_sect;     /* Temporary free space section */
2245
0
            H5FS_section_class_t *tmp_sect_cls; /* Temporary section's class */
2246
2247
            /* Get the pointer to the last section, from the last node */
2248
0
            tmp_sect = (H5FS_section_info_t *)H5SL_item(last_node);
2249
0
            assert(tmp_sect);
2250
0
            tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
2251
0
            if (tmp_sect_cls->can_shrink) {
2252
                /* Check if the section can be shrunk away */
2253
0
                if ((ret_value = (*tmp_sect_cls->can_shrink)(tmp_sect, op_data)) < 0)
2254
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking container");
2255
0
                if (ret_value > 0) {
2256
0
                    assert(tmp_sect_cls->shrink);
2257
2258
                    /* Remove section from free space manager */
2259
0
                    if (H5FS__sect_remove_real(fspace, tmp_sect) < 0)
2260
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
2261
0
                                    "can't remove section from internal data structures");
2262
0
                    section_removed = true;
2263
2264
                    /* Shrink away section */
2265
0
                    if ((*tmp_sect_cls->shrink)(&tmp_sect, op_data) < 0)
2266
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't shrink free space container");
2267
0
                } /* end if */
2268
0
            }     /* end if */
2269
0
        }         /* end if */
2270
0
    }             /* end if */
2271
2272
0
done:
2273
    /* Release the section info */
2274
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, section_removed) < 0)
2275
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
2276
2277
0
    FUNC_LEAVE_NOAPI(ret_value)
2278
0
} /* H5FS_sect_try_shrink_eoa() */
2279
2280
/*-------------------------------------------------------------------------
2281
 * Function:    H5FS_vfd_alloc_hdr_and_section_info_if_needed
2282
 *
2283
 * Purpose:     The purpose of this function is to allocate file space for
2284
 *              the header and section info of the target free space manager
2285
 *              if they are not allocated yet.
2286
 *
2287
 *              The previous hack in this routine to avoid the potential infinite
2288
 *              loops by allocating file space directly from the end of the file
2289
 *              is removed.  The allocation can now be done via the usual
2290
 *              file space allocation call H5MF_alloc().
2291
 *
2292
 *              The design flaw is addressed by not allowing the size
2293
 *              of section info to shrink.  This means, when trying to allocate
2294
 *              section info size X via H5MF_alloc() and the section info size
2295
 *              after H5MF_alloc() changes to Y:
2296
 *              --if Y is larger than X, free the just allocated file space X
2297
 *                via H5MF_xfree() and set fspace->sect_size to Y.
2298
 *                This routine will be called again later from
2299
 *                H5MF_settle_meta_data_fsm() to allocate section info with the
2300
 *                larger fpsace->sect_size Y.
2301
 *              --if Y is smaller than X, no further allocation is needed and
2302
 *                fspace->sect_size and fspace->alloc_sect_size are set to X.
2303
 *                This means fspace->sect_size may be larger than what is
2304
 *                actually needed.
2305
 *
2306
 *              This routine also re-inserts the header and section info in the
2307
 *              metadata cache with this allocation.
2308
 *
2309
 * Return:      Success:        non-negative
2310
 *              Failure:        negative
2311
 *
2312
 *-------------------------------------------------------------------------
2313
 */
2314
herr_t
2315
H5FS_vfd_alloc_hdr_and_section_info_if_needed(H5F_t *f, H5FS_t *fspace, haddr_t *fs_addr_ptr)
2316
0
{
2317
0
    hsize_t hdr_alloc_size;
2318
0
    hsize_t sinfo_alloc_size;
2319
0
    haddr_t sect_addr = HADDR_UNDEF; /* address of sinfo */
2320
0
    haddr_t eoa       = HADDR_UNDEF; /* Initial EOA for the file */
2321
0
    herr_t  ret_value = SUCCEED;     /* Return value */
2322
2323
0
    FUNC_ENTER_NOAPI_NOINIT
2324
2325
    /* Check arguments. */
2326
0
    assert(f);
2327
0
    assert(f->shared);
2328
0
    assert(f->shared->lf);
2329
0
    assert(fspace);
2330
0
    assert(fs_addr_ptr);
2331
2332
    /* the section info should be unlocked */
2333
0
    assert(fspace->sinfo_lock_count == 0);
2334
2335
    /* persistent free space managers must be enabled */
2336
0
    assert(f->shared->fs_persist);
2337
2338
    /* At present, all free space strategies enable the free space managers.
2339
     * This will probably change -- at which point this assertion should
2340
     * be revisited.
2341
     */
2342
    /* Updated: Only the following two strategies enable the free-space managers */
2343
0
    assert((f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR) ||
2344
0
           (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE));
2345
2346
0
    if (fspace->serial_sect_count > 0 && fspace->sinfo) {
2347
        /* the section info is floating, so space->sinfo should be defined */
2348
2349
0
        if (!H5_addr_defined(fspace->addr)) {
2350
2351
            /* start by allocating file space for the header */
2352
2353
            /* Get the EOA for the file -- need for sanity check below */
2354
0
            if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_FSPACE_HDR)))
2355
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa");
2356
2357
            /* check for overlap into temporary allocation space */
2358
0
            if (H5F_IS_TMP_ADDR(f, (eoa + fspace->sect_size)))
2359
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL,
2360
0
                            "hdr file space alloc will overlap into 'temporary' file space");
2361
2362
0
            hdr_alloc_size = H5FS_HEADER_SIZE(f);
2363
2364
0
            if (H5F_PAGED_AGGR(f))
2365
0
                assert(0 == (eoa % f->shared->fs_page_size));
2366
2367
            /* Allocate space for the free space header */
2368
0
            if (HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, hdr_alloc_size)))
2369
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for free space header");
2370
2371
            /* Cache the new free space header (pinned) */
2372
0
            if (H5AC_insert_entry(f, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
2373
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space header to cache");
2374
2375
0
            *fs_addr_ptr = fspace->addr;
2376
0
        }
2377
2378
0
        if (!H5_addr_defined(fspace->sect_addr)) {
2379
2380
            /* now allocate file space for the section info */
2381
2382
            /* Get the EOA for the file -- need for sanity check below */
2383
0
            if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_FSPACE_SINFO)))
2384
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "Unable to get eoa");
2385
2386
            /* check for overlap into temporary allocation space */
2387
0
            if (H5F_IS_TMP_ADDR(f, (eoa + fspace->sect_size)))
2388
0
                HGOTO_ERROR(H5E_FSPACE, H5E_BADRANGE, FAIL,
2389
0
                            "sinfo file space alloc will overlap into 'temporary' file space");
2390
2391
0
            sinfo_alloc_size = fspace->sect_size;
2392
2393
0
            if (H5F_PAGED_AGGR(f))
2394
0
                assert(0 == (eoa % f->shared->fs_page_size));
2395
2396
            /* allocate space for the section info */
2397
0
            if (HADDR_UNDEF == (sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, sinfo_alloc_size)))
2398
0
                HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for section info");
2399
2400
            /* update fspace->alloc_sect_size and fspace->sect_addr to reflect
2401
             * the allocation
2402
             */
2403
0
            if (fspace->sect_size > sinfo_alloc_size) {
2404
0
                hsize_t saved_sect_size = fspace->sect_size;
2405
2406
0
                if (H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, sect_addr, sinfo_alloc_size) < 0)
2407
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections");
2408
0
                fspace->sect_size = saved_sect_size;
2409
0
            }
2410
0
            else {
2411
0
                fspace->alloc_sect_size = sinfo_alloc_size;
2412
0
                fspace->sect_size       = sinfo_alloc_size;
2413
0
                fspace->sect_addr       = sect_addr;
2414
2415
                /* insert the new section info into the metadata cache.  */
2416
2417
                /* Question: Do we need to worry about this insertion causing an
2418
                 * eviction from the metadata cache?  Think on this.  If so, add a
2419
                 * flag to H5AC_insert() to force it to skip the call to make space in
2420
                 * cache.
2421
                 *
2422
                 * On reflection, no.
2423
                 *
2424
                 * On a regular file close, any eviction will not change the
2425
                 * the contents of the free space manager(s), as all entries
2426
                 * should have correct file space allocated by the time this
2427
                 * function is called.
2428
                 *
2429
                 * In the cache image case, the selection of entries for inclusion
2430
                 * in the cache image will not take place until after this call.
2431
                 * (Recall that this call is made during the metadata fsm settle
2432
                 * routine, which is called during the serialization routine in
2433
                 * the cache image case.  Entries are not selected for inclusion
2434
                 * in the image until after the cache is serialized.)
2435
                 *
2436
                 *                                        JRM -- 11/4/16
2437
                 */
2438
0
                if (H5AC_insert_entry(f, H5AC_FSPACE_SINFO, sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
2439
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sinfo to cache");
2440
2441
                /* We have changed the sinfo address -- Mark free space header dirty */
2442
0
                if (H5AC_mark_entry_dirty(fspace) < 0)
2443
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
2444
0
                                "unable to mark free space header as dirty");
2445
2446
                /* since space has been allocated for the section info and the sinfo
2447
                 * has been inserted into the cache, relinquish ownership (i.e. float)
2448
                 * the section info.
2449
                 */
2450
0
                fspace->sinfo = NULL;
2451
0
            }
2452
0
        }
2453
0
    } /* end if */
2454
2455
0
done:
2456
0
    FUNC_LEAVE_NOAPI(ret_value)
2457
0
} /* H5FS_vfd_alloc_hdr_and_section_info_if_needed() */