Coverage Report

Created: 2026-08-31 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Dbtree2.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
 * Purpose: v2 B-tree indexing for chunked datasets with > 1 unlimited dimensions.
16
 *   Each dataset chunk in the b-tree is identified by its dimensional offset.
17
 *
18
 */
19
20
/****************/
21
/* Module Setup */
22
/****************/
23
24
#include "H5Dmodule.h" /* This source code file is part of the H5D module */
25
26
/***********/
27
/* Headers */
28
/***********/
29
#include "H5private.h"   /* Generic Functions                    */
30
#include "H5Dpkg.h"      /* Datasets                             */
31
#include "H5FLprivate.h" /* Free Lists                           */
32
#include "H5MFprivate.h" /* File space management                */
33
#include "H5MMprivate.h" /* Memory management                    */
34
#include "H5VMprivate.h" /* Vector and array functions           */
35
36
/****************/
37
/* Local Macros */
38
/****************/
39
40
0
#define H5D_BT2_IDX_IS_OPEN(idx_info) (NULL != (idx_info)->layout->storage.u.chunk.u.btree2.bt2)
41
42
/*
43
 * Macro to compute the size required for encoding the size of a chunk. For version 4, this is the minimum
44
 * number of bytes required to encode the size of an unfiltered chunk plus an extra byte, in case the filter
45
 * makes the chunk larger. For versions after 4, this is simply the size of lengths for the file. For
46
 * unfiltered chunks, this is 0.
47
 */
48
#define H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, idx_info)                                             \
49
0
    do {                                                                                                     \
50
0
        if ((idx_info)->pline->nused > 0) {                                                                  \
51
0
            if ((idx_info)->layout->version > H5O_LAYOUT_VERSION_4)                                          \
52
0
                (chunk_size_len) = H5F_SIZEOF_SIZE((idx_info)->f);                                           \
53
0
            else {                                                                                           \
54
0
                (chunk_size_len) =                                                                           \
55
0
                    1 + ((H5VM_log2_gen((uint64_t)(idx_info)->layout->u.chunk.size) + 8) / 8);               \
56
0
                if ((chunk_size_len) > 8)                                                                    \
57
0
                    (chunk_size_len) = 8;                                                                    \
58
0
            }                                                                                                \
59
0
        }                                                                                                    \
60
0
        else                                                                                                 \
61
0
            (chunk_size_len) = 0;                                                                            \
62
0
    } while (0)
63
64
/******************/
65
/* Local Typedefs */
66
/******************/
67
/* User data for creating callback context */
68
typedef struct H5D_bt2_ctx_ud_t {
69
    const H5F_t *f;              /* Pointer to file info */
70
    hsize_t      chunk_size;     /* Size of chunk (bytes; for filtered object) */
71
    unsigned     ndims;          /* Number of dimensions */
72
    size_t       chunk_size_len; /* Size of chunk sizes in the file (bytes) */
73
    hsize_t     *dim;            /* Size of chunk in elements */
74
} H5D_bt2_ctx_ud_t;
75
76
/* The callback context */
77
typedef struct H5D_bt2_ctx_t {
78
    hsize_t  chunk_size;     /* Size of chunk (bytes; constant for unfiltered object) */
79
    size_t   sizeof_addr;    /* Size of file addresses in the file (bytes) */
80
    size_t   chunk_size_len; /* Size of chunk sizes in the file (bytes) */
81
    unsigned ndims;          /* Number of dimensions in chunk */
82
    hsize_t *dim;            /* Size of chunk in elements */
83
} H5D_bt2_ctx_t;
84
85
/* Callback info for iteration over chunks in v2 B-tree */
86
typedef struct H5D_bt2_it_ud_t {
87
    H5D_chunk_cb_func_t cb;    /* Callback routine for the chunk */
88
    void               *udata; /* User data for the chunk's callback routine */
89
} H5D_bt2_it_ud_t;
90
91
/* User data for compare callback */
92
typedef struct H5D_bt2_ud_t {
93
    H5D_chunk_rec_t rec;   /* The record to search for */
94
    unsigned        ndims; /* Number of dimensions for the chunked dataset */
95
} H5D_bt2_ud_t;
96
97
/********************/
98
/* Local Prototypes */
99
/********************/
100
101
/* Shared v2 B-tree methods for indexing filtered and non-filtered chunked datasets */
102
static void  *H5D__bt2_crt_context(void *udata);
103
static herr_t H5D__bt2_dst_context(void *ctx);
104
static herr_t H5D__bt2_store(void *native, const void *udata);
105
static herr_t H5D__bt2_compare(const void *rec1, const void *rec2, int *result);
106
107
/* v2 B-tree class for indexing non-filtered chunked datasets */
108
static herr_t H5D__bt2_unfilt_encode(uint8_t *raw, const void *native, void *ctx);
109
static herr_t H5D__bt2_unfilt_decode(const uint8_t *raw, void *native, void *ctx);
110
static herr_t H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth, const void *record,
111
                                    const void *u_ctx);
112
113
/* v2 B-tree class for indexing filtered chunked datasets */
114
static herr_t H5D__bt2_filt_encode(uint8_t *raw, const void *native, void *ctx);
115
static herr_t H5D__bt2_filt_decode(const uint8_t *raw, void *native, void *ctx);
116
static herr_t H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth, const void *record,
117
                                  const void *u_ctx);
118
119
/* Helper routine */
120
static herr_t H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info);
121
122
/* Callback for H5B2_iterate() which is called in H5D__bt2_idx_iterate() */
123
static int H5D__bt2_idx_iterate_cb(const void *_record, void *_udata);
124
125
/* Callback for H5B2_find() which is called in H5D__bt2_idx_get_addr() */
126
static herr_t H5D__bt2_found_cb(const void *nrecord, void *op_data);
127
128
/*
129
 * Callback for H5B2_remove() and H5B2_delete() which is called
130
 * in H5D__bt2_idx_remove() and H5D__bt2_idx_delete().
131
 */
132
static herr_t H5D__bt2_remove_cb(const void *nrecord, void *_udata);
133
134
/* Callback for H5B2_update() which is called in H5D__bt2_idx_insert() */
135
static herr_t H5D__bt2_mod_cb(void *_record, void *_op_data, bool *changed);
136
137
/* Chunked layout indexing callbacks for v2 B-tree indexing */
138
static herr_t H5D__bt2_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space,
139
                                haddr_t dset_ohdr_addr);
140
static herr_t H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info);
141
static herr_t H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info);
142
static herr_t H5D__bt2_idx_close(const H5D_chk_idx_info_t *idx_info);
143
static herr_t H5D__bt2_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open);
144
static bool   H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
145
static herr_t H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
146
                                  const H5D_t *dset);
147
static herr_t H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata);
148
static herr_t H5D__bt2_idx_load_metadata(const H5D_chk_idx_info_t *idx_info);
149
static int    H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb,
150
                                   void *chunk_udata);
151
static herr_t H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata);
152
static herr_t H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info);
153
static herr_t H5D__bt2_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
154
                                      const H5D_chk_idx_info_t *idx_info_dst);
