Coverage Report

Created: 2024-06-18 06:29

/src/hdf5/src/H5HFspace.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 COPYING 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
 *
15
 * Created:   H5HFspace.c
16
 *
17
 * Purpose:   Space allocation routines for fractal heaps.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"  /* Generic Functions      */
32
#include "H5Eprivate.h" /* Error handling       */
33
#include "H5HFpkg.h"    /* Fractal heaps      */
34
35
/****************/
36
/* Local Macros */
37
/****************/
38
39
0
#define H5HF_FSPACE_SHRINK    80  /* Percent of "normal" size to shrink serialized free space size */
40
0
#define H5HF_FSPACE_EXPAND    120 /* Percent of "normal" size to expand serialized free space size */
41
0
#define H5HF_FSPACE_THRHD_DEF 1   /* Default: no alignment threshold */
42
0
#define H5HF_FSPACE_ALIGN_DEF 1   /* Default: no alignment */
43
44
/******************/
45
/* Local Typedefs */
46
/******************/
47
48
/********************/
49
/* Package Typedefs */
50
/********************/
51
52
/********************/
53
/* Local Prototypes */
54
/********************/
55
56
/*********************/
57
/* Package Variables */
58
/*********************/
59
60
/*****************************/
61
/* Library Private Variables */
62
/*****************************/
63
64
/*******************/
65
/* Local Variables */
66
/*******************/
67
68
/*-------------------------------------------------------------------------
69
 * Function:  H5HF__space_start
70
 *
71
 * Purpose: "Start up" free space for heap - open existing free space
72
 *              structure if one exists, otherwise create a new free space
73
 *              structure
74
 *
75
 * Return:  Success:  non-negative
76
 *
77
 *    Failure:  negative
78
 *
79
 *-------------------------------------------------------------------------
80
 */
81
herr_t
82
H5HF__space_start(H5HF_hdr_t *hdr, bool may_create)
83
0
{
84
0
    const H5FS_section_class_t *classes[] = {/* Free space section classes implemented for fractal heap */
85
0
                                             H5HF_FSPACE_SECT_CLS_SINGLE, H5HF_FSPACE_SECT_CLS_FIRST_ROW,
86
0
                                             H5HF_FSPACE_SECT_CLS_NORMAL_ROW, H5HF_FSPACE_SECT_CLS_INDIRECT};
87
0
    herr_t                      ret_value = SUCCEED; /* Return value */
88
89
0
    FUNC_ENTER_PACKAGE
90
91
    /*
92
     * Check arguments.
93
     */
94
0
    assert(hdr);
95
96
    /* Check for creating free space info for the heap */
97
0
    if (H5_addr_defined(hdr->fs_addr)) {
98
        /* Open an existing free space structure for the heap */
99
0
        if (NULL == (hdr->fspace = H5FS_open(hdr->f, hdr->fs_addr, NELMTS(classes), classes, hdr,
100
0
                                             (hsize_t)H5HF_FSPACE_THRHD_DEF, (hsize_t)H5HF_FSPACE_ALIGN_DEF)))
101
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info");
102
0
    } /* end if */
103
0
    else {
104
        /* Check if we are allowed to create the free space manager */
105
0
        if (may_create) {
106
0
            H5FS_create_t fs_create; /* Free space creation parameters */
107
108
            /* Set the free space creation parameters */
109
0
            fs_create.client         = H5FS_CLIENT_FHEAP_ID;
110
0
            fs_create.shrink_percent = H5HF_FSPACE_SHRINK;
111
0
            fs_create.expand_percent = H5HF_FSPACE_EXPAND;
112
0
            fs_create.max_sect_size  = hdr->man_dtable.cparam.max_direct_size;
113
0
            fs_create.max_sect_addr  = hdr->man_dtable.cparam.max_index;
114
115
            /* Create the free space structure for the heap */
116
0
            if (NULL ==
117
0
                (hdr->fspace = H5FS_create(hdr->f, &hdr->fs_addr, &fs_create, NELMTS(classes), classes, hdr,
118
0
                                           (hsize_t)H5HF_FSPACE_THRHD_DEF, (hsize_t)H5HF_FSPACE_ALIGN_DEF)))
119
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info");
120
0
            assert(H5_addr_defined(hdr->fs_addr));
121
0
        } /* end if */
122
0
    }     /* end else */
123
124
0
done:
125
0
    FUNC_LEAVE_NOAPI(ret_value)
126
0
} /* end H5HF__space_start() */
127
128
/*-------------------------------------------------------------------------
129
 * Function:  H5HF__space_add
130
 *
131
 * Purpose: Add a section to the free space for the heap
132
 *
133
 * Return:  Success:  non-negative
134
 *
135
 *    Failure:  negative
136
 *
137
 *-------------------------------------------------------------------------
138
 */
