Coverage Report

Created: 2024-06-18 06:29

/src/hdf5/src/H5HFhdr.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:   H5HFhdr.c
16
 *
17
 * Purpose:   Heap header 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 "H5FLprivate.h" /* Free Lists                               */
34
#include "H5HFpkg.h"     /* Fractal heaps     */
35
#include "H5MFprivate.h" /* File memory management    */
36
#include "H5MMprivate.h" /* Memory management     */
37
#include "H5VMprivate.h" /* Vectors and arrays      */
38
39
/****************/
40
/* Local Macros */
41
/****************/
42
43
#ifndef NDEBUG
44
/* Limit on the size of the max. direct block size */
45
/* (This is limited to 32-bits currently, because I think it's unlikely to
46
 *      need to be larger, the 32-bit limit for H5VM_log2_of2(n), and
47
 *      some offsets/sizes are encoded with a maximum of 32-bits  - QAK)
48
 */
49
#define H5HF_MAX_DIRECT_SIZE_LIMIT ((hsize_t)2 * 1024 * 1024 * 1024)
50
51
/* Limit on the width of the doubling table */
52
/* (This is limited to 16-bits currently, because I think it's unlikely to
53
 *      need to be larger, and its encoded with a maximum of 16-bits  - QAK)
54
 */
55
#define H5HF_WIDTH_LIMIT (64 * 1024)
56
#endif /* NDEBUG */
57
58
/******************/
59
/* Local Typedefs */
60
/******************/
61
62
/********************/
63
/* Package Typedefs */
64
/********************/
65
66
/********************/
67
/* Local Prototypes */
68
/********************/
69
70
/*********************/
71
/* Package Variables */
72
/*********************/
73
74
/* Declare a free list to manage the H5HF_hdr_t struct */
75
H5FL_DEFINE_STATIC(H5HF_hdr_t);
76
77
/*****************************/
78
/* Library Private Variables */
79
/*****************************/
80
81
/*******************/
82
/* Local Variables */
83
/*******************/
84
85
/*-------------------------------------------------------------------------
86
 * Function:  H5HF__hdr_alloc
87
 *
88
 * Purpose: Allocate shared fractal heap header
89
 *
90
 * Return:  Non-negative on success/Negative on failure
91
 *
92
 *-------------------------------------------------------------------------
93
 */
94
H5HF_hdr_t *
95
H5HF__hdr_alloc(H5F_t *f)
96
0
{
97
0
    H5HF_hdr_t *hdr       = NULL; /* Shared fractal heap header */
98
0
    H5HF_hdr_t *ret_value = NULL; /* Return value */
99
100
0
    FUNC_ENTER_PACKAGE
101
102
    /*
103
     * Check arguments.
104
     */
105
0
    assert(f);
106
107
    /* Allocate space for the shared information */
108
0
    if (NULL == (hdr = H5FL_CALLOC(H5HF_hdr_t)))
109
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "allocation failed for fractal heap shared header");
110
111
    /* Set the internal parameters for the heap */
112
0
    hdr->f           = f;
113
0
    hdr->sizeof_size = H5F_SIZEOF_SIZE(f);
114
0
    hdr->sizeof_addr = H5F_SIZEOF_ADDR(f);
115
116
    /* Set the return value */
117
0
    ret_value = hdr;
118
119
0
done:
120
0
    FUNC_LEAVE_NOAPI(ret_value)
121
0
} /* end H5HF__hdr_alloc() */
122
123
/*-------------------------------------------------------------------------
124
 * Function:  H5HF_hdr_free_space
125
 *
126
 * Purpose: Compute direct block free space, for indirect blocks of
127
 *              different sizes.
128
 *
129
 * Return:  Non-negative on success/Negative on failure
130
 *
131
 *-------------------------------------------------------------------------
132
 */
133
static herr_t
134
H5HF__hdr_compute_free_space(H5HF_hdr_t *hdr, unsigned iblock_row)
135
0
{
136
0
    hsize_t  acc_heap_size;       /* Accumumated heap space */
137
0
    hsize_t  iblock_size;         /* Size of indirect block to calculate for */
138
0
    hsize_t  acc_dblock_free;     /* Accumumated direct block free space */
139
0
    size_t   max_dblock_free;     /* Max. direct block free space */
140
0
    unsigned curr_row;            /* Current row in block */
141
0
    herr_t   ret_value = SUCCEED; /* Return value */
142
143
0
    FUNC_ENTER_PACKAGE_NOERR
144
145
    /*
146
     * Check arguments.
147
     */
148
0
    assert(hdr);
149
0
    assert(iblock_row >= hdr->man_dtable.max_direct_rows);
150
151
    /* Set the free space in direct blocks */
152
0
    acc_heap_size   = 0;
153
0
    acc_dblock_free = 0;
154
0
    max_dblock_free = 0;
155
0
    iblock_size     = hdr->man_dtable.row_block_size[iblock_row];
156
0
    curr_row        = 0;
157
0
    while (acc_heap_size < iblock_size) {
158
0
        acc_heap_size += hdr->man_dtable.row_block_size[curr_row] * hdr->man_dtable.cparam.width;
159
0
        acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[curr_row] * hdr->man_dtable.cparam.width;
160
0
        if (hdr->man_dtable.row_max_dblock_free[curr_row] > max_dblock_free)
161
0
            max_dblock_free = hdr->man_dtable.row_max_dblock_free[curr_row];
162
0
        curr_row++;
163
0
    } /* end while */
164
165
    /* Set direct block free space values for indirect block */
166
0
    hdr->man_dtable.row_tot_dblock_free[iblock_row] = acc_dblock_free;
167
0
    hdr->man_dtable.row_max_dblock_free[iblock_row] = max_dblock_free;
168
169
0
    FUNC_LEAVE_NOAPI(ret_value)
170
0
} /* end H5HF__hdr_compute_free_space() */
171
172
/*-------------------------------------------------------------------------
173
 * Function:  H5HF__hdr_finish_init_phase1
174
 *
175
 * Purpose: First phase to finish initializing info in shared heap header
176
 *
177
 * Return:  Non-negative on success/Negative on failure
178
 *
179
 *-------------------------------------------------------------------------
180
 */
181
herr_t
182
H5HF__hdr_finish_init_phase1(H5HF_hdr_t *hdr)
183
0
{
184
0
    herr_t ret_value = SUCCEED; /* Return value */
185
186
0
    FUNC_ENTER_PACKAGE
187
188
    /*
189
     * Check arguments.
190
     */
191
0
    assert(hdr);
192
193
    /* Compute/cache some values */
194
0
    hdr->heap_off_size = (uint8_t)H5HF_SIZEOF_OFFSET_BITS(hdr->man_dtable.cparam.max_index);
195
0
    if (H5HF__dtable_init(&hdr->man_dtable) < 0)
196
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize doubling table info");
197
198
    /* Set the size of heap IDs */
199
0
    hdr->heap_len_size =
200
0
        (uint8_t)MIN(hdr->man_dtable.max_dir_blk_off_size, H5VM_limit_enc_size((uint64_t)hdr->max_man_size));
201
202
0
done:
203
0
    FUNC_LEAVE_NOAPI(ret_value)
204
0
} /* end H5HF__hdr_finish_init_phase1() */
205
206
/*-------------------------------------------------------------------------
207
 * Function:  H5HF__hdr_finish_init_phase2
208
 *
209
 * Purpose: Second phase to finish initializing info in shared heap header
210
 *
211
 * Return:  Non-negative on success/Negative on failure
212
 *
213
 *-------------------------------------------------------------------------
214
 */
