Coverage Report

Created: 2026-02-26 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Dvirtual.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:
15
 *      Virtual Dataset (VDS) functions.  Creates a layout type which allows
16
 *      definition of a virtual dataset, where the actual dataset is stored in
17
 *      other datasets (called source datasets).  The mappings between the
18
 *      virtual and source datasets are specified by hyperslab or "all"
19
 *      dataspace selections.  Point selections are not currently supported.
20
 *      Overlaps in the mappings in the virtual dataset result in undefined
21
 *      behaviour.
22
 *
23
 *      Mapping selections may be unlimited, in which case the size of the
24
 *      virtual dataset is determined by the size of the source dataset(s).
25
 *      Names for the source datasets may also be generated procedurally, in
26
 *      which case the virtual selection should be unlimited with an unlimited
27
 *      count and the source selection should be limited with a size equal to
28
 *      that of the virtual selection with the unlimited count set to 1.
29
 *
30
 *      Source datasets are opened lazily (only when needed for I/O or to
31
 *      determine the size of the virtual dataset), and are currently held open
32
 *      until the virtual dataset is closed.
33
 */
34
35
/*
36
 * Note: H5S_select_project_intersection has been updated to no longer require
37
 * that the source and source intersect spaces have the same extent.  This file
38
 * should therefore be updated to remove code that ensures this condition, which
39
 * should improve both maintainability and performance.
40
 */
41
42
/****************/
43
/* Module Setup */
44
/****************/
45
46
#include "H5Dmodule.h" /* This source code file is part of the H5D module */
47
48
/***********/
49
/* Headers */
50
/***********/
51
#include "H5private.h"   /* Generic Functions                    */
52
#include "H5CXprivate.h" /* API Contexts                         */
53
#include "H5Dpkg.h"      /* Dataset functions                    */
54
#include "H5Eprivate.h"  /* Error handling                       */
55
#include "H5Fprivate.h"  /* Files                                */
56
#include "H5FLprivate.h" /* Free Lists                           */
57
#include "H5Gprivate.h"  /* Groups                               */
58
#include "H5HGprivate.h" /* Global Heaps                         */
59
#include "H5Iprivate.h"  /* IDs                                  */
60
#include "H5MMprivate.h" /* Memory management                    */
61
#include "H5Oprivate.h"  /* Object headers                       */
62
#include "H5Pprivate.h"  /* Property Lists                       */
63
#include "H5RTprivate.h" /* R-trees                              */
64
#include "H5Sprivate.h"  /* Dataspaces                           */
65
#include "H5VLprivate.h" /* Virtual Object Layer                 */
66
67
/****************/
68
/* Local Macros */
69
/****************/
70
71
/* Default size for sub_dset array */
72
0
#define H5D_VIRTUAL_DEF_SUB_DSET_SIZE 128
73
74
/* Default size for not_in_tree list allocation */
75
0
#define H5D_VIRTUAL_NOT_IN_TREE_INIT_SIZE 64
76
77
/*
78
 * Determines whether a virtual dataset mapping entry should be inserted
79
 * into the R-tree spatial index.
80
 *
81
 * The following mappings cannot be added to the tree:
82
 * - Mappings with an unlimited dimension, since this would invalidate the spatial search process
83
 * - Mappings with zero dimensions, since the tree relies on each entry having at least one dimension
84
 *
85
 */
86
87
/* Mappings with an unlimited dimension */
88
#define H5D_RTREE_SHOULD_INSERT(entry)                                                                       \
89
0
    !(((entry)->unlim_dim_virtual >= 0) || ((entry)->source_dset.virtual_select &&                           \
90
0
                                            H5S_GET_EXTENT_NDIMS((entry)->source_dset.virtual_select) < 1))
91
92
/******************/
93
/* Local Typedefs */
94
/******************/
95
96
/********************/
97
/* Local Prototypes */
98
/********************/
99
100
/* Layout operation callbacks */
101
static herr_t H5D__virtual_construct(H5F_t *f, H5D_t *dset);
102
static herr_t H5D__virtual_init(H5F_t *f, H5D_t *dset, hid_t dapl_id, bool open_op);
103
static bool   H5D__virtual_is_space_alloc(const H5O_storage_t *storage);
104
static bool   H5D__virtual_is_data_cached(const H5D_shared_t *shared_dset);
105
static herr_t H5D__virtual_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo);
106
static herr_t H5D__virtual_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo);
107
static herr_t H5D__virtual_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo);
108
static herr_t H5D__virtual_flush(H5D_t *dset);
109
110
/* Other functions */
111
static herr_t H5D__virtual_free_layout_mappings(H5O_storage_virtual_t *virt);
112
static herr_t H5D__virtual_open_source_dset(const H5D_t *vdset, H5O_storage_virtual_ent_t *virtual_ent,
113
                                            H5O_storage_virtual_srcdset_t *source_dset);
114
static herr_t H5D__virtual_reset_source_dset(H5O_storage_virtual_ent_t     *virtual_ent,
115
                                             H5O_storage_virtual_srcdset_t *source_dset);
116
static herr_t H5D__virtual_str_append(const char *src, size_t src_len, char **p, char **buf,
117
                                      size_t *buf_size);
118
static herr_t H5D__virtual_copy_parsed_name(H5O_storage_virtual_name_seg_t **dst,
119
                                            H5O_storage_virtual_name_seg_t  *src);
120
static herr_t H5D__virtual_build_source_name(char                                 *source_name,
121
                                             const H5O_storage_virtual_name_seg_t *parsed_name,
122
                                             size_t static_strlen, size_t nsubs, hsize_t blockno,
123
                                             char **built_name);
124
static herr_t H5D__virtual_init_all(const H5D_t *dset);
125
static herr_t H5D__virtual_pre_io(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_t *storage,
126
                                  H5S_t *file_space, H5S_t *mem_space, hsize_t *tot_nelmts,
127
                                  H5RT_result_set_t *mappings);
128
static herr_t H5D__virtual_post_io(H5O_storage_virtual_t *storage, H5RT_result_set_t *mappings);
129
static herr_t H5D__virtual_close_mapping(H5O_storage_virtual_ent_t *mapping);
130
static herr_t H5D__virtual_read_one_mapping(H5D_dset_io_info_t        *dset_info,
131
                                            H5O_storage_virtual_ent_t *mapping);
132
static herr_t H5D__virtual_read_one_src(H5D_dset_io_info_t            *dset_info,
133
                                        H5O_storage_virtual_srcdset_t *source_dset);
134
static herr_t H5D__virtual_write_one_mapping(H5D_dset_io_info_t        *dset_info,
135
                                             H5O_storage_virtual_ent_t *mapping);
136
static herr_t H5D__virtual_write_one_src(H5D_dset_io_info_t            *dset_info,
137
                                         H5O_storage_virtual_srcdset_t *source_dset);
138
139
/* R-tree helper functions */
140
static herr_t H5D__virtual_build_tree(H5O_storage_virtual_t *virt, int rank);
141
static herr_t H5D__mappings_to_leaves(H5O_storage_virtual_ent_t *mappings, size_t num_mappings,
142
                                      H5RT_leaf_t **leaves_out, H5O_storage_virtual_ent_t ***not_in_tree_out,
143
                                      size_t *leaf_count, size_t *not_in_tree_count,
144
                                      size_t *not_in_tree_nalloc);
145
static herr_t H5D__should_build_tree(H5O_storage_virtual_t *storage, hid_t dapl_id, bool *should_build_tree);
146
static herr_t H5D__virtual_not_in_tree_grow(H5O_storage_virtual_ent_t ***list, size_t *nalloc);
147
static herr_t H5D__virtual_not_in_tree_add(H5O_storage_virtual_ent_t ***list, size_t *nused, size_t *nalloc,
148
                                           H5O_storage_virtual_ent_t *mapping);
149
/*********************/
150
/* Package Variables */
151
/*********************/
152
153
/* Contiguous storage layout I/O ops */
154
const H5D_layout_ops_t H5D_LOPS_VIRTUAL[1] = {{
155
    H5D__virtual_construct,      /* construct */
156
    H5D__virtual_init,           /* init */
157
    H5D__virtual_is_space_alloc, /* is_space_alloc */
158
    H5D__virtual_is_data_cached, /* is_data_cached */
159
    H5D__virtual_io_init,        /* io_init */
160
    NULL,                        /* mdio_init */
161
    H5D__virtual_read,           /* ser_read */
162
    H5D__virtual_write,          /* ser_write */
163
    NULL,                        /* readvv */
164
    NULL,                        /* writevv */
165
    H5D__virtual_flush,          /* flush */
166
    NULL,                        /* io_term */
167
    NULL                         /* dest */
168
}};
169
170
/*******************/
171
/* Local Variables */
172
/*******************/
173
174
/* Declare a free list to manage the H5O_storage_virtual_name_seg_t struct */
175
H5FL_DEFINE(H5O_storage_virtual_name_seg_t);
176
177
/* Declare a static free list to manage H5D_virtual_file_list_t structs */
178
H5FL_DEFINE_STATIC(H5D_virtual_held_file_t);
179
180
/*-------------------------------------------------------------------------
181
 * Function:    H5D_virtual_check_mapping_pre
182
 *
183
 * Purpose:     Checks that the provided virtual and source selections are
184
 *              legal for use as a VDS mapping, prior to creating the rest
185
 *              of the mapping entry.
186
 *
187
 * Return:      Non-negative on success/Negative on failure
188
 *
189
 *-------------------------------------------------------------------------
190
 */
191
herr_t
192
H5D_virtual_check_mapping_pre(const H5S_t *vspace, const H5S_t *src_space,
193
                              H5O_virtual_space_status_t space_status)
194
0
{
195
0
    H5S_sel_type select_type;         /* Selection type */
196
0
    hsize_t      nelmts_vs;           /* Number of elements in virtual selection */
197
0
    hsize_t      nelmts_ss;           /* Number of elements in source selection */
198
0
    herr_t       ret_value = SUCCEED; /* Return value */
199
200
0
    FUNC_ENTER_NOAPI(FAIL)
201
202
    /* Check for point selections (currently unsupported) */
203
0
    if (H5S_SEL_ERROR == (select_type = H5S_GET_SELECT_TYPE(vspace)))
204
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get selection type");
205
0
    if (select_type == H5S_SEL_POINTS)
206
0
        HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
207
0
                    "point selections not currently supported with virtual datasets");
208
0
    if (H5S_SEL_ERROR == (select_type = H5S_GET_SELECT_TYPE(src_space)))
209
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get selection type");
210
0
    if (select_type == H5S_SEL_POINTS)
211
0
        HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
212
0
                    "point selections not currently supported with virtual datasets");
213
214
    /* Get number of elements in spaces */
215
0
    nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(vspace);
216
0
    nelmts_ss = (hsize_t)H5S_GET_SELECT_NPOINTS(src_space);
217
218
    /* Check for unlimited vspace */
219
0
    if (nelmts_vs == H5S_UNLIMITED) {
220
        /* Check for unlimited src_space */
221
0
        if (nelmts_ss == H5S_UNLIMITED) {
222
0
            hsize_t nenu_vs; /* Number of elements in the non-unlimited dimensions of vspace */
223
0
            hsize_t nenu_ss; /* Number of elements in the non-unlimited dimensions of src_space */
224
225
            /* Non-printf unlimited selection.  Make sure both selections have
226
             * the same number of elements in the non-unlimited dimension.  Note
227
             * we can always check this even if the space status is invalid
228
             * because unlimited selections are never dependent on the extent.
229
             */
230
0
            if (H5S_get_select_num_elem_non_unlim(vspace, &nenu_vs) < 0)
231
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL,
232
0
                            "can't get number of elements in non-unlimited dimension");
233
0
            if (H5S_get_select_num_elem_non_unlim(src_space, &nenu_ss) < 0)
234
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL,
235
0
                            "can't get number of elements in non-unlimited dimension");
236
0
            if (nenu_vs != nenu_ss)
237
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
238
0
                            "numbers of elements in the non-unlimited dimensions is different for source and "
239
0
                            "virtual spaces");
240
0
        } /* end if */
241
        /* We will handle the printf case after parsing the source names */
242
0
    } /* end if */
243
0
    else if (space_status != H5O_VIRTUAL_STATUS_INVALID)
244
        /* Limited selections.  Check number of points is the same. */
245
0
        if (nelmts_vs != nelmts_ss)
246
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
247
0
                        "virtual and source space selections have different numbers of elements");
248
249
0
done:
250
0
    FUNC_LEAVE_NOAPI(ret_value)
251
0
} /* end H5D_virtual_check_mapping_pre() */
252
253
/*-------------------------------------------------------------------------
254
 * Function:    H5D_virtual_check_mapping_post
255
 *
256
 * Purpose:     Checks that the provided virtual dataset mapping entry is
257
 *              legal, after the mapping is otherwise complete.
258
 *
259
 * Return:      Non-negative on success/Negative on failure
260
 *
261
 *-------------------------------------------------------------------------
262
 */
263
herr_t
264
H5D_virtual_check_mapping_post(const H5O_storage_virtual_ent_t *ent)
265
0
{
266
0
    hsize_t nelmts_vs;           /* Number of elements in virtual selection */
267
0
    hsize_t nelmts_ss;           /* Number of elements in source selection */
268
0
    H5S_t  *tmp_space = NULL;    /* Temporary dataspace */
269
0
    herr_t  ret_value = SUCCEED; /* Return value */
270
271
0
    FUNC_ENTER_NOAPI(FAIL)
272
273
    /* Get number of elements in spaces */
274
0
    nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(ent->source_dset.virtual_select);
275
0
    nelmts_ss = (hsize_t)H5S_GET_SELECT_NPOINTS(ent->source_select);
276
277
    /* Check for printf selection */
278
0
    if ((nelmts_vs == H5S_UNLIMITED) && (nelmts_ss != H5S_UNLIMITED)) {
279
        /* Make sure there at least one %b substitution in the source file or
280
         * dataset name */
281
0
        if ((ent->psfn_nsubs == 0) && (ent->psdn_nsubs == 0))
282
0
            HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL,
283
0
                        "unlimited virtual selection, limited source selection, and no printf specifiers in "
284
0
                        "source names");
285
286
        /* Make sure virtual space uses hyperslab selection */
287
0
        if (H5S_GET_SELECT_TYPE(ent->source_dset.virtual_select) != H5S_SEL_HYPERSLABS)
288
0
            HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL,
289
0
                        "virtual selection with printf mapping must be hyperslab");
290
291
        /* Check that the number of elements in one block in the virtual
292
         * selection matches the total number of elements in the source
293
         * selection, if the source space status is not invalid (virtual space
294
         * status does not matter here because it is unlimited) */
295
0
        if (ent->source_space_status != H5O_VIRTUAL_STATUS_INVALID) {
296
            /* Get first block in virtual selection */
297
0
            if (NULL == (tmp_space = H5S_hyper_get_unlim_block(ent->source_dset.virtual_select, (hsize_t)0)))
298
0
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get first block in virtual selection");
299
300
            /* Check number of points */
301
0
            nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(tmp_space);
302
0
            if (nelmts_vs != nelmts_ss)
303
0
                HGOTO_ERROR(
304
0
                    H5E_ARGS, H5E_BADVALUE, FAIL,
305
0
                    "virtual (single block) and source space selections have different numbers of elements");
306
0
        } /* end if */
307
0
    }     /* end if */
308
0
    else
309
        /* Make sure there are no printf substitutions */
310
0
        if ((ent->psfn_nsubs > 0) || (ent->psdn_nsubs > 0))
311
0
            HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL,
312
0
                        "printf specifier(s) in source name(s) without an unlimited virtual selection and "
313
0
                        "limited source selection");
314
315
0
done:
316
    /* Free temporary space */
317
0
    if (tmp_space)
318
0
        if (H5S_close(tmp_space) < 0)
319
0
            HDONE_ERROR(H5E_PLIST, H5E_CLOSEERROR, FAIL, "can't close dataspace");
320
321
0
    FUNC_LEAVE_NOAPI(ret_value)
322
0
} /* end H5D_virtual_check_mapping_post() */
323
324
/*-------------------------------------------------------------------------
325
 * Function:    H5D_virtual_update_min_dims
326
 *
327
 * Purpose:     Updates the virtual layout's "min_dims" field to take into
328
 *              account the "idx"th entry in the mapping list.  The entry
329
 *              must be complete, though top level field list_nused (and
330
 *              of course min_dims) does not need to take it into account.
331
 *
332
 * Return:      Non-negative on success/Negative on failure
333
 *
334
 *-------------------------------------------------------------------------
335
 */
336
herr_t
337
H5D_virtual_update_min_dims(H5O_layout_t *layout, size_t idx)
338
0
{
339
0
    H5O_storage_virtual_t     *virt = &layout->storage.u.virt;
340
0
    H5O_storage_virtual_ent_t *ent  = &virt->list[idx];
341
0
    H5S_sel_type               sel_type;
342
0
    int                        rank;
343
0
    hsize_t                    bounds_start[H5S_MAX_RANK];
344
0
    hsize_t                    bounds_end[H5S_MAX_RANK];
345
0
    int                        i;
346
0
    herr_t                     ret_value = SUCCEED;
347
348
0
    FUNC_ENTER_NOAPI(FAIL)
349
350
0
    assert(layout);
351
0
    assert(layout->type == H5D_VIRTUAL);
352
0
    assert(idx < virt->list_nalloc);
353
354
    /* Get type of selection */
355
0
    if (H5S_SEL_ERROR == (sel_type = H5S_GET_SELECT_TYPE(ent->source_dset.virtual_select)))
356
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection type");
357
358
    /* Do not update min_dims for "all" or "none" selections */
359
0
    if ((sel_type == H5S_SEL_ALL) || (sel_type == H5S_SEL_NONE))
360
0
        HGOTO_DONE(SUCCEED);
361
362
    /* Get rank of vspace */
363
0
    if ((rank = H5S_GET_EXTENT_NDIMS(ent->source_dset.virtual_select)) < 0)
364
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions");
365
366
    /* Get selection bounds */
367
0
    if (H5S_SELECT_BOUNDS(ent->source_dset.virtual_select, bounds_start, bounds_end) < 0)
368
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds");
369
370
    /* Update min_dims */
371
0
    for (i = 0; i < rank; i++)
372
        /* Don't check unlimited dimensions in the selection */
373
0
        if ((i != ent->unlim_dim_virtual) && (bounds_end[i] >= virt->min_dims[i]))
374
0
            virt->min_dims[i] = bounds_end[i] + (hsize_t)1;
375
376
0
done:
377
0
    FUNC_LEAVE_NOAPI(ret_value)
378
0
} /* end H5D_virtual_update_min_dims() */
379
380
/*-------------------------------------------------------------------------
381
 * Function:    H5D_virtual_check_min_dims
382
 *
383
 * Purpose:     Checks if the dataset's dimensions are at least the
384
 *              calculated minimum dimensions from the mappings.
385
 *
386
 * Return:      Non-negative on success/Negative on failure
387
 *
388
 *-------------------------------------------------------------------------
389
 */
390
herr_t
391
H5D_virtual_check_min_dims(const H5D_t *dset)
392
0
{
393
0
    int     rank;
394
0
    hsize_t dims[H5S_MAX_RANK];
395
0
    int     i;
396
0
    herr_t  ret_value = SUCCEED;
397
398
0
    FUNC_ENTER_NOAPI(FAIL)
399
400
0
    assert(dset);
401
0
    assert(dset->shared);
402
0
    assert(dset->shared->layout.type == H5D_VIRTUAL);
403
404
    /* Get rank of dataspace */
405
0
    if ((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0)
406
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions");
407
408
    /* Get VDS dimensions */
409
0
    if (H5S_get_simple_extent_dims(dset->shared->space, dims, NULL) < 0)
410
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions");
411
412
    /* Verify that dimensions are larger than min_dims */
413
0
    for (i = 0; i < rank; i++)
414
0
        if (dims[i] < dset->shared->layout.storage.u.virt.min_dims[i])
415
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
416
0
                        "virtual dataset dimensions not large enough to contain all limited dimensions in "
417
0
                        "all selections");
418
419
0
done:
420
0
    FUNC_LEAVE_NOAPI(ret_value)
421
0
} /* end H5D_virtual_check_min_dims() */
422
423
/*-------------------------------------------------------------------------
424
 * Function:    H5D__virtual_store_layout
425
 *
426
 * Purpose:     Store virtual dataset layout information, for new dataset
427
 *
428
 * Note:        We assume here that the contents of the heap block cannot
429
 *        change!  If this ever stops being the case we must change
430
 *        this code to allow overwrites of the heap block.  -NAF
431
 *
432
 * Return:      Success:    SUCCEED
433
 *              Failure:    FAIL
434
 *
435
 *-------------------------------------------------------------------------
436
 */
437
herr_t
438
H5D__virtual_store_layout(H5F_t *f, H5O_layout_t *layout)
439
0
{
440
0
    H5O_storage_virtual_t *virt       = &layout->storage.u.virt;
441
0
    uint8_t               *heap_block = NULL; /* Block to add to heap */
442
0
    size_t                *str_size   = NULL; /* Array for VDS entry string lengths */
443
0
    uint8_t               *heap_block_p;      /* Pointer into the heap block, while encoding */
444
0
    size_t                 block_size;        /* Total size of block needed */
445
0
    hsize_t                tmp_hsize;         /* Temp. variable for encoding hsize_t */
446
0
    uint32_t               chksum;            /* Checksum for heap data */
447
0
    uint8_t                max_version;       /* Maximum encoding version allowed by version bounds */
448
0
    uint8_t                version = H5O_LAYOUT_VDS_GH_ENC_VERS_0; /* Encoding version */
449
0
    size_t                 i;                                      /* Local index variable */
450
0
    herr_t                 ret_value = SUCCEED;                    /* Return value */
451
452
0
    FUNC_ENTER_PACKAGE
453
454
    /* Sanity checking */
455
0
    assert(f);
456
0
    assert(layout);
457
0
    assert(virt->serial_list_hobjid.addr == HADDR_UNDEF);
458
459
    /* Create block if # of used entries > 0 */
460
0
    if (virt->list_nused > 0) {
461
462
        /* Set the low/high bounds according to 'f' for the API context */
463
0
        H5CX_set_libver_bounds(f);
464
465
        /* Calculate maximum encoding version. Currently there are no features that require a later version,
466
         * so we only upgrade if the lower bound is high enough that we don't worry about backward
467
         * compatibility, and if there is a benefit (will calculate the benefit later). */
468
0
        max_version =
469
0
            H5F_LOW_BOUND(f) >= H5F_LIBVER_V200 ? H5O_LAYOUT_VDS_GH_ENC_VERS_1 : H5O_LAYOUT_VDS_GH_ENC_VERS_0;
470
471
        /* Allocate array for caching results of strlen */
472
0
        if (NULL == (str_size = (size_t *)H5MM_malloc(2 * virt->list_nused * sizeof(size_t))))
473
0
            HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, FAIL, "unable to allocate string length array");
474
475
        /*
476
         * Calculate heap block size
477
         */
478
479
        /* Version and number of entries */
480
0
        block_size = (size_t)1 + H5F_SIZEOF_SIZE(f);
481
482
        /* Calculate size of each entry */
483
0
        for (i = 0; i < virt->list_nused; i++) {
484
0
            H5O_storage_virtual_ent_t *ent = &virt->list[i];
485
0
            hssize_t                   select_serial_size; /* Size of serialized selection */
486
487
0
            assert(ent->source_file_name);
488
0
            assert(ent->source_dset_name);
489
0
            assert(ent->source_select);
490
0
            assert(ent->source_dset.virtual_select);
491
492
            /* Source file name */
493
0
            str_size[2 * i] = strlen(ent->source_file_name) + (size_t)1;
494
0
            block_size += str_size[2 * i];
495
496
            /* Source dset name */
497
0
            str_size[(2 * i) + 1] = strlen(ent->source_dset_name) + (size_t)1;
498
0
            block_size += str_size[(2 * i) + 1];
499
500
            /* Source selection */
501
0
            if ((select_serial_size = H5S_SELECT_SERIAL_SIZE(ent->source_select)) < 0)
502
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size");
503
0
            block_size += (size_t)select_serial_size;
504
505
            /* Virtual dataset selection */
506
0
            if ((select_serial_size = H5S_SELECT_SERIAL_SIZE(ent->source_dset.virtual_select)) < 0)
507
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size");
508
0
            block_size += (size_t)select_serial_size;
509
0
        }
510
511
        /* Checksum */
512
0
        block_size += 4;
513
514
        /*
515
         * Calculate_heap_block_size for version 1, if available
516
         */
517
0
        if (max_version >= H5O_LAYOUT_VDS_GH_ENC_VERS_1) {
518
0
            size_t block_size_1; /* Block size if we use version 1 */
519
            /* Version and number of entries */
520
0
            block_size_1 = (size_t)1 + H5F_SIZEOF_SIZE(f);
521
522
            /* Calculate size of each entry */
523
0
            for (i = 0; i < virt->list_nused; i++) {
524
0
                H5O_storage_virtual_ent_t *ent = &virt->list[i];
525
0
                hssize_t                   select_serial_size; /* Size of serialized selection */
526
527
                /* Flags */
528
0
                block_size_1 += (size_t)1;
529
530
                /* Source file name (no encoding necessary for ".") */
531
0
                if (strcmp(ent->source_file_name, ".")) {
532
0
                    if (ent->source_file_orig == SIZE_MAX)
533
0
                        block_size_1 += str_size[2 * i];
534
0
                    else
535
0
                        block_size_1 += MIN(str_size[2 * i], H5F_SIZEOF_SIZE(f));
536
0
                }
537
538
                /* Source dset name */
539
0
                if (ent->source_dset_orig == SIZE_MAX)
540
0
                    block_size_1 += str_size[(2 * i) + 1];
541
0
                else
542
0
                    block_size_1 += MIN(str_size[(2 * i) + 1], H5F_SIZEOF_SIZE(f));
543
544
                /* Source selection */
545
0
                if ((select_serial_size = H5S_SELECT_SERIAL_SIZE(ent->source_select)) < 0)
546
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size");
547
0
                block_size_1 += (size_t)select_serial_size;
548
549
                /* Virtual dataset selection */
550
0
                if ((select_serial_size = H5S_SELECT_SERIAL_SIZE(ent->source_dset.virtual_select)) < 0)
551
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size");
552
0
                block_size_1 += (size_t)select_serial_size;
553
0
            }
554
555
            /* Checksum */
556
0
            block_size_1 += 4;
557
558
            /* Determine which version to use. Only use version 1 if we save space. In the case of a tie, use
559
             * version 1 since it will allow faster decoding since we know (some of) which strings are shared
560
             * and won't need to do hash table lookups for those. */
561
0
            if (block_size_1 <= block_size) {
562
0
                version    = H5O_LAYOUT_VDS_GH_ENC_VERS_1;
563
0
                block_size = block_size_1;
564
0
            }
565
0
        }
566
567
        /* Allocate heap block */
568
0
        if (NULL == (heap_block = (uint8_t *)H5MM_malloc(block_size)))
569
0
            HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, FAIL, "unable to allocate heap block");
