Coverage Report

Created: 2026-02-23 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Dearray.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
 * Purpose:     Extensible array indexed (chunked) I/O functions.  The chunks
15
 *              are given a single-dimensional index which is used as the
16
 *              offset in an extensible array that maps a chunk coordinate to
17
 *              a disk address.
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 "H5Eprivate.h"  /* Error handling                       */
32
#include "H5EAprivate.h" /* Extensible arrays                    */
33
#include "H5FLprivate.h" /* Free Lists                           */
34
#include "H5MFprivate.h" /* File space management                */
35
#include "H5MMprivate.h" /* Memory management                    */
36
#include "H5VMprivate.h" /* Vector functions                     */
37
38
/****************/
39
/* Local Macros */
40
/****************/
41
42
0
#define H5D_EARRAY_IDX_IS_OPEN(idx_info) (NULL != (idx_info)->layout->storage.u.chunk.u.earray.ea)
43
44
/* Value to fill unset array elements with */
45
0
#define H5D_EARRAY_FILL HADDR_UNDEF
46
#define H5D_EARRAY_FILT_FILL                                                                                 \
47
0
    {                                                                                                        \
48
0
        HADDR_UNDEF, 0, 0                                                                                    \
49
0
    }
50
51
/*
52
 * Macros to compute the size required for encoding the size of a chunk. For version 4, this is the minimum
53
 * number of bytes required to encode the size of an unfiltered chunk plus an extra byte, in case the filter
54
 * makes the chunk larger. For versions after 4, this is simply the size of lengths for the file. For
55
 * unfiltered chunks, this is 0.
56
 */
57
#define H5D_EARRAY_FILT_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, f, layout)                                    \
58
0
    do {                                                                                                     \
59
0
        if ((layout)->version > H5O_LAYOUT_VERSION_4)                                                        \
60
0
            (chunk_size_len) = H5F_SIZEOF_SIZE(f);                                                           \
61
0
        else {                                                                                               \
62
0
            (chunk_size_len) = 1 + ((H5VM_log2_gen((uint64_t)(layout)->u.chunk.size) + 8) / 8);              \
63
0
            if ((chunk_size_len) > 8)                                                                        \
64
0
                (chunk_size_len) = 8;                                                                        \
65
0
        }                                                                                                    \
66
0
    } while (0)
67
#define H5D_EARRAY_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, idx_info)                                          \
68
0
    do {                                                                                                     \
69
0
        if ((idx_info)->pline->nused > 0)                                                                    \
70
0
            H5D_EARRAY_FILT_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, (idx_info)->f, (idx_info)->layout);       \
71
0
        else                                                                                                 \
72
0
            (chunk_size_len) = 0;                                                                            \
73
0
    } while (0)
74
75
/******************/
76
/* Local Typedefs */
77
/******************/
78
79
/* Extensible array create/open user data */
80
typedef struct H5D_earray_ctx_ud_t {
81
    const H5F_t *f;              /* Pointer to file info */
82
    size_t       chunk_size_len; /* Size of chunk sizes in the file (bytes) */
83
} H5D_earray_ctx_ud_t;
84
85
/* Extensible array callback context */
86
typedef struct H5D_earray_ctx_t {
87
    size_t file_addr_len;  /* Size of addresses in the file (bytes) */
88
    size_t chunk_size_len; /* Size of chunk sizes in the file (bytes) */
89
} H5D_earray_ctx_t;
90
91
/* Extensible Array callback info for iteration over chunks */
92
typedef struct H5D_earray_it_ud_t {
93
    H5D_chunk_common_ud_t common;    /* Common info for Fixed Array user data (must be first) */
94
    H5D_chunk_rec_t       chunk_rec; /* Generic chunk record for callback */
95
    bool                  filtered;  /* Whether the chunks are filtered */
96
    H5D_chunk_cb_func_t   cb;        /* Chunk callback routine */
97
    void                 *udata;     /* User data for chunk callback routine */
98
} H5D_earray_it_ud_t;
99
100
/* Native extensible array element for chunks w/filters */
101
typedef struct H5D_earray_filt_elmt_t {
102
    haddr_t  addr;        /* Address of chunk */
103
    hsize_t  nbytes;      /* Size of chunk (in file) */
104
    uint32_t filter_mask; /* Excluded filters for chunk */
105
} H5D_earray_filt_elmt_t;
106
107
/********************/
108
/* Local Prototypes */
109
/********************/
110
/* Extensible array iterator callbacks */
111
static int H5D__earray_idx_iterate_cb(hsize_t idx, const void *_elmt, void *_udata);
112
static int H5D__earray_idx_delete_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
113
114
/* Extensible array class callbacks for chunks w/o filters */
115
static void  *H5D__earray_crt_context(void *udata);
116
static herr_t H5D__earray_dst_context(void *ctx);
117
static herr_t H5D__earray_fill(void *nat_blk, size_t nelmts);
118
static herr_t H5D__earray_encode(void *raw, const void *elmt, size_t nelmts, void *ctx);
119
static herr_t H5D__earray_decode(const void *raw, void *elmt, size_t nelmts, void *ctx);
120
static herr_t H5D__earray_debug(FILE *stream, int indent, int fwidth, hsize_t idx, const void *elmt);
121
static void  *H5D__earray_crt_dbg_context(H5F_t *f, haddr_t obj_addr);
122
static herr_t H5D__earray_dst_dbg_context(void *dbg_ctx);
123
124
/* Extensible array class callbacks for chunks w/filters */
125
/* (some shared with callbacks for chunks w/o filters) */
126
static herr_t H5D__earray_filt_fill(void *nat_blk, size_t nelmts);
127
static herr_t H5D__earray_filt_encode(void *raw, const void *elmt, size_t nelmts, void *ctx);
128
static herr_t H5D__earray_filt_decode(const void *raw, void *elmt, size_t nelmts, void *ctx);
129
static herr_t H5D__earray_filt_debug(FILE *stream, int indent, int fwidth, hsize_t idx, const void *elmt);
130
static void  *H5D__earray_filt_crt_dbg_context(H5F_t *f, haddr_t obj_addr);
131
132
/* Chunked layout indexing callbacks */
133
static herr_t H5D__earray_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space,
134
                                   haddr_t dset_ohdr_addr);
135
static herr_t H5D__earray_idx_create(const H5D_chk_idx_info_t *idx_info);
136
static herr_t H5D__earray_idx_open(const H5D_chk_idx_info_t *idx_info);
137
static herr_t H5D__earray_idx_close(const H5D_chk_idx_info_t *idx_info);
138
static herr_t H5D__earray_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open);
139
static bool   H5D__earray_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
140
static herr_t H5D__earray_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
141
                                     const H5D_t *dset);
142
static herr_t H5D__earray_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata);
143
static herr_t H5D__earray_idx_load_metadata(const H5D_chk_idx_info_t *idx_info);
144
static herr_t H5D__earray_idx_resize(H5O_layout_chunk_t *layout);
145
static int    H5D__earray_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb,
146
                                      void *chunk_udata);
147
static herr_t H5D__earray_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata);
148
static herr_t H5D__earray_idx_delete(const H5D_chk_idx_info_t *idx_info);
149
static herr_t H5D__earray_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
150
                                         const H5D_chk_idx_info_t *idx_info_dst);
151
static herr_t H5D__earray_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
152
                                            H5O_storage_chunk_t *storage_dst);
153
static herr_t H5D__earray_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *size);
154
static herr_t H5D__earray_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr);
155
static herr_t H5D__earray_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream);
156
static herr_t H5D__earray_idx_dest(const H5D_chk_idx_info_t *idx_info);
157
158
/* Generic extensible array routines */
159
static herr_t H5D__earray_idx_depend(const H5D_chk_idx_info_t *idx_info);
160
161
/*********************/
162
/* Package Variables */
163
/*********************/
164
165
/* Extensible array indexed chunk I/O ops */
166
const H5D_chunk_ops_t H5D_COPS_EARRAY[1] = {{
167
    true,                           /* Extensible array indices support SWMR access */
168
    H5D__earray_idx_init,           /* init */
169
    H5D__earray_idx_create,         /* create */
170
    H5D__earray_idx_open,           /* open */
171
    H5D__earray_idx_close,          /* close */
172
    H5D__earray_idx_is_open,        /* is_open */
173
    H5D__earray_idx_is_space_alloc, /* is_space_alloc */
174
    H5D__earray_idx_insert,         /* insert */
175
    H5D__earray_idx_get_addr,       /* get_addr */
176
    H5D__earray_idx_load_metadata,  /* load_metadata */
177
    H5D__earray_idx_resize,         /* resize */
178
    H5D__earray_idx_iterate,        /* iterate */
179
    H5D__earray_idx_remove,         /* remove */
180
    H5D__earray_idx_delete,         /* delete */
181
    H5D__earray_idx_copy_setup,     /* copy_setup */
182
    H5D__earray_idx_copy_shutdown,  /* copy_shutdown */
183
    H5D__earray_idx_size,           /* size */
184
    H5D__earray_idx_reset,          /* reset */
185
    H5D__earray_idx_dump,           /* dump */
186
    H5D__earray_idx_dest            /* destroy */
187
}};
188
189
/*****************************/
190
/* Library Private Variables */
191
/*****************************/
192
193
/* Extensible array class callbacks for dataset chunks w/o filters */
194
const H5EA_class_t H5EA_CLS_CHUNK[1] = {{
195
    H5EA_CLS_CHUNK_ID,           /* Type of extensible array */
196
    "Chunk w/o filters",         /* Name of extensible array class */
197
    sizeof(haddr_t),             /* Size of native element */
198
    H5D__earray_crt_context,     /* Create context */
199
    H5D__earray_dst_context,     /* Destroy context */
200
    H5D__earray_fill,            /* Fill block of missing elements callback */
201
    H5D__earray_encode,          /* Element encoding callback */
202
    H5D__earray_decode,          /* Element decoding callback */
203
    H5D__earray_debug,           /* Element debugging callback */
204
    H5D__earray_crt_dbg_context, /* Create debugging context */
205
    H5D__earray_dst_dbg_context  /* Destroy debugging context */
206
}};
207
208
/* Extensible array class callbacks for dataset chunks w/filters */
209
const H5EA_class_t H5EA_CLS_FILT_CHUNK[1] = {{
210
    H5EA_CLS_FILT_CHUNK_ID,           /* Type of extensible array */
211
    "Chunk w/filters",                /* Name of extensible array class */
212
    sizeof(H5D_earray_filt_elmt_t),   /* Size of native element */
213
    H5D__earray_crt_context,          /* Create context */
214
    H5D__earray_dst_context,          /* Destroy context */
215
    H5D__earray_filt_fill,            /* Fill block of missing elements callback */
216
    H5D__earray_filt_encode,          /* Element encoding callback */
217
    H5D__earray_filt_decode,          /* Element decoding callback */
218
    H5D__earray_filt_debug,           /* Element debugging callback */
219
    H5D__earray_filt_crt_dbg_context, /* Create debugging context */
220
    H5D__earray_dst_dbg_context       /* Destroy debugging context */
221
}};
222
223
/*******************/
224
/* Local Variables */
225
/*******************/
226
227
/* Declare a free list to manage the H5D_earray_ctx_t struct */
228
/* Declare a free list to manage the H5D_earray_ctx_ud_t struct */
229
H5FL_DEFINE_STATIC(H5D_earray_ctx_t);
230
H5FL_DEFINE_STATIC(H5D_earray_ctx_ud_t);
231
232
/*-------------------------------------------------------------------------
233
 * Function:    H5D__earray_crt_context
234
 *
235
 * Purpose:     Create context for callbacks
236
 *
237
 * Return:      Success:    non-NULL
238
 *              Failure:    NULL
239
 *
240
 *-------------------------------------------------------------------------
241
 */