139
herr_t
140
H5HF__space_add(H5HF_hdr_t *hdr, H5HF_free_section_t *node, unsigned flags)
141
0
{
142
0
    H5HF_sect_add_ud_t udata;               /* User data for free space manager 'add' */
143
0
    herr_t             ret_value = SUCCEED; /* Return value */
144
145
0
    FUNC_ENTER_PACKAGE
146
147
    /*
148
     * Check arguments.
149
     */
150
0
    assert(hdr);
151
0
    assert(node);
152
153
    /* Check if the free space for the heap has been initialized */
154
0
    if (!hdr->fspace)
155
0
        if (H5HF__space_start(hdr, true) < 0)
156
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space");
157
158
    /* Construct user data */
159
0
    udata.hdr = hdr;
160
161
    /* Add to the free space for the heap */
162
0
    if (H5FS_sect_add(hdr->f, hdr->fspace, (H5FS_section_info_t *)node, flags, &udata) < 0)
163
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't add section to heap free space");
164
165
0
done:
166
0
    FUNC_LEAVE_NOAPI(ret_value)
167
0
} /* end H5HF__space_add() */
168
169
/*-------------------------------------------------------------------------
170
 * Function:  H5HF__space_find
171
 *
172
 * Purpose: Attempt to find space in a fractal heap
173
 *
174
 * Return:  Success:  non-negative
175
 *    Failure:  negative
176
 *
177
 *-------------------------------------------------------------------------
178
 */
179
htri_t
180
H5HF__space_find(H5HF_hdr_t *hdr, hsize_t request, H5HF_free_section_t **node)
181
0
{
182
0
    htri_t node_found = false; /* Whether an existing free list node was found */
183
0
    htri_t ret_value  = FAIL;  /* Return value */
184
185
0
    FUNC_ENTER_PACKAGE
186
187
    /*
188
     * Check arguments.
189
     */
190
0
    assert(hdr);
191
0
    assert(request);
192
0
    assert(node);
193
194
    /* Check if the free space for the heap has been initialized */
195
0
    if (!hdr->fspace)
196
0
        if (H5HF__space_start(hdr, false) < 0)
197
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space");
198
199
    /* Search for free space in the heap */
200
0
    if (hdr->fspace)
201
0
        if ((node_found = H5FS_sect_find(hdr->f, hdr->fspace, request, (H5FS_section_info_t **)node)) < 0)
202
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't locate free space in fractal heap");
203
204
    /* Set return value */
205
0
    ret_value = node_found;
206
207
0
done:
208
0
    FUNC_LEAVE_NOAPI(ret_value)
209
0
} /* end H5HF__space_find() */
210
211
/*-------------------------------------------------------------------------
212
 * Function:  H5HF__space_revert_root_cb
213
 *
214
 * Purpose: Callback routine from iterator, to reset 'parent' pointers in
215
 *    sections, when the heap is changing from having a root indirect
216
 *    block to a direct block.
217
 *
218
 * Return:  Success:  non-negative
219
 *    Failure:  negative
220
 *
221
 *-------------------------------------------------------------------------
222
 */
