Coverage Report

Created: 2026-01-08 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5HF.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*-------------------------------------------------------------------------
14
 *
15
 * Created:   H5HF.c
16
 *
17
 * Purpose:   Implements a "fractal heap" for storing variable-
18
 *                      length objects in a file.
19
 *
20
 *                      Please see the documentation in:
21
 *                      doc/html/TechNotes/FractalHeap.html for a full description
22
 *                      of how they work, etc.
23
 *
24
 *-------------------------------------------------------------------------
25
 */
26
27
/****************/
28
/* Module Setup */
29
/****************/
30
31
#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
32
33
/***********/
34
/* Headers */
35
/***********/
36
#include "H5private.h"   /* Generic Functions     */
37
#include "H5Eprivate.h"  /* Error handling        */
38
#include "H5FLprivate.h" /* Free Lists                               */
39
#include "H5HFpkg.h"     /* Fractal heaps     */
40
#include "H5MMprivate.h" /* Memory management     */
41
42
/****************/
43
/* Local Macros */
44
/****************/
45
46
/******************/
47
/* Local Typedefs */
48
/******************/
49
50
/********************/
51
/* Package Typedefs */
52
/********************/
53
54
/********************/
55
/* Local Prototypes */
56
/********************/
57
58
/*********************/
59
/* Package Variables */
60
/*********************/
61
62
/* Package initialization variable */
63
bool H5_PKG_INIT_VAR = false;
64
65
/*****************************/
66
/* Library Private Variables */
67
/*****************************/
68
69
/*******************/
70
/* Local Variables */
71
/*******************/
72
73
/* Declare a free list to manage the H5HF_t struct */
74
H5FL_DEFINE_STATIC(H5HF_t);
75
76
/*-------------------------------------------------------------------------
77
 * Function:  H5HF__op_read
78
 *
79
 * Purpose: Performs a 'read' operation for a heap 'op' callback
80
 *
81
 * Return:  SUCCEED/FAIL
82
 *
83
 *-------------------------------------------------------------------------
84
 */
85
herr_t
86
H5HF__op_read(const void *obj, size_t obj_len, void *op_data)
87
0
{
88
0
    FUNC_ENTER_PACKAGE_NOERR
89
90
    /* Perform "read", using memcpy() */
91
0
    H5MM_memcpy(op_data, obj, obj_len);
92
93
0
    FUNC_LEAVE_NOAPI(SUCCEED)
94
0
} /* end H5HF__op_read() */
95
96
/*-------------------------------------------------------------------------
97
 * Function:  H5HF__op_write
98
 *
99
 * Purpose: Performs a 'write' operation for a heap 'op' callback
100
 *
101
 * Return:  SUCCEED/FAIL
102
 *
103
 *-------------------------------------------------------------------------
104
 */
105
herr_t
106
H5HF__op_write(const void *obj, size_t obj_len, void *op_data)
107
0
{
108
0
    FUNC_ENTER_PACKAGE_NOERR
109
110
    /* Perform "write", using memcpy()
111
     *
112
     * We cast away const here because no obj pointer that was originally
113
     * const should ever arrive here.
114
     */
115
0
    H5_WARN_CAST_AWAY_CONST_OFF
116
0
    H5MM_memcpy((void *)obj, op_data, obj_len);
117
0
    H5_WARN_CAST_AWAY_CONST_ON
118
119
0
    FUNC_LEAVE_NOAPI(SUCCEED)
120
0
} /* end H5HF__op_write() */
121
122
/*-------------------------------------------------------------------------
123
 * Function:  H5HF_create
124
 *
125
 * Purpose: Creates a new empty fractal heap in the file.
126
 *
127
 * Return:  Pointer to heap wrapper on success
128
 *              NULL on failure
129
 *
130
 *-------------------------------------------------------------------------
131
 */