242
static void *
243
H5D__earray_crt_context(void *_udata)
244
0
{
245
0
    H5D_earray_ctx_t    *ctx;                                   /* Extensible array callback context */
246
0
    H5D_earray_ctx_ud_t *udata = (H5D_earray_ctx_ud_t *)_udata; /* User data for extensible array context */
247
0
    void                *ret_value = NULL;                      /* Return value */
248
249
0
    FUNC_ENTER_PACKAGE
250
251
    /* Sanity checks */
252
0
    assert(udata);
253
0
    assert(udata->f);
254
255
    /* Allocate new context structure */
256
0
    if (NULL == (ctx = H5FL_MALLOC(H5D_earray_ctx_t)))
257
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL,
258
0
                    "can't allocate extensible array client callback context");
259
260
    /* Initialize the context */
261
0
    ctx->file_addr_len  = H5F_SIZEOF_ADDR(udata->f);
262
0
    ctx->chunk_size_len = udata->chunk_size_len;
263
264
    /* Set return value */
265
0
    ret_value = ctx;
266
267
0
done:
268
0
    FUNC_LEAVE_NOAPI(ret_value)
269
0
} /* end H5D__earray_crt_context() */
270
271
/*-------------------------------------------------------------------------
272
 * Function:    H5D__earray_dst_context
273
 *
274
 * Purpose:     Destroy context for callbacks
275
 *
276
 * Return:      Success:    non-NULL
277
 *              Failure:    NULL
278
 *
279
 *-------------------------------------------------------------------------
280
 */
281
static herr_t
282
H5D__earray_dst_context(void *_ctx)
283
0
{
284
0
    H5D_earray_ctx_t *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
285
286
0
    FUNC_ENTER_PACKAGE_NOERR
287
288
    /* Sanity checks */
289
0
    assert(ctx);
290
291
    /* Release context structure */
292
0
    ctx = H5FL_FREE(H5D_earray_ctx_t, ctx);
293
294
0
    FUNC_LEAVE_NOAPI(SUCCEED)
295
0
} /* end H5D__earray_dst_context() */
296
297
/*-------------------------------------------------------------------------
298
 * Function:    H5D__earray_fill
299
 *
300
 * Purpose:     Fill "missing elements" in block of elements
301
 *
302
 * Return:      Success:    non-negative
303
 *              Failure:    negative
304
 *
305
 *-------------------------------------------------------------------------
306
 */
307
static herr_t
308
H5D__earray_fill(void *nat_blk, size_t nelmts)
309
0
{
310
0
    haddr_t fill_val = H5D_EARRAY_FILL; /* Value to fill elements with */
311
312
0
    FUNC_ENTER_PACKAGE_NOERR
313
314
    /* Sanity checks */
315
0
    assert(nat_blk);
316
0
    assert(nelmts);
317
318
0
    H5VM_array_fill(nat_blk, &fill_val, H5EA_CLS_CHUNK->nat_elmt_size, nelmts);
319
320
0
    FUNC_LEAVE_NOAPI(SUCCEED)
321
0
} /* end H5D__earray_fill() */
322
323
/*-------------------------------------------------------------------------
324
 * Function:    H5D__earray_encode
325
 *
326
 * Purpose:     Encode an element from "native" to "raw" form
327
 *
328
 * Return:      Success:    non-negative
329
 *              Failure:    negative
330
 *
331
 *-------------------------------------------------------------------------
332
 */
333
static herr_t
334
H5D__earray_encode(void *raw, const void *_elmt, size_t nelmts, void *_ctx)
335
0
{
336
0
    H5D_earray_ctx_t *ctx  = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
337
0
    const haddr_t    *elmt = (const haddr_t *)_elmt;   /* Convenience pointer to native elements */
338
339
0
    FUNC_ENTER_PACKAGE_NOERR
340
341
    /* Sanity checks */
342
0
    assert(raw);
343
0
    assert(elmt);
344
0
    assert(nelmts);
345
0
    assert(ctx);
346
347
    /* Encode native elements into raw elements */
348
0
    while (nelmts) {
349
        /* Encode element */
350
        /* (advances 'raw' pointer) */
351
0
        H5F_addr_encode_len(ctx->file_addr_len, (uint8_t **)&raw, *elmt);
352
353
        /* Advance native element pointer */
354
0
        elmt++;
355
356
        /* Decrement # of elements to encode */
357
0
        nelmts--;
358
0
    } /* end while */
359
360
0
    FUNC_LEAVE_NOAPI(SUCCEED)
361
0
} /* end H5D__earray_encode() */
362
363
/*-------------------------------------------------------------------------
364
 * Function:    H5D__earray_decode
365
 *
366
 * Purpose:     Decode an element from "raw" to "native" form
367
 *
368
 * Return:      Success:    non-negative
369
 *              Failure:    negative
370
 *
371
 *-------------------------------------------------------------------------
372
 */
373
static herr_t
374
H5D__earray_decode(const void *_raw, void *_elmt, size_t nelmts, void *_ctx)
375
0
{
376
0
    H5D_earray_ctx_t *ctx  = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
377
0
    haddr_t          *elmt = (haddr_t *)_elmt;         /* Convenience pointer to native elements */
378
0
    const uint8_t    *raw  = (const uint8_t *)_raw;    /* Convenience pointer to raw elements */
379
380
0
    FUNC_ENTER_PACKAGE_NOERR
381
382
    /* Sanity checks */
383
0
    assert(raw);
384
0
    assert(elmt);
385
0
    assert(nelmts);
386
387
    /* Decode raw elements into native elements */
388
0
    while (nelmts) {
389
        /* Decode element */
390
        /* (advances 'raw' pointer) */
391
0
        H5F_addr_decode_len(ctx->file_addr_len, &raw, elmt);
392
393
        /* Advance native element pointer */
394
0
        elmt++;
395
396
        /* Decrement # of elements to decode */
397
0
        nelmts--;
398
0
    } /* end while */
399
400
0
    FUNC_LEAVE_NOAPI(SUCCEED)
401
0
} /* end H5D__earray_decode() */
402
403
/*-------------------------------------------------------------------------
404
 * Function:    H5D__earray_debug
405
 *
406
 * Purpose:     Display an element for debugging
407
 *
408
 * Return:      Success:    non-negative
409
 *              Failure:    negative
410
 *
411
 *-------------------------------------------------------------------------
412
 */
413
static herr_t
414
H5D__earray_debug(FILE *stream, int indent, int fwidth, hsize_t idx, const void *elmt)
415
0
{
416
0
    char temp_str[128]; /* Temporary string, for formatting */
417
418
0
    FUNC_ENTER_PACKAGE_NOERR
419
420
    /* Sanity checks */
421
0
    assert(stream);
422
0
    assert(elmt);
423
424
    /* Print element */
425
0
    snprintf(temp_str, sizeof(temp_str), "Element #%" PRIuHSIZE ":", idx);
426
0
    fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, temp_str, *(const haddr_t *)elmt);
427
428
0
    FUNC_LEAVE_NOAPI(SUCCEED)
429
0
} /* end H5D__earray_debug() */
430
431
/*-------------------------------------------------------------------------
432
 * Function:    H5D__earray_filt_fill
433
 *
434
 * Purpose:     Fill "missing elements" in block of elements
435
 *
436
 * Return:      Success:    non-negative
437
 *              Failure:    negative
438
 *
439
 *-------------------------------------------------------------------------
440
 */
441
static herr_t
442
H5D__earray_filt_fill(void *nat_blk, size_t nelmts)
443
0
{
444
0
    H5D_earray_filt_elmt_t fill_val = H5D_EARRAY_FILT_FILL; /* Value to fill elements with */
445
446
0
    FUNC_ENTER_PACKAGE_NOERR
447
448
    /* Sanity checks */
449
0
    assert(nat_blk);
450
0
    assert(nelmts);
451
0
    assert(sizeof(fill_val) == H5EA_CLS_FILT_CHUNK->nat_elmt_size);
452
453
0
    H5VM_array_fill(nat_blk, &fill_val, H5EA_CLS_FILT_CHUNK->nat_elmt_size, nelmts);
454
455
0
    FUNC_LEAVE_NOAPI(SUCCEED)
456
0
} /* end H5D__earray_filt_fill() */
457
458
/*-------------------------------------------------------------------------
459
 * Function:    H5D__earray_filt_encode
460
 *
461
 * Purpose:     Encode an element from "native" to "raw" form
462
 *
463
 * Return:      Success:    non-negative
464
 *              Failure:    negative
465
 *
466
 *-------------------------------------------------------------------------
467
 */