570
571
        /*
572
         * Encode heap block
573
         */
574
0
        heap_block_p = heap_block;
575
576
        /* Encode heap block encoding version */
577
0
        *heap_block_p++ = version;
578
579
        /* Number of entries */
580
0
        H5_CHECK_OVERFLOW(virt->list_nused, size_t, hsize_t);
581
0
        tmp_hsize = (hsize_t)virt->list_nused;
582
0
        H5F_ENCODE_LENGTH(f, heap_block_p, tmp_hsize);
583
584
        /* Encode each entry */
585
0
        for (i = 0; i < virt->list_nused; i++) {
586
0
            H5O_storage_virtual_ent_t *ent   = &virt->list[i];
587
0
            uint8_t                    flags = 0;
588
589
            /* Flags */
590
0
            if (version >= H5O_LAYOUT_VDS_GH_ENC_VERS_1) {
591
0
                if (!strcmp(ent->source_file_name, "."))
592
                    /* Source file in same file as VDS */
593
0
                    flags |= H5O_LAYOUT_VDS_SOURCE_SAME_FILE;
594
0
                else if ((ent->source_file_orig != SIZE_MAX) && (str_size[2 * i] >= H5F_SIZEOF_SIZE(f)))
595
                    /* Source file name is shared (stored in another entry) */
596
0
                    flags |= H5O_LAYOUT_VDS_SOURCE_FILE_SHARED;
597
598
0
                if ((ent->source_dset_orig != SIZE_MAX) && (str_size[(2 * i) + 1] >= H5F_SIZEOF_SIZE(f)))
599
                    /* Source dataset name is shared (stored in another entry) */
600
0
                    flags |= H5O_LAYOUT_VDS_SOURCE_DSET_SHARED;
601
602
0
                *heap_block_p++ = flags;
603
0
            }
604
605
            /* Source file name */
606
0
            if (!(flags & H5O_LAYOUT_VDS_SOURCE_SAME_FILE)) {
607
0
                if (flags & H5O_LAYOUT_VDS_SOURCE_FILE_SHARED) {
608
0
                    assert(ent->source_file_orig < i);
609
0
                    tmp_hsize = (hsize_t)ent->source_file_orig;
610
0
                    H5F_ENCODE_LENGTH(f, heap_block_p, tmp_hsize);
611
0
                }
612
0
                else {
613
0
                    H5MM_memcpy((char *)heap_block_p, ent->source_file_name, str_size[2 * i]);
614
0
                    heap_block_p += str_size[2 * i];
615
0
                }
616
0
            }
617
618
            /* Source dataset name */
619
0
            if (flags & H5O_LAYOUT_VDS_SOURCE_DSET_SHARED) {
620
0
                assert(ent->source_dset_orig < i);
621
0
                tmp_hsize = (hsize_t)ent->source_dset_orig;
622
0
                H5F_ENCODE_LENGTH(f, heap_block_p, tmp_hsize);
623
0
            }
624
0
            else {
625
0
                H5MM_memcpy((char *)heap_block_p, ent->source_dset_name, str_size[(2 * i) + 1]);
626
0
                heap_block_p += str_size[(2 * i) + 1];
627
0
            }
628
629
            /* Source selection */
630
0
            if (H5S_SELECT_SERIALIZE(ent->source_select, &heap_block_p) < 0)
631
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to serialize source selection");
632
633
            /* Virtual selection */
634
0
            if (H5S_SELECT_SERIALIZE(ent->source_dset.virtual_select, &heap_block_p) < 0)
635
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to serialize virtual selection");
636
0
        }
637
638
        /* Checksum */
639
0
        chksum = H5_checksum_metadata(heap_block, block_size - (size_t)4, 0);
640
0
        UINT32ENCODE(heap_block_p, chksum);
641
642
        /* Insert block into global heap */
643
0
        if (H5HG_insert(f, block_size, heap_block, &(virt->serial_list_hobjid)) < 0)
644
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to insert virtual dataset heap block");
645
0
    }
646
647
0
done:
648
0
    heap_block = (uint8_t *)H5MM_xfree(heap_block);
649
0
    str_size   = (size_t *)H5MM_xfree(str_size);
650
651
0
    FUNC_LEAVE_NOAPI(ret_value)
652
0
} /* end H5D__virtual_store_layout() */
653
654
/*-------------------------------------------------------------------------
655
 * Function:    H5D__virtual_load_layout
656
 *
657
 * Purpose:     Loads virtual dataset layout information from global heap
658
 *
659
 * Return:      Success:    SUCCEED
660
 *              Failure:    FAIL
661
 *
662
 *-------------------------------------------------------------------------
663
 */
664
herr_t
665
H5D__virtual_load_layout(H5F_t *f, H5O_layout_t *layout)
666
0
{
667
0
    uint8_t *heap_block = NULL;
668
0
    herr_t   ret_value  = SUCCEED; /* Return value */
669
670
0
    FUNC_ENTER_PACKAGE
671
672
    /* Decode heap block if it exists and we don't already have the list of mappings */
673
0
    if (!layout->storage.u.virt.list && layout->storage.u.virt.serial_list_hobjid.addr != HADDR_UNDEF) {
674
0
        const uint8_t *heap_block_p;
675
0
        const uint8_t *heap_block_p_end;
676
0
        uint8_t        heap_vers;
677
0
        size_t         block_size = 0;
678
0
        size_t         tmp_size;
679
0
        hsize_t        tmp_hsize = 0;
680
0
        uint32_t       stored_chksum;
681
0
        uint32_t       computed_chksum;
682
0
        size_t         first_same_file       = SIZE_MAX;
683
0
        bool           clear_file_hash_table = false;
684
685
        /* Read heap */
686
0
        if (NULL == (heap_block = (uint8_t *)H5HG_read(f, &(layout->storage.u.virt.serial_list_hobjid), NULL,
687
0
                                                       &block_size)))
688
0
            HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "Unable to read global heap block");
689
690
0
        heap_block_p     = (const uint8_t *)heap_block;
691
0
        heap_block_p_end = heap_block_p + block_size - 1;
692
693
        /* Decode the version number of the heap block encoding */
694
0
        if (H5_IS_BUFFER_OVERFLOW(heap_block_p, 1, heap_block_p_end))
695
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
696
0
        heap_vers = (uint8_t)*heap_block_p++;
697
698
0
        assert(H5O_LAYOUT_VDS_GH_ENC_VERS_0 == 0);
699
0
        if (heap_vers > (uint8_t)H5O_LAYOUT_VDS_GH_ENC_VERS_1)
700
0
            HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL,
701
0
                        "bad version # of encoded VDS heap information, expected %u or lower, got %u",
702
0
                        (unsigned)H5O_LAYOUT_VDS_GH_ENC_VERS_1, (unsigned)heap_vers);
703
704
        /* Number of entries */
705
0
        if (H5_IS_BUFFER_OVERFLOW(heap_block_p, H5F_sizeof_size(f), heap_block_p_end))
706
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
707
0
        H5F_DECODE_LENGTH(f, heap_block_p, tmp_hsize);
708
709
        /* Allocate entry list */
710
0
        if (tmp_hsize > 0) {
711
0
            if (NULL == (layout->storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_calloc(
712
0
                             (size_t)tmp_hsize * sizeof(H5O_storage_virtual_ent_t))))
713
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "unable to allocate heap block");
714
0
        }
715
0
        else {
716
            /* Avoid zero-size allocation */
717
0
            layout->storage.u.virt.list = NULL;
718
0
        }
719
720
0
        layout->storage.u.virt.list_nalloc = (size_t)tmp_hsize;
721
0
        layout->storage.u.virt.list_nused  = (size_t)tmp_hsize;
722
723
        /* Decode each entry */
724
0
        for (size_t i = 0; i < layout->storage.u.virt.list_nused; i++) {
725
0
            H5O_storage_virtual_ent_t *ent = &layout->storage.u.virt.list[i]; /* Convenience pointer */
726
0
            ptrdiff_t                  avail_buffer_space;
727
0
            uint8_t                    flags = 0;
728
729
0
            avail_buffer_space = heap_block_p_end - heap_block_p + 1;
730
0
            if (avail_buffer_space <= 0)
731
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
732
733
            /* Flags */
734
0
            if (heap_vers >= H5O_LAYOUT_VDS_GH_ENC_VERS_1) {
735
0
                flags = *heap_block_p++;
736
737
0
                if (flags & ~H5O_LAYOUT_ALL_VDS_FLAGS)
738
0
                    HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad flag value for VDS mapping");
739
0
            }
740
741
0
            avail_buffer_space = heap_block_p_end - heap_block_p + 1;
742
743
            /* Source file name */
744
0
            if (flags & H5O_LAYOUT_VDS_SOURCE_SAME_FILE) {
745
                /* Source file in same file as VDS, use "." */
746
0
                if (first_same_file == SIZE_MAX) {
747
                    /* No previous instance of ".", copy "." to entry and record this instance */
748
0
                    if (NULL == (ent->source_file_name = (char *)H5MM_malloc(2)))
749
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL,
750
0
                                    "memory allocation failed for source file string");
751
0
                    ent->source_file_name[0] = '.';
752
0
                    ent->source_file_name[1] = '\0';
753
0
                    ent->source_file_orig    = SIZE_MAX;
754
0
                    first_same_file          = i;
755
756
                    /* Invalidate hash table for use after decoding since it is missing this "."
757
                     */
758
0
                    clear_file_hash_table = true;
759
0
                }
760
0
                else {
761
                    /* Reference previous instance of "." */
762
0
                    assert(first_same_file < i);
763
0
                    ent->source_file_name = layout->storage.u.virt.list[first_same_file].source_file_name;
764
0
                    ent->source_file_orig = first_same_file;
765
0
                }
766
0
            }
767
0
            else {
768
0
                if (flags & H5O_LAYOUT_VDS_SOURCE_FILE_SHARED) {
769
0
                    if (avail_buffer_space < H5F_SIZEOF_SIZE(f))
770
0
                        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL,
771
0
                                    "ran off end of input buffer while decoding");
772
773
                    /* Source file is shared (stored in another entry), decode origin entry number
774
                     */
775
0
                    H5F_DECODE_LENGTH(f, heap_block_p, tmp_hsize);
776
0
                    H5_CHECK_OVERFLOW(tmp_hsize, hsize_t, size_t);
777
0
                    if ((size_t)tmp_hsize >= i)
778
0
                        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL,
779
0
                                    "origin source file entry has higher index than current entry");
780
0
                    ent->source_file_orig = (size_t)tmp_hsize;
781
782
                    /* Use source file name from origin entry */
783
0
                    ent->source_file_name = layout->storage.u.virt.list[tmp_hsize].source_file_name;
784
0
                }
785
0
                else {
786
0
                    tmp_size = strnlen((const char *)heap_block_p, (size_t)avail_buffer_space);
787
0
                    if (tmp_size == (size_t)avail_buffer_space)
788
0
                        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL,
789
0
                                    "ran off end of input buffer while decoding - unterminated source file "
790
0
                                    "name string");
791
0
                    else
792
0
                        tmp_size += 1; /* Add space for NUL terminator */
793
794
                    /* Check for source dataset name in hash table and add it if not found */
795
0
                    H5D_VIRTUAL_FIND_OR_ADD_NAME(file, layout, heap_block_p, tmp_size - 1, ent, FAIL);
796
797
                    /* Advance pointer */
798
0
                    heap_block_p += tmp_size;
799
0
                }
800
0
            }
801
802
0
            avail_buffer_space = heap_block_p_end - heap_block_p + 1;
803
804
            /* Source dataset name */
805
0
            if (flags & H5O_LAYOUT_VDS_SOURCE_DSET_SHARED) {
806
0
                if (avail_buffer_space < H5F_SIZEOF_SIZE(f))
807
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
808
809
                /* Source dataset is shared (stored in another entry), decode origin entry number
810
                 */
811
0
                H5F_DECODE_LENGTH(f, heap_block_p, tmp_hsize);
812
0
                H5_CHECK_OVERFLOW(tmp_hsize, hsize_t, size_t);
813
0
                if ((size_t)tmp_hsize >= i)
814
0
                    HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL,
815
0
                                "origin source dataset entry has higher index than current entry");
816
0
                ent->source_dset_orig = (size_t)tmp_hsize;
817
818
                /* Use source dataset name from origin entry */
819
0
                ent->source_dset_name = layout->storage.u.virt.list[tmp_hsize].source_dset_name;
820
0
            }
821
0
            else {
822
0
                tmp_size = strnlen((const char *)heap_block_p, (size_t)avail_buffer_space);
823
0
                if (tmp_size == (size_t)avail_buffer_space)
824
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL,
825
0
                                "ran off end of input buffer while decoding - unterminated source dataset "
826
0
                                "name string");
827
0
                else
828
0
                    tmp_size += 1; /* Add space for NUL terminator */
829
830
                /* Check for source dataset name in hash table and add it if not found */
831
0
                H5D_VIRTUAL_FIND_OR_ADD_NAME(dset, layout, heap_block_p, tmp_size - 1, ent, FAIL);
832
833
                /* Advance pointer */
834
0
                heap_block_p += tmp_size;
835
0
            }
836
837
            /* Source selection */
838
0
            avail_buffer_space = heap_block_p_end - heap_block_p + 1;
839
840
0
            if (avail_buffer_space <= 0)
841
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding layout");
842
843
0
            if (H5S_SELECT_DESERIALIZE(&ent->source_select, &heap_block_p, (size_t)(avail_buffer_space)) < 0)
844
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't decode source space selection");
845
846
            /* Virtual selection */
847
848
            /* Buffer space must be updated after previous deserialization */
849
0
            avail_buffer_space = heap_block_p_end - heap_block_p + 1;
850
851
0
            if (avail_buffer_space <= 0)
852
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding layout");
853
854
0
            if (H5S_SELECT_DESERIALIZE(&ent->source_dset.virtual_select, &heap_block_p,
855
0
                                       (size_t)(avail_buffer_space)) < 0)
856
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't decode virtual space selection");
857
858
            /* Parse source file and dataset names for "printf"
859
             * style format specifiers */
860
0
            if (H5D_virtual_parse_source_name(ent->source_file_name, &ent->parsed_source_file_name,
861
0
                                              &ent->psfn_static_strlen, &ent->psfn_nsubs) < 0)
862
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "can't parse source file name");
863
0
            if (H5D_virtual_parse_source_name(ent->source_dset_name, &ent->parsed_source_dset_name,
864
0
                                              &ent->psdn_static_strlen, &ent->psdn_nsubs) < 0)
865
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "can't parse source dataset name");
866
867
            /* Set source names in source_dset struct */
868
0
            if ((ent->psfn_nsubs == 0) && (ent->psdn_nsubs == 0)) {
869
0
                if (ent->parsed_source_file_name)
870
0
                    ent->source_dset.file_name = ent->parsed_source_file_name->name_segment;
871
0
                else
872
0
                    ent->source_dset.file_name = ent->source_file_name;
873
0
                if (ent->parsed_source_dset_name)
874
0
                    ent->source_dset.dset_name = ent->parsed_source_dset_name->name_segment;
875
0
                else
876
0
                    ent->source_dset.dset_name = ent->source_dset_name;
877
0
            }
878
879
            /* Unlim_dim fields */
880
0
            ent->unlim_dim_source     = H5S_get_select_unlim_dim(ent->source_select);
881
0
            ent->unlim_dim_virtual    = H5S_get_select_unlim_dim(ent->source_dset.virtual_select);
882
0
            ent->unlim_extent_source  = HSIZE_UNDEF;
883
0
            ent->unlim_extent_virtual = HSIZE_UNDEF;
884
0
            ent->clip_size_source     = HSIZE_UNDEF;
885
0
            ent->clip_size_virtual    = HSIZE_UNDEF;
886
887
            /* Clipped selections */
888
0
            if (ent->unlim_dim_virtual < 0) {
889
0
                ent->source_dset.clipped_source_select  = ent->source_select;
890
0
                ent->source_dset.clipped_virtual_select = ent->source_dset.virtual_select;
891
0
            }
892
893
            /* Check mapping for validity (do both pre and post
894
             * checks here, since we had to allocate the entry list
895
             * before decoding the selections anyways) */
896
0
            if (H5D_virtual_check_mapping_pre(ent->source_dset.virtual_select, ent->source_select,
897
0
                                              H5O_VIRTUAL_STATUS_INVALID) < 0)
898
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "invalid mapping selections");
899
0
            if (H5D_virtual_check_mapping_post(ent) < 0)
900
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid mapping entry");
901
902
            /* Update min_dims */
903
0
            if (H5D_virtual_update_min_dims(layout, i) < 0)
904
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL,
905
0
                            "unable to update virtual dataset minimum dimensions");
906
0
        }
907
908
        /* Read stored checksum */
909
0
        if (H5_IS_BUFFER_OVERFLOW(heap_block_p, 4, heap_block_p_end))
910
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
911
0
        UINT32DECODE(heap_block_p, stored_chksum);
912
913
        /* Compute checksum */
914
0
        computed_chksum = H5_checksum_metadata(heap_block, block_size - (size_t)4, 0);
915
916
        /* Verify checksum */
917
0
        if (stored_chksum != computed_chksum)
918
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "incorrect metadata checksum for global heap block");
919
920
        /* Verify that the heap block size is correct */
921
0
        if ((size_t)(heap_block_p - heap_block) != block_size)
922
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "incorrect heap block size");
923
924
        /* Clear hash tables if requested */
925
0
        if (clear_file_hash_table)
926
0
            HASH_CLEAR(hh_source_file, layout->storage.u.virt.source_file_hash_table);
927
0
    } /* end if */
928
929
0
done:
930
0
    heap_block = (uint8_t *)H5MM_xfree(heap_block);
931
932
    /* Free mappings on failure */
933
0
    if (ret_value < 0)
934
0
        if (H5D__virtual_free_layout_mappings(&layout->storage.u.virt) < 0)
935
0
            HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release VDS mappings");
936
937
0
    FUNC_LEAVE_NOAPI(ret_value)
938
0
} /* end H5D__virtual_load_layout() */
939
940
/*-------------------------------------------------------------------------
941
 * Function:    H5D__virtual_copy_layout
942
 *
943
 * Purpose:     Deep copies virtual storage layout message in memory.
944
 *              This function assumes that the top-level struct has
945
 *              already been copied (so the source struct retains
946
 *              ownership of the fields passed to this function).
947
 *
948
 * Return:      Non-negative on success/Negative on failure
949
 *
950
 *-------------------------------------------------------------------------
951
 */
952
herr_t
953
H5D__virtual_copy_layout(H5O_layout_t *layout)
954
0
{
955
0
    H5O_storage_virtual_ent_t  *orig_list             = NULL;
956
0
    H5O_storage_virtual_ent_t **orig_not_in_tree_list = NULL;
957
0
    H5O_storage_virtual_t      *virt                  = &layout->storage.u.virt;
958
0
    hid_t                       orig_source_fapl;
959
0
    hid_t                       orig_source_dapl;
960
0
    H5P_genplist_t             *plist;
961
0
    size_t                      i;
962
0
    herr_t                      ret_value = SUCCEED;
963
0
    H5RT_t                     *new_tree  = NULL;
964
965
0
    FUNC_ENTER_PACKAGE
966
967
0
    assert(layout);
968
0
    assert(layout->type == H5D_VIRTUAL);
969
970
    /* Reset hash tables (they are owned by the original list). No need to recreate here - they are only
971
     * needed when adding mappings, and if we add a new mapping the code in H5Pset_virtual() will rebuild
972
     * them). */
973
0
    virt->source_file_hash_table = NULL;
974
0
    virt->source_dset_hash_table = NULL;
975
976
    /* Save original entry list and top-level property lists and reset in layout
977
     * so the originals aren't closed on error */
978
0
    orig_source_fapl       = virt->source_fapl;
979
0
    virt->source_fapl      = -1;
980
0
    orig_source_dapl       = virt->source_dapl;
981
0
    virt->source_dapl      = -1;
982
0
    orig_list              = virt->list;
983
0
    virt->list             = NULL;
984
0
    orig_not_in_tree_list  = virt->not_in_tree_list;
985
0
    virt->not_in_tree_list = NULL;
986
987
    /* Copy entry list */
988
0
    if (virt->list_nused > 0) {
989
0
        assert(orig_list);
990
991
        /* Allocate memory for the list */
992
0
        if (NULL == (virt->list = H5MM_calloc(virt->list_nused * sizeof(virt->list[0]))))
993
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
994
0
                        "unable to allocate memory for virtual dataset entry list");
995
0
        virt->list_nalloc = virt->list_nused;
996
997
        /* Copy the list entries, though set source_dset.dset and sub_dset to
998
         * NULL */
999
0
        for (i = 0; i < virt->list_nused; i++) {
1000
0
            H5O_storage_virtual_ent_t *ent = &virt->list[i];
1001
1002
            /* Copy virtual selection */
1003
0
            if (NULL == (ent->source_dset.virtual_select =
1004
0
                             H5S_copy(orig_list[i].source_dset.virtual_select, false, true)))
1005
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection");
1006
1007
            /* Copy source file name.  If the original is shared, share it in the copy too. */
1008
0
            ent->source_file_orig = orig_list[i].source_file_orig;
1009
0
            if (ent->source_file_orig == SIZE_MAX) {
1010
                /* Source file name is not shared, simply strdup to new ent */
1011
0
                if (NULL == (ent->source_file_name = H5MM_strdup(orig_list[i].source_file_name)))
1012
0
                    HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source file name");
1013
0
            }
1014
0
            else
1015
                /* Source file name is shared, link to correct index in new list */
1016
0
                ent->source_file_name = virt->list[ent->source_file_orig].source_file_name;
1017
1018
            /* Copy source dataset name.  If the original is shared, share it in the copy too. */
1019
0
            ent->source_dset_orig = orig_list[i].source_dset_orig;
1020
0
            if (ent->source_dset_orig == SIZE_MAX) {
1021
0
                if (NULL == (ent->source_dset_name = H5MM_strdup(orig_list[i].source_dset_name)))
1022
0
                    HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source dataset name");
1023
0
            }
1024
0
            else
1025
                /* Source dataset name is shared, link to correct index in new list */
1026
0
                ent->source_dset_name = virt->list[ent->source_dset_orig].source_dset_name;
1027
1028
            /* Copy source selection */
1029
0
            if (NULL == (ent->source_select = H5S_copy(orig_list[i].source_select, false, true)))
1030
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection");
1031
1032
            /* Initialize clipped selections */
1033
0
            if (orig_list[i].unlim_dim_virtual < 0) {
1034
0
                ent->source_dset.clipped_source_select  = ent->source_select;
1035
0
                ent->source_dset.clipped_virtual_select = ent->source_dset.virtual_select;
1036
0
            } /* end if */
1037
1038
            /* Copy parsed names */
1039
0
            if (H5D__virtual_copy_parsed_name(&ent->parsed_source_file_name,
1040
0
                                              orig_list[i].parsed_source_file_name) < 0)
1041
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy parsed source file name");
1042
0
            ent->psfn_static_strlen = orig_list[i].psfn_static_strlen;
1043
0
            ent->psfn_nsubs         = orig_list[i].psfn_nsubs;
1044
0
            if (H5D__virtual_copy_parsed_name(&ent->parsed_source_dset_name,
1045
0
                                              orig_list[i].parsed_source_dset_name) < 0)
1046
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy parsed source dataset name");
1047
0
            ent->psdn_static_strlen = orig_list[i].psdn_static_strlen;
1048
0
            ent->psdn_nsubs         = orig_list[i].psdn_nsubs;
1049
1050
            /* Copy source names in source dset or add reference as appropriate
1051
             */
1052
0
            if (orig_list[i].source_dset.file_name) {
1053
0
                if (orig_list[i].source_dset.file_name == orig_list[i].source_file_name)
1054
0
                    ent->source_dset.file_name = ent->source_file_name;
1055
0
                else if (orig_list[i].parsed_source_file_name &&
1056
0
                         (orig_list[i].source_dset.file_name !=
1057
0
                          orig_list[i].parsed_source_file_name->name_segment)) {
1058
0
                    assert(ent->parsed_source_file_name);
1059
0
                    assert(ent->parsed_source_file_name->name_segment);
1060
0
                    ent->source_dset.file_name = ent->parsed_source_file_name->name_segment;
1061
0
                } /* end if */
1062
0
                else if (NULL ==
1063
0
                         (ent->source_dset.file_name = H5MM_strdup(orig_list[i].source_dset.file_name)))
1064
0
                    HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source file name");
1065
0
            } /* end if */
1066
0
            if (orig_list[i].source_dset.dset_name) {
1067
0
                if (orig_list[i].source_dset.dset_name == orig_list[i].source_dset_name)
1068
0
                    ent->source_dset.dset_name = ent->source_dset_name;
1069
0
                else if (orig_list[i].parsed_source_dset_name &&
1070
0
                         (orig_list[i].source_dset.dset_name !=
1071
0
                          orig_list[i].parsed_source_dset_name->name_segment)) {
1072
0
                    assert(ent->parsed_source_dset_name);
1073
0
                    assert(ent->parsed_source_dset_name->name_segment);
1074
0
                    ent->source_dset.dset_name = ent->parsed_source_dset_name->name_segment;
1075
0
                } /* end if */
1076
0
                else if (NULL ==
1077
0
                         (ent->source_dset.dset_name = H5MM_strdup(orig_list[i].source_dset.dset_name)))
1078
0
                    HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source dataset name");
1079
0
            } /* end if */
1080
1081
            /* Copy other fields in entry */
1082
0
            ent->unlim_dim_source     = orig_list[i].unlim_dim_source;
1083
0
            ent->unlim_dim_virtual    = orig_list[i].unlim_dim_virtual;
1084
0
            ent->unlim_extent_source  = orig_list[i].unlim_extent_source;
1085
0
            ent->unlim_extent_virtual = orig_list[i].unlim_extent_virtual;
1086
0
            ent->clip_size_source     = orig_list[i].clip_size_source;
1087
0
            ent->clip_size_virtual    = orig_list[i].clip_size_virtual;
1088
0
            ent->source_space_status  = orig_list[i].source_space_status;
1089
0
            ent->virtual_space_status = orig_list[i].virtual_space_status;
1090
0
        } /* end for */
1091
0
    }     /* end if */