132
H5HF_t *
133
H5HF_create(H5F_t *f, const H5HF_create_t *cparam)
134
0
{
135
0
    H5HF_t     *fh  = NULL;       /* Pointer to new fractal heap */
136
0
    H5HF_hdr_t *hdr = NULL;       /* The fractal heap header information */
137
0
    haddr_t     fh_addr;          /* Heap header address */
138
0
    H5HF_t     *ret_value = NULL; /* Return value */
139
140
0
    FUNC_ENTER_NOAPI(NULL)
141
142
    /*
143
     * Check arguments.
144
     */
145
0
    assert(f);
146
0
    assert(cparam);
147
148
    /* Create shared fractal heap header */
149
0
    if (HADDR_UNDEF == (fh_addr = H5HF__hdr_create(f, cparam)))
150
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't create fractal heap header");
151
152
    /* Allocate fractal heap wrapper */
153
0
    if (NULL == (fh = H5FL_MALLOC(H5HF_t)))
154
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed for fractal heap info");
155
156
    /* Lock the heap header into memory */
157
0
    if (NULL == (hdr = H5HF__hdr_protect(f, fh_addr, H5AC__NO_FLAGS_SET)))
158
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header");
159
160
    /* Point fractal heap wrapper at header and bump it's ref count */
161
0
    fh->hdr = hdr;
162
0
    if (H5HF__hdr_incr(fh->hdr) < 0)
163
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header");
164
165
    /* Increment # of files using this heap header */
166
0
    if (H5HF__hdr_fuse_incr(fh->hdr) < 0)
167
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL,
168
0
                    "can't increment file reference count on shared heap header");
169
170
    /* Set file pointer for this heap open context */
171
0
    fh->f = f;
172
173
    /* Set the return value */
174
0
    ret_value = fh;
175
176
0
done:
177
0
    if (hdr && H5AC_unprotect(f, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
178
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release fractal heap header");
179
0
    if (!ret_value && fh)
180
0
        if (H5HF_close(fh) < 0)
181
0
            HDONE_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, NULL, "unable to close fractal heap");
182
183
0
    FUNC_LEAVE_NOAPI(ret_value)
184
0
} /* end H5HF_create() */
185
186
/*-------------------------------------------------------------------------
187
 * Function:  H5HF_open
188
 *
189
 * Purpose: Opens an existing fractal heap in the file.
190
 *
191
 * Return:  Pointer to heap wrapper on success
192
 *              NULL on failure
193
 *
194
 *-------------------------------------------------------------------------
195
 */
196
H5HF_t *
197
H5HF_open(H5F_t *f, haddr_t fh_addr)
198
0
{
199
0
    H5HF_t     *fh        = NULL; /* Pointer to new fractal heap */
200
0
    H5HF_hdr_t *hdr       = NULL; /* The fractal heap header information */
201
0
    H5HF_t     *ret_value = NULL; /* Return value */
202
203
0
    FUNC_ENTER_NOAPI(NULL)
204
205
    /*
206
     * Check arguments.
207
     */
208
0
    assert(f);
209
0
    assert(H5_addr_defined(fh_addr));
210
211
    /* Load the heap header into memory */
212
0
    if (NULL == (hdr = H5HF__hdr_protect(f, fh_addr, H5AC__READ_ONLY_FLAG)))
213
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header");
214
215
    /* Check for pending heap deletion */
216
0
    if (hdr->pending_delete)
217
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, NULL, "can't open fractal heap pending deletion");
218
219
    /* Create fractal heap info */
220
0
    if (NULL == (fh = H5FL_MALLOC(H5HF_t)))
221
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed for fractal heap info");
222
223
    /* Point fractal heap wrapper at header */
224
0
    fh->hdr = hdr;
225
0
    if (H5HF__hdr_incr(fh->hdr) < 0)
226
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header");
227
228
    /* Increment # of files using this heap header */
229
0
    if (H5HF__hdr_fuse_incr(fh->hdr) < 0)
230
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL,
231
0
                    "can't increment file reference count on shared heap header");
232
233
    /* Set file pointer for this heap open context */
234
0
    fh->f = f;
235
236
    /* Set the return value */
237
0
    ret_value = fh;