468
static herr_t
469
H5D__earray_filt_encode(void *_raw, const void *_elmt, size_t nelmts, void *_ctx)
470
0
{
471
0
    H5D_earray_ctx_t             *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
472
0
    uint8_t                      *raw = (uint8_t *)_raw;          /* Convenience pointer to raw elements */
473
0
    const H5D_earray_filt_elmt_t *elmt =
474
0
        (const H5D_earray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
475
476
0
    FUNC_ENTER_PACKAGE_NOERR
477
478
    /* Sanity checks */
479
0
    assert(raw);
480
0
    assert(elmt);
481
0
    assert(nelmts);
482
0
    assert(ctx);
483
484
    /* Encode native elements into raw elements */
485
0
    while (nelmts) {
486
        /* Encode element */
487
        /* (advances 'raw' pointer) */
488
0
        H5F_addr_encode_len(ctx->file_addr_len, &raw, elmt->addr);
489
0
        UINT64ENCODE_VAR(raw, elmt->nbytes, ctx->chunk_size_len);
490
0
        UINT32ENCODE(raw, elmt->filter_mask);
491
492
        /* Advance native element pointer */
493
0
        elmt++;
494
495
        /* Decrement # of elements to encode */
496
0
        nelmts--;
497
0
    } /* end while */
498
499
0
    FUNC_LEAVE_NOAPI(SUCCEED)
500
0
} /* end H5D__earray_filt_encode() */
501
502
/*-------------------------------------------------------------------------
503
 * Function:    H5D__earray_filt_decode
504
 *
505
 * Purpose:     Decode an element from "raw" to "native" form
506
 *
507
 * Return:      Success:    non-negative
508
 *              Failure:    negative
509
 *
510
 *-------------------------------------------------------------------------
511
 */
512
static herr_t
513
H5D__earray_filt_decode(const void *_raw, void *_elmt, size_t nelmts, void *_ctx)
514
0
{
515
0
    H5D_earray_ctx_t       *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
516
0
    H5D_earray_filt_elmt_t *elmt =
517
0
        (H5D_earray_filt_elmt_t *)_elmt;        /* Convenience pointer to native elements */
518
0
    const uint8_t *raw = (const uint8_t *)_raw; /* Convenience pointer to raw elements */
519
520
0
    FUNC_ENTER_PACKAGE_NOERR
521
522
    /* Sanity checks */
523
0
    assert(raw);
524
0
    assert(elmt);
525
0
    assert(nelmts);
526
527
    /* Decode raw elements into native elements */
528
0
    while (nelmts) {
529
        /* Decode element */
530
        /* (advances 'raw' pointer) */
531
0
        H5F_addr_decode_len(ctx->file_addr_len, &raw, &elmt->addr);
532
0
        UINT64DECODE_VAR(raw, elmt->nbytes, ctx->chunk_size_len);
533
0
        UINT32DECODE(raw, elmt->filter_mask);
534
535
        /* Advance native element pointer */
536
0
        elmt++;
537
538
        /* Decrement # of elements to decode */
539
0
        nelmts--;
540
0
    } /* end while */
541
542
0
    FUNC_LEAVE_NOAPI(SUCCEED)
543
0
} /* end H5D__earray_filt_decode() */
544
545
/*-------------------------------------------------------------------------
546
 * Function:    H5D__earray_filt_debug
547
 *
548
 * Purpose:     Display an element for debugging
549
 *
550
 * Return:      Success:    non-negative
551
 *              Failure:    negative
552
 *
553
 *-------------------------------------------------------------------------
554
 */
555
static herr_t
556
H5D__earray_filt_debug(FILE *stream, int indent, int fwidth, hsize_t idx, const void *_elmt)
557
0
{
558
0
    const H5D_earray_filt_elmt_t *elmt =
559
0
        (const H5D_earray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
560
0
    char temp_str[128];                        /* Temporary string, for formatting */
561
562
0
    FUNC_ENTER_PACKAGE_NOERR
563
564
    /* Sanity checks */
565
0
    assert(stream);
566
0
    assert(elmt);
567
568
    /* Print element */
569
0
    snprintf(temp_str, sizeof(temp_str), "Element #%" PRIuHSIZE ":", idx);
570
0
    fprintf(stream, "%*s%-*s {%" PRIuHADDR ", %" PRIuHSIZE ", %0x}\n", indent, "", fwidth, temp_str,
571
0
            elmt->addr, elmt->nbytes, elmt->filter_mask);
572
573
0
    FUNC_LEAVE_NOAPI(SUCCEED)
574
0
} /* end H5D__earray_filt_debug() */
575
576
/*-------------------------------------------------------------------------
577
 * Function:    H5D__earray_crt_dbg_context
578
 *
579
 * Purpose:     Create context for debugging callback
580
 *              (get the layout message in the specified object header)
581
 *
582
 * Return:      Success:    non-NULL
583
 *              Failure:    NULL
584
 *
585
 *-------------------------------------------------------------------------
586
 */
587
static void *
588
H5D__earray_crt_dbg_context(H5F_t *f, haddr_t H5_ATTR_UNUSED obj_addr)
589
0
{
590
0
    H5D_earray_ctx_ud_t *dbg_ctx   = NULL; /* Context for fixed array callback */
591
0
    void                *ret_value = NULL; /* Return value */
592
593
0
    FUNC_ENTER_PACKAGE
594
595
    /* Sanity checks */
596
0
    assert(f);
597
0
    assert(H5_addr_defined(obj_addr));
598
599
    /* Allocate context for debugging callback */
600
0
    if (NULL == (dbg_ctx = H5FL_MALLOC(H5D_earray_ctx_ud_t)))
601
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL,
602
0
                    "can't allocate extensible array client callback context");
603
604
    /* Create user data */
605
0
    dbg_ctx->f              = f;
606
0
    dbg_ctx->chunk_size_len = 0;
607
608
    /* Set return value */
609
0
    ret_value = dbg_ctx;
610
611
0
done:
612
    /* Cleanup on error */
613
0
    if (ret_value == NULL)
614
        /* Release context structure */
615
0
        if (dbg_ctx)
616
0
            dbg_ctx = H5FL_FREE(H5D_earray_ctx_ud_t, dbg_ctx);
617
618
0
    FUNC_LEAVE_NOAPI(ret_value)
619
0
} /* end H5D__earray_crt_dbg_context() */
620
621
/*-------------------------------------------------------------------------
622
 * Function:    H5D__earray_filt_crt_dbg_context
623
 *
624
 * Purpose:     Create context for debugging callback
625
 *              (get the layout message in the specified object header)
626
 *
627
 * Return:      Success:    non-NULL
628
 *              Failure:    NULL
629
 *
630
 *-------------------------------------------------------------------------
631
 */
632
static void *
633
H5D__earray_filt_crt_dbg_context(H5F_t *f, haddr_t obj_addr)
634
0
{
635
0
    H5D_earray_ctx_ud_t *dbg_ctx = NULL;     /* Context for fixed array callback */
636
0
    H5O_loc_t            obj_loc;            /* Pointer to an object's location */
637
0
    bool                 obj_opened = false; /* Flag to indicate that the object header was opened */
638
0
    H5O_layout_t         layout;             /* Layout message */
639
0
    void                *ret_value = NULL;   /* Return value */
640
641
0
    FUNC_ENTER_PACKAGE
642
643
    /* Sanity checks */
644
0
    assert(f);
645
0
    assert(H5_addr_defined(obj_addr));
646
647
    /* Allocate context for debugging callback */
648
0
    if (NULL == (dbg_ctx = H5FL_MALLOC(H5D_earray_ctx_ud_t)))
649
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL,
650
0
                    "can't allocate extensible array client callback context");
651
652
    /* Set up the object header location info */
653
0
    H5O_loc_reset(&obj_loc);
654
0
    obj_loc.file = f;
655
0
    obj_loc.addr = obj_addr;
656
657
    /* Open the object header where the layout message resides */
658
0
    if (H5O_open(&obj_loc) < 0)
659
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, NULL, "can't open object header");
660
0
    obj_opened = true;
661
662
    /* Read the layout message */
663
0
    if (NULL == H5O_msg_read(&obj_loc, H5O_LAYOUT_ID, &layout))
664
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't get layout info");
665
666
    /* close the object header */
667
0
    if (H5O_close(&obj_loc, NULL) < 0)
668
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, NULL, "can't close object header");
669
0
    obj_opened = false;
670
671
    /* Create user data */
672
0
    dbg_ctx->f = f;
673
674
    /* Calculate length of chunk size field */
675
0
    H5D_EARRAY_FILT_COMPUTE_CHUNK_SIZE_LEN(dbg_ctx->chunk_size_len, f, &layout);
676
677
    /* Set return value */
678
0
    ret_value = dbg_ctx;
679
680
0
done:
681
    /* Cleanup on error */
682
0
    if (ret_value == NULL) {
683
        /* Release context structure */
684
0
        if (dbg_ctx)
685
0
            dbg_ctx = H5FL_FREE(H5D_earray_ctx_ud_t, dbg_ctx);
686
687
        /* Close object header */
688
0
        if (obj_opened)
689
0
            if (H5O_close(&obj_loc, NULL) < 0)
690
0
                HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, NULL, "can't close object header");
691
0
    }
692
0
    else
693
0
        assert(!obj_opened);
694
695
0
    FUNC_LEAVE_NOAPI(ret_value)
696
0
} /* end H5D__earray_filt_crt_dbg_context() */
697
698
/*-------------------------------------------------------------------------
699
 * Function:    H5D__earray_dst_dbg_context
700
 *
701
 * Purpose:     Destroy context for debugging callback
702
 *              (free the layout message from the specified object header)
703
 *
704
 * Return:      Success:    non-negative
705
 *              Failure:    negative
706
 *
707
 *-------------------------------------------------------------------------
708
 */