1092
0
    else {
1093
        /* Zero out other fields related to list, just to be sure */
1094
0
        virt->list        = NULL;
1095
0
        virt->list_nalloc = 0;
1096
0
    } /* end else */
1097
1098
    /* Copy spatial tree if it exists */
1099
0
    if (virt->tree) {
1100
0
        if ((new_tree = H5RT_copy(virt->tree)) == NULL)
1101
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy spatial tree");
1102
0
        virt->tree = new_tree;
1103
1104
        /* Copy not_in_tree_list (pointer array) */
1105
0
        if (virt->not_in_tree_nused > 0) {
1106
0
            assert(orig_not_in_tree_list);
1107
1108
            /* Allocate new pointer array */
1109
0
            if ((virt->not_in_tree_list = (H5O_storage_virtual_ent_t **)H5MM_calloc(
1110
0
                     virt->not_in_tree_nused * sizeof(H5O_storage_virtual_ent_t *))) == NULL)
1111
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
1112
0
                            "unable to allocate not_in_tree_list pointer array");
1113
1114
0
            virt->not_in_tree_nalloc = virt->not_in_tree_nused;
1115
1116
            /* Point to corresponding entries in the new list */
1117
0
            for (i = 0; i < virt->not_in_tree_nused; i++) {
1118
0
                ptrdiff_t offset = orig_not_in_tree_list[i] - orig_list;  /* Calculate original offset */
1119
0
                assert(offset >= 0 && (size_t)offset < virt->list_nused); /* Validate offset */
1120
0
                virt->not_in_tree_list[i] = &virt->list[offset];          /* Point to new list entry */
1121
0
            }
1122
0
        }
1123
0
    }
1124
0
    else {
1125
0
        virt->tree               = NULL;
1126
0
        virt->not_in_tree_list   = NULL;
1127
0
        virt->not_in_tree_nused  = 0;
1128
0
        virt->not_in_tree_nalloc = 0;
1129
0
    }
1130
1131
    /* Copy property lists */
1132
0
    if (orig_source_fapl >= 0) {
1133
0
        if (NULL == (plist = (H5P_genplist_t *)H5I_object_verify(orig_source_fapl, H5I_GENPROP_LST)))
1134
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
1135
0
        if ((virt->source_fapl = H5P_copy_plist(plist, false)) < 0)
1136
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy fapl");
1137
0
    } /* end if */
1138
0
    if (orig_source_dapl >= 0) {
1139
0
        if (NULL == (plist = (H5P_genplist_t *)H5I_object_verify(orig_source_dapl, H5I_GENPROP_LST)))
1140
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
1141
0
        if ((virt->source_dapl = H5P_copy_plist(plist, false)) < 0)
1142
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dapl");
1143
0
    } /* end if */
1144
1145
    /* New layout is not fully initialized */
1146
0
    virt->init = false;
1147
1148
0
done:
1149
    /* Release allocated resources on failure */
1150
0
    if (ret_value < 0)
1151
0
        if (H5D__virtual_reset_layout(layout) < 0)
1152
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset virtual layout");
1153
1154
0
    FUNC_LEAVE_NOAPI(ret_value)
1155
0
} /* end H5D__virtual_copy_layout() */
1156
1157
/*-------------------------------------------------------------------------
1158
 * Function:    H5D__virtual_free_layout_mappings
1159
 *
1160
 * Purpose:     Frees internal structures in a virtual storage layout
1161
 *              message associated with the list of mappings.  This
1162
 *              function is safe to use on incomplete structures (for
1163
 *              recovery from failure) provided the internal structures
1164
 *              are initialized with all bytes set to 0.
1165
 *
1166
 * Return:      Non-negative on success/Negative on failure
1167
 *
1168
 *-------------------------------------------------------------------------
1169
 */
1170
static herr_t
1171
H5D__virtual_free_layout_mappings(H5O_storage_virtual_t *virt)
1172
0
{
1173
0
    size_t i, j;
1174
0
    herr_t ret_value = SUCCEED;
1175
1176
0
    FUNC_ENTER_PACKAGE
1177
1178
0
    assert(virt);
1179
1180
    /* Clear hash tables */
1181
0
    HASH_CLEAR(hh_source_file, virt->source_file_hash_table);
1182
0
    HASH_CLEAR(hh_source_dset, virt->source_dset_hash_table);
1183
1184
    /* Free the list entries.  Note we always attempt to free everything even in
1185
     * the case of a failure.  Because of this, and because we free the list
1186
     * afterwards, we do not need to zero out the memory in the list. */
1187
0
    for (i = 0; i < virt->list_nused; i++) {
1188
0
        H5O_storage_virtual_ent_t *ent = &virt->list[i];
1189
        /* Free source_dset */
1190
0
        if (H5D__virtual_reset_source_dset(ent, &ent->source_dset) < 0)
1191
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset source dataset");
1192
1193
        /* Free original source names */
1194
0
        if (ent->source_file_orig == SIZE_MAX)
1195
0
            (void)H5MM_xfree(ent->source_file_name);
1196
0
        if (ent->source_dset_orig == SIZE_MAX)
1197
0
            (void)H5MM_xfree(ent->source_dset_name);
1198
1199
        /* Free sub_dset */
1200
0
        for (j = 0; j < ent->sub_dset_nalloc; j++)
1201
0
            if (H5D__virtual_reset_source_dset(ent, &ent->sub_dset[j]) < 0)
1202
0
                HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset source dataset");
1203
0
        ent->sub_dset = H5MM_xfree(ent->sub_dset);
1204
1205
        /* Free source_select */
1206
0
        if (ent->source_select)
1207
0
            if (H5S_close(ent->source_select) < 0)
1208
0
                HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release source selection");
1209
1210
        /* Free parsed_source_file_name */
1211
0
        H5D_virtual_free_parsed_name(ent->parsed_source_file_name);
1212
1213
        /* Free parsed_source_dset_name */
1214
0
        H5D_virtual_free_parsed_name(ent->parsed_source_dset_name);
1215
0
    }
1216
1217
    /* Free the list */
1218
0
    virt->list        = H5MM_xfree(virt->list);
1219
0
    virt->list_nalloc = (size_t)0;
1220
0
    virt->list_nused  = (size_t)0;
1221
0
    (void)memset(virt->min_dims, 0, sizeof(virt->min_dims));
1222
1223
    /* Destroy the spatial tree, if it exists */
1224
0
    if (virt->tree) {
1225
0
        if (H5RT_free(virt->tree) < 0) {
1226
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to destroy spatial tree");
1227
0
        }
1228
0
        virt->tree = NULL;
1229
0
    }
1230
1231
    /* Destroy the pointer array tracking which mappings are not in spatial tree */
1232
0
    if (virt->not_in_tree_list) {
1233
        /* Only free the pointer array itself - the entries are owned by the main list */
1234
0
        virt->not_in_tree_list   = H5MM_xfree(virt->not_in_tree_list);
1235
0
        virt->not_in_tree_nused  = 0;
1236
0
        virt->not_in_tree_nalloc = 0;
1237
0
    }
1238
1239
    /* Note the lack of a done: label.  This is because there are no HGOTO_ERROR
1240
     * calls.  If one is added, a done: label must also be added */
1241
0
    FUNC_LEAVE_NOAPI(ret_value)
1242
0
} /* end H5D__virtual_free_layout_mappings() */
1243
1244
/*-------------------------------------------------------------------------
1245
 * Function:    H5D__virtual_reset_layout
1246
 *
1247
 * Purpose:     Frees internal structures in a virtual storage layout
1248
 *              message in memory.  This function is safe to use on
1249
 *              incomplete structures (for recovery from failure) provided
1250
 *              the internal structures are initialized with all bytes set
1251
 *              to 0.
1252
 *
1253
 * Return:      Non-negative on success/Negative on failure
1254
 *
1255
 *-------------------------------------------------------------------------
1256
 */
1257
herr_t
1258
H5D__virtual_reset_layout(H5O_layout_t *layout)
1259
0
{
1260
0
    H5O_storage_virtual_t *virt      = &layout->storage.u.virt;
1261
0
    herr_t                 ret_value = SUCCEED;
1262
1263
0
    FUNC_ENTER_PACKAGE
1264
1265
0
    assert(layout);
1266
0
    assert(layout->type == H5D_VIRTUAL);
1267
1268
    /* Free the list entries and associated data (the hash tables, which point into the list entries) */
1269
0
    if (H5D__virtual_free_layout_mappings(virt) < 0)
1270
0
        HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release VDS mappings");
1271
1272
    /* Close access property lists */
1273
0
    if (virt->source_fapl >= 0) {
1274
0
        if (H5I_dec_ref(virt->source_fapl) < 0)
1275
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close source fapl");
1276
0
        virt->source_fapl = -1;
1277
0
    }
1278
0
    if (virt->source_dapl >= 0) {
1279
0
        if (H5I_dec_ref(virt->source_dapl) < 0)
1280
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close source dapl");
1281
0
        virt->source_dapl = -1;
1282
0
    }
1283
1284
    /* The list is no longer initialized */
1285
0
    virt->init = false;
1286
1287
    /* Note the lack of a done: label.  This is because there are no HGOTO_ERROR
1288
     * calls.  If one is added, a done: label must also be added */
1289
0
    FUNC_LEAVE_NOAPI(ret_value)
1290
0
} /* end H5D__virtual_reset_layout() */
1291
1292
/*-------------------------------------------------------------------------
1293
 * Function:    H5D__virtual_copy
1294
 *
1295
 * Purpose:     Copy virtual storage raw data from SRC file to DST file.
1296
 *
1297
 * Return:      Non-negative on success/Negative on failure
1298
 *
1299
 *-------------------------------------------------------------------------
1300
 */
1301
herr_t
1302
H5D__virtual_copy(H5F_t *f_dst, H5O_layout_t *layout_dst)
1303
0
{
1304
0
    herr_t ret_value = SUCCEED;
1305
1306
0
    FUNC_ENTER_PACKAGE
1307
1308
#ifdef NOT_YET
1309
    /* Check for copy to the same file */
1310
    if (f_dst == f_src) {
1311
        /* Increase reference count on global heap object */
1312
        if ((heap_rc = H5HG_link(f_dst, (H5HG_t *)&(layout_dst->u.virt.serial_list_hobjid), 1)) < 0)
1313
            HGOTO_ERROR(H5E_DATASET, H5E_CANTMODIFY, FAIL, "unable to adjust global heap reference count");
1314
    } /* end if */
1315
    else
1316
#endif /* NOT_YET */
1317
0
    {
1318
        /* Reset global heap id */
1319
0
        layout_dst->storage.u.virt.serial_list_hobjid.addr = HADDR_UNDEF;
1320
0
        layout_dst->storage.u.virt.serial_list_hobjid.idx  = (size_t)0;
1321
1322
        /* Write the VDS data to destination file's heap */
1323
0
        if (H5D__virtual_store_layout(f_dst, layout_dst) < 0)
1324
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to store VDS info");
1325
0
    } /* end block/else */
1326
1327
0
done:
1328
0
    FUNC_LEAVE_NOAPI(ret_value)
1329
0
} /* end H5D__virtual_copy() */
1330
1331
/*-------------------------------------------------------------------------
1332
 * Function:    H5D__virtual_delete
1333
 *
1334
 * Purpose:     Delete the file space for a virtual dataset
1335
 *
1336
 * Return:      Non-negative on success/Negative on failure
1337
 *
1338
 *-------------------------------------------------------------------------
1339
 */
1340
herr_t
1341
H5D__virtual_delete(H5F_t *f, H5O_storage_t *storage)
1342
0
{
1343
#ifdef NOT_YET
1344
    int heap_rc;                /* Reference count of global heap object */
1345
#endif                          /* NOT_YET */
1346
0
    herr_t ret_value = SUCCEED; /* Return value */
1347
1348
0
    FUNC_ENTER_PACKAGE
1349
1350
    /* check args */
1351
0
    assert(f);
1352
0
    assert(storage);
1353
0
    assert(storage->type == H5D_VIRTUAL);
1354
1355
    /* Check for global heap block */
1356
0
    if (storage->u.virt.serial_list_hobjid.addr != HADDR_UNDEF) {
1357
#ifdef NOT_YET
1358
        /* Unlink the global heap block */
1359
        if ((heap_rc = H5HG_link(f, (H5HG_t *)&(storage->u.virt.serial_list_hobjid), -1)) < 0)
1360
            HGOTO_ERROR(H5E_DATASET, H5E_CANTMODIFY, FAIL, "unable to adjust global heap reference count");
1361
        if (heap_rc == 0)
1362
#endif /* NOT_YET */
1363
            /* Delete the global heap block */
1364
0
            if (H5HG_remove(f, (H5HG_t *)&(storage->u.virt.serial_list_hobjid)) < 0)
1365
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to remove heap object");
1366
0
    } /* end if */
1367
1368
    /* Clear global heap ID in storage */
1369
0
    storage->u.virt.serial_list_hobjid.addr = HADDR_UNDEF;
1370
0
    storage->u.virt.serial_list_hobjid.idx  = 0;
1371
1372
0
done:
1373
0
    FUNC_LEAVE_NOAPI(ret_value)
1374
0
} /* end H5D__virtual_delete */
1375
1376
/*-------------------------------------------------------------------------
1377
 * Function:    H5D__virtual_open_source_dset
1378
 *
1379
 * Purpose:     Attempts to open a source dataset.
1380
 *
1381
 * Return:      Non-negative on success/Negative on failure
1382
 *
1383
 *-------------------------------------------------------------------------
1384
 */
1385
static herr_t
1386
H5D__virtual_open_source_dset(const H5D_t *vdset, H5O_storage_virtual_ent_t *virtual_ent,
1387
                              H5O_storage_virtual_srcdset_t *source_dset)
1388
0
{
1389
0
    H5F_t *src_file      = NULL;    /* Source file */
1390
0
    bool   src_file_open = false;   /* Whether we have opened and need to close src_file */
1391
0
    herr_t ret_value     = SUCCEED; /* Return value */
1392
1393
0
    FUNC_ENTER_PACKAGE
1394
1395
    /* Sanity check */
1396
0
    assert(vdset);
1397
0
    assert(source_dset);
1398
0
    assert(!source_dset->dset);
1399
0
    assert(source_dset->file_name);
1400
0
    assert(source_dset->dset_name);
1401
1402
    /* Check if we need to open the source file */
1403
0
    if (strcmp(source_dset->file_name, ".") != 0) {
1404
0
        unsigned intent; /* File access permissions */
1405
1406
        /* Get the virtual dataset's file open flags ("intent") */
1407
0
        intent = H5F_INTENT(vdset->oloc.file);
1408
1409
        /* Try opening the file */
1410
0
        if (H5F_prefix_open_file(true, &src_file, vdset->oloc.file, H5F_PREFIX_VDS, vdset->shared->vds_prefix,
1411
0
                                 source_dset->file_name, intent,
1412
0
                                 vdset->shared->layout.storage.u.virt.source_fapl) < 0)
1413
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENFILE, FAIL, "can't try opening file");
1414
1415
        /* If we opened the source file here, we should close it when leaving */
1416
0
        if (src_file)
1417
0
            src_file_open = true;
1418
0
    } /* end if */
1419
0
    else
1420
        /* Source file is ".", use the virtual dataset's file */
1421
0
        src_file = vdset->oloc.file;
1422
1423
0
    if (src_file) {
1424
0
        H5G_loc_t src_root_loc; /* Object location of source file root group */
1425
0
        bool      exists = false;
1426
1427
        /* Set up the root group in the destination file */
1428
0
        if (NULL == (src_root_loc.oloc = H5G_oloc(H5G_rootof(src_file))))
1429
0
            HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to get object location for root group");
1430
0
        if (NULL == (src_root_loc.path = H5G_nameof(H5G_rootof(src_file))))
1431
0
            HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to get path for root group");
1432
1433
        /* Check if the source dataset exists */
1434
0
        if (H5G_loc_exists(&src_root_loc, source_dset->dset_name, &exists /*out*/) < 0)
1435
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTFIND, FAIL, "can't check object's existence");
1436
1437
        /* Dataset exists */
1438
0
        if (exists) {
1439
            /* Try opening the source dataset */
1440
0
            if (NULL ==
1441
0
                (source_dset->dset = H5D__open_name(&src_root_loc, source_dset->dset_name,
1442
0
                                                    vdset->shared->layout.storage.u.virt.source_dapl)))
1443
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset");
1444
1445
            /* Dataset exists */
1446
0
            source_dset->dset_exists = true;
1447
1448
            /* Patch the source selection if necessary */
1449
0
            if (virtual_ent->source_space_status != H5O_VIRTUAL_STATUS_CORRECT) {
1450
0
                if (H5S_extent_copy(virtual_ent->source_select, source_dset->dset->shared->space) < 0)
1451
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent");
1452
0
                virtual_ent->source_space_status = H5O_VIRTUAL_STATUS_CORRECT;
1453
0
            } /* end if */
1454
0
        }     /* end else */
1455
0
        else
1456
            /* Dataset does not exist */
1457
0
            source_dset->dset_exists = false;
1458
0
    } /* end if */
1459
1460
0
done:
1461
    /* Release resources */
1462
0
    if (src_file_open)
1463
0
        if (H5F_efc_close(vdset->oloc.file, src_file) < 0)
1464
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "can't close source file");
1465
1466
0
    FUNC_LEAVE_NOAPI(ret_value)
1467
0
} /* end H5D__virtual_open_source_dset() */
1468
1469
/*-------------------------------------------------------------------------
1470
 * Function:    H5D__virtual_reset_source_dset
1471
 *
1472
 * Purpose:     Frees space referenced by a source dataset struct.
1473
 *
1474
 * Return:      Non-negative on success/Negative on failure
1475
 *
1476
 *-------------------------------------------------------------------------
1477
 */
1478
static herr_t
1479
H5D__virtual_reset_source_dset(H5O_storage_virtual_ent_t     *virtual_ent,
1480
                               H5O_storage_virtual_srcdset_t *source_dset)
1481
0
{
1482
0
    herr_t ret_value = SUCCEED; /* Return value */
1483
1484
0
    FUNC_ENTER_PACKAGE
1485
1486
    /* Sanity check */
1487
0
    assert(source_dset);
1488
1489
    /* Free dataset */
1490
0
    if (source_dset->dset) {
1491
0
        if (H5D_close(source_dset->dset) < 0)
1492
0
            HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to close source dataset");
1493
0
        source_dset->dset = NULL;
1494
0
    } /* end if */
1495
1496
    /* Free file name */
1497
0
    if (virtual_ent->parsed_source_file_name &&
1498
0
        (source_dset->file_name != virtual_ent->parsed_source_file_name->name_segment))
1499
0
        source_dset->file_name = (char *)H5MM_xfree(source_dset->file_name);
1500
0
    else
1501
0
        assert((source_dset->file_name == virtual_ent->source_file_name) ||
1502
0
               (virtual_ent->parsed_source_file_name &&
1503
0
                (source_dset->file_name == virtual_ent->parsed_source_file_name->name_segment)) ||
1504
0
               !source_dset->file_name);
1505
1506
    /* Free dataset name */
1507
0
    if (virtual_ent->parsed_source_dset_name &&
1508
0
        (source_dset->dset_name != virtual_ent->parsed_source_dset_name->name_segment))
1509
0
        source_dset->dset_name = (char *)H5MM_xfree(source_dset->dset_name);
1510
0
    else
1511
0
        assert((source_dset->dset_name == virtual_ent->source_dset_name) ||
1512
0
               (virtual_ent->parsed_source_dset_name &&
1513
0
                (source_dset->dset_name == virtual_ent->parsed_source_dset_name->name_segment)) ||
1514
0
               !source_dset->dset_name);
1515
1516
    /* Free clipped virtual selection */
1517
0
    if (source_dset->clipped_virtual_select) {
1518
0
        if (source_dset->clipped_virtual_select != source_dset->virtual_select)
1519
0
            if (H5S_close(source_dset->clipped_virtual_select) < 0)
1520
0
                HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual selection");
1521
0
        source_dset->clipped_virtual_select = NULL;
1522
0
    } /* end if */
1523
1524
    /* Free virtual selection */
1525
0
    if (source_dset->virtual_select) {
1526
0
        if (H5S_close(source_dset->virtual_select) < 0)
1527
0
            HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release virtual selection");
1528
0
        source_dset->virtual_select = NULL;
1529
0
    } /* end if */
1530
1531
    /* Free clipped source selection */
1532
0
    if (source_dset->clipped_source_select) {
1533
0
        if (source_dset->clipped_source_select != virtual_ent->source_select)
1534
0
            if (H5S_close(source_dset->clipped_source_select) < 0)
1535
0
                HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source selection");
1536
0
        source_dset->clipped_source_select = NULL;
1537
0
    } /* end if */
1538
1539
    /* The projected memory space should never exist when this function is
1540
     * called */
1541
0
    assert(!source_dset->projected_mem_space);
1542
1543
    /* Note the lack of a done: label.  This is because there are no HGOTO_ERROR
1544
     * calls.  If one is added, a done: label must also be added */
1545
0
    FUNC_LEAVE_NOAPI(ret_value)
1546
0
} /* end H5D__virtual_reset_source_dset() */
1547
1548
/*-------------------------------------------------------------------------
1549
 * Function:    H5D__virtual_str_append
1550
 *
1551
 * Purpose:     Appends src_len bytes of the string src to the position *p
1552
 *              in the buffer *buf (allocating *buf if necessary).
1553
 *
1554
 * Return:      Non-negative on success/Negative on failure
1555
 *
1556
 *-------------------------------------------------------------------------
1557
 */
1558
static herr_t
1559
H5D__virtual_str_append(const char *src, size_t src_len, char **p, char **buf, size_t *buf_size)
1560
0
{
1561
0
    herr_t ret_value = SUCCEED; /* Return value */
1562
1563
0
    FUNC_ENTER_PACKAGE
1564
1565
    /* Sanity check */
1566
0
    assert(src);
1567
0
    assert(src_len > 0);
1568
0
    assert(p);
1569
0
    assert(buf);
1570
0
    assert(*p >= *buf);
1571
0
    assert(buf_size);
1572
1573
    /* Allocate or extend buffer if necessary */
1574
0
    if (!*buf) {
1575
0
        assert(!*p);
1576
0
        assert(*buf_size == 0);
1577
1578
        /* Allocate buffer */
1579
0
        if (NULL == (*buf = (char *)H5MM_malloc(src_len + (size_t)1)))
1580
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct");
1581
0
        *buf_size = src_len + (size_t)1;
1582
0
        *p        = *buf;
1583
0
    } /* end if */
1584
0
    else {
1585
0
        size_t p_offset = (size_t)(*p - *buf); /* Offset of p within buf */
1586
1587
        /* Extend buffer if necessary */
1588
0
        if ((p_offset + src_len + (size_t)1) > *buf_size) {
1589
0
            char  *tmp_buf;
1590
0
            size_t tmp_buf_size;
1591
1592
            /* Calculate new size of buffer */
1593
0
            tmp_buf_size = MAX(p_offset + src_len + (size_t)1, *buf_size * (size_t)2);
1594
1595
            /* Reallocate buffer */
1596
0
            if (NULL == (tmp_buf = (char *)H5MM_realloc(*buf, tmp_buf_size)))
1597
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to reallocate name segment buffer");
1598
0
            *buf      = tmp_buf;
1599
0
            *buf_size = tmp_buf_size;
1600
0
            *p        = *buf + p_offset;
1601
0
        } /* end if */
1602
0
    }     /* end else */
1603
1604
    /* Copy string to *p.  Note that since src in not NULL terminated, we must
1605
     * use memcpy */
1606
0
    H5MM_memcpy(*p, src, src_len);
1607
1608
    /* Advance *p */
1609
0
    *p += src_len;
1610
1611
    /* Add NULL terminator */
1612
0
    **p = '\0';
1613
1614
0
done:
1615
0
    FUNC_LEAVE_NOAPI(ret_value)
1616
0
} /* end H5D__virtual_str_append() */
1617
1618
/*-------------------------------------------------------------------------
1619
 * Function:    H5D_virtual_parse_source_name
1620
 *
1621
 * Purpose:     Parses a source file or dataset name.
1622
 *
1623
 * Return:      Non-negative on success/Negative on failure
1624
 *
1625
 *-------------------------------------------------------------------------
1626
 */