238
239
0
done:
240
0
    if (hdr && H5AC_unprotect(f, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
241
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release fractal heap header");
242
0
    if (!ret_value && fh)
243
0
        if (H5HF_close(fh) < 0)
244
0
            HDONE_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, NULL, "unable to close fractal heap");
245
246
0
    FUNC_LEAVE_NOAPI(ret_value)
247
0
} /* end H5HF_open() */
248
249
/*-------------------------------------------------------------------------
250
 * Function:  H5HF_get_id_len
251
 *
252
 * Purpose: Get the size of IDs for entries in a fractal heap
253
 *
254
 * Return:  SUCCEED/FAIL
255
 *
256
 *-------------------------------------------------------------------------
257
 */
258
herr_t
259
H5HF_get_id_len(H5HF_t *fh, size_t *id_len_p)
260
0
{
261
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
262
263
    /*
264
     * Check arguments.
265
     */
266
0
    assert(fh);
267
0
    assert(id_len_p);
268
269
    /* Retrieve the ID length for entries in this heap */
270
0
    *id_len_p = fh->hdr->id_len;
271
272
0
    FUNC_LEAVE_NOAPI(SUCCEED)
273
0
} /* end H5HF_get_id_len() */
274
275
/*-------------------------------------------------------------------------
276
 * Function:  H5HF_get_heap_addr
277
 *
278
 * Purpose: Get the address of a fractal heap
279
 *
280
 * Return:  SUCCEED/FAIL
281
 *
282
 *-------------------------------------------------------------------------
283
 */
284
herr_t
285
H5HF_get_heap_addr(const H5HF_t *fh, haddr_t *heap_addr_p)
286
0
{
287
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
288
289
    /*
290
     * Check arguments.
291
     */
292
0
    assert(fh);
293
0
    assert(heap_addr_p);
294
295
    /* Retrieve the heap header address for this heap */
296
0
    *heap_addr_p = fh->hdr->heap_addr;
297
298
0
    FUNC_LEAVE_NOAPI(SUCCEED)
299
0
} /* end H5HF_get_heap_addr() */
300
301
/*-------------------------------------------------------------------------
302
 * Function:  H5HF_insert
303
 *
304
 * Purpose: Insert a new object into a fractal heap.
305
 *
306
 * Return:  Non-negative on success (with heap ID of new object
307
 *              filled in), negative on failure
308
 *
309
 *-------------------------------------------------------------------------
310
 */
311
herr_t
312
H5HF_insert(H5HF_t *fh, size_t size, const void *obj, void *id /*out*/)
313
0
{
314
0
    H5HF_hdr_t *hdr       = NULL; /* The fractal heap header information */
315
0
    herr_t      ret_value = SUCCEED;
316
317
0
    FUNC_ENTER_NOAPI(FAIL)
318
319
    /* Sanity check */
320
0
    assert(fh);
321
0
    assert(obj);
322
0
    assert(id);
323
324
    /* Check arguments */
325
0
    if (size == 0)
326
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "can't insert 0-sized objects");
327
328
    /* Set the shared heap header's file context for this operation */
329
0
    fh->hdr->f = fh->f;
330
331
    /* Get the fractal heap header */
332
0
    hdr = fh->hdr;
333
334
    /* Check for 'huge' object */
335
0
    if (size > hdr->max_man_size) {
336
        /* Store 'huge' object in heap
337
         *
338
         * Although not ideal, we can quiet the const warning here because no
339
         * obj pointer that was originally const should ever arrive here.
340
         */
341
0
        H5_WARN_CAST_AWAY_CONST_OFF
342
0
        if (H5HF__huge_insert(hdr, size, (void *)obj, id) < 0)
343
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'huge' object in fractal heap");
344
0
        H5_WARN_CAST_AWAY_CONST_ON
345
0
    } /* end if */
346
    /* Check for 'tiny' object */
