Coverage Report

Created: 2025-08-29 07:09

/src/hdf5/src/H5FSsection.c
Line
Count
Source (jump to first uncovered line)
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
44
{
112
44
    H5FS_sinfo_t *sinfo     = NULL; /* Section information struct created */
113
44
    H5FS_sinfo_t *ret_value = NULL; /* Return value */
114
115
44
    FUNC_ENTER_PACKAGE
116
117
    /* Check arguments. */
118
44
    assert(f);
119
44
    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
44
    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
44
    sinfo->nbins            = H5VM_log2_gen(fspace->max_sect_size);
130
44
    sinfo->sect_prefix_size = H5FS_SINFO_PREFIX_SIZE(f);
131
44
    sinfo->sect_off_size    = (fspace->max_sect_addr + 7) / 8;
132
44
    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
44
    if (NULL == (sinfo->bins = H5FL_SEQ_CALLOC(H5FS_bin_t, (size_t)sinfo->nbins)))
143
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
144
44
                    "memory allocation failed for free space section bin array");
145
146
    /* Increment the reference count on the free space manager header */
147
44
    if (H5FS__incr(fspace) < 0)
148
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINC, NULL, "unable to increment ref. count on free space header");
149
44
    sinfo->fspace = fspace;
150
151
    /* Link free space manager to section info */
152
    /* (for deserializing sections) */
153
44
    assert(fspace->sinfo == NULL);
154
44
    fspace->sinfo = sinfo;
155
156
    /* Set return value */
157
44
    ret_value = sinfo;
158
159
44
done:
160
44
    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
44
    FUNC_LEAVE_NOAPI(ret_value)
170
44
} /* 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
424
{
189
424
    H5FS_sinfo_cache_ud_t cache_udata;         /* User-data for cache callback */
190
424
    herr_t                ret_value = SUCCEED; /* Return value */
191
192
424
    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
424
    assert(f);
205
424
    assert(fspace);
206
207
    /* only H5AC__READ_ONLY_FLAG may appear in accmode */
208
424
    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
424
    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
338
        assert(((fspace->sinfo_accmode) & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
218
219
338
        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
338
    }         /* end if */
240
86
    else {
241
        /* If the section address is defined, load it from the file */
242
86
        if (H5_addr_defined(fspace->sect_addr)) {
243
            /* Sanity check */
244
55
            assert(fspace->sinfo_protected == false);
245
55
            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
55
            cache_udata.f      = f;
253
55
            cache_udata.fspace = fspace;
254
55
            if (NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, H5AC_FSPACE_SINFO, fspace->sect_addr,
255
55
                                                                      &cache_udata, accmode)))
256
3
                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
52
            fspace->sinfo_protected = true;
260
52
            fspace->sinfo_accmode   = accmode;
261
52
        } /* end if */
262
31
        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
31
            assert(fspace->tot_sect_count == 0);
268
31
            assert(fspace->serial_sect_count == 0);
269
31
            assert(fspace->ghost_sect_count == 0);
270
271
            /* Allocate and initialize free space section info */
272
31
            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
31
            fspace->sect_size = fspace->alloc_sect_size = 0;
277
31
        } /* end if */
278
86
    }     /* end if */
279
421
    assert(fspace->rc == 2);
280
281
    /* Increment the section info lock count */
282
421
    fspace->sinfo_lock_count++;
283
284
424
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
424
    FUNC_LEAVE_NOAPI(ret_value)
294
424
} /* 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
421
{
323
421
    herr_t ret_value = SUCCEED; /* Return value */
324
325
421
    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
421
    assert(f);
339
421
    assert(fspace);
340
421
    assert(fspace->rc == 2);
341
421
    assert(fspace->sinfo);
342
343
    /* Check if we modified any section */
344
421
    if (modified) {
345
        /* Check if the section info was protected with a different access mode */
346
287
        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
287
        fspace->sinfo->dirty = true;
351
352
        /* Remember that the section info was modified while locked */
353
287
        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
287
        if (H5FS__dirty(fspace) < 0)
359
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty");
360
287
    } /* end if */
361
362
    /* Decrement the lock count on the section info */
363
421
    fspace->sinfo_lock_count--;
364
365
    /* Check if section info lock count dropped to zero */
366
421
    if (fspace->sinfo_lock_count == 0) {
367
421
        bool release_sinfo_space = false; /* Flag to indicate section info space in file should be released */
368
421
        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
421
        if (!closing_or_flushing &&
372
421
            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
421
        if (fspace->sinfo_protected) {
377
52
            unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap */
378
379
            /* Sanity check */
380
52
            assert(H5_addr_defined(fspace->addr));
381
382
            /* Check if we've made new changes to the section info while locked */
383
52
            if (fspace->sinfo_modified) {
384
                /* Note that we've modified the section info */
385
21
                cache_flags |= H5AC__DIRTIED_FLAG;
386
387
                /* On file close or flushing, does not allow section info to shrink in size */
388
21
                if (closing_or_flushing) {
389
14
                    if (fspace->sect_size > fspace->alloc_sect_size)
390
2
                        cache_flags |= H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG;
391
12
                    else
392
12
                        fspace->sect_size = fspace->alloc_sect_size;
393
394
                    /* Check if the section info size in the file has changed */
395
14
                }
396
7
                else if (fspace->sect_size != fspace->alloc_sect_size)
397
7
                    cache_flags |= H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG;
398
399
21
            } /* end if */
400
401
            /* Sanity check */
402
52
            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
52
            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
52
            fspace->sinfo_protected = false;
415
416
            /* Check if header is taking ownership of section info */
417
52
            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
9
                release_sinfo_space = true;
423
9
            } /* end if */
424
43
            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
43
                fspace->sinfo = NULL;
430
43
            } /* end else */
431
52
        }     /* end if */
432
369
        else {
433
            /* Check if the section info was modified */
434
369
            if (fspace->sinfo_modified) {
435
                /* Check if we need to release section info in the file */
436
266
                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
266
                else
450
266
                    assert(fspace->alloc_sect_size == 0);
451
452
266
            } /* end if */
453
103
            else {
454
                /* Sanity checks... */
455
103
                if (H5_addr_defined(fspace->sect_addr))
456
10
                    assert(fspace->alloc_sect_size == fspace->sect_size);
457
93
                else
458
93
                    assert(fspace->alloc_sect_size == 0);
459
103
            } /* end else */
460
369
        }     /* end else */
461
462
        /* Reset the "section info modified" flag */
463
421
        fspace->sinfo_modified = false;
464
465
        /* Check if header needs to release section info in the file */
466
421
        if (release_sinfo_space) {
467
9
            haddr_t old_sect_addr       = fspace->sect_addr; /* Previous location of section info in file */
468
9
            hsize_t old_alloc_sect_size = fspace->alloc_sect_size; /* Previous size of section info in file */
469
470
            /* Sanity check */
471
9
            assert(H5_addr_defined(fspace->addr));
472
473
            /* Reset section info in header */
474
9
            fspace->sect_addr       = HADDR_UNDEF;
475
9
            fspace->alloc_sect_size = 0;
476
477
            /* If we haven't already marked the header dirty, do so now */
478
9
            if (!modified)
479
0
                if (H5FS__dirty(fspace) < 0)
480
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
481
9
                                "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
9
            if (!H5F_IS_TMP_ADDR(f, old_sect_addr))
491
9
                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
9
        } /* end if */
494
421
    }     /* end if */
495
496
421
done:
497
#ifdef H5FS_SINFO_DEBUG
498
    fprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value);
499
#endif /* H5FS_SINFO_DEBUG */
500
421
    FUNC_LEAVE_NOAPI(ret_value)
501
421
} /* 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
316
{
515
316
    FUNC_ENTER_PACKAGE_NOERR
516
517
    /* Check arguments. */
518
316
    assert(fspace);
519
520
    /* Compute the size of the buffer required to serialize all the sections */
521
316
    if (fspace->serial_sect_count > 0) {
522
271
        size_t sect_buf_size; /* Section buffer size */
523
524
        /* Serialized sections prefix */
525
271
        sect_buf_size = fspace->sinfo->sect_prefix_size;
526
527
        /* Count for each differently sized serializable section */
528
271
        sect_buf_size +=
529
271
            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
271
        sect_buf_size += fspace->sinfo->serial_size_count * fspace->sinfo->sect_len_size;
533
534
        /* Offsets of each section in address space */
535
271
        sect_buf_size += fspace->serial_sect_count * fspace->sinfo->sect_off_size;
536
537
        /* Class of each section */
538
271
        sect_buf_size += fspace->serial_sect_count * 1 /* byte */;
539
540
        /* Extra space required to serialize each section */
541
271
        sect_buf_size += fspace->sinfo->serial_size;
542
543
        /* Update section size in header */
544
271
        fspace->sect_size = sect_buf_size;
545
271
    } /* end if */
546
45
    else
547
        /* Reset section size in header */
548
45
        fspace->sect_size = fspace->sinfo->sect_prefix_size;
549
550
316
    FUNC_LEAVE_NOAPI(SUCCEED)
551
316
} /* 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
207
{
566
207
    herr_t ret_value = SUCCEED; /* Return value */
567
568
207
    FUNC_ENTER_PACKAGE
569
570
    /* Check arguments. */
571
207
    assert(fspace);
572
207
    assert(fspace->sinfo);
573
207
    assert(cls);
574
575
    /* Increment total # of sections on free space list */
576
207
    fspace->tot_sect_count++;
577
578
    /* Check for serializable or 'ghost' section */
579
207
    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
207
    else {
587
        /* Increment # of serializable sections */
588
207
        fspace->serial_sect_count++;
589
590
        /* Increment amount of space required to serialize all sections */
591
207
        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
207
        if (!(flags & H5FS_ADD_DESERIALIZING)) {
596
197
            if (H5FS__sect_serialize_size(fspace) < 0)
597
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL,
598
197
                            "can't adjust free space section size on disk");
599
197
        } /* end if */
600
207
    }     /* end else */
601
602
207
done:
603
207
    FUNC_LEAVE_NOAPI(ret_value)
604
207
} /* 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
119
{
619
119
    herr_t ret_value = SUCCEED; /* Return value */