1627
herr_t
1628
H5D_virtual_parse_source_name(const char *source_name, H5O_storage_virtual_name_seg_t **parsed_name,
1629
                              size_t *static_strlen, size_t *nsubs)
1630
0
{
1631
0
    H5O_storage_virtual_name_seg_t  *tmp_parsed_name   = NULL;
1632
0
    H5O_storage_virtual_name_seg_t **tmp_parsed_name_p = &tmp_parsed_name;
1633
0
    size_t                           tmp_static_strlen;
1634
0
    size_t                           tmp_strlen;
1635
0
    size_t                           tmp_nsubs = 0;
1636
0
    const char                      *p;
1637
0
    const char                      *pct;
1638
0
    char                            *name_seg_p    = NULL;
1639
0
    size_t                           name_seg_size = 0;
1640
0
    herr_t                           ret_value     = SUCCEED; /* Return value */
1641
1642
0
    FUNC_ENTER_NOAPI(FAIL)
1643
1644
    /* Sanity check */
1645
0
    assert(source_name);
1646
0
    assert(parsed_name);
1647
0
    assert(static_strlen);
1648
0
    assert(nsubs);
1649
1650
    /* Initialize p and tmp_static_strlen */
1651
0
    p                 = source_name;
1652
0
    tmp_static_strlen = tmp_strlen = strlen(source_name);
1653
1654
    /* Iterate over name */
1655
    /* Note this will not work with UTF-8!  We should support this eventually
1656
     * -NAF 5/18/2015 */
1657
0
    while ((pct = strchr(p, '%'))) {
1658
0
        assert(pct >= p);
1659
1660
        /* Allocate name segment struct if necessary */
1661
0
        if (!*tmp_parsed_name_p)
1662
0
            if (NULL == (*tmp_parsed_name_p = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
1663
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct");
1664
1665
        /* Check for type of format specifier */
1666
0
        if (pct[1] == 'b') {
1667
            /* Check for blank string before specifier */
1668
0
            if (pct != p)
1669
                /* Append string to name segment */
1670
0
                if (H5D__virtual_str_append(p, (size_t)(pct - p), &name_seg_p,
1671
0
                                            &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
1672
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment");
1673
1674
            /* Update other variables */
1675
0
            tmp_parsed_name_p = &(*tmp_parsed_name_p)->next;
1676
0
            tmp_static_strlen -= 2;
1677
0
            tmp_nsubs++;
1678
0
            name_seg_p    = NULL;
1679
0
            name_seg_size = 0;
1680
0
        } /* end if */
1681
0
        else if (pct[1] == '%') {
1682
            /* Append string to name segment (include first '%') */
1683
0
            if (H5D__virtual_str_append(p, (size_t)(pct - p) + (size_t)1, &name_seg_p,
1684
0
                                        &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
1685
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment");
1686
1687
            /* Update other variables */
1688
0
            tmp_static_strlen -= 1;
1689
0
        } /* end else */
1690
0
        else
1691
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid format specifier");
1692
1693
0
        p = pct + 2;
1694
0
    } /* end while */
1695
1696
    /* Copy last segment of name, if any, unless the parsed name was not
1697
     * allocated */
1698
0
    if (tmp_parsed_name) {
1699
0
        assert(p >= source_name);
1700
0
        if (*p == '\0')
1701
0
            assert((size_t)(p - source_name) == tmp_strlen);
1702
0
        else {
1703
0
            assert((size_t)(p - source_name) < tmp_strlen);
1704
1705
            /* Allocate name segment struct if necessary */
1706
0
            if (!*tmp_parsed_name_p)
1707
0
                if (NULL == (*tmp_parsed_name_p = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
1708
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct");
1709
1710
            /* Append string to name segment */
1711
0
            if (H5D__virtual_str_append(p, tmp_strlen - (size_t)(p - source_name), &name_seg_p,
1712
0
                                        &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
1713
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment");
1714
0
        } /* end else */
1715
0
    }     /* end if */
1716
1717
    /* Set return values */
1718
0
    *parsed_name    = tmp_parsed_name;
1719
0
    tmp_parsed_name = NULL;
1720
0
    *static_strlen  = tmp_static_strlen;
1721
0
    *nsubs          = tmp_nsubs;
1722
1723
0
done:
1724
0
    if (tmp_parsed_name) {
1725
0
        assert(ret_value < 0);
1726
0
        H5D_virtual_free_parsed_name(tmp_parsed_name);
1727
0
    } /* end if */
1728
1729
0
    FUNC_LEAVE_NOAPI(ret_value)
1730
0
} /* end H5D_virtual_parse_source_name() */
1731
1732
/*-------------------------------------------------------------------------
1733
 * Function:    H5D__virtual_copy_parsed_name
1734
 *
1735
 * Purpose:     Deep copies a parsed source file or dataset name.
1736
 *
1737
 * Return:      Non-negative on success/Negative on failure
1738
 *
1739
 *-------------------------------------------------------------------------
1740
 */
1741
static herr_t
1742
H5D__virtual_copy_parsed_name(H5O_storage_virtual_name_seg_t **dst, H5O_storage_virtual_name_seg_t *src)
1743
0
{
1744
0
    H5O_storage_virtual_name_seg_t  *tmp_dst   = NULL;
1745
0
    H5O_storage_virtual_name_seg_t  *p_src     = src;
1746
0
    H5O_storage_virtual_name_seg_t **p_dst     = &tmp_dst;
1747
0
    herr_t                           ret_value = SUCCEED;
1748
1749
0
    FUNC_ENTER_PACKAGE
1750
1751
    /* Sanity check */
1752
0
    assert(dst);
1753
1754
    /* Walk over parsed name, duplicating it */
1755
0
    while (p_src) {
1756
        /* Allocate name segment struct */
1757
0
        if (NULL == (*p_dst = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
1758
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct");
1759
1760
        /* Duplicate name segment */
1761
0
        if (p_src->name_segment) {
1762
0
            if (NULL == ((*p_dst)->name_segment = H5MM_strdup(p_src->name_segment)))
1763
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to duplicate name segment");
1764
0
        } /* end if */
1765
1766
        /* Advance pointers */
1767
0
        p_src = p_src->next;
1768
0
        p_dst = &(*p_dst)->next;
1769
0
    } /* end while */
1770
1771
    /* Set dst */
1772
0
    *dst    = tmp_dst;
1773
0
    tmp_dst = NULL;
1774
1775
0
done:
1776
0
    if (tmp_dst) {
1777
0
        assert(ret_value < 0);
1778
0
        H5D_virtual_free_parsed_name(tmp_dst);
1779
0
    } /* end if */
1780
1781
0
    FUNC_LEAVE_NOAPI(ret_value)
1782
0
} /* end H5D__virtual_copy_parsed_name() */
1783
1784
/*-------------------------------------------------------------------------
1785
 * Function:    H5D_virtual_free_parsed_name
1786
 *
1787
 * Purpose:     Frees the provided parsed name.
1788
 *
1789
 * Return:      void
1790
 *
1791
 *-------------------------------------------------------------------------
1792
 */
1793
herr_t
1794
H5D_virtual_free_parsed_name(H5O_storage_virtual_name_seg_t *name_seg)
1795
0
{
1796
0
    H5O_storage_virtual_name_seg_t *next_seg;
1797
0
    herr_t                          ret_value = SUCCEED; /* Return value */
1798
1799
0
    FUNC_ENTER_NOAPI(FAIL)
1800
1801
    /* Walk name segments, freeing them */
1802
0
    while (name_seg) {
1803
0
        (void)H5MM_xfree(name_seg->name_segment);
1804
0
        next_seg = name_seg->next;
1805
0
        (void)H5FL_FREE(H5O_storage_virtual_name_seg_t, name_seg);
1806
0
        name_seg = next_seg;
1807
0
    } /* end while */
1808
1809
0
done:
1810
0
    FUNC_LEAVE_NOAPI(ret_value)
1811
0
} /* end H5D_virtual_free_parsed_name() */
1812
1813
/*-------------------------------------------------------------------------
1814
 * Function:    H5D__virtual_build_source_name
1815
 *
1816
 * Purpose:     Builds a source file or dataset name from a parsed name.
1817
 *
1818
 * Return:      Non-negative on success/Negative on failure
1819
 *
1820
 *-------------------------------------------------------------------------
1821
 */
1822
static herr_t
1823
H5D__virtual_build_source_name(char *source_name, const H5O_storage_virtual_name_seg_t *parsed_name,
1824
                               size_t static_strlen, size_t nsubs, hsize_t blockno, char **built_name)
1825
0
{
1826
0
    char  *tmp_name  = NULL;    /* Name buffer */
1827
0
    herr_t ret_value = SUCCEED; /* Return value */
1828
1829
0
    FUNC_ENTER_PACKAGE
1830
1831
    /* Sanity check */
1832
0
    assert(source_name);
1833
0
    assert(built_name);
1834
1835
    /* Check for static name */
1836
0
    if (nsubs == 0) {
1837
0
        if (parsed_name)
1838
0
            *built_name = parsed_name->name_segment;
1839
0
        else
1840
0
            *built_name = source_name;
1841
0
    } /* end if */
1842
0
    else {
1843
0
        const H5O_storage_virtual_name_seg_t *name_seg = parsed_name;
1844
0
        char                                 *p;
1845
0
        hsize_t                               blockno_down = blockno;
1846
0
        size_t                                blockno_len  = 1;
1847
0
        size_t                                name_len;
1848
0
        size_t                                name_len_rem;
1849
0
        size_t                                seg_len;
1850
0
        size_t                                nsubs_rem = nsubs;
1851
1852
0
        assert(parsed_name);
1853
1854
        /* Calculate length of printed block number */
1855
0
        do {
1856
0
            blockno_down /= (hsize_t)10;
1857
0
            if (blockno_down == 0)
1858
0
                break;
1859
0
            blockno_len++;
1860
0
        } while (1);
1861
1862
        /* Calculate length of name buffer */
1863
0
        name_len_rem = name_len = static_strlen + (nsubs * blockno_len) + (size_t)1;
1864
1865
        /* Allocate name buffer */
1866
0
        if (NULL == (tmp_name = (char *)H5MM_malloc(name_len)))
1867
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name buffer");
1868
0
        p = tmp_name;
1869
1870
        /* Build name */
1871
0
        do {
1872
            /* Add name segment */
1873
0
            if (name_seg->name_segment) {
1874
0
                seg_len = strlen(name_seg->name_segment);
1875
0
                assert(seg_len > 0);
1876
0
                assert(seg_len < name_len_rem);
1877
0
                strncpy(p, name_seg->name_segment, name_len_rem);
1878
0
                name_len_rem -= seg_len;
1879
0
                p += seg_len;
1880
0
            } /* end if */
1881
1882
            /* Add block number */
1883
0
            if (nsubs_rem > 0) {
1884
0
                assert(blockno_len < name_len_rem);
1885
0
                if (snprintf(p, name_len_rem, "%llu", (long long unsigned)blockno) < 0)
1886
0
                    HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write block number to string");
1887
0
                name_len_rem -= blockno_len;
1888
0
                p += blockno_len;
1889
0
                nsubs_rem--;
1890
0
            } /* end if */
1891
1892
            /* Advance name_seg */
1893
0
            name_seg = name_seg->next;
1894
0
        } while (name_seg);
1895
1896
        /* Assign built_name */
1897
0
        *built_name = tmp_name;
1898
0
        tmp_name    = NULL;
1899
0
    } /* end else */
1900
1901
0
done:
1902
0
    if (tmp_name) {
1903
0
        assert(ret_value < 0);
1904
0
        H5MM_free(tmp_name);
1905
0
    } /* end if */
1906
1907
0
    FUNC_LEAVE_NOAPI(ret_value)
1908
0
} /* end H5D__virtual_build_source_name() */
1909
1910
/*-------------------------------------------------------------------------
1911
 * Function:    H5D__virtual_set_extent_unlim
1912
 *
1913
 * Purpose:     Sets the extent of the virtual dataset by checking the
1914
 *              extents of source datasets where an unlimited selection
1915
 *              matching.  Dimensions that are not unlimited in any
1916
 *              virtual mapping selections are not affected.
1917
 *
1918
 * Return:      Non-negative on success/Negative on failure
1919
 *
1920
 *-------------------------------------------------------------------------
1921
 */
1922
herr_t
1923
H5D__virtual_set_extent_unlim(const H5D_t *dset)
1924
0
{
1925
0
    H5O_storage_virtual_t *storage;
1926
0
    hsize_t                new_dims[H5S_MAX_RANK];
1927
0
    hsize_t                curr_dims[H5S_MAX_RANK];
1928
0
    hsize_t                clip_size;
1929
0
    int                    rank;
1930
0
    bool                   changed = false; /* Whether the VDS extent changed */
1931
0
    size_t                 i, j;
1932
0
    herr_t                 ret_value = SUCCEED; /* Return value */
1933
1934
0
    FUNC_ENTER_PACKAGE
1935
1936
    /* Sanity check */
1937
0
    assert(dset);
1938
0
    assert(dset->shared->layout.storage.type == H5D_VIRTUAL);
1939
0
    storage = &dset->shared->layout.storage.u.virt;
1940
0
    assert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
1941
1942
    /* Get rank of VDS */
1943
0
    if ((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0)
1944
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions");
1945
1946
    /* Initialize new_dims to HSIZE_UNDEF */
1947
0
    for (i = 0; i < (size_t)rank; i++)
1948
0
        new_dims[i] = HSIZE_UNDEF;
1949
1950
    /* Iterate over mappings */
1951
0
    for (i = 0; i < storage->list_nused; i++)
1952
        /* Check for unlimited dimension */
1953
0
        if (storage->list[i].unlim_dim_virtual >= 0) {
1954
            /* Check for "printf" source dataset resolution */
1955
0
            if (storage->list[i].unlim_dim_source >= 0) {
1956
                /* Non-printf mapping */
1957
                /* Open source dataset */
1958
0
                if (!storage->list[i].source_dset.dset)
1959
0
                    if (H5D__virtual_open_source_dset(dset, &storage->list[i],
1960
0
                                                      &storage->list[i].source_dset) < 0)
1961
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset");
1962
1963
                /* Check if source dataset is open */
1964
0
                if (storage->list[i].source_dset.dset) {
1965
                    /* Retrieve current source dataset extent and patch mapping
1966
                     */
1967
0
                    if (H5S_extent_copy(storage->list[i].source_select,
1968
0
                                        storage->list[i].source_dset.dset->shared->space) < 0)
1969
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent");
1970
1971
                    /* Get source space dimensions */
1972
0
                    if (H5S_get_simple_extent_dims(storage->list[i].source_select, curr_dims, NULL) < 0)
1973
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get source space dimensions");
1974
1975
                    /* Check if the source extent in the unlimited dimension
1976
                     * changed since the last time the VDS extent/mapping
1977
                     * was updated */
1978
0
                    if (curr_dims[storage->list[i].unlim_dim_source] == storage->list[i].unlim_extent_source)
1979
                        /* Use cached result for clip size */
1980
0
                        clip_size = storage->list[i].clip_size_virtual;
1981
0
                    else {
1982
                        /* Get size that virtual selection would be clipped to
1983
                         * to match size of source selection within source
1984
                         * extent */
1985
0
                        clip_size = H5S_hyper_get_clip_extent_match(
1986
0
                            storage->list[i].source_dset.virtual_select, storage->list[i].source_select,
1987
0
                            curr_dims[storage->list[i].unlim_dim_source],
1988
0
                            storage->view == H5D_VDS_FIRST_MISSING);
1989
1990
                        /* If we are setting the extent by the last available
1991
                         * data, clip virtual_select and source_select.  Note
1992
                         * that if we used the cached clip_size above or it
1993
                         * happens to be the same, the virtual selection will
1994
                         * already be clipped to the correct size.  Likewise,
1995
                         * if we used the cached clip_size the source selection
1996
                         * will already be correct. */
1997
0
                        if (storage->view == H5D_VDS_LAST_AVAILABLE) {
1998
0
                            if (clip_size != storage->list[i].clip_size_virtual) {
1999
                                /* Close previous clipped virtual selection, if
2000
                                 * any */
2001
0
                                if (storage->list[i].source_dset.clipped_virtual_select) {
2002
0
                                    assert(storage->list[i].source_dset.clipped_virtual_select !=
2003
0
                                           storage->list[i].source_dset.virtual_select);
2004
0
                                    if (H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
2005
0
                                        HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2006
0
                                                    "unable to release clipped virtual dataspace");
2007
0
                                } /* end if */
2008
2009
                                /* Copy virtual selection */
2010
0
                                if (NULL == (storage->list[i].source_dset.clipped_virtual_select = H5S_copy(
2011
0
                                                 storage->list[i].source_dset.virtual_select, false, true)))
2012
0
                                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL,
2013
0
                                                "unable to copy virtual selection");
2014
2015
                                /* Clip virtual selection */
2016
0
                                if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select,
2017
0
                                                         clip_size))
2018
0
                                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
2019
0
                                                "failed to clip unlimited selection");
2020
0
                            } /* end if */
2021
2022
                            /* Close previous clipped source selection, if any
2023
                             */
2024
0
                            if (storage->list[i].source_dset.clipped_source_select) {
2025
0
                                assert(storage->list[i].source_dset.clipped_source_select !=
2026
0
                                       storage->list[i].source_select);
2027
0
                                if (H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
2028
0
                                    HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2029
0
                                                "unable to release clipped source dataspace");
2030
0
                            } /* end if */
2031
2032
                            /* Copy source selection */
2033
0
                            if (NULL == (storage->list[i].source_dset.clipped_source_select =
2034
0
                                             H5S_copy(storage->list[i].source_select, false, true)))
2035
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL,
2036
0
                                            "unable to copy source selection");
2037
2038
                            /* Clip source selection */
2039
0
                            if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select,
2040
0
                                                     curr_dims[storage->list[i].unlim_dim_source]))
2041
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
2042
0
                                            "failed to clip unlimited selection");
2043
0
                        } /* end if */
2044
2045
                        /* Update cached values unlim_extent_source and
2046
                         * clip_size_virtual */
2047
0
                        storage->list[i].unlim_extent_source = curr_dims[storage->list[i].unlim_dim_source];
2048
0
                        storage->list[i].clip_size_virtual   = clip_size;
2049
0
                    } /* end else */
2050
0
                }     /* end if */
2051
0
                else
2052
0
                    clip_size = 0;
2053
0
            } /* end if */
2054
0
            else {
2055
                /* printf mapping */
2056
0
                hsize_t first_missing =
2057
0
                    0; /* First missing dataset in the current block of missing datasets */
2058
2059
                /* Search for source datasets */
2060
0
                assert(storage->printf_gap != HSIZE_UNDEF);
2061
0
                for (j = 0; j <= (storage->printf_gap + first_missing); j++) {
2062
                    /* Check for running out of space in sub_dset array */
2063
0
                    if (j >= (hsize_t)storage->list[i].sub_dset_nalloc) {
2064
0
                        if (storage->list[i].sub_dset_nalloc == 0) {
2065
                            /* Allocate sub_dset */
2066
0
                            if (NULL ==
2067
0
                                (storage->list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_calloc(
2068
0
                                     H5D_VIRTUAL_DEF_SUB_DSET_SIZE * sizeof(H5O_storage_virtual_srcdset_t))))
2069
0
                                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
2070
0
                                            "unable to allocate sub dataset array");
2071
0
                            storage->list[i].sub_dset_nalloc = H5D_VIRTUAL_DEF_SUB_DSET_SIZE;
2072
0
                        } /* end if */
2073
0
                        else {
2074
0
                            H5O_storage_virtual_srcdset_t *tmp_sub_dset;
2075
2076
                            /* Extend sub_dset */
2077
0
                            if (NULL ==
2078
0
                                (tmp_sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_realloc(
2079
0
                                     storage->list[i].sub_dset, 2 * storage->list[i].sub_dset_nalloc *
2080
0
                                                                    sizeof(H5O_storage_virtual_srcdset_t))))
2081
0
                                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
2082
0
                                            "unable to extend sub dataset array");
2083
0
                            storage->list[i].sub_dset = tmp_sub_dset;
2084
2085
                            /* Clear new space in sub_dset */
2086
0
                            (void)memset(&storage->list[i].sub_dset[storage->list[i].sub_dset_nalloc], 0,
2087
0
                                         storage->list[i].sub_dset_nalloc *
2088
0
                                             sizeof(H5O_storage_virtual_srcdset_t));
2089
2090
                            /* Update sub_dset_nalloc */
2091
0
                            storage->list[i].sub_dset_nalloc *= 2;
2092
0
                        } /* end else */
2093
0
                    }     /* end if */
2094
2095
                    /* Check if the dataset was already opened */
2096
0
                    if (storage->list[i].sub_dset[j].dset_exists)
2097
0
                        first_missing = j + 1;
2098
0
                    else {
2099
                        /* Resolve file name */
2100
0
                        if (!storage->list[i].sub_dset[j].file_name)
2101
0
                            if (H5D__virtual_build_source_name(storage->list[i].source_file_name,
2102
0
                                                               storage->list[i].parsed_source_file_name,
2103
0
                                                               storage->list[i].psfn_static_strlen,
2104
0
                                                               storage->list[i].psfn_nsubs, j,
2105
0
                                                               &storage->list[i].sub_dset[j].file_name) < 0)
2106
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
2107
0
                                            "unable to build source file name");
2108
2109
                        /* Resolve dset name */
2110
0
                        if (!storage->list[i].sub_dset[j].dset_name)
2111
0
                            if (H5D__virtual_build_source_name(storage->list[i].source_dset_name,
2112
0
                                                               storage->list[i].parsed_source_dset_name,
2113
0
                                                               storage->list[i].psdn_static_strlen,
2114
0
                                                               storage->list[i].psdn_nsubs, j,
2115
0
                                                               &storage->list[i].sub_dset[j].dset_name) < 0)
2116
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
2117
0
                                            "unable to build source dataset name");
2118
2119
                        /* Resolve virtual selection for block */
2120
0
                        if (!storage->list[i].sub_dset[j].virtual_select)
2121
0
                            if (NULL ==
2122
0
                                (storage->list[i].sub_dset[j].virtual_select = H5S_hyper_get_unlim_block(
2123
0
                                     storage->list[i].source_dset.virtual_select, j)))
2124
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
2125
0
                                            "unable to get block in unlimited selection");
2126
2127
                        /* Initialize clipped selections */
2128
0
                        if (!storage->list[i].sub_dset[j].clipped_source_select)
2129
0
                            storage->list[i].sub_dset[j].clipped_source_select =
2130
0
                                storage->list[i].source_select;
2131
0
                        if (!storage->list[i].sub_dset[j].clipped_virtual_select)
2132
0
                            storage->list[i].sub_dset[j].clipped_virtual_select =
2133
0
                                storage->list[i].sub_dset[j].virtual_select;
2134
2135
                        /* Open source dataset */
2136
0
                        if (H5D__virtual_open_source_dset(dset, &storage->list[i],
2137
0
                                                          &storage->list[i].sub_dset[j]) < 0)
2138
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset");
2139
2140
0
                        if (storage->list[i].sub_dset[j].dset) {
2141
                            /* Update first_missing */
2142
0
                            first_missing = j + 1;
2143
2144
                            /* Close source dataset so we don't have huge
2145
                             * numbers of datasets open */
2146
0
                            if (H5D_close(storage->list[i].sub_dset[j].dset) < 0)
2147
0
                                HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2148
0
                                            "unable to close source dataset");
2149
0
                            storage->list[i].sub_dset[j].dset = NULL;
2150
0
                        } /* end if */
2151
0
                    }     /* end else */
2152
0
                }         /* end for */
2153
2154
                /* Check if the size changed */
2155
0
                if ((first_missing == (hsize_t)storage->list[i].sub_dset_nused) &&
2156
0
                    (storage->list[i].clip_size_virtual != HSIZE_UNDEF))
2157
                    /* Use cached clip_size */
2158
0
                    clip_size = storage->list[i].clip_size_virtual;
2159
0
                else {
2160
                    /* Check for no datasets */
2161
0
                    if (first_missing == 0)
2162
                        /* Set clip size to 0 */
2163
0
                        clip_size = (hsize_t)0;
2164
0
                    else {
2165
0
                        hsize_t bounds_start[H5S_MAX_RANK];
2166
0
                        hsize_t bounds_end[H5S_MAX_RANK];
2167
2168
                        /* Get clip size from selection */
2169
0
                        if (storage->view == H5D_VDS_LAST_AVAILABLE) {
2170
                            /* Get bounds from last valid virtual selection */
2171
0
                            if (H5S_SELECT_BOUNDS(
2172
0
                                    storage->list[i].sub_dset[first_missing - (hsize_t)1].virtual_select,
2173
0
                                    bounds_start, bounds_end) < 0)
2174
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds");
2175
2176
                            /* Set clip_size to bounds_end in unlimited
2177
                             * dimension */
2178
0
                            clip_size = bounds_end[storage->list[i].unlim_dim_virtual] + (hsize_t)1;
2179
0
                        } /* end if */
2180
0
                        else {
2181
                            /* Get bounds from first missing virtual selection
2182
                             */
2183
0
                            if (H5S_SELECT_BOUNDS(storage->list[i].sub_dset[first_missing].virtual_select,
2184
0
                                                  bounds_start, bounds_end) < 0)
2185
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds");
2186
2187
                            /* Set clip_size to bounds_start in unlimited
2188
                             * dimension */
2189
0
                            clip_size = bounds_start[storage->list[i].unlim_dim_virtual];
2190
0
                        } /* end else */
2191
0
                    }     /* end else */
2192
2193
                    /* Set sub_dset_nused and clip_size_virtual */
2194
0
                    storage->list[i].sub_dset_nused    = (size_t)first_missing;
2195
0
                    storage->list[i].clip_size_virtual = clip_size;
2196
0
                } /* end else */
2197
0
            }     /* end else */
2198
2199
            /* Update new_dims */
2200
0
            if ((new_dims[storage->list[i].unlim_dim_virtual] == HSIZE_UNDEF) ||
2201
0
                (storage->view == H5D_VDS_FIRST_MISSING
2202
0
                     ? (clip_size < (hsize_t)new_dims[storage->list[i].unlim_dim_virtual])
2203
0
                     : (clip_size > (hsize_t)new_dims[storage->list[i].unlim_dim_virtual])))
2204
0
                new_dims[storage->list[i].unlim_dim_virtual] = clip_size;
2205
0
        } /* end if */
