Coverage Report

Created: 2025-12-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5HFman.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:   H5HFman.c
16
 *
17
 * Purpose:   "Managed" object routines for fractal heaps.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions     */
32
#include "H5Eprivate.h"  /* Error handling        */
33
#include "H5HFpkg.h"     /* Fractal heaps     */
34
#include "H5MMprivate.h" /* Memory management     */
35
36
/****************/
37
/* Local Macros */
38
/****************/
39
40
/* Macro to check if we can apply all filters in the pipeline.  Use whenever
41
 * performing a modification operation */
42
#define H5HF_MAN_WRITE_CHECK_PLINE(HDR)                                                                      \
43
0
    {                                                                                                        \
44
0
        if (!((HDR)->checked_filters)) {                                                                     \
45
0
            if ((HDR)->pline.nused)                                                                          \
46
0
                if (H5Z_can_apply_direct(&((HDR)->pline)) < 0)                                               \
47
0
                    HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "I/O filters can't operate on this heap");     \
48
0
                                                                                                             \
49
0
            (HDR)->checked_filters = true;                                                                   \
50
0
        } /* end if */                                                                                       \
51
0
    }
52
53
/******************/
54
/* Local Typedefs */
55
/******************/
56
57
/********************/
58
/* Package Typedefs */
59
/********************/
60
61
/********************/
62
/* Local Prototypes */
63
/********************/
64
static herr_t H5HF__man_op_real(H5HF_hdr_t *hdr, const uint8_t *id, H5HF_operator_t op, void *op_data,
65
                                unsigned op_flags);
66
67
/*********************/
68
/* Package Variables */
69
/*********************/
70
71
/*****************************/
72
/* Library Private Variables */
73
/*****************************/
74
75
/*******************/
76
/* Local Variables */
77
/*******************/
78
79
/*-------------------------------------------------------------------------
80
 * Function:  H5HF__man_insert
81
 *
82
 * Purpose: Insert an object in a managed direct block
83
 *
84
 * Return:  SUCCEED/FAIL
85
 *
86
 *-------------------------------------------------------------------------
87
 */
88
herr_t
89
H5HF__man_insert(H5HF_hdr_t *hdr, size_t obj_size, const void *obj, void *_id)
90
0
{
91
0
    H5HF_free_section_t *sec_node    = NULL;        /* Pointer to free space section */
92
0
    H5HF_direct_t       *dblock      = NULL;        /* Pointer to direct block to modify */
93
0
    haddr_t              dblock_addr = HADDR_UNDEF; /* Direct block address */
94
0
    size_t               dblock_size;               /* Direct block size */
95
0
    uint8_t             *id = (uint8_t *)_id;       /* Pointer to ID buffer */
96
0
    size_t               blk_off;                   /* Offset of object within block */
97
0
    htri_t               node_found;                /* Whether an existing free list node was found */
98
0
    herr_t               ret_value = SUCCEED;       /* Return value */
99
100
0
    FUNC_ENTER_PACKAGE
101
102
    /*
103
     * Check arguments.
104
     */
105
0
    assert(hdr);
106
0
    assert(obj_size > 0);
107
0
    assert(obj);
108
0
    assert(id);
109
110
    /* Check pipeline */
111
0
    H5HF_MAN_WRITE_CHECK_PLINE(hdr)
112
113
    /* Look for free space */
114
0
    if ((node_found = H5HF__space_find(hdr, (hsize_t)obj_size, &sec_node)) < 0)
115
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't locate free space in fractal heap");
116
117
    /* If we didn't find a node, go create a direct block big enough to hold the requested block */
118
0
    if (!node_found)
119
        /* Allocate direct block big enough to hold requested size */
120
0
        if (H5HF__man_dblock_new(hdr, obj_size, &sec_node) < 0)
121
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "can't create fractal heap direct block");
122
123
    /* Check for row section */
124
0
    if (sec_node->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW ||
125
0
        sec_node->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW) {
126
127
        /* Allocate 'single' selection out of 'row' selection */
128
0
        if (H5HF__man_iblock_alloc_row(hdr, &sec_node) < 0)
129
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't break up row section");
130
0
    } /* end if */