223
static herr_t
224
H5HF__space_revert_root_cb(H5FS_section_info_t *_sect, void H5_ATTR_UNUSED *_udata)
225
0
{
226
0
    H5HF_free_section_t *sect      = (H5HF_free_section_t *)_sect; /* Section to dump info */
227
0
    herr_t               ret_value = SUCCEED;                      /* Return value */
228
229
0
    FUNC_ENTER_PACKAGE
230
231
    /*
232
     * Check arguments.
233
     */
234
0
    assert(sect);
235
236
    /* Only modify "live" single blocks... */
237
0
    if (sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE && sect->sect_info.state == H5FS_SECT_LIVE) {
238
        /* Release hold on previous indirect block (we must have one) */
239
0
        assert(sect->u.single.parent);
240
0
        if (H5HF__iblock_decr(sect->u.single.parent) < 0)
241
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL,
242
0
                        "can't decrement reference count on section's indirect block");
243
244
        /* Reset parent information */
245
0
        sect->u.single.parent    = NULL;
246
0
        sect->u.single.par_entry = 0;
247
0
    } /* end if */
248
249
0
done:
250
0
    FUNC_LEAVE_NOAPI(ret_value)
251
0
} /* end H5HF__space_revert_root_cb() */
252
253
/*-------------------------------------------------------------------------
254
 * Function:  H5HF__space_revert_root
255
 *
256
 * Purpose: Reset 'parent' pointers in sections, when the heap is
257
 *    changing from having a root indirect block to a direct block.
258
 *
259
 * Return:  Success:  non-negative
260
 *    Failure:  negative
261
 *
262
 *-------------------------------------------------------------------------
263
 */
264
herr_t
265
H5HF__space_revert_root(const H5HF_hdr_t *hdr)
266
0
{
267
0
    herr_t ret_value = SUCCEED; /* Return value */
268
269
0
    FUNC_ENTER_PACKAGE
270
271
    /*
272
     * Check arguments.
273
     */
274
0
    assert(hdr);
275
276
    /* Only need to scan the sections if the free space has been initialized */
277
0
    if (hdr->fspace)
278
        /* Iterate over all sections, resetting the parent pointers in 'single' sections */
279
0
        if (H5FS_sect_iterate(hdr->f, hdr->fspace, H5HF__space_revert_root_cb, NULL) < 0)
280
0
            HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL,
281
0
                        "can't iterate over sections to reset parent pointers");
282
283
0
done:
284
0
    FUNC_LEAVE_NOAPI(ret_value)
285
0
} /* end H5HF__space_revert_root() */
286
287
/*-------------------------------------------------------------------------
288
 * Function:  H5HF__space_create_root_cb
289
 *
290
 * Purpose: Callback routine from iterator, to set 'parent' pointers in
291
 *    sections to newly created root indirect block, when the heap
292
 *    is changing from having a root direct block to an indirect block.
293
 *
294
 * Return:  Success:  non-negative
295
 *    Failure:  negative
296
 *
297
 *-------------------------------------------------------------------------
298
 */
299
static herr_t
300
H5HF__space_create_root_cb(H5FS_section_info_t *_sect, void *_udata)
301
0
{
302
0
    H5HF_free_section_t *sect        = (H5HF_free_section_t *)_sect; /* Section to dump info */
303
0
    H5HF_indirect_t     *root_iblock = (H5HF_indirect_t *)_udata;    /* User data for callback */
304
0
    herr_t               ret_value   = SUCCEED;                      /* Return value */
305
306
0
    FUNC_ENTER_PACKAGE
307
308
    /*
309
     * Check arguments.
310
     */
311
0
    assert(sect);
312
0
    assert(root_iblock);
313
314
    /* Sanity check sections */
315
    /* (If we are switching from a direct block for the root block of the heap, */
316
    /*  there should only be 'single' type sections. -QAK) */
317
0
    assert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
318
319
    /* Increment ref. count on new root indirect block */
320
0
    if (H5HF__iblock_incr(root_iblock) < 0)
321
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL,
322
0
                    "can't increment reference count on section's indirect block");
323
324
    /* Set parent info ("live" section must _NOT_ have a parent right now) */
325
0
    if (sect->sect_info.state == H5FS_SECT_SERIALIZED)