2206
2207
    /* Get current VDS dimensions */
2208
0
    if (H5S_get_simple_extent_dims(dset->shared->space, curr_dims, NULL) < 0)
2209
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions");
2210
2211
    /* Calculate new extent */
2212
0
    for (i = 0; i < (size_t)rank; i++) {
2213
0
        if (new_dims[i] == HSIZE_UNDEF)
2214
0
            new_dims[i] = curr_dims[i];
2215
0
        else if (new_dims[i] < storage->min_dims[i])
2216
0
            new_dims[i] = storage->min_dims[i];
2217
0
        if (new_dims[i] != curr_dims[i])
2218
0
            changed = true;
2219
0
    } /* end for */
2220
2221
    /* Update extent if it changed */
2222
0
    if (changed) {
2223
        /* Update VDS extent */
2224
0
        if (H5S_set_extent(dset->shared->space, new_dims) < 0)
2225
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace");
2226
2227
        /* Mark the space as dirty, for later writing to the file */
2228
0
        if (H5F_INTENT(dset->oloc.file) & H5F_ACC_RDWR)
2229
0
            if (H5D__mark(dset, H5D_MARK_SPACE) < 0)
2230
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark dataspace as dirty");
2231
0
    } /* end if */
2232
2233
    /* If we did not change the VDS dimensions, there is nothing more to update
2234
     */
2235
0
    if (changed || (!storage->init && (storage->view == H5D_VDS_FIRST_MISSING))) {
2236
        /* Iterate over mappings again to update source selections and virtual
2237
         * mapping extents */
2238
0
        for (i = 0; i < storage->list_nused; i++) {
2239
            /* If there is an unlimited dimension, we are setting extent by the
2240
             * minimum of mappings, and the virtual extent in the unlimited
2241
             * dimension has changed since the last time the VDS extent/mapping
2242
             * was updated, we must adjust the selections */
2243
0
            if ((storage->list[i].unlim_dim_virtual >= 0) && (storage->view == H5D_VDS_FIRST_MISSING) &&
2244
0
                (new_dims[storage->list[i].unlim_dim_virtual] != storage->list[i].unlim_extent_virtual)) {
2245
                /* Check for "printf" style mapping */
2246
0
                if (storage->list[i].unlim_dim_source >= 0) {
2247
                    /* Non-printf mapping */
2248
                    /* Close previous clipped virtual selection, if any */
2249
0
                    if (storage->list[i].source_dset.clipped_virtual_select) {
2250
0
                        assert(storage->list[i].source_dset.clipped_virtual_select !=
2251
0
                               storage->list[i].source_dset.virtual_select);
2252
0
                        if (H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
2253
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2254
0
                                        "unable to release clipped virtual dataspace");
2255
0
                    } /* end if */
2256
2257
                    /* Copy virtual selection */
2258
0
                    if (NULL == (storage->list[i].source_dset.clipped_virtual_select =
2259
0
                                     H5S_copy(storage->list[i].source_dset.virtual_select, false, true)))
2260
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection");
2261
2262
                    /* Clip space to virtual extent */
2263
0
                    if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select,
2264
0
                                             new_dims[storage->list[i].unlim_dim_source]))
2265
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection");
2266
2267
                    /* Get size that source selection will be clipped to to
2268
                     * match size of virtual selection */
2269
0
                    clip_size =
2270
0
                        H5S_hyper_get_clip_extent(storage->list[i].source_select,
2271
0
                                                  storage->list[i].source_dset.clipped_virtual_select, false);
2272
2273
                    /* Check if the clip size changed */
2274
0
                    if (clip_size != storage->list[i].clip_size_source) {
2275
                        /* Close previous clipped source selection, if any */
2276
0
                        if (storage->list[i].source_dset.clipped_source_select) {
2277
0
                            assert(storage->list[i].source_dset.clipped_source_select !=
2278
0
                                   storage->list[i].source_select);
2279
0
                            if (H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
2280
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2281
0
                                            "unable to release clipped source dataspace");
2282
0
                        } /* end if */
2283
2284
                        /* Copy source selection */
2285
0
                        if (NULL == (storage->list[i].source_dset.clipped_source_select =
2286
0
                                         H5S_copy(storage->list[i].source_select, false, true)))
2287
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection");
2288
2289
                        /* Clip source selection */
2290
0
                        if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select,
2291
0
                                                 clip_size))
2292
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
2293
0
                                        "failed to clip unlimited selection");
2294
2295
                        /* Update cached value clip_size_source */
2296
0
                        storage->list[i].clip_size_source = clip_size;
2297
0
                    } /* end if */
2298
0
                }     /* end if */
2299
0
                else {
2300
                    /* printf mapping */
2301
0
                    hsize_t first_inc_block;
2302
0
                    bool    partial_block;
2303
2304
                    /* Get index of first incomplete block in virtual
2305
                     * selection */
2306
0
                    first_inc_block = H5S_hyper_get_first_inc_block(
2307
0
                        storage->list[i].source_dset.virtual_select,
2308
0
                        new_dims[storage->list[i].unlim_dim_virtual], &partial_block);
2309
2310
                    /* Iterate over sub datasets */
2311
0
                    for (j = 0; j < storage->list[i].sub_dset_nalloc; j++) {
2312
                        /* Close previous clipped source selection, if any */
2313
0
                        if (storage->list[i].sub_dset[j].clipped_source_select !=
2314
0
                            storage->list[i].source_select) {
2315
0
                            if (storage->list[i].sub_dset[j].clipped_source_select)
2316
0
                                if (H5S_close(storage->list[i].sub_dset[j].clipped_source_select) < 0)
2317
0
                                    HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2318
0
                                                "unable to release clipped source dataspace");
2319
2320
                            /* Initialize clipped source selection to point to
2321
                             * base source selection */
2322
0
                            storage->list[i].sub_dset[j].clipped_source_select =
2323
0
                                storage->list[i].source_select;
2324
0
                        } /* end if */
2325
2326
                        /* Close previous clipped virtual selection, if any */
2327
0
                        if (storage->list[i].sub_dset[j].clipped_virtual_select !=
2328
0
                            storage->list[i].sub_dset[j].virtual_select) {
2329
0
                            if (storage->list[i].sub_dset[j].clipped_virtual_select)
2330
0
                                if (H5S_close(storage->list[i].sub_dset[j].clipped_virtual_select) < 0)
2331
0
                                    HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2332
0
                                                "unable to release clipped virtual dataspace");
2333
2334
                            /* Initialize clipped virtual selection to point to
2335
                             * unclipped virtual selection */
2336
0
                            storage->list[i].sub_dset[j].clipped_virtual_select =
2337
0
                                storage->list[i].sub_dset[j].virtual_select;
2338
0
                        } /* end if */
2339
2340
                        /* Only initialize clipped selections if it is a
2341
                         * complete block, for incomplete blocks defer to
2342
                         * H5D__virtual_pre_io() as we may not have a valid
2343
                         * source extent here.  For unused blocks we will never
2344
                         * need clipped selections (until the extent is
2345
                         * recalculated in this function). */
2346
0
                        if (j >= (size_t)first_inc_block) {
2347
                            /* Clear clipped source and virtual selections */
2348
0
                            storage->list[i].sub_dset[j].clipped_source_select  = NULL;
2349
0
                            storage->list[i].sub_dset[j].clipped_virtual_select = NULL;
2350
0
                        } /* end if */
2351
0
                    }     /* end for */
2352
0
                }         /* end else */
2353
2354
                /* Update cached value unlim_extent_virtual */
2355
0
                storage->list[i].unlim_extent_virtual = new_dims[storage->list[i].unlim_dim_virtual];
2356
0
            } /* end if */
2357
2358
            /* Update top level virtual_select and clipped_virtual_select
2359
             * extents */
2360
0
            if (H5S_set_extent(storage->list[i].source_dset.virtual_select, new_dims) < 0)
2361
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace");
2362
0
            if ((storage->list[i].source_dset.clipped_virtual_select !=
2363
0
                 storage->list[i].source_dset.virtual_select) &&
2364
0
                storage->list[i].source_dset.clipped_virtual_select)
2365
0
                if (H5S_set_extent(storage->list[i].source_dset.clipped_virtual_select, new_dims) < 0)
2366
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace");
2367
2368
            /* Update sub dataset virtual_select and clipped_virtual_select
2369
             * extents */
2370
0
            for (j = 0; j < storage->list[i].sub_dset_nalloc; j++)
2371
0
                if (storage->list[i].sub_dset[j].virtual_select) {
2372
0
                    if (H5S_set_extent(storage->list[i].sub_dset[j].virtual_select, new_dims) < 0)
2373
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace");
2374
0
                    if ((storage->list[i].sub_dset[j].clipped_virtual_select !=
2375
0
                         storage->list[i].sub_dset[j].virtual_select) &&
2376
0
                        storage->list[i].sub_dset[j].clipped_virtual_select)
2377
0
                        if (H5S_set_extent(storage->list[i].sub_dset[j].clipped_virtual_select, new_dims) < 0)
2378
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
2379
0
                                        "unable to modify size of dataspace");
2380
0
                } /* end if */
2381
0
                else
2382
0
                    assert(!storage->list[i].sub_dset[j].clipped_virtual_select);
2383
0
        } /* end for */
2384
0
    }     /* end if */
2385
2386
    /* Mark layout as fully initialized */
2387
0
    storage->init = true;
2388
2389
0
done:
2390
0
    FUNC_LEAVE_NOAPI(ret_value)
2391
0
} /* end H5D__virtual_set_extent_unlim() */
2392
2393
/*-------------------------------------------------------------------------
2394
 * Function:    H5D__virtual_init_all
2395
 *
2396
 * Purpose:     Finishes initializing layout in preparation for I/O.
2397
 *              Only necessary if H5D__virtual_set_extent_unlim() has not
2398
 *              been called yet.  Initializes clipped_virtual_select and
2399
 *              clipped_source_select for all mappings in this layout.
2400
 *
2401
 * Return:      Non-negative on success/Negative on failure
2402
 *
2403
 *-------------------------------------------------------------------------
2404
 */
2405
static herr_t
2406
H5D__virtual_init_all(const H5D_t *dset)
2407
0
{
2408
0
    H5O_storage_virtual_t *storage;
2409
0
    hsize_t                virtual_dims[H5S_MAX_RANK];
2410
0
    hsize_t                source_dims[H5S_MAX_RANK];
2411
0
    hsize_t                clip_size;
2412
0
    size_t                 i, j;
2413
0
    herr_t                 ret_value = SUCCEED; /* Return value */
2414
2415
0
    FUNC_ENTER_PACKAGE
2416
2417
    /* Sanity check */
2418
0
    assert(dset);
2419
0
    assert(dset->shared->layout.storage.type == H5D_VIRTUAL);
2420
0
    storage = &dset->shared->layout.storage.u.virt;
2421
0
    assert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
2422
2423
    /* Get current VDS dimensions */
2424
0
    if (H5S_get_simple_extent_dims(dset->shared->space, virtual_dims, NULL) < 0)
2425
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions");
2426
2427
    /* Iterate over mappings */
2428
0
    for (i = 0; i < storage->list_nused; i++)
2429
        /* Check for unlimited dimension */
2430
0
        if (storage->list[i].unlim_dim_virtual >= 0) {
2431
            /* Check for "printf" source dataset resolution */
2432
0
            if (storage->list[i].unlim_dim_source >= 0) {
2433
                /* Non-printf mapping */
2434
                /* Open source dataset */
2435
0
                if (!storage->list[i].source_dset.dset)
2436
0
                    if (H5D__virtual_open_source_dset(dset, &storage->list[i],
2437
0
                                                      &storage->list[i].source_dset) < 0)
2438
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset");
2439
2440
                /* Check if source dataset is open */
2441
0
                if (storage->list[i].source_dset.dset) {
2442
                    /* Retrieve current source dataset extent and patch mapping
2443
                     */
2444
0
                    if (H5S_extent_copy(storage->list[i].source_select,
2445
0
                                        storage->list[i].source_dset.dset->shared->space) < 0)
2446
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent");
2447
2448
                    /* Get source space dimensions */
2449
0
                    if (H5S_get_simple_extent_dims(storage->list[i].source_select, source_dims, NULL) < 0)
2450
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get source space dimensions");
2451
2452
                    /* Get size that source selection would be clipped to to
2453
                     * match size of virtual selection */
2454
0
                    clip_size = H5S_hyper_get_clip_extent_match(
2455
0
                        storage->list[i].source_select, storage->list[i].source_dset.virtual_select,
2456
0
                        virtual_dims[storage->list[i].unlim_dim_virtual], false);
2457
2458
                    /* Close previous clipped virtual selection, if any */
2459
0
                    if (storage->list[i].source_dset.clipped_virtual_select) {
2460
0
                        assert(storage->list[i].source_dset.clipped_virtual_select !=
2461
0
                               storage->list[i].source_dset.virtual_select);
2462
0
                        if (H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
2463
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2464
0
                                        "unable to release clipped virtual dataspace");
2465
0
                    } /* end if */
2466
2467
                    /* Copy virtual selection */
2468
0
                    if (NULL == (storage->list[i].source_dset.clipped_virtual_select =
2469
0
                                     H5S_copy(storage->list[i].source_dset.virtual_select, false, true)))
2470
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection");
2471
2472
                    /* Close previous clipped source selection, if any */
2473
0
                    if (storage->list[i].source_dset.clipped_source_select) {
2474
0
                        assert(storage->list[i].source_dset.clipped_source_select !=
2475
0
                               storage->list[i].source_select);
2476
0
                        if (H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
2477
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2478
0
                                        "unable to release clipped source dataspace");
2479
0
                    } /* end if */
2480
2481
                    /* Copy source selection */
2482
0
                    if (NULL == (storage->list[i].source_dset.clipped_source_select =
2483
0
                                     H5S_copy(storage->list[i].source_select, false, true)))
2484
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection");
2485
2486
                    /* Check if the clip size is within the current extent of
2487
                     * the source dataset */
2488
0
                    if (clip_size <= source_dims[storage->list[i].unlim_dim_source]) {
2489
                        /* Clip virtual selection to extent */
2490
0
                        if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select,
2491
0
                                                 virtual_dims[storage->list[i].unlim_dim_virtual]))
2492
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
2493
0
                                        "failed to clip unlimited selection");
2494
2495
                        /* Clip source selection to clip_size */
2496
0
                        if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select,
2497
0
                                                 clip_size))
2498
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
2499
0
                                        "failed to clip unlimited selection");
2500
0
                    } /* end if */
2501
0
                    else {
2502
                        /* Get size that virtual selection will be clipped to to
2503
                         * match size of source selection within source extent
2504
                         */
2505
0
                        clip_size = H5S_hyper_get_clip_extent_match(
2506
0
                            storage->list[i].source_dset.virtual_select, storage->list[i].source_select,
2507
0
                            source_dims[storage->list[i].unlim_dim_source], false);
2508
2509
                        /* Clip virtual selection to clip_size */
2510
0
                        if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select,
2511
0
                                                 clip_size))
2512
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
2513
0
                                        "failed to clip unlimited selection");
2514
2515
                        /* Clip source selection to extent */
2516
0
                        if (H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select,
2517
0
                                                 source_dims[storage->list[i].unlim_dim_source]))
2518
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
2519
0
                                        "failed to clip unlimited selection");
2520
0
                    } /* end else */
2521
0
                }     /* end if */
2522
0
                else {
2523
0
                    assert(!storage->list[i].source_dset.clipped_virtual_select);
2524
0
                    assert(!storage->list[i].source_dset.clipped_source_select);
2525
0
                } /* end else */
2526
0
            }     /* end if */
2527
0
            else {
2528
                /* printf mapping */
2529
0
                size_t sub_dset_max;
2530
0
                bool   partial_block;
2531
2532
                /* Get number of sub-source datasets in current extent */
2533
0
                sub_dset_max = (size_t)H5S_hyper_get_first_inc_block(
2534
0
                    storage->list[i].source_dset.virtual_select,
2535
0
                    virtual_dims[storage->list[i].unlim_dim_virtual], &partial_block);
2536
0
                if (partial_block)
2537
0
                    sub_dset_max++;
2538
2539
                /* Allocate or grow the sub_dset array if necessary */
2540
0
                if (!storage->list[i].sub_dset) {
2541
                    /* Allocate sub_dset array */
2542
0
                    if (NULL == (storage->list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_calloc(
2543
0
                                     sub_dset_max * sizeof(H5O_storage_virtual_srcdset_t))))
2544
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
2545
0
                                    "unable to allocate sub dataset array");
2546
2547
                    /* Update sub_dset_nalloc */
2548
0
                    storage->list[i].sub_dset_nalloc = sub_dset_max;
2549
0
                } /* end if */
2550
0
                else if (sub_dset_max > storage->list[i].sub_dset_nalloc) {
2551
0
                    H5O_storage_virtual_srcdset_t *tmp_sub_dset;
2552
2553
                    /* Extend sub_dset array */
2554
0
                    if (NULL == (tmp_sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_realloc(
2555
0
                                     storage->list[i].sub_dset,
2556
0
                                     sub_dset_max * sizeof(H5O_storage_virtual_srcdset_t))))
2557
0
                        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend sub dataset array");
2558
0
                    storage->list[i].sub_dset = tmp_sub_dset;
2559
2560
                    /* Clear new space in sub_dset */
2561
0
                    (void)memset(&storage->list[i].sub_dset[storage->list[i].sub_dset_nalloc], 0,
2562
0
                                 (sub_dset_max - storage->list[i].sub_dset_nalloc) *
2563
0
                                     sizeof(H5O_storage_virtual_srcdset_t));
2564
2565
                    /* Update sub_dset_nalloc */
2566
0
                    storage->list[i].sub_dset_nalloc = sub_dset_max;
2567
0
                } /* end if */
2568
2569
                /* Iterate over sub dsets */
2570
0
                for (j = 0; j < sub_dset_max; j++) {
2571
                    /* Resolve file name */
2572
0
                    if (!storage->list[i].sub_dset[j].file_name)
2573
0
                        if (H5D__virtual_build_source_name(
2574
0
                                storage->list[i].source_file_name, storage->list[i].parsed_source_file_name,
2575
0
                                storage->list[i].psfn_static_strlen, storage->list[i].psfn_nsubs, j,
2576
0
                                &storage->list[i].sub_dset[j].file_name) < 0)
2577
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source file name");
2578
2579
                    /* Resolve dset name */
2580
0
                    if (!storage->list[i].sub_dset[j].dset_name)
2581
0
                        if (H5D__virtual_build_source_name(
2582
0
                                storage->list[i].source_dset_name, storage->list[i].parsed_source_dset_name,
2583
0
                                storage->list[i].psdn_static_strlen, storage->list[i].psdn_nsubs, j,
2584
0
                                &storage->list[i].sub_dset[j].dset_name) < 0)
2585
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
2586
0
                                        "unable to build source dataset name");
2587
2588
                    /* Resolve virtual selection for block */
2589
0
                    if (!storage->list[i].sub_dset[j].virtual_select)
2590
0
                        if (NULL == (storage->list[i].sub_dset[j].virtual_select = H5S_hyper_get_unlim_block(
2591
0
                                         storage->list[i].source_dset.virtual_select, j)))
2592
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
2593
0
                                        "unable to get block in unlimited selection");
2594
2595
                    /* Close previous clipped source selection, if any */
2596
0
                    if (storage->list[i].sub_dset[j].clipped_source_select !=
2597
0
                        storage->list[i].source_select) {
2598
0
                        if (storage->list[i].sub_dset[j].clipped_source_select)
2599
0
                            if (H5S_close(storage->list[i].sub_dset[j].clipped_source_select) < 0)
2600
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2601
0
                                            "unable to release clipped source dataspace");
2602
2603
                        /* Initialize clipped source selection to point to base
2604
                         * source selection */
2605
0
                        storage->list[i].sub_dset[j].clipped_source_select = storage->list[i].source_select;
2606
0
                    } /* end if */
2607
2608
                    /* Close previous clipped virtual selection, if any */
2609
0
                    if (storage->list[i].sub_dset[j].clipped_virtual_select !=
2610
0
                        storage->list[i].sub_dset[j].virtual_select) {
2611
0
                        if (storage->list[i].sub_dset[j].clipped_virtual_select)
2612
0
                            if (H5S_close(storage->list[i].sub_dset[j].clipped_virtual_select) < 0)
2613
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL,
2614
0
                                            "unable to release clipped virtual dataspace");
2615
2616
                        /* Initialize clipped virtual selection to point to
2617
                         * unclipped virtual selection */
2618
0
                        storage->list[i].sub_dset[j].clipped_virtual_select =
2619
0
                            storage->list[i].sub_dset[j].virtual_select;
2620
0
                    } /* end if */
2621
2622
                    /* Clear clipped selections if this is a partial block,
2623
                     * defer calculation of real clipped selections to
2624
                     * H5D__virtual_pre_io() as we may not have a valid source
2625
                     * extent here */
2626
0
                    if ((j == (sub_dset_max - 1)) && partial_block) {
2627
                        /* Clear clipped source and virtual selections */
2628
0
                        storage->list[i].sub_dset[j].clipped_source_select  = NULL;
2629
0
                        storage->list[i].sub_dset[j].clipped_virtual_select = NULL;
2630
0
                    } /* end else */
2631
                    /* Note we do not need to open the source file, this will
2632
                     * happen later in H5D__virtual_pre_io() */
2633
0
                } /* end for */
2634
2635
                /* Update sub_dset_nused */
2636
0
                storage->list[i].sub_dset_nused = sub_dset_max;
2637
0
            } /* end else */
2638
0
        }     /* end if */
2639
0
        else {
2640
            /* Limited mapping, just make sure the clipped selections were
2641
             * already set.  Again, no need to open the source file. */
2642
0
            assert(storage->list[i].source_dset.clipped_virtual_select);
2643
0
            assert(storage->list[i].source_dset.clipped_source_select);
2644
0
        } /* end else */
2645
2646
    /* Mark layout as fully initialized */
2647
0
    storage->init = true;
2648
2649
0
done:
2650
0
    FUNC_LEAVE_NOAPI(ret_value)
2651
0
} /* end H5D__virtual_init_all() */
2652
2653
/*-------------------------------------------------------------------------
2654
 * Function:    H5D__virtual_construct
2655
 *
2656
 * Purpose:     Constructs new virtual layout information for dataset and
2657
 *              upgrades layout version if appropriate
2658
 *
2659
 * Return:      Non-negative on success/Negative on failure
2660
 *
2661
 *-------------------------------------------------------------------------
2662
 */
2663
static herr_t
2664
H5D__virtual_construct(H5F_t *f, H5D_t *dset)
2665
0
{
2666
0
    unsigned version;             /* Message version */
2667
0
    herr_t   ret_value = SUCCEED; /* Return value */
2668
2669
0
    FUNC_ENTER_PACKAGE
2670
2671
    /* Sanity checks */
2672
0
    assert(f);
2673
0
    assert(dset);
2674
0
    assert(dset->shared);
2675
2676
    /* Currently only handles layout version */
2677
    /* If the layout is below version 4, upgrade to version 4 if allowed. If not allowed throw an error, since
2678
     * virtual datasets require layout version 4. Do not upgrade past version 3 since there is no benefit. */
2679
0
    if (dset->shared->layout.version < H5O_LAYOUT_VERSION_4) {
2680
0
        version = MAX(dset->shared->layout.version, H5O_LAYOUT_VERSION_4);
2681
2682
        /* Version bounds check */
2683
0
        if (version > H5O_layout_ver_bounds[H5F_HIGH_BOUND(f)])
2684
0
            HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "layout version out of bounds");
2685
2686
0
        dset->shared->layout.version = version;
2687
0
    }
2688
2689
0
done:
2690
0
    FUNC_LEAVE_NOAPI(ret_value)
2691
0
} /* end H5D__virtual_construct() */
2692
2693
/*-------------------------------------------------------------------------
2694
 * Function:    H5D__virtual_init
2695
 *
2696
 * Purpose:     Initialize the virtual layout information for a dataset.
2697
 *              This is called when the dataset is initialized.
2698
 *
2699
 * Return:      Non-negative on success/Negative on failure
2700
 *
2701
 *-------------------------------------------------------------------------
2702
 */
2703
static herr_t
2704
H5D__virtual_init(H5F_t *f, H5D_t *dset, hid_t dapl_id, bool H5_ATTR_UNUSED open_op)
2705
0
{
2706
0
    H5O_storage_virtual_t *storage;                      /* Convenience pointer */
2707
0
    H5P_genplist_t        *dapl;                         /* Data access property list object pointer */
2708
0
    hssize_t               old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset (unused) */
2709
0
    size_t                 i;                            /* Local index variables */
2710
0
    herr_t                 ret_value = SUCCEED;          /* Return value */
2711
2712
0
    FUNC_ENTER_PACKAGE
2713
2714
    /* Sanity check */
2715
0
    assert(dset);
2716
0
    storage = &dset->shared->layout.storage.u.virt;
2717
0
    assert(storage->list || (storage->list_nused == 0));
2718
2719
0
    if (H5D__virtual_load_layout(f, &dset->shared->layout) < 0)
2720
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTLOAD, FAIL, "unable to load virtual layout information");
2721
2722
    /* Check that the dimensions of the VDS are large enough */