347
0
    else if (size <= hdr->tiny_max_len) {
348
        /* Store 'tiny' object in heap */
349
0
        if (H5HF__tiny_insert(hdr, size, obj, id) < 0)
350
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'tiny' object in fractal heap");
351
0
    } /* end if */
352
0
    else {
353
        /* Check if we are in "append only" mode, or if there's enough room for the object */
354
0
        if (hdr->write_once) {
355
0
            HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "'write once' managed blocks not supported yet");
356
0
        } /* end if */
357
0
        else {
358
            /* Allocate space for object in 'managed' heap */
359
0
            if (H5HF__man_insert(hdr, size, obj, id) < 0)
360
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'managed' object in fractal heap");
361
0
        } /* end else */
362
0
    }     /* end else */
363
364
0
done:
365
0
    FUNC_LEAVE_NOAPI(ret_value)
366
0
} /* end H5HF_insert() */
367
368
/*-------------------------------------------------------------------------
369
 * Function:  H5HF_get_obj_len
370
 *
371
 * Purpose: Get the size of an entry in a fractal heap
372
 *
373
 * Return:  SUCCEED/FAIL
374
 *
375
 *-------------------------------------------------------------------------
376
 */
377
herr_t
378
H5HF_get_obj_len(H5HF_t *fh, const void *_id, size_t *obj_len_p)
379
0
{
380
0
    const uint8_t *id = (const uint8_t *)_id; /* Object ID */
381
0
    uint8_t        id_flags;                  /* Heap ID flag bits */
382
0
    herr_t         ret_value = SUCCEED;       /* Return value */
383
384
0
    FUNC_ENTER_NOAPI(FAIL)
385
386
    /*
387
     * Check arguments.
388
     */
389
0
    assert(fh);
390
0
    assert(id);
391
0
    assert(obj_len_p);
392
393
    /* Get the ID flags */
394
0
    id_flags = *id;
395
396
    /* Check for correct heap ID version */
397
0
    if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
398
0
        HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version");
399
400
    /* Set the shared heap header's file context for this operation */
401
0
    fh->hdr->f = fh->f;
402
403
    /* Check type of object in heap */
404
0
    if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
405
0
        if (H5HF__man_get_obj_len(fh->hdr, id, obj_len_p) < 0)
406
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'managed' object's length");
407
0
    } /* end if */
408
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
409
0
        if (H5HF__huge_get_obj_len(fh->hdr, id, obj_len_p) < 0)
410
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'huge' object's length");
411
0
    } /* end if */
412
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
413
0
        if (H5HF__tiny_get_obj_len(fh->hdr, id, obj_len_p) < 0)
414
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'tiny' object's length");
415
0
    } /* end if */
416
0
    else {
417
0
        fprintf(stderr, "%s: Heap ID type not supported yet!\n", __func__);
418
0
        HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet");
419
0
    } /* end else */
420
421
0
done:
422
0
    FUNC_LEAVE_NOAPI(ret_value)
423
0
} /* end H5HF_get_obj_len() */
424
425
/*-------------------------------------------------------------------------
426
 * Function:  H5HF_get_obj_off
427
 *
428
 * Purpose: Get the offset of an entry in a fractal heap
429
 *
430
 * Return:  SUCCEED/FAIL
431
 *
432
 *-------------------------------------------------------------------------
433
 */
434
herr_t
435
H5HF_get_obj_off(H5HF_t *fh, const void *_id, hsize_t *obj_off_p)
436
0
{
437
0
    const uint8_t *id = (const uint8_t *)_id; /* Object ID */
438
0
    uint8_t        id_flags;                  /* Heap ID flag bits */
439
0
    herr_t         ret_value = SUCCEED;       /* Return value */
440
441
0
    FUNC_ENTER_NOAPI(FAIL)
442
443
    /*
444
     * Check arguments.
445
     */
446
0
    assert(fh);
447
0
    assert(id);
448
0
    assert(obj_off_p);
449
450
    /* Get the ID flags */
451
0
    id_flags = *id;
452
453
    /* Check for correct heap ID version */
454
0
    if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
455
0
        HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version");
456
457
    /* Set the shared heap header's file context for this operation */
458
0
    fh->hdr->f = fh->f;
459
460
    /* Check type of object in heap */
461
0
    if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
462
0
        H5HF__man_get_obj_off(fh->hdr, id, obj_off_p);
463
0
    } /* end if */