155
static herr_t H5D__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst);
156
static herr_t H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *size);
157
static herr_t H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr);
158
static herr_t H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream);
159
static herr_t H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info);
160
161
/*********************/
162
/* Package Variables */
163
/*********************/
164
165
/* Chunked dataset I/O ops for v2 B-tree indexing */
166
const H5D_chunk_ops_t H5D_COPS_BT2[1] = {{
167
    true,                        /* Fixed array indices support SWMR access */
168
    H5D__bt2_idx_init,           /* init */
169
    H5D__bt2_idx_create,         /* create */
170
    H5D__bt2_idx_open,           /* open */
171
    H5D__bt2_idx_close,          /* close */
172
    H5D__bt2_idx_is_open,        /* is_open */
173
    H5D__bt2_idx_is_space_alloc, /* is_space_alloc */
174
    H5D__bt2_idx_insert,         /* insert */
175
    H5D__bt2_idx_get_addr,       /* get_addr */
176
    H5D__bt2_idx_load_metadata,  /* load_metadata */
177
    NULL,                        /* resize */
178
    H5D__bt2_idx_iterate,        /* iterate */
179
    H5D__bt2_idx_remove,         /* remove */
180
    H5D__bt2_idx_delete,         /* delete */
181
    H5D__bt2_idx_copy_setup,     /* copy_setup */
182
    H5D__bt2_idx_copy_shutdown,  /* copy_shutdown */
183
    H5D__bt2_idx_size,           /* size */
184
    H5D__bt2_idx_reset,          /* reset */
185
    H5D__bt2_idx_dump,           /* dump */
186
    H5D__bt2_idx_dest            /* destroy */
187
}};
188
189
/*****************************/
190
/* Library Private Variables */
191
/*****************************/
192
193
/* v2 B-tree class for indexing non-filtered chunked datasets */
194
const H5B2_class_t H5D_BT2[1] = {{
195
    /* B-tree class information */
196
    H5B2_CDSET_ID,           /* Type of B-tree */
197
    "H5B2_CDSET_ID",         /* Name of B-tree class */
198
    sizeof(H5D_chunk_rec_t), /* Size of native record */
199
    H5D__bt2_crt_context,    /* Create client callback context */
200
    H5D__bt2_dst_context,    /* Destroy client callback context */
201
    H5D__bt2_store,          /* Record storage callback */
202
    H5D__bt2_compare,        /* Record comparison callback */
203
    H5D__bt2_unfilt_encode,  /* Record encoding callback */
204
    H5D__bt2_unfilt_decode,  /* Record decoding callback */
205
    H5D__bt2_unfilt_debug    /* Record debugging callback */
206
}};
207
208
/* v2 B-tree class for indexing filtered chunked datasets */
209
const H5B2_class_t H5D_BT2_FILT[1] = {{
210
    /* B-tree class information */
211
    H5B2_CDSET_FILT_ID,      /* Type of B-tree */
212
    "H5B2_CDSET_FILT_ID",    /* Name of B-tree class */
213
    sizeof(H5D_chunk_rec_t), /* Size of native record */
214
    H5D__bt2_crt_context,    /* Create client callback context */
215
    H5D__bt2_dst_context,    /* Destroy client callback context */
216
    H5D__bt2_store,          /* Record storage callback */
217
    H5D__bt2_compare,        /* Record comparison callback */
218
    H5D__bt2_filt_encode,    /* Record encoding callback */
219
    H5D__bt2_filt_decode,    /* Record decoding callback */
220
    H5D__bt2_filt_debug      /* Record debugging callback */
221
}};
222
223
/*******************/
224
/* Local Variables */
225
/*******************/
226
227
/* Declare a free list to manage the H5D_bt2_ctx_t struct */
228
H5FL_DEFINE_STATIC(H5D_bt2_ctx_t);
229
230
/* Declare a free list to manage the page elements */
231
H5FL_ARR_DEFINE_STATIC(hsize_t, H5O_LAYOUT_NDIMS);
232
233
/*-------------------------------------------------------------------------
234
 * Function:    H5D__bt2_crt_context
235
 *
236
 * Purpose:     Create client callback context
237
 *
238
 * Return:      Success:    non-NULL
239
 *              Failure:    NULL
240
 *
241
 *-------------------------------------------------------------------------
242
 */
243
static void *
244
H5D__bt2_crt_context(void *_udata)
245
0
{
246
0
    H5D_bt2_ctx_ud_t *udata = (H5D_bt2_ctx_ud_t *)_udata; /* User data for building callback context */
247
0
    H5D_bt2_ctx_t    *ctx;                                /* Callback context structure */
248
0
    hsize_t          *my_dim    = NULL;                   /* Pointer to copy of chunk dimension size */
249
0
    void             *ret_value = NULL;                   /* Return value */
250
251
0
    FUNC_ENTER_PACKAGE
252
253
    /* Sanity check */
254
0
    assert(udata);
255
0
    assert(udata->f);
256
0
    assert(udata->ndims > 0 && udata->ndims < H5O_LAYOUT_NDIMS);
257
258
    /* Allocate callback context */
259
0
    if (NULL == (ctx = H5FL_MALLOC(H5D_bt2_ctx_t)))
260
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate callback context");
261
262
    /* Determine the size of addresses and set the chunk size, # of dimensions for the dataset, and bytes used
263
     * to encode the chunk size */
264
0
    ctx->sizeof_addr    = H5F_SIZEOF_ADDR(udata->f);
265
0
    ctx->chunk_size     = udata->chunk_size;
266
0
    ctx->ndims          = udata->ndims;
267
0
    ctx->chunk_size_len = udata->chunk_size_len;
268
269
    /* Set up the "local" information for this dataset's chunk dimension sizes */
270
0
    if (NULL == (my_dim = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, H5O_LAYOUT_NDIMS)))
271
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate chunk dims");
272
0
    H5MM_memcpy(my_dim, udata->dim, H5O_LAYOUT_NDIMS * sizeof(hsize_t));
273
0
    ctx->dim = my_dim;
274
275
    /* Set return value */
276
0
    ret_value = ctx;
277
278
0
done:
279
0
    FUNC_LEAVE_NOAPI(ret_value)
280
0
} /* H5D__bt2_crt_context() */
281
282
/*-------------------------------------------------------------------------
283
 * Function:    H5D__bt2_dst_context
284
 *
285
 * Purpose:     Destroy client callback context
286
 *
287
 * Return:      Success:    non-negative
288
 *              Failure:    negative
289
 *
290
 *-------------------------------------------------------------------------
291
 */
292
static herr_t
293
H5D__bt2_dst_context(void *_ctx)
294
0
{
295
0
    H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */
296
297
0
    FUNC_ENTER_PACKAGE_NOERR
298
299
    /* Sanity check */
300
0
    assert(ctx);
301
302
    /* Free array for chunk dimension sizes */
303
0
    if (ctx->dim)
304
0
        H5FL_ARR_FREE(hsize_t, ctx->dim);
305
    /* Release callback context */
306
0
    ctx = H5FL_FREE(H5D_bt2_ctx_t, ctx);
307
308
0
    FUNC_LEAVE_NOAPI(SUCCEED)
309
0
} /* H5D__bt2_dst_context() */
310
311
/*-------------------------------------------------------------------------
312
 * Function:    H5D__bt2_store
313
 *
314
 * Purpose:     Store native information into record for v2 B-tree
315
 *              (non-filtered)
316
 *
317
 * Return:      Success:    non-negative
318
 *              Failure:    negative
319
 *
320
 *-------------------------------------------------------------------------
321
 */
322
static herr_t
323
H5D__bt2_store(void *record, const void *_udata)
324
0
{
325
0
    const H5D_bt2_ud_t *udata = (const H5D_bt2_ud_t *)_udata; /* User data */
326
327
0
    FUNC_ENTER_PACKAGE_NOERR
328
329
0
    *(H5D_chunk_rec_t *)record = udata->rec;
330
331
0
    FUNC_LEAVE_NOAPI(SUCCEED)
332
0
} /* H5D__bt2_store() */
333
334
/*-------------------------------------------------------------------------
335
 * Function:    H5D__bt2_compare
336
 *
337
 * Purpose:     Compare two native information records, according to some
338
 *              key (non-filtered)
339
 *
340
 * Return:      <0 if rec1 < rec2
341
 *              =0 if rec1 == rec2
342
 *              >0 if rec1 > rec2
343
 *
344
 *-------------------------------------------------------------------------
345
 */
346
static herr_t
347
H5D__bt2_compare(const void *_udata, const void *_rec2, int *result)
348
0
{
349
0
    const H5D_bt2_ud_t    *udata     = (const H5D_bt2_ud_t *)_udata;   /* User data */
350
0
    const H5D_chunk_rec_t *rec1      = &(udata->rec);                  /* The search record */
351
0
    const H5D_chunk_rec_t *rec2      = (const H5D_chunk_rec_t *)_rec2; /* The native record */
352
0
    herr_t                 ret_value = SUCCEED;                        /* Return value */
353
354
0
    FUNC_ENTER_PACKAGE_NOERR
355
356
    /* Sanity checks */
357
0
    assert(rec1);
358
0
    assert(rec2);
359
360
    /* Compare the offsets but ignore the other fields */
361
0
    *result = H5VM_vector_cmp_u(udata->ndims, rec1->scaled, rec2->scaled);
362
363
0
    FUNC_LEAVE_NOAPI(ret_value)
364
0
} /* H5D__bt2_compare() */
365
366
/*-------------------------------------------------------------------------
367
 * Function:    H5D__bt2_unfilt_encode
368
 *
369
 * Purpose:     Encode native information into raw form for storing on disk
370
 *              (non-filtered)
371
 *
372
 * Return:      Success:    non-negative
373
 *              Failure:    negative
374
 *
375
 *-------------------------------------------------------------------------
376
 */