2723
0
    if (H5D_virtual_check_min_dims(dset) < 0)
2724
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
2725
0
                    "virtual dataset dimensions not large enough to contain all limited dimensions in all "
2726
0
                    "selections");
2727
2728
    /* Patch the virtual selection dataspaces.  Note we always patch the space
2729
     * status because this layout could be from an old version held in the
2730
     * object header message code.  We cannot update that held message because
2731
     * the layout message is constant, so just overwrite the values here (and
2732
     * invalidate other fields by setting storage->init to false below).  Also
2733
     * remove offset from selections.  We only have to update
2734
     * source_space_status and virtual_space_status because others will be based
2735
     * on these and should therefore already have been normalized. */
2736
0
    for (i = 0; i < storage->list_nused; i++) {
2737
0
        assert(storage->list[i].sub_dset_nalloc == 0);
2738
2739
        /* Patch extent */
2740
0
        if (H5S_extent_copy(storage->list[i].source_dset.virtual_select, dset->shared->space) < 0)
2741
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy virtual dataspace extent");
2742
0
        storage->list[i].virtual_space_status = H5O_VIRTUAL_STATUS_CORRECT;
2743
2744
        /* Mark source extent as invalid */
2745
0
        storage->list[i].source_space_status = H5O_VIRTUAL_STATUS_INVALID;
2746
2747
        /* Normalize offsets, toss out old offset values */
2748
0
        if (H5S_hyper_normalize_offset(storage->list[i].source_dset.virtual_select, old_offset) < 0)
2749
0
            HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset");
2750
0
        if (H5S_hyper_normalize_offset(storage->list[i].source_select, old_offset) < 0)
2751
0
            HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset");
2752
0
    } /* end for */
2753
2754
    /* Get dataset access property list */
2755
0
    if (NULL == (dapl = (H5P_genplist_t *)H5I_object(dapl_id)))
2756
0
        HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for dapl ID");
2757
2758
    /* Get view option */
2759
0
    if (H5P_get(dapl, H5D_ACS_VDS_VIEW_NAME, &storage->view) < 0)
2760
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get virtual view option");
2761
2762
    /* Get printf gap if view is H5D_VDS_LAST_AVAILABLE, otherwise set to 0 */
2763
0
    if (storage->view == H5D_VDS_LAST_AVAILABLE) {
2764
0
        if (H5P_get(dapl, H5D_ACS_VDS_PRINTF_GAP_NAME, &storage->printf_gap) < 0)
2765
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get virtual printf gap");
2766
0
    } /* end if */
2767
0
    else
2768
0
        storage->printf_gap = (hsize_t)0;
2769
2770
    /* Retrieve VDS file FAPL to layout */
2771
0
    if (storage->source_fapl <= 0) {
2772
0
        H5P_genplist_t    *source_fapl  = NULL;           /* Source file FAPL */
2773
0
        H5F_close_degree_t close_degree = H5F_CLOSE_WEAK; /* Close degree for source files */
2774
2775
0
        if ((storage->source_fapl = H5F_get_access_plist(f, false)) < 0)
2776
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get fapl");
2777
2778
        /* Get property list pointer */
2779
0
        if (NULL == (source_fapl = (H5P_genplist_t *)H5I_object(storage->source_fapl)))
2780
0
            HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, H5I_INVALID_HID, "not a property list");
2781
2782
        /* Source files must always be opened with H5F_CLOSE_WEAK close degree */
2783
0
        if (H5P_set(source_fapl, H5F_ACS_CLOSE_DEGREE_NAME, &close_degree) < 0)
2784
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file close degree");
2785
0
    } /* end if */
2786
#ifndef NDEBUG
2787
    else {
2788
        H5P_genplist_t    *source_fapl = NULL; /* Source file FAPL */
2789
        H5F_close_degree_t close_degree;       /* Close degree for source files */
2790
2791
        /* Get property list pointer */
2792
        if (NULL == (source_fapl = (H5P_genplist_t *)H5I_object(storage->source_fapl)))
2793
            HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, H5I_INVALID_HID, "not a property list");
2794
2795
        /* Verify H5F_CLOSE_WEAK close degree is set */
2796
        if (H5P_get(source_fapl, H5F_ACS_CLOSE_DEGREE_NAME, &close_degree) < 0)
2797
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file close degree");
2798
2799
        assert(close_degree == H5F_CLOSE_WEAK);
2800
    }  /* end else */
2801
#endif /* NDEBUG */
2802
2803
    /* Copy DAPL to layout */
2804
0
    if (storage->source_dapl <= 0)
2805
0
        if ((storage->source_dapl = H5P_copy_plist(dapl, false)) < 0)
2806
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dapl");
2807
2808
    /* Mark layout as not fully initialized (must be done prior to I/O for
2809
     * unlimited/printf selections) */
2810
0
    storage->init = false;
2811
2812
0
done:
2813
0
    FUNC_LEAVE_NOAPI(ret_value)
2814
0
} /* end H5D__virtual_init() */
2815
2816
/*-------------------------------------------------------------------------
2817
 * Function:    H5D__virtual_is_space_alloc
2818
 *
2819
 * Purpose:     Query if space is allocated for layout
2820
 *
2821
 * Return:      true if space is allocated
2822
 *              false if it is not
2823
 *              Negative on failure
2824
 *
2825
 *-------------------------------------------------------------------------
2826
 */
2827
static bool
2828
H5D__virtual_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage)
2829
0
{
2830
0
    bool ret_value = false; /* Return value */
2831
2832
0
    FUNC_ENTER_PACKAGE_NOERR
2833
2834
    /* Just return true, since the global heap object containing the mappings is
2835
     * created when the layout message is encoded, and nothing else needs to be
2836
     * allocated for virtual datasets.  This also ensures that the library never
2837
     * assumes (falsely) that no data is present in the dataset, causing errors.
2838
     */
2839
0
    ret_value = true;
2840
2841
0
    FUNC_LEAVE_NOAPI(ret_value)
2842
0
} /* end H5D__virtual_is_space_alloc() */
2843
2844
/*-------------------------------------------------------------------------
2845
 * Function:    H5D__virtual_is_data_cached
2846
 *
2847
 * Purpose:     Query if raw data is cached for dataset
2848
 *
2849
 * Return:      Non-negative on success/Negative on failure
2850
 *
2851
 *-------------------------------------------------------------------------
2852
 */
2853
static bool
2854
H5D__virtual_is_data_cached(const H5D_shared_t *shared_dset)
2855
0
{
2856
0
    const H5O_storage_virtual_t *storage;           /* Convenience pointer */
2857
0
    size_t                       i, j;              /* Local index variables */
2858
0
    bool                         ret_value = false; /* Return value */
2859
2860
0
    FUNC_ENTER_PACKAGE_NOERR
2861
2862
    /* Sanity checks */
2863
0
    assert(shared_dset);
2864
0
    storage = &shared_dset->layout.storage.u.virt;
2865
2866
    /* Iterate over mappings */
2867
0
    for (i = 0; i < storage->list_nused; i++)
2868
        /* Check for "printf" source dataset resolution */
2869
0
        if (storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2870
            /* Iterate over sub-source dsets */
2871
0
            for (j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++)
2872
                /* Check for cached data in source dset */
2873
0
                if (storage->list[i].sub_dset[j].dset &&
2874
0
                    storage->list[i].sub_dset[j].dset->shared->layout.ops->is_data_cached &&
2875
0
                    storage->list[i].sub_dset[j].dset->shared->layout.ops->is_data_cached(
2876
0
                        storage->list[i].sub_dset[j].dset->shared))
2877
0
                    HGOTO_DONE(true);
2878
0
        } /* end if */
2879
0
        else if (storage->list[i].source_dset.dset &&
2880
0
                 storage->list[i].source_dset.dset->shared->layout.ops->is_data_cached &&
2881
0
                 storage->list[i].source_dset.dset->shared->layout.ops->is_data_cached(
2882
0
                     storage->list[i].source_dset.dset->shared))
2883
0
            HGOTO_DONE(true);
2884
2885
0
done:
2886
0
    FUNC_LEAVE_NOAPI(ret_value)
2887
0
} /* end H5D__virtual_is_data_cached() */
2888
2889
/*-------------------------------------------------------------------------
2890
 * Function:    H5D__virtual_io_init
2891
 *
2892
 * Purpose:     Performs initialization before any sort of I/O on the raw data
2893
 *
2894
 * Return:      Non-negative on success/Negative on failure
2895
 *
2896
 *-------------------------------------------------------------------------
2897
 */
2898
static herr_t
2899
H5D__virtual_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t H5_ATTR_UNUSED *dinfo)
2900
0
{
2901
0
    FUNC_ENTER_PACKAGE_NOERR
2902
2903
    /* Disable selection I/O */
2904
0
    io_info->use_select_io = H5D_SELECTION_IO_MODE_OFF;
2905
0
    io_info->no_selection_io_cause |= H5D_SEL_IO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET;
2906
2907
0
    FUNC_LEAVE_NOAPI(SUCCEED)
2908
0
} /* end H5D__virtual_io_init() */
2909
2910
/*-------------------------------------------------------------------------
2911
 * Function:    H5D__virtual_pre_io_process_mapping
2912
 *
2913
 * Purpose:     Process a single virtual mapping to prepare for I/O.
2914
 *              This includes projecting the virtual mapping onto mem_space
2915
 *              and opening source datasets. The number of elements included
2916
 *              in this mapping selection is added to tot_nelmts.
2917
 *
2918
 * Return:      Non-negative on success/Negative on failure
2919
 *
2920
 *-------------------------------------------------------------------------
2921
 */
2922
static herr_t
2923
H5D__virtual_pre_io_process_mapping(H5D_dset_io_info_t *dset_info, H5S_t *file_space, H5S_t *mem_space,
2924
                                    hsize_t *tot_nelmts, H5O_storage_virtual_ent_t *curr_mapping)
2925
0
{
2926
0
    const H5D_t *dset = dset_info->dset;     /* Local pointer to dataset info */
2927
0
    hssize_t     select_nelmts;              /* Number of elements in selection */
2928
0
    hsize_t      bounds_start[H5S_MAX_RANK]; /* Selection bounds start */
2929
0
    hsize_t      bounds_end[H5S_MAX_RANK];   /* Selection bounds end */
2930
0
    int          rank        = 0;
2931
0
    bool         bounds_init = false; /* Whether bounds_start, bounds_end, and rank are valid */
2932
0
    size_t       j, k;                /* Local index variables */
2933
0
    herr_t       ret_value = SUCCEED; /* Return value */
2934
2935
0
    FUNC_ENTER_PACKAGE
2936
2937
    /* Sanity check that the virtual space has been patched by now */
2938
0
    assert(curr_mapping->virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
2939
2940
    /* Check for "printf" source dataset resolution */
2941
0
    if (curr_mapping->psfn_nsubs || curr_mapping->psdn_nsubs) {
2942
0
        bool partial_block;
2943
2944
0
        assert(curr_mapping->unlim_dim_virtual >= 0);
2945
2946
        /* Get selection bounds if necessary */
2947
0
        if (!bounds_init) {
2948
            /* Get rank of VDS */
2949
0
            if ((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0)
2950
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions");
2951
2952
            /* Get selection bounds */
2953
0
            if (H5S_SELECT_BOUNDS(file_space, bounds_start, bounds_end) < 0)
2954
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds");
2955
2956
            /* Adjust bounds_end to represent the extent just enclosing them
2957
             * (add 1) */
2958
0
            for (j = 0; j < (size_t)rank; j++)
2959
0
                bounds_end[j]++;
2960
2961
            /* Bounds are now initialized */
2962
0
            bounds_init = true;
2963
0
        } /* end if */
2964
2965
        /* Get index of first block in virtual selection */
2966
0
        curr_mapping->sub_dset_io_start = (size_t)H5S_hyper_get_first_inc_block(
2967
0
            curr_mapping->source_dset.virtual_select, bounds_start[curr_mapping->unlim_dim_virtual], NULL);
2968
2969
        /* Get index of first block outside of virtual selection */
2970
0
        curr_mapping->sub_dset_io_end = (size_t)H5S_hyper_get_first_inc_block(
2971
0
            curr_mapping->source_dset.virtual_select, bounds_end[curr_mapping->unlim_dim_virtual],
2972
0
            &partial_block);
2973
0
        if (partial_block)
2974
0
            curr_mapping->sub_dset_io_end++;
2975
0
        if (curr_mapping->sub_dset_io_end > curr_mapping->sub_dset_nused)
2976
0
            curr_mapping->sub_dset_io_end = curr_mapping->sub_dset_nused;
2977
2978
        /* Iterate over sub-source dsets */
2979
0
        for (j = curr_mapping->sub_dset_io_start; j < curr_mapping->sub_dset_io_end; j++) {
2980
            /* Check for clipped virtual selection */
2981
0
            if (!curr_mapping->sub_dset[j].clipped_virtual_select) {
2982
0
                hsize_t start[H5S_MAX_RANK];
2983
                /* This should only be NULL if this is a partial block */
2984
0
                assert((j == (curr_mapping->sub_dset_io_end - 1)) && partial_block);
2985
2986
                /* If the source space status is not correct, we must try to
2987
                 * open the source dataset to patch it */
2988
0
                if (curr_mapping->source_space_status != H5O_VIRTUAL_STATUS_CORRECT) {
2989
0
                    assert(!curr_mapping->sub_dset[j].dset);
2990
0
                    if (H5D__virtual_open_source_dset(dset, curr_mapping, &curr_mapping->sub_dset[j]) < 0)
2991
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset");
2992
0
                } /* end if */
2993
2994
                /* If we obtained a valid source space, we must create
2995
                 * clipped source and virtual selections, otherwise we
2996
                 * cannot do this and we will leave them NULL.  This doesn't
2997
                 * hurt anything because we can't do I/O because the dataset
2998
                 * must not have been found. */
2999
0
                if (curr_mapping->source_space_status == H5O_VIRTUAL_STATUS_CORRECT) {
3000
0
                    hsize_t tmp_dims[H5S_MAX_RANK];
3001
0
                    hsize_t vbounds_end[H5S_MAX_RANK];
3002
3003
                    /* Get bounds of virtual selection */
3004
0
                    if (H5S_SELECT_BOUNDS(curr_mapping->sub_dset[j].virtual_select, tmp_dims, vbounds_end) <
3005
0
                        0)
3006
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds");
3007
3008
0
                    assert(bounds_init);
3009
3010
                    /* Convert bounds to extent (add 1) */
3011
0
                    for (k = 0; k < (size_t)rank; k++)
3012
0
                        vbounds_end[k]++;
3013
3014
                    /* Temporarily set extent of virtual selection to bounds */
3015
0
                    if (H5S_set_extent(curr_mapping->sub_dset[j].virtual_select, vbounds_end) < 0)
3016
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace");
3017
3018
                    /* Get current VDS dimensions */
3019
0
                    if (H5S_get_simple_extent_dims(dset->shared->space, tmp_dims, NULL) < 0)
3020
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions");
3021
3022
                    /* Copy virtual selection */
3023
0
                    if (NULL == (curr_mapping->sub_dset[j].clipped_virtual_select =
3024
0
                                     H5S_copy(curr_mapping->sub_dset[j].virtual_select, false, true)))
3025
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection");
3026
3027
                    /* Clip virtual selection to real virtual extent */
3028
0
                    (void)memset(start, 0, sizeof(start));
3029
0
                    if (H5S_select_hyperslab(curr_mapping->sub_dset[j].clipped_virtual_select, H5S_SELECT_AND,
3030
0
                                             start, NULL, tmp_dims, NULL) < 0)
3031
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to clip hyperslab");
3032
3033
                    /* Project intersection of virtual space and clipped
3034
                     * virtual space onto source space (create
3035
                     * clipped_source_select) */
3036
0
                    if (H5S_select_project_intersection(
3037
0
                            curr_mapping->sub_dset[j].virtual_select, curr_mapping->source_select,
3038
0
                            curr_mapping->sub_dset[j].clipped_virtual_select,
3039
0
                            &curr_mapping->sub_dset[j].clipped_source_select, true) < 0)
3040
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
3041
0
                                    "can't project virtual intersection onto memory space");
3042
3043
                    /* Set extents of virtual_select and
3044
                     * clipped_virtual_select to virtual extent */
3045
0
                    if (H5S_set_extent(curr_mapping->sub_dset[j].virtual_select, tmp_dims) < 0)
3046
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace");
3047
0
                    if (H5S_set_extent(curr_mapping->sub_dset[j].clipped_virtual_select, tmp_dims) < 0)
3048
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace");
3049
0
                } /* end if */
3050
0
            }     /* end if */
3051
3052
            /* Only continue if we managed to obtain a
3053
             * clipped_virtual_select */
3054
0
            if (curr_mapping->sub_dset[j].clipped_virtual_select) {
3055
                /* Project intersection of file space and mapping virtual space
3056
                 * onto memory space */
3057
0
                if (H5S_select_project_intersection(file_space, mem_space,
3058
0
                                                    curr_mapping->sub_dset[j].clipped_virtual_select,
3059
0
                                                    &curr_mapping->sub_dset[j].projected_mem_space, true) < 0)
3060
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
3061
0
                                "can't project virtual intersection onto memory space");
3062
3063
                /* Check number of elements selected */
3064
0
                if ((select_nelmts =
3065
0
                         (hssize_t)H5S_GET_SELECT_NPOINTS(curr_mapping->sub_dset[j].projected_mem_space)) < 0)
3066
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL,
3067
0
                                "unable to get number of elements in selection");
3068
3069
                /* Check if anything is selected */
3070
0
                if (select_nelmts > (hssize_t)0) {
3071
                    /* Open source dataset */
3072
0
                    if (!curr_mapping->sub_dset[j].dset)
3073
                        /* Try to open dataset */
3074
0
                        if (H5D__virtual_open_source_dset(dset, curr_mapping, &curr_mapping->sub_dset[j]) < 0)
3075
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset");
3076
3077
                    /* If the source dataset is not open, mark the selected
3078
                     * elements as zero so projected_mem_space is freed */
3079
0
                    if (!curr_mapping->sub_dset[j].dset)
3080
0
                        select_nelmts = (hssize_t)0;
3081
0
                } /* end if */
3082
3083
                /* If there are not elements selected in this mapping, free
3084
                 * projected_mem_space, otherwise update tot_nelmts */
3085
0
                if (select_nelmts == (hssize_t)0) {
3086
0
                    if (H5S_close(curr_mapping->sub_dset[j].projected_mem_space) < 0)
3087
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected memory space");
3088
0
                    curr_mapping->sub_dset[j].projected_mem_space = NULL;
3089
0
                } /* end if */
3090
0
                else
3091
0
                    *tot_nelmts += (hsize_t)select_nelmts;
3092
0
            } /* end if */
3093
0
        }     /* end for */
3094
0
    }         /* end if */
3095
0
    else {
3096
0
        if (curr_mapping->source_dset.clipped_virtual_select) {
3097
            /* Project intersection of file space and mapping virtual space onto
3098
             * memory space */
3099
0
            if (H5S_select_project_intersection(file_space, mem_space,
3100
0
                                                curr_mapping->source_dset.clipped_virtual_select,
3101
0
                                                &curr_mapping->source_dset.projected_mem_space, true) < 0)
3102
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
3103
0
                            "can't project virtual intersection onto memory space");
3104
3105
            /* Check number of elements selected, add to tot_nelmts */
3106
0
            if ((select_nelmts =
3107
0
                     (hssize_t)H5S_GET_SELECT_NPOINTS(curr_mapping->source_dset.projected_mem_space)) < 0)
3108
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL,
3109
0
                            "unable to get number of elements in selection");
3110
3111
            /* Check if anything is selected */
3112
0
            if (select_nelmts > (hssize_t)0) {
3113
                /* Open source dataset */
3114
0
                if (!curr_mapping->source_dset.dset)
3115
                    /* Try to open dataset */
3116
0
                    if (H5D__virtual_open_source_dset(dset, curr_mapping, &curr_mapping->source_dset) < 0)
3117
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset");
3118
3119
                /* If the source dataset is not open, mark the selected elements
3120
                 * as zero so projected_mem_space is freed */
3121
0
                if (!curr_mapping->source_dset.dset)
3122
0
                    select_nelmts = (hssize_t)0;
3123
0
            } /* end if */
3124
3125
            /* If there are not elements selected in this mapping, free
3126
             * projected_mem_space, otherwise update tot_nelmts */
3127
0
            if (select_nelmts == (hssize_t)0) {
3128
0
                if (H5S_close(curr_mapping->source_dset.projected_mem_space) < 0)
3129
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected memory space");
3130
0
                curr_mapping->source_dset.projected_mem_space = NULL;
3131
0
            } /* end if */
3132
0
            else
3133
0
                *tot_nelmts += (hsize_t)select_nelmts;
3134
0
        } /* end if */
3135
0
        else {
3136
            /* If there is no clipped_dim_virtual, this must be an unlimited
3137
             * selection whose dataset was not found in the last call to
3138
             * H5Dget_space().  Do not attempt to open it as this might
3139
             * affect the extent and we are not going to recalculate it
3140
             * here. */
3141
0
            assert(curr_mapping->unlim_dim_virtual >= 0);
3142
0
            assert(!curr_mapping->source_dset.dset);
3143
0
        } /* end else */
3144
0
    }     /* end else */
3145
0
done:
3146
0
    FUNC_LEAVE_NOAPI(ret_value)
3147
0
} /* end H5D__virtual_pre_io_process_mapping() */
3148
3149
/*-------------------------------------------------------------------------
3150
 * Function:    H5D__virtual_pre_io
3151
 *
3152
 * Purpose:     Project all virtual mappings onto mem_space, with the
3153
 *              results stored in projected_mem_space for each mapping.
3154
 *              Opens all source datasets if possible.  The total number
3155
 *              of elements is stored in tot_nelmts.
3156
 *
3157
 * Return:      Non-negative on success/Negative on failure
3158
 *
3159
 *-------------------------------------------------------------------------
3160
 */
3161
static herr_t
3162
H5D__virtual_pre_io(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_t *storage, H5S_t *file_space,
3163
                    H5S_t *mem_space, hsize_t *tot_nelmts, H5RT_result_set_t *mappings)
3164
0
{
3165
0
    herr_t ret_value = SUCCEED; /* Return value */
3166
3167
0
    FUNC_ENTER_PACKAGE
3168
3169
    /* Sanity check */
3170
0
    assert(storage);
3171
0
    assert(mem_space);
3172
0
    assert(file_space);
3173
0
    assert(tot_nelmts);
3174
3175
    /* Initialize tot_nelmts */
3176
0
    *tot_nelmts = 0;
3177
3178
    /* Iterate over the mappings */
3179
0
    if (mappings) {
3180
        /* First, iterate over the mappings with an intersection found via the tree */
3181
0
        for (size_t i = 0; i < mappings->count; i++) {
3182
0
            H5RT_leaf_t *curr_leaf = mappings->results[i];
3183
0
            assert(curr_leaf);
3184
3185
0
            if (H5D__virtual_pre_io_process_mapping(dset_info, file_space, mem_space, tot_nelmts,
3186
0
                                                    (H5O_storage_virtual_ent_t *)curr_leaf->record) < 0)
3187
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't process mapping for pre I/O");
3188
0
        }
3189
3190
        /* Iterate over the mappings that are not stored in the tree */
3191
0
        for (size_t i = 0; i < storage->not_in_tree_nused; i++) {
3192
0
            if (H5D__virtual_pre_io_process_mapping(dset_info, file_space, mem_space, tot_nelmts,
3193
0
                                                    storage->not_in_tree_list[i]) < 0)
3194
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't process mapping for pre I/O");
3195
0
        }
3196
0
    }
3197
0
    else {
3198
        /* No tree - iterate over all mappings directly */
3199
0
        for (size_t i = 0; i < storage->list_nused; i++) {
3200
0
            if (H5D__virtual_pre_io_process_mapping(dset_info, file_space, mem_space, tot_nelmts,
3201
0
                                                    &storage->list[i]) < 0)
3202
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't process mapping for pre I/O");
3203
0
        }
3204
0
    }
3205
3206
0
done:
3207
0
    FUNC_LEAVE_NOAPI(ret_value)
3208
0
} /* end H5D__virtual_pre_io() */
3209
3210
/*-------------------------------------------------------------------------
3211
 * Function:    H5D__virtual_post_io
3212
 *
3213
 * Purpose:     Frees memory structures allocated by H5D__virtual_pre_io.
3214
 *
3215
 * Return:      Non-negative on success/Negative on failure
3216
 *
3217
 *-------------------------------------------------------------------------
3218
 */
3219
static herr_t
3220
H5D__virtual_post_io(H5O_storage_virtual_t *storage, H5RT_result_set_t *mappings)
3221
0
{
3222
0
    size_t i;                   /* Local index variables */
3223
0
    herr_t ret_value = SUCCEED; /* Return value */
3224
3225
0
    FUNC_ENTER_PACKAGE
3226
3227
    /* Sanity check */
3228
0
    assert(storage);
3229
3230
0
    if (mappings) {
3231
        /* Iterate over mappings in tree */
3232
0
        for (i = 0; i < mappings->count; i++) {
3233
0
            H5RT_leaf_t *curr_leaf = mappings->results[i];
3234
0
            assert(curr_leaf);
3235
3236
0
            if (H5D__virtual_close_mapping(curr_leaf->record) < 0)
3237
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't process mapping for pre I/O");
3238
0
        }
3239
3240
        /* Iterate over the mappings that are not stored in the tree */
3241
0
        for (i = 0; i < storage->not_in_tree_nused; i++) {
3242
0
            if (H5D__virtual_close_mapping(storage->not_in_tree_list[i]) < 0)
3243
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't process mapping for pre I/O");
3244
0
        }
3245
0
    }
3246
0
    else {
3247
        /* Iterate over all mappings */
3248
0
        for (i = 0; i < storage->list_nused; i++)
3249
0
            if (H5D__virtual_close_mapping(&storage->list[i]) < 0)
3250
0
                HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "failed to close mapping");
3251
0
    }