709
static herr_t
710
H5D__earray_dst_dbg_context(void *_dbg_ctx)
711
0
{
712
0
    H5D_earray_ctx_ud_t *dbg_ctx =
713
0
        (H5D_earray_ctx_ud_t *)_dbg_ctx; /* Context for extensible array callback */
714
715
0
    FUNC_ENTER_PACKAGE_NOERR
716
717
    /* Sanity checks */
718
0
    assert(dbg_ctx);
719
720
    /* Release context structure */
721
0
    dbg_ctx = H5FL_FREE(H5D_earray_ctx_ud_t, dbg_ctx);
722
723
0
    FUNC_LEAVE_NOAPI(SUCCEED)
724
0
} /* end H5D__earray_dst_dbg_context() */
725
726
/*-------------------------------------------------------------------------
727
 * Function:    H5D__earray_idx_depend
728
 *
729
 * Purpose:     Create flush dependency between extensible array and dataset's
730
 *              object header.
731
 *
732
 * Return:      Success:    non-negative
733
 *              Failure:    negative
734
 *
735
 *-------------------------------------------------------------------------
736
 */
737
static herr_t
738
H5D__earray_idx_depend(const H5D_chk_idx_info_t *idx_info)
739
0
{
740
0
    H5O_t              *oh = NULL;           /* Object header */
741
0
    H5O_loc_t           oloc;                /* Temporary object header location for dataset */
742
0
    H5AC_proxy_entry_t *oh_proxy;            /* Dataset's object header proxy */
743
0
    herr_t              ret_value = SUCCEED; /* Return value */
744
745
0
    FUNC_ENTER_PACKAGE
746
747
    /* Check args */
748
0
    assert(idx_info);
749
0
    assert(idx_info->f);
750
0
    assert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE);
751
0
    assert(idx_info->pline);
752
0
    assert(idx_info->layout);
753
0
    assert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->u.chunk.idx_type);
754
0
    assert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->storage.u.chunk.idx_type);
755
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
756
0
    assert(idx_info->layout->storage.u.chunk.u.earray.ea);
757
758
    /* Set up object header location for dataset */
759
0
    H5O_loc_reset(&oloc);
760
0
    oloc.file = idx_info->f;
761
0
    oloc.addr = idx_info->layout->storage.u.chunk.u.earray.dset_ohdr_addr;
762
763
    /* Get header */
764
0
    if (NULL == (oh = H5O_protect(&oloc, H5AC__READ_ONLY_FLAG, true)))
765
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect object header");
766
767
    /* Retrieve the dataset's object header proxy */
768
0
    if (NULL == (oh_proxy = H5O_get_proxy(oh)))
769
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset object header proxy");
770
771
    /* Make the extensible array a child flush dependency of the dataset's object header */
772
0
    if (H5EA_depend(idx_info->layout->storage.u.chunk.u.earray.ea, oh_proxy) < 0)
773
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL,
774
0
                    "unable to create flush dependency on object header proxy");
775
776
0
done:
777
    /* Release the object header from the cache */
778
0
    if (oh && H5O_unprotect(&oloc, oh, H5AC__NO_FLAGS_SET) < 0)
779
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
780
781
0
    FUNC_LEAVE_NOAPI(ret_value)
782
0
} /* end H5D__earray_idx_depend() */
783
784
/*-------------------------------------------------------------------------
785
 * Function:    H5D__earray_idx_init
786
 *
787
 * Purpose:     Initialize the indexing information for a dataset.
788
 *
789
 * Return:      Non-negative on success/Negative on failure
790
 *
791
 *-------------------------------------------------------------------------
792
 */
793
static herr_t
794
H5D__earray_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space, haddr_t dset_ohdr_addr)
795
0
{
796
0
    hsize_t  max_dims[H5O_LAYOUT_NDIMS]; /* Max. size of dataset dimensions */
797
0
    int      unlim_dim;                  /* Rank of the dataset's unlimited dimension */
798
0
    int      sndims;                     /* Rank of dataspace */
799
0
    unsigned ndims;                      /* Rank of dataspace */
800
0
    unsigned u;                          /* Local index variable */
801
0
    herr_t   ret_value = SUCCEED;        /* Return value */
802
803
0
    FUNC_ENTER_PACKAGE
804
805
    /* Check args */
806
0
    assert(idx_info);
807
0
    assert(idx_info->f);
808
0
    assert(idx_info->pline);
809
0
    assert(idx_info->layout);
810
0
    assert(space);
811
0
    assert(H5_addr_defined(dset_ohdr_addr));
812
813
    /* Get the dim info for dataset */
814
0
    if ((sndims = H5S_get_simple_extent_dims(space, NULL, max_dims)) < 0)
815
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataspace dimensions");
816
0
    H5_CHECKED_ASSIGN(ndims, unsigned, sndims, int);
817
818
    /* Find the rank of the unlimited dimension */
819
0
    unlim_dim = (-1);
820
0
    for (u = 0; u < ndims; u++) {
821
        /* Check for unlimited dimension */
822
0
        if (H5S_UNLIMITED == max_dims[u]) {
823
            /* Check if we've already found an unlimited dimension */
824
0
            if (unlim_dim >= 0)
825
0
                HGOTO_ERROR(H5E_DATASET, H5E_ALREADYINIT, FAIL, "already found unlimited dimension");
826
827
            /* Set the unlimited dimension */
828
0
            unlim_dim = (int)u;
829
0
        } /* end if */
830
0
    }     /* end for */
831
832
    /* Check if we didn't find an unlimited dimension */
833
0
    if (unlim_dim < 0)
834
0
        HGOTO_ERROR(H5E_DATASET, H5E_UNINITIALIZED, FAIL, "didn't find unlimited dimension");
835
836
    /* Set the unlimited dimension for the layout's future use */
837
0
    idx_info->layout->u.chunk.u.earray.unlim_dim = (unsigned)unlim_dim;
838
839
    /* Store the dataset's object header address for later */
840
0
    idx_info->layout->storage.u.chunk.u.earray.dset_ohdr_addr = dset_ohdr_addr;
841
842
0
done:
843
0
    FUNC_LEAVE_NOAPI(ret_value)
844
0
} /* end H5D__earray_idx_init() */
845
846
/*-------------------------------------------------------------------------
847
 * Function:    H5D__earray_idx_create
848
 *
849
 * Purpose:     Creates a new indexed-storage extensible array and initializes
850
 *              the layout struct with information about the storage.  The
851
 *              struct should be immediately written to the object header.
852
 *
853
 *              This function must be called before passing LAYOUT to any of
854
 *              the other indexed storage functions!
855
 *
856
 * Return:      Non-negative on success (with the LAYOUT argument initialized
857
 *              and ready to write to an object header). Negative on failure.
858
 *
859
 *-------------------------------------------------------------------------
860
 */
861
static herr_t
862
H5D__earray_idx_create(const H5D_chk_idx_info_t *idx_info)
863
0
{
864
0
    H5EA_create_t       cparam;                   /* Extensible array creation parameters */
865
0
    H5D_earray_ctx_ud_t udata;                    /* User data for extensible array create call */
866
0
    unsigned            chunk_size_len = 0;       /* Size of encoded chunk size */
867
0
    herr_t              ret_value      = SUCCEED; /* Return value */
868
869
0
    FUNC_ENTER_PACKAGE
870
871
    /* Check args */
872
0
    assert(idx_info);
873
0
    assert(idx_info->f);
874
0
    assert(idx_info->pline);
875
0
    assert(idx_info->layout);
876
0
    assert(!H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
877
0
    assert(NULL == idx_info->layout->storage.u.chunk.u.earray.ea);
878
879
    /* General parameters */
880
0
    H5D_EARRAY_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, idx_info);
881
0
    if (idx_info->pline->nused > 0) {
882
0
        cparam.cls           = H5EA_CLS_FILT_CHUNK;
883
0
        cparam.raw_elmt_size = (uint8_t)(H5F_SIZEOF_ADDR(idx_info->f) + chunk_size_len + 4);
884
0
    } /* end if */
885
0
    else {
886
0
        cparam.cls           = H5EA_CLS_CHUNK;
887
0
        cparam.raw_elmt_size = (uint8_t)H5F_SIZEOF_ADDR(idx_info->f);
888
0
    } /* end else */
889
0
    cparam.max_nelmts_bits = idx_info->layout->u.chunk.u.earray.cparam.max_nelmts_bits;
890
0
    assert(cparam.max_nelmts_bits > 0);
891
0
    cparam.idx_blk_elmts = idx_info->layout->u.chunk.u.earray.cparam.idx_blk_elmts;
892
0
    assert(cparam.idx_blk_elmts > 0);
893
0
    cparam.sup_blk_min_data_ptrs = idx_info->layout->u.chunk.u.earray.cparam.sup_blk_min_data_ptrs;
894
0
    assert(cparam.sup_blk_min_data_ptrs > 0);
895
0
    cparam.data_blk_min_elmts = idx_info->layout->u.chunk.u.earray.cparam.data_blk_min_elmts;
896
0
    assert(cparam.data_blk_min_elmts > 0);
897
0
    cparam.max_dblk_page_nelmts_bits = idx_info->layout->u.chunk.u.earray.cparam.max_dblk_page_nelmts_bits;
898
0
    assert(cparam.max_dblk_page_nelmts_bits > 0);
899
900
    /* Set up the user data */
901
0
    udata.f              = idx_info->f;
902
0
    udata.chunk_size_len = (size_t)chunk_size_len;
903
904
    /* Create the extensible array for the chunk index */
905
0
    if (NULL == (idx_info->layout->storage.u.chunk.u.earray.ea = H5EA_create(idx_info->f, &cparam, &udata)))
906
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create extensible array");
907
908
    /* Get the address of the extensible array in file */
909
0
    if (H5EA_get_addr(idx_info->layout->storage.u.chunk.u.earray.ea,
910
0
                      &(idx_info->layout->storage.u.chunk.idx_addr)) < 0)
911
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query extensible array address");
912
913
    /* Check for SWMR writes to the file */
914
0
    if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
915
0
        if (H5D__earray_idx_depend(idx_info) < 0)
916
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL,
917
0
                        "unable to create flush dependency on object header");
918
919
0
done:
920
0
    FUNC_LEAVE_NOAPI(ret_value)
921
0
} /* end H5D__earray_idx_create() */
922
923
/*-------------------------------------------------------------------------
924
 * Function:    H5D__earray_idx_open
925
 *
926
 * Purpose:     Opens an existing extensible array.
927
 *
928
 * Note:        This information is passively initialized from each index
929
 *              operation callback because those abstract chunk index
930
 *              operations are designed to work with the v1 B-tree chunk
931
 *              indices also, which don't require an 'open' for the data
932
 *              structure.
933
 *
934
 * Return:      Success:    non-negative
935
 *              Failure:    negative
936
 *
937
 *-------------------------------------------------------------------------
938
 */
