Coverage Report

Created: 2025-12-08 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5HFdblock.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:   H5HFdblock.c
16
 *
17
 * Purpose:   Direct block 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 "H5Fprivate.h"  /* File access       */
34
#include "H5FLprivate.h" /* Free Lists                               */
35
#include "H5HFpkg.h"     /* Fractal heaps     */
36
#include "H5MFprivate.h" /* File memory management    */
37
#include "H5VMprivate.h" /* Vectors and arrays      */
38
39
/****************/
40
/* Local Macros */
41
/****************/
42
43
/******************/
44
/* Local Typedefs */
45
/******************/
46
47
/********************/
48
/* Package Typedefs */
49
/********************/
50
51
/********************/
52
/* Local Prototypes */
53
/********************/
54
55
/*********************/
56
/* Package Variables */
57
/*********************/
58
59
/* Declare a free list to manage the H5HF_direct_t struct */
60
H5FL_DEFINE(H5HF_direct_t);
61
62
/*****************************/
63
/* Library Private Variables */
64
/*****************************/
65
66
/*******************/
67
/* Local Variables */
68
/*******************/
69
70
/*-------------------------------------------------------------------------
71
 * Function:  H5HF__man_dblock_create
72
 *
73
 * Purpose: Allocate & initialize a managed direct block
74
 *
75
 * Return:  Pointer to new direct block on success, NULL on failure
76
 *
77
 *-------------------------------------------------------------------------
78
 */
79
herr_t
80
H5HF__man_dblock_create(H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblock, unsigned par_entry, haddr_t *addr_p,
81
                        H5HF_free_section_t **ret_sec_node)
82
0
{
83
0
    H5HF_free_section_t *sec_node;            /* Pointer to free space section for block */
84
0
    H5HF_direct_t       *dblock = NULL;       /* Pointer to direct block */
85
0
    haddr_t              dblock_addr;         /* Direct block's address */
86
0
    size_t               free_space;          /* Free space in new block */
87
0
    herr_t               ret_value = SUCCEED; /* Return value */
88
89
0
    FUNC_ENTER_PACKAGE
90
91
    /*
92
     * Check arguments.
93
     */
94
0
    assert(hdr);
95
96
    /*
97
     * Allocate file and memory data structures.
98
     */
99
0
    if (NULL == (dblock = H5FL_MALLOC(H5HF_direct_t)))
100
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
101
0
                    "memory allocation failed for fractal heap direct block");
102
103
    /* Reset the metadata cache info for the heap header */
104
0
    memset(&dblock->cache_info, 0, sizeof(H5AC_info_t));
105
106
    /* Share common heap information */
107
0
    dblock->hdr = hdr;
108
0
    if (H5HF__hdr_incr(hdr) < 0)
109
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header");
110
111
    /* Set info for direct block */
112
0
    if (par_iblock) {
113
0
        unsigned par_row = par_entry / hdr->man_dtable.cparam.width; /* Row for block */
114
115
        /* Compute offset & size, based on parent's information */
116
0
        dblock->block_off = par_iblock->block_off;
117
0
        dblock->block_off += hdr->man_dtable.row_block_off[par_row];
118
0
        dblock->block_off +=
119
0
            hdr->man_dtable.row_block_size[par_row] * (par_entry % hdr->man_dtable.cparam.width);
120
0
        H5_CHECKED_ASSIGN(dblock->size, size_t, hdr->man_dtable.row_block_size[par_row], hsize_t);
121
0
    } /* end if */
122
0
    else {
123
        /* Must be the root direct block */
124
0
        dblock->block_off = 0;
125
0
        dblock->size      = hdr->man_dtable.cparam.start_block_size;
126
0
    } /* end else */
127
0
    dblock->file_size = 0;
128
0
    free_space        = dblock->size - H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
129
130
    /* Allocate buffer for block */
131
    /* XXX: Change to using free-list factories */
132
0
    if ((dblock->blk = H5FL_BLK_MALLOC(direct_block, dblock->size)) == NULL)
133
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
134
0
    memset(dblock->blk, 0, dblock->size);