464
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
465
        /* Huge objects are located directly in the file */
466
0
        if (H5HF__huge_get_obj_off(fh->hdr, id, obj_off_p) < 0)
467
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'huge' object's offset");
468
0
    } /* end if */
469
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
470
        /* Tiny objects are not stored in the heap */
471
0
        *obj_off_p = (hsize_t)0;
472
0
    } /* end if */
473
0
    else {
474
0
        fprintf(stderr, "%s: Heap ID type not supported yet!\n", __func__);
475
0
        HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet");
476
0
    } /* end else */
477
478
0
done:
479
0
    FUNC_LEAVE_NOAPI(ret_value)
480
0
} /* end H5HF_get_obj_off() */
481
482
/*-------------------------------------------------------------------------
483
 * Function:  H5HF_read
484
 *
485
 * Purpose: Read an object from a fractal heap into a buffer
486
 *
487
 * Return:  SUCCEED/FAIL
488
 *
489
 *-------------------------------------------------------------------------
490
 */
491
herr_t
492
H5HF_read(H5HF_t *fh, const void *_id, void *obj /*out*/)
493
0
{
494
0
    const uint8_t *id = (const uint8_t *)_id; /* Object ID */
495
0
    uint8_t        id_flags;                  /* Heap ID flag bits */
496
0
    herr_t         ret_value = SUCCEED;       /* Return value */
497
498
0
    FUNC_ENTER_NOAPI(FAIL)
499
500
    /*
501
     * Check arguments.
502
     */
503
0
    assert(fh);
504
0
    assert(id);
505
0
    assert(obj);
506
507
    /* Get the ID flags */
508
0
    id_flags = *id;
509
510
    /* Check for correct heap ID version */
511
0
    if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
512
0
        HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version");
513
514
    /* Set the shared heap header's file context for this operation */
515
0
    fh->hdr->f = fh->f;
516
517
    /* Check type of object in heap */
518
0
    if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
519
        /* Read object from managed heap blocks */
520
0
        if (H5HF__man_read(fh->hdr, id, obj) < 0)
521
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read object from fractal heap");
522
0
    } /* end if */
523
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
524
        /* Read 'huge' object from file */
525
0
        if (H5HF__huge_read(fh->hdr, id, obj) < 0)
526
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read 'huge' object from fractal heap");
527
0
    } /* end if */
528
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
529
        /* Read 'tiny' object from file */
530
0
        if (H5HF__tiny_read(fh->hdr, id, obj) < 0)
531
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read 'tiny' object from fractal heap");
532
0
    } /* end if */
533
0
    else {
534
0
        fprintf(stderr, "%s: Heap ID type not supported yet!\n", __func__);
535
0
        HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet");
536
0
    } /* end else */
537
538
0
done:
539
0
    FUNC_LEAVE_NOAPI(ret_value)
540
0
} /* end H5HF_read() */
541
542
/*-------------------------------------------------------------------------
543
 * Function:  H5HF_write
544
 *
545
 * Purpose: Write an object from a buffer into a fractal heap
546
 *
547
 * Notes: Writing objects in "managed" heap blocks is only storage
548
 *    method currently supported.  (Which could be expanded to
549
 *    'huge' and 'tiny' objects, with some work)
550
 *
551
 *    Also, assumes that the 'op' routine modifies the data, and
552
 *    marks data to be written back to disk, even if 'op' routine
553
 *    didn't actually change anything.  (Which could be modified
554
 *    to pass "did_modify" flag to callback, if necessary)
555
 *
556
 *    Also, assumes that object to write is same size as object in
557
 *    heap.
558
 *
559
 * Return:  SUCCEED/FAIL
560
 *
561
 *-------------------------------------------------------------------------
562
 */