377
static herr_t
378
H5D__bt2_unfilt_encode(uint8_t *raw, const void *_record, void *_ctx)
379
0
{
380
0
    H5D_bt2_ctx_t         *ctx    = (H5D_bt2_ctx_t *)_ctx;            /* Callback context structure */
381
0
    const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
382
0
    unsigned               u;                                         /* Local index variable */
383
384
0
    FUNC_ENTER_PACKAGE_NOERR
385
386
    /* Sanity check */
387
0
    assert(ctx);
388
389
    /* Encode the record's fields */
390
0
    H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr);
391
    /* (Don't encode the chunk size & filter mask for non-filtered B-tree records) */
392
0
    for (u = 0; u < ctx->ndims; u++)
393
0
        UINT64ENCODE(raw, record->scaled[u]);
394
395
0
    FUNC_LEAVE_NOAPI(SUCCEED)
396
0
} /* H5D__bt2_unfilt_encode() */
397
398
/*-------------------------------------------------------------------------
399
 * Function:    H5D__bt2_unfilt_decode
400
 *
401
 * Purpose:     Decode raw disk form of record into native form
402
 *              (non-filtered)
403
 *
404
 * Return:      Success:    non-negative
405
 *              Failure:    negative
406
 *
407
 *-------------------------------------------------------------------------
408
 */
409
static herr_t
410
H5D__bt2_unfilt_decode(const uint8_t *raw, void *_record, void *_ctx)
411
0
{
412
0
    H5D_bt2_ctx_t   *ctx    = (H5D_bt2_ctx_t *)_ctx;      /* Callback context structure */
413
0
    H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */
414
0
    unsigned         u;                                   /* Local index variable */
415
416
0
    FUNC_ENTER_PACKAGE_NOERR
417
418
    /* Sanity check */
419
0
    assert(ctx);
420
421
    /* Decode the record's fields */
422
0
    H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr);
423
0
    record->nbytes      = ctx->chunk_size;
424
0
    record->filter_mask = 0;
425
0
    for (u = 0; u < ctx->ndims; u++)
426
0
        UINT64DECODE(raw, record->scaled[u]);
427
428
0
    FUNC_LEAVE_NOAPI(SUCCEED)
429
0
} /* H5D__bt2_unfilt_decode() */
430
431
/*-------------------------------------------------------------------------
432
 * Function:    H5D__bt2_unfilt_debug
433
 *
434
 * Purpose:     Debug native form of record (non-filtered)
435
 *
436
 * Return:      Success:    non-negative
437
 *              Failure:    negative
438
 *
439
 *-------------------------------------------------------------------------
440
 */
441
static herr_t
442
H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth, const void *_record, const void *_ctx)
443
0
{
444
0
    const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
445
0
    const H5D_bt2_ctx_t   *ctx    = (const H5D_bt2_ctx_t *)_ctx;      /* Callback context */
446
0
    unsigned               u;                                         /* Local index variable */
447
448
0
    FUNC_ENTER_PACKAGE_NOERR
449
450
    /* Sanity checks */
451
0
    assert(record);
452
0
    assert(ctx->chunk_size == record->nbytes);
453
0
    assert(0 == record->filter_mask);
454
455
0
    fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, "Chunk address:", record->chunk_addr);
456
457
0
    fprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:");
458
0
    for (u = 0; u < ctx->ndims; u++)
459
0
        fprintf(stream, "%s%" PRIuHSIZE, u ? ", " : "", record->scaled[u] * ctx->dim[u]);
460
0
    fputs("}\n", stream);
461
462
0
    FUNC_LEAVE_NOAPI(SUCCEED)
463
0
} /* H5D__bt2_unfilt_debug() */
464
465
/*-------------------------------------------------------------------------
466
 * Function:    H5D__bt2_filt_encode
467
 *
468
 * Purpose:     Encode native information into raw form for storing on disk
469
 *              (filtered)
470
 *
471
 * Return:      Success:    non-negative
472
 *              Failure:    negative
473
 *
474
 *-------------------------------------------------------------------------
475
 */
476
static herr_t
477
H5D__bt2_filt_encode(uint8_t *raw, const void *_record, void *_ctx)
478
0
{
479
0
    H5D_bt2_ctx_t         *ctx    = (H5D_bt2_ctx_t *)_ctx;            /* Callback context structure */
480
0
    const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
481
0
    unsigned               u;                                         /* Local index variable */
482
483
0
    FUNC_ENTER_PACKAGE_NOERR
484
485
    /* Sanity check */
486
0
    assert(ctx);
487
0
    assert(record);
488
0
    assert(H5_addr_defined(record->chunk_addr));
489
0
    assert(0 != record->nbytes);
490
491
    /* Encode the record's fields */
492
0
    H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr);
493
0
    UINT64ENCODE_VAR(raw, record->nbytes, ctx->chunk_size_len);
494
0
    UINT32ENCODE(raw, record->filter_mask);
495
0
    for (u = 0; u < ctx->ndims; u++)
496
0
        UINT64ENCODE(raw, record->scaled[u]);
497
498
0
    FUNC_LEAVE_NOAPI(SUCCEED)
499
0
} /* H5D__bt2_filt_encode() */
500
501
/*-------------------------------------------------------------------------
502
 * Function:    H5D__bt2_filt_decode
503
 *
504
 * Purpose:     Decode raw disk form of record into native form
505
 *              (filtered)
506
 *
507
 * Return:      Success:    non-negative
508
 *              Failure:    negative
509
 *
510
 *-------------------------------------------------------------------------
511
 */
512
static herr_t
513
H5D__bt2_filt_decode(const uint8_t *raw, void *_record, void *_ctx)
514
0
{
515
0
    H5D_bt2_ctx_t   *ctx    = (H5D_bt2_ctx_t *)_ctx;      /* Callback context structure */
516
0
    H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */
517
0
    unsigned         u;                                   /* Local index variable */
518
519
0
    FUNC_ENTER_PACKAGE_NOERR
520
521
    /* Sanity check */
522
0
    assert(ctx);
523
0
    assert(record);
524
525
    /* Decode the record's fields */
526
0
    H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr);
527
0
    UINT64DECODE_VAR(raw, record->nbytes, ctx->chunk_size_len);
528
0
    UINT32DECODE(raw, record->filter_mask);
529
0
    for (u = 0; u < ctx->ndims; u++)
530
0
        UINT64DECODE(raw, record->scaled[u]);
531
532
    /* Sanity checks */
533
0
    assert(H5_addr_defined(record->chunk_addr));
534
0
    assert(0 != record->nbytes);
535
536
0
    FUNC_LEAVE_NOAPI(SUCCEED)
537
0
} /* H5D__bt2_filt_decode() */
538
539
/*-------------------------------------------------------------------------
540
 * Function:    H5D__bt2_filt_debug
541
 *
542
 * Purpose:     Debug native form of record (filtered)
543
 *
544
 * Return:      Success:    non-negative
545
 *              Failure:    negative
546
 *
547
 *-------------------------------------------------------------------------
548
 */
549
static herr_t
550
H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth, const void *_record, const void *_ctx)
551
0
{
552
0
    const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
553
0
    const H5D_bt2_ctx_t   *ctx    = (const H5D_bt2_ctx_t *)_ctx;      /* Callback context */
554
0
    unsigned               u;                                         /* Local index variable */
555
556
0
    FUNC_ENTER_PACKAGE_NOERR
557
558
    /* Sanity checks */
559
0
    assert(record);
560
0
    assert(H5_addr_defined(record->chunk_addr));
561
0
    assert(0 != record->nbytes);
562
563
0
    fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, "Chunk address:", record->chunk_addr);
564
0
    fprintf(stream, "%*s%-*s %" PRIuHSIZE " bytes\n", indent, "", fwidth, "Chunk size:", record->nbytes);
565
0
    fprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth, "Filter mask:", record->filter_mask);
566
567
0
    fprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:");
568
0
    for (u = 0; u < ctx->ndims; u++)
569
0
        fprintf(stream, "%s%" PRIuHSIZE, u ? ", " : "", record->scaled[u] * ctx->dim[u]);
570
0
    fputs("}\n", stream);
571
572
0
    FUNC_LEAVE_NOAPI(SUCCEED)
573
0
} /* H5D__bt2_filt_debug() */
574
575
/*-------------------------------------------------------------------------
576
 * Function:    H5D__bt2_idx_init
577
 *
578
 * Purpose:     Initialize the indexing information for a dataset.
579
 *
580
 * Return:      Non-negative on success/Negative on failure
581
 *
582
 *-------------------------------------------------------------------------
583
 */