135
136
0
    dblock->write_buf  = NULL;
137
0
    dblock->write_size = 0;
138
139
    /* Allocate [temporary] space for the direct block on disk */
140
0
    if (H5F_USE_TMP_SPACE(hdr->f)) {
141
0
        if (HADDR_UNDEF == (dblock_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)dblock->size)))
142
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
143
0
                        "file allocation failed for fractal heap direct block");
144
0
    } /* end if */
145
0
    else {
146
0
        if (HADDR_UNDEF == (dblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_DBLOCK, (hsize_t)dblock->size)))
147
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
148
0
                        "file allocation failed for fractal heap direct block");
149
0
    } /* end else */
150
151
    /* Attach to parent indirect block, if there is one */
152
0
    dblock->parent = par_iblock;
153
0
    if (dblock->parent) {
154
0
        if (H5HF__man_iblock_attach(dblock->parent, par_entry, dblock_addr) < 0)
155
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach direct block to parent indirect block");
156
0
        dblock->fd_parent = par_iblock;
157
0
    } /* end if */
158
0
    else
159
0
        dblock->fd_parent = hdr;
160
0
    dblock->par_entry = par_entry;
161
162
    /* Create a new 'single' section for the free space in the block */
163
0
    if (NULL == (sec_node = H5HF__sect_single_new((dblock->block_off + H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)),
164
0
                                                  free_space, dblock->parent, dblock->par_entry)))
165
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create section for new direct block's free space");
166
167
    /* Check what to do with section node */
168
0
    if (ret_sec_node)
169
        /* Pass back the pointer to the section instead of adding it to the free list */
170
0
        *ret_sec_node = sec_node;
171
0
    else {
172
        /* Add new free space to the heap's list of space */
173
0
        if (H5HF__space_add(hdr, sec_node, 0) < 0)
174
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list");
175
0
    } /* end else */
176
177
    /* Cache the new fractal heap direct block */