620
621
119
    FUNC_ENTER_PACKAGE
622
623
    /* Check arguments. */
624
119
    assert(fspace);
625
119
    assert(fspace->sinfo);
626
119
    assert(cls);
627
628
    /* Decrement total # of sections in free space manager */
629
119
    fspace->tot_sect_count--;
630
631
    /* Check for serializable or 'ghost' section */
632
119
    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
119
    else {
640
        /* Decrement # of serializable sections */
641
119
        fspace->serial_sect_count--;
642
643
        /* Decrement amount of space required to serialize all sections */
644
119
        fspace->sinfo->serial_size -= cls->serial_size;
645
646
        /* Update the free space sections' serialized size */
647
119
        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
119
    } /* end else */
650
651
119
done:
652
119
    FUNC_LEAVE_NOAPI(ret_value)
653
119
} /* 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
119
{
668
119
    herr_t ret_value = SUCCEED; /* Return value */
669
670
119
    FUNC_ENTER_PACKAGE
671
672
    /* Check arguments. */
673
119
    assert(sinfo);
674
119
    assert(fspace_node);
675
119
    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
119
    sinfo->bins[bin].tot_sect_count--;
682
683
    /* Check for 'ghost' or 'serializable' section */
684
119
    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
119
    else {
696
        /* Decrement node's serializable section count */
697
119
        fspace_node->serial_count--;
698
699
        /* Decrement bin's serializable section count */
700
119
        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
119
        if (fspace_node->serial_count == 0)
705
116
            sinfo->serial_size_count--;
706
119
    } /* end else */
707
708
    /* Check for no more nodes on list of that size */
709
119
    if (H5SL_count(fspace_node->sect_list) == 0) {
710
116
        H5FS_node_t *tmp_fspace_node; /* Free space list size node */
711
712
        /* Sanity checks */
713
116
        assert(fspace_node->ghost_count == 0);
714
116
        assert(fspace_node->serial_count == 0);
715
716
        /* Remove size tracking list from bin */
717
116
        tmp_fspace_node = (H5FS_node_t *)H5SL_remove(sinfo->bins[bin].bin_list, &fspace_node->sect_size);
718
116
        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
116
        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
116
        fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
727
728
        /* Decrement total number of section sizes managed */
729
116
        sinfo->tot_size_count--;
730
116
    } /* end if */
731
732
119
done:
733
119
    FUNC_LEAVE_NOAPI(ret_value)
734
119
} /* 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
34
{
749
34
    H5FS_node_t         *fspace_node;         /* Free list size node */
750
34
    H5FS_section_info_t *tmp_sect_node;       /* Temporary section node */
751
34
    unsigned             bin;                 /* Bin to put the free space section in */
752
34
    herr_t               ret_value = SUCCEED; /* Return value */
753
754
34
    FUNC_ENTER_PACKAGE
755
756
    /* Check arguments. */
757
34
    assert(sinfo);
758
34
    assert(sinfo->bins);
759
34
    assert(sect);
760
34
    assert(cls);
761
762
    /* Determine correct bin which holds items of at least the section's size */
763
34
    bin = H5VM_log2_gen(sect->size);
764
34
    assert(bin < sinfo->nbins);
765
34
    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
34
    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
34
    tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace_node->sect_list, &sect->addr);
774
34
    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
34
    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
34
done:
782
34
    FUNC_LEAVE_NOAPI(ret_value)
783
34
} /* 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
119
{
799
119
    herr_t ret_value = SUCCEED; /* Return value */
800
801
119
    FUNC_ENTER_PACKAGE
802
803
    /* Check arguments. */
804
119
    assert(fspace);
805
119
    assert(fspace->sinfo);
806
119
    assert(cls);
807
119
    assert(sect);
808
809
    /* Remove node from merge list, if it was entered there */
810
119
    if (!(cls->flags & H5FS_CLS_SEPAR_OBJ)) {
811
119
        H5FS_section_info_t *tmp_sect_node; /* Temporary section node */
812
813
119
        tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace->sinfo->merge_list, &sect->addr);
814
119
        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
119
    } /* end if */
817
818
    /* Update section info & check if we need less room for the serialized free space sections */
819
119
    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
119
    fspace->tot_space -= sect->size;
824
825
119
done:
826
119
    FUNC_LEAVE_NOAPI(ret_value)
827
119
} /* 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
34
{
841
34
    const H5FS_section_class_t *cls;                 /* Class of section */
842
34
    herr_t                      ret_value = SUCCEED; /* Return value */
843
844
34
    FUNC_ENTER_PACKAGE
845
846
    /* Check arguments. */
847
34
    assert(fspace);
848
34
    assert(fspace->sinfo);
849
34
    assert(sect);
850
851
    /* Get section's class */
852
34
    cls = &fspace->sect_cls[sect->type];
853
854
    /* Remove node from size tracked data structures */
855
34
    if (H5FS__sect_unlink_size(fspace->sinfo, cls, sect) < 0)
856
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
857
34
                    "can't remove section from size tracking data structures");
858
859
    /* Update rest of free space manager data structures for node removal */
860
34
    if (H5FS__sect_unlink_rest(fspace, cls, sect) < 0)
861
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
862
34
                    "can't remove section from non-size tracking data structures");
863
864
34
done:
865
34
    FUNC_LEAVE_NOAPI(ret_value)
866
34
} /* 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
207
{
919
207
    H5FS_node_t *fspace_node       = NULL;  /* Pointer to free space node of the correct size */
920
207
    bool         fspace_node_alloc = false; /* Whether the free space node was allocated */
921
207
    unsigned     bin;                       /* Bin to put the free space section in */
922
207
    herr_t       ret_value = SUCCEED;       /* Return value */
923
924
207
    FUNC_ENTER_PACKAGE
925
926
    /* Check arguments. */
927
207
    assert(sinfo);
928
207
    assert(sect);
929
207
    assert(H5_addr_defined(sect->addr));
930
207
    assert(sect->size);
931
932
    /* Determine correct bin which holds items of the section's size */
933
207
    bin = H5VM_log2_gen(sect->size);
934
207
    assert(bin < sinfo->nbins);
935
207
    if (sinfo->bins[bin].bin_list == NULL) {
936
98
        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
98
    } /* end if */
939
109
    else
940
        /* Check for node list of the correct size already */
941
109
        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
207
    if (fspace_node == NULL) {
945
        /* Allocate new free list size node */
946
203
        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
203
        fspace_node_alloc = true;
949
950
        /* Initialize the free list size node */
951
203
        fspace_node->sect_size    = sect->size;
952
203
        fspace_node->serial_count = fspace_node->ghost_count = 0;
953
203
        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
203
        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
203
        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
203
        sinfo->tot_size_count++;
963
203
    } /* 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
207
    sinfo->bins[bin].tot_sect_count++;
970
207
    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
207
    else {
979
207
        sinfo->bins[bin].serial_sect_count++;
980
207
        fspace_node->serial_count++;
981
982
        /* Check for first serializable section in node */
983
207
        if (fspace_node->serial_count == 1)
984
203
            sinfo->serial_size_count++;
985
207
    } /* end else */
986
987
    /* Insert free space node into correct skip list */
988
207
    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
207
done:
992
207
    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
207
    FUNC_LEAVE_NOAPI(ret_value)
1001
207
} /* 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
207
{
1017
207
    herr_t ret_value = SUCCEED; /* Return value */
1018
1019
207
    FUNC_ENTER_PACKAGE
1020
1021
    /* Check arguments. */
1022
207
    assert(fspace);
1023
207
    assert(fspace->sinfo);
1024
207
    assert(sect);
1025
1026
    /* Add section to the address-ordered list of sections, if allowed */
1027
207
    if (!(cls->flags & H5FS_CLS_SEPAR_OBJ)) {
1028
207
        if (fspace->sinfo->merge_list == NULL)
1029
41
            if (NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
1030
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL,
1031
207
                            "can't create skip list for merging free space sections");
1032
207
        if (H5SL_insert(fspace->sinfo->merge_list, sect, &sect->addr) < 0)
1033
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1034
207
                        "can't insert free space node into merging skip list");
1035
207
    } /* end if */
1036
1037
    /* Update section info & check if we need more room for the serialized free space sections */
1038
207
    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
207
    fspace->tot_space += sect->size;
1043
1044
207
done:
1045
207
    FUNC_LEAVE_NOAPI(ret_value)
1046
207
} /* 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
207
{
1060
207
    const H5FS_section_class_t *cls;                 /* Class of section */
1061
207
    herr_t                      ret_value = SUCCEED; /* Return value */
1062
1063
207
    FUNC_ENTER_PACKAGE
1064
1065
    /* Check arguments. */
1066
207
    assert(fspace);
1067
207
    assert(fspace->sinfo);
1068
207
    assert(sect);
1069
1070
    /* Get section's class */
1071
207
    cls = &fspace->sect_cls[sect->type];
1072
1073
    /* Add section to size tracked data structures */
1074
207
    if (H5FS__sect_link_size(fspace->sinfo, cls, sect) < 0)
1075
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to size tracking data structures");
1076
1077
    /* Update rest of free space manager data structures for section addition */
1078
207
    if (H5FS__sect_link_rest(fspace, cls, sect, flags) < 0)
1079
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1080
207
                    "can't add section to non-size tracking data structures");
1081
1082
207
done:
1083
207
    FUNC_LEAVE_NOAPI(ret_value)
1084
207
} /* H5FS__sect_link() */
1085
1086
/*-------------------------------------------------------------------------
1087
 * Function:    H5FS__sect_merge
1088
 *
1089
 * Purpose:     Attempt to merge a returned free space section with existing
1090
 *              free space.
1091
 *
1092
 * Return:      SUCCEED/FAIL
1093
 *
1094
 *-------------------------------------------------------------------------
1095
 */