584
static herr_t
585
H5D__bt2_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t H5_ATTR_UNUSED *space,
586
                  haddr_t dset_ohdr_addr)
587
0
{
588
0
    FUNC_ENTER_PACKAGE_NOERR
589
590
    /* Check args */
591
0
    assert(H5_addr_defined(dset_ohdr_addr));
592
593
0
    idx_info->layout->storage.u.chunk.u.btree2.dset_ohdr_addr = dset_ohdr_addr;
594
595
0
    FUNC_LEAVE_NOAPI(SUCCEED)
596
0
} /* end H5D__bt2_idx_init() */
597
598
/*-------------------------------------------------------------------------
599
 * Function:    H5D__btree2_idx_depend
600
 *
601
 * Purpose:     Create flush dependency between v2 B-tree and dataset's
602
 *              object header.
603
 *
604
 * Return:      Success:    non-negative
605
 *              Failure:    negative
606
 *
607
 *-------------------------------------------------------------------------
608
 */
609
static herr_t
610
H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info)
611
0
{
612
0
    H5O_t              *oh = NULL;           /* Object header */
613
0
    H5O_loc_t           oloc;                /* Temporary object header location for dataset */
614
0
    H5AC_proxy_entry_t *oh_proxy;            /* Dataset's object header proxy */
615
0
    herr_t              ret_value = SUCCEED; /* Return value */
616
617
0
    FUNC_ENTER_PACKAGE
618
619
    /* Check args */
620
0
    assert(idx_info);
621
0
    assert(idx_info->f);
622
0
    assert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE);
623
0
    assert(idx_info->pline);
624
0
    assert(idx_info->layout);
625
0
    assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->u.chunk.idx_type);
626
0
    assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->storage.u.chunk.idx_type);
627
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
628
0
    assert(idx_info->layout->storage.u.chunk.u.btree2.bt2);
629
630
    /* Set up object header location for dataset */
631
0
    H5O_loc_reset(&oloc);
632
0
    oloc.file = idx_info->f;
633
0
    oloc.addr = idx_info->layout->storage.u.chunk.u.btree.dset_ohdr_addr;
634
635
    /* Get header */
636
0
    if (NULL == (oh = H5O_protect(&oloc, H5AC__READ_ONLY_FLAG, true)))
637
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect object header");
638
639
    /* Retrieve the dataset's object header proxy */
640
0
    if (NULL == (oh_proxy = H5O_get_proxy(oh)))
641
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset object header proxy");
642
643
    /* Make the v2 B-tree a child flush dependency of the dataset's object header proxy */
644
0
    if (H5B2_depend(idx_info->layout->storage.u.chunk.u.btree2.bt2, oh_proxy) < 0)
645
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL,
646
0
                    "unable to create flush dependency on object header proxy");
647
648
0
done:
649
    /* Release the object header from the cache */
650
0
    if (oh && H5O_unprotect(&oloc, oh, H5AC__NO_FLAGS_SET) < 0)
651
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
652
653
0
    FUNC_LEAVE_NOAPI(ret_value)
654
0
} /* end H5D__btree2_idx_depend() */
655
656
/*-------------------------------------------------------------------------
657
 * Function:    H5D__bt2_idx_create
658
 *
659
 * Purpose:     Create the v2 B-tree for tracking dataset chunks
660
 *
661
 * Return:      SUCCEED/FAIL
662
 *
663
 *-------------------------------------------------------------------------
664
 */
665
static herr_t
666
H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info)
667
0
{
668
0
    H5B2_create_t    bt2_cparam;               /* v2 B-tree creation parameters */
669
0
    H5D_bt2_ctx_ud_t u_ctx;                    /* data for context call */
670
0
    unsigned         chunk_size_len = 0;       /* Size of encoded chunk size */
671
0
    herr_t           ret_value      = SUCCEED; /* Return value */
672
673
0
    FUNC_ENTER_PACKAGE
674
675
    /* Check args */
676
0
    assert(idx_info);
677
0
    assert(idx_info->f);
678
0
    assert(idx_info->pline);
679
0
    assert(idx_info->layout);
680
0
    assert(!H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
681
682
    /* Compute number of bytes used to encode the chunk size */
683
0
    H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, idx_info);
684
685
    /* Set up b-tree creation parameters */
686
0
    bt2_cparam.rrec_size =
687
0
        H5F_SIZEOF_ADDR(idx_info->f)                 /* Address of chunk */
688
0
        + (idx_info->layout->u.chunk.ndims - 1) * 8; /* # of dimensions x 64-bit chunk offsets */
689
690
    /* General parameters */
691
0
    if (idx_info->pline->nused > 0) {
692
0
        bt2_cparam.rrec_size += chunk_size_len + 4; /* Size of encoded chunk size & filter mask */
693
0
        bt2_cparam.cls = H5D_BT2_FILT;
694
0
    } /* end if */
695
0
    else
696
0
        bt2_cparam.cls = H5D_BT2;
697
698
0
    bt2_cparam.node_size     = idx_info->layout->u.chunk.u.btree2.cparam.node_size;
699
0
    bt2_cparam.split_percent = idx_info->layout->u.chunk.u.btree2.cparam.split_percent;
700
0
    bt2_cparam.merge_percent = idx_info->layout->u.chunk.u.btree2.cparam.merge_percent;
701
702
    /* Set up client context */
703
0
    u_ctx.f              = idx_info->f;
704
0
    u_ctx.ndims          = idx_info->layout->u.chunk.ndims - 1;
705
0
    u_ctx.chunk_size     = idx_info->layout->u.chunk.size;
706
0
    u_ctx.dim            = idx_info->layout->u.chunk.dim;
707
0
    u_ctx.chunk_size_len = (size_t)chunk_size_len;
708
709
    /* Create the v2 B-tree for the chunked dataset */
710
0
    if (NULL ==
711
0
        (idx_info->layout->storage.u.chunk.u.btree2.bt2 = H5B2_create(idx_info->f, &bt2_cparam, &u_ctx)))
712
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create v2 B-tree for tracking chunked dataset");
713
714
    /* Retrieve the v2 B-tree's address in the file */
715
0
    if (H5B2_get_addr(idx_info->layout->storage.u.chunk.u.btree2.bt2,
716
0
                      &(idx_info->layout->storage.u.chunk.idx_addr)) < 0)
717
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
718
0
                    "can't get v2 B-tree address for tracking chunked dataset");
719
720
    /* Check for SWMR writes to the file */
721
0
    if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
722
0
        if (H5D__btree2_idx_depend(idx_info) < 0)
723
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL,
724
0
                        "unable to create flush dependency on object header");
725
726
0
done:
727
0
    FUNC_LEAVE_NOAPI(ret_value)
728
0
} /* end H5D__bt2_idx_create() */
729
730
/*-------------------------------------------------------------------------
731
 * Function:    H5D__bt2_idx_open()
732
 *
733
 * Purpose:     Opens an existing v2 B-tree.
734
 *
735
 * Note:        This information is passively initialized from each index
736
 *              operation callback because those abstract chunk index
737
 *              operations are designed to work with the v2 B-tree chunk
738
 *              indices also, which don't require an 'open' for the data
739
 *              structure.
740
 *
741
 * Return:      Success:    non-negative
742
 *              Failure:    negative
743
 *
744
 *-------------------------------------------------------------------------
745
 */
746
static herr_t
747
H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info)
748
0
{
749
0
    H5D_bt2_ctx_ud_t u_ctx;               /* user data for creating context */
750
0
    herr_t           ret_value = SUCCEED; /* Return value */
751
752
0
    FUNC_ENTER_PACKAGE
753
754
    /* Check args */
755
0
    assert(idx_info);
756
0
    assert(idx_info->f);
757
0
    assert(idx_info->pline);
758
0
    assert(idx_info->layout);
759
0
    assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->u.chunk.idx_type);
760
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
761
0
    assert(NULL == idx_info->layout->storage.u.chunk.u.btree2.bt2);
762
763
    /* Set up the user data */
764
0
    u_ctx.f          = idx_info->f;
765
0
    u_ctx.ndims      = idx_info->layout->u.chunk.ndims - 1;
766
0
    u_ctx.chunk_size = idx_info->layout->u.chunk.size;
767
0
    u_ctx.dim        = idx_info->layout->u.chunk.dim;
768
769
    /* Compute number of bytes used to encode the chunk size */
770
0
    H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(u_ctx.chunk_size_len, idx_info);