215
herr_t
216
H5HF__hdr_finish_init_phase2(H5HF_hdr_t *hdr)
217
0
{
218
0
    unsigned u;                   /* Local index variable */
219
0
    herr_t   ret_value = SUCCEED; /* Return value */
220
221
0
    FUNC_ENTER_PACKAGE
222
223
    /*
224
     * Check arguments.
225
     */
226
0
    assert(hdr);
227
228
    /* Set the free space in direct blocks */
229
0
    for (u = 0; u < hdr->man_dtable.max_root_rows; u++) {
230
0
        if (u < hdr->man_dtable.max_direct_rows) {
231
0
            hdr->man_dtable.row_tot_dblock_free[u] =
232
0
                hdr->man_dtable.row_block_size[u] - H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
233
0
            H5_CHECKED_ASSIGN(hdr->man_dtable.row_max_dblock_free[u], size_t,
234
0
                              hdr->man_dtable.row_tot_dblock_free[u], hsize_t);
235
0
        } /* end if */
236
0
        else if (H5HF__hdr_compute_free_space(hdr, u) < 0)
237
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL,
238
0
                        "can't initialize direct block free space for indirect block");
239
0
    } /* end for */
240
241
    /* Initialize the block iterator for searching for free space */
242
0
    if (H5HF__man_iter_init(&hdr->next_block) < 0)
243
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize space search block iterator");
244
245
    /* Initialize the information for tracking 'huge' objects */
246
0
    if (H5HF__huge_init(hdr) < 0)
247
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize info for tracking huge objects");
248
249
    /* Initialize the information for tracking 'tiny' objects */
250
0
    if (H5HF__tiny_init(hdr) < 0)
251
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize info for tracking tiny objects");
252
253
0
done:
254
0
    FUNC_LEAVE_NOAPI(ret_value)
255
0
} /* end H5HF__hdr_finish_init_phase2() */
256
257
/*-------------------------------------------------------------------------
258
 * Function:  H5HF__hdr_finish_init
259
 *
260
 * Purpose: Finish initializing info in shared heap header
261
 *
262
 * Return:  Non-negative on success/Negative on failure
263
 *
264
 *-------------------------------------------------------------------------
265
 */
266
herr_t
267
H5HF__hdr_finish_init(H5HF_hdr_t *hdr)
268
0
{
269
0
    herr_t ret_value = SUCCEED; /* Return value */
270
271
0
    FUNC_ENTER_PACKAGE
272
273
    /*
274
     * Check arguments.
275
     */
276
0
    assert(hdr);
277
278
    /* First phase of header final initialization */
279
0
    if (H5HF__hdr_finish_init_phase1(hdr) < 0)
280
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't finish phase #1 of header final initialization");
281
282
    /* Second phase of header final initialization */
283
0
    if (H5HF__hdr_finish_init_phase2(hdr) < 0)
284
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't finish phase #2 of header final initialization");
285
286
0
done:
287
0
    FUNC_LEAVE_NOAPI(ret_value)
288
0
} /* end H5HF__hdr_finish_init() */
289
290
/*-------------------------------------------------------------------------
291
 * Function:  H5HF__hdr_create
292
 *
293
 * Purpose: Create new fractal heap header
294
 *
295
 * Return:  Non-negative on success/Negative on failure
296
 *
297
 *-------------------------------------------------------------------------
298
 */
299
haddr_t
300
H5HF__hdr_create(H5F_t *f, const H5HF_create_t *cparam)
301
0
{
302
0
    H5HF_hdr_t *hdr = NULL;              /* The new fractal heap header information */
303
0
    size_t      dblock_overhead;         /* Direct block's overhead */
304
0
    haddr_t     ret_value = HADDR_UNDEF; /* Return value */
305
306
0
    FUNC_ENTER_PACKAGE
307
308
    /*
309
     * Check arguments.
310
     */
311
0
    assert(f);
312
0
    assert(cparam);
313
314
#ifndef NDEBUG
315
    /* Check for valid parameters */
316
    if (cparam->managed.width == 0)
317
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width must be greater than zero");
318
    if (cparam->managed.width > H5HF_WIDTH_LIMIT)
319
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width too large");
320
    if (!POWER_OF_TWO(cparam->managed.width))
321
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width not power of two");
322
    if (cparam->managed.start_block_size == 0)
323
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "starting block size must be greater than zero");
324
    if (!POWER_OF_TWO(cparam->managed.start_block_size))
325
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "starting block size not power of two");
326
    if (cparam->managed.max_direct_size == 0)
327
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size must be greater than zero");
328
    if (cparam->managed.max_direct_size > H5HF_MAX_DIRECT_SIZE_LIMIT)
329
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size too large");
330
    if (!POWER_OF_TWO(cparam->managed.max_direct_size))
331
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size not power of two");
332
    if (cparam->managed.max_direct_size < cparam->max_man_size)
333
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF,
334
                    "max. direct block size not large enough to hold all managed blocks");
335
    if (cparam->managed.max_index == 0)
336
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. heap size must be greater than zero");
337
#endif /* NDEBUG */
338
339
    /* Allocate & basic initialization for the shared header */
340
0
    if (NULL == (hdr = H5HF__hdr_alloc(f)))
341
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "can't allocate space for shared heap info");
342
343
#ifndef NDEBUG
344
    if (cparam->managed.max_index > (unsigned)(8 * hdr->sizeof_size))
345
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. heap size too large for file");
346
#endif /* NDEBUG */
347
348
    /* Set the creation parameters for the heap */
349
0
    hdr->max_man_size     = cparam->max_man_size;
350
0
    hdr->checksum_dblocks = cparam->checksum_dblocks;
351
0
    H5MM_memcpy(&(hdr->man_dtable.cparam), &(cparam->managed), sizeof(H5HF_dtable_cparam_t));
352
353
    /* Set root table address to indicate that the heap is empty currently */
354
0
    hdr->man_dtable.table_addr = HADDR_UNDEF;
355
356
    /* Set free list header address to indicate that the heap is empty currently */
357
0
    hdr->fs_addr = HADDR_UNDEF;
358
359
    /* Set "huge" object tracker v2 B-tree address to indicate that there aren't any yet */
360
0
    hdr->huge_bt2_addr = HADDR_UNDEF;
361
362
    /* First phase of header final initialization */
363
    /* (doesn't need ID length set up) */
364
0
    if (H5HF__hdr_finish_init_phase1(hdr) < 0)
365
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF,
366
0
                    "can't finish phase #1 of header final initialization");
367
368
    /* Copy any I/O filter pipeline */
369
    /* (This code is not in the "finish init phase" routines because those
370
     *  routines are also called from the cache 'load' callback, and the filter
371
     *  length is already set in that case (its stored in the header on disk))
372
     */
373
0
    if (cparam->pline.nused > 0) {
374
        /* Check if the filters in the DCPL can be applied to this dataset */
375
0
        if (H5Z_can_apply_direct(&(cparam->pline)) < 0)
376
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "I/O filters can't operate on this heap");
377
378
        /* Mark the filters as checked */