1096
static herr_t
1097
H5FS__sect_merge(H5FS_t *fspace, H5FS_section_info_t **sect, void *op_data)
1098
203
{
1099
203
    H5FS_section_class_t *sect_cls;            /* Section's class */
1100
203
    bool                  modified;            /* Flag to indicate merge or shrink occurred */
1101
203
    bool                  remove_sect = false; /* Whether a section should be removed before shrinking */
1102
203
    htri_t                status;              /* Status value */
1103
203
    herr_t                ret_value = SUCCEED; /* Return value */
1104
1105
203
    FUNC_ENTER_PACKAGE
1106
1107
    /* Check arguments. */
1108
203
    assert(fspace);
1109
203
    assert(*sect);
1110
203
    assert(H5_addr_defined((*sect)->addr));
1111
203
    assert((*sect)->size);
1112
1113
    /* Loop until no more merging */
1114
203
    if (fspace->sinfo->merge_list) {
1115
198
        do {
1116
198
            H5SL_node_t *less_sect_node;           /* Skip list node for section less than new section */
1117
198
            H5SL_node_t *greater_sect_node = NULL; /* Skip list node for section greater than new section */
1118
198
            H5FS_section_info_t  *tmp_sect;        /* Temporary free space section */
1119
198
            H5FS_section_class_t *tmp_sect_cls;    /* Temporary section's class */
1120
198
            bool greater_sect_node_valid = false;  /* Indicate if 'greater than' section node is valid */
1121
1122
            /* Reset 'modification occurred' flag */
1123
198
            modified = false;
1124
1125
            /* Look for neighboring section before new section */
1126
198
            less_sect_node = H5SL_below(fspace->sinfo->merge_list, &(*sect)->addr);
1127
1128
            /* Check for node before new node able to merge with new node */
1129
198
            if (less_sect_node) {
1130
                /* Check for node greater than section */
1131
112
                greater_sect_node       = H5SL_next(less_sect_node);
1132
112
                greater_sect_node_valid = true;
1133
1134
                /* Get section for 'less than' skip list node */
1135
112
                tmp_sect = (H5FS_section_info_t *)H5SL_item(less_sect_node);
1136
1137
                /* Get classes for right & left sections */
1138
112
                tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
1139
112
                sect_cls     = &fspace->sect_cls[(*sect)->type];
1140
1141
                /* Check if sections of the left most class can merge with sections
1142
                 *  of another class & whether the sections are the same type,
1143
                 *  then check for 'can merge' callback
1144
                 */
1145
112
                if ((!(tmp_sect_cls->flags & H5FS_CLS_MERGE_SYM) || (tmp_sect->type == (*sect)->type)) &&
1146
112
                    tmp_sect_cls->can_merge) {
1147
                    /* Determine if the sections can merge */
1148
112
                    if ((status = (*tmp_sect_cls->can_merge)(tmp_sect, *sect, op_data)) < 0)
1149
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections");
1150
112
                    if (status > 0) {
1151
                        /* Sanity check */
1152
10
                        assert(tmp_sect_cls->merge);
1153
1154
                        /* Remove 'less than' node from data structures */
1155
10
                        if (H5FS__sect_remove_real(fspace, tmp_sect) < 0)
1156
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1157
10
                                        "can't remove section from internal data structures");
1158
1159
                        /* Merge the two sections together */
1160
10
                        if ((*tmp_sect_cls->merge)(&tmp_sect, *sect, op_data) < 0)
1161
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections");
1162
1163
                        /* Retarget section pointer to 'less than' node that was merged into */
1164
10
                        *sect = tmp_sect;
1165
10
                        if (*sect == NULL)
1166
0
                            HGOTO_DONE(ret_value);
1167
1168
                        /* Indicate successful merge occurred */
1169
10
                        modified = true;
1170
10
                    } /* end if */
1171
112
                }     /* end if */
1172
112
            }         /* end if */
1173
1174
            /* Look for section after new (or merged) section, if not already determined */
1175
198
            if (!greater_sect_node_valid)
1176
86
                greater_sect_node = H5SL_above(fspace->sinfo->merge_list, &(*sect)->addr);
1177
1178
            /* Check for node after new node able to merge with new node */
1179
198
            if (greater_sect_node) {
1180
                /* Get section for 'greater than' skip list node */
1181
102
                tmp_sect = (H5FS_section_info_t *)H5SL_item(greater_sect_node);
1182
1183
                /* Get classes for right & left sections */
1184
102
                sect_cls     = &fspace->sect_cls[(*sect)->type];
1185
102
                tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
1186
1187
                /* Check if sections of the left most class can merge with sections
1188
                 *  of another class & whether the sections are the same type,
1189
                 *  then check for 'can merge' callback
1190
                 */
1191
102
                if ((!(sect_cls->flags & H5FS_CLS_MERGE_SYM) || ((*sect)->type == tmp_sect->type)) &&
1192
102
                    sect_cls->can_merge) {
1193
1194
                    /* Determine if the sections can merge */
1195
102
                    if ((status = (*sect_cls->can_merge)(*sect, tmp_sect, op_data)) < 0)
1196
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections");
1197
102
                    if (status > 0) {
1198
                        /* Sanity check */
1199
24
                        assert(sect_cls->merge);
1200
1201
                        /* Remove 'greater than' node from data structures */
1202
24
                        if (H5FS__sect_remove_real(fspace, tmp_sect) < 0)
1203
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1204
24
                                        "can't remove section from internal data structures");
1205
1206
                        /* Merge the two sections together */
1207
24
                        if ((*sect_cls->merge)(sect, tmp_sect, op_data) < 0)
1208
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections");
1209
1210
                        /* It's possible that the merge caused the section to be deleted (particularly in the
1211
                         * paged allocation case) */
1212
24
                        if (*sect == NULL)
1213
3
                            HGOTO_DONE(ret_value);
1214
1215
                        /* Indicate successful merge occurred */
1216
21
                        modified = true;
1217
21
                    } /* end if */
1218
102
                }     /* end if */
1219
102
            }         /* end if */
1220
198
        } while (modified);
1221
172
    } /* end if */
1222
200
    assert(*sect);
1223
1224
    /* Loop until no more shrinking */
1225
210
    do {
1226
        /* Reset 'modification occurred' flag */
1227
210
        modified = false;
1228
1229
        /* Check for (possibly merged) section able to shrink the size of the container */
1230
210
        sect_cls = &fspace->sect_cls[(*sect)->type];
1231
210
        if (sect_cls->can_shrink) {
1232
96
            if ((status = (*sect_cls->can_shrink)(*sect, op_data)) < 0)
1233
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking container");
1234
96
            if (status > 0) {
1235
                /* Remove SECT from free-space manager */
1236
                /* (only possible to happen on second+ pass through loop) */
1237
10
                if (remove_sect) {
1238
0
                    if (H5FS__sect_remove_real(fspace, *sect) < 0)
1239
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1240
0
                                    "can't remove section from internal data structures");
1241
0
                    remove_sect = false;
1242
0
                } /* end if */
1243
1244
                /* Shrink the container */
1245
                /* (callback can indicate that it has discarded the section by setting *sect to NULL) */
1246
10
                assert(sect_cls->shrink);
1247
10
                if ((*sect_cls->shrink)(sect, op_data) < 0)
1248
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't shrink free space container");
1249
1250
                /* If this section was shrunk away, we may need to shrink another section */
1251
10
                if (*sect == NULL) {
1252
                    /* Check for sections on merge list */
1253
10
                    if (fspace->sinfo->merge_list) {
1254
10
                        H5SL_node_t *last_node; /* Last node in merge list */
1255
1256
                        /* Check for last node in the merge list */
1257
10
                        if (NULL != (last_node = H5SL_last(fspace->sinfo->merge_list))) {
1258
                            /* Get the pointer to the last section, from the last node */
1259
10
                            *sect = (H5FS_section_info_t *)H5SL_item(last_node);
1260
10
                            assert(*sect);
1261
1262
                            /* Indicate that this section needs to be removed if it causes a shrink */
1263
10
                            remove_sect = true;
1264
10
                        } /* end if */
1265
10
                    }     /* end if */
1266
10
                }         /* end if */
1267
1268
                /* Indicate successful merge occurred */
1269
10
                modified = true;
1270
10
            } /* end if */
1271
96
        }     /* end if */
1272
210
    } while (modified && *sect);
1273
1274
    /* Check for section that was shrunk away and next section not shrinking */
1275
200
    if (remove_sect && (*sect != NULL))
1276
10
        *sect = NULL;
1277
1278
203
done:
1279
203
    FUNC_LEAVE_NOAPI(ret_value)
1280
203
} /* H5FS__sect_merge() */
1281
1282
/*-------------------------------------------------------------------------
1283
 * Function:    H5FS_sect_add
1284
 *
1285
 * Purpose:     Add a section of free space to the free list
1286
 *
1287
 * Return:      SUCCEED/FAIL
1288
 *
1289
 *-------------------------------------------------------------------------
1290
 */