771
772
    /* Open v2 B-tree for the chunk index */
773
0
    if (NULL == (idx_info->layout->storage.u.chunk.u.btree2.bt2 =
774
0
                     H5B2_open(idx_info->f, idx_info->layout->storage.u.chunk.idx_addr, &u_ctx)))
775
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't open v2 B-tree for tracking chunked dataset");
776
777
    /* Check for SWMR writes to the file */
778
0
    if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
779
0
        if (H5D__btree2_idx_depend(idx_info) < 0)
780
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL,
781
0
                        "unable to create flush dependency on object header");
782
783
0
done:
784
0
    FUNC_LEAVE_NOAPI(ret_value)
785
0
} /* end H5D__bt2_idx_open() */
786
787
/*-------------------------------------------------------------------------
788
 * Function:    H5D__bt2_idx_close()
789
 *
790
 * Purpose:     Closes an existing v2 B-tree.
791
 *
792
 * Return:      Success:    non-negative
793
 *              Failure:    negative
794
 *
795
 *-------------------------------------------------------------------------
796
 */
797
static herr_t
798
H5D__bt2_idx_close(const H5D_chk_idx_info_t *idx_info)
799
0
{
800
0
    herr_t ret_value = SUCCEED; /* Return value */
801
802
0
    FUNC_ENTER_PACKAGE
803
804
0
    assert(idx_info);
805
0
    assert(idx_info->layout);
806
0
    assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->storage.u.chunk.idx_type);
807
0
    assert(idx_info->layout->storage.u.chunk.u.btree2.bt2);
808
809
0
    if (H5B2_close(idx_info->layout->storage.u.chunk.u.btree2.bt2) < 0)
810
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree");
811
0
    idx_info->layout->storage.u.chunk.u.btree2.bt2 = NULL;
812
813
0
done:
814
0
    FUNC_LEAVE_NOAPI(ret_value)
815
0
} /* end H5D__bt2_idx_close() */
816
817
/*-------------------------------------------------------------------------
818
 * Function:    H5D__bt2_idx_is_open
819
 *
820
 * Purpose:     Query if the index is opened or not
821
 *
822
 * Return:      SUCCEED (can't fail)
823
 *
824
 *-------------------------------------------------------------------------
825
 */
826
static herr_t
827
H5D__bt2_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open)
828
0
{
829
0
    FUNC_ENTER_PACKAGE_NOERR
830
831
0
    assert(idx_info);
832
0
    assert(idx_info->layout);
833
0
    assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->storage.u.chunk.idx_type);
834
0
    assert(is_open);
835
836
0
    *is_open = H5D_BT2_IDX_IS_OPEN(idx_info);
837
838
0
    FUNC_LEAVE_NOAPI(SUCCEED)
839
0
} /* end H5D__bt2_idx_is_open() */
840
841
/*-------------------------------------------------------------------------
842
 * Function:    H5D__bt2_idx_is_space_alloc
843
 *
844
 * Purpose:     Query if space is allocated for index method
845
 *
846
 * Return:      true/false
847
 *
848
 *-------------------------------------------------------------------------
849
 */
850
static bool
851
H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
852
0
{
853
0
    FUNC_ENTER_PACKAGE_NOERR
854
855
    /* Check args */
856
0
    assert(storage);
857
858
0
    FUNC_LEAVE_NOAPI((bool)H5_addr_defined(storage->idx_addr))
859
0
} /* end H5D__bt2_idx_is_space_alloc() */
860
861
/*-------------------------------------------------------------------------
862
 * Function:    H5D__bt2_mod_cb
863
 *
864
 * Purpose:     Modify record for dataset chunk when it is found in a v2
865
 *              B-tree. This is the callback for H5B2_update() which is
866
 *              called in H5D__bt2_idx_insert().
867
 *
868
 * Return:      Success:    non-negative
869
 *              Failure:    negative
870
 *
871
 *-------------------------------------------------------------------------
872
 */
873
static herr_t
874
H5D__bt2_mod_cb(void *_record, void *_op_data, bool *changed)
875
0
{
876
0
    H5D_bt2_ud_t    *op_data = (H5D_bt2_ud_t *)_op_data;   /* User data for v2 B-tree calls */
877
0
    H5D_chunk_rec_t *record  = (H5D_chunk_rec_t *)_record; /* Chunk record */
878
879
0
    FUNC_ENTER_PACKAGE_NOERR
880
881
/* Sanity check */
882
#ifndef NDEBUG
883
    {
884
        unsigned u; /* Local index variable */
885
886
        for (u = 0; u < op_data->ndims; u++)
887
            assert(record->scaled[u] == op_data->rec.scaled[u]);
888
    }
889
#endif /* NDEBUG */
890
891
    /* Modify record */
892
0
    *record = op_data->rec;
893
894
    /* Note that the record changed */
895
0
    *changed = true;
896
897
0
    FUNC_LEAVE_NOAPI(SUCCEED)
898
0
} /* end H5D__bt2_mod_cb() */
899
900
/*-------------------------------------------------------------------------
901
 * Function:    H5D__bt2_idx_insert
902
 *
903
 * Purpose:     Insert chunk address into the indexing structure.
904
 *              A non-filtered chunk:
905
 *                Should not exist
906
 *                Allocate the chunk and pass chunk address back up
907
 *              A filtered chunk:
908
 *                If it was not found, create the chunk and pass chunk
909
 *                  address back up
910
 *                If it was found but its size changed, reallocate the chunk
911
 *                  and pass chunk address back up
912
 *                If it was found but its size was the same, pass chunk
913
 *                  address back up
914
 *
915
 * Return:      Non-negative on success/Negative on failure
916
 *
917
 *-------------------------------------------------------------------------
918
 */
919
static herr_t
920
H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
921
                    const H5D_t H5_ATTR_UNUSED *dset)
922
0
{
923
0
    H5B2_t      *bt2;                 /* v2 B-tree handle for indexing chunks */
924
0
    H5D_bt2_ud_t bt2_udata;           /* User data for v2 B-tree calls */
925
0
    unsigned     u;                   /* Local index variable */
926
0
    herr_t       ret_value = SUCCEED; /* Return value */
927
928
0
    FUNC_ENTER_PACKAGE
929
930
    /* Sanity checks */
931
0
    assert(idx_info);
932
0
    assert(idx_info->f);
933
0
    assert(idx_info->pline);
934
0
    assert(idx_info->layout);
935
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
936
0
    assert(udata);
937
0
    assert(H5_addr_defined(udata->chunk_block.offset));
938
939
    /* Check if the v2 B-tree is open yet */
940
0
    if (!H5D_BT2_IDX_IS_OPEN(idx_info)) {
941
        /* Open existing v2 B-tree */
942
0
        if (H5D__bt2_idx_open(idx_info) < 0)
943
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree");
944
0
    }    /* end if */
945
0
    else /* Patch the top level file pointer contained in bt2 if needed */
946
0
        if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0)
947
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer");
948
949
    /* Set convenience pointer to v2 B-tree structure */
950
0
    bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2;
951
952
    /* Set up callback info */
953
0
    bt2_udata.ndims          = idx_info->layout->u.chunk.ndims - 1;
954
0
    bt2_udata.rec.chunk_addr = udata->chunk_block.offset;
955
0
    if (idx_info->pline->nused > 0) { /* filtered chunk */
956
0
        bt2_udata.rec.nbytes      = udata->chunk_block.length;
957
0
        bt2_udata.rec.filter_mask = udata->filter_mask;
958
0
    }      /* end if */
959
0
    else { /* non-filtered chunk */
960
0
        bt2_udata.rec.nbytes      = idx_info->layout->u.chunk.size;
961
0
        bt2_udata.rec.filter_mask = 0;
962
0
    } /* end else */
963
0
    for (u = 0; u < (idx_info->layout->u.chunk.ndims - 1); u++)
964
0
        bt2_udata.rec.scaled[u] = udata->common.scaled[u];
965
966
    /* Update record for v2 B-tree (could be insert or modify) */
967
0
    if (H5B2_update(bt2, &bt2_udata, H5D__bt2_mod_cb, &bt2_udata) < 0)
968
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTUPDATE, FAIL, "unable to update record in v2 B-tree");
969
970
0
done:
971
0
    FUNC_LEAVE_NOAPI(ret_value)