939
static herr_t
940
H5D__earray_idx_open(const H5D_chk_idx_info_t *idx_info)
941
0
{
942
0
    H5D_earray_ctx_ud_t udata;               /* User data for extensible array open call */
943
0
    herr_t              ret_value = SUCCEED; /* Return value */
944
945
0
    FUNC_ENTER_PACKAGE
946
947
    /* Check args */
948
0
    assert(idx_info);
949
0
    assert(idx_info->f);
950
0
    assert(idx_info->pline);
951
0
    assert(idx_info->layout);
952
0
    assert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->u.chunk.idx_type);
953
0
    assert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->storage.u.chunk.idx_type);
954
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
955
0
    assert(NULL == idx_info->layout->storage.u.chunk.u.earray.ea);
956
957
    /* Set up the user data */
958
0
    udata.f = idx_info->f;
959
960
    /* Compute number of bytes used to encode the chunk size */
961
0
    H5D_EARRAY_COMPUTE_CHUNK_SIZE_LEN(udata.chunk_size_len, idx_info);
962
963
    /* Open the extensible array for the chunk index */
964
0
    if (NULL == (idx_info->layout->storage.u.chunk.u.earray.ea =
965
0
                     H5EA_open(idx_info->f, idx_info->layout->storage.u.chunk.idx_addr, &udata)))
966
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't open extensible array");
967
968
    /* Check for SWMR writes to the file */
969
0
    if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
970
0
        if (H5D__earray_idx_depend(idx_info) < 0)
971
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL,
972
0
                        "unable to create flush dependency on object header");
973
974
0
done:
975
0
    FUNC_LEAVE_NOAPI(ret_value)
976
0
} /* end H5D__earray_idx_open() */
977
978
/*-------------------------------------------------------------------------
979
 * Function:    H5D__earray_idx_close
980
 *
981
 * Purpose:     Closes an existing extensible array.
982
 *
983
 * Return:      Success:    non-negative
984
 *              Failure:    negative
985
 *
986
 *-------------------------------------------------------------------------
987
 */
988
static herr_t
989
H5D__earray_idx_close(const H5D_chk_idx_info_t *idx_info)
990
0
{
991
0
    herr_t ret_value = SUCCEED; /* Return value */
992
993
0
    FUNC_ENTER_PACKAGE
994
995
0
    assert(idx_info);
996
0
    assert(idx_info->layout);
997
0
    assert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->storage.u.chunk.idx_type);
998
0
    assert(idx_info->layout->storage.u.chunk.u.earray.ea);
999
1000
0
    if (H5EA_close(idx_info->layout->storage.u.chunk.u.earray.ea) < 0)
1001
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array");
1002
0
    idx_info->layout->storage.u.chunk.u.earray.ea = NULL;
1003
1004
0
done:
1005
0
    FUNC_LEAVE_NOAPI(ret_value)
1006
0
} /* end H5D__earray_idx_close() */
1007
1008
/*-------------------------------------------------------------------------
1009
 * Function:    H5D__earray_idx_is_open
1010
 *
1011
 * Purpose:     Query if the index is opened or not
1012
 *
1013
 * Return:      SUCCEED (can't fail)
1014
 *
1015
 *-------------------------------------------------------------------------
1016
 */
1017
static herr_t
1018
H5D__earray_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open)
1019
0
{
1020
0
    FUNC_ENTER_PACKAGE_NOERR
1021
1022
0
    assert(idx_info);
1023
0
    assert(idx_info->layout);
1024
0
    assert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->storage.u.chunk.idx_type);
1025
0
    assert(is_open);
1026
1027
0
    *is_open = H5D_EARRAY_IDX_IS_OPEN(idx_info);
1028
1029
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1030
0
} /* end H5D__earray_idx_is_open() */
1031
1032
/*-------------------------------------------------------------------------
1033
 * Function:    H5D__earray_idx_is_space_alloc
1034
 *
1035
 * Purpose:     Query if space is allocated for index method
1036
 *
1037
 * Return:      true/false
1038
 *
1039
 *-------------------------------------------------------------------------
1040
 */
1041
static bool
1042
H5D__earray_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
1043
0
{
1044
0
    FUNC_ENTER_PACKAGE_NOERR
1045
1046
    /* Check args */
1047
0
    assert(storage);
1048
1049
0
    FUNC_LEAVE_NOAPI((bool)H5_addr_defined(storage->idx_addr))
1050
0
} /* end H5D__earray_idx_is_space_alloc() */
1051
1052
/*-------------------------------------------------------------------------
1053
 * Function:    H5D__earray_idx_insert
1054
 *
1055
 * Purpose:     Insert chunk address into the indexing structure.
1056
 *
1057
 * Return:      Non-negative on success/Negative on failure
1058
 *
1059
 *-------------------------------------------------------------------------
1060
 */
1061
static herr_t
1062
H5D__earray_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
1063
                       const H5D_t H5_ATTR_UNUSED *dset)
1064
0
{
1065
0
    H5EA_t *ea;                  /* Pointer to extensible array structure */
1066
0
    herr_t  ret_value = SUCCEED; /* Return value */
1067
1068
0
    FUNC_ENTER_PACKAGE
1069
1070
    /* Sanity checks */
1071
0
    assert(idx_info);
1072
0
    assert(idx_info->f);
1073
0
    assert(idx_info->pline);
1074
0
    assert(idx_info->layout);
1075
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1076
0
    assert(udata);
1077
1078
    /* Check if the extensible array is open yet */
1079
0
    if (!H5D_EARRAY_IDX_IS_OPEN(idx_info)) {
1080
        /* Open the extensible array in file */
1081
0
        if (H5D__earray_idx_open(idx_info) < 0)
1082
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array");
1083
0
    }
1084
0
    else /* Patch the top level file pointer contained in ea if needed */
1085
0
        H5EA_patch_file(idx_info->layout->storage.u.chunk.u.earray.ea, idx_info->f);
1086
1087
    /* Set convenience pointer to extensible array structure */
1088
0
    ea = idx_info->layout->storage.u.chunk.u.earray.ea;
1089
1090
0
    if (!H5_addr_defined(udata->chunk_block.offset))
1091
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "The chunk should have allocated already");
1092
0
    if (udata->chunk_idx != (udata->chunk_idx & 0xffffffff)) /* negative value */
1093
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "chunk index must be less than 2^32");
1094
1095
    /* Check for filters on chunks */
1096
0
    if (idx_info->pline->nused > 0) {
1097
0
        H5D_earray_filt_elmt_t elmt; /* Extensible array element */
1098
1099
0
        elmt.addr        = udata->chunk_block.offset;
1100
0
        elmt.nbytes      = udata->chunk_block.length;
1101
0
        elmt.filter_mask = udata->filter_mask;
1102
1103
        /* Set the info for the chunk */
1104
0
        if (H5EA_set(ea, udata->chunk_idx, &elmt) < 0)
1105
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set chunk info");
1106
0
    } /* end if */
1107
0
    else {
1108
        /* Set the address for the chunk */
1109
0
        if (H5EA_set(ea, udata->chunk_idx, &udata->chunk_block.offset) < 0)
1110
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set chunk address");
1111
0
    } /* end else */
1112
1113
0
done:
1114
0
    FUNC_LEAVE_NOAPI(ret_value)
1115
0
} /* H5D__earray_idx_insert() */
1116
1117
/*-------------------------------------------------------------------------
1118
 * Function:    H5D__earray_idx_get_addr
1119
 *
1120
 * Purpose:     Get the file address of a chunk if file space has been
1121
 *              assigned.  Save the retrieved information in the udata
1122
 *              supplied.
1123
 *
1124
 * Return:      Non-negative on success/Negative on failure
1125
 *
1126
 *-------------------------------------------------------------------------
1127
 */