1291
herr_t
1292
H5FS_sect_add(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags, void *op_data)
1293
214
{
1294
214
    H5FS_section_class_t *cls;                      /* Section's class */
1295
214
    bool                  sinfo_valid    = false;   /* Whether the section info is valid */
1296
214
    bool                  sinfo_modified = false;   /* Whether the section info was modified */
1297
214
    herr_t                ret_value      = SUCCEED; /* Return value */
1298
1299
214
    FUNC_ENTER_NOAPI(FAIL)
1300
1301
#ifdef H5FS_SINFO_DEBUG
1302
    fprintf(stderr, "%s: *sect = {%" PRIuHADDR ", %" PRIuHSIZE ", %u, %s}\n", __func__, sect->addr,
1303
            sect->size, sect->type,
1304
            (sect->state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED"));
1305
#endif /* H5FS_SINFO_DEBUG */
1306
1307
    /* Check arguments. */
1308
214
    assert(fspace);
1309
214
    assert(sect);
1310
214
    assert(H5_addr_defined(sect->addr));
1311
214
    assert(sect->size);
1312
1313
    /* Get a pointer to the section info */
1314
214
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1315
1
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1316
213
    sinfo_valid = true;
1317
1318
    /* Call "add" section class callback, if there is one */
1319
213
    cls = &fspace->sect_cls[sect->type];
1320
213
    if (cls->add)
1321
118
        if ((*cls->add)(&sect, &flags, op_data) < 0)
1322
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "'add' section class callback failed");
1323
1324
    /* Check for merging returned space with existing section node */
1325
213
    if (flags & H5FS_ADD_RETURNED_SPACE) {
1326
#ifdef H5FS_SINFO_DEBUG
1327
        fprintf(stderr, "%s: Returning space\n", __func__);
1328
#endif /* H5FS_SINFO_DEBUG */
1329
1330
        /* Attempt to merge returned section with existing sections */
1331
199
        if (H5FS__sect_merge(fspace, &sect, op_data) < 0)
1332
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections");
1333
199
    } /* end if */
1334
1335
    /* Add new (possibly merged) node to free sections data structures */
1336
    /* (If section has been completely merged or shrunk away, 'sect' will
1337
     *  be NULL at this point - QAK)
1338
     */
1339
213
    if (sect)
1340
199
        if (H5FS__sect_link(fspace, sect, flags) < 0)
1341
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list");
1342
1343
#ifdef H5FS_SINFO_DEBUG
1344
    fprintf(stderr, "%s: fspace->tot_space = %" PRIuHSIZE "\n", __func__, fspace->tot_space);
1345
#endif /* H5FS_SINFO_DEBUG */
1346
    /* Mark free space sections as changed */
1347
    /* (if adding sections while deserializing sections, don't set the flag) */
1348
213
    if (!(flags & (H5FS_ADD_DESERIALIZING | H5FS_PAGE_END_NO_ADD)))
1349
199
        sinfo_modified = true;
1350
1351
214
done:
1352
    /* Release the section info */
1353
214
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1354
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1355
1356
#ifdef H5FS_DEBUG_ASSERT
1357
    if (!(flags & (H5FS_ADD_DESERIALIZING | H5FS_ADD_SKIP_VALID)))
1358
        H5FS__assert(fspace);
1359
#endif /* H5FS_DEBUG_ASSERT */
1360
#ifdef H5FS_SINFO_DEBUG
1361
    fprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value);
1362
#endif /* H5FS_SINFO_DEBUG */
1363
214
    FUNC_LEAVE_NOAPI(ret_value)
1364
214
} /* H5FS_sect_add() */
1365
1366
/*-------------------------------------------------------------------------
1367
 * Function:    H5FS_sect_try_extend
1368
 *
1369
 * Purpose:     Try to extend a block using space from a section on the free list
1370
 *
1371
 * Return:      SUCCEED/FAIL
1372
 *
1373
 *-------------------------------------------------------------------------
1374
 */
1375
htri_t
1376
H5FS_sect_try_extend(H5F_t *f, H5FS_t *fspace, haddr_t addr, hsize_t size, hsize_t extra_requested,
1377
                     unsigned flags, void *op_data)
1378
10
{
1379
10
    bool   sinfo_valid    = false; /* Whether the section info is valid */
1380
10
    bool   sinfo_modified = false; /* Whether the section info was modified */
1381
10
    htri_t ret_value      = false; /* Return value */
1382
1383
10
    FUNC_ENTER_NOAPI(FAIL)
1384
1385
#ifdef H5FS_SINFO_DEBUG
1386
    fprintf(stderr, "%s: addr = %" PRIuHADDR ", size = %" PRIuHSIZE ", extra_requested = %" PRIuHSIZE "\n",
1387
            __func__, addr, size, extra_requested);
1388
#endif /* H5FS_SINFO_DEBUG */
1389
1390
    /* Check arguments. */
1391
10
    assert(f);
1392
10
    assert(fspace);
1393
10
    assert(H5_addr_defined(addr));
1394
10
    assert(size > 0);
1395
10
    assert(extra_requested > 0);
1396
1397
    /* Check for any sections on free space list */
1398
#ifdef H5FS_SINFO_DEBUG
1399
    fprintf(stderr, "%s: fspace->tot_sect_count = %" PRIuHSIZE "\n", __func__, fspace->tot_sect_count);
1400
    fprintf(stderr, "%s: fspace->serial_sect_count = %" PRIuHSIZE "\n", __func__, fspace->serial_sect_count);
1401
    fprintf(stderr, "%s: fspace->ghost_sect_count = %" PRIuHSIZE "\n", __func__, fspace->ghost_sect_count);
1402
#endif /* H5FS_SINFO_DEBUG */
1403
10
    if (fspace->tot_sect_count > 0) {
1404
10
        H5FS_section_info_t *sect; /* Temporary free space section */
1405
1406
        /* Get a pointer to the section info */
1407
10
        if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1408
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1409
10
        sinfo_valid = true;
1410
1411
        /*
1412
1413
        Pseudo-code for algorithm:
1414
1415
        _section_ = <Get pointer to section with address > _region.addr_>
1416
        if(_section_)
1417
            if(_section_ adjoins _region_ && _section.size_ >= _extra_requested_)
1418
                <remove section from data structures>
1419
                if(_section.size_ > _extra_requested_)
1420
                    if(<can adjust _section_>)
1421
                        <adjust _section_ by _extra_requested_>
1422
                        <add adjusted section back to data structures>
1423
                    else
1424
                        <re-add UNadjusted section back to data structures>
1425
                        <error>
1426
                <mark free space sections as changed in metadata cache>
1427
1428
        */
1429
        /* Look for a section after block to extend */
1430
10
        if ((sect = (H5FS_section_info_t *)H5SL_greater(fspace->sinfo->merge_list, &addr))) {
1431
            /* Check if this section adjoins the block and is large enough to
1432
             *  fulfill extension request.
1433
             *
1434
             * (Note: we assume that the section is fully merged with any
1435
             *  possible neighboring nodes and is not at the end of the file
1436
             *  (or it would have been eliminated), etc)
1437
             */
1438
10
            if (sect->size >= extra_requested && (addr + size) == sect->addr) {
1439
0
                H5FS_section_class_t *cls; /* Section's class */
1440
1441
                /* Remove section from data structures */
1442
0
                if (H5FS__sect_remove_real(fspace, sect) < 0)
1443
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
1444
0
                                "can't remove section from internal data structures");
1445
1446
                /* Get class for section */
1447
0
                cls = &fspace->sect_cls[sect->type];
1448
1449
                /* Check for the section needing to be adjusted and re-added */
1450
                /* (Note: we should probably add a can_adjust/adjust callback
1451
                 *      to the section class structure, but we don't need it
1452
                 *      for the current usage, so I've deferred messing with
1453
                 *      it. - QAK - 2008/01/08)
1454
                 */
1455
0
                if (sect->size > extra_requested) {
1456
                    /* Sanity check (for now) */
1457
0
                    assert(cls->flags & H5FS_CLS_ADJUST_OK);
1458
1459
                    /* Adjust section by amount requested */
1460
0
                    sect->addr += extra_requested;
1461
0
                    sect->size -= extra_requested;
1462
0
                    if (cls->add)
1463
0
                        if ((*cls->add)(&sect, &flags, op_data) < 0)
1464
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1465
0
                                        "'add' section class callback failed");
1466
1467
                    /* Re-adding the section could cause it to disappear (particularly when paging) */
1468
0
                    if (sect) {
1469
                        /* Re-add adjusted section to free sections data structures */
1470
0
                        if (H5FS__sect_link(fspace, sect, 0) < 0)
1471
0
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1472
0
                                        "can't insert free space section into skip list");
1473
0
                    } /* end if */
1474
0
                }     /* end if */
1475
0
                else {
1476
                    /* Sanity check */
1477
0
                    assert(sect->size == extra_requested);
1478
1479
                    /* Exact match, so just free section */
1480
0
                    if ((*cls->free)(sect) < 0)
1481
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't free section");
1482
0
                } /* end else */
1483
1484
                /* Note that we modified the section info */
1485
0
                sinfo_modified = true;
1486
1487
                /* Indicate success */
1488
0
                HGOTO_DONE(true);
1489
0
            } /* end if */
1490
10
        }     /* end if */
1491
10
    }         /* end if */
1492
1493
10
done:
1494
    /* Release the section info */
1495
10
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1496
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1497
1498
10
    FUNC_LEAVE_NOAPI(ret_value)
1499
10
} /* H5FS_sect_try_extend() */
1500
1501
/*-------------------------------------------------------------------------
1502
 * Function:    H5FS_sect_try_merge
1503
 *
1504
 * Purpose:     Try to merge/shrink a block
1505
 *
1506
 * Return:      true:       merged/shrunk
1507
 *              false:      not merged/not shrunk
1508
 *              Failure:    negative
1509
 *
1510
 *-------------------------------------------------------------------------
1511
 */
1512
htri_t
1513
H5FS_sect_try_merge(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags, void *op_data)
1514
4
{
1515
4
    bool    sinfo_valid    = false; /* Whether the section info is valid */
1516
4
    bool    sinfo_modified = false; /* Whether the section info was modified */
1517
4
    hsize_t saved_fs_size;          /* Copy of the free-space section size */
1518
4
    htri_t  ret_value = false;      /* Return value */
1519
1520
4
    FUNC_ENTER_NOAPI(FAIL)
1521
1522
    /* Check arguments. */
1523
4
    assert(f);
1524
4
    assert(fspace);
1525
4
    assert(sect);
1526
4
    assert(H5_addr_defined(sect->addr));
1527
4
    assert(sect->size);
1528
1529
    /* Get a pointer to the section info */
1530
4
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1531
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1532
4
    sinfo_valid   = true;
1533
4
    saved_fs_size = sect->size;
1534
1535
    /* Attempt to merge/shrink section with existing sections */
1536
4
    if (H5FS__sect_merge(fspace, &sect, op_data) < 0)
1537
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections");
1538
1539
    /* Check if section is shrunk and/or merged away completely */
1540
4
    if (!sect) {
1541
3
        sinfo_modified = true;
1542
3
        HGOTO_DONE(true);
1543
3
    } /* end if */
1544
1
    else {
1545
        /* Check if section is merged */
1546
1
        if (sect->size != saved_fs_size) {
1547
0
            if (H5FS__sect_link(fspace, sect, flags) < 0)
1548
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1549
0
                            "can't insert free space section into skip list");
1550
0
            sinfo_modified = true;
1551
0
            HGOTO_DONE(true);
1552
0
        } /* end if */
1553
1
    }     /* end else */