326
0
        sect->sect_info.state = H5FS_SECT_LIVE; /* Mark "live" now */
327
0
    else
328
0
        assert(!sect->u.single.parent);
329
0
    sect->u.single.parent    = root_iblock;
330
0
    sect->u.single.par_entry = 0;
331
332
0
done:
333
0
    FUNC_LEAVE_NOAPI(ret_value)
334
0
} /* end H5HF__space_create_root_cb() */
335
336
/*-------------------------------------------------------------------------
337
 * Function:  H5HF__space_create_root
338
 *
339
 * Purpose: Set 'parent' pointers in sections to new indirect block, when
340
 *    the heap is changing from having a root direct block to a
341
 *    indirect block.
342
 *
343
 * Return:  Success:  non-negative
344
 *    Failure:  negative
345
 *
346
 *-------------------------------------------------------------------------
347
 */
348
herr_t
349
H5HF__space_create_root(const H5HF_hdr_t *hdr, H5HF_indirect_t *root_iblock)
350
0
{
351
0
    herr_t ret_value = SUCCEED; /* Return value */
352
353
0
    FUNC_ENTER_PACKAGE
354
355
    /*
356
     * Check arguments.
357
     */
358
0
    assert(hdr);
359
0
    assert(root_iblock);
360
361
    /* Only need to scan the sections if the free space has been initialized */
362
0
    if (hdr->fspace)
363
        /* Iterate over all sections, setting the parent pointers in 'single' sections to the new indirect
364
         * block */
365
0
        if (H5FS_sect_iterate(hdr->f, hdr->fspace, H5HF__space_create_root_cb, root_iblock) < 0)
366
0
            HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over sections to set parent pointers");
367
368
0
done:
369
0
    FUNC_LEAVE_NOAPI(ret_value)
370
0
} /* end H5HF__space_create_root() */
371
372
/*-------------------------------------------------------------------------
373
 * Function:  H5HF__space_size
374
 *
375
 * Purpose: Query the size of the heap's free space info on disk
376
 *
377
 * Return:  Success:  non-negative
378
 *    Failure:  negative
379
 *
380
 *-------------------------------------------------------------------------
381
 */
382
herr_t
383
H5HF__space_size(H5HF_hdr_t *hdr, hsize_t *fs_size)
384
0
{
385
0
    herr_t ret_value = SUCCEED; /* Return value */
386
387
0
    FUNC_ENTER_PACKAGE
388
389
    /*
390
     * Check arguments.
391
     */
392
0
    assert(hdr);
393
0
    assert(fs_size);
394
395
    /* Check if the free space for the heap has been initialized */
396
0
    if (!hdr->fspace)
397
0
        if (H5HF__space_start(hdr, false) < 0)
398
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space");
399
400
    /* Get free space metadata size */
401
0
    if (hdr->fspace) {
402
0
        if (H5FS_size(hdr->fspace, fs_size) < 0)
403
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't retrieve FS meta storage info");
404
0
    } /* end if */
405
0
    else
406
0
        *fs_size = 0;
407
408
0
done:
409
0
    FUNC_LEAVE_NOAPI(ret_value)
410
0
} /* end H5HF__space_size() */
411
412
/*-------------------------------------------------------------------------
413
 * Function:  H5HF__space_remove
414
 *
415
 * Purpose: Remove a section from the free space for the heap
416
 *
417
 * Return:  Success:  non-negative
418
 *    Failure:  negative
419
 *
420
 *-------------------------------------------------------------------------
421
 */
422
herr_t
423
H5HF__space_remove(H5HF_hdr_t *hdr, H5HF_free_section_t *node)
424
0
{
425
0
    herr_t ret_value = SUCCEED; /* Return value */
426
427
0
    FUNC_ENTER_PACKAGE
428
429
    /*
430
     * Check arguments.
431
     */
432
0
    assert(hdr);
433
0
    assert(hdr->fspace);
434
0
    assert(node);
435
436
    /* Remove from the free space for the heap */
437
0
    if (H5FS_sect_remove(hdr->f, hdr->fspace, (H5FS_section_info_t *)node) < 0)
438
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove section from heap free space");
439
440
0
done:
441
0
    FUNC_LEAVE_NOAPI(ret_value)
442
0
} /* end H5HF__space_remove() */
443
444
/*-------------------------------------------------------------------------
445
 * Function:  H5HF__space_close
446
 *
447
 * Purpose: Close the free space for the heap
448
 *
449
 * Return:  Success:  non-negative
450
 *
451
 *    Failure:  negative
452
 *
453
 *-------------------------------------------------------------------------
454
 */