1128
static herr_t
1129
H5D__earray_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
1130
0
{
1131
0
    H5EA_t *ea;                  /* Pointer to extensible array structure */
1132
0
    hsize_t idx;                 /* Array index of chunk */
1133
0
    herr_t  ret_value = SUCCEED; /* Return value */
1134
1135
0
    FUNC_ENTER_PACKAGE
1136
1137
    /* Sanity checks */
1138
0
    assert(idx_info);
1139
0
    assert(idx_info->f);
1140
0
    assert(idx_info->pline);
1141
0
    assert(idx_info->layout);
1142
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1143
0
    assert(udata);
1144
1145
    /* Check if the extensible array is open yet */
1146
0
    if (!H5D_EARRAY_IDX_IS_OPEN(idx_info)) {
1147
        /* Open the extensible array in file */
1148
0
        if (H5D__earray_idx_open(idx_info) < 0)
1149
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array");
1150
0
    }
1151
0
    else /* Patch the top level file pointer contained in ea if needed */
1152
0
        H5EA_patch_file(idx_info->layout->storage.u.chunk.u.earray.ea, idx_info->f);
1153
1154
    /* Set convenience pointer to extensible array structure */
1155
0
    ea = idx_info->layout->storage.u.chunk.u.earray.ea;
1156
1157
    /* Check for unlimited dim. not being the slowest-changing dim. */
1158
0
    if (idx_info->layout->u.chunk.u.earray.unlim_dim > 0) {
1159
0
        hsize_t  swizzled_coords[H5O_LAYOUT_NDIMS];             /* swizzled chunk coordinates */
1160
0
        unsigned ndims = (idx_info->layout->u.chunk.ndims - 1); /* Number of dimensions */
1161
0
        unsigned u;
1162
1163
        /* Compute coordinate offset from scaled offset */
1164
0
        for (u = 0; u < ndims; u++)
1165
0
            swizzled_coords[u] = udata->common.scaled[u] * idx_info->layout->u.chunk.dim[u];
1166
1167
0
        H5VM_swizzle_coords(hsize_t, swizzled_coords, idx_info->layout->u.chunk.u.earray.unlim_dim);
1168
1169
        /* Calculate the index of this chunk */
1170
0
        idx = H5VM_chunk_index(ndims, swizzled_coords, idx_info->layout->u.chunk.u.earray.swizzled_dim,
1171
0
                               idx_info->layout->u.chunk.u.earray.swizzled_max_down_chunks);
1172
0
    } /* end if */
1173
0
    else {
1174
        /* Calculate the index of this chunk */
1175
0
        idx = H5VM_array_offset_pre((idx_info->layout->u.chunk.ndims - 1),
1176
0
                                    idx_info->layout->u.chunk.max_down_chunks, udata->common.scaled);
1177
0
    } /* end else */
1178
1179
0
    udata->chunk_idx = idx;
1180
1181
    /* Check for filters on chunks */
1182
0
    if (idx_info->pline->nused > 0) {
1183
0
        H5D_earray_filt_elmt_t elmt; /* Extensible array element */
1184
1185
        /* Get the information for the chunk */
1186
0
        if (H5EA_get(ea, idx, &elmt) < 0)
1187
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info");
1188
1189
        /* Set the info for the chunk */
1190
0
        udata->chunk_block.offset = elmt.addr;
1191
0
        udata->chunk_block.length = elmt.nbytes;
1192
0
        udata->filter_mask        = elmt.filter_mask;
1193
0
    } /* end if */
1194
0
    else {
1195
        /* Get the address for the chunk */
1196
0
        if (H5EA_get(ea, idx, &udata->chunk_block.offset) < 0)
1197
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address");
1198
1199
        /* Update the other (constant) information for the chunk */
1200
0
        udata->chunk_block.length = idx_info->layout->u.chunk.size;
1201
0
        udata->filter_mask        = 0;
1202
0
    } /* end else */
1203
1204
0
    if (!H5_addr_defined(udata->chunk_block.offset))
1205
0
        udata->chunk_block.length = 0;
1206
1207
0
done:
1208
0
    FUNC_LEAVE_NOAPI(ret_value)
1209
0
} /* H5D__earray_idx_get_addr() */
1210
1211
/*-------------------------------------------------------------------------
1212
 * Function:    H5D__earray_idx_load_metadata
1213
 *
1214
 * Purpose:     Load additional chunk index metadata beyond the chunk index
1215
 *              itself.
1216
 *
1217
 * Return:      Non-negative on success/Negative on failure
1218
 *
1219
 *-------------------------------------------------------------------------
1220
 */
1221
static herr_t
1222
H5D__earray_idx_load_metadata(const H5D_chk_idx_info_t *idx_info)
1223
0
{
1224
0
    H5D_chunk_ud_t chunk_ud;
1225
0
    hsize_t        scaled[H5O_LAYOUT_NDIMS] = {0};
1226
0
    herr_t         ret_value                = SUCCEED;
1227
1228
0
    FUNC_ENTER_PACKAGE
1229
1230
    /*
1231
     * After opening a dataset that uses an extensible array,
1232
     * the extensible array header index block will generally
1233
     * not be read in until an element is looked up for the
1234
     * first time. Since there isn't currently a good way of
1235
     * controlling that explicitly, perform a fake lookup of
1236
     * a chunk to cause it to be read in or created if it
1237
     * doesn't exist yet.
1238
     */
1239
0
    chunk_ud.common.layout  = &idx_info->layout->u.chunk;
1240
0
    chunk_ud.common.storage = &idx_info->layout->storage.u.chunk;
1241
0
    chunk_ud.common.scaled  = scaled;
1242
1243
0
    chunk_ud.chunk_block.offset = HADDR_UNDEF;
1244
0
    chunk_ud.chunk_block.length = 0;
1245
0
    chunk_ud.filter_mask        = 0;
1246
0
    chunk_ud.new_unfilt_chunk   = false;
1247
0
    chunk_ud.idx_hint           = UINT_MAX;
1248
1249
0
    if (H5D__earray_idx_get_addr(idx_info, &chunk_ud) < 0)
1250
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't load extensible array header index block");
1251
1252
0
done:
1253
0
    FUNC_LEAVE_NOAPI(ret_value)
1254
0
} /* H5D__earray_idx_load_metadata() */
1255
1256
/*-------------------------------------------------------------------------
1257
 * Function:    H5D__earray_idx_resize
1258
 *
1259
 * Purpose:     Calculate/setup the swizzled down chunk array, used for chunk
1260
 *              index calculations.
1261
 *
1262
 * Return:      Non-negative on success/Negative on failure
1263
 *
1264
 *-------------------------------------------------------------------------
1265
 */
1266
static herr_t
1267
H5D__earray_idx_resize(H5O_layout_chunk_t *layout)
1268
0
{
1269
0
    FUNC_ENTER_PACKAGE_NOERR
1270
1271
    /* Check args */
1272
0
    assert(layout);
1273
1274
    /* "Swizzle" constant dimensions for this dataset */
1275
0
    if (layout->u.earray.unlim_dim > 0) {
1276
0
        hsize_t swizzled_chunks[H5O_LAYOUT_NDIMS]; /* Swizzled form of # of chunks in each dimension */
1277
0
        hsize_t
1278
0
            swizzled_max_chunks[H5O_LAYOUT_NDIMS]; /* Swizzled form of max # of chunks in each dimension */
1279
1280
        /* Get the swizzled chunk dimensions */
1281
0
        H5MM_memcpy(layout->u.earray.swizzled_dim, layout->dim, (layout->ndims - 1) * sizeof(layout->dim[0]));
1282
0
        H5VM_swizzle_coords(hsize_t, layout->u.earray.swizzled_dim, layout->u.earray.unlim_dim);
1283
1284
        /* Get the swizzled number of chunks in each dimension */
1285
0
        H5MM_memcpy(swizzled_chunks, layout->chunks, (layout->ndims - 1) * sizeof(swizzled_chunks[0]));
1286
0
        H5VM_swizzle_coords(hsize_t, swizzled_chunks, layout->u.earray.unlim_dim);
1287
1288
        /* Get the swizzled "down" sizes for each dimension */
1289
0
        H5VM_array_down((layout->ndims - 1), swizzled_chunks, layout->u.earray.swizzled_down_chunks);
1290
1291
        /* Get the swizzled max number of chunks in each dimension */
1292
0
        H5MM_memcpy(swizzled_max_chunks, layout->max_chunks,
1293
0
                    (layout->ndims - 1) * sizeof(swizzled_max_chunks[0]));
1294
0
        H5VM_swizzle_coords(hsize_t, swizzled_max_chunks, layout->u.earray.unlim_dim);
1295
1296
        /* Get the swizzled max "down" sizes for each dimension */
1297
0
        H5VM_array_down((layout->ndims - 1), swizzled_max_chunks, layout->u.earray.swizzled_max_down_chunks);
1298
0
    }
1299
1300
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1301
0
} /* end H5D__earray_idx_resize() */
1302
1303
/*-------------------------------------------------------------------------
1304
 * Function:    H5D__earray_idx_iterate_cb
1305
 *
1306
 * Purpose:     Callback routine for extensible array element iteration.
1307
 *
1308
 * Return:      Non-negative on success/Negative on failure
1309
 *
1310
 *-------------------------------------------------------------------------
1311
 */
1312
static int
1313
H5D__earray_idx_iterate_cb(hsize_t H5_ATTR_UNUSED idx, const void *_elmt, void *_udata)
1314
0
{
1315
0
    H5D_earray_it_ud_t *udata = (H5D_earray_it_ud_t *)_udata; /* User data */
1316
0
    unsigned            ndims;                                /* Rank of chunk */
1317
0
    int                 curr_dim;                             /* Current dimension */
1318
0
    int                 ret_value = H5_ITER_CONT;             /* Return value */
1319
1320
0
    FUNC_ENTER_PACKAGE_NOERR
1321
1322
    /* Compose generic chunk record for callback */
1323
0
    if (udata->filtered) {
1324
0
        const H5D_earray_filt_elmt_t *filt_elmt = (const H5D_earray_filt_elmt_t *)_elmt;
1325
1326
0
        udata->chunk_rec.chunk_addr  = filt_elmt->addr;
1327
0
        udata->chunk_rec.nbytes      = filt_elmt->nbytes;
1328
0
        udata->chunk_rec.filter_mask = filt_elmt->filter_mask;
1329
0
    } /* end if */
1330
0
    else
1331
0
        udata->chunk_rec.chunk_addr = *(const haddr_t *)_elmt;
1332
1333
    /* Make "generic chunk" callback */
1334
0
    if (H5_addr_defined(udata->chunk_rec.chunk_addr))
1335
0
        if ((ret_value = (udata->cb)(&udata->chunk_rec, udata->udata)) < 0)
1336
0
            HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
1337
1338
    /* Update coordinates of chunk in dataset */
1339
0
    ndims = udata->common.layout->ndims - 1;
1340
0
    assert(ndims > 0);
1341
0
    curr_dim = (int)(ndims - 1);
1342
0
    while (curr_dim >= 0) {
1343
        /* Increment coordinate in current dimension */
1344
0
        udata->chunk_rec.scaled[curr_dim]++;
1345
1346
        /* Check if we went off the end of the current dimension */
1347
0
        if (udata->chunk_rec.scaled[curr_dim] >= udata->common.layout->max_chunks[curr_dim]) {
1348
            /* Reset coordinate & move to next faster dimension */
1349
0
            udata->chunk_rec.scaled[curr_dim] = 0;
1350
0
            curr_dim--;
1351
0
        } /* end if */
1352
0
        else
1353
0
            break;
1354
0
    } /* end while */
1355
1356
0
    FUNC_LEAVE_NOAPI(ret_value)
1357
0
} /* H5D__earray_idx_iterate_cb() */
1358
1359
/*-------------------------------------------------------------------------
1360
 * Function:    H5D__earray_idx_iterate
1361
 *
1362
 * Purpose:     Iterate over the chunks in an index, making a callback
1363
 *              for each one.
1364
 *
1365
 * Return:      Non-negative on success/Negative on failure
1366
 *
1367
 *-------------------------------------------------------------------------
1368
 */