563
herr_t
564
H5HF_write(H5HF_t *fh, void *_id, bool H5_ATTR_UNUSED *id_changed, const void *obj)
565
0
{
566
0
    uint8_t *id = (uint8_t *)_id; /* Object ID */
567
0
    uint8_t  id_flags;            /* Heap ID flag bits */
568
0
    herr_t   ret_value = SUCCEED; /* Return value */
569
570
0
    FUNC_ENTER_NOAPI(FAIL)
571
572
    /*
573
     * Check arguments.
574
     */
575
0
    assert(fh);
576
0
    assert(id);
577
0
    assert(obj);
578
579
    /* Get the ID flags */
580
0
    id_flags = *id;
581
582
    /* Check for correct heap ID version */
583
0
    if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
584
0
        HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version");
585
586
    /* Set the shared heap header's file context for this operation */
587
0
    fh->hdr->f = fh->f;
588
589
    /* Check type of object in heap */
590
0
    if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
591
        /* Operate on object from managed heap blocks */
592
        /* (ID can't change and modifying object is "easy" to manage) */
593
0
        if (H5HF__man_write(fh->hdr, id, obj) < 0)
594
0
            HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'managed' heap object");
595
0
    } /* end if */
596
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
597
        /* Operate on "huge" object */
598
0
        if (H5HF__huge_write(fh->hdr, id, obj) < 0)
599
0
            HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'huge' heap object");
600
0
    } /* end if */
601
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
602
        /* Check for writing a 'tiny' object */
603
        /* (which isn't supported yet - ID will change) */
604
0
        HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "modifying 'tiny' object not supported yet");
605
0
    } /* end if */
606
0
    else {
607
0
        fprintf(stderr, "%s: Heap ID type not supported yet!\n", __func__);
608
0
        HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet");
609
0
    } /* end else */
610
611
0
done:
612
0
    FUNC_LEAVE_NOAPI(ret_value)
613
0
} /* end H5HF_write() */
614
615
/*-------------------------------------------------------------------------
616
 * Function:  H5HF_op
617
 *
618
 * Purpose: Perform an operation directly on a heap object
619
 *
620
 * Note:  The library routines currently assume that the 'op' callback
621
 *    won't modify the object.  This can easily be changed later for
622
 *    "managed" heap objects, and, with some difficulty, for 'huge'
623
 *    and 'tiny' heap objects.
624
 *
625
 * Return:  SUCCEED/FAIL
626
 *
627
 *-------------------------------------------------------------------------
628
 */
629
herr_t
630
H5HF_op(H5HF_t *fh, const void *_id, H5HF_operator_t op, void *op_data)
631
0
{
632
0
    const uint8_t *id = (const uint8_t *)_id; /* Object ID */
633
0
    uint8_t        id_flags;                  /* Heap ID flag bits */
634
0
    herr_t         ret_value = SUCCEED;       /* Return value */
635
636
0
    FUNC_ENTER_NOAPI(FAIL)
637
638
    /*
639
     * Check arguments.
640
     */
641
0
    assert(fh);
642
0
    assert(id);
643
0
    assert(op);
644
645
    /* Get the ID flags */
646
0
    id_flags = *id;
647
648
    /* Check for correct heap ID version */
649
0
    if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
650
0
        HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version");
651
652
    /* Set the shared heap header's file context for this operation */
653
0
    fh->hdr->f = fh->f;
654
655
    /* Check type of object in heap */
656
0
    if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
657
        /* Operate on object from managed heap blocks */
658
0
        if (H5HF__man_op(fh->hdr, id, op, op_data) < 0)
659
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on object from fractal heap");
660
0
    } /* end if */
661
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
662
        /* Operate on 'huge' object from file */
663
0
        if (H5HF__huge_op(fh->hdr, id, op, op_data) < 0)
664
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on 'huge' object from fractal heap");
665
0
    } /* end if */
666
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
667
        /* Operate on 'tiny' object from file */
668
0
        if (H5HF__tiny_op(fh->hdr, id, op, op_data) < 0)