379
0
        hdr->checked_filters = true;
380
381
        /* Make the "set local" filter callbacks for this dataset */
382
0
        if (H5Z_set_local_direct(&(cparam->pline)) < 0)
383
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to set local filter parameters");
384
385
        /* Copy the I/O filter pipeline from the creation parameters to the header */
386
0
        if (NULL == H5O_msg_copy(H5O_PLINE_ID, &(cparam->pline), &(hdr->pline)))
387
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTCOPY, HADDR_UNDEF, "can't copy I/O filter pipeline");
388
389
        /* Set the version for the I/O pipeline message */
390
0
        if (H5O_pline_set_version(hdr->f, &(hdr->pline)) < 0)
391
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, HADDR_UNDEF, "can't set version of I/O filter pipeline");
392
393
        /* Compute the I/O filters' encoded size */
394
0
        if (0 == (hdr->filter_len = (unsigned)H5O_msg_raw_size(hdr->f, H5O_PLINE_ID, false, &(hdr->pline))))
395
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGETSIZE, HADDR_UNDEF, "can't get I/O filter pipeline size");
396
397
        /* Compute size of header on disk */
398
        hdr->heap_size = H5HF_HEADER_SIZE(hdr) /* Base header size */
399
0
                         + hdr->sizeof_size    /* Size of size for filtered root direct block */
400
0
                         + 4                   /* Size of filter mask for filtered root direct block */
401
0
                         + hdr->filter_len;    /* Size of encoded I/O filter info */
402
0
    }                                          /* end if */
403
0
    else {
404
        /* Set size of header on disk */
405
0
        hdr->heap_size = H5HF_HEADER_SIZE(hdr);
406
407
        /* Mark filters as checked, for performance reasons */
408
0
        hdr->checked_filters = true;
409
0
    } /* end else */
410
411
    /* Set the length of IDs in the heap */
412
    /* (This code is not in the "finish init phase" routines because those
413
     *  routines are also called from the cache 'load' callback, and the ID
414
     *  length is already set in that case (its stored in the header on disk))
415
     */
416
0
    switch (cparam->id_len) {
417
0
        case 0: /* Set the length of heap IDs to just enough to hold the offset & length of 'normal' objects
418
                   in the heap */
419
0
            hdr->id_len = (unsigned)1 + hdr->heap_off_size + hdr->heap_len_size;
420
0
            break;
421
422
0
        case 1: /* Set the length of heap IDs to just enough to hold the information needed to directly access
423
                   'huge' objects in the heap */
424
0
            if (hdr->filter_len > 0)
425
0
                hdr->id_len = (unsigned)1         /* ID flags */
426
0
                              + hdr->sizeof_addr  /* Address of filtered object */
427
0
                              + hdr->sizeof_size  /* Length of filtered object */
428
0
                              + 4                 /* Filter mask for filtered object */
429
0
                              + hdr->sizeof_size; /* Size of de-filtered object in memory */
430
0
            else
431
0
                hdr->id_len = (unsigned)1         /* ID flags */
432
0
                              + hdr->sizeof_addr  /* Address of object */
433
0
                              + hdr->sizeof_size; /* Length of object */
434
0
            break;
435
436
0
        default: /* Use the requested size for the heap ID */
437
            /* Check boundaries */
438
0
            if (cparam->id_len < (1 + hdr->heap_off_size + hdr->heap_len_size))
439
0
                HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, HADDR_UNDEF,
440
0
                            "ID length not large enough to hold object IDs");
441
0
            else if (cparam->id_len > H5HF_MAX_ID_LEN)
442
0
                HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, HADDR_UNDEF,
443
0
                            "ID length too large to store tiny object lengths");
444
445
            /* Use the requested size for the heap ID */
446
0
            hdr->id_len = cparam->id_len;
447
0
            break;
448
0
    } /* end switch */
449
450
    /* Second phase of header final initialization */
451
    /* (needs ID and filter lengths set up) */
452
0
    if (H5HF__hdr_finish_init_phase2(hdr) < 0)
453
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF,
454
0
                    "can't finish phase #2 of header final initialization");
455
456
    /* Extra checking for possible gap between max. direct block size minus
457
     * overhead and "huge" object size */
458
0
    dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
459
0
    if ((cparam->managed.max_direct_size - dblock_overhead) < cparam->max_man_size)
460
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF,
461
0
                    "max. direct block size not large enough to hold all managed blocks");
462
463
    /* Allocate space for the header on disk */
464
0
    if (HADDR_UNDEF == (hdr->heap_addr = H5MF_alloc(f, H5FD_MEM_FHEAP_HDR, (hsize_t)hdr->heap_size)))
465
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for fractal heap header");
466
467
    /* Cache the new fractal heap header */
468
0
    if (H5AC_insert_entry(f, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
469
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, HADDR_UNDEF, "can't add fractal heap header to cache");
470
471
    /* Set address of heap header to return */
472
0
    ret_value = hdr->heap_addr;
473
474
0
done:
475
0
    if (!H5_addr_defined(ret_value) && hdr)
476
0
        if (H5HF__hdr_free(hdr) < 0)
477
0
            HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, HADDR_UNDEF, "unable to release fractal heap header");
478
479
0
    FUNC_LEAVE_NOAPI(ret_value)
480
0
} /* end H5HF__hdr_create() */
481
482
/*-------------------------------------------------------------------------
483
 * Function:  H5HF__hdr_protect
484
 *
485
 * Purpose: Convenience wrapper around H5AC_protect on an indirect block
486
 *
487
 * Return:  Pointer to indirect block on success, NULL on failure
488
 *
489
 *-------------------------------------------------------------------------
490
 */
491
H5HF_hdr_t *
492
H5HF__hdr_protect(H5F_t *f, haddr_t addr, unsigned flags)
493
0
{
494
0
    H5HF_hdr_cache_ud_t cache_udata;      /* User-data for callback */
495
0
    H5HF_hdr_t         *hdr;              /* Fractal heap header */
496
0
    H5HF_hdr_t         *ret_value = NULL; /* Return value */
497
498
0
    FUNC_ENTER_PACKAGE
499
500
    /* Check arguments */
501
0
    assert(f);
502
0
    assert(H5_addr_defined(addr));
503
504
    /* only H5AC__READ_ONLY_FLAG may appear in flags */
505
0
    assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
506
507
    /* Set up userdata for protect call */
508
0
    cache_udata.f = f;
509
510
    /* Lock the heap header into memory */
511
0
    if (NULL == (hdr = (H5HF_hdr_t *)H5AC_protect(f, H5AC_FHEAP_HDR, addr, &cache_udata, flags)))
512
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header");
513
514
    /* Set the header's address */
515
0
    hdr->heap_addr = addr;
516
517
    /* Update header's file pointer */
518
0
    hdr->f = f;
519
520
    /* Set the return value */
521
0
    ret_value = hdr;
522
523
0
done:
524
0
    FUNC_LEAVE_NOAPI(ret_value)
525
0
} /* end H5HF__hdr_protect() */
526
527
/*-------------------------------------------------------------------------
528
 * Function:  H5HF__hdr_incr
529
 *
530
 * Purpose: Increment component reference count on shared heap header
531
 *
532
 * Return:  Non-negative on success/Negative on failure
533
 *
534
 *-------------------------------------------------------------------------
535
 */