131
0
    assert(sec_node->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
132
133
    /* Check for 'single' section being serialized */
134
0
    if (sec_node->sect_info.state == H5FS_SECT_SERIALIZED)
135
0
        if (H5HF__sect_single_revive(hdr, sec_node) < 0)
136
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section");
137
0
    assert(sec_node->sect_info.state == H5FS_SECT_LIVE);
138
139
    /* Retrieve direct block address from section */
140
0
    if (H5HF__sect_single_dblock_info(hdr, sec_node, &dblock_addr, &dblock_size) < 0)
141
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve direct block information");
142
143
    /* Lock direct block */
144
0
    if (NULL == (dblock = H5HF__man_dblock_protect(hdr, dblock_addr, dblock_size, sec_node->u.single.parent,
145
0
                                                   sec_node->u.single.par_entry, H5AC__NO_FLAGS_SET)))
146
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block");
147
148
    /* Insert object into block */
149
150
    /* Get the offset of the object within the block */
151
0
    H5_CHECK_OVERFLOW((sec_node->sect_info.addr - dblock->block_off), hsize_t, size_t);
152
0
    blk_off = (size_t)(sec_node->sect_info.addr - dblock->block_off);
153
154
    /* Sanity checks */
155
0
    assert(sec_node->sect_info.size >= obj_size);
156
157
    /* Reduce (& possibly re-add) single section */
158
0
    if (H5HF__sect_single_reduce(hdr, sec_node, obj_size) < 0)
159
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce single section node");
160
0
    sec_node = NULL;
161
162
    /* Encode the object in the block */
163
0
    {
164
0
        uint8_t *p; /* Temporary pointer to obj info in block */
165
166
        /* Point to location for object */
167
0
        p = dblock->blk + blk_off;
168
169
        /* Copy the object's data into the heap */
170
0
        H5MM_memcpy(p, obj, obj_size);
171
0
        p += obj_size;
172
173
        /* Sanity check */
174
0
        assert((size_t)(p - (dblock->blk + blk_off)) == obj_size);
175
0
    } /* end block */
176
177
    /* Set the heap ID for the new object (heap offset & obj length) */
178
0
    H5HF_MAN_ID_ENCODE(id, hdr, (dblock->block_off + blk_off), obj_size);
179
180
    /* Update statistics about heap */
181
0
    hdr->man_nobjs++;
182
183
    /* Reduce space available in heap (marks header dirty) */
184
0
    if (H5HF__hdr_adj_free(hdr, -(ssize_t)obj_size) < 0)
185
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't adjust free space for heap");
186
187
0
done:
188
    /* Release section node on error */
189
0
    if (ret_value < 0)
190
0
        if (sec_node && H5HF__sect_single_free((H5FS_section_info_t *)sec_node) < 0)
191
0
            HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release section node");
192
193
    /* Release the direct block (marked as dirty) */
194
0
    if (dblock && H5AC_unprotect(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__DIRTIED_FLAG) < 0)
195
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block");
196
197
0
    FUNC_LEAVE_NOAPI(ret_value)
198
0
} /* end H5HF__man_insert() */
199
200
/*-------------------------------------------------------------------------
201
 * Function:    H5HF__man_get_obj_len
202
 *
203
 * Purpose:     Get the size of a managed heap object
204
 *
205
 * Return:      SUCCEED (Can't fail)
206
 *
207
 *-------------------------------------------------------------------------
208
 */
209
herr_t
210
H5HF__man_get_obj_len(H5HF_hdr_t *hdr, const uint8_t *id, size_t *obj_len_p)
211
0
{
212
213
0
    FUNC_ENTER_PACKAGE_NOERR
214
215
    /*
216
     * Check arguments.
217
     */
218
0
    assert(hdr);
219
0
    assert(id);
220
0
    assert(obj_len_p);
221
222
    /* Skip over the flag byte */
223
0
    id++;
224
225
    /* Skip over object offset */
226
0
    id += hdr->heap_off_size;
227
228
    /* Retrieve the entry length */
229
0
    UINT64DECODE_VAR(id, *obj_len_p, hdr->heap_len_size);
230
231
0
    FUNC_LEAVE_NOAPI(SUCCEED)
232
0
} /* end H5HF__man_get_obj_len() */
233
234
/*-------------------------------------------------------------------------
235
 * Function:    H5HF__man_get_obj_off
236
 *
237
 * Purpose:     Get the offset of a managed heap object
238
 *
239
 * Return:      SUCCEED (Can't fail)
240
 *
241
 *-------------------------------------------------------------------------
242
 */