1554
1555
4
done:
1556
    /* Release the section info */
1557
4
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1558
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1559
1560
4
    FUNC_LEAVE_NOAPI(ret_value)
1561
4
} /* H5FS_sect_try_merge() */
1562
1563
/*-------------------------------------------------------------------------
1564
 * Function:    H5FS__sect_find_node
1565
 *
1566
 * Purpose:     Locate a section of free space (in existing free space list
1567
 *              bins) that is large enough to fulfill request.
1568
 *
1569
 * Return:      SUCCEED/FAIL
1570
 *
1571
 *-------------------------------------------------------------------------
1572
 */
1573
static htri_t
1574
H5FS__sect_find_node(H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node)
1575
109
{
1576
109
    H5FS_node_t *fspace_node;       /* Free list size node */
1577
109
    unsigned     bin;               /* Bin to put the free space section in */
1578
109
    htri_t       ret_value = false; /* Return value */
1579
1580
109
    H5SL_node_t                *curr_size_node = NULL;
1581
109
    const H5FS_section_class_t *cls; /* Class of section */
1582
109
    hsize_t                     alignment;
1583
1584
109
    FUNC_ENTER_PACKAGE
1585
1586
    /* Check arguments. */
1587
109
    assert(fspace);
1588
109
    assert(fspace->sinfo);
1589
109
    assert(fspace->sinfo->bins);
1590
109
    assert(request > 0);
1591
109
    assert(node);
1592
1593
    /* Determine correct bin which holds items of at least the section's size */
1594
109
    bin = H5VM_log2_gen(request);
1595
109
    assert(bin < fspace->sinfo->nbins);
1596
109
    alignment = fspace->alignment;
1597
109
    if (!((alignment > 1) && (request >= fspace->align_thres)))
1598
99
        alignment = 0; /* no alignment */
1599
1600
2.31k
    do {
1601
        /* Check if there's any sections in this bin */
1602
2.31k
        if (fspace->sinfo->bins[bin].bin_list) {
1603
1604
157
            if (!alignment) { /* no alignment */
1605
                /* Find the first free space section that is large enough to fulfill request */
1606
                /* (Since the bins use skip lists to track the sizes of the address-ordered
1607
                 *  lists, this is actually a "best fit" algorithm)
1608
                 */
1609
                /* Look for large enough free space section in this bin */
1610
147
                if ((fspace_node =
1611
147
                         (H5FS_node_t *)H5SL_greater(fspace->sinfo->bins[bin].bin_list, &request))) {
1612
                    /* Take first node off of the list (ie. node w/lowest address) */
1613
75
                    if (NULL == (*node = (H5FS_section_info_t *)H5SL_remove_first(fspace_node->sect_list)))
1614
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1615
75
                                    "can't remove free space node from skip list");
1616
1617
                    /* Get section's class */
1618
75
                    cls = &fspace->sect_cls[(*node)->type];
1619
                    /* Decrement # of sections in section size node */
1620
75
                    if (H5FS__size_node_decr(fspace->sinfo, bin, fspace_node, cls) < 0)
1621
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1622
75
                                    "can't remove free space size node from skip list");
1623
75
                    if (H5FS__sect_unlink_rest(fspace, cls, *node) < 0)
1624
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
1625
75
                                    "can't remove section from non-size tracking data structures");
1626
                    /* Indicate that we found a node for the request */
1627
75
                    HGOTO_DONE(true);
1628
75
                }  /* end if */
1629
147
            }      /* end if */
1630
10
            else { /* alignment is set */
1631
                /* get the first node of a certain size in this bin */
1632
10
                curr_size_node = H5SL_first(fspace->sinfo->bins[bin].bin_list);
1633
10
                while (curr_size_node != NULL) {
1634
10
                    H5FS_node_t *curr_fspace_node = NULL;
1635
10
                    H5SL_node_t *curr_sect_node   = NULL;
1636
1637
                    /* Get the free space node for free space sections of the same size */
1638
10
                    curr_fspace_node = (H5FS_node_t *)H5SL_item(curr_size_node);
1639
1640
                    /* Get the Skip list which holds  pointers to actual free list sections */
1641
10
                    curr_sect_node = (H5SL_node_t *)H5SL_first(curr_fspace_node->sect_list);
1642
1643
10
                    while (curr_sect_node != NULL) {
1644
10
                        H5FS_section_info_t *curr_sect = NULL;
1645
10
                        hsize_t              mis_align = 0, frag_size = 0;
1646
10
                        H5FS_section_info_t *split_sect = NULL;
1647
1648
                        /* Get section node */
1649
10
                        curr_sect = (H5FS_section_info_t *)H5SL_item(curr_sect_node);
1650
1651
10
                        assert(H5_addr_defined(curr_sect->addr));
1652
10
                        assert(curr_fspace_node->sect_size == curr_sect->size);
1653
1654
10
                        cls = &fspace->sect_cls[curr_sect->type];
1655
1656
10
                        assert(alignment);
1657
10
                        assert(cls);
1658
1659
10
                        if ((mis_align = curr_sect->addr % alignment))
1660
8
                            frag_size = alignment - mis_align;
1661
1662
10
                        if ((curr_sect->size >= (request + frag_size)) && (cls->split)) {
1663
                            /* remove the section with aligned address */
1664
10
                            if (NULL == (*node = (H5FS_section_info_t *)H5SL_remove(
1665
10
                                             curr_fspace_node->sect_list, &curr_sect->addr)))
1666
0
                                HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1667
10
                                            "can't remove free space node from skip list");
1668
                            /* Decrement # of sections in section size node */
1669
10
                            if (H5FS__size_node_decr(fspace->sinfo, bin, curr_fspace_node, cls) < 0)
1670
0
                                HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL,
1671
10
                                            "can't remove free space size node from skip list");
1672
1673
10
                            if (H5FS__sect_unlink_rest(fspace, cls, *node) < 0)
1674
0
                                HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL,
1675
10
                                            "can't remove section from non-size tracking data structures");
1676
1677
                            /*
1678
                             * The split() callback splits NODE into 2 sections:
1679
                             *  split_sect is the unused fragment for aligning NODE
1680
                             *  NODE's addr & size are updated to point to the remaining aligned section
1681
                             * split_sect is re-added to free-space
1682
                             */
1683
10
                            if (mis_align) {
1684
8
                                split_sect = cls->split(*node, frag_size);
1685
8
                                if ((H5FS__sect_link(fspace, split_sect, 0) < 0))
1686
0
                                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
1687
8
                                                "can't insert free space section into skip list");
1688
                                /* sanity check */
1689
8
                                assert(split_sect->addr < (*node)->addr);
1690
8
                                assert(request <= (*node)->size);
1691
8
                            } /* end if */
1692
                            /* Indicate that we found a node for the request */
1693
10
                            HGOTO_DONE(true);
1694
10
                        } /* end if */
1695
1696
                        /* Get the next section node in the list */
1697
0
                        curr_sect_node = H5SL_next(curr_sect_node);
1698
0
                    } /* end while of curr_sect_node */
1699
1700
                    /* Get the next size node in the bin */
1701
0
                    curr_size_node = H5SL_next(curr_size_node);
1702
0
                } /* end while of curr_size_node */
1703
10
            }     /* else of alignment */
1704
157
        }         /* if bin_list */
1705
        /* Advance to next larger bin */
1706
2.23k
        bin++;
1707
2.23k
    } while (bin < fspace->sinfo->nbins);
1708
1709
109
done:
1710
109
    FUNC_LEAVE_NOAPI(ret_value)
1711
109
} /* H5FS__sect_find_node() */
1712
1713
/*-------------------------------------------------------------------------
1714
 * Function:    H5FS_sect_find
1715
 *
1716
 * Purpose:     Locate a section of free space (in existing free space list) that
1717
 *              is large enough to fulfill request.
1718
 *
1719
 * Return:      SUCCEED/FAIL
1720
 *
1721
 *-------------------------------------------------------------------------
1722
 */
1723
htri_t
1724
H5FS_sect_find(H5F_t *f, H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node)
1725
115
{
1726
115
    bool   sinfo_valid    = false; /* Whether the section info is valid */
1727
115
    bool   sinfo_modified = false; /* Whether the section info was modified */
1728
115
    htri_t ret_value      = false; /* Return value */
1729
1730
115
    FUNC_ENTER_NOAPI(FAIL)
1731
1732
    /* Check arguments. */
1733
115
    assert(fspace);
1734
115
    assert(fspace->nclasses);
1735
115
    assert(request);
1736
115
    assert(node);
1737
1738
    /* Check for any sections on free space list */
1739
115
    if (fspace->tot_sect_count > 0) {
1740
        /* Get a pointer to the section info */
1741
109
        if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1742
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1743
109
        sinfo_valid = true;
1744
1745
        /* Look for node in bins */
1746
109
        if ((ret_value = H5FS__sect_find_node(fspace, request, node)) < 0)
1747
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from bins");
1748
1749
        /* Decrement # of sections on free list, if we found an object */
1750
109
        if (ret_value > 0) {
1751
            /* Note that we've modified the section info */
1752
85
            sinfo_modified = true;
1753
85
        } /* end if */
1754
109
    }     /* end if */
1755
1756
115
done:
1757
    /* Release the section info */
1758
115
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, sinfo_modified) < 0)
1759
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1760
1761
#ifdef H5FS_DEBUG_ASSERT
1762
    H5FS__assert(fspace);
1763
#endif /* H5FS_DEBUG_ASSERT */
1764
115
    FUNC_LEAVE_NOAPI(ret_value)
1765
115
} /* H5FS_sect_find() */
1766
1767
/*-------------------------------------------------------------------------
1768
 * Function:    H5FS__iterate_sect_cb
1769
 *
1770
 * Purpose:     Skip list iterator callback to iterate over free space sections
1771
 *              of a particular size
1772
 *
1773
 * Return:      SUCCEED/FAIL
1774
 *
1775
 *-------------------------------------------------------------------------
1776
 */