178
0
    if (H5AC_insert_entry(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
179
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add fractal heap direct block to cache");
180
181
    /* Increase the allocated heap size */
182
0
    if (H5HF__hdr_inc_alloc(hdr, dblock->size) < 0)
183
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size");
184
185
    /* Set the address of of direct block, if requested */
186
0
    if (addr_p)
187
0
        *addr_p = dblock_addr;
188
189
0
done:
190
0
    if (ret_value < 0)
191
0
        if (dblock)
192
0
            if (H5HF__man_dblock_dest(dblock) < 0)
193
0
                HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block");
194
195
0
    FUNC_LEAVE_NOAPI(ret_value)
196
0
} /* end H5HF__man_dblock_create() */
197
198
/*-------------------------------------------------------------------------
199
 * Function:  H5HF__man_dblock_destroy
200
 *
201
 * Purpose: Destroy a managed direct block
202
 *
203
 * Note:  This routine does _not_ insert a range section for the
204
 *              destroyed direct block, that must be handled by the
205
 *              caller.
206
 *
207
 * Return:  SUCCEED/FAIL
208
 *
209
 *-------------------------------------------------------------------------
210
 */
211
herr_t
212
H5HF__man_dblock_destroy(H5HF_hdr_t *hdr, H5HF_direct_t *dblock, haddr_t dblock_addr, bool *parent_removed)
213
0
{
214
0
    hsize_t  dblock_size;                      /* Size of direct block on disk */
215
0
    unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting indirect block */
216
0
    herr_t   ret_value   = SUCCEED;            /* Return value */
217
218
0
    FUNC_ENTER_PACKAGE
219
220
    /*
221
     * Check arguments.
222
     */
223
0
    assert(hdr);
224
0
    assert(dblock);
225
226
    /* Check for I/O filters on this heap */
227
0
    if (hdr->filter_len > 0) {
228
        /* Check for root direct block */
229
0
        if (dblock->parent == NULL)
230
            /* Get direct block's actual size */
231
0
            dblock_size = (hsize_t)hdr->pline_root_direct_size;
232
0
        else {
233
0
            H5HF_indirect_t *par_iblock; /* Parent indirect block */
234
0
            unsigned         par_entry;  /* Entry in parent indirect block */
235
236
            /* Get parent information */
237
0
            par_iblock = dblock->parent;
238
0
            par_entry  = dblock->par_entry;
239
240
            /* Get direct block's actual size */
241
0
            dblock_size = (hsize_t)par_iblock->filt_ents[par_entry].size;
242
0
        } /* end else */
243
0
    }     /* end if */
244
0
    else
245
0
        dblock_size = (hsize_t)dblock->size;
246
247
    /* Reset the parent_removed flag */
248
0
    if (parent_removed)
249
0
        *parent_removed = false;
250
251
    /* Check for root direct block */
252
0
    if (hdr->man_dtable.curr_root_rows == 0) {
253
        /* Sanity check */
254
0
        assert(hdr->man_dtable.table_addr == dblock_addr);
255
0
        assert(hdr->man_dtable.cparam.start_block_size == dblock->size);
256
257
        /* Sanity check block iterator */
258
0
        assert(!H5HF__man_iter_ready(&hdr->next_block));
259
260
        /* Reset header information back to "empty heap" state */
261
0
        if (H5HF__hdr_empty(hdr) < 0)
262
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't make heap empty");
263
0
    } /* end if */
264
0
    else {
265
        /* Adjust heap statistics */
266
0
        hdr->man_alloc_size -= dblock->size;
267
268
        /* Check for this direct block being the highest in the heap */
269
0
        if ((dblock->block_off + dblock->size) == hdr->man_iter_off)
270
            /* Move 'next block' iterator backwards (may shrink heap) */
271
0
            if (H5HF__hdr_reverse_iter(hdr, dblock_addr) < 0)
272
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reverse 'next block' iterator");
273
274
        /* Detach from parent indirect block */
275
0
        if (dblock->parent) {
276
            /* Destroy flush dependency between direct block and parent */
277
0
            if (H5AC_destroy_flush_dependency(dblock->fd_parent, dblock) < 0)
278
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency");
279
0
            dblock->fd_parent = NULL;
280
281
            /* If this is the last direct block for the indirect block, the
282
             *  indirect block will be removed when this direct block is detached
283
             */
284
0
            if (parent_removed && 1 == dblock->parent->nchildren)
285
0
                *parent_removed = true;
286
287
0
            if (H5HF__man_iblock_detach(dblock->parent, dblock->par_entry) < 0)
288
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach from parent indirect block");
289
0
            dblock->parent    = NULL;
290
0
            dblock->par_entry = 0;
291
0
        } /* end if */
292
0
    }     /* end else */
293
294
    /* Indicate that the direct block should be deleted */
295
0
    dblock->file_size = dblock_size;
296
0
    cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG;
297
298
    /* If the dblock is in real file space, also tell the cache to free its file space */
299
0
    if (!H5F_IS_TMP_ADDR(hdr->f, dblock_addr))
300
0
        cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
301
302
0
done:
303
    /* Unprotect the indirect block, with appropriate flags */
304
0
    if (H5AC_unprotect(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, cache_flags) < 0)
305
0
        HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block");
306
307
0
    FUNC_LEAVE_NOAPI(ret_value)
308
0
} /* end H5HF__man_dblock_destroy() */
309
310
/*-------------------------------------------------------------------------
311
 * Function:  H5HF__man_dblock_new
312
 *
313
 * Purpose: Create a direct block large enough to hold an object of
314
 *              the requested size
315
 *
316
 * Return:  SUCCEED/FAIL
317
 *
318
 *-------------------------------------------------------------------------
319
 */
320
herr_t
321
H5HF__man_dblock_new(H5HF_hdr_t *hdr, size_t request, H5HF_free_section_t **ret_sec_node)
322
0
{
323
0
    haddr_t dblock_addr;         /* Address of new direct block */
324
0
    size_t  min_dblock_size;     /* Min. size of direct block to allocate */
325
0
    herr_t  ret_value = SUCCEED; /* Return value */
326
327
0
    FUNC_ENTER_PACKAGE
328
329
    /*
330
     * Check arguments.
331
     */
332
0
    assert(hdr);
333
0
    assert(request > 0);
334
335
    /* Compute the min. size of the direct block needed to fulfill the request */
336
0
    if (request < hdr->man_dtable.cparam.start_block_size)
337
0
        min_dblock_size = hdr->man_dtable.cparam.start_block_size;
338
0
    else {
339
0
        min_dblock_size = ((size_t)1) << (1 + H5VM_log2_gen((uint64_t)request));
340
0
        assert(min_dblock_size <= hdr->man_dtable.cparam.max_direct_size);
341
0
    } /* end else */
342
343
    /* Adjust the size of block needed to fulfill request, with overhead */
344
0
    if (min_dblock_size < H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) + request)
345
0
        min_dblock_size *= 2;
346
347
    /* Check if this is the first block in the heap */
348
0
    if (!H5_addr_defined(hdr->man_dtable.table_addr) &&
349
0
        min_dblock_size == hdr->man_dtable.cparam.start_block_size) {
350
        /* Create new direct block at starting offset */
351
0
        if (H5HF__man_dblock_create(hdr, NULL, 0, &dblock_addr, ret_sec_node) < 0)
352
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block");
353
354
        /* Point root at new direct block */
355
0
        hdr->man_dtable.curr_root_rows = 0;
356
0
        hdr->man_dtable.table_addr     = dblock_addr;
357
0
        if (hdr->filter_len > 0) {
358
0
            hdr->pline_root_direct_size        = hdr->man_dtable.cparam.start_block_size;
359
0
            hdr->pline_root_direct_filter_mask = 0;
360
0
        } /* end if */
361
362
        /* Extend heap to cover new direct block */
363
0
        if (H5HF__hdr_adjust_heap(hdr, (hsize_t)hdr->man_dtable.cparam.start_block_size,
364
0
                                  (hssize_t)hdr->man_dtable.row_tot_dblock_free[0]) < 0)
365
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block");
366
0
    } /* end if */
367
    /* Root entry already exists, allocate direct block from root indirect block */
368
0
    else {
369
0
        H5HF_indirect_t *iblock;     /* Pointer to indirect block to create */
370
0
        unsigned         next_row;   /* Iterator's next block row */
371
0
        unsigned         next_entry; /* Iterator's next block entry */
372
0
        size_t           next_size;  /* Size of next direct block to create */
373
374
        /* Update iterator to reflect any previous increments as well as allow for requested direct block size
375
         */
376
0
        if (H5HF__hdr_update_iter(hdr, min_dblock_size) < 0)
377
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTUPDATE, FAIL, "unable to update block iterator");
378
379
        /* Retrieve information about current iterator position */
380
0
        if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
381
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location");
382
0
        assert(next_row < iblock->nrows);
383
0
        H5_CHECKED_ASSIGN(next_size, size_t, hdr->man_dtable.row_block_size[next_row], hsize_t);
384
385
        /* Check for skipping over blocks */
386
0
        if (min_dblock_size > next_size) {
387
0
            fprintf(stderr,
388
0
                    "%s: Skipping direct block sizes not supported, min_dblock_size = %zu, next_size = %zu\n",
389
0
                    __func__, min_dblock_size, next_size);
390
0
            HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "skipping direct block sizes not supported yet");
391
0
        } /* end if */