536
herr_t
537
H5HF__hdr_incr(H5HF_hdr_t *hdr)
538
0
{
539
0
    herr_t ret_value = SUCCEED; /* Return value */
540
541
0
    FUNC_ENTER_PACKAGE
542
543
    /* Sanity check */
544
0
    assert(hdr);
545
546
    /* Mark header as un-evictable when a block is depending on it */
547
0
    if (hdr->rc == 0)
548
0
        if (H5AC_pin_protected_entry(hdr) < 0)
549
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin fractal heap header");
550
551
    /* Increment reference count on shared header */
552
0
    hdr->rc++;
553
554
0
done:
555
0
    FUNC_LEAVE_NOAPI(ret_value)
556
0
} /* end H5HF__hdr_incr() */
557
558
/*-------------------------------------------------------------------------
559
 * Function:  H5HF__hdr_decr
560
 *
561
 * Purpose: Decrement component reference count on shared heap header
562
 *
563
 * Return:  Non-negative on success/Negative on failure
564
 *
565
 *-------------------------------------------------------------------------
566
 */
567
herr_t
568
H5HF__hdr_decr(H5HF_hdr_t *hdr)
569
0
{
570
0
    herr_t ret_value = SUCCEED; /* Return value */
571
572
0
    FUNC_ENTER_PACKAGE
573
574
    /* Sanity check */
575
0
    assert(hdr);
576
0
    assert(hdr->rc);
577
578
    /* Decrement reference count on shared header */
579
0
    hdr->rc--;
580
581
    /* Mark header as evictable again when no child blocks depend on it */
582
0
    if (hdr->rc == 0) {
583
0
        assert(hdr->file_rc == 0);
584
0
        if (H5AC_unpin_entry(hdr) < 0)
585
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap header");
586
0
    } /* end if */
587
588
0
done:
589
0
    FUNC_LEAVE_NOAPI(ret_value)
590
0
} /* end H5HF__hdr_decr() */
591
592
/*-------------------------------------------------------------------------
593
 * Function:  H5HF__hdr_fuse_incr
594
 *
595
 * Purpose: Increment file reference count on shared heap header
596
 *
597
 * Return:  Non-negative on success/Negative on failure
598
 *
599
 *-------------------------------------------------------------------------
600
 */
601
herr_t
602
H5HF__hdr_fuse_incr(H5HF_hdr_t *hdr)
603
0
{
604
0
    FUNC_ENTER_PACKAGE_NOERR
605
606
    /* Sanity check */
607
0
    assert(hdr);
608
609
    /* Increment file reference count on shared header */
610
0
    hdr->file_rc++;
611
612
0
    FUNC_LEAVE_NOAPI(SUCCEED)
613
0
} /* end H5HF__hdr_fuse_incr() */
614
615
/*-------------------------------------------------------------------------
616
 * Function:  H5HF__hdr_fuse_decr
617
 *
618
 * Purpose: Decrement file reference count on shared heap header
619
 *
620
 * Return:  Non-negative on success/Negative on failure
621
 *
622
 *-------------------------------------------------------------------------
623
 */
624
size_t
625
H5HF__hdr_fuse_decr(H5HF_hdr_t *hdr)
626
0
{
627
0
    FUNC_ENTER_PACKAGE_NOERR
628
629
    /* Sanity check */
630
0
    assert(hdr);
631
0
    assert(hdr->file_rc);
632
633
    /* Decrement file reference count on shared header */
634
0
    hdr->file_rc--;
635
636
0
    FUNC_LEAVE_NOAPI(hdr->file_rc)
637
0
} /* end H5HF__hdr_fuse_decr() */
638
639
/*-------------------------------------------------------------------------
640
 * Function:  H5HF__hdr_dirty
641
 *
642
 * Purpose: Mark heap header as dirty
643
 *
644
 * Return:  Non-negative on success/Negative on failure
645
 *
646
 *-------------------------------------------------------------------------
647
 */
648
herr_t
649
H5HF__hdr_dirty(H5HF_hdr_t *hdr)
650
0
{
651
0
    herr_t ret_value = SUCCEED; /* Return value */
652
653
0
    FUNC_ENTER_PACKAGE
654
655
    /* Sanity check */
656
0
    assert(hdr);
657
658
    /* Resize pinned header in cache if I/O filter is present. */
659
0
    if (hdr->filter_len > 0)
660
0
        if (H5AC_resize_entry(hdr, (size_t)hdr->heap_size) < 0)
661
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize fractal heap header");
662
663
    /* Mark header as dirty in cache */
664
0
    if (H5AC_mark_entry_dirty(hdr) < 0)
665
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap header as dirty");
666
667
0
done:
668
0
    FUNC_LEAVE_NOAPI(ret_value)
669
0
} /* end H5HF__hdr_dirty() */
670
671
/*-------------------------------------------------------------------------
672
 * Function:  H5HF__hdr_adj_free
673
 *
674
 * Purpose: Adjust the free space for a heap
675
 *
676
 * Return:  SUCCEED/FAIL
677
 *
678
 *-------------------------------------------------------------------------
679
 */
680
herr_t
681
H5HF__hdr_adj_free(H5HF_hdr_t *hdr, ssize_t amt)
682
0
{
683
0
    herr_t ret_value = SUCCEED; /* Return value */
684
685
0
    FUNC_ENTER_PACKAGE
686
687
    /*
688
     * Check arguments.
689
     */
690
0
    assert(hdr);
691
692
    /* Update heap header */
693
0
    assert(amt > 0 || hdr->total_man_free >= (hsize_t)-amt);
694
0
    hdr->total_man_free = (hsize_t)((hssize_t)hdr->total_man_free + amt);
695
696
    /* Mark heap header as modified */
697
0
    if (H5HF__hdr_dirty(hdr) < 0)
698
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty");
699
700
0
done:
701
0
    FUNC_LEAVE_NOAPI(ret_value)
702
0
} /* end H5HF__hdr_adj_free() */
703
704
/*-------------------------------------------------------------------------
705
 * Function:  H5HF__hdr_adjust_heap
706
 *
707
 * Purpose: Adjust heap space
708
 *
709
 * Return:  Non-negative on success/Negative on failure
710
 *
711
 *-------------------------------------------------------------------------
712
 */
713
herr_t
714
H5HF__hdr_adjust_heap(H5HF_hdr_t *hdr, hsize_t new_size, hssize_t extra_free)
715
0
{
716
0
    herr_t ret_value = SUCCEED; /* Return value */
717
718
0
    FUNC_ENTER_PACKAGE
719
720
    /*
721
     * Check arguments.
722
     */
723
0
    assert(hdr);
724
725
    /* Set the total managed space in heap */
726
0
    hdr->man_size = new_size;
727
728
    /* Adjust the free space in direct blocks */
729
0
    assert(extra_free > 0 || hdr->total_man_free >= (hsize_t)-extra_free);
730
0
    hdr->total_man_free = (hsize_t)((hssize_t)hdr->total_man_free + extra_free);
731
732
    /* Mark heap header as modified */
733
0
    if (H5HF__hdr_dirty(hdr) < 0)
734
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty");
735
736
0
done:
737
0
    FUNC_LEAVE_NOAPI(ret_value)
738
0
} /* end H5HF__hdr_adjust_heap() */
739
740
/*-------------------------------------------------------------------------
741
 * Function:  H5HF__hdr_inc_alloc
742
 *
743
 * Purpose: Increase allocated size of heap
744
 *
745
 * Return:  Non-negative on success/Negative on failure
746
 *
747
 *-------------------------------------------------------------------------
748
 */