972
0
} /* H5D__bt2_idx_insert() */
973
974
/*-------------------------------------------------------------------------
975
 * Function:    H5D__bt2_found_cb
976
 *
977
 * Purpose:     Retrieve record for dataset chunk when it is found in a v2
978
 *              B-tree. This is the callback for H5B2_find() which is called
979
 *              in H5D__bt2_idx_get_addr() and H5D__bt2_idx_insert().
980
 *
981
 * Return:      Success:    non-negative
982
 *              Failure:    negative
983
 *
984
 *-------------------------------------------------------------------------
985
 */
986
static herr_t
987
H5D__bt2_found_cb(const void *nrecord, void *op_data)
988
0
{
989
0
    FUNC_ENTER_PACKAGE_NOERR
990
991
0
    *(H5D_chunk_rec_t *)op_data = *(const H5D_chunk_rec_t *)nrecord;
992
993
0
    FUNC_LEAVE_NOAPI(SUCCEED)
994
0
} /* H5D__bt2_found_cb() */
995
996
/*-------------------------------------------------------------------------
997
 * Function:    H5D__bt2_idx_get_addr
998
 *
999
 * Purpose:     Get the file address of a chunk if file space has been
1000
 *              assigned.  Save the retrieved information in the udata
1001
 *              supplied.
1002
 *
1003
 * Return:      Non-negative on success/Negative on failure
1004
 *
1005
 *-------------------------------------------------------------------------
1006
 */
1007
static herr_t
1008
H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
1009
0
{
1010
0
    H5B2_t         *bt2;                 /* v2 B-tree handle for indexing chunks */
1011
0
    H5D_bt2_ud_t    bt2_udata;           /* User data for v2 B-tree calls */
1012
0
    H5D_chunk_rec_t found_rec;           /* Record found from searching for object */
1013
0
    unsigned        u;                   /* Local index variable */
1014
0
    bool            found;               /* Whether chunk was found */
1015
0
    herr_t          ret_value = SUCCEED; /* Return value */
1016
1017
0
    FUNC_ENTER_PACKAGE
1018
1019
    /* Sanity checks */
1020
0
    assert(idx_info);
1021
0
    assert(idx_info->f);
1022
0
    assert(idx_info->pline);
1023
0
    assert(idx_info->layout);
1024
0
    assert(idx_info->layout->u.chunk.ndims > 0);
1025
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1026
0
    assert(udata);
1027
1028
    /* Check if the v2 B-tree is open yet */
1029
0
    if (!H5D_BT2_IDX_IS_OPEN(idx_info)) {
1030
        /* Open existing v2 B-tree */
1031
0
        if (H5D__bt2_idx_open(idx_info) < 0)
1032
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree");
1033
0
    }    /* end if */
1034
0
    else /* Patch the top level file pointer contained in bt2 if needed */
1035
0
        if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0)
1036
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer");
1037
1038
    /* Set convenience pointer to v2 B-tree structure */
1039
0
    bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2;
1040
1041
    /* Clear the found record */
1042
0
    found_rec.chunk_addr  = HADDR_UNDEF;
1043
0
    found_rec.nbytes      = 0;
1044
0
    found_rec.filter_mask = 0;
1045
1046
    /* Prepare user data for compare callback */
1047
0
    bt2_udata.rec.chunk_addr = HADDR_UNDEF;
1048
0
    bt2_udata.ndims          = idx_info->layout->u.chunk.ndims - 1;
1049
1050
    /* Set the chunk offset to be searched for */
1051
0
    for (u = 0; u < (idx_info->layout->u.chunk.ndims - 1); u++)
1052
0
        bt2_udata.rec.scaled[u] = udata->common.scaled[u];
1053
1054
    /* Go get chunk information from v2 B-tree */
1055
0
    found = false;
1056
0
    if (H5B2_find(bt2, &bt2_udata, &found, H5D__bt2_found_cb, &found_rec) < 0)
1057
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFIND, FAIL, "can't check for chunk in v2 B-tree");
1058
1059
    /* Check if chunk was found */
1060
0
    if (found) {
1061
        /* Sanity check */
1062
0
        assert(0 != found_rec.nbytes);
1063
1064
        /* Set common info for the chunk */
1065
0
        udata->chunk_block.offset = found_rec.chunk_addr;
1066
1067
        /* Set other info for the chunk */
1068
0
        if (idx_info->pline->nused > 0) { /* filtered chunk */
1069
0
            udata->chunk_block.length = found_rec.nbytes;
1070
0
            udata->filter_mask        = found_rec.filter_mask;
1071
0
        }      /* end if */
1072
0
        else { /* non-filtered chunk */
1073
0
            udata->chunk_block.length = idx_info->layout->u.chunk.size;
1074
0
            udata->filter_mask        = 0;
1075
0
        } /* end else */
1076
0
    }     /* end if */
1077
0
    else {
1078
0
        udata->chunk_block.offset = HADDR_UNDEF;
1079
0
        udata->chunk_block.length = 0;
1080
0
        udata->filter_mask        = 0;
1081
0
    } /* end else */
1082
1083
0
done:
1084
0
    FUNC_LEAVE_NOAPI(ret_value)
1085
0
} /* H5D__bt2_idx_get_addr() */
1086
1087
/*-------------------------------------------------------------------------
1088
 * Function:    H5D__bt2_idx_load_metadata
1089
 *
1090
 * Purpose:     Load additional chunk index metadata beyond the chunk index
1091
 *              itself.
1092
 *
1093
 * Return:      Non-negative on success/Negative on failure
1094
 *
1095
 *-------------------------------------------------------------------------
1096
 */
1097
static herr_t
1098
H5D__bt2_idx_load_metadata(const H5D_chk_idx_info_t *idx_info)
1099
0
{
1100
0
    H5D_chunk_ud_t chunk_ud;
1101
0
    hsize_t        scaled[H5O_LAYOUT_NDIMS] = {0};
1102
0
    herr_t         ret_value                = SUCCEED;
1103
1104
0
    FUNC_ENTER_PACKAGE
1105
1106
    /*
1107
     * After opening a dataset that uses a v2 Btree, the root
1108
     * node will generally not be read in until an element is
1109
     * looked up for the first time. Since there isn't currently
1110
     * a good way of controlling that explicitly, perform a fake
1111
     * lookup of a chunk to cause it to be read in.
1112
     */
1113
0
    chunk_ud.common.layout  = &idx_info->layout->u.chunk;
1114
0
    chunk_ud.common.storage = &idx_info->layout->storage.u.chunk;
1115
0
    chunk_ud.common.scaled  = scaled;
1116
1117
0
    chunk_ud.chunk_block.offset = HADDR_UNDEF;
1118
0
    chunk_ud.chunk_block.length = 0;
1119
0
    chunk_ud.filter_mask        = 0;
1120
0
    chunk_ud.new_unfilt_chunk   = false;
1121
0
    chunk_ud.idx_hint           = UINT_MAX;
1122
1123
0
    if (H5D__bt2_idx_get_addr(idx_info, &chunk_ud) < 0)
1124
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't load v2 B-tree root node");
1125
1126
0
done:
1127
0
    FUNC_LEAVE_NOAPI(ret_value)
1128
0
} /* H5D__bt2_idx_load_metadata() */
1129
1130
/*-------------------------------------------------------------------------
1131
 * Function:    H5D__bt2_idx_iterate_cb
1132
 *
1133
 * Purpose:     Translate the B-tree specific chunk record into a generic
1134
 *              form and make the callback to the generic chunk callback
1135
 *              routine.
1136
 *              This is the callback for H5B2_iterate() which is called in
1137
 *              H5D__bt2_idx_iterate().
1138
 *
1139
 * Return:      Success:    Non-negative
1140
 *              Failure:    Negative
1141
 *
1142
 *-------------------------------------------------------------------------
1143
 */
1144
static int
1145
H5D__bt2_idx_iterate_cb(const void *_record, void *_udata)
1146
0
{
1147
0
    H5D_bt2_it_ud_t       *udata     = (H5D_bt2_it_ud_t *)_udata;        /* User data */
1148
0
    const H5D_chunk_rec_t *record    = (const H5D_chunk_rec_t *)_record; /* Native record */
1149
0
    int                    ret_value = -1;                               /* Return value */
1150
1151
0
    FUNC_ENTER_PACKAGE_NOERR
1152
1153
    /* Make "generic chunk" callback */
1154
0
    if ((ret_value = (udata->cb)(record, udata->udata)) < 0)
1155
0
        HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
1156
1157
0
    FUNC_LEAVE_NOAPI(ret_value)
1158
0
} /* H5D__bt2_idx_iterate_cb() */
1159
1160
/*-------------------------------------------------------------------------
1161
 * Function:    H5D__bt2_idx_iterate
1162
 *
1163
 * Purpose:     Iterate over the chunks in an index, making a callback
1164
 *              for each one.
1165
 *
1166
 * Return:      Non-negative on success/Negative on failure
1167
 *
1168
 *-------------------------------------------------------------------------
1169
 */