669
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on 'tiny' object from fractal heap");
670
0
    } /* end if */
671
0
    else {
672
0
        fprintf(stderr, "%s: Heap ID type not supported yet!\n", __func__);
673
0
        HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet");
674
0
    } /* end else */
675
676
0
done:
677
0
    FUNC_LEAVE_NOAPI(ret_value)
678
0
} /* end H5HF_op() */
679
680
/*-------------------------------------------------------------------------
681
 * Function:  H5HF_remove
682
 *
683
 * Purpose: Remove an object from a fractal heap
684
 *
685
 * Return:  SUCCEED/FAIL
686
 *
687
 *-------------------------------------------------------------------------
688
 */
689
herr_t
690
H5HF_remove(H5HF_t *fh, const void *_id)
691
0
{
692
0
    const uint8_t *id = (const uint8_t *)_id; /* Object ID */
693
0
    uint8_t        id_flags;                  /* Heap ID flag bits */
694
0
    herr_t         ret_value = SUCCEED;       /* Return value */
695
696
0
    FUNC_ENTER_NOAPI(FAIL)
697
698
    /*
699
     * Check arguments.
700
     */
701
0
    assert(fh);
702
0
    assert(fh->hdr);
703
0
    assert(id);
704
705
    /* Get the ID flags */
706
0
    id_flags = *id;
707
708
    /* Check for correct heap ID version */
709
0
    if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
710
0
        HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version");
711
712
    /* Set the shared heap header's file context for this operation */
713
0
    fh->hdr->f = fh->f;
714
715
    /* Check type of object in heap */
716
0
    if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
717
        /* Remove object from managed heap blocks */
718
0
        if (H5HF__man_remove(fh->hdr, id) < 0)
719
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from fractal heap");
720
0
    } /* end if */
721
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
722
        /* Remove 'huge' object from file & v2 B-tree tracker */
723
0
        if (H5HF__huge_remove(fh->hdr, id) < 0)
724
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove 'huge' object from fractal heap");
725
0
    } /* end if */
726
0
    else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
727
        /* Remove 'tiny' object from heap statistics */
728
0
        if (H5HF__tiny_remove(fh->hdr, id) < 0)
729
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove 'tiny' object from fractal heap");
730
0
    } /* end if */
731
0
    else {
732
0
        fprintf(stderr, "%s: Heap ID type not supported yet!\n", __func__);
733
0
        HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet");
734
0
    } /* end else */
735
736
0
done:
737
0
    FUNC_LEAVE_NOAPI(ret_value)
738
0
} /* end H5HF_remove() */
739
740
/*-------------------------------------------------------------------------
741
 * Function:  H5HF_close
742
 *
743
 * Purpose: Close a fractal heap
744
 *
745
 * Return:  SUCCEED/FAIL
746
 *
747
 *-------------------------------------------------------------------------
748
 */