1777
static herr_t
1778
H5FS__iterate_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
1779
0
{
1780
0
    H5FS_section_info_t *sect_info = (H5FS_section_info_t *)_item; /* Free space section to work on */
1781
0
    H5FS_iter_ud_t      *udata     = (H5FS_iter_ud_t *)_udata;     /* Callback info */
1782
0
    herr_t               ret_value = SUCCEED;                      /* Return value */
1783
1784
0
    FUNC_ENTER_PACKAGE
1785
1786
    /* Check arguments. */
1787
0
    assert(sect_info);
1788
0
    assert(udata->fspace);
1789
0
    assert(udata->op);
1790
1791
    /* Make callback for this section */
1792
0
    if ((*udata->op)(sect_info, udata->op_data) < 0)
1793
0
        HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "iteration callback failed");
1794
1795
0
done:
1796
0
    FUNC_LEAVE_NOAPI(ret_value)
1797
0
} /* H5FS__iterate_sect_cb() */
1798
1799
/*-------------------------------------------------------------------------
1800
 * Function:    H5FS__iterate_node_cb
1801
 *
1802
 * Purpose:     Skip list iterator callback to iterate over free space sections
1803
 *              in a bin
1804
 *
1805
 * Return:      SUCCEED/FAIL
1806
 *
1807
 *-------------------------------------------------------------------------
1808
 */
1809
static herr_t
1810
H5FS__iterate_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
1811
0
{
1812
0
    H5FS_node_t    *fspace_node = (H5FS_node_t *)_item;     /* Free space size node to work on */
1813
0
    H5FS_iter_ud_t *udata       = (H5FS_iter_ud_t *)_udata; /* Callback info */
1814
0
    herr_t          ret_value   = SUCCEED;                  /* Return value */
1815
1816
0
    FUNC_ENTER_PACKAGE
1817
1818
    /* Check arguments. */
1819
0
    assert(fspace_node);
1820
0
    assert(udata->fspace);
1821
0
    assert(udata->op);
1822
1823
    /* Iterate through all the sections of this size */
1824
0
    assert(fspace_node->sect_list);
1825
0
    if (H5SL_iterate(fspace_node->sect_list, H5FS__iterate_sect_cb, udata) < 0)
1826
0
        HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section nodes");
1827
1828
0
done:
1829
0
    FUNC_LEAVE_NOAPI(ret_value)
1830
0
} /* H5FS__iterate_node_cb() */
1831
1832
/*-------------------------------------------------------------------------
1833
 * Function:    H5FS_sect_iterate
1834
 *
1835
 * Purpose:     Iterate over all the sections managed
1836
 *
1837
 * Return:      SUCCEED/FAIL
1838
 *
1839
 *-------------------------------------------------------------------------
1840
 */
1841
herr_t
1842
H5FS_sect_iterate(H5F_t *f, H5FS_t *fspace, H5FS_operator_t op, void *op_data)
1843
0
{
1844
0
    H5FS_iter_ud_t udata;                 /* User data for callbacks */
1845
0
    bool           sinfo_valid = false;   /* Whether the section info is valid */
1846
0
    herr_t         ret_value   = SUCCEED; /* Return value */
1847
1848
0
    FUNC_ENTER_NOAPI_NOINIT
1849
1850
    /* Check arguments. */
1851
0
    assert(fspace);
1852
0
    assert(op);
1853
1854
    /* Set up user data for iterator */
1855
0
    udata.fspace  = fspace;
1856
0
    udata.op      = op;
1857
0
    udata.op_data = op_data;
1858
1859
    /* Iterate over sections, if there are any */
1860
0
    if (fspace->tot_sect_count) {
1861
0
        unsigned bin; /* Current bin we are on */
1862
1863
        /* Get a pointer to the section info */
1864
0
        if (H5FS__sinfo_lock(f, fspace, H5AC__READ_ONLY_FLAG) < 0)
1865
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1866
0
        sinfo_valid = true;
1867
1868
        /* Iterate over all the bins */
1869
0
        for (bin = 0; bin < fspace->sinfo->nbins; bin++) {
1870
            /* Check if there are any sections in this bin */
1871
0
            if (fspace->sinfo->bins[bin].bin_list) {
1872
                /* Iterate over list of section size nodes for bin */
1873
0
                if (H5SL_iterate(fspace->sinfo->bins[bin].bin_list, H5FS__iterate_node_cb, &udata) < 0)
1874
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section size nodes");
1875
0
            } /* end if */
1876
0
        }     /* end for */
1877
0
    }         /* end if */
1878
1879
0
done:
1880
    /* Release the section info */
1881
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, false) < 0)
1882
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
1883
1884
0
    FUNC_LEAVE_NOAPI(ret_value)
1885
0
} /* H5FS_sect_iterate() */
1886
1887
/*-------------------------------------------------------------------------
1888
 * Function:    H5FS_sect_stats
1889
 *
1890
 * Purpose:     Retrieve info about the sections managed
1891
 *
1892
 * Return:      SUCCEED/FAIL
1893
 *
1894
 *-------------------------------------------------------------------------
1895
 */
1896
herr_t
1897
H5FS_sect_stats(const H5FS_t *fspace, hsize_t *tot_space, hsize_t *nsects)
1898
0
{
1899
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1900
1901
    /* Check arguments. */
1902
0
    assert(fspace);
1903
1904
    /* Get the stats desired */
1905
0
    if (tot_space)
1906
0
        *tot_space = fspace->tot_space;
1907
0
    if (nsects)
1908
0
        *nsects = fspace->tot_sect_count;
1909
1910
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1911
0
} /* H5FS_sect_stats() */
1912
1913
/*-------------------------------------------------------------------------
1914
 * Function:    H5FS_sect_change_class
1915
 *
1916
 * Purpose:     Make appropriate adjustments to internal data structures when
1917
 *              a section changes class
1918
 *
1919
 * Return:      SUCCEED/FAIL
1920
 *
1921
 *-------------------------------------------------------------------------
1922
 */
1923
herr_t
1924
H5FS_sect_change_class(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, uint16_t new_class)
1925
0
{
1926
0
    const H5FS_section_class_t *old_cls;               /* Old class of section */
1927
0
    const H5FS_section_class_t *new_cls;               /* New class of section */
1928
0
    unsigned                    old_class;             /* Old class ID of section */
1929
0
    bool                        sinfo_valid = false;   /* Whether the section info is valid */
1930
0
    herr_t                      ret_value   = SUCCEED; /* Return value */
1931
1932
0
    FUNC_ENTER_NOAPI_NOINIT
1933
1934
    /* Check arguments. */
1935
0
    assert(fspace);
1936
0
    assert(sect);
1937
0
    assert(sect->type < fspace->nclasses);
1938
0
    assert(new_class < fspace->nclasses);
1939
1940
    /* Get a pointer to the section info */
1941
0
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
1942
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
1943
0
    sinfo_valid = true;
1944
1945
    /* Get class info */
1946
0
    old_class = sect->type;
1947
0
    old_cls   = &fspace->sect_cls[sect->type];
1948
0
    new_cls   = &fspace->sect_cls[new_class];
1949
1950
    /* Check if the section's class change will affect the # of serializable or ghost sections */
1951
0
    if ((old_cls->flags & H5FS_CLS_GHOST_OBJ) != (new_cls->flags & H5FS_CLS_GHOST_OBJ)) {
1952
0
        H5FS_node_t *fspace_node; /* Free list size node */
1953
0
        unsigned     bin;         /* Bin to put the free space section in */
1954
0
        bool         to_ghost;    /* Flag if the section is changing to a ghost section */
1955
1956
        /* Determine if this section is becoming a ghost or is becoming serializable */
1957
0
        if (old_cls->flags & H5FS_CLS_GHOST_OBJ)
1958
0
            to_ghost = false;
1959
0
        else
1960
0
            to_ghost = true;
1961
1962
        /* Sanity check */
1963
0
        assert(fspace->sinfo->bins);
1964
1965
        /* Determine correct bin which holds items of at least the section's size */
1966
0
        bin = H5VM_log2_gen(sect->size);
1967
0
        assert(bin < fspace->sinfo->nbins);
1968
0
        assert(fspace->sinfo->bins[bin].bin_list);
1969
1970
        /* Get space node for section's size */
1971
0
        fspace_node = (H5FS_node_t *)H5SL_search(fspace->sinfo->bins[bin].bin_list, &sect->size);
1972
0
        assert(fspace_node);
1973
1974
        /* Adjust serializable/ghost counts */
1975
0
        if (to_ghost) {
1976
            /* Adjust global section count totals */
1977
0
            fspace->serial_sect_count--;
1978
0
            fspace->ghost_sect_count++;
1979
1980
            /* Adjust bin's section count totals */
1981
0
            fspace->sinfo->bins[bin].serial_sect_count--;
1982
0
            fspace->sinfo->bins[bin].ghost_sect_count++;
1983
1984
            /* Adjust section size node's section count totals */
1985
0
            fspace_node->serial_count--;
1986
0
            fspace_node->ghost_count++;
1987
1988
            /* Check if we switched a section size node's status */
1989
0
            if (fspace_node->serial_count == 0)
1990
0
                fspace->sinfo->serial_size_count--;
1991
0
            if (fspace_node->ghost_count == 1)
1992
0
                fspace->sinfo->ghost_size_count++;
1993
0
        } /* end if */
1994
0
        else {
1995
            /* Adjust global section count totals */
1996
0
            fspace->serial_sect_count++;
1997
0
            fspace->ghost_sect_count--;
1998
1999
            /* Adjust bin's section count totals */
2000
0
            fspace->sinfo->bins[bin].serial_sect_count++;
2001
0
            fspace->sinfo->bins[bin].ghost_sect_count--;
2002
2003
            /* Adjust section size node's section count totals */
2004
0
            fspace_node->serial_count++;
2005
0
            fspace_node->ghost_count--;
2006
2007
            /* Check if we switched a section size node's status */
2008
0
            if (fspace_node->serial_count == 1)
2009
0
                fspace->sinfo->serial_size_count++;
2010
0
            if (fspace_node->ghost_count == 0)
2011
0
                fspace->sinfo->ghost_size_count--;
2012
0
        } /* end else */
2013
0
    }     /* end if */
2014
2015
    /* Check if the section's class change will affect the mergeable list */
2016
0
    if ((old_cls->flags & H5FS_CLS_SEPAR_OBJ) != (new_cls->flags & H5FS_CLS_SEPAR_OBJ)) {
2017
0
        bool to_mergable; /* Flag if the section is changing to a mergeable section */
2018
2019
        /* Determine if this section is becoming mergeable or is becoming separate */
2020
0
        if (old_cls->flags & H5FS_CLS_SEPAR_OBJ)
2021
0
            to_mergable = true;
2022
0
        else
2023
0
            to_mergable = false;
2024
2025
        /* Add or remove section from merge list, as appropriate */
2026
0
        if (to_mergable) {
2027
0
            if (fspace->sinfo->merge_list == NULL)
2028
0
                if (NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
2029
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL,
2030
0
                                "can't create skip list for merging free space sections");
2031
0
            if (H5SL_insert(fspace->sinfo->merge_list, sect, &sect->addr) < 0)
2032
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL,
2033
0
                            "can't insert free space node into merging skip list");
2034
0
        } /* end if */
2035
0
        else {
2036
0
            H5FS_section_info_t *tmp_sect_node; /* Temporary section node */
2037
2038
0
            tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace->sinfo->merge_list, &sect->addr);
2039
0
            if (tmp_sect_node == NULL || tmp_sect_node != sect)
2040
0
                HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list");
2041
0
        } /* end else */