3252
3253
0
done:
3254
0
    FUNC_LEAVE_NOAPI(ret_value)
3255
0
} /* end H5D__virtual_post_io() */
3256
3257
/*-------------------------------------------------------------------------
3258
 * Function:    H5D__virtual_read_one_src
3259
 *
3260
 * Purpose:     Read from a single source dataset in a virtual dataset.
3261
 *
3262
 * Return:      Non-negative on success/Negative on failure
3263
 *
3264
 *-------------------------------------------------------------------------
3265
 */
3266
static herr_t
3267
H5D__virtual_read_one_src(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_srcdset_t *source_dset)
3268
0
{
3269
0
    H5S_t             *projected_src_space = NULL; /* File space for selection in a single source dataset */
3270
0
    H5D_dset_io_info_t source_dinfo;               /* Dataset info for source dataset read */
3271
0
    herr_t             ret_value = SUCCEED;        /* Return value */
3272
3273
0
    FUNC_ENTER_PACKAGE
3274
3275
0
    assert(source_dset);
3276
3277
    /* Only perform I/O if there is a projected memory space, otherwise there
3278
     * were no elements in the projection or the source dataset could not be
3279
     * opened */
3280
0
    if (source_dset->projected_mem_space) {
3281
0
        assert(source_dset->dset);
3282
0
        assert(source_dset->clipped_source_select);
3283
3284
        /* Project intersection of file space and mapping virtual space onto
3285
         * mapping source space */
3286
0
        if (H5S_select_project_intersection(source_dset->clipped_virtual_select,
3287
0
                                            source_dset->clipped_source_select, dset_info->file_space,
3288
0
                                            &projected_src_space, true) < 0)
3289
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
3290
0
                        "can't project virtual intersection onto source space");
3291
3292
0
        {
3293
            /* Initialize source_dinfo */
3294
0
            source_dinfo.dset       = source_dset->dset;
3295
0
            source_dinfo.mem_space  = source_dset->projected_mem_space;
3296
0
            source_dinfo.file_space = projected_src_space;
3297
0
            source_dinfo.buf.vp     = dset_info->buf.vp;
3298
0
            source_dinfo.mem_type   = dset_info->type_info.dst_type;
3299
3300
            /* Read in the point (with the custom VL memory allocator) */
3301
0
            if (H5D__read(1, &source_dinfo) < 0)
3302
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset");
3303
0
        }
3304
3305
        /* Close projected_src_space */
3306
0
        if (H5S_close(projected_src_space) < 0)
3307
0
            HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space");
3308
0
        projected_src_space = NULL;
3309
0
    } /* end if */
3310
3311
0
done:
3312
    /* Release allocated resources */
3313
0
    if (projected_src_space) {
3314
0
        assert(ret_value < 0);
3315
0
        if (H5S_close(projected_src_space) < 0)
3316
0
            HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space");
3317
0
    } /* end if */
3318
3319
0
    FUNC_LEAVE_NOAPI(ret_value)
3320
0
} /* end H5D__virtual_read_one_src() */
3321
3322
/*-------------------------------------------------------------------------
3323
 * Function:    H5D__virtual_read
3324
 *
3325
 * Purpose:     Read from a virtual dataset.
3326
 *
3327
 * Return:      Non-negative on success/Negative on failure
3328
 *
3329
 *-------------------------------------------------------------------------
3330
 */
3331
static herr_t
3332
H5D__virtual_read(H5D_io_info_t H5_ATTR_NDEBUG_UNUSED *io_info, H5D_dset_io_info_t *dset_info)
3333
0
{
3334
0
    H5O_storage_virtual_t *storage;                     /* Convenient pointer into layout struct */
3335
0
    hsize_t                tot_nelmts;                  /* Total number of elements mapped to mem_space */
3336
0
    H5S_t                 *fill_space = NULL;           /* Space to fill with fill value */
3337
0
    size_t                 nelmts;                      /* Number of elements to process */
3338
0
    size_t                 i, j;                        /* Local index variables */
3339
0
    herr_t                 ret_value         = SUCCEED; /* Return value */
3340
0
    bool                   should_build_tree = false;   /* Whether to build a spatial tree */
3341
0
    H5RT_result_set_t     *mappings          = NULL;    /* Search results from R-tree */
3342
0
    hsize_t                min[H5S_MAX_RANK];
3343
0
    hsize_t                max[H5S_MAX_RANK];
3344
3345
0
    FUNC_ENTER_PACKAGE
3346
3347
    /* Sanity check */
3348
0
    assert(io_info);
3349
0
    assert(dset_info);
3350
0
    assert(dset_info->buf.vp);
3351
0
    assert(dset_info->mem_space);
3352
0
    assert(dset_info->file_space);
3353
3354
0
    storage = &(dset_info->dset->shared->layout.storage.u.virt);
3355
0
    assert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
3356
3357
    /* Initialize nelmts */
3358
0
    nelmts = H5S_GET_SELECT_NPOINTS(dset_info->file_space);
3359
3360
0
    memset(min, 0, sizeof(min));
3361
0
    memset(max, 0, sizeof(max));
3362
#ifdef H5_HAVE_PARALLEL
3363
    /* Parallel reads are not supported (yet) */
3364
    if (H5F_HAS_FEATURE(dset_info->dset->oloc.file, H5FD_FEAT_HAS_MPI))
3365
        HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel reads not supported on virtual datasets");
3366
#endif /* H5_HAVE_PARALLEL */
3367
3368
    /* Initialize layout if necessary */
3369
0
    if (!storage->init)
3370
0
        if (H5D__virtual_init_all(dset_info->dset) < 0)
3371
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize virtual layout");
3372
3373
0
    if (H5D__should_build_tree(storage, dset_info->dset->shared->dapl_id, &should_build_tree) < 0)
3374
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't determine if should build VDS tree");
3375
3376
0
    if (should_build_tree) {
3377
0
        int rank = 0;
3378
3379
        /* Get the rank of the dataset */
3380
0
        if ((rank = H5S_GET_EXTENT_NDIMS(dset_info->dset->shared->space)) < 0 || rank >= H5S_MAX_RANK)
3381
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset rank");
3382
3383
0
        if (rank == 0)
3384
0
            HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "virtual dataset has no rank");
3385
3386
0
        if (H5D__virtual_build_tree(storage, rank) < 0)
3387
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't build virtual mapping tree");
3388
0
    }
3389
3390
0
    if (storage->tree && nelmts > 0) {
3391
        /* Perform a spatial tree search to get a list of mappings
3392
         * whose virtual selection intersects the IO operation */
3393
0
        if (H5S_SELECT_BOUNDS(dset_info->file_space, min, max) < 0)
3394
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds");
3395
3396
0
        if (H5RT_search(storage->tree, min, max, &mappings) < 0)
3397
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "R-tree search failed");
3398
0
    }
3399
3400
    /* Prepare for I/O operation */
3401
0
    if (H5D__virtual_pre_io(dset_info, storage, dset_info->file_space, dset_info->mem_space, &tot_nelmts,
3402
0
                            mappings) < 0)
3403
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation");
3404
3405
    /* Iterate over mappings */
3406
0
    if (mappings) {
3407
        /* Iterate over intersections in tree */
3408
0
        for (i = 0; i < mappings->count; i++) {
3409
0
            H5RT_leaf_t *curr_leaf = mappings->results[i];
3410
0
            assert(curr_leaf);
3411
3412
0
            if (H5D__virtual_read_one_mapping(dset_info, curr_leaf->record) < 0)
3413
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset");
3414
0
        }
3415
3416
        /* Iterate over not-in-tree mappings */
3417
0
        for (i = 0; i < storage->not_in_tree_nused; i++) {
3418
0
            if (H5D__virtual_read_one_mapping(dset_info, storage->not_in_tree_list[i]) < 0)
3419
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset");
3420
0
        }
3421
0
    }
3422
0
    else {
3423
        /* Iterate over all mappings */
3424
0
        for (i = 0; i < storage->list_nused; i++) {
3425
0
            if (H5D__virtual_read_one_mapping(dset_info, &storage->list[i]) < 0)
3426
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset");
3427
0
        } /* end for */
3428
0
    }
3429
3430
    /* Fill unmapped part of buffer with fill value */
3431
0
    if (tot_nelmts < nelmts) {
3432
0
        H5D_fill_value_t fill_status; /* Fill value status */
3433
3434
        /* Check the fill value status */
3435
0
        if (H5P_is_fill_value_defined(&dset_info->dset->shared->dcpl_cache.fill, &fill_status) < 0)
3436
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if fill value defined");
3437
3438
        /* Always write fill value to memory buffer unless it is undefined */
3439
0
        if (fill_status != H5D_FILL_VALUE_UNDEFINED) {
3440
            /* Start with fill space equal to memory space */
3441
0
            if (NULL == (fill_space = H5S_copy(dset_info->mem_space, false, true)))
3442
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy memory selection");
3443
3444
            /* Iterate over mappings */
3445
0
            for (i = 0; i < storage->list_nused; i++)
3446
                /* Check for "printf" source dataset resolution */
3447
0
                if (storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
3448
                    /* Iterate over sub-source dsets */
3449
0
                    for (j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++)
3450
0
                        if (storage->list[i].sub_dset[j].projected_mem_space)
3451
0
                            if (H5S_select_subtract(fill_space,
3452
0
                                                    storage->list[i].sub_dset[j].projected_mem_space) < 0)
3453
0
                                HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection");
3454
0
                } /* end if */
3455
0
                else if (storage->list[i].source_dset.projected_mem_space)
3456
                    /* Subtract projected memory space from fill space */
3457
0
                    if (H5S_select_subtract(fill_space, storage->list[i].source_dset.projected_mem_space) < 0)
3458
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection");
3459
3460
            /* Write fill values to memory buffer */
3461
0
            if (H5D__fill(dset_info->dset->shared->dcpl_cache.fill.buf, dset_info->dset->shared->type,
3462
0
                          dset_info->buf.vp, dset_info->type_info.mem_type, fill_space) < 0)
3463
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "filling buf failed");
3464
3465
#ifndef NDEBUG
3466
            /* Make sure the total number of elements written (including fill
3467
             * values) >= nelmts */
3468
            {
3469
                hssize_t select_nelmts; /* Number of elements in selection */
3470
3471
                /* Get number of elements in fill dataspace */
3472
                if ((select_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(fill_space)) < 0)
3473
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL,
3474
                                "unable to get number of elements in selection");
3475
3476
                /* Verify number of elements is correct.  Note that since we
3477
                 * don't check for overlap we can't assert that these are equal
3478
                 */
3479
                assert((tot_nelmts + (hsize_t)select_nelmts) >= nelmts);
3480
            } /* end block */
3481
#endif        /* NDEBUG */
3482
0
        }     /* end if */
3483
0
    }         /* end if */
3484
3485
0
done:
3486
    /* Cleanup I/O operation */
3487
0
    if (H5D__virtual_post_io(storage, mappings) < 0)
3488
0
        HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't cleanup I/O operation");
3489
3490
0
    if (mappings)
3491
0
        if (H5RT_free_results(mappings) < 0)
3492
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free R-tree search results");
3493
3494
    /* Close fill space */
3495
0
    if (fill_space)
3496
0
        if (H5S_close(fill_space) < 0)
3497
0
            HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close fill space");
3498
3499
0
    FUNC_LEAVE_NOAPI(ret_value)
3500
0
} /* end H5D__virtual_read() */
3501
3502
/*-------------------------------------------------------------------------
3503
 * Function:    H5D__virtual_write_one_src
3504
 *
3505
 * Purpose:     Write to a single source dataset in a virtual dataset.
3506
 *
3507
 * Return:      Non-negative on success/Negative on failure
3508
 *
3509
 *-------------------------------------------------------------------------
3510
 */
3511
static herr_t
3512
H5D__virtual_write_one_src(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_srcdset_t *source_dset)
3513
0
{
3514
0
    H5S_t             *projected_src_space = NULL; /* File space for selection in a single source dataset */
3515
0
    H5D_dset_io_info_t source_dinfo;               /* Dataset info for source dataset write */
3516
0
    herr_t             ret_value = SUCCEED;        /* Return value */
3517
3518
0
    FUNC_ENTER_PACKAGE
3519
3520
0
    assert(source_dset);
3521
3522
    /* Only perform I/O if there is a projected memory space, otherwise there
3523
     * were no elements in the projection */
3524
0
    if (source_dset->projected_mem_space) {
3525
0
        assert(source_dset->dset);
3526
0
        assert(source_dset->clipped_source_select);
3527
3528
        /* In the future we may wish to extent this implementation to extend
3529
         * source datasets if a write to a virtual dataset goes past the current
3530
         * extent in the unlimited dimension.  -NAF */
3531
        /* Project intersection of file space and mapping virtual space onto
3532
         * mapping source space */
3533
0
        if (H5S_select_project_intersection(source_dset->clipped_virtual_select,
3534
0
                                            source_dset->clipped_source_select, dset_info->file_space,
3535
0
                                            &projected_src_space, true) < 0)
3536
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL,
3537
0
                        "can't project virtual intersection onto source space");
3538
3539
0
        {
3540
            /* Initialize source_dinfo */
3541
0
            source_dinfo.dset       = source_dset->dset;
3542
0
            source_dinfo.mem_space  = source_dset->projected_mem_space;
3543
0
            source_dinfo.file_space = projected_src_space;
3544
0
            source_dinfo.buf.cvp    = dset_info->buf.cvp;
3545
0
            source_dinfo.mem_type   = dset_info->type_info.dst_type;
3546
3547
            /* Read in the point (with the custom VL memory allocator) */
3548
0
            if (H5D__write(1, &source_dinfo) < 0)
3549
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset");
3550
0
        }
3551
3552
        /* Close projected_src_space */
3553
0
        if (H5S_close(projected_src_space) < 0)
3554
0
            HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space");
3555
0
        projected_src_space = NULL;
3556
0
    } /* end if */
3557
3558
0
done:
3559
    /* Release allocated resources */
3560
0
    if (projected_src_space) {
3561
0
        assert(ret_value < 0);
3562
0
        if (H5S_close(projected_src_space) < 0)
3563
0
            HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space");
3564
0
    } /* end if */
3565
3566
0
    FUNC_LEAVE_NOAPI(ret_value)
3567
0
} /* end H5D__virtual_write_one_src() */
3568
3569
/*-------------------------------------------------------------------------
3570
 * Function:    H5D__virtual_write
3571
 *
3572
 * Purpose:     Write to a virtual dataset.
3573
 *
3574
 * Return:      Non-negative on success/Negative on failure
3575
 *
3576
 *-------------------------------------------------------------------------
3577
 */
3578
static herr_t
3579
H5D__virtual_write(H5D_io_info_t H5_ATTR_NDEBUG_UNUSED *io_info, H5D_dset_io_info_t *dset_info)
3580
0
{
3581
0
    H5O_storage_virtual_t *storage;                     /* Convenient pointer into layout struct */
3582
0
    hsize_t                tot_nelmts;                  /* Total number of elements mapped to mem_space */
3583
0
    size_t                 nelmts;                      /* Number of elements to process */
3584
0
    size_t                 i;                           /* Local index variables */
3585
0
    herr_t                 ret_value         = SUCCEED; /* Return value */
3586
0
    bool                   should_build_tree = false;   /* Whether to build a spatial tree */
3587
0
    H5RT_result_set_t     *mappings          = NULL;    /* Search results from R-tree */
3588
0
    hsize_t                min[H5S_MAX_RANK];
3589
0
    hsize_t                max[H5S_MAX_RANK];
3590
3591
0
    FUNC_ENTER_PACKAGE
3592
3593
    /* Sanity check */
3594
0
    assert(io_info);
3595
0
    assert(dset_info);
3596
0
    assert(dset_info->buf.cvp);
3597
0
    assert(dset_info->mem_space);
3598
0
    assert(dset_info->file_space);
3599
3600
0
    storage = &(dset_info->dset->shared->layout.storage.u.virt);
3601
0
    assert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
3602
3603
    /* Initialize nelmts */
3604
0
    nelmts = H5S_GET_SELECT_NPOINTS(dset_info->file_space);
3605
3606
0
    memset(min, 0, sizeof(min));
3607
0
    memset(max, 0, sizeof(max));
3608
#ifdef H5_HAVE_PARALLEL
3609
    /* Parallel writes are not supported (yet) */
3610
    if (H5F_HAS_FEATURE(dset_info->dset->oloc.file, H5FD_FEAT_HAS_MPI))
3611
        HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel writes not supported on virtual datasets");
3612
#endif /* H5_HAVE_PARALLEL */
3613
3614
    /* Initialize layout if necessary */
3615
0
    if (!storage->init)
3616
0
        if (H5D__virtual_init_all(dset_info->dset) < 0)
3617
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize virtual layout");
3618
3619
0
    if (H5D__should_build_tree(storage, dset_info->dset->shared->dapl_id, &should_build_tree) < 0)
3620
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't determine if should build VDS tree");
3621
3622
0
    if (should_build_tree) {
3623
0
        int rank = 0;
3624
3625
        /* Get the rank of the dataset */
3626
0
        if ((rank = H5S_GET_EXTENT_NDIMS(dset_info->dset->shared->space)) < 0 || rank >= H5S_MAX_RANK)
3627
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset rank");
3628
3629
0
        if (rank == 0)
3630
0
            HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "virtual dataset has no rank");
3631
3632
0
        if (H5D__virtual_build_tree(storage, rank) < 0)
3633
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't build virtual mapping tree");
3634
0
    }
3635
3636
0
    if (storage->tree && nelmts > 0) {
3637
        /* Perform a spatial tree search to get a list of mappings
3638
         * whose virtual selection intersects the IO operation */
3639
0
        if (H5S_SELECT_BOUNDS(dset_info->file_space, min, max) < 0)
3640
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds");
3641
3642
0
        if (H5RT_search(storage->tree, min, max, &mappings) < 0)
3643
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "R-tree search failed");
3644
0
    }
3645
3646
    /* Prepare for I/O operation */
3647
0
    if (H5D__virtual_pre_io(dset_info, storage, dset_info->file_space, dset_info->mem_space, &tot_nelmts,
3648
0
                            mappings) < 0)
3649
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation");
3650
3651
    /* Fail if there are unmapped parts of the selection as they would not be
3652
     * written */
3653
0
    if (tot_nelmts != nelmts)
3654
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
3655
0
                    "write requested to unmapped portion of virtual dataset");
3656
3657
0
    if (mappings) {
3658
        /* Iterate over intersections in tree */
3659
0
        for (i = 0; i < mappings->count; i++) {
3660
0
            H5RT_leaf_t *curr_leaf = mappings->results[i];
3661
0
            assert(curr_leaf);
3662
3663
0
            if (H5D__virtual_write_one_mapping(dset_info, curr_leaf->record) < 0)
3664
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset");
3665
0
        }
3666
3667
        /* Iterate over not-in-tree mappings */
3668
0
        for (i = 0; i < storage->not_in_tree_nused; i++) {
3669
0
            if (H5D__virtual_write_one_mapping(dset_info, storage->not_in_tree_list[i]) < 0)
3670
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset");
3671
0
        }
3672
0
    }
3673
0
    else {
3674
        /* Iterate over all mappings */
3675
0
        for (i = 0; i < storage->list_nused; i++) {
3676
0
            if (H5D__virtual_write_one_mapping(dset_info, &storage->list[i]) < 0)
3677
0
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write to virtual mapping");
3678
0
        }
3679
0
    }
3680
3681
0
done:
3682
    /* Cleanup I/O operation */
3683
0
    if (H5D__virtual_post_io(storage, mappings) < 0)
3684
0
        HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't cleanup I/O operation");
3685
3686
0
    if (mappings)
3687
0
        H5RT_free_results(mappings);
3688
3689
0
    FUNC_LEAVE_NOAPI(ret_value)
3690
0
} /* end H5D__virtual_write() */
3691
3692
/*-------------------------------------------------------------------------
3693
 * Function:    H5D__virtual_flush
3694
 *
3695
 * Purpose:     Writes all dirty data to disk.
3696
 *
3697
 * Return:      Non-negative on success/Negative on failure
3698
 *
3699
 *-------------------------------------------------------------------------
3700
 */
3701
static herr_t
3702
H5D__virtual_flush(H5D_t *dset)
3703
0
{
3704
0
    H5O_storage_virtual_t *storage;             /* Convenient pointer into layout struct */
3705
0
    size_t                 i, j;                /* Local index variables */
3706
0
    herr_t                 ret_value = SUCCEED; /* Return value */
3707
3708
0
    FUNC_ENTER_PACKAGE
3709
3710
    /* Sanity check */
3711
0
    assert(dset);
3712
3713
0
    storage = &dset->shared->layout.storage.u.virt;
3714
3715
    /* Flush only open datasets */
3716
0
    for (i = 0; i < storage->list_nused; i++)
3717
        /* Check for "printf" source dataset resolution */
3718
0
        if (storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
3719
            /* Iterate over sub-source dsets */
3720
0
            for (j = 0; j < storage->list[i].sub_dset_nused; j++)
3721
0
                if (storage->list[i].sub_dset[j].dset)
3722
                    /* Flush source dataset */
3723
0
                    if (H5D__flush_real(storage->list[i].sub_dset[j].dset) < 0)
3724
0
                        HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush source dataset");
3725
0
        } /* end if */
3726
0
        else if (storage->list[i].source_dset.dset)
3727
            /* Flush source dataset */
3728
0
            if (H5D__flush_real(storage->list[i].source_dset.dset) < 0)
3729
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to flush source dataset");
3730
3731
0
done:
3732
0
    FUNC_LEAVE_NOAPI(ret_value)
3733
0
} /* end H5D__virtual_flush() */
3734
3735
/*-------------------------------------------------------------------------
3736
 * Function:    H5D__virtual_hold_source_dset_files
3737
 *
3738
 * Purpose:     Hold open the source files that are open, during a refresh event
3739
 *
3740
 * Return:      Non-negative on success/Negative on failure
3741
 *
3742
 *-------------------------------------------------------------------------
3743
 */