1170
static int
1171
H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
1172
0
{
1173
0
    H5B2_t         *bt2;              /* v2 B-tree handle for indexing chunks */
1174
0
    H5D_bt2_it_ud_t udata;            /* User data for B-tree iterator callback */
1175
0
    int             ret_value = FAIL; /* Return value */
1176
1177
0
    FUNC_ENTER_PACKAGE
1178
1179
    /* Sanity checks */
1180
0
    assert(idx_info);
1181
0
    assert(idx_info->f);
1182
0
    assert(idx_info->pline);
1183
0
    assert(idx_info->layout);
1184
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1185
0
    assert(chunk_cb);
1186
0
    assert(chunk_udata);
1187
1188
    /* Check if the v2 B-tree is open yet */
1189
0
    if (!H5D_BT2_IDX_IS_OPEN(idx_info)) {
1190
        /* Open existing v2 B-tree */
1191
0
        if (H5D__bt2_idx_open(idx_info) < 0)
1192
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree");
1193
0
    }    /* end if */
1194
0
    else /* Patch the top level file pointer contained in bt2 if needed */
1195
0
        if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0)
1196
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer");
1197
1198
    /* Set convenience pointer to v2 B-tree structure */
1199
0
    bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2;
1200
1201
    /* Prepare user data for iterate callback */
1202
0
    udata.cb    = chunk_cb;
1203
0
    udata.udata = chunk_udata;
1204
1205
    /* Iterate over the records in the v2 B-tree */
1206
0
    if ((ret_value = H5B2_iterate(bt2, H5D__bt2_idx_iterate_cb, &udata)) < 0)
1207
0
        HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over chunk v2 B-tree");
1208
1209
0
done:
1210
0
    FUNC_LEAVE_NOAPI(ret_value)
1211
0
} /* end H5D__bt2_idx_iterate() */
1212
1213
/*-------------------------------------------------------------------------
1214
 * Function:    H5D__bt2_remove_cb()
1215
 *
1216
 * Purpose:     Free space for 'dataset chunk' object as v2 B-tree
1217
 *              is being deleted or v2 B-tree node is removed.
1218
 *              This is the callback for H5B2_remove() and H5B2_delete()
1219
 *              which are called in H5D__bt2_idx_remove() and
1220
 *              H5D__bt2_idx_delete().
1221
 *
1222
 * Return:      Success:    non-negative
1223
 *              Failure:    negative
1224
 *
1225
 *-------------------------------------------------------------------------
1226
 */
1227
static herr_t
1228
H5D__bt2_remove_cb(const void *_record, void *_udata)
1229
0
{
1230
0
    const H5D_chunk_rec_t *record    = (const H5D_chunk_rec_t *)_record; /* The native record */
1231
0
    H5F_t                 *f         = (H5F_t *)_udata;                  /* User data for removal callback */
1232
0
    herr_t                 ret_value = SUCCEED;                          /* Return value */
1233
1234
0
    FUNC_ENTER_PACKAGE
1235
1236
    /* Sanity checks */
1237
0
    assert(f);
1238
1239
    /* Free the space in the file for the object being removed */
1240
0
    if (H5MF_xfree(f, H5FD_MEM_DRAW, record->chunk_addr, record->nbytes) < 0)
1241
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk");
1242
1243
0
done:
1244
0
    FUNC_LEAVE_NOAPI(ret_value)
1245
0
} /* H5D__bt2_remove_cb() */
1246
1247
/*-------------------------------------------------------------------------
1248
 * Function:    H5D__bt2_idx_remove
1249
 *
1250
 * Purpose:     Remove chunk from index.
1251
 *
1252
 * Return:      Non-negative on success/Negative on failure
1253
 *
1254
 *-------------------------------------------------------------------------
1255
 */
1256
static herr_t
1257
H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata)
1258
0
{
1259
0
    H5B2_t      *bt2;                 /* v2 B-tree handle for indexing chunks */
1260
0
    H5D_bt2_ud_t bt2_udata;           /* User data for v2 B-tree find call */
1261
0
    unsigned     u;                   /* Local index variable */
1262
0
    herr_t       ret_value = SUCCEED; /* Return value */
1263
1264
0
    FUNC_ENTER_PACKAGE
1265
1266
    /* Sanity checks */
1267
0
    assert(idx_info);
1268
0
    assert(idx_info->f);
1269
0
    assert(idx_info->pline);
1270
0
    assert(idx_info->layout);
1271
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1272
0
    assert(udata);
1273
1274
    /* Check if the v2 B-tree is open yet */
1275
0
    if (!H5D_BT2_IDX_IS_OPEN(idx_info)) {
1276
        /* Open existing v2 B-tree */
1277
0
        if (H5D__bt2_idx_open(idx_info) < 0)
1278
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree");
1279
0
    }    /* end if */
1280
0
    else /* Patch the top level file pointer contained in bt2 if needed */
1281
0
        if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0)
1282
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer");
1283
1284
    /* Set convenience pointer to v2 B-tree structure */
1285
0
    bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2;
1286
1287
    /* Prepare user data for compare callback */
1288
0
    bt2_udata.ndims = idx_info->layout->u.chunk.ndims - 1;
1289
1290
    /* Initialize the record to search for */
1291
0
    for (u = 0; u < (idx_info->layout->u.chunk.ndims - 1); u++)
1292
0
        bt2_udata.rec.scaled[u] = udata->scaled[u];
1293
1294
    /* Remove the record for the "dataset chunk" object from the v2 B-tree */
1295
    /* (space in the file for the object is freed in the 'remove' callback) */
1296
0
    if (H5B2_remove(bt2, &bt2_udata,
1297
0
                    (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) ? NULL : H5D__bt2_remove_cb,
1298
0
                    idx_info->f) < 0)
1299
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree");
1300
1301
0
done:
1302
0
    FUNC_LEAVE_NOAPI(ret_value)
1303
0
} /* H5D__bt2_idx_remove() */
1304
1305
/*-------------------------------------------------------------------------
1306
 * Function:    H5D__bt2_idx_delete
1307
 *
1308
 * Purpose:     Delete index and raw data storage for entire dataset
1309
 *              (i.e. all chunks)
1310
 *
1311
 * Return:      Success:    Non-negative
1312
 *              Failure:    negative
1313
 *
1314
 *-------------------------------------------------------------------------
1315
 */
1316
static herr_t
1317
H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info)
1318
0
{
1319
0
    H5B2_remove_t    remove_op;           /* The removal callback */
1320
0
    H5D_bt2_ctx_ud_t u_ctx;               /* data for context call */
1321
0
    herr_t           ret_value = SUCCEED; /* Return value */
1322
1323
0
    FUNC_ENTER_PACKAGE
1324
1325
    /* Sanity checks */
1326
0
    assert(idx_info);
1327
0
    assert(idx_info->f);
1328
0
    assert(idx_info->pline);
1329
0
    assert(idx_info->layout);
1330
1331
    /* Check if the index data structure has been allocated */
1332
0
    if (H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)) {
1333
        /* Set up user data for creating context */
1334
0
        u_ctx.f          = idx_info->f;
1335
0
        u_ctx.ndims      = idx_info->layout->u.chunk.ndims - 1;
1336
0
        u_ctx.chunk_size = idx_info->layout->u.chunk.size;
1337
0
        u_ctx.dim        = idx_info->layout->u.chunk.dim;
1338
1339
        /* Compute number of bytes used to encode the chunk size */
1340
0
        H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(u_ctx.chunk_size_len, idx_info);
1341
1342
        /* Set remove operation.  Do not remove chunks in SWMR_WRITE mode */
1343
0
        if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
1344
0
            remove_op = NULL;
1345
0
        else
1346
0
            remove_op = H5D__bt2_remove_cb;
1347
1348
        /* Delete the v2 B-tree */
1349
        /*(space in the file for each object is freed in the 'remove' callback) */
1350
0
        if (H5B2_delete(idx_info->f, idx_info->layout->storage.u.chunk.idx_addr, &u_ctx, remove_op,
1351
0
                        idx_info->f) < 0)
1352
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "can't delete v2 B-tree");
1353
1354
0
        idx_info->layout->storage.u.chunk.idx_addr = HADDR_UNDEF;