2042
0
    }     /* end if */
2043
2044
    /* Change the section's class */
2045
0
    sect->type = new_class;
2046
2047
    /* Change the serialized size of sections */
2048
0
    fspace->sinfo->serial_size -= fspace->sect_cls[old_class].serial_size;
2049
0
    fspace->sinfo->serial_size += fspace->sect_cls[new_class].serial_size;
2050
2051
    /* Update current space used for free space sections */
2052
0
    if (H5FS__sect_serialize_size(fspace) < 0)
2053
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk");
2054
2055
0
done:
2056
    /* Release the section info */
2057
0
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, true) < 0)
2058
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
2059
2060
0
    FUNC_LEAVE_NOAPI(ret_value)
2061
0
} /* H5FS_sect_change_class() */
2062
2063
#ifdef H5FS_DEBUG_ASSERT
2064
2065
/*-------------------------------------------------------------------------
2066
 * Function:    H5FS__sect_assert
2067
 *
2068
 * Purpose:     Verify that the sections managed are mostly sane
2069
 *
2070
 * Return:      void
2071
 *
2072
 *-------------------------------------------------------------------------
2073
 */
2074
void
2075
H5FS__sect_assert(const H5FS_t *fspace)
2076
{
2077
    hsize_t separate_obj; /* The number of separate objects managed */
2078
2079
    FUNC_ENTER_PACKAGE_NOERR
2080
2081
    /* Initialize state */
2082
    separate_obj = 0;
2083
2084
    /* Check for bins to work on */
2085
    if (fspace->sinfo->bins) {
2086
        hsize_t  acc_tot_sect_count;    /* Accumulated total section count from bins */
2087
        hsize_t  acc_serial_sect_count; /* Accumulated serializable section count from bins */
2088
        hsize_t  acc_ghost_sect_count;  /* Accumulated ghost section count from bins */
2089
        size_t   acc_tot_size_count;    /* Accumulated total section size count from bins */
2090
        size_t   acc_serial_size_count; /* Accumulated serializable section size count from bins */
2091
        size_t   acc_ghost_size_count;  /* Accumulated ghost section size count from bins */
2092
        unsigned u;                     /* Local index variable */
2093
2094
        /* Walk through all sections in bins */
2095
        acc_tot_sect_count    = 0;
2096
        acc_serial_sect_count = 0;
2097
        acc_ghost_sect_count  = 0;
2098
        acc_tot_size_count    = 0;
2099
        acc_serial_size_count = 0;
2100
        acc_ghost_size_count  = 0;
2101
        for (u = 0; u < fspace->sinfo->nbins; u++) {
2102
            acc_tot_sect_count += fspace->sinfo->bins[u].tot_sect_count;
2103
            acc_serial_sect_count += fspace->sinfo->bins[u].serial_sect_count;
2104
            acc_ghost_sect_count += fspace->sinfo->bins[u].ghost_sect_count;
2105
            if (fspace->sinfo->bins[u].bin_list) {
2106
                H5SL_node_t *curr_size_node;   /* Current section size node in skip list */
2107
                size_t       bin_serial_count; /* # of serializable sections in this bin */
2108
                size_t       bin_ghost_count;  /* # of ghost sections in this bin */
2109
2110
                acc_tot_size_count += H5SL_count(fspace->sinfo->bins[u].bin_list);
2111
2112
                /* Walk through the sections in this bin */
2113
                curr_size_node   = H5SL_first(fspace->sinfo->bins[u].bin_list);
2114
                bin_serial_count = 0;
2115
                bin_ghost_count  = 0;
2116
                while (curr_size_node != NULL) {
2117
                    H5FS_node_t *fspace_node;       /* Section size node */
2118
                    H5SL_node_t *curr_sect_node;    /* Current section node in skip list */
2119
                    size_t       size_serial_count; /* # of serializable sections of this size */
2120
                    size_t       size_ghost_count;  /* # of ghost sections of this size */
2121
2122
                    /* Get section size node */
2123
                    fspace_node = (H5FS_node_t *)H5SL_item(curr_size_node);
2124
2125
                    /* Check sections on list */
2126
                    curr_sect_node    = H5SL_first(fspace_node->sect_list);
2127
                    size_serial_count = 0;
2128
                    size_ghost_count  = 0;
2129
                    while (curr_sect_node != NULL) {
2130
                        H5FS_section_class_t *cls;  /* Class of section */
2131
                        H5FS_section_info_t  *sect; /* Section */
2132
2133
                        /* Get section node & it's class */
2134
                        sect = (H5FS_section_info_t *)H5SL_item(curr_sect_node);
2135
                        cls  = &fspace->sect_cls[sect->type];
2136
2137
                        /* Sanity check section */
2138
                        assert(H5_addr_defined(sect->addr));
2139
                        assert(fspace_node->sect_size == sect->size);
2140
                        if (cls->valid)
2141
                            (*cls->valid)(cls, sect);
2142
2143
                        /* Add to correct count */
2144
                        if (cls->flags & H5FS_CLS_GHOST_OBJ)
2145
                            size_ghost_count++;
2146
                        else
2147
                            size_serial_count++;
2148
2149
                        /* Count node, if separate */
2150
                        if (cls->flags & H5FS_CLS_SEPAR_OBJ)
2151
                            separate_obj++;
2152
2153
                        /* Get the next section node in the list */
2154
                        curr_sect_node = H5SL_next(curr_sect_node);
2155
                    } /* end while */
2156
2157
                    /* Check the number of serializable & ghost sections of this size */
2158
                    assert(fspace_node->serial_count == size_serial_count);
2159
                    assert(fspace_node->ghost_count == size_ghost_count);
2160
2161
                    /* Add to global count of serializable & ghost section sizes */
2162
                    if (fspace_node->serial_count > 0)
2163
                        acc_serial_size_count++;
2164
                    if (fspace_node->ghost_count > 0)
2165
                        acc_ghost_size_count++;
2166
2167
                    /* Add to bin's serializable & ghost counts */
2168
                    bin_serial_count += size_serial_count;
2169
                    bin_ghost_count += size_ghost_count;
2170
2171
                    /* Get the next section size node in the list */
2172
                    curr_size_node = H5SL_next(curr_size_node);
2173
                } /* end while */
2174
2175
                /* Check the number of serializable & ghost sections in this bin */
2176
                assert(fspace->sinfo->bins[u].tot_sect_count == (bin_serial_count + bin_ghost_count));
2177
                assert(fspace->sinfo->bins[u].serial_sect_count == bin_serial_count);
2178
                assert(fspace->sinfo->bins[u].ghost_sect_count == bin_ghost_count);
2179
            } /* end if */
2180
        }     /* end for */
2181
2182
        /* Check counts from bins vs. global counts */
2183
        assert(fspace->sinfo->tot_size_count == acc_tot_size_count);
2184
        assert(fspace->sinfo->serial_size_count == acc_serial_size_count);
2185
        assert(fspace->sinfo->ghost_size_count == acc_ghost_size_count);
2186
        assert(fspace->tot_sect_count == acc_tot_sect_count);
2187
        assert(fspace->serial_sect_count == acc_serial_sect_count);
2188
        assert(fspace->ghost_sect_count == acc_ghost_sect_count);
2189
    } /* end if */
2190
    else {
2191
        /* Check counts are zero */
2192
        assert(fspace->tot_sect_count == 0);
2193
        assert(fspace->serial_sect_count == 0);
2194
        assert(fspace->ghost_sect_count == 0);
2195
    } /* end else */
2196
2197
    /* Make certain that the number of sections on the address list is correct */
2198
    if (fspace->sinfo->merge_list)
2199
        assert(fspace->tot_sect_count == (separate_obj + H5SL_count(fspace->sinfo->merge_list)));
2200
2201
    FUNC_LEAVE_NOAPI_VOID
2202
} /* end H5FS__sect_assert() */
2203
#endif /* H5FS_DEBUG_ASSERT */
2204
2205
/*-------------------------------------------------------------------------
2206
 * Function:    H5FS_sect_try_shrink_eoa
2207
 *
2208
 * Purpose:     To shrink the last section on the merge list if the section
2209
 *              is at EOF.
2210
 *
2211
 * Return:      true/false/FAIL
2212
 *
2213
 *-------------------------------------------------------------------------
2214
 */