392
393
        /* Advance "next block" iterator to next direct block entry */
394
0
        if (H5HF__hdr_inc_iter(hdr, (hsize_t)next_size, 1) < 0)
395
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment 'next block' iterator");
396
397
        /* Create new direct block at current location*/
398
0
        if (H5HF__man_dblock_create(hdr, iblock, next_entry, &dblock_addr, ret_sec_node) < 0)
399
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block");
400
0
    } /* end else */
401
402
0
done:
403
0
    FUNC_LEAVE_NOAPI(ret_value)
404
0
} /* end H5HF__man_dblock_new() */
405
406
/*-------------------------------------------------------------------------
407
 * Function:  H5HF__man_dblock_protect
408
 *
409
 * Purpose: Convenience wrapper around H5AC_protect on a direct block
410
 *              (Use H5AC_unprotect to unprotect it for now)
411
 *
412
 * Return:  Pointer to direct block on success, NULL on failure
413
 *
414
 *-------------------------------------------------------------------------
415
 */
416
H5HF_direct_t *
417
H5HF__man_dblock_protect(H5HF_hdr_t *hdr, haddr_t dblock_addr, size_t dblock_size,
418
                         H5HF_indirect_t *par_iblock, unsigned par_entry, unsigned flags)
419
0
{
420
0
    H5HF_direct_t         *dblock;           /* Direct block from cache */
421
0
    H5HF_dblock_cache_ud_t udata;            /* parent and other info for deserializing direct block */
422
0
    H5HF_direct_t         *ret_value = NULL; /* Return value */
423
424
0
    FUNC_ENTER_PACKAGE
425
426
    /*
427
     * Check arguments.
428
     */
429
0
    assert(hdr);
430
0
    assert(H5_addr_defined(dblock_addr));
431
0
    assert(dblock_size > 0);
432
433
    /* only H5AC__READ_ONLY_FLAG may appear in flags */
434
0
    assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
435
436
    /* Set up parent info */
437
0
    udata.par_info.hdr    = hdr;
438
0
    udata.par_info.iblock = par_iblock;
439
0
    udata.par_info.entry  = par_entry;
440
441
    /* set up the file pointer in the user data */
442
0
    udata.f = hdr->f;
443
444
    /* set up the direct block size */
445
0
    udata.dblock_size = dblock_size;
446
447
    /* compute the on disk image size -- observe that odi_size and
448
     * dblock_size will be identical if there is no filtering.
449
     */
450
0
    if (hdr->filter_len > 0) {
451
0
        if (par_iblock == NULL) {
452
0
            udata.odi_size    = hdr->pline_root_direct_size;
453
0
            udata.filter_mask = hdr->pline_root_direct_filter_mask;
454
0
        } /* end if */
455
0
        else {
456
            /* Sanity check */
457
0
            assert(H5_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr));
458
459
            /* Set up parameters to read filtered direct block */
460
0
            udata.odi_size    = par_iblock->filt_ents[par_entry].size;
461
0
            udata.filter_mask = par_iblock->filt_ents[par_entry].filter_mask;
462
0
        } /* end else */
463
0
    }     /* end if */