749
herr_t
750
H5HF__hdr_inc_alloc(H5HF_hdr_t *hdr, size_t alloc_size)
751
0
{
752
0
    FUNC_ENTER_PACKAGE_NOERR
753
754
    /*
755
     * Check arguments.
756
     */
757
0
    assert(hdr);
758
0
    assert(alloc_size);
759
760
    /* Update the "allocated" size within the heap */
761
0
    hdr->man_alloc_size += alloc_size;
762
763
0
    FUNC_LEAVE_NOAPI(SUCCEED)
764
0
} /* end H5HF__hdr_inc_alloc() */
765
766
/*-------------------------------------------------------------------------
767
 * Function:  H5HF__hdr_start_iter
768
 *
769
 * Purpose: Start "next block" iterator at an offset/entry in the heap
770
 *
771
 * Return:  Non-negative on success/Negative on failure
772
 *
773
 *-------------------------------------------------------------------------
774
 */
775
herr_t
776
H5HF__hdr_start_iter(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, hsize_t curr_off, unsigned curr_entry)
777
0
{
778
0
    herr_t ret_value = SUCCEED; /* Return value */
779
780
0
    FUNC_ENTER_PACKAGE
781
782
    /*
783
     * Check arguments.
784
     */
785
0
    assert(hdr);
786
0
    assert(iblock);
787
788
    /* Set up "next block" iterator at correct location */
789
0
    if (H5HF__man_iter_start_entry(hdr, &hdr->next_block, iblock, curr_entry) < 0)
790
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize block iterator");
791
792
    /* Set the offset of the iterator in the heap */
793
0
    hdr->man_iter_off = curr_off;
794
795
0
done:
796
0
    FUNC_LEAVE_NOAPI(ret_value)
797
0
} /* end H5HF__hdr_start_iter() */
798
799
/*-------------------------------------------------------------------------
800
 * Function:  H5HF__hdr_reset_iter
801
 *
802
 * Purpose: Reset "next block" iterator
803
 *
804
 * Return:  Non-negative on success/Negative on failure
805
 *
806
 *-------------------------------------------------------------------------
807
 */
808
herr_t
809
H5HF__hdr_reset_iter(H5HF_hdr_t *hdr, hsize_t curr_off)
810
0
{
811
0
    herr_t ret_value = SUCCEED; /* Return value */
812
813
0
    FUNC_ENTER_PACKAGE
814
815
    /*
816
     * Check arguments.
817
     */
818
0
    assert(hdr);
819
820
    /* Reset "next block" iterator */
821
0
    if (H5HF__man_iter_reset(&hdr->next_block) < 0)
822
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator");
823
824
    /* Set the offset of the iterator in the heap */
825
0
    hdr->man_iter_off = curr_off;
826
827
0
done:
828
0
    FUNC_LEAVE_NOAPI(ret_value)
829
0
} /* end H5HF__hdr_reset_iter() */
830
831
/*-------------------------------------------------------------------------
832
 * Function:  H5HF__hdr_skip_blocks
833
 *
834
 * Purpose: Add skipped direct blocks to free space for heap
835
 *
836
 * Return:  SUCCEED/FAIL
837
 *
838
 *-------------------------------------------------------------------------
839
 */
840
herr_t
841
H5HF__hdr_skip_blocks(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, unsigned start_entry, unsigned nentries)
842
0
{
843
0
    unsigned row, col;            /* Row & column of entry */
844
0
    hsize_t  sect_size;           /* Size of section in heap space */
845
0
    herr_t   ret_value = SUCCEED; /* Return value */
846
847
0
    FUNC_ENTER_PACKAGE
848
849
    /*
850
     * Check arguments.
851
     */
852
0
    assert(hdr);
853
0
    assert(iblock);
854
0
    assert(nentries);
855
856
    /* Compute the span within the heap to skip */
857
0
    row       = start_entry / hdr->man_dtable.cparam.width;
858
0
    col       = start_entry % hdr->man_dtable.cparam.width;
859
0
    sect_size = H5HF__dtable_span_size(&hdr->man_dtable, row, col, nentries);
860
0
    assert(sect_size > 0);
861
862
    /* Advance the new block iterator */
863
0
    if (H5HF__hdr_inc_iter(hdr, sect_size, nentries) < 0)
864
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size");
865
866
    /* Add 'indirect' section for blocks skipped in this row */
867
0
    if (H5HF__sect_indirect_add(hdr, iblock, start_entry, nentries) < 0)
868
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL,
869
0
                    "can't create indirect section for indirect block's free space");
870
871
0
done:
872
0
    FUNC_LEAVE_NOAPI(ret_value)
873
0
} /* end H5HF__hdr_skip_blocks() */
874
875
/*-------------------------------------------------------------------------
876
 * Function:  H5HF__hdr_update_iter
877
 *
878
 * Purpose: Update state of heap to account for current iterator
879
 *              position.
880
 *
881
 * Note:  Creates necessary indirect blocks
882
 *
883
 * Return:  Non-negative on success/Negative on failure
884
 *
885
 *-------------------------------------------------------------------------
886
 */