749
herr_t
750
H5HF_close(H5HF_t *fh)
751
0
{
752
0
    bool    pending_delete = false;       /* Whether the heap is pending deletion */
753
0
    haddr_t heap_addr      = HADDR_UNDEF; /* Address of heap (for deletion) */
754
0
    herr_t  ret_value      = SUCCEED;     /* Return value */
755
756
0
    FUNC_ENTER_NOAPI(FAIL)
757
758
    /*
759
     * Check arguments.
760
     */
761
0
    assert(fh);
762
763
    /* Decrement file reference & check if this is the last open fractal heap using the shared heap header */
764
0
    if (0 == H5HF__hdr_fuse_decr(fh->hdr)) {
765
        /* Set the shared heap header's file context for this operation */
766
0
        fh->hdr->f = fh->f;
767
768
        /* Close the free space information */
769
        /* (Can't put this in header "destroy" routine, because it has
770
         *      pointers to indirect blocks in the heap, which would create
771
         *      a reference loop and the objects couldn't be removed from
772
         *      the metadata cache - QAK)
773
         */
774
0
        if (H5HF__space_close(fh->hdr) < 0)
775
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info");
776
777
        /* Reset the block iterator, if necessary */
778
        /* (Can't put this in header "destroy" routine, because it has
779
         *      pointers to indirect blocks in the heap, which would create
780
         *      a reference loop and the objects couldn't be removed from
781
         *      the metadata cache - QAK)
782
         */
783
0
        if (H5HF__man_iter_ready(&fh->hdr->next_block))
784
0
            if (H5HF__man_iter_reset(&fh->hdr->next_block) < 0)
785
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator");
786
787
        /* Shut down the huge object information */
788
        /* (Can't put this in header "destroy" routine, because it has
789
         *      has the address of an object in the file, which might be
790
         *      modified by the shutdown routine - QAK)
791
         */
792
0
        if (H5HF__huge_term(fh->hdr) < 0)
793
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release 'huge' object info");
794
795
        /* Check for pending heap deletion */
796
0
        if (fh->hdr->pending_delete) {
797
            /* Set local info, so heap deletion can occur after decrementing the
798
             *  header's ref count
799
             */
800
0
            pending_delete = true;
801
0
            heap_addr      = fh->hdr->heap_addr;
802
0
        } /* end if */
803
0
    }     /* end if */
804
805
    /* Decrement the reference count on the heap header */
806
    /* (don't put in H5HF__hdr_fuse_decr() as the heap header may be evicted
807
     *  immediately -QAK)
808
     */
809
0
    if (H5HF__hdr_decr(fh->hdr) < 0)
810
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header");
811
812
    /* Check for pending heap deletion */
813
0
    if (pending_delete) {
814
0
        H5HF_hdr_t *hdr; /* Another pointer to fractal heap header */
815
816
        /* Lock the heap header into memory */
817
0
        if (NULL == (hdr = H5HF__hdr_protect(fh->f, heap_addr, H5AC__NO_FLAGS_SET)))
818
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header");
819
820
        /* Delete heap, starting with header (unprotects header) */
821
0
        if (H5HF__hdr_delete(hdr) < 0)
822
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap");
823
0
    } /* end if */
824
825
0
done:
826
    /* Release the fractal heap wrapper */
827
0
    fh = H5FL_FREE(H5HF_t, fh);
828
829
0
    FUNC_LEAVE_NOAPI(ret_value)
830
0
} /* end H5HF_close() */
831
832
/*-------------------------------------------------------------------------
833
 * Function:  H5HF_delete
834
 *
835
 * Purpose: Delete a fractal heap
836
 *
837
 * Return:  SUCCEED/FAIL
838
 *
839
 *-------------------------------------------------------------------------
840
 */
841
herr_t
842
H5HF_delete(H5F_t *f, haddr_t fh_addr)
843
0
{
844
0
    H5HF_hdr_t *hdr       = NULL;    /* The fractal heap header information */
845
0
    herr_t      ret_value = SUCCEED; /* Return value */
846
847
0
    FUNC_ENTER_NOAPI(FAIL)
848
849
    /*
850
     * Check arguments.
851
     */
852
0
    assert(f);
853
0
    assert(H5_addr_defined(fh_addr));
854
855
    /* Lock the heap header into memory */
856
0
    if (NULL == (hdr = H5HF__hdr_protect(f, fh_addr, H5AC__NO_FLAGS_SET)))
857
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header");
858
859
    /* Check for files using shared heap header */
860
0
    if (hdr->file_rc)
861
0
        hdr->pending_delete = true;
862
0
    else {
863
        /* Delete heap now, starting with header (unprotects header) */
864
0
        if (H5HF__hdr_delete(hdr) < 0)
865
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap");
866
0
        hdr = NULL;
867
0
    } /* end if */
868
869
0
done:
870
    /* Unprotect the header, if an error occurred */
871
0
    if (hdr && H5AC_unprotect(f, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
872
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header");
873
874
0
    FUNC_LEAVE_NOAPI(ret_value)
875
0
} /* end H5HF_delete() */