1355
0
    } /* end if */
1356
1357
0
done:
1358
0
    FUNC_LEAVE_NOAPI(ret_value)
1359
0
} /* end H5D__bt2_idx_delete() */
1360
1361
/*-------------------------------------------------------------------------
1362
 * Function:    H5D__bt2_idx_copy_setup
1363
 *
1364
 * Purpose:     Set up any necessary information for copying chunks
1365
 *
1366
 * Return:      Non-negative on success/Negative on failure
1367
 *
1368
 *-------------------------------------------------------------------------
1369
 */
1370
static herr_t
1371
H5D__bt2_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src, const H5D_chk_idx_info_t *idx_info_dst)
1372
0
{
1373
0
    herr_t ret_value = SUCCEED; /* Return value */
1374
1375
0
    FUNC_ENTER_PACKAGE
1376
1377
    /* Source file */
1378
0
    assert(idx_info_src);
1379
0
    assert(idx_info_src->f);
1380
0
    assert(idx_info_src->pline);
1381
0
    assert(idx_info_src->layout);
1382
1383
    /* Destination file */
1384
0
    assert(idx_info_dst);
1385
0
    assert(idx_info_dst->f);
1386
0
    assert(idx_info_dst->pline);
1387
0
    assert(idx_info_dst->layout);
1388
0
    assert(!H5_addr_defined(idx_info_dst->layout->storage.u.chunk.idx_addr));
1389
1390
    /* Check if the source v2 B-tree is open yet */
1391
0
    if (!H5D_BT2_IDX_IS_OPEN(idx_info_src))
1392
0
        if (H5D__bt2_idx_open(idx_info_src) < 0)
1393
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree");
1394
1395
    /* Set copied metadata tag */
1396
0
    H5_BEGIN_TAG(H5AC__COPIED_TAG)
1397
1398
    /* Create v2 B-tree that describes the chunked dataset in the destination file */
1399
0
    if (H5D__bt2_idx_create(idx_info_dst) < 0)
1400
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage");
1401
0
    assert(H5_addr_defined(idx_info_dst->layout->storage.u.chunk.idx_addr));
1402
1403
    /* Reset metadata tag */
1404
0
    H5_END_TAG
1405
1406
0
done:
1407
0
    FUNC_LEAVE_NOAPI(ret_value)
1408
0
} /* end H5D__bt2_idx_copy_setup() */
1409
1410
/*-------------------------------------------------------------------------
1411
 * Function:    H5D__bt2_idx_copy_shutdown
1412
 *
1413
 * Purpose:     Shutdown any information from copying chunks
1414
 *
1415
 * Return:      Non-negative on success/Negative on failure
1416
 *
1417
 *-------------------------------------------------------------------------
1418
 */
1419
static herr_t
1420
H5D__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst)
1421
0
{
1422
0
    herr_t ret_value = SUCCEED; /* Return value */
1423
1424
0
    FUNC_ENTER_PACKAGE
1425
1426
    /* Check args */
1427
0
    assert(storage_src);
1428
0
    assert(storage_src->u.btree2.bt2);
1429
0
    assert(storage_dst);
1430
0
    assert(storage_dst->u.btree2.bt2);
1431
1432
    /* Close v2 B-tree for source file */
1433
0
    if (H5B2_close(storage_src->u.btree2.bt2) < 0)
1434
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree");
1435
0
    storage_src->u.btree2.bt2 = NULL;
1436
1437
    /* Close v2 B-tree for destination file */
1438
0
    if (H5B2_close(storage_dst->u.btree2.bt2) < 0)
1439
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree");
1440
0
    storage_dst->u.btree2.bt2 = NULL;
1441
1442
0
done:
1443
0
    FUNC_LEAVE_NOAPI(ret_value)
1444
0
} /* end H5D__bt2_idx_copy_shutdown() */
1445
1446
/*-------------------------------------------------------------------------
1447
 * Function:    H5D__bt2_idx_size
1448
 *
1449
 * Purpose:     Retrieve the amount of index storage for chunked dataset
1450
 *
1451
 * Return:      Success:    Non-negative
1452
 *              Failure:    negative
1453
 *
1454
 *-------------------------------------------------------------------------
1455
 */
1456
static herr_t
1457
H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
1458
0
{
1459
0
    H5B2_t *bt2_cdset = NULL;    /* Pointer to v2 B-tree structure */
1460
0
    herr_t  ret_value = SUCCEED; /* Return value */
1461
1462
0
    FUNC_ENTER_PACKAGE
1463
1464
    /* Check args */
1465
0
    assert(idx_info);
1466
0
    assert(idx_info->f);
1467
0
    assert(idx_info->pline);
1468
0
    assert(idx_info->layout);
1469
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1470
0
    assert(index_size);
1471
1472
    /* Open v2 B-tree */
1473
0
    if (H5D__bt2_idx_open(idx_info) < 0)
1474
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree");
1475
1476
    /* Set convenience pointer to v2 B-tree structure */
1477
0
    bt2_cdset = idx_info->layout->storage.u.chunk.u.btree2.bt2;
1478
1479
    /* Get v2 B-tree size for indexing chunked dataset */
1480
0
    if (H5B2_size(bt2_cdset, index_size) < 0)
1481
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
1482
0
                    "can't retrieve v2 B-tree storage info for chunked dataset");
1483
1484
0
done:
1485
    /* Close v2 B-tree index */
1486
0
    if (H5D__bt2_idx_close(idx_info) < 0)
1487
0
        HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for tracking chunked dataset");
1488
1489
0
    FUNC_LEAVE_NOAPI(ret_value)
1490
0
} /* end H5D__bt2_idx_size() */
1491
1492
/*-------------------------------------------------------------------------
1493
 * Function:    H5D__bt2_idx_reset
1494
 *
1495
 * Purpose:     Reset indexing information.
1496
 *
1497
 * Return:      Non-negative on success/Negative on failure
1498
 *
1499
 *-------------------------------------------------------------------------
1500
 */
1501
static herr_t
1502
H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr)
1503
0
{
1504
0
    FUNC_ENTER_PACKAGE_NOERR
1505
1506
    /* Sanity checks */
1507
0
    assert(storage);
1508
1509
    /* Reset index info */
1510
0
    if (reset_addr)
1511
0
        storage->idx_addr = HADDR_UNDEF;
1512
0
    storage->u.btree2.bt2 = NULL;
1513
1514
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1515
0
} /* end H5D__bt2_idx_reset() */
1516
1517
/*-------------------------------------------------------------------------
1518
 * Function:    H5D__bt2_idx_dump
1519
 *
1520
 * Purpose:     Dump indexing information to a stream.
1521
 *
1522
 * Return:      Non-negative on success/Negative on failure
1523
 *
1524
 *-------------------------------------------------------------------------
1525
 */
1526
static herr_t
1527
H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
1528
0
{
1529
0
    FUNC_ENTER_PACKAGE_NOERR
1530
1531
    /* Sanity checks */
1532
0
    assert(storage);
1533
0
    assert(stream);
1534
1535
0
    fprintf(stream, "    Address: %" PRIuHADDR "\n", storage->idx_addr);
1536
1537
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1538
0
} /* end H5D__bt2_idx_dump() */
1539
1540
/*-------------------------------------------------------------------------
1541
 * Function:    H5D__bt2_idx_dest
1542
 *
1543
 * Purpose:     Release indexing information in memory.
1544
 *
1545
 * Return:      Non-negative on success/Negative on failure
1546
 *
1547
 *-------------------------------------------------------------------------
1548
 */
1549
static herr_t
1550
H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info)
1551
0
{
1552
0
    herr_t ret_value = SUCCEED; /* Return value */
1553
1554
0
    FUNC_ENTER_PACKAGE
1555
1556
    /* Check args */
1557
0
    assert(idx_info);
1558
0
    assert(idx_info->f);
1559
0
    assert(idx_info->layout);
1560
1561
    /* Check if the v2-btree is open */
1562
0
    if (H5D_BT2_IDX_IS_OPEN(idx_info)) {
1563
        /* Patch the top level file pointer contained in bt2 if needed */
1564
0
        if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0)
1565
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer");
1566
1567
        /* Close v2 B-tree */
1568
0
        if (H5D__bt2_idx_close(idx_info) < 0)
1569
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree");
1570
0
    } /* end if */
1571
1572
0
done:
1573
0
    FUNC_LEAVE_NOAPI(ret_value)
1574
0
} /* end H5D__bt2_idx_dest() */