243
void
244
H5HF__man_get_obj_off(const H5HF_hdr_t *hdr, const uint8_t *id, hsize_t *obj_off_p)
245
0
{
246
0
    FUNC_ENTER_PACKAGE_NOERR
247
248
    /*
249
     * Check arguments.
250
     */
251
0
    assert(hdr);
252
0
    assert(id);
253
0
    assert(obj_off_p);
254
255
    /* Skip over the flag byte */
256
0
    id++;
257
258
    /* Skip over object offset */
259
0
    UINT64DECODE_VAR(id, *obj_off_p, hdr->heap_off_size);
260
261
0
    FUNC_LEAVE_NOAPI_VOID
262
0
} /* end H5HF__man_get_obj_off() */
263
264
/*-------------------------------------------------------------------------
265
 * Function:  H5HF__man_op_real
266
 *
267
 * Purpose: Internal routine to perform an operation on a managed heap
268
 *              object
269
 *
270
 * Return:  SUCCEED/FAIL
271
 *
272
 *-------------------------------------------------------------------------
273
 */
274
static herr_t
275
H5HF__man_op_real(H5HF_hdr_t *hdr, const uint8_t *id, H5HF_operator_t op, void *op_data, unsigned op_flags)
276
0
{
277
0
    H5HF_direct_t *dblock = NULL;       /* Pointer to direct block to query */
278
0
    unsigned       dblock_access_flags; /* Access method for direct block */
279
                                        /* must equal either
280
                                         * H5AC__NO_FLAGS_SET or
281
                                         * H5AC__READ_ONLY_FLAG
282
                                         */
283
0
    haddr_t  dblock_addr = HADDR_UNDEF; /* Direct block address */
284
0
    size_t   dblock_size;               /* Direct block size */
285
0
    unsigned dblock_cache_flags = 0;    /* Flags for unprotecting direct block */
286
0
    hsize_t  obj_off;                   /* Object's offset in heap */
287
0
    size_t   obj_len;                   /* Object's length in heap */
288
0
    size_t   blk_off;                   /* Offset of object in block */
289
0
    uint8_t *p;                         /* Temporary pointer to obj info in block */
290
0
    herr_t   ret_value = SUCCEED;       /* Return value */
291
292
0
    FUNC_ENTER_PACKAGE
293
294
    /*
295
     * Check arguments.
296
     */
297
0
    assert(hdr);
298
0
    assert(id);
299
0
    assert(op);
300
301
    /* Set the access mode for the direct block */
302
0
    if (op_flags & H5HF_OP_MODIFY) {
303
        /* Check pipeline */
304
0
        H5HF_MAN_WRITE_CHECK_PLINE(hdr)
305
306
0
        dblock_access_flags = H5AC__NO_FLAGS_SET;
307
0
        dblock_cache_flags  = H5AC__DIRTIED_FLAG;
308
0
    } /* end if */
309
0
    else {
310
0
        dblock_access_flags = H5AC__READ_ONLY_FLAG;
311
0
        dblock_cache_flags  = H5AC__NO_FLAGS_SET;
312
0
    } /* end else */
313
314
    /* Skip over the flag byte */
315
0
    id++;
316
317
    /* Decode the object offset within the heap & its length */
318
0
    UINT64DECODE_VAR(id, obj_off, hdr->heap_off_size);
319
0
    UINT64DECODE_VAR(id, obj_len, hdr->heap_len_size);
320
321
    /* Check for bad offset or length */
322
0
    if (obj_off == 0)
323
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap offset");
324
0
    if (obj_off > hdr->man_size)
325
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object offset too large");
326
0
    if (obj_len == 0)
327
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap object size");
328
0
    if (obj_len > hdr->man_dtable.cparam.max_direct_size)
329
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object size too large for direct block");
330
0
    if (obj_len > hdr->max_man_size)
331
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object should be standalone");
332
333
    /* Check for root direct block */
334
0
    if (hdr->man_dtable.curr_root_rows == 0) {
335
        /* Set direct block info */
336
0
        dblock_addr = hdr->man_dtable.table_addr;
337
0
        dblock_size = hdr->man_dtable.cparam.start_block_size;
338
339
        /* Lock direct block */
340
0
        if (NULL ==
341
0
            (dblock = H5HF__man_dblock_protect(hdr, dblock_addr, dblock_size, NULL, 0, dblock_access_flags)))
342
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block");
343
0
    } /* end if */
344
0
    else {
345
0
        H5HF_indirect_t *iblock;      /* Pointer to indirect block */
346
0
        bool             did_protect; /* Whether we protected the indirect block or not */
347
0
        unsigned         entry;       /* Entry of block */
348
349
        /* Look up indirect block containing direct block */
350
0
        if (H5HF__man_dblock_locate(hdr, obj_off, &iblock, &entry, &did_protect, H5AC__READ_ONLY_FLAG) < 0)
351
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section");
352
353
        /* Set direct block info */
354
0
        dblock_addr = iblock->ents[entry].addr;
355
0
        H5_CHECK_OVERFLOW((hdr->man_dtable.row_block_size[entry / hdr->man_dtable.cparam.width]), hsize_t,
356
0
                          size_t);
357
0
        dblock_size = (size_t)hdr->man_dtable.row_block_size[entry / hdr->man_dtable.cparam.width];
358
359
        /* Check for offset of invalid direct block */
360
0
        if (!H5_addr_defined(dblock_addr)) {
361
            /* Unlock indirect block */
362
0
            if (H5HF__man_iblock_unprotect(iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
363
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL,
364
0
                            "unable to release fractal heap indirect block");
365
366
0
            HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap ID not in allocated direct block");
367
0
        } /* end if */
368
369
        /* Lock direct block */
370
0
        if (NULL == (dblock = H5HF__man_dblock_protect(hdr, dblock_addr, dblock_size, iblock, entry,
371
0
                                                       dblock_access_flags))) {
372
            /* Unlock indirect block */
373
0
            if (H5HF__man_iblock_unprotect(iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
374
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL,
375
0
                            "unable to release fractal heap indirect block");
376
377
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block");
378
0
        } /* end if */
379
380
        /* Unlock indirect block */
381
0
        if (H5HF__man_iblock_unprotect(iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
382
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block");
383
0
        iblock = NULL;
384
0
    } /* end else */
385
386
    /* Compute offset of object within block */
387
0
    assert((obj_off - dblock->block_off) < (hsize_t)dblock_size);
388
0
    blk_off = (size_t)(obj_off - dblock->block_off);
389
390
    /* Check for object's offset in the direct block prefix information */
391
0
    if (blk_off < (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr))
392
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object located in prefix of direct block");
393
394
    /* Check for object's length overrunning the end of the direct block */
395
0
    if ((blk_off + obj_len) > dblock_size)
396
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object overruns end of direct block");
397
398
    /* Point to location for object */
399
0
    p = dblock->blk + blk_off;
400
401
    /* Call the user's 'op' callback */
402
0
    if (op(p, obj_len, op_data) < 0)
403
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "application's callback failed");
404
405
0
done:
406
    /* Unlock direct block */
407
0
    if (dblock && H5AC_unprotect(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, dblock_cache_flags) < 0)
408
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block");
409
410
0
    FUNC_LEAVE_NOAPI(ret_value)
411
0
} /* end H5HF__man_op_real() */
412
413
/*-------------------------------------------------------------------------
414
 * Function:  H5HF__man_read
415
 *
416
 * Purpose: Read an object from a managed heap
417
 *
418
 * Return:  SUCCEED/FAIL
419
 *
420
 *-------------------------------------------------------------------------
421
 */
422
herr_t
423
H5HF__man_read(H5HF_hdr_t *hdr, const uint8_t *id, void *obj)
424
0
{
425
0
    herr_t ret_value = SUCCEED; /* Return value */
426
427
0
    FUNC_ENTER_PACKAGE
428
429
    /*
430
     * Check arguments.
431
     */
432
0
    assert(hdr);
433
0
    assert(id);
434
0
    assert(obj);
435
436
    /* Call the internal 'op' routine routine */
437
0
    if (H5HF__man_op_real(hdr, id, H5HF__op_read, obj, 0) < 0)
438
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object");
439
440
0
done:
441
0
    FUNC_LEAVE_NOAPI(ret_value)
442
0
} /* end H5HF__man_read() */
443
444
/*-------------------------------------------------------------------------
445
 * Function:  H5HF__man_write
446
 *
447
 * Purpose: Write an object to a managed heap
448
 *
449
 * Return:  SUCCEED/FAIL
450
 *
451
 *-------------------------------------------------------------------------
452
 */
453
herr_t
454
H5HF__man_write(H5HF_hdr_t *hdr, const uint8_t *id, const void *obj)
455
0
{
456
0
    herr_t ret_value = SUCCEED; /* Return value */
457
458
0
    FUNC_ENTER_PACKAGE
459
460
    /*
461
     * Check arguments.
462
     */
463
0
    assert(hdr);
464
0
    assert(id);
465
0
    assert(obj);
466
467
    /* Call the internal 'op' routine routine
468
     *
469
     * In this case, the callback operation needs to modify the obj buffer that
470
     * was passed in as const. We quiet the warning here because an obj pointer
471
     * that was originally const should *never* arrive here.
472
     */
473
0
    H5_WARN_CAST_AWAY_CONST_OFF
474
0
    if (H5HF__man_op_real(hdr, id, H5HF__op_write, (void *)obj, H5HF_OP_MODIFY) < 0)
475
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object");
476
0
    H5_WARN_CAST_AWAY_CONST_ON
477
478
0
done:
479
0
    FUNC_LEAVE_NOAPI(ret_value)
480
0
} /* end H5HF__man_write() */
481
482
/*-------------------------------------------------------------------------
483
 * Function:  H5HF__man_op
484
 *
485
 * Purpose: Operate directly on an object from a managed heap
486
 *
487
 * Return:  SUCCEED/FAIL
488
 *
489
 *-------------------------------------------------------------------------
490
 */
491
herr_t
492
H5HF__man_op(H5HF_hdr_t *hdr, const uint8_t *id, H5HF_operator_t op, void *op_data)
493
0
{
494
0
    herr_t ret_value = SUCCEED; /* Return value */
495
496
0
    FUNC_ENTER_PACKAGE
497
498
    /*
499
     * Check arguments.
500
     */
501
0
    assert(hdr);
502
0
    assert(id);
503
0
    assert(op);
504
505
    /* Call the internal 'op' routine routine */
506
0
    if (H5HF__man_op_real(hdr, id, op, op_data, 0) < 0)
507
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object");
508
509
0
done:
510
0
    FUNC_LEAVE_NOAPI(ret_value)
511
0
} /* end H5HF__man_op() */
512
513
/*-------------------------------------------------------------------------
514
 * Function:  H5HF__man_remove
515
 *
516
 * Purpose: Remove an object from a managed heap
517
 *
518
 * Return:  SUCCEED/FAIL
519
 *
520
 *-------------------------------------------------------------------------
521
 */
522
herr_t
523
H5HF__man_remove(H5HF_hdr_t *hdr, const uint8_t *id)
524
0
{
525
0
    H5HF_free_section_t *sec_node    = NULL;  /* Pointer to free space section for block */
526
0
    H5HF_indirect_t     *iblock      = NULL;  /* Pointer to indirect block */
527
0
    bool                 did_protect = false; /* Whether we protected the indirect block or not */
528
0
    hsize_t              obj_off;             /* Object's offset in heap */
529
0
    size_t               obj_len;             /* Object's length in heap */
530
0
    size_t               dblock_size;         /* Direct block size */
531
0
    hsize_t              dblock_block_off;    /* Offset of the direct block within the heap's address space */
532
0
    unsigned             dblock_entry;        /* Entry of direct block in parent indirect block */
533
0
    size_t               blk_off;             /* Offset of object in block */
534
0
    herr_t               ret_value = SUCCEED; /* Return value */
535
536
0
    FUNC_ENTER_PACKAGE
537
538
    /*
539
     * Check arguments.
540
     */
541
0
    assert(hdr);
542
0
    assert(id);
543
544
    /* Check pipeline */
545
0
    H5HF_MAN_WRITE_CHECK_PLINE(hdr)
546
547
    /* Skip over the flag byte */
548
0
    id++;
549
550
    /* Decode the object offset within the heap & it's length */
551
0
    UINT64DECODE_VAR(id, obj_off, hdr->heap_off_size);
552
0
    UINT64DECODE_VAR(id, obj_len, hdr->heap_len_size);
553
554
    /* Check for bad offset or length */
555
0
    if (obj_off == 0)
556
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap offset");
557
0
    if (obj_off > hdr->man_size)
558
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object offset too large");
559
0
    if (obj_len == 0)
560
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap object size");
561
0
    if (obj_len > hdr->man_dtable.cparam.max_direct_size)
562
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object size too large for direct block");
563
0
    if (obj_len > hdr->max_man_size)
564
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object should be standalone");
565
566
    /* Check for root direct block */
567
0
    if (hdr->man_dtable.curr_root_rows == 0) {
568
        /* Set direct block info */
569
0
        dblock_size      = hdr->man_dtable.cparam.start_block_size;
570
0
        dblock_block_off = 0;
571
0
        dblock_entry     = 0;
572
0
    } /* end if */
573
0
    else {
574
        /* Look up indirect block containing direct block */
575
0
        if (H5HF__man_dblock_locate(hdr, obj_off, &iblock, &dblock_entry, &did_protect, H5AC__NO_FLAGS_SET) <
576
0
            0)
577
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section");
578
579
        /* Check for offset of invalid direct block */
580
0
        if (!H5_addr_defined(iblock->ents[dblock_entry].addr))
581
0
            HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap ID not in allocated direct block");
582
583
        /* Set direct block info */
584
0
        H5_CHECK_OVERFLOW((hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width]),
585
0
                          hsize_t, size_t);
586
0
        dblock_size = (size_t)(hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width]);
587
588
        /* Compute the direct block's offset in the heap's address space */
589
        /* (based on parent indirect block's block offset) */
590
0
        dblock_block_off = iblock->block_off;
591
0
        dblock_block_off += hdr->man_dtable.row_block_off[dblock_entry / hdr->man_dtable.cparam.width];
592
0
        dblock_block_off += hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width] *
593
0
                            (dblock_entry % hdr->man_dtable.cparam.width);
594
0
    } /* end else */
595
596
    /* Compute offset of object within block */
597
0
    assert((obj_off - dblock_block_off) < (hsize_t)dblock_size);
598
0
    blk_off = (size_t)(obj_off - dblock_block_off);
599
600
    /* Check for object's offset in the direct block prefix information */
601
0
    if (blk_off < (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr))
602
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object located in prefix of direct block");
603
604
    /* Check for object's length overrunning the end of the direct block */
605
0
    if ((blk_off + obj_len) > dblock_size)
606
0
        HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object overruns end of direct block");
607
608
    /* Create free space section node */
609
0
    if (NULL == (sec_node = H5HF__sect_single_new(obj_off, obj_len, iblock, dblock_entry)))
610
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create section for direct block's free space");
611
612
    /* Unlock indirect block */
613
0
    if (iblock) {
614
0
        if (H5HF__man_iblock_unprotect(iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
615
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block");
616
0
        iblock = NULL;
617
0
    } /* end if */
618
619
    /* Increase space available in heap (marks header dirty) */
620
0
    if (H5HF__hdr_adj_free(hdr, (ssize_t)obj_len) < 0)
621
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't adjust free space for heap");
622
623
    /* Update statistics about heap */
624
0
    hdr->man_nobjs--;
625
626
    /* Return free space to the heap's list of space */
627
0
    if (H5HF__space_add(hdr, sec_node, H5FS_ADD_RETURNED_SPACE) < 0)
628
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list");
629
0
    sec_node = NULL;
630
631
0
done:
632
0
    if (ret_value < 0) {
633
        /* Release section node */
634
0
        if (sec_node && H5HF__sect_single_free((H5FS_section_info_t *)sec_node) < 0)
635
0
            HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release section node");
636
0
    } /* end if */
637
638
    /* Unlock indirect block */
639
0
    if (iblock && H5HF__man_iblock_unprotect(iblock, H5AC__NO_FLAGS_SET, did_protect) < 0)
640
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block");
641
642
0
    FUNC_LEAVE_NOAPI(ret_value)
643
0
} /* end H5HF__man_remove() */