455
herr_t
456
H5HF__space_close(H5HF_hdr_t *hdr)
457
0
{
458
0
    herr_t ret_value = SUCCEED; /* Return value */
459
460
0
    FUNC_ENTER_PACKAGE
461
462
    /*
463
     * Check arguments.
464
     */
465
0
    assert(hdr);
466
467
    /* Check if the free space was ever opened */
468
0
    if (hdr->fspace) {
469
0
        hsize_t nsects; /* Number of sections for this heap */
470
471
        /* Retrieve the number of sections for this heap */
472
0
        if (H5FS_sect_stats(hdr->fspace, NULL, &nsects) < 0)
473
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTCOUNT, FAIL, "can't query free space section count");
474
475
        /* Close the free space for the heap */
476
0
        if (H5FS_close(hdr->f, hdr->fspace) < 0)
477
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info");
478
0
        hdr->fspace = NULL;
479
480
        /* Check if we can delete the free space manager for this heap */
481
0
        if (!nsects) {
482
0
            if (H5FS_delete(hdr->f, hdr->fs_addr) < 0)
483
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "can't delete free space info");
484
0
            hdr->fs_addr = HADDR_UNDEF;
485
0
        } /* end if */
486
0
    }     /* end if */
487
488
0
done:
489
0
    FUNC_LEAVE_NOAPI(ret_value)
490
0
} /* end H5HF__space_close() */
491
492
/*-------------------------------------------------------------------------
493
 * Function:  H5HF__space_delete
494
 *
495
 * Purpose: Delete the free space manager for the heap
496
 *
497
 * Return:  Success:  non-negative
498
 *    Failure:  negative
499
 *
500
 *-------------------------------------------------------------------------
501
 */
502
herr_t
503
H5HF__space_delete(H5HF_hdr_t *hdr)
504
0
{
505
0
    herr_t ret_value = SUCCEED; /* Return value */
506
507
0
    FUNC_ENTER_PACKAGE
508
509
    /*
510
     * Check arguments.
511
     */
512
0
    assert(hdr);
513
514
    /* Delete the free space manager */
515
0
    if (H5FS_delete(hdr->f, hdr->fs_addr) < 0)
516
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "can't delete to free space manager");
517
518
0
done:
519
0
    FUNC_LEAVE_NOAPI(ret_value)
520
0
} /* end H5HF__space_delete() */
521
522
/*-------------------------------------------------------------------------
523
 * Function:  H5HF__space_sect_change_class
524
 *
525
 * Purpose: Change a section's class
526
 *
527
 * Return:  Success:  non-negative
528
 *
529
 *    Failure:  negative
530
 *
531
 *-------------------------------------------------------------------------
532
 */
533
herr_t
534
H5HF__space_sect_change_class(H5HF_hdr_t *hdr, H5HF_free_section_t *sect, uint16_t new_class)
535
0
{
536
0
    herr_t ret_value = SUCCEED; /* Return value */
537
538
0
    FUNC_ENTER_PACKAGE
539
540
    /*
541
     * Check arguments.
542
     */
543
0
    assert(hdr);
544
0
    assert(hdr->fspace);
545
0
    assert(sect);
546
547
    /* Notify the free space manager that a section has changed class */
548
0
    if (H5FS_sect_change_class(hdr->f, hdr->fspace, (H5FS_section_info_t *)sect, new_class) < 0)
549
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, FAIL, "can't modify class of free space section");
550
551
0
done:
552
0
    FUNC_LEAVE_NOAPI(ret_value)
553
0
} /* end H5HF__space_sect_change_class() */