2215
htri_t
2216
H5FS_sect_try_shrink_eoa(H5F_t *f, H5FS_t *fspace, void *op_data)
2217
87
{
2218
87
    bool   sinfo_valid     = false; /* Whether the section info is valid */
2219
87
    bool   section_removed = false; /* Whether a section was removed */
2220
87
    htri_t ret_value       = false; /* Return value */
2221
2222
87
    FUNC_ENTER_NOAPI(FAIL)
2223
2224
    /* Check arguments. */
2225
87
    assert(fspace);
2226
2227
87
    if (H5FS__sinfo_lock(f, fspace, H5AC__NO_FLAGS_SET) < 0)
2228
2
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info");
2229
85
    sinfo_valid = true;
2230
2231
85
    if (fspace->sinfo && fspace->sinfo->merge_list) {
2232
85
        H5SL_node_t *last_node; /* Last node in merge list */
2233
2234
        /* Check for last node in the merge list */
2235
85
        if (NULL != (last_node = H5SL_last(fspace->sinfo->merge_list))) {
2236
85
            H5FS_section_info_t  *tmp_sect;     /* Temporary free space section */
2237
85
            H5FS_section_class_t *tmp_sect_cls; /* Temporary section's class */
2238
2239
            /* Get the pointer to the last section, from the last node */
2240
85
            tmp_sect = (H5FS_section_info_t *)H5SL_item(last_node);
2241
85
            assert(tmp_sect);
2242
85
            tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
2243
85
            if (tmp_sect_cls->can_shrink) {
2244
                /* Check if the section can be shrunk away */
2245
50
                if ((ret_value = (*tmp_sect_cls->can_shrink)(tmp_sect, op_data)) < 0)
2246
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking container");
2247
50
                if (ret_value > 0) {
2248
0
                    assert(tmp_sect_cls->shrink);
2249
2250
                    /* Remove section from free space manager */
2251
0
                    if (H5FS__sect_remove_real(fspace, tmp_sect) < 0)
2252
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL,
2253
0
                                    "can't remove section from internal data structures");
2254
0
                    section_removed = true;
2255
2256
                    /* Shrink away section */
2257
0
                    if ((*tmp_sect_cls->shrink)(&tmp_sect, op_data) < 0)
2258
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't shrink free space container");
2259
0
                } /* end if */
2260
50
            }     /* end if */
2261
85
        }         /* end if */
2262
85
    }             /* end if */
2263
2264
87
done:
2265
    /* Release the section info */
2266
87
    if (sinfo_valid && H5FS__sinfo_unlock(f, fspace, section_removed) < 0)
2267
0
        HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info");
2268
2269
87
    FUNC_LEAVE_NOAPI(ret_value)
2270
87
} /* H5FS_sect_try_shrink_eoa() */
2271
2272
/*-------------------------------------------------------------------------
2273
 * Function:    H5FS_vfd_alloc_hdr_and_section_info_if_needed
2274
 *
2275
 * Purpose:     The purpose of this function is to allocate file space for
2276
 *              the header and section info of the target free space manager
2277
 *              if they are not allocated yet.
2278
 *
2279
 *              The previous hack in this routine to avoid the potential infinite
2280
 *              loops by allocating file space directly from the end of the file
2281
 *              is removed.  The allocation can now be done via the usual
2282
 *              file space allocation call H5MF_alloc().
2283
 *
2284
 *              The design flaw is addressed by not allowing the size
2285
 *              of section info to shrink.  This means, when trying to allocate
2286
 *              section info size X via H5MF_alloc() and the section info size
2287
 *              after H5MF_alloc() changes to Y:
2288
 *              --if Y is larger than X, free the just allocated file space X
2289
 *                via H5MF_xfree() and set fspace->sect_size to Y.
2290
 *                This routine will be called again later from
2291
 *                H5MF_settle_meta_data_fsm() to allocate section info with the
2292
 *                larger fpsace->sect_size Y.
2293
 *              --if Y is smaller than X, no further allocation is needed and
2294
 *                fspace->sect_size and fspace->alloc_sect_size are set to X.
2295
 *                This means fspace->sect_size may be larger than what is
2296
 *                actually needed.
2297
 *
2298
 *              This routine also re-inserts the header and section info in the
2299
 *              metadata cache with this allocation.
2300
 *
2301
 * Return:      Success:        non-negative
2302
 *              Failure:        negative
2303
 *
2304
 *-------------------------------------------------------------------------
2305
 */
2306
herr_t
2307
H5FS_vfd_alloc_hdr_and_section_info_if_needed(H5F_t *f, H5FS_t *fspace, haddr_t *fs_addr_ptr)
2308
61
{
2309
61
    hsize_t hdr_alloc_size;
2310
61
    hsize_t sinfo_alloc_size;
2311
61
    haddr_t sect_addr = HADDR_UNDEF; /* address of sinfo */
2312
61
    haddr_t eoa       = HADDR_UNDEF; /* Initial EOA for the file */
2313
61
    herr_t  ret_value = SUCCEED;     /* Return value */
2314
2315
61
    FUNC_ENTER_NOAPI_NOINIT
2316
2317
    /* Check arguments. */
2318
61
    assert(f);
2319
61
    assert(f->shared);
2320
61
    assert(f->shared->lf);
2321
61
    assert(fspace);
2322
61
    assert(fs_addr_ptr);
2323
2324
    /* the section info should be unlocked */
2325
61
    assert(fspace->sinfo_lock_count == 0);
2326
2327
    /* persistent free space managers must be enabled */
2328
61
    assert(f->shared->fs_persist);
2329
2330
    /* At present, all free space strategies enable the free space managers.
2331
     * This will probably change -- at which point this assertion should
2332
     * be revisited.
2333
     */
2334
    /* Updated: Only the following two strategies enable the free-space managers */
2335
61
    assert((f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR) ||
2336
61
           (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE));
2337
2338
61
    if (fspace->serial_sect_count > 0 && fspace->sinfo) {
2339
        /* the section info is floating, so space->sinfo should be defined */
2340
2341
52
        if (!H5_addr_defined(fspace->addr)) {
2342
2343
            /* start by allocating file space for the header */
2344
2345
            /* Get the EOA for the file -- need for sanity check below */
2346
29
            if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_FSPACE_HDR)))
2347
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa");
2348
2349
            /* check for overlap into temporary allocation space */
2350
29
            if (H5F_IS_TMP_ADDR(f, (eoa + fspace->sect_size)))
2351
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL,
2352
29
                            "hdr file space alloc will overlap into 'temporary' file space");
2353
2354
29
            hdr_alloc_size = H5FS_HEADER_SIZE(f);
2355
2356
29
            if (H5F_PAGED_AGGR(f))
2357
25
                assert(0 == (eoa % f->shared->fs_page_size));
2358
2359
            /* Allocate space for the free space header */
2360
29
            if (HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, hdr_alloc_size)))
2361
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for free space header");
2362
2363
            /* Cache the new free space header (pinned) */
2364
29
            if (H5AC_insert_entry(f, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
2365
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space header to cache");
2366
2367
29
            *fs_addr_ptr = fspace->addr;
2368
29
        }
2369
2370
52
        if (!H5_addr_defined(fspace->sect_addr)) {
2371
2372
            /* now allocate file space for the section info */
2373
2374
            /* Get the EOA for the file -- need for sanity check below */
2375
52
            if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_FSPACE_SINFO)))
2376
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "Unable to get eoa");
2377
2378
            /* check for overlap into temporary allocation space */
2379
52
            if (H5F_IS_TMP_ADDR(f, (eoa + fspace->sect_size)))
2380
0
                HGOTO_ERROR(H5E_FSPACE, H5E_BADRANGE, FAIL,
2381
52
                            "sinfo file space alloc will overlap into 'temporary' file space");
2382
2383
52
            sinfo_alloc_size = fspace->sect_size;
2384
2385
52
            if (H5F_PAGED_AGGR(f))
2386
48
                assert(0 == (eoa % f->shared->fs_page_size));
2387
2388
            /* allocate space for the section info */
2389
52
            if (HADDR_UNDEF == (sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, sinfo_alloc_size)))
2390
0
                HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for section info");
2391
2392
            /* update fspace->alloc_sect_size and fspace->sect_addr to reflect
2393
             * the allocation
2394
             */
2395
52
            if (fspace->sect_size > sinfo_alloc_size) {
2396
21
                hsize_t saved_sect_size = fspace->sect_size;
2397
2398
21
                if (H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, sect_addr, sinfo_alloc_size) < 0)
2399
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections");
2400
21
                fspace->sect_size = saved_sect_size;
2401
21
            }
2402
31
            else {
2403
31
                fspace->alloc_sect_size = sinfo_alloc_size;
2404
31
                fspace->sect_size       = sinfo_alloc_size;
2405
31
                fspace->sect_addr       = sect_addr;
2406
2407
                /* insert the new section info into the metadata cache.  */
2408
2409
                /* Question: Do we need to worry about this insertion causing an
2410
                 * eviction from the metadata cache?  Think on this.  If so, add a
2411
                 * flag to H5AC_insert() to force it to skip the call to make space in
2412
                 * cache.
2413
                 *
2414
                 * On reflection, no.
2415
                 *
2416
                 * On a regular file close, any eviction will not change the
2417
                 * the contents of the free space manager(s), as all entries
2418
                 * should have correct file space allocated by the time this
2419
                 * function is called.
2420
                 *
2421
                 * In the cache image case, the selection of entries for inclusion
2422
                 * in the cache image will not take place until after this call.
2423
                 * (Recall that this call is made during the metadata fsm settle
2424
                 * routine, which is called during the serialization routine in
2425
                 * the cache image case.  Entries are not selected for inclusion
2426
                 * in the image until after the cache is serialized.)
2427
                 *
2428
                 *                                        JRM -- 11/4/16
2429
                 */
2430
31
                if (H5AC_insert_entry(f, H5AC_FSPACE_SINFO, sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
2431
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sinfo to cache");
2432
2433
                /* We have changed the sinfo address -- Mark free space header dirty */
2434
31
                if (H5AC_mark_entry_dirty(fspace) < 0)
2435
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL,
2436
31
                                "unable to mark free space header as dirty");
2437
2438
                /* since space has been allocated for the section info and the sinfo
2439
                 * has been inserted into the cache, relinquish ownership (i.e. float)
2440
                 * the section info.
2441
                 */
2442
31
                fspace->sinfo = NULL;
2443
31
            }
2444
52
        }
2445
52
    } /* end if */
2446
2447
61
done:
2448
61
    FUNC_LEAVE_NOAPI(ret_value)
2449
61
} /* H5FS_vfd_alloc_hdr_and_section_info_if_needed() */