464
0
    else {
465
0
        udata.odi_size    = dblock_size;
466
0
        udata.filter_mask = 0;
467
0
    } /* end else */
468
469
    /* Reset compression context info */
470
0
    udata.decompressed = false;
471
0
    udata.dblk         = NULL;
472
473
    /* Protect the direct block */
474
0
    if (NULL ==
475
0
        (dblock = (H5HF_direct_t *)H5AC_protect(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, &udata, flags)))
476
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap direct block");
477
478
    /* Set the return value */
479
0
    ret_value = dblock;
480
481
0
done:
482
0
    FUNC_LEAVE_NOAPI(ret_value)
483
0
} /* end H5HF__man_dblock_protect() */
484
485
/*-------------------------------------------------------------------------
486
 * Function:  H5HF__man_dblock_locate
487
 *
488
 * Purpose: Locate a direct block in a managed heap
489
 *
490
 * Return:  SUCCEED/FAIL
491
 *
492
 *-------------------------------------------------------------------------
493
 */
494
herr_t
495
H5HF__man_dblock_locate(H5HF_hdr_t *hdr, hsize_t obj_off, H5HF_indirect_t **ret_iblock, unsigned *ret_entry,
496
                        bool *ret_did_protect, unsigned flags)
497
0
{
498
0
    haddr_t          iblock_addr;         /* Indirect block's address */
499
0
    H5HF_indirect_t *iblock;              /* Pointer to indirect block */
500
0
    bool             did_protect;         /* Whether we protected the indirect block or not */
501
0
    unsigned         row, col;            /* Row & column for object's block */
502
0
    unsigned         entry;               /* Entry of block */
503
0
    herr_t           ret_value = SUCCEED; /* Return value */
504
505
0
    FUNC_ENTER_PACKAGE
506
507
    /*
508
     * Check arguments.
509
     */
510
0
    assert(hdr);
511
0
    assert(hdr->man_dtable.curr_root_rows); /* Only works for heaps with indirect root block */
512
0
    assert(ret_iblock);
513
0
    assert(ret_did_protect);
514
515
    /* only H5AC__READ_ONLY_FLAG may appear in flags */
516
0
    assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
517
518
    /* Look up row & column for object */
519
0
    if (H5HF__dtable_lookup(&hdr->man_dtable, obj_off, &row, &col) < 0)
520
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of object");
521
522
    /* Set initial indirect block info */
523
0
    iblock_addr = hdr->man_dtable.table_addr;
524
525
    /* Lock root indirect block */
526
0
    if (NULL == (iblock = H5HF__man_iblock_protect(hdr, iblock_addr, hdr->man_dtable.curr_root_rows, NULL, 0,
527
0
                                                   false, flags, &did_protect)))
528
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block");
529
530
    /* Check for indirect block row */
531
0
    while (row >= hdr->man_dtable.max_direct_rows) {
532
0
        H5HF_indirect_t *new_iblock;      /* Pointer to new indirect block */
533
0
        bool             new_did_protect; /* Whether we protected the indirect block or not */
534
0
        unsigned         nrows;           /* Number of rows in new indirect block */
535
0
        unsigned         cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting parent indirect block */
536
537
        /* Compute # of rows in child indirect block */
538
0
        nrows = (H5VM_log2_gen(hdr->man_dtable.row_block_size[row]) - hdr->man_dtable.first_row_bits) + 1;
539
0
        assert(nrows < iblock->nrows); /* child must be smaller than parent */
540
541
        /* Compute indirect block's entry */
542
0
        entry = (row * hdr->man_dtable.cparam.width) + col;
543
544
        /* Locate child indirect block */
545
0
        iblock_addr = iblock->ents[entry].addr;
546
547
        /* Check if we need to (re-)create the child indirect block */
548
0
        if (!H5_addr_defined(iblock_addr)) {
549
0
            if (H5HF__man_iblock_create(hdr, iblock, entry, nrows, nrows, &iblock_addr) < 0)
550
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block");
551
552
            /* Indicate that the parent indirect block was modified */
553
0
            cache_flags |= H5AC__DIRTIED_FLAG;
554
0
        } /* end if */
555
556
        /* Lock child indirect block */
557
0
        if (NULL == (new_iblock = H5HF__man_iblock_protect(hdr, iblock_addr, nrows, iblock, entry, false,
558
0
                                                           flags, &new_did_protect)))
559
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block");
560
561
        /* Release the current indirect block */
562
0
        if (H5HF__man_iblock_unprotect(iblock, cache_flags, did_protect) < 0)
563
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block");
564
565
        /* Switch variables to use new indirect block */
566
0
        iblock      = new_iblock;
567
0
        did_protect = new_did_protect;
568
569
        /* Look up row & column in new indirect block for object */
570
0
        if (H5HF__dtable_lookup(&hdr->man_dtable, (obj_off - iblock->block_off), &row, &col) < 0)
571
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of object");
572
0
        assert(row < iblock->nrows); /* child must be smaller than parent */
573
0
    }                                /* end while */
574
575
    /* Set return parameters */
576
0
    if (ret_entry)
577
0
        *ret_entry = (row * hdr->man_dtable.cparam.width) + col;
578
0
    *ret_iblock      = iblock;
579
0
    *ret_did_protect = did_protect;
580
581
0
done:
582
0
    FUNC_LEAVE_NOAPI(ret_value)
583
0
} /* end H5HF__man_dblock_locate() */
584
585
/*-------------------------------------------------------------------------
586
 * Function:  H5HF__man_dblock_delete
587
 *
588
 * Purpose: Delete a managed direct block
589
 *
590
 * Note:  This routine does _not_ modify any indirect block that points
591
 *              to this direct block, it is assumed that the whole heap is
592
 *              being deleted.  (H5HF__man_dblock_destroy modifies the indirect
593
 *              block)
594
 *
595
 * Return:  SUCCEED/FAIL
596
 *
597
 *-------------------------------------------------------------------------
598
 */