1369
static int
1370
H5D__earray_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
1371
0
{
1372
0
    H5EA_t     *ea;                       /* Pointer to extensible array structure */
1373
0
    H5EA_stat_t ea_stat;                  /* Extensible array statistics */
1374
0
    int         ret_value = H5_ITER_CONT; /* Return value */
1375
1376
0
    FUNC_ENTER_PACKAGE
1377
1378
    /* Sanity checks */
1379
0
    assert(idx_info);
1380
0
    assert(idx_info->f);
1381
0
    assert(idx_info->pline);
1382
0
    assert(idx_info->layout);
1383
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1384
0
    assert(chunk_cb);
1385
0
    assert(chunk_udata);
1386
1387
    /* Check if the extensible array is open yet */
1388
0
    if (!H5D_EARRAY_IDX_IS_OPEN(idx_info)) {
1389
        /* Open the extensible array in file */
1390
0
        if (H5D__earray_idx_open(idx_info) < 0)
1391
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, H5_ITER_ERROR, "can't open extensible array");
1392
0
    }
1393
0
    else /* Patch the top level file pointer contained in ea if needed */
1394
0
        H5EA_patch_file(idx_info->layout->storage.u.chunk.u.earray.ea, idx_info->f);
1395
1396
    /* Set convenience pointer to extensible array structure */
1397
0
    ea = idx_info->layout->storage.u.chunk.u.earray.ea;
1398
1399
    /* Get the extensible array statistics */
1400
0
    if (H5EA_get_stats(ea, &ea_stat) < 0)
1401
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, H5_ITER_ERROR, "can't query extensible array statistics");
1402
1403
0
    if (ea_stat.stored.max_idx_set > 0) {
1404
0
        H5D_earray_it_ud_t udata; /* User data for iteration callback */
1405
1406
        /* Initialize userdata */
1407
0
        memset(&udata, 0, sizeof udata);
1408
0
        udata.common.layout  = &idx_info->layout->u.chunk;
1409
0
        udata.common.storage = &idx_info->layout->storage.u.chunk;
1410
0
        memset(&udata.chunk_rec, 0, sizeof(udata.chunk_rec));
1411
0
        udata.filtered = (idx_info->pline->nused > 0);
1412
0
        if (!udata.filtered) {
1413
0
            udata.chunk_rec.nbytes      = idx_info->layout->u.chunk.size;
1414
0
            udata.chunk_rec.filter_mask = 0;
1415
0
        } /* end if */
1416
0
        udata.cb    = chunk_cb;
1417
0
        udata.udata = chunk_udata;
1418
1419
        /* Iterate over the extensible array elements */
1420
0
        if ((ret_value = H5EA_iterate(ea, H5D__earray_idx_iterate_cb, &udata)) < 0)
1421
0
            HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over fixed array chunk index");
1422
0
    } /* end if */
1423
1424
0
done:
1425
0
    FUNC_LEAVE_NOAPI(ret_value)
1426
0
} /* end H5D__earray_idx_iterate() */
1427
1428
/*-------------------------------------------------------------------------
1429
 * Function:    H5D__earray_idx_remove
1430
 *
1431
 * Purpose:     Remove chunk from index.
1432
 *
1433
 * Return:      Non-negative on success/Negative on failure
1434
 *
1435
 *-------------------------------------------------------------------------
1436
 */
1437
static herr_t
1438
H5D__earray_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata)
1439
0
{
1440
0
    H5EA_t *ea;                  /* Pointer to extensible array structure */
1441
0
    hsize_t idx;                 /* Array index of chunk */
1442
0
    herr_t  ret_value = SUCCEED; /* Return value */
1443
1444
0
    FUNC_ENTER_PACKAGE
1445
1446
    /* Sanity checks */
1447
0
    assert(idx_info);
1448
0
    assert(idx_info->f);
1449
0
    assert(idx_info->pline);
1450
0
    assert(idx_info->layout);
1451
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1452
0
    assert(udata);
1453
1454
    /* Check if the extensible array is open yet */
1455
0
    if (!H5D_EARRAY_IDX_IS_OPEN(idx_info)) {
1456
        /* Open the extensible array in file */
1457
0
        if (H5D__earray_idx_open(idx_info) < 0)
1458
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array");
1459
0
    }
1460
0
    else /* Patch the top level file pointer contained in ea if needed */
1461
0
        if (H5EA_patch_file(idx_info->layout->storage.u.chunk.u.earray.ea, idx_info->f) < 0)
1462
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch earray file pointer");
1463
1464
    /* Set convenience pointer to extensible array structure */
1465
0
    ea = idx_info->layout->storage.u.chunk.u.earray.ea;
1466
1467
    /* Check for unlimited dim. not being the slowest-changing dim. */
1468
0
    if (idx_info->layout->u.chunk.u.earray.unlim_dim > 0) {
1469
0
        hsize_t  swizzled_coords[H5O_LAYOUT_NDIMS];             /* swizzled chunk coordinates */
1470
0
        unsigned ndims = (idx_info->layout->u.chunk.ndims - 1); /* Number of dimensions */
1471
0
        unsigned u;
1472
1473
        /* Compute coordinate offset from scaled offset */
1474
0
        for (u = 0; u < ndims; u++)
1475
0
            swizzled_coords[u] = udata->scaled[u] * idx_info->layout->u.chunk.dim[u];
1476
1477
0
        H5VM_swizzle_coords(hsize_t, swizzled_coords, idx_info->layout->u.chunk.u.earray.unlim_dim);
1478
1479
        /* Calculate the index of this chunk */
1480
0
        idx = H5VM_chunk_index(ndims, swizzled_coords, idx_info->layout->u.chunk.u.earray.swizzled_dim,
1481
0
                               idx_info->layout->u.chunk.u.earray.swizzled_max_down_chunks);
1482
0
    } /* end if */
1483
0
    else {
1484
        /* Calculate the index of this chunk */
1485
0
        idx = H5VM_array_offset_pre((idx_info->layout->u.chunk.ndims - 1),
1486
0
                                    idx_info->layout->u.chunk.max_down_chunks, udata->scaled);
1487
0
    } /* end else */
1488
1489
    /* Check for filters on chunks */
1490
0
    if (idx_info->pline->nused > 0) {
1491
0
        H5D_earray_filt_elmt_t elmt; /* Extensible array element */
1492
1493
        /* Get the info about the chunk for the index */
1494
0
        if (H5EA_get(ea, idx, &elmt) < 0)
1495
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info");
1496
1497
        /* Remove raw data chunk from file if not doing SWMR writes */
1498
0
        assert(H5_addr_defined(elmt.addr));
1499
0
        if (!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE))
1500
0
            if (H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, elmt.addr, elmt.nbytes) < 0)
1501
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk");
1502
1503
        /* Reset the info about the chunk for the index */
1504
0
        elmt.addr        = HADDR_UNDEF;
1505
0
        elmt.nbytes      = 0;
1506
0
        elmt.filter_mask = 0;
1507
0
        if (H5EA_set(ea, idx, &elmt) < 0)
1508
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to reset chunk info");
1509
0
    } /* end if */
1510
0
    else {
1511
0
        haddr_t addr = HADDR_UNDEF; /* Chunk address */
1512
1513
        /* Get the address of the chunk for the index */
1514
0
        if (H5EA_get(ea, idx, &addr) < 0)
1515
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address");
1516
1517
        /* Remove raw data chunk from file if not doing SWMR writes */
1518
0
        assert(H5_addr_defined(addr));
1519
0
        if (!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE))
1520
0
            if (H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, addr, idx_info->layout->u.chunk.size) < 0)
1521
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk");
1522
1523
        /* Reset the address of the chunk for the index */
1524
0
        addr = HADDR_UNDEF;
1525
0
        if (H5EA_set(ea, idx, &addr) < 0)
1526
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to reset chunk address");
1527
0
    } /* end else */
1528
1529
0
done:
1530
0
    FUNC_LEAVE_NOAPI(ret_value)
1531
0
} /* H5D__earray_idx_remove() */
1532
1533
/*-------------------------------------------------------------------------
1534
 * Function:    H5D__earray_idx_delete_cb
1535
 *
1536
 * Purpose:     Delete space for chunk in file
1537
 *
1538
 * Return:      Success:    Non-negative
1539
 *              Failure:    negative
1540
 *
1541
 *-------------------------------------------------------------------------
1542
 */
1543
static int
1544
H5D__earray_idx_delete_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
1545
0
{
1546
0
    H5F_t *f         = (H5F_t *)_udata; /* User data for callback */
1547
0
    int    ret_value = H5_ITER_CONT;    /* Return value */
1548
1549
0
    FUNC_ENTER_PACKAGE
1550
1551
    /* Sanity checks */
1552
0
    assert(chunk_rec);
1553
0
    assert(H5_addr_defined(chunk_rec->chunk_addr));
1554
0
    assert(chunk_rec->nbytes > 0);
1555
0
    assert(f);
1556
1557
    /* Remove raw data chunk from file */
1558
0
    if (H5MF_xfree(f, H5FD_MEM_DRAW, chunk_rec->chunk_addr, chunk_rec->nbytes) < 0)
1559
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, H5_ITER_ERROR, "unable to free chunk");
1560
1561
0
done:
1562
0
    FUNC_LEAVE_NOAPI(ret_value)
1563
0
} /* end H5D__earray_idx_delete_cb() */
1564
1565
/*-------------------------------------------------------------------------
1566
 * Function:    H5D__earray_idx_delete
1567
 *
1568
 * Purpose:     Delete index and raw data storage for entire dataset
1569
 *              (i.e. all chunks)
1570
 *
1571
 * Note:        This implementation is slow, particularly for sparse
1572
 *              extensible arrays, replace it with call to H5EA_iterate()
1573
 *              when that's available.
1574
 *
1575
 * Return:      Success:    Non-negative
1576
 *              Failure:    negative
1577
 *
1578
 *-------------------------------------------------------------------------
1579
 */
