Coverage Report

Created: 2025-08-26 06:30

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