599
herr_t
600
H5HF__man_dblock_delete(H5F_t *f, haddr_t dblock_addr, hsize_t dblock_size)
601
0
{
602
0
    unsigned dblock_status = 0;       /* Direct block's status in the metadata cache */
603
0
    herr_t   ret_value     = SUCCEED; /* Return value */
604
605
0
    FUNC_ENTER_PACKAGE
606
607
    /*
608
     * Check arguments.
609
     */
610
0
    assert(f);
611
0
    assert(H5_addr_defined(dblock_addr));
612
0
    assert(dblock_size > 0);
613
614
    /* Check the direct block's status in the metadata cache */
615
0
    if (H5AC_get_entry_status(f, dblock_addr, &dblock_status) < 0)
616
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for direct block");
617
618
    /* If the direct block is in the cache, expunge it now */
619
0
    if (dblock_status & H5AC_ES__IN_CACHE) {
620
        /* Sanity checks on direct block */
621
0
        assert(!(dblock_status & H5AC_ES__IS_PINNED));
622
0
        assert(!(dblock_status & H5AC_ES__IS_PROTECTED));
623
624
        /* Evict the direct block from the metadata cache */
625
0
        if (H5AC_expunge_entry(f, H5AC_FHEAP_DBLOCK, dblock_addr, H5AC__NO_FLAGS_SET) < 0)
626
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove direct block from cache");
627
0
    } /* end if */
628
629
    /* Check if the direct block is NOT currently allocated in temp. file space */
630
    /* (temp. file space does not need to be freed) */
631
0
    if (!H5F_IS_TMP_ADDR(f, dblock_addr))
632
        /* Release direct block's disk space */
633
        /* (XXX: Under the best of circumstances, this block's space in the file
634
         *          would be freed in the H5AC_expunge_entry() call above (and the
635
         *          H5AC__FREE_FILE_SPACE_FLAG used there), but since the direct
636
         *          block structure might have a different size on disk than in
637
         *          the heap's 'abstract' address space, we would need to set the
638
         *          "file_size" field for the direct block structure.  In order to
639
         *          do that, we'd have to protect/unprotect the direct block and
640
         *          that would add a bunch of unnecessary overhead to the process,
641
         *          so we just release the file space here, directly.  -QAK)
642
         */
643
0
        if (H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dblock_addr, dblock_size) < 0)