887
herr_t
888
H5HF__hdr_update_iter(H5HF_hdr_t *hdr, size_t min_dblock_size)
889
0
{
890
0
    herr_t ret_value = SUCCEED; /* Return value */
891
892
0
    FUNC_ENTER_PACKAGE
893
894
    /*
895
     * Check arguments.
896
     */
897
0
    assert(hdr);
898
0
    assert(min_dblock_size > 0);
899
900
    /* Check for creating first indirect block */
901
0
    if (hdr->man_dtable.curr_root_rows == 0) {
902
0
        if (H5HF__man_iblock_root_create(hdr, min_dblock_size) < 0)
903
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to create root indirect block");
904
0
    } /* end if */
905
0
    else {
906
0
        H5HF_indirect_t *iblock;                 /* Pointer to indirect block */
907
0
        bool             walked_up, walked_down; /* Condition variables for finding direct block location */
908
0
        unsigned         next_row;               /* Iterator's next block row */
909
0
        unsigned         next_entry;             /* Iterator's next block entry */
910
0
        unsigned         min_dblock_row;         /* Minimum row for direct block size request */
911
912
        /* Compute min. row for direct block requested */
913
0
        min_dblock_row = H5HF__dtable_size_to_row(&hdr->man_dtable, min_dblock_size);
914
915
        /* Initialize block iterator, if necessary */
916
0
        if (!H5HF__man_iter_ready(&hdr->next_block)) {
917
            /* Start iterator with previous offset of iterator */
918
0
            if (H5HF__man_iter_start_offset(hdr, &hdr->next_block, hdr->man_iter_off) < 0)
919
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location");
920
0
        } /* end if */
921
922
        /* Get information about current iterator location */
923
0
        if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
924
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location");
925
926
        /* Check for skipping over blocks in the current block */
927
0
        if (min_dblock_row > next_row && next_row < iblock->nrows) {
928
0
            unsigned min_entry;    /* Min entry for direct block requested */
929
0
            unsigned skip_entries; /* Number of entries to skip in the current block */
930
931
            /* Compute the number of entries to skip in the current block */
932
0
            min_entry = min_dblock_row * hdr->man_dtable.cparam.width;
933
0
            if (min_dblock_row >= iblock->nrows)
934
0
                skip_entries = (iblock->nrows * hdr->man_dtable.cparam.width) - next_entry;
935
0
            else
936
0
                skip_entries = min_entry - next_entry;
937
938
            /* Add skipped direct blocks to heap's free space */
939
0
            if (H5HF__hdr_skip_blocks(hdr, iblock, next_entry, skip_entries) < 0)
940
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space");
941
942
            /* Get information about new iterator location */
943
0
            if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
944
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
945
0
                            "unable to retrieve current block iterator location");
946
0
        } /* end if */
947
948
0
        do {
949
            /* Reset conditions for leaving loop */
950
0
            walked_up = walked_down = false;
951
952
            /* Check for walking off end of indirect block */
953
            /* (walk up iterator) */
954
0
            while (next_row >= iblock->nrows) {
955
                /* Check for needing to expand root indirect block */
956
0
                if (iblock->parent == NULL) {
957
0
                    if (H5HF__man_iblock_root_double(hdr, min_dblock_size) < 0)
958
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to double root indirect block");
959
0
                } /* end if */
960
0
                else {
961
                    /* Move iterator up one level */
962
0
                    if (H5HF__man_iter_up(&hdr->next_block) < 0)
963
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL,
964
0
                                    "unable to advance current block iterator location");
965
966
                    /* Increment location of next block at this level */
967
0
                    if (H5HF__man_iter_next(hdr, &hdr->next_block, 1) < 0)
968
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't advance fractal heap block location");
969
0
                } /* end else */
970
971
                /* Get information about new iterator location */
972
0
                if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
973
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
974
0
                                "unable to retrieve current block iterator location");
975
976
                /* Indicate that we walked up */
977
0
                walked_up = true;
978
0
            } /* end while */
979
980
            /* Check for walking into child indirect block */
981
            /* (walk down iterator) */
982
0
            if (next_row >= hdr->man_dtable.max_direct_rows) {
983
0
                unsigned child_nrows; /* Number of rows in new indirect block */
984
985
0
                assert(!H5_addr_defined(iblock->ents[next_entry].addr));
986
987
                /* Compute # of rows in next child indirect block to use */
988
0
                child_nrows =
989
0
                    H5HF__dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[next_row]);
990
991
                /* Check for skipping over indirect blocks */
992
                /* (that don't have direct blocks large enough to hold direct block size requested) */
993
0
                if (hdr->man_dtable.row_block_size[child_nrows - 1] < min_dblock_size) {
994
0
                    unsigned child_rows_needed; /* Number of rows needed to hold direct block */
995
0
                    unsigned child_entry;       /* Entry of child indirect block */
996
997
                    /* Compute # of rows needed in child indirect block */
998
0
                    child_rows_needed = (H5VM_log2_of2((uint32_t)min_dblock_size) -
999
0
                                         H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size)) +
1000
0
                                        2;
1001
0
                    assert(child_rows_needed > child_nrows);
1002
0
                    child_entry =
1003
0
                        (next_row + (child_rows_needed - child_nrows)) * hdr->man_dtable.cparam.width;
1004
0
                    if (child_entry > (iblock->nrows * hdr->man_dtable.cparam.width))
1005
0
                        child_entry = iblock->nrows * hdr->man_dtable.cparam.width;
1006
1007
                    /* Add skipped indirect blocks to heap's free space */
1008
0
                    if (H5HF__hdr_skip_blocks(hdr, iblock, next_entry, (child_entry - next_entry)) < 0)
1009
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL,
1010
0
                                    "can't add skipped blocks to heap's free space");
1011
0
                } /* end if */
1012
0
                else {
1013
0
                    H5HF_indirect_t *new_iblock;      /* Pointer to new indirect block */
1014
0
                    bool             did_protect;     /* Whether we protected the indirect block or not */
1015
0
                    haddr_t          new_iblock_addr; /* New indirect block's address */
1016
1017
                    /* Allocate new indirect block */
1018
0
                    if (H5HF__man_iblock_create(hdr, iblock, next_entry, child_nrows, child_nrows,
1019
0
                                                &new_iblock_addr) < 0)
1020
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL,
1021
0
                                    "can't allocate fractal heap indirect block");
1022
1023
                    /* Lock new indirect block */
1024
0
                    if (NULL == (new_iblock = H5HF__man_iblock_protect(hdr, new_iblock_addr, child_nrows,
1025
0
                                                                       iblock, next_entry, false,
1026
0
                                                                       H5AC__NO_FLAGS_SET, &did_protect)))
1027
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL,
1028
0
                                    "unable to protect fractal heap indirect block");
1029
1030
                    /* Move iterator down one level (pins indirect block) */
1031
0
                    if (H5HF__man_iter_down(&hdr->next_block, new_iblock) < 0)
1032
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL,
1033
0
                                    "unable to advance current block iterator location");
1034
1035
                    /* Check for skipping over rows and add free section for skipped rows */
1036
0
                    if (min_dblock_size > hdr->man_dtable.cparam.start_block_size) {
1037
0
                        unsigned new_entry; /* Entry of direct block which is large enough */
1038
1039
                        /* Compute entry for direct block size requested */
1040
0
                        new_entry = hdr->man_dtable.cparam.width * min_dblock_row;
1041
1042
                        /* Add skipped blocks to heap's free space */
1043
0
                        if (H5HF__hdr_skip_blocks(hdr, new_iblock, 0, new_entry) < 0)
1044
0
                            HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL,
1045
0
                                        "can't add skipped blocks to heap's free space");
1046
0
                    } /* end if */
1047
1048
                    /* Unprotect child indirect block */
1049
0
                    if (H5HF__man_iblock_unprotect(new_iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
1050
0
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL,
1051
0
                                    "unable to release fractal heap indirect block");
1052
0
                } /* end else */
1053
1054
                /* Get information about new iterator location */
1055
0
                if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
1056
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
1057
0
                                "unable to retrieve current block iterator location");
1058
1059
                /* Indicate that we walked down */
1060
0
                walked_down = true;
1061
0
            } /* end if */
1062
0
        } while (walked_down || walked_up);
1063
0
    } /* end else */
1064
1065
0
done:
1066
0
    FUNC_LEAVE_NOAPI(ret_value)
1067
0
} /* end H5HF__hdr_update_iter() */
1068
1069
/*-------------------------------------------------------------------------
1070
 * Function:  H5HF__hdr_inc_iter
1071
 *
1072
 * Purpose: Advance "next block" iterator
1073
 *
1074
 * Return:  Non-negative on success/Negative on failure
1075
 *
1076
 *-------------------------------------------------------------------------
1077
 */