1580
static herr_t
1581
H5D__earray_idx_delete(const H5D_chk_idx_info_t *idx_info)
1582
0
{
1583
0
    herr_t ret_value = SUCCEED; /* Return value */
1584
1585
0
    FUNC_ENTER_PACKAGE
1586
1587
    /* Sanity checks */
1588
0
    assert(idx_info);
1589
0
    assert(idx_info->f);
1590
0
    assert(idx_info->pline);
1591
0
    assert(idx_info->layout);
1592
1593
    /* Check if the index data structure has been allocated */
1594
0
    if (H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)) {
1595
0
        H5D_earray_ctx_ud_t ctx_udata; /* User data for extensible array open call */
1596
1597
        /* Iterate over the chunk addresses in the extensible array, deleting each chunk */
1598
0
        if (H5D__earray_idx_iterate(idx_info, H5D__earray_idx_delete_cb, idx_info->f) < 0)
1599
0
            HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk addresses");
1600
1601
        /* Close extensible array */
1602
0
        if (H5D__earray_idx_close(idx_info) < 0)
1603
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array");
1604
1605
        /* Set up the context user data */
1606
0
        ctx_udata.f = idx_info->f;
1607
1608
        /* Compute number of bytes used to encode the chunk size */
1609
0
        H5D_EARRAY_COMPUTE_CHUNK_SIZE_LEN(ctx_udata.chunk_size_len, idx_info);
1610
1611
        /* Delete extensible array */
1612
0
        if (H5EA_delete(idx_info->f, idx_info->layout->storage.u.chunk.idx_addr, &ctx_udata) < 0)
1613
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk extensible array");
1614
0
        idx_info->layout->storage.u.chunk.idx_addr = HADDR_UNDEF;
1615
0
    } /* end if */
1616
0
    else
1617
0
        assert(NULL == idx_info->layout->storage.u.chunk.u.earray.ea);
1618
1619
0
done:
1620
0
    FUNC_LEAVE_NOAPI(ret_value)
1621
0
} /* end H5D__earray_idx_delete() */
1622
1623
/*-------------------------------------------------------------------------
1624
 * Function:    H5D__earray_idx_copy_setup
1625
 *
1626
 * Purpose:     Set up any necessary information for copying chunks
1627
 *
1628
 * Return:      Non-negative on success/Negative on failure
1629
 *
1630
 *-------------------------------------------------------------------------
1631
 */
1632
static herr_t
1633
H5D__earray_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src, const H5D_chk_idx_info_t *idx_info_dst)
1634
0
{
1635
0
    herr_t ret_value = SUCCEED; /* Return value */
1636
1637
0
    FUNC_ENTER_PACKAGE
1638
1639
    /* Check args */
1640
0
    assert(idx_info_src);
1641
0
    assert(idx_info_src->f);
1642
0
    assert(idx_info_src->pline);
1643
0
    assert(idx_info_src->layout);
1644
0
    assert(idx_info_dst);
1645
0
    assert(idx_info_dst->f);
1646
0
    assert(idx_info_dst->pline);
1647
0
    assert(idx_info_dst->layout);
1648
0
    assert(!H5_addr_defined(idx_info_dst->layout->storage.u.chunk.idx_addr));
1649
1650
    /* Check if the source extensible array is open yet */
1651
0
    if (!H5D_EARRAY_IDX_IS_OPEN(idx_info_src))
1652
        /* Open the extensible array in file */
1653
0
        if (H5D__earray_idx_open(idx_info_src) < 0)
1654
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array");
1655
1656
    /* Set copied metadata tag */
1657
0
    H5_BEGIN_TAG(H5AC__COPIED_TAG)
1658
1659
    /* Create the extensible array that describes chunked storage in the dest. file */
1660
0
    if (H5D__earray_idx_create(idx_info_dst) < 0)
1661
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage");
1662
0
    assert(H5_addr_defined(idx_info_dst->layout->storage.u.chunk.idx_addr));
1663
1664
    /* Reset metadata tag */
1665
0
    H5_END_TAG
1666
1667
0
done:
1668
0
    FUNC_LEAVE_NOAPI(ret_value)
1669
0
} /* end H5D__earray_idx_copy_setup() */
1670
1671
/*-------------------------------------------------------------------------
1672
 * Function:    H5D__earray_idx_copy_shutdown
1673
 *
1674
 * Purpose:     Shutdown any information from copying chunks
1675
 *
1676
 * Return:      Non-negative on success/Negative on failure
1677
 *
1678
 *-------------------------------------------------------------------------
1679
 */
1680
static herr_t
1681
H5D__earray_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst)
1682
0
{
1683
0
    herr_t ret_value = SUCCEED; /* Return value */
1684
1685
0
    FUNC_ENTER_PACKAGE
1686
1687
    /* Check args */
1688
0
    assert(storage_src);
1689
0
    assert(storage_src->u.earray.ea);
1690
0
    assert(storage_dst);
1691
0
    assert(storage_dst->u.earray.ea);
1692
1693
    /* Close extensible arrays */
1694
0
    if (H5EA_close(storage_src->u.earray.ea) < 0)
1695
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array");
1696
0
    storage_src->u.earray.ea = NULL;
1697
0
    if (H5EA_close(storage_dst->u.earray.ea) < 0)
1698
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array");
1699
0
    storage_dst->u.earray.ea = NULL;
1700
1701
0
done:
1702
0
    FUNC_LEAVE_NOAPI(ret_value)
1703
0
} /* end H5D__earray_idx_copy_shutdown() */
1704
1705
/*-------------------------------------------------------------------------
1706
 * Function:    H5D__earray_idx_size
1707
 *
1708
 * Purpose:     Retrieve the amount of index storage for chunked dataset
1709
 *
1710
 * Return:      Success:        Non-negative
1711
 *              Failure:        negative
1712
 *
1713
 *-------------------------------------------------------------------------
1714
 */
1715
static herr_t
1716
H5D__earray_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
1717
0
{
1718
0
    H5EA_t     *ea;                  /* Pointer to extensible array structure */
1719
0
    H5EA_stat_t ea_stat;             /* Extensible array statistics */
1720
0
    herr_t      ret_value = SUCCEED; /* Return value */
1721
1722
0
    FUNC_ENTER_PACKAGE
1723
1724
    /* Check args */
1725
0
    assert(idx_info);
1726
0
    assert(idx_info->f);
1727
0
    assert(idx_info->pline);
1728
0
    assert(idx_info->layout);
1729
0
    assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr));
1730
0
    assert(index_size);
1731
1732
    /* Open the extensible array in file */
1733
0
    if (H5D__earray_idx_open(idx_info) < 0)
1734
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array");
1735
1736
    /* Set convenience pointer to extensible array structure */
1737
0
    ea = idx_info->layout->storage.u.chunk.u.earray.ea;
1738
1739
    /* Get the extensible array statistics */
1740
0
    if (H5EA_get_stats(ea, &ea_stat) < 0)
1741
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query extensible array statistics");
1742
1743
    /* Set the size of the extensible array */
1744
0
    *index_size = ea_stat.computed.hdr_size + ea_stat.computed.index_blk_size +
1745
0
                  ea_stat.stored.super_blk_size + ea_stat.stored.data_blk_size;
1746
1747
0
done:
1748
0
    if (idx_info->layout->storage.u.chunk.u.earray.ea) {
1749
0
        if (H5D__earray_idx_close(idx_info) < 0)
1750
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array");
1751
0
    } /* end if */
1752
1753
0
    FUNC_LEAVE_NOAPI(ret_value)
1754
0
} /* end H5D__earray_idx_size() */
1755
1756
/*-------------------------------------------------------------------------
1757
 * Function:    H5D__earray_idx_reset
1758
 *
1759
 * Purpose:     Reset indexing information.
1760
 *
1761
 * Return:      Non-negative on success/Negative on failure
1762
 *
1763
 *-------------------------------------------------------------------------
1764
 */
1765
static herr_t
1766
H5D__earray_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr)
1767
0
{
1768
0
    FUNC_ENTER_PACKAGE_NOERR
1769
1770
    /* Check args */
1771
0
    assert(storage);
1772
1773
    /* Reset index info */
1774
0
    if (reset_addr) {
1775
0
        storage->idx_addr                = HADDR_UNDEF;
1776
0
        storage->u.earray.dset_ohdr_addr = HADDR_UNDEF;
1777
0
    } /* end if */
1778
0
    storage->u.earray.ea = NULL;
1779
1780
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1781
0
} /* end H5D__earray_idx_reset() */
1782
1783
/*-------------------------------------------------------------------------
1784
 * Function:    H5D__earray_idx_dump
1785
 *
1786
 * Purpose:     Dump indexing information to a stream.
1787
 *
1788
 * Return:      Non-negative on success/Negative on failure
1789
 *
1790
 *-------------------------------------------------------------------------
1791
 */
1792
static herr_t
1793
H5D__earray_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
1794
0
{
1795
0
    FUNC_ENTER_PACKAGE_NOERR
1796
1797
    /* Check args */
1798
0
    assert(storage);
1799
0
    assert(stream);
1800
1801
0
    fprintf(stream, "    Address: %" PRIuHADDR "\n", storage->idx_addr);
1802
1803
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1804
0
} /* end H5D__earray_idx_dump() */
1805
1806
/*-------------------------------------------------------------------------
1807
 * Function:    H5D__earray_idx_dest
1808
 *
1809
 * Purpose:     Release indexing information in memory.
1810
 *
1811
 * Return:      Non-negative on success/Negative on failure
1812
 *
1813
 *-------------------------------------------------------------------------
1814
 */
1815
static herr_t
1816
H5D__earray_idx_dest(const H5D_chk_idx_info_t *idx_info)
1817
0
{
1818
0
    herr_t ret_value = SUCCEED; /* Return value */
1819
1820
0
    FUNC_ENTER_PACKAGE
1821
1822
    /* Check args */
1823
0
    assert(idx_info);
1824
0
    assert(idx_info->f);
1825
0
    assert(idx_info->layout);
1826
1827
    /* Check if the extensible array is open */
1828
0
    if (H5D_EARRAY_IDX_IS_OPEN(idx_info)) {
1829
        /* Patch the top level file pointer contained in ea if needed */
1830
0
        if (H5EA_patch_file(idx_info->layout->storage.u.chunk.u.earray.ea, idx_info->f) < 0)
1831
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch earray file pointer");
1832
1833
        /* Close extensible array */
1834
0
        if (H5D__earray_idx_close(idx_info) < 0)
1835
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array");
1836
0
    } /* end if */
1837
1838
0
done:
1839
0
    FUNC_LEAVE_NOAPI(ret_value)
1840
0
} /* end H5D__earray_idx_dest() */