3744
herr_t
3745
H5D__virtual_hold_source_dset_files(const H5D_t *dset, H5D_virtual_held_file_t **head)
3746
0
{
3747
0
    H5O_storage_virtual_t   *storage;             /* Convenient pointer into layout struct */
3748
0
    H5D_virtual_held_file_t *tmp;                 /* Temporary held file node */
3749
0
    size_t                   i;                   /* Local index variable */
3750
0
    herr_t                   ret_value = SUCCEED; /* Return value */
3751
3752
0
    FUNC_ENTER_PACKAGE
3753
3754
    /* Sanity check */
3755
0
    assert(dset);
3756
0
    assert(head && NULL == *head);
3757
3758
    /* Set the convenience pointer */
3759
0
    storage = &dset->shared->layout.storage.u.virt;
3760
3761
    /* Hold only files for open datasets */
3762
0
    for (i = 0; i < storage->list_nused; i++)
3763
        /* Check for "printf" source dataset resolution */
3764
0
        if (storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
3765
0
            size_t j; /* Local index variable */
3766
3767
            /* Iterate over sub-source dsets */
3768
0
            for (j = 0; j < storage->list[i].sub_dset_nused; j++)
3769
0
                if (storage->list[i].sub_dset[j].dset) {
3770
                    /* Hold open the file */
3771
0
                    H5F_INCR_NOPEN_OBJS(storage->list[i].sub_dset[j].dset->oloc.file);
3772
3773
                    /* Allocate a node for this file */
3774
0
                    if (NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
3775
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node");
3776
3777
                    /* Set up node & connect to list */
3778
0
                    tmp->file = storage->list[i].sub_dset[j].dset->oloc.file;
3779
0
                    tmp->next = *head;
3780
0
                    *head     = tmp;
3781
0
                } /* end if */
3782
0
        }         /* end if */
3783
0
        else if (storage->list[i].source_dset.dset) {
3784
            /* Hold open the file */
3785
0
            H5F_INCR_NOPEN_OBJS(storage->list[i].source_dset.dset->oloc.file);
3786
3787
            /* Allocate a node for this file */
3788
0
            if (NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
3789
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node");
3790
3791
            /* Set up node & connect to list */
3792
0
            tmp->file = storage->list[i].source_dset.dset->oloc.file;
3793
0
            tmp->next = *head;
3794
0
            *head     = tmp;
3795
0
        } /* end if */
3796
3797
0
done:
3798
0
    if (ret_value < 0)
3799
        /* Release hold on files and delete list on error */
3800
0
        if (*head && H5D__virtual_release_source_dset_files(*head) < 0)
3801
0
            HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't release source datasets' files held open");
3802
3803
0
    FUNC_LEAVE_NOAPI(ret_value)
3804
0
} /* end H5D__virtual_hold_source_dset_files() */
3805
3806
/*-------------------------------------------------------------------------
3807
 * Function:    H5D__virtual_refresh_source_dset
3808
 *
3809
 * Purpose:     Refresh a source dataset
3810
 *
3811
 * Return:      Non-negative on success/Negative on failure
3812
 *
3813
 *-------------------------------------------------------------------------
3814
 */
3815
static herr_t
3816
H5D__virtual_refresh_source_dset(H5D_t **dset)
3817
0
{
3818
0
    hid_t          temp_id   = H5I_INVALID_HID; /* Temporary dataset identifier */
3819
0
    H5VL_object_t *vol_obj   = NULL;            /* VOL object stored with the ID */
3820
0
    herr_t         ret_value = SUCCEED;         /* Return value */
3821
3822
0
    FUNC_ENTER_PACKAGE
3823
3824
    /* Sanity check */
3825
0
    assert(dset && *dset);
3826
3827
    /* Get a temporary identifier for this source dataset */
3828
0
    if ((temp_id = H5VL_wrap_register(H5I_DATASET, *dset, false)) < 0)
3829
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "can't register (temporary) source dataset ID");
3830
3831
    /* Refresh source dataset */
3832
0
    if (H5D__refresh(*dset, temp_id) < 0)
3833
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset");
3834
3835
    /* Discard the identifier & replace the dataset */
3836
0
    if (NULL == (vol_obj = (H5VL_object_t *)H5I_remove(temp_id)))
3837
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't unregister source dataset ID");
3838
0
    if (NULL == (*dset = (H5D_t *)H5VL_object_unwrap(vol_obj)))
3839
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve library object from VOL object");
3840
0
    H5VL_OBJ_DATA_RESET(vol_obj);
3841
3842
0
done:
3843
0
    if (vol_obj && H5VL_free_object(vol_obj) < 0)
3844
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to free VOL object");
3845
3846
0
    FUNC_LEAVE_NOAPI(ret_value)
3847
0
} /* end H5D__virtual_refresh_source_dset() */
3848
3849
/*-------------------------------------------------------------------------
3850
 * Function:    H5D__virtual_refresh_source_dsets
3851
 *
3852
 * Purpose:     Refresh the source datasets
3853
 *
3854
 * Return:      Non-negative on success/Negative on failure
3855
 *
3856
 *-------------------------------------------------------------------------
3857
 */
3858
herr_t
3859
H5D__virtual_refresh_source_dsets(H5D_t *dset)
3860
0
{
3861
0
    H5O_storage_virtual_t *storage;             /* Convenient pointer into layout struct */
3862
0
    size_t                 i;                   /* Local index variable */
3863
0
    herr_t                 ret_value = SUCCEED; /* Return value */
3864
3865
0
    FUNC_ENTER_PACKAGE
3866
3867
    /* Sanity check */
3868
0
    assert(dset);
3869
3870
    /* Set convenience pointer */
3871
0
    storage = &dset->shared->layout.storage.u.virt;
3872
3873
    /* Refresh only open datasets */
3874
0
    for (i = 0; i < storage->list_nused; i++)
3875
        /* Check for "printf" source dataset resolution */
3876
0
        if (storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
3877
0
            size_t j; /* Local index variable */
3878
3879
            /* Iterate over sub-source datasets */
3880
0
            for (j = 0; j < storage->list[i].sub_dset_nused; j++)
3881
                /* Check if sub-source dataset is open */
3882
0
                if (storage->list[i].sub_dset[j].dset)
3883
                    /* Refresh sub-source dataset */
3884
0
                    if (H5D__virtual_refresh_source_dset(&storage->list[i].sub_dset[j].dset) < 0)
3885
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset");
3886
0
        } /* end if */
3887
0
        else
3888
            /* Check if source dataset is open */
3889
0
            if (storage->list[i].source_dset.dset)
3890
                /* Refresh source dataset */
3891
0
                if (H5D__virtual_refresh_source_dset(&storage->list[i].source_dset.dset) < 0)
3892
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset");
3893
3894
0
done:
3895
0
    FUNC_LEAVE_NOAPI(ret_value)
3896
0
} /* end H5D__virtual_refresh_source_dsets() */
3897
3898
/*-------------------------------------------------------------------------
3899
 * Function:    H5D__virtual_release_source_dset_files
3900
 *
3901
 * Purpose:     Release the hold on source files that are open, during a refresh event
3902
 *
3903
 * Return:      Non-negative on success/Negative on failure
3904
 *
3905
 *-------------------------------------------------------------------------
3906
 */
3907
herr_t
3908
H5D__virtual_release_source_dset_files(H5D_virtual_held_file_t *head)
3909
0
{
3910
0
    herr_t ret_value = SUCCEED; /* Return value */
3911
3912
0
    FUNC_ENTER_PACKAGE
3913
3914
    /* Release hold on files and delete list */
3915
0
    while (head) {
3916
0
        H5D_virtual_held_file_t *tmp = head->next; /* Temporary pointer to next node */
3917
3918
        /* Release hold on file */
3919
0
        H5F_DECR_NOPEN_OBJS(head->file);
3920
3921
        /* Attempt to close the file */
3922
        /* (Should always succeed, since the 'top' source file pointer is
3923
         *      essentially "private" to the virtual dataset, since it wasn't
3924
         *      opened through an API routine -QAK)
3925
         */
3926
0
        if (H5F_try_close(head->file, NULL) < 0)
3927
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close");
3928
3929
        /* Delete node */
3930
0
        (void)H5FL_FREE(H5D_virtual_held_file_t, head);
3931
3932
        /* Advance to next node */
3933
0
        head = tmp;
3934
0
    } /* end while */
3935
3936
0
done:
3937
0
    FUNC_LEAVE_NOAPI(ret_value)
3938
0
} /* end H5D__virtual_release_source_dset_files() */
3939
3940
/*-------------------------------------------------------------------------
3941
 * Function:    H5D__mappings_to_leaves
3942
 *
3943
 * Purpose:     Allocate leaf array and boolean array for construction of a
3944
 *               spatial tree from a list of mappings
3945
 *
3946
 * Parameters:  mappings : Pointer to array of mappings to be inserted
3947
 *              num_mappings: Number of mappings in the array
3948
 *              leaves_out: Pointer to array of leaves, one per mapping that should be inserted
3949
 *                          Allocated on success and must be freed by caller.
3950
 *              not_in_tree_out: Pointer to array of pointers to mappings NOT in tree.
3951
 *                               Allocated on success and must be freed by caller.
3952
 *              leaf_count: Pointer to number of leaves allocated in leaves_out.
3953
 *              not_in_tree_count: Pointer to number of entries in not_in_tree_out.
3954
 *              not_in_tree_nalloc: Pointer to allocated capacity of not_in_tree_out.
3955
 *
3956
 * Return:      Non-negative on success/Negative on failure
3957
 *
3958
 *-------------------------------------------------------------------------
3959
 */
3960
static herr_t
3961
H5D__mappings_to_leaves(H5O_storage_virtual_ent_t *mappings, size_t num_mappings, H5RT_leaf_t **leaves_out,
3962
                        H5O_storage_virtual_ent_t ***not_in_tree_out, size_t *leaf_count,
3963
                        size_t *not_in_tree_count, size_t *not_in_tree_nalloc)
3964
0
{
3965
0
    herr_t ret_value = SUCCEED;
3966
3967
0
    H5RT_leaf_t                *leaves_temp = NULL;
3968
0
    H5O_storage_virtual_ent_t **not_in_tree = NULL;
3969
3970
0
    H5O_storage_virtual_ent_t *curr_mapping         = NULL;
3971
0
    H5RT_leaf_t               *curr_leaf            = NULL;
3972
0
    size_t                     curr_leaf_count      = 0;
3973
0
    size_t                     curr_not_tree_count  = 0;
3974
0
    size_t                     not_in_tree_capacity = 0;
3975
0
    H5S_t                     *curr_space           = NULL;
3976
3977
0
    int rank = 0;
3978
3979
0
    FUNC_ENTER_PACKAGE
3980
3981
0
    assert(mappings);
3982
0
    assert(num_mappings > 0);
3983
0
    assert(leaf_count);
3984
0
    assert(leaves_out);
3985
0
    assert(not_in_tree_out);
3986
0
    assert(not_in_tree_count);
3987
0
    assert(not_in_tree_nalloc);
3988
3989
    /* Get rank from the first mapping's virtual selection */
3990
0
    if ((curr_space = mappings[0].source_dset.virtual_select) == NULL)
3991
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "first mapping has no virtual space");
3992
3993
0
    if ((rank = H5S_GET_EXTENT_NDIMS(curr_space)) < 0 || rank > H5S_MAX_RANK)
3994
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get rank of dataspace");
3995
3996
0
    if (rank == 0)
3997
0
        HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "mapping has zero-dimensional space");
3998
3999
    /* Allocate array of leaf structures */
4000
0
    if ((leaves_temp = (H5RT_leaf_t *)calloc(num_mappings, sizeof(H5RT_leaf_t))) == NULL)
4001
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate leaves array");
4002
4003
    /* Initialize not_in_tree list with initial capacity */
4004
0
    not_in_tree_capacity = H5D_VIRTUAL_NOT_IN_TREE_INIT_SIZE;
4005
4006
0
    if (NULL == (not_in_tree = (H5O_storage_virtual_ent_t **)H5MM_malloc(
4007
0
                     not_in_tree_capacity * sizeof(H5O_storage_virtual_ent_t *))))
4008
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "failed to allocate not_in_tree_list");
4009
4010
0
    for (size_t i = 0; i < num_mappings; i++) {
4011
0
        curr_mapping = &mappings[i];
4012
4013
0
        if (!(H5D_RTREE_SHOULD_INSERT(curr_mapping))) {
4014
            /* Add to not_in_tree list, growing if needed */
4015
0
            if (H5D__virtual_not_in_tree_add(&not_in_tree, &curr_not_tree_count, &not_in_tree_capacity,
4016
0
                                             curr_mapping) < 0)
4017
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "failed to add to not_in_tree_list");
4018
0
            continue;
4019
0
        }
4020
4021
        /* Initialize leaf with dynamic coordinate allocation */
4022
0
        curr_leaf = &leaves_temp[curr_leaf_count];
4023
0
        if (H5RT_leaf_init(curr_leaf, rank, (void *)curr_mapping) < 0)
4024
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't initialize R-tree leaf");
4025
4026
        /* Record is already set by H5RT_leaf_init */
4027
0
        assert(mappings[i].source_dset.virtual_select);
4028
0
        curr_space = mappings[i].source_dset.virtual_select;
4029
4030
        /* Get selection bounds */
4031
0
        if (H5S_SELECT_BOUNDS(curr_space, curr_leaf->min, curr_leaf->max) < 0)
4032
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get selection bounds");
4033
4034
0
        for (int d = 0; d < rank; d++) {
4035
            /* Validate bounds and compute midpoint safely */
4036
0
            if (curr_leaf->min[d] > curr_leaf->max[d])
4037
0
                HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "invalid selection bounds: min > max");
4038
0
            curr_leaf->mid[d] = curr_leaf->min[d] + (curr_leaf->max[d] - curr_leaf->min[d]) / 2;
4039
0
        }
4040
4041
0
        curr_leaf_count++;
4042
0
    }
4043
4044
0
    *leaves_out         = leaves_temp;
4045
0
    *leaf_count         = curr_leaf_count;
4046
0
    *not_in_tree_out    = not_in_tree;
4047
0
    *not_in_tree_count  = curr_not_tree_count;
4048
0
    *not_in_tree_nalloc = not_in_tree_capacity;
4049
0
done:
4050
0
    if (ret_value < 0) {
4051
0
        if (leaves_temp) {
4052
            /* Clean up coordinate arrays for initialized leaves */
4053
0
            for (size_t j = 0; j < curr_leaf_count; j++) {
4054
0
                H5RT_leaf_cleanup(&leaves_temp[j]);
4055
0
            }
4056
0
            free(leaves_temp);
4057
0
        }
4058
0
        if (not_in_tree)
4059
0
            H5MM_free(not_in_tree);
4060
0
    }
4061
4062
0
    FUNC_LEAVE_NOAPI(ret_value);
4063
0
} /* end H5D__mappings_to_leaves() */
4064
4065
/*-------------------------------------------------------------------------
4066
 * Function:    H5D__virtual_build_tree
4067
 *
4068
 * Purpose:     Build a spatial tree of mapping indices, and a list of
4069
 *              mappings not in the tree, and store them on
4070
 *              the provided virtual layout
4071
 *
4072
 * Parameters:  virt: The virtual layout with the mapping to build the
4073
 *              tree from. The tree will be stored at virt->tree,
4074
 *              and the list of non-tree mappings will be stored at
4075
 *              virt->not_in_tree_list.
4076
 *
4077
 * Return:      Non-negative on success/Negative on failure
4078
 *
4079
 *-------------------------------------------------------------------------
4080
 */
4081
static herr_t
4082
H5D__virtual_build_tree(H5O_storage_virtual_t *virt, int rank)
4083
0
{
4084
0
    H5O_storage_virtual_ent_t *mappings     = virt->list;
4085
0
    size_t                     num_mappings = virt->list_nused;
4086
4087
0
    H5RT_leaf_t                *leaves               = NULL;
4088
0
    size_t                      num_leaves           = 0;
4089
0
    H5O_storage_virtual_ent_t **not_in_tree_mappings = NULL;
4090
0
    size_t                      not_in_tree_count    = 0;
4091
0
    size_t                      not_in_tree_nalloc   = 0;
4092
0
    herr_t                      ret_value            = SUCCEED;
4093
4094
0
    FUNC_ENTER_PACKAGE
4095
4096
0
    assert(virt);
4097
4098
0
    if (H5D__mappings_to_leaves(mappings, num_mappings, &leaves, &not_in_tree_mappings, &num_leaves,
4099
0
                                &not_in_tree_count, &not_in_tree_nalloc) < 0)
4100
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to get leaves from mappings");
4101
4102
0
    if (num_leaves == 0) {
4103
        /* No tree to build */
4104
0
        virt->tree = NULL;
4105
0
        if (leaves) {
4106
0
            free(leaves);
4107
0
            leaves = NULL;
4108
0
        }
4109
0
    }
4110
0
    else {
4111
        /* Build the tree */
4112
0
        if ((virt->tree = H5RT_create(rank, leaves, num_leaves)) == NULL)
4113
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create mapping tree");
4114
        /* Tree takes ownership of leaves array and coordinate arrays */
4115
0
        leaves = NULL;
4116
0
    }
4117
4118
    /* Store not-in-tree mappings (regardless of whether tree was built) */
4119
0
    if (not_in_tree_count > 0) {
4120
0
        virt->not_in_tree_list   = not_in_tree_mappings;
4121
0
        virt->not_in_tree_nused  = not_in_tree_count;
4122
0
        virt->not_in_tree_nalloc = not_in_tree_nalloc;
4123
0
        not_in_tree_mappings     = NULL; /* Transfer ownership to virt */
4124
0
    }
4125
0
    else {
4126
        /* Clean up any existing allocation */
4127
0
        if (virt->not_in_tree_list) {
4128
0
            H5MM_free(virt->not_in_tree_list);
4129
0
        }
4130
0
        virt->not_in_tree_list   = NULL;
4131
0
        virt->not_in_tree_nused  = 0;
4132
0
        virt->not_in_tree_nalloc = 0;
4133
0
        if (not_in_tree_mappings) {
4134
0
            H5MM_free(not_in_tree_mappings);
4135
0
            not_in_tree_mappings = NULL;
4136
0
        }
4137
0
    }
4138
4139
0
done:
4140
0
    if (ret_value < 0) {
4141
0
        if (leaves) {
4142
            /* Clean up coordinate arrays and the leaf array */
4143
0
            for (size_t i = 0; i < num_leaves; i++) {
4144
0
                H5RT_leaf_cleanup(&leaves[i]);
4145
0
            }
4146
0
            free(leaves);
4147
0
        }
4148
0
        if (not_in_tree_mappings)
4149
0
            H5MM_free(not_in_tree_mappings);
4150
0
    }
4151
4152
0
    FUNC_LEAVE_NOAPI(ret_value)
4153
0
} /* end H5D__virtual_build_tree() */
4154
4155
/*-------------------------------------------------------------------------
4156
 * Function:    H5D__virtual_not_in_tree_grow
4157
 *
4158
 * Purpose:     Double the capacity of the not_in_tree_list buffer
4159
 *
4160
 * Return:      Non-negative on success/Negative on failure
4161
 *
4162
 *-------------------------------------------------------------------------
4163
 */
4164
static herr_t
4165
H5D__virtual_not_in_tree_grow(H5O_storage_virtual_ent_t ***list, size_t *nalloc)
4166
0
{
4167
0
    size_t                      new_capacity = 0;
4168
0
    H5O_storage_virtual_ent_t **new_list     = NULL;
4169
0
    herr_t                      ret_value    = SUCCEED;
4170
4171
0
    FUNC_ENTER_PACKAGE
4172
4173
0
    assert(list);
4174
0
    assert(*list);
4175
0
    assert(nalloc);
4176
4177
0
    new_capacity = *nalloc * 2;
4178
4179
    /* Overflow check */
4180
0
    if (new_capacity < *nalloc || new_capacity > (SIZE_MAX / sizeof(H5O_storage_virtual_ent_t *)))
4181
0
        HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "not_in_tree_list capacity overflow");
4182
4183
0
    if (NULL == (new_list = (H5O_storage_virtual_ent_t **)H5MM_realloc(
4184
0
                     *list, new_capacity * sizeof(H5O_storage_virtual_ent_t *))))
4185
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "failed to grow not_in_tree_list");
4186
4187
0
    *list   = new_list;
4188
0
    *nalloc = new_capacity;
4189
4190
0
done:
4191
0
    FUNC_LEAVE_NOAPI(ret_value)
4192
0
} /* end H5D__virtual_not_in_tree_grow() */
4193
4194
/*-------------------------------------------------------------------------
4195
 * Function:    H5D__virtual_not_in_tree_add
4196
 *
4197
 * Purpose:     Add a mapping to the not_in_tree_list, growing if necessary
4198
 *
4199
 * Return:      Non-negative on success/Negative on failure
4200
 *
4201
 *-------------------------------------------------------------------------
4202
 */
4203
static herr_t
4204
H5D__virtual_not_in_tree_add(H5O_storage_virtual_ent_t ***list, size_t *nused, size_t *nalloc,
4205
                             H5O_storage_virtual_ent_t *mapping)
4206
0
{
4207
0
    herr_t ret_value = SUCCEED;
4208
4209
0
    FUNC_ENTER_PACKAGE
4210
4211
0
    assert(list);
4212
0
    assert(*list);
4213
0
    assert(nused);
4214
0
    assert(nalloc);
4215
0
    assert(mapping);
4216
4217
    /* Grow buffer if full */
4218
0
    if (*nused >= *nalloc) {
4219
0
        if (H5D__virtual_not_in_tree_grow(list, nalloc) < 0)
4220
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "failed to grow not_in_tree_list");
4221
0
    }
4222
4223
0
    (*list)[*nused] = mapping;
4224
0
    (*nused)++;
4225
4226
0
done:
4227
0
    FUNC_LEAVE_NOAPI(ret_value)
4228
0
} /* end H5D__virtual_not_in_tree_add() */
4229
4230
/*-------------------------------------------------------------------------
4231
 * Function:    H5D__should_build_tree
4232
 *
4233
 * Purpose:     Determine whether to build a spatial tree of mapping indices
4234
 *              for the provided dataset layout
4235
 *
4236
 * Return:      Non-negative on success/Negative on failure
4237
 *
4238
 *-------------------------------------------------------------------------
4239
 */
4240
static herr_t
4241
H5D__should_build_tree(H5O_storage_virtual_t *storage, hid_t dapl_id, bool *should_build_tree)
4242
0
{
4243
0
    herr_t          ret_value         = SUCCEED;
4244
0
    H5P_genplist_t *dapl_plist        = NULL;
4245
0
    bool            tree_enabled_dapl = false;
4246
4247
0
    FUNC_ENTER_PACKAGE
4248
4249
0
    assert(storage);
4250
0
    assert(should_build_tree);
4251
0
    assert(dapl_id != H5I_INVALID_HID);
4252
4253
    /* Don't build if already exists */
4254
0
    if (storage->tree) {
4255
0
        *should_build_tree = false;
4256
0
        HGOTO_DONE(SUCCEED);
4257
0
    }
4258
4259
    /* Don't build if too few mappings */
4260
0
    if (storage->list_nused < H5D_VIRTUAL_TREE_THRESHOLD) {
4261
0
        *should_build_tree = false;
4262
0
        HGOTO_DONE(SUCCEED);
4263
0
    }
4264
4265
    /* Don't build if DAPL property has disabled the tree */
4266
0
    if (NULL == (dapl_plist = (H5P_genplist_t *)H5I_object(dapl_id)))
4267
0
        HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for dapl ID");
4268
4269
0
    if (H5P_get(dapl_plist, H5D_ACS_USE_TREE_NAME, &tree_enabled_dapl) < 0)
4270
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get virtual use tree flag");
4271
4272
0
    if (!tree_enabled_dapl) {
4273
0
        *should_build_tree = false;
4274
0
        HGOTO_DONE(SUCCEED);
4275
0
    }
4276
4277
0
    *should_build_tree = true;
4278
0
done:
4279
0
    FUNC_LEAVE_NOAPI(ret_value);
4280
0
} /* end H5D__should_build_tree() */
4281
4282
/*-------------------------------------------------------------------------
4283
 * Function:    H5D__virtual_read_one_mapping
4284
 *
4285
 * Purpose:     Read from a single mapping entry in a virtual dataset
4286
 *
4287
 * Return:      Non-negative on success/Negative on failure
4288
 *
4289
 *-------------------------------------------------------------------------
4290
 */
4291
static herr_t
4292
H5D__virtual_read_one_mapping(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_ent_t *mapping)
4293
0
{
4294
0
    herr_t ret_value = SUCCEED;
4295
4296
0
    FUNC_ENTER_PACKAGE
4297
4298
    /* Sanity check that the virtual space has been patched by now */
4299
0
    assert(mapping->virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
4300
4301
    /* Check for "printf" source dataset resolution */
4302
0
    if (mapping->psfn_nsubs || mapping->psdn_nsubs) {
4303
        /* Iterate over sub-source dsets */
4304
0
        for (size_t j = mapping->sub_dset_io_start; j < mapping->sub_dset_io_end; j++)
4305
0
            if (H5D__virtual_read_one_src(dset_info, &mapping->sub_dset[j]) < 0)
4306
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset");
4307
0
    } /* end if */
4308
0
    else
4309
        /* Read from source dataset */
4310
0
        if (H5D__virtual_read_one_src(dset_info, &mapping->source_dset) < 0)
4311
0
            HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset");
4312
4313
0
done:
4314
0
    FUNC_LEAVE_NOAPI(ret_value)
4315
0
} /* end H5D__virtual_read_one_mapping() */
4316
4317
/*-------------------------------------------------------------------------
4318
 * Function:    H5D__virtual_write_one_mapping
4319
 *
4320
 * Purpose:     Write to a single mapping entry in a virtual dataset
4321
 *
4322
 * Return:      Non-negative on success/Negative on failure
4323
 *
4324
 *-------------------------------------------------------------------------
4325
 */
4326
static herr_t
4327
H5D__virtual_write_one_mapping(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_ent_t *mapping)
4328
0
{
4329
0
    herr_t ret_value = SUCCEED;
4330
4331
0
    FUNC_ENTER_PACKAGE
4332
4333
    /* Sanity check that virtual space has been patched by now */
4334
0
    assert(mapping->virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
4335
4336
    /* Check for "printf" source dataset resolution */
4337
0
    if (mapping->psfn_nsubs || mapping->psdn_nsubs) {
4338
        /* Iterate over sub-source dsets */
4339
0
        for (size_t j = mapping->sub_dset_io_start; j < mapping->sub_dset_io_end; j++)
4340
0
            if (H5D__virtual_write_one_src(dset_info, &mapping->sub_dset[j]) < 0)
4341
0
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset");
4342
0
    }
4343
0
    else
4344
        /* Write to source dataset */
4345
0
        if (H5D__virtual_write_one_src(dset_info, &mapping->source_dset) < 0)
4346
0
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset");
4347
4348
0
done:
4349
0
    FUNC_LEAVE_NOAPI(ret_value)
4350
0
} /* end H5D__virtual_write_one_mapping() */
4351
4352
/*-------------------------------------------------------------------------
4353
 * Function:    H5D__virtual_close_mapping
4354
 *
4355
 * Purpose:     Frees memory structures allocated by H5D__virtual_pre_io
4356
 *              for a particular mapping
4357
 *
4358
 * Return:      Non-negative on success/Negative on failure
4359
 *
4360
 *-------------------------------------------------------------------------
4361
 */
4362
static herr_t
4363
H5D__virtual_close_mapping(H5O_storage_virtual_ent_t *mapping)
4364
0
{
4365
0
    herr_t ret_value = SUCCEED;
4366
4367
0
    FUNC_ENTER_PACKAGE
4368
4369
    /* Check for "printf" source dataset resolution */
4370
0
    if (mapping->psfn_nsubs || mapping->psdn_nsubs) {
4371
        /* Iterate over sub-source dsets */
4372
0
        for (size_t j = mapping->sub_dset_io_start; j < mapping->sub_dset_io_end; j++)
4373
            /* Close projected memory space */
4374
0
            if (mapping->sub_dset[j].projected_mem_space) {
4375
                /* Use HDONE_ERROR to attempt to close all spaces even after failure */
4376
0
                if (H5S_close(mapping->sub_dset[j].projected_mem_space) < 0)
4377
0
                    HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close temporary space");
4378
0
                mapping->sub_dset[j].projected_mem_space = NULL;
4379
0
            } /* end if */
4380
0
    }         /* end if */
4381
0
    else
4382
        /* Close projected memory space */
4383
0
        if (mapping->source_dset.projected_mem_space) {
4384
0
            if (H5S_close(mapping->source_dset.projected_mem_space) < 0)
4385
0
                HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close temporary space");
4386
0
            mapping->source_dset.projected_mem_space = NULL;
4387
0
        } /* end if */
4388
4389
0
    FUNC_LEAVE_NOAPI(ret_value);
4390
0
} /* end H5D__virtual_close_mapping() */