1078
herr_t
1079
H5HF__hdr_inc_iter(H5HF_hdr_t *hdr, hsize_t adv_size, unsigned nentries)
1080
0
{
1081
0
    herr_t ret_value = SUCCEED; /* Return value */
1082
1083
0
    FUNC_ENTER_PACKAGE
1084
1085
    /*
1086
     * Check arguments.
1087
     */
1088
0
    assert(hdr);
1089
0
    assert(nentries);
1090
1091
    /* Advance the iterator for the current location within the indirect block */
1092
0
    if (hdr->next_block.curr)
1093
0
        if (H5HF__man_iter_next(hdr, &hdr->next_block, nentries) < 0)
1094
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location");
1095
1096
    /* Increment the offset of the iterator in the heap */
1097
0
    hdr->man_iter_off += adv_size;
1098
1099
0
done:
1100
0
    FUNC_LEAVE_NOAPI(ret_value)
1101
0
} /* end H5HF__hdr_inc_iter() */
1102
1103
/*-------------------------------------------------------------------------
1104
 * Function:  H5HF__hdr_reverse_iter
1105
 *
1106
 * Purpose: Walk "next block" iterator backwards until the correct
1107
 *              location to allocate next block from is found
1108
 *
1109
 * Return:  Non-negative on success/Negative on failure
1110
 *
1111
 *-------------------------------------------------------------------------
1112
 */
1113
herr_t
1114
H5HF__hdr_reverse_iter(H5HF_hdr_t *hdr, haddr_t dblock_addr)
1115
0
{
1116
0
    H5HF_indirect_t *iblock;              /* Indirect block where iterator is located */
1117
0
    unsigned         curr_entry;          /* Current entry for iterator */
1118
0
    bool             walked_down;         /* Loop flag */
1119
0
    bool             walked_up;           /* Loop flag */
1120
0
    herr_t           ret_value = SUCCEED; /* Return value */
1121
1122
0
    FUNC_ENTER_PACKAGE
1123
1124
    /*
1125
     * Check arguments.
1126
     */
1127
0
    assert(hdr);
1128
1129
    /* Initialize block iterator, if necessary */
1130
0
    if (!H5HF__man_iter_ready(&hdr->next_block))
1131
        /* Start iterator with previous offset of iterator */
1132
0
        if (H5HF__man_iter_start_offset(hdr, &hdr->next_block, hdr->man_iter_off) < 0)
1133
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location");
1134
1135
    /* Walk backwards through heap, looking for direct block to place iterator after */
1136
1137
    /* Get information about current iterator location */
1138
0
    if (H5HF__man_iter_curr(&hdr->next_block, NULL, NULL, &curr_entry, &iblock) < 0)
1139
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator information");
1140
1141
    /* Move current iterator position backwards once */
1142
0
    curr_entry--;
1143
1144
    /* Search backwards in the heap address space for direct block to latch onto */
1145
0
    do {
1146
0
        int tmp_entry; /* Temp. entry for iterator (use signed value to detect errors) */
1147
1148
        /* Reset loop flags */
1149
0
        walked_down = false;
1150
0
        walked_up   = false;
1151
1152
        /* Walk backwards through entries, until we find one that has a child */
1153
        /* (Skip direct block that will be deleted, if we find it) */
1154
0
        tmp_entry = (int)curr_entry;
1155
0
        while (tmp_entry >= 0 && (H5_addr_eq(iblock->ents[tmp_entry].addr, dblock_addr) ||
1156
0
                                  !H5_addr_defined(iblock->ents[tmp_entry].addr)))
1157
0
            tmp_entry--;
1158
        /* Check for no earlier blocks in this indirect block */
1159
0
        if (tmp_entry < 0) {
1160
            /* Check for parent of current indirect block */
1161
0
            if (iblock->parent) {
1162
                /* Move iterator to parent of current block */
1163
0
                if (H5HF__man_iter_up(&hdr->next_block) < 0)
1164
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL,
1165
0
                                "unable to move current block iterator location up");
1166
1167
                /* Get information about current iterator location */
1168
0
                if (H5HF__man_iter_curr(&hdr->next_block, NULL, NULL, &curr_entry, &iblock) < 0)
1169
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL,
1170
0
                                "unable to retrieve current block iterator information");
1171
1172
                /* Move current iterator position backwards once */
1173
0
                curr_entry--;
1174
1175
                /* Note that we walked up */
1176
0
                walked_up = true;
1177
0
            } /* end if */
1178
0
            else {
1179
                /* Reset iterator offset */
1180
0
                hdr->man_iter_off = 0;
1181
1182
                /* Reset 'next block' iterator */
1183
0
                if (H5HF__man_iter_reset(&hdr->next_block) < 0)
1184
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator");
1185
0
            } /* end else */
1186
0
        }     /* end if */
1187
0
        else {
1188
0
            unsigned row; /* Row for entry */
1189
1190
0
            curr_entry = (unsigned)tmp_entry;
1191
1192
            /* Check if entry is for a direct block */
1193
0
            row = curr_entry / hdr->man_dtable.cparam.width;
1194
0
            if (row < hdr->man_dtable.max_direct_rows) {
1195
                /* Increment entry to empty location */
1196
0
                curr_entry++;
1197
1198
                /* Set the current location of the iterator to next entry after the existing direct block */
1199
0
                if (H5HF__man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0)
1200
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location");
1201
1202
                /* Update iterator offset */
1203
0
                hdr->man_iter_off = iblock->block_off;
1204
0
                hdr->man_iter_off += hdr->man_dtable.row_block_off[curr_entry / hdr->man_dtable.cparam.width];
1205
0
                hdr->man_iter_off +=
1206
0
                    hdr->man_dtable.row_block_size[curr_entry / hdr->man_dtable.cparam.width] *
1207
0
                    (curr_entry % hdr->man_dtable.cparam.width);
1208
0
            } /* end if */
1209
0
            else {
1210
0
                H5HF_indirect_t *child_iblock; /* Pointer to child indirect block */
1211
0
                bool             did_protect;  /* Whether we protected the indirect block or not */
1212
0
                unsigned         child_nrows;  /* # of rows in child block */
1213
1214
                /* Compute # of rows in next child indirect block to use */
1215
0
                child_nrows =
1216
0
                    H5HF__dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[row]);
1217
1218
                /* Lock child indirect block */
1219
0
                if (NULL == (child_iblock = H5HF__man_iblock_protect(hdr, iblock->ents[curr_entry].addr,
1220
0
                                                                     child_nrows, iblock, curr_entry, false,
1221
0
                                                                     H5AC__NO_FLAGS_SET, &did_protect)))
1222
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL,
1223
0
                                "unable to protect fractal heap indirect block");
1224
1225
                /* Set the current location of the iterator */
1226
0
                if (H5HF__man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0)
1227
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location");
1228
1229
                /* Walk down into child indirect block (pins child block) */
1230
0
                if (H5HF__man_iter_down(&hdr->next_block, child_iblock) < 0)
1231
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL,
1232
0
                                "unable to advance current block iterator location");
1233
1234
                /* Update iterator location */
1235
0
                iblock     = child_iblock;
1236
0
                curr_entry = (child_iblock->nrows * hdr->man_dtable.cparam.width) - 1;
1237
1238
                /* Unprotect child indirect block */
1239
0
                if (H5HF__man_iblock_unprotect(child_iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
1240
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL,
1241
0
                                "unable to release fractal heap indirect block");
1242
1243
                /* Note that we walked down */
1244
0
                walked_down = true;
1245
0
            } /* end else */
1246
0
        }     /* end else */
1247
0
    } while (walked_down || walked_up);
1248
1249
0
done:
1250
0
    FUNC_LEAVE_NOAPI(ret_value)