644
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block file space");
645
646
0
done:
647
0
    FUNC_LEAVE_NOAPI(ret_value)
648
0
} /* end H5HF__man_dblock_delete() */
649
650
/*-------------------------------------------------------------------------
651
 * Function:  H5HF__man_dblock_dest
652
 *
653
 * Purpose: Destroys a fractal heap direct block in memory.
654
 *
655
 * Return:  Non-negative on success/Negative on failure
656
 *
657
 *-------------------------------------------------------------------------
658
 */
659
herr_t
660
H5HF__man_dblock_dest(H5HF_direct_t *dblock)
661
0
{
662
0
    herr_t ret_value = SUCCEED; /* Return value */
663
664
0
    FUNC_ENTER_PACKAGE
665
666
    /*
667
     * Check arguments.
668
     */
669
0
    assert(dblock);
670
671
    /* Decrement reference count on shared fractal heap info */
672
0
    assert(dblock->hdr != NULL);
673
0
    if (H5HF__hdr_decr(dblock->hdr) < 0)
674
0
        HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header");
675
0
    if (dblock->parent)
676
0
        if (H5HF__iblock_decr(dblock->parent) < 0)
677
0
            HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL,
678
0
                        "can't decrement reference count on shared indirect block");
679
680
    /* Free block's buffer */
681
0
    dblock->blk = H5FL_BLK_FREE(direct_block, dblock->blk);
682
683
    /* Free fractal heap direct block info */
684
0
    dblock = H5FL_FREE(H5HF_direct_t, dblock);
685
686
0
done:
687
0
    FUNC_LEAVE_NOAPI(ret_value)
688
0
} /* end H5HF__man_dblock_dest() */