1251
0
} /* end H5HF__hdr_reverse_iter() */
1252
1253
/*-------------------------------------------------------------------------
1254
 * Function:  H5HF__hdr_empty
1255
 *
1256
 * Purpose: Reset heap header to 'empty heap' state
1257
 *
1258
 * Return:  Non-negative on success/Negative on failure
1259
 *
1260
 *-------------------------------------------------------------------------
1261
 */
1262
herr_t
1263
H5HF__hdr_empty(H5HF_hdr_t *hdr)
1264
0
{
1265
0
    herr_t ret_value = SUCCEED; /* Return value */
1266
1267
0
    FUNC_ENTER_PACKAGE
1268
1269
    /* Sanity check */
1270
0
    assert(hdr);
1271
1272
    /* Reset block iterator, if necessary */
1273
0
    if (H5HF__man_iter_ready(&hdr->next_block))
1274
0
        if (H5HF__man_iter_reset(&hdr->next_block) < 0)
1275
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator");
1276
1277
    /* Shrink managed heap size */
1278
0
    hdr->man_size       = 0;
1279
0
    hdr->man_alloc_size = 0;
1280
1281
    /* Reset root pointer information */
1282
0
    hdr->man_dtable.curr_root_rows = 0;
1283
0
    hdr->man_dtable.table_addr     = HADDR_UNDEF;
1284
1285
    /* Reset the 'next block' iterator location */
1286
0
    hdr->man_iter_off = 0;
1287
1288
    /* Reset the free space in direct blocks */
1289
0
    hdr->total_man_free = 0;
1290
1291
    /* Mark heap header as modified */
1292
0
    if (H5HF__hdr_dirty(hdr) < 0)
1293
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty");
1294
1295
0
done:
1296
0
    FUNC_LEAVE_NOAPI(ret_value)
1297
0
} /* end H5HF__hdr_empty() */
1298
1299
/*-------------------------------------------------------------------------
1300
 * Function:  H5HF__hdr_free
1301
 *
1302
 * Purpose: Free shared fractal heap header
1303
 *
1304
 * Return:  Non-negative on success/Negative on failure
1305
 *
1306
 *-------------------------------------------------------------------------
1307
 */
1308
herr_t
1309
H5HF__hdr_free(H5HF_hdr_t *hdr)
1310
0
{
1311
0
    herr_t ret_value = SUCCEED; /* Return value */
1312
1313
0
    FUNC_ENTER_PACKAGE
1314
1315
    /*
1316
     * Check arguments.
1317
     */
1318
0
    assert(hdr);
1319
1320
    /* Free the block size lookup table for the doubling table */
1321
0
    if (H5HF__dtable_dest(&hdr->man_dtable) < 0)
1322
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap doubling table");
1323
1324
    /* Release any I/O pipeline filter information */
1325
0
    if (hdr->pline.nused)
1326
0
        if (H5O_msg_reset(H5O_PLINE_ID, &(hdr->pline)) < 0)
1327
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to reset I/O pipeline message");
1328
1329
    /* Free the shared info itself */
1330
0
    hdr = H5FL_FREE(H5HF_hdr_t, hdr);
1331
1332
0
done:
1333
0
    FUNC_LEAVE_NOAPI(ret_value)
1334
0
} /* end H5HF__hdr_free() */
1335
1336
/*-------------------------------------------------------------------------
1337
 * Function:  H5HF__hdr_delete
1338
 *
1339
 * Purpose: Delete a fractal heap, starting with the header
1340
 *
1341
 * Return:  SUCCEED/FAIL
1342
 *
1343
 *-------------------------------------------------------------------------
1344
 */
1345
herr_t
1346
H5HF__hdr_delete(H5HF_hdr_t *hdr)
1347
0
{
1348
0
    unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap header */
1349
0
    herr_t   ret_value   = SUCCEED;            /* Return value */
1350
1351
0
    FUNC_ENTER_PACKAGE
1352
1353
    /*
1354
     * Check arguments.
1355
     */
1356
0
    assert(hdr);
1357
0
    assert(!hdr->file_rc);
1358
1359
#ifndef NDEBUG
1360
    {
1361
        unsigned hdr_status = 0; /* Heap header's status in the metadata cache */
1362
1363
        /* Check the heap header's status in the metadata cache */
1364
        if (H5AC_get_entry_status(hdr->f, hdr->heap_addr, &hdr_status) < 0)
1365
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for heap header");
1366
1367
        /* Sanity checks on heap header */
1368
        assert(hdr_status & H5AC_ES__IN_CACHE);
1369
        assert(hdr_status & H5AC_ES__IS_PROTECTED);
1370
    }  /* end block */
1371
#endif /* NDEBUG */
1372
1373
    /* Check for free space manager for heap */
1374
    /* (must occur before attempting to delete the heap, so indirect blocks
1375
     *  will get unpinned)
1376
     */
1377
0
    if (H5_addr_defined(hdr->fs_addr))
1378
        /* Delete free space manager for heap */
1379
0
        if (H5HF__space_delete(hdr) < 0)
1380
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap free space manager");
1381
1382
    /* Check for root direct/indirect block */
1383
0
    if (H5_addr_defined(hdr->man_dtable.table_addr)) {
1384
0
        if (hdr->man_dtable.curr_root_rows == 0) {
1385
0
            hsize_t dblock_size; /* Size of direct block on disk */
1386
1387
            /* Check for I/O filters on this heap */
1388
0
            if (hdr->filter_len > 0) {
1389
                /* Set the dblock's size */
1390
0
                dblock_size = hdr->pline_root_direct_size;
1391
1392
                /* Reset the header's pipeline information */
1393
0
                hdr->pline_root_direct_size        = 0;
1394
0
                hdr->pline_root_direct_filter_mask = 0;
1395
0
            } /* end if */
1396
0
            else
1397
0
                dblock_size = hdr->man_dtable.cparam.start_block_size;
1398
1399
            /* Delete root direct block */
1400
0
            if (H5HF__man_dblock_delete(hdr->f, hdr->man_dtable.table_addr, dblock_size) < 0)
1401
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root direct block");
1402
0
        } /* end if */
1403
0
        else {
1404
            /* Delete root indirect block */
1405
0
            if (H5HF__man_iblock_delete(hdr, hdr->man_dtable.table_addr, hdr->man_dtable.curr_root_rows, NULL,
1406
0
                                        0) < 0)
1407
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL,
1408
0
                            "unable to release fractal heap root indirect block");
1409
0
        } /* end else */
1410
0
    }     /* end if */
1411
1412
    /* Check for 'huge' objects in heap */
1413
0
    if (H5_addr_defined(hdr->huge_bt2_addr)) {
1414
        /* Delete huge objects in heap and their tracker */
1415
0
        if (H5HF__huge_delete(hdr) < 0)
1416
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL,
1417
0
                        "unable to release fractal heap 'huge' objects and tracker");
1418
0
    } /* end if */
1419
1420
    /* Indicate that the heap header should be deleted & file space freed */
1421
0
    cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
1422
1423
0
done:
1424
    /* Unprotect the header with appropriate flags */
1425
0
    if (H5AC_unprotect(hdr->f, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, cache_flags) < 0)
1426
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header");
1427
1428
0
    FUNC_LEAVE_NOAPI(ret_value)
1429
0
} /* end H5HF__hdr_delete() */