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 COPYING file, which can be found at the root of the source code       *
8  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
9  * If you do not have access to either file, you may request a copy from     *
10  * help@hdfgroup.org.                                                        *
11  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12 
13 /*
14  * Programmer:  Neil Fortner <nfortne2@hdfgroup.org>
15  *              Wednesday, January 28, 2015
16  *
17  * Purpose:
18  *      Virtual Dataset (VDS) functions.  Creates a layout type which allows
19  *      definition of a virtual dataset, where the actual dataset is stored in
20  *      other datasets (called source datasets).  The mappings between the
21  *      virtual and source datasets are specified by hyperslab or "all"
22  *      dataspace selections.  Point selections are not currently supported.
23  *      Overlaps in the mappings in the virtual dataset result in undefined
24  *      behaviour.
25  *
26  *      Mapping selections may be unlimited, in which case the size of the
27  *      virtual dataset is determined by the size of the source dataset(s).
28  *      Names for the source datasets may also be generated procedurally, in
29  *      which case the virtual selection should be unlimited with an unlimited
30  *      count and the source selection should be limited with a size equal to
31  *      that of the virtual selection with the unlimited count set to 1.
32  *
33  *      Source datasets are opened lazily (only when needed for I/O or to
34  *      determine the size of the virtual dataset), and are currently held open
35  *      until the virtual dataset is closed.
36  */
37 
38 /****************/
39 /* Module Setup */
40 /****************/
41 
42 #include "H5Dmodule.h"          /* This source code file is part of the H5D module */
43 
44 
45 /***********/
46 /* Headers */
47 /***********/
48 #include "H5private.h"          /* Generic Functions                    */
49 #include "H5CXprivate.h"        /* API Contexts                         */
50 #include "H5Dpkg.h"             /* Dataset functions                    */
51 #include "H5Eprivate.h"         /* Error handling                       */
52 #include "H5Fprivate.h"         /* Files                                */
53 #include "H5FLprivate.h"        /* Free Lists                           */
54 #include "H5Gprivate.h"         /* Groups                               */
55 #include "H5HGprivate.h"        /* Global Heaps                         */
56 #include "H5Iprivate.h"         /* IDs                                  */
57 #include "H5MMprivate.h"        /* Memory management                    */
58 #include "H5Oprivate.h"         /* Object headers                       */
59 #include "H5Pprivate.h"         /* Property Lists                       */
60 #include "H5Sprivate.h"         /* Dataspaces                           */
61 
62 
63 /****************/
64 /* Local Macros */
65 /****************/
66 
67 /* Default size for sub_dset array */
68 #define H5D_VIRTUAL_DEF_SUB_DSET_SIZE 128
69 
70 
71 /******************/
72 /* Local Typedefs */
73 /******************/
74 
75 
76 /********************/
77 /* Local Prototypes */
78 /********************/
79 
80 /* Layout operation callbacks */
81 static herr_t H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t
82     *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
83     H5D_chunk_map_t *fm);
84 static herr_t H5D__virtual_write(H5D_io_info_t *io_info,
85     const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
86     const H5S_t *mem_space, H5D_chunk_map_t *fm);
87 static herr_t H5D__virtual_flush(H5D_t *dset);
88 
89 /* Other functions */
90 static herr_t H5D__virtual_open_source_dset(const H5D_t *vdset,
91     H5O_storage_virtual_ent_t *virtual_ent,
92     H5O_storage_virtual_srcdset_t *source_dset);
93 static herr_t H5D__virtual_reset_source_dset(H5O_storage_virtual_ent_t *virtual_ent,
94     H5O_storage_virtual_srcdset_t *source_dset);
95 static herr_t H5D__virtual_str_append(const char *src, size_t src_len, char **p,
96     char **buf, size_t *buf_size);
97 static herr_t H5D__virtual_copy_parsed_name(
98     H5O_storage_virtual_name_seg_t **dst, H5O_storage_virtual_name_seg_t *src);
99 static herr_t H5D__virtual_build_source_name(char *source_name,
100     const H5O_storage_virtual_name_seg_t *parsed_name, size_t static_strlen,
101     size_t nsubs, hsize_t blockno, char **built_name);
102 static herr_t H5D__virtual_init_all(const H5D_t *dset);
103 static herr_t H5D__virtual_pre_io(H5D_io_info_t *io_info,
104     H5O_storage_virtual_t *storage, const H5S_t *file_space,
105     const H5S_t *mem_space, hsize_t *tot_nelmts);
106 static herr_t H5D__virtual_post_io(H5O_storage_virtual_t *storage);
107 static herr_t H5D__virtual_read_one(H5D_io_info_t *io_info,
108     const H5D_type_info_t *type_info, const H5S_t *file_space,
109     H5O_storage_virtual_srcdset_t *source_dset);
110 static herr_t H5D__virtual_write_one(H5D_io_info_t *io_info,
111     const H5D_type_info_t *type_info, const H5S_t *file_space,
112     H5O_storage_virtual_srcdset_t *source_dset);
113 
114 
115 /*********************/
116 /* Package Variables */
117 /*********************/
118 
119 /* Contiguous storage layout I/O ops */
120 const H5D_layout_ops_t H5D_LOPS_VIRTUAL[1] = {{
121     NULL,
122     H5D__virtual_init,
123     H5D__virtual_is_space_alloc,
124     NULL,
125     H5D__virtual_read,
126     H5D__virtual_write,
127 #ifdef H5_HAVE_PARALLEL
128     NULL,
129     NULL,
130 #endif /* H5_HAVE_PARALLEL */
131     NULL,
132     NULL,
133     H5D__virtual_flush,
134     NULL,
135     NULL
136 }};
137 
138 
139 /*******************/
140 /* Local Variables */
141 /*******************/
142 
143 /* Declare a free list to manage the H5O_storage_virtual_name_seg_t struct */
144 H5FL_DEFINE(H5O_storage_virtual_name_seg_t);
145 
146 /* Declare a static free list to manage H5D_virtual_file_list_t structs */
147 H5FL_DEFINE_STATIC(H5D_virtual_held_file_t);
148 
149 
150 
151 /*-------------------------------------------------------------------------
152  * Function:    H5D_virtual_check_mapping_pre
153  *
154  * Purpose:     Checks that the provided virtual and source selections are
155  *              legal for use as a VDS mapping, prior to creating the rest
156  *              of the mapping entry.
157  *
158  * Return:      Non-negative on success/Negative on failure
159  *
160  * Programmer:  Neil Fortner
161  *              August 12, 2015
162  *
163  *-------------------------------------------------------------------------
164  */
165 herr_t
H5D_virtual_check_mapping_pre(const H5S_t * vspace,const H5S_t * src_space,H5O_virtual_space_status_t space_status)166 H5D_virtual_check_mapping_pre(const H5S_t *vspace, const H5S_t *src_space,
167     H5O_virtual_space_status_t space_status)
168 {
169     H5S_sel_type    select_type; /* Selection type */
170     hsize_t         nelmts_vs;  /* Number of elements in virtual selection */
171     hsize_t         nelmts_ss;  /* Number of elements in source selection */
172     herr_t          ret_value = SUCCEED; /* Return value */
173 
174     FUNC_ENTER_NOAPI(FAIL)
175 
176     /* Check for point selections (currently unsupported) */
177     if(H5S_SEL_ERROR == (select_type = H5S_GET_SELECT_TYPE(vspace)))
178         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get selection type")
179     if(select_type == H5S_SEL_POINTS)
180         HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "point selections not currently supported with virtual datasets")
181     if(H5S_SEL_ERROR == (select_type = H5S_GET_SELECT_TYPE(src_space)))
182         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get selection type")
183     if(select_type == H5S_SEL_POINTS)
184         HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "point selections not currently supported with virtual datasets")
185 
186     /* Get number of elements in spaces */
187     nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(vspace);
188     nelmts_ss = (hsize_t)H5S_GET_SELECT_NPOINTS(src_space);
189 
190     /* Check for unlimited vspace */
191     if(nelmts_vs == H5S_UNLIMITED) {
192         /* Check for unlimited src_space */
193         if(nelmts_ss == H5S_UNLIMITED) {
194             hsize_t nenu_vs;    /* Number of elements in the non-unlimited dimensions of vspace */
195             hsize_t nenu_ss;    /* Number of elements in the non-unlimited dimensions of src_space */
196 
197             /* Non-printf unlimited selection.  Make sure both selections have
198              * the same number of elements in the non-unlimited dimension.  Note
199              * we can always check this even if the space status is invalid
200              * because unlimited selections are never dependent on the extent.
201              */
202             if(H5S_get_select_num_elem_non_unlim(vspace, &nenu_vs) < 0)
203                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "can't get number of elements in non-unlimited dimension")
204             if(H5S_get_select_num_elem_non_unlim(src_space, &nenu_ss) < 0)
205                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "can't get number of elements in non-unlimited dimension")
206             if(nenu_vs != nenu_ss)
207                 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "numbers of elemnts in the non-unlimited dimensions is different for source and virtual spaces")
208         } /* end if */
209         /* We will handle the printf case after parsing the source names */
210     } /* end if */
211     else if(space_status != H5O_VIRTUAL_STATUS_INVALID)
212         /* Limited selections.  Check number of points is the same. */
213         if(nelmts_vs != nelmts_ss)
214             HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual and source space selections have different numbers of elements")
215 
216 done:
217     FUNC_LEAVE_NOAPI(ret_value)
218 } /* end H5D_virtual_check_mapping_pre() */
219 
220 
221 /*-------------------------------------------------------------------------
222  * Function:    H5D_virtual_check_mapping_post
223  *
224  * Purpose:     Checks that the provided virtual dataset mapping entry is
225  *              legal, after the mapping is otherwise complete.
226  *
227  * Return:      Non-negative on success/Negative on failure
228  *
229  * Programmer:  Neil Fortner
230  *              August 12, 2015
231  *
232  *-------------------------------------------------------------------------
233  */
234 herr_t
H5D_virtual_check_mapping_post(const H5O_storage_virtual_ent_t * ent)235 H5D_virtual_check_mapping_post(const H5O_storage_virtual_ent_t *ent)
236 {
237     hsize_t         nelmts_vs;  /* Number of elements in virtual selection */
238     hsize_t         nelmts_ss;  /* Number of elements in source selection */
239     H5S_t           *tmp_space = NULL; /* Temporary dataspace */
240     herr_t          ret_value = SUCCEED; /* Return value */
241 
242     FUNC_ENTER_NOAPI(FAIL)
243 
244     /* Get number of elements in spaces */
245     nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(ent->source_dset.virtual_select);
246     nelmts_ss = (hsize_t)H5S_GET_SELECT_NPOINTS(ent->source_select);
247 
248     /* Check for printf selection */
249     if((nelmts_vs == H5S_UNLIMITED) && (nelmts_ss != H5S_UNLIMITED)) {
250         /* Make sure there at least one %b substitution in the source file or
251          * dataset name */
252         if((ent->psfn_nsubs == 0) && (ent->psdn_nsubs == 0))
253             HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unlimited virtual selection, limited source selection, and no printf specifiers in source names")
254 
255         /* Make sure virtual space uses hyperslab selection */
256         if(H5S_GET_SELECT_TYPE(ent->source_dset.virtual_select) != H5S_SEL_HYPERSLABS)
257             HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "virtual selection with printf mapping must be hyperslab")
258 
259         /* Check that the number of elements in one block in the virtual
260          * selection matches the total number of elements in the source
261          * selection, if the source space status is not invalid (virtual space
262          * status does not matter here because it is unlimited) */
263         if(ent->source_space_status != H5O_VIRTUAL_STATUS_INVALID) {
264             /* Get first block in virtual selection */
265             if(NULL == (tmp_space = H5S_hyper_get_unlim_block(ent->source_dset.virtual_select, (hsize_t)0)))
266                 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get first block in virtual selection")
267 
268             /* Check number of points */
269             nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(tmp_space);
270             if(nelmts_vs != nelmts_ss)
271                 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual (single block) and source space selections have different numbers of elements")
272         } /* end if */
273     } /* end if */
274     else
275         /* Make sure there are no printf substitutions */
276         if((ent->psfn_nsubs > 0) || (ent->psdn_nsubs > 0))
277             HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "printf specifier(s) in source name(s) without an unlimited virtual selection and limited source selection")
278 
279 done:
280     /* Free temporary space */
281     if(tmp_space)
282         if(H5S_close(tmp_space) < 0)
283             HDONE_ERROR(H5E_PLIST, H5E_CLOSEERROR, FAIL, "can't close dataspace")
284 
285     FUNC_LEAVE_NOAPI(ret_value)
286 } /* end H5D_virtual_check_mapping_post() */
287 
288 
289 /*-------------------------------------------------------------------------
290  * Function:    H5D_virtual_update_min_dims
291  *
292  * Purpose:     Updates the virtual layout's "min_dims" field to take into
293  *              account the "idx"th entry in the mapping list.  The entry
294  *              must be complete, though top level field list_nused (and
295  *              of course min_dims) does not need to take it into account.
296  *
297  * Return:      Non-negative on success/Negative on failure
298  *
299  * Programmer:  Neil Fortner
300  *              February 10, 2015
301  *
302  *-------------------------------------------------------------------------
303  */
304 herr_t
H5D_virtual_update_min_dims(H5O_layout_t * layout,size_t idx)305 H5D_virtual_update_min_dims(H5O_layout_t *layout, size_t idx)
306 {
307     H5S_sel_type    sel_type;
308     int             rank;
309     hsize_t         bounds_start[H5S_MAX_RANK];
310     hsize_t         bounds_end[H5S_MAX_RANK];
311     int             i;
312     herr_t          ret_value = SUCCEED;
313 
314     FUNC_ENTER_NOAPI(FAIL)
315 
316     HDassert(layout);
317     HDassert(layout->type == H5D_VIRTUAL);
318     HDassert(idx < layout->storage.u.virt.list_nalloc);
319 
320     /* Get type of selection */
321     if(H5S_SEL_ERROR == (sel_type = H5S_GET_SELECT_TYPE(layout->storage.u.virt.list[idx].source_dset.virtual_select)))
322         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection type")
323 
324     /* Do not update min_dims for "all" or "none" selections */
325     if((sel_type == H5S_SEL_ALL) || (sel_type == H5S_SEL_NONE))
326         HGOTO_DONE(SUCCEED)
327 
328     /* Get rank of vspace */
329     if((rank = H5S_GET_EXTENT_NDIMS(layout->storage.u.virt.list[idx].source_dset.virtual_select)) < 0)
330         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
331 
332     /* Get selection bounds */
333     if(H5S_SELECT_BOUNDS(layout->storage.u.virt.list[idx].source_dset.virtual_select, bounds_start, bounds_end) < 0)
334         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
335 
336     /* Update min_dims */
337     for(i = 0; i < rank; i++)
338         /* Don't check unlimited dimensions in the selection */
339         if((i != layout->storage.u.virt.list[idx].unlim_dim_virtual)
340                 && (bounds_end[i] >= layout->storage.u.virt.min_dims[i]))
341             layout->storage.u.virt.min_dims[i] = bounds_end[i] + (hsize_t)1;
342 
343 done:
344     FUNC_LEAVE_NOAPI(ret_value)
345 } /* end H5D_virtual_update_min_dims() */
346 
347 
348 /*-------------------------------------------------------------------------
349  * Function:    H5D_virtual_check_min_dims
350  *
351  * Purpose:     Checks if the dataset's dimensions are at least the
352  *              calculated minimum dimensions from the mappings.
353  *
354  * Return:      Non-negative on success/Negative on failure
355  *
356  * Programmer:  Neil Fortner
357  *              August 13, 2015
358  *
359  *-------------------------------------------------------------------------
360  */
361 herr_t
H5D_virtual_check_min_dims(const H5D_t * dset)362 H5D_virtual_check_min_dims(const H5D_t *dset)
363 {
364     int             rank;
365     hsize_t         dims[H5S_MAX_RANK];
366     int             i;
367     herr_t          ret_value = SUCCEED;
368 
369     FUNC_ENTER_NOAPI(FAIL)
370 
371     HDassert(dset);
372     HDassert(dset->shared);
373     HDassert(dset->shared->layout.type == H5D_VIRTUAL);
374 
375     /* Get rank of dataspace */
376     if((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0)
377         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
378 
379     /* Get VDS dimensions */
380     if(H5S_get_simple_extent_dims(dset->shared->space, dims, NULL) < 0)
381         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
382 
383     /* Verify that dimensions are larger than min_dims */
384     for(i = 0; i < rank; i++)
385         if(dims[i] < dset->shared->layout.storage.u.virt.min_dims[i])
386             HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual dataset dimensions not large enough to contain all limited dimensions in all selections")
387 
388 done:
389     FUNC_LEAVE_NOAPI(ret_value)
390 } /* end H5D_virtual_check_min_dims() */
391 
392 
393 /*-------------------------------------------------------------------------
394  * Function:    H5D__virtual_store_layout
395  *
396  * Purpose:     Store virtual dataset layout information, for new dataset
397  *
398  * Note:        We assume here that the contents of the heap block cannot
399  *		change!  If this ever stops being the case we must change
400  *		this code to allow overwrites of the heap block.  -NAF
401  *
402  * Return:      Success:    SUCCEED
403  *              Failure:    FAIL
404  *
405  * Programmer:  Quincey Koziol
406  *              Sunday, Feberuary 11, 2018
407  *
408  *-------------------------------------------------------------------------
409  */
410 herr_t
H5D__virtual_store_layout(H5F_t * f,H5O_layout_t * layout)411 H5D__virtual_store_layout(H5F_t *f, H5O_layout_t *layout)
412 {
413     uint8_t *heap_block = NULL;         /* Block to add to heap */
414     size_t *str_size = NULL;            /* Array for VDS entry string lengths */
415     uint8_t *heap_block_p;              /* Pointer into the heap block, while encoding */
416     size_t block_size;                  /* Total size of block needed */
417     hsize_t tmp_nentries;               /* Temp. variable for # of VDS entries */
418     uint32_t chksum;                    /* Checksum for heap data */
419     size_t i;                           /* Local index variable */
420     H5P_genplist_t *fapl_plist;         /* The file access property list */
421     hid_t new_fapl_id;                  /* The file access property list ID */
422     H5F_libver_t low_bound = H5F_LIBVER_V110;   /* Set the low bound in fapl to latest */
423     H5F_libver_t high_bound = H5F_LIBVER_V110;  /* Set the high bound in fapl to latest */
424     H5F_t *tmp_f = NULL;                /* Pointer to faked file structure */
425     herr_t ret_value = SUCCEED;         /* Return value */
426 
427     FUNC_ENTER_PACKAGE
428 
429     /* Sanity checking */
430     HDassert(f);
431     HDassert(layout);
432     HDassert(layout->storage.u.virt.serial_list_hobjid.addr == HADDR_UNDEF);
433 
434     /* Create block if # of used entries > 0 */
435     if(layout->storage.u.virt.list_nused > 0) {
436 
437         /* Make a copy of the default file access property list */
438         if(NULL == (fapl_plist = (H5P_genplist_t *)H5I_object(H5P_LST_FILE_ACCESS_ID_g)))
439             HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
440 
441         /* Set latest format in fapl_plist for virtual layout encoding */
442         if(H5P_set(fapl_plist, H5F_ACS_LIBVER_LOW_BOUND_NAME, &low_bound) < 0)
443             HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'low' bound for library format versions")
444         if(H5P_set(fapl_plist, H5F_ACS_LIBVER_HIGH_BOUND_NAME, &high_bound) < 0)
445             HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'high' bound for library format versions")
446         /* Copy and return the fapl id */
447         if((new_fapl_id = H5P_copy_plist(fapl_plist, FALSE)) < 0)
448             HGOTO_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL, "can't copy file access property list")
449 
450         /* Allocate "fake" file structure with the fapl setting */
451         if(NULL == (tmp_f = H5F_fake_alloc((uint8_t)0, new_fapl_id)))
452             HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate fake file struct")
453 
454         /* Allocate array for caching results of strlen */
455         if(NULL == (str_size = (size_t *)H5MM_malloc(2 * layout->storage.u.virt.list_nused * sizeof(size_t))))
456             HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, FAIL, "unable to allocate string length array")
457 
458         /*
459          * Calculate heap block size
460          */
461 
462         /* Version and number of entries */
463         block_size = (size_t)1 + H5F_SIZEOF_SIZE(f);
464 
465         /* Calculate size of each entry */
466         for(i = 0; i < layout->storage.u.virt.list_nused; i++) {
467             hssize_t select_serial_size;        /* Size of serialized selection */
468 
469             HDassert(layout->storage.u.virt.list[i].source_file_name);
470             HDassert(layout->storage.u.virt.list[i].source_dset_name);
471             HDassert(layout->storage.u.virt.list[i].source_select);
472             HDassert(layout->storage.u.virt.list[i].source_dset.virtual_select);
473 
474             /* Source file name */
475             str_size[2 * i] = HDstrlen(layout->storage.u.virt.list[i].source_file_name) + (size_t)1;
476             block_size += str_size[2 * i];
477 
478             /* Source dset name */
479             str_size[(2 * i) + 1] = HDstrlen(layout->storage.u.virt.list[i].source_dset_name) + (size_t)1;
480             block_size += str_size[(2 * i) + 1];
481 
482             /* Source selection */
483             if((select_serial_size = H5S_SELECT_SERIAL_SIZE(layout->storage.u.virt.list[i].source_select, tmp_f)) < 0)
484                 HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size")
485             block_size += (size_t)select_serial_size;
486 
487             /* Virtual dataset selection */
488             if((select_serial_size = H5S_SELECT_SERIAL_SIZE(layout->storage.u.virt.list[i].source_dset.virtual_select, tmp_f)) < 0)
489                 HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size")
490             block_size += (size_t)select_serial_size;
491         } /* end for */
492 
493         /* Checksum */
494         block_size += 4;
495 
496 
497         /* Allocate heap block */
498         if(NULL == (heap_block = (uint8_t *)H5MM_malloc(block_size)))
499             HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, FAIL, "unable to allocate heap block")
500 
501 
502         /*
503          * Encode heap block
504          */
505         heap_block_p = heap_block;
506 
507         /* Encode heap block encoding version */
508         *heap_block_p++ = (uint8_t)H5O_LAYOUT_VDS_GH_ENC_VERS;
509 
510         /* Number of entries */
511         tmp_nentries = (hsize_t)layout->storage.u.virt.list_nused;
512         H5F_ENCODE_LENGTH(f, heap_block_p, tmp_nentries)
513 
514         /* Encode each entry */
515         for(i = 0; i < layout->storage.u.virt.list_nused; i++) {
516             /* Source file name */
517             HDmemcpy((char *)heap_block_p, layout->storage.u.virt.list[i].source_file_name, str_size[2 * i]);
518             heap_block_p += str_size[2 * i];
519 
520             /* Source dataset name */
521             HDmemcpy((char *)heap_block_p, layout->storage.u.virt.list[i].source_dset_name, str_size[(2 * i) + 1]);
522             heap_block_p += str_size[(2 * i) + 1];
523 
524             /* Source selection */
525             if(H5S_SELECT_SERIALIZE(layout->storage.u.virt.list[i].source_select, &heap_block_p, tmp_f) < 0)
526                 HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to serialize source selection")
527 
528             /* Virtual selection */
529 		  if(H5S_SELECT_SERIALIZE(layout->storage.u.virt.list[i].source_dset.virtual_select, &heap_block_p, tmp_f) < 0)
530                 HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to serialize virtual selection")
531         } /* end for */
532 
533         /* Checksum */
534         chksum = H5_checksum_metadata(heap_block, block_size - (size_t)4, 0);
535         UINT32ENCODE(heap_block_p, chksum)
536 
537         /* Insert block into global heap */
538         if(H5HG_insert(f, block_size, heap_block, &(layout->storage.u.virt.serial_list_hobjid)) < 0) /* Casting away const OK  --NAF */
539             HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to insert virtual dataset heap block")
540     } /* end if */
541 
542 done:
543     /* Release fake file structure */
544     if(tmp_f && H5F_fake_free(tmp_f) < 0)
545         HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release fake file struct")
546 
547     heap_block = (uint8_t *)H5MM_xfree(heap_block);
548     str_size = (size_t *)H5MM_xfree(str_size);
549 
550 
551     FUNC_LEAVE_NOAPI(ret_value)
552 } /* end H5D__virtual_store_layout() */
553 
554 
555 /*-------------------------------------------------------------------------
556  * Function:    H5D__virtual_copy_layout
557  *
558  * Purpose:     Deep copies virtual storage layout message in memory.
559  *              This function assumes that the top-level struct has
560  *              already been copied (so the source struct retains
561  *              ownership of the fields passed to this function).
562  *
563  * Return:      Non-negative on success/Negative on failure
564  *
565  * Programmer:  Neil Fortner
566  *              February 10, 2015
567  *
568  *-------------------------------------------------------------------------
569  */
570 herr_t
H5D__virtual_copy_layout(H5O_layout_t * layout)571 H5D__virtual_copy_layout(H5O_layout_t *layout)
572 {
573     H5O_storage_virtual_ent_t *orig_list = NULL;
574     hid_t           orig_source_fapl;
575     hid_t           orig_source_dapl;
576     H5P_genplist_t *plist;
577     size_t          i;
578     herr_t          ret_value = SUCCEED;
579 
580     FUNC_ENTER_PACKAGE
581 
582     HDassert(layout);
583     HDassert(layout->type == H5D_VIRTUAL);
584 
585     /* Save original entry list and top-level property lists and reset in layout
586      * so the originals aren't closed on error */
587     orig_source_fapl = layout->storage.u.virt.source_fapl;
588     layout->storage.u.virt.source_fapl = -1;
589     orig_source_dapl = layout->storage.u.virt.source_dapl;
590     layout->storage.u.virt.source_dapl = -1;
591     orig_list = layout->storage.u.virt.list;
592     layout->storage.u.virt.list = NULL;
593 
594     /* Copy entry list */
595     if(layout->storage.u.virt.list_nused > 0) {
596         HDassert(orig_list);
597 
598         /* Allocate memory for the list */
599         if(NULL == (layout->storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_calloc(layout->storage.u.virt.list_nused * sizeof(H5O_storage_virtual_ent_t))))
600             HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate memory for virtual dataset entry list")
601         layout->storage.u.virt.list_nalloc = layout->storage.u.virt.list_nused;
602 
603         /* Copy the list entries, though set source_dset.dset and sub_dset to
604          * NULL */
605         for(i = 0; i < layout->storage.u.virt.list_nused; i++) {
606             /* Copy virtual selection */
607             if(NULL == (layout->storage.u.virt.list[i].source_dset.virtual_select
608                     = H5S_copy(orig_list[i].source_dset.virtual_select, FALSE, TRUE)))
609                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
610 
611             /* Copy original source names */
612             if(NULL == (layout->storage.u.virt.list[i].source_file_name
613                     = H5MM_strdup(orig_list[i].source_file_name)))
614                 HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source file name")
615             if(NULL == (layout->storage.u.virt.list[i].source_dset_name
616                     = H5MM_strdup(orig_list[i].source_dset_name)))
617                 HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source dataset name")
618 
619             /* Copy source selection */
620             if(NULL == (layout->storage.u.virt.list[i].source_select
621                     = H5S_copy(orig_list[i].source_select, FALSE, TRUE)))
622                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
623 
624             /* Initialize clipped selections */
625             if(orig_list[i].unlim_dim_virtual < 0) {
626                 layout->storage.u.virt.list[i].source_dset.clipped_source_select = layout->storage.u.virt.list[i].source_select;
627                 layout->storage.u.virt.list[i].source_dset.clipped_virtual_select = layout->storage.u.virt.list[i].source_dset.virtual_select;
628             } /* end if */
629 
630             /* Copy parsed names */
631             if(H5D__virtual_copy_parsed_name(&layout->storage.u.virt.list[i].parsed_source_file_name, orig_list[i].parsed_source_file_name) < 0)
632                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy parsed source file name")
633             layout->storage.u.virt.list[i].psfn_static_strlen = orig_list[i].psfn_static_strlen;
634             layout->storage.u.virt.list[i].psfn_nsubs = orig_list[i].psfn_nsubs;
635             if(H5D__virtual_copy_parsed_name(&layout->storage.u.virt.list[i].parsed_source_dset_name, orig_list[i].parsed_source_dset_name) < 0)
636                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy parsed source dataset name")
637             layout->storage.u.virt.list[i].psdn_static_strlen = orig_list[i].psdn_static_strlen;
638             layout->storage.u.virt.list[i].psdn_nsubs = orig_list[i].psdn_nsubs;
639 
640             /* Copy source names in source dset or add reference as appropriate
641              */
642             if(orig_list[i].source_dset.file_name) {
643                 if(orig_list[i].source_dset.file_name
644                         == orig_list[i].source_file_name)
645                     layout->storage.u.virt.list[i].source_dset.file_name = layout->storage.u.virt.list[i].source_file_name;
646                 else if(orig_list[i].parsed_source_file_name
647                         && (orig_list[i].source_dset.file_name
648                         != orig_list[i].parsed_source_file_name->name_segment)) {
649                     HDassert(layout->storage.u.virt.list[i].parsed_source_file_name);
650                     HDassert(layout->storage.u.virt.list[i].parsed_source_file_name->name_segment);
651                     layout->storage.u.virt.list[i].source_dset.file_name = layout->storage.u.virt.list[i].parsed_source_file_name->name_segment;
652                 } /* end if */
653                 else
654                     if(NULL == (layout->storage.u.virt.list[i].source_dset.file_name
655                             = H5MM_strdup(orig_list[i].source_dset.file_name)))
656                         HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source file name")
657             } /* end if */
658             if(orig_list[i].source_dset.dset_name) {
659                 if(orig_list[i].source_dset.dset_name
660                         == orig_list[i].source_dset_name)
661                     layout->storage.u.virt.list[i].source_dset.dset_name = layout->storage.u.virt.list[i].source_dset_name;
662                 else if(orig_list[i].parsed_source_dset_name
663                         && (orig_list[i].source_dset.dset_name
664                         != orig_list[i].parsed_source_dset_name->name_segment)) {
665                     HDassert(layout->storage.u.virt.list[i].parsed_source_dset_name);
666                     HDassert(layout->storage.u.virt.list[i].parsed_source_dset_name->name_segment);
667                     layout->storage.u.virt.list[i].source_dset.dset_name = layout->storage.u.virt.list[i].parsed_source_dset_name->name_segment;
668                 } /* end if */
669                 else
670                     if(NULL == (layout->storage.u.virt.list[i].source_dset.dset_name
671                             = H5MM_strdup(orig_list[i].source_dset.dset_name)))
672                         HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source dataset name")
673             } /* end if */
674 
675             /* Copy other fields in entry */
676             layout->storage.u.virt.list[i].unlim_dim_source = orig_list[i].unlim_dim_source;
677             layout->storage.u.virt.list[i].unlim_dim_virtual = orig_list[i].unlim_dim_virtual;
678             layout->storage.u.virt.list[i].unlim_extent_source = orig_list[i].unlim_extent_source;
679             layout->storage.u.virt.list[i].unlim_extent_virtual = orig_list[i].unlim_extent_virtual;
680             layout->storage.u.virt.list[i].clip_size_source = orig_list[i].clip_size_source;
681             layout->storage.u.virt.list[i].clip_size_virtual = orig_list[i].clip_size_virtual;
682             layout->storage.u.virt.list[i].source_space_status = orig_list[i].source_space_status;
683             layout->storage.u.virt.list[i].virtual_space_status = orig_list[i].virtual_space_status;
684         } /* end for */
685     } /* end if */
686     else {
687         /* Zero out other fields related to list, just to be sure */
688         layout->storage.u.virt.list = NULL;
689         layout->storage.u.virt.list_nalloc = 0;
690     } /* end else */
691 
692     /* Copy property lists */
693     if(orig_source_fapl >= 0) {
694         if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(orig_source_fapl, H5I_GENPROP_LST)))
695             HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
696         if((layout->storage.u.virt.source_fapl = H5P_copy_plist(plist, FALSE)) < 0)
697             HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy fapl")
698     } /* end if */
699     if(orig_source_dapl >= 0) {
700         if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(orig_source_dapl, H5I_GENPROP_LST)))
701             HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
702         if((layout->storage.u.virt.source_dapl = H5P_copy_plist(plist, FALSE)) < 0)
703             HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dapl")
704     } /* end if */
705 
706     /* New layout is not fully initialized */
707     layout->storage.u.virt.init = FALSE;
708 
709 done:
710     /* Release allocated resources on failure */
711     if(ret_value < 0)
712         if(H5D__virtual_reset_layout(layout) < 0)
713             HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset virtual layout")
714 
715     FUNC_LEAVE_NOAPI(ret_value)
716 } /* end H5D__virtual_copy_layout() */
717 
718 
719 /*-------------------------------------------------------------------------
720  * Function:    H5D__virtual_reset_layout
721  *
722  * Purpose:     Frees internal structures in a virtual storage layout
723  *              message in memory.  This function is safe to use on
724  *              incomplete structures (for recovery from failure) provided
725  *              the internal structures are initialized with all bytes set
726  *              to 0.
727  *
728  * Return:      Non-negative on success/Negative on failure
729  *
730  * Programmer:  Neil Fortner
731  *              February 11, 2015
732  *
733  *-------------------------------------------------------------------------
734  */
735 herr_t
H5D__virtual_reset_layout(H5O_layout_t * layout)736 H5D__virtual_reset_layout(H5O_layout_t *layout)
737 {
738     size_t          i, j;
739     herr_t          ret_value = SUCCEED;
740 
741     FUNC_ENTER_PACKAGE
742 
743     HDassert(layout);
744     HDassert(layout->type == H5D_VIRTUAL);
745 
746     /* Free the list entries.  Note we always attempt to free everything even in
747      * the case of a failure.  Because of this, and because we free the list
748      * afterwards, we do not need to zero out the memory in the list. */
749     for(i = 0; i < layout->storage.u.virt.list_nused; i++) {
750         /* Free source_dset */
751         if(H5D__virtual_reset_source_dset(&layout->storage.u.virt.list[i], &layout->storage.u.virt.list[i].source_dset) < 0)
752             HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset source dataset")
753 
754         /* Free original source names */
755         (void)H5MM_xfree(layout->storage.u.virt.list[i].source_file_name);
756         (void)H5MM_xfree(layout->storage.u.virt.list[i].source_dset_name);
757 
758         /* Free sub_dset */
759         for(j = 0; j < layout->storage.u.virt.list[i].sub_dset_nalloc; j++)
760             if(H5D__virtual_reset_source_dset(&layout->storage.u.virt.list[i], &layout->storage.u.virt.list[i].sub_dset[j]) < 0)
761                 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset source dataset")
762         layout->storage.u.virt.list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_xfree(layout->storage.u.virt.list[i].sub_dset);
763 
764         /* Free source_select */
765         if(layout->storage.u.virt.list[i].source_select)
766             if(H5S_close(layout->storage.u.virt.list[i].source_select) < 0)
767                 HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release source selection")
768 
769         /* Free parsed_source_file_name */
770         H5D_virtual_free_parsed_name(layout->storage.u.virt.list[i].parsed_source_file_name);
771 
772         /* Free parsed_source_dset_name */
773         H5D_virtual_free_parsed_name(layout->storage.u.virt.list[i].parsed_source_dset_name);
774     } /* end for */
775 
776     /* Free the list */
777     layout->storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_xfree(layout->storage.u.virt.list);
778     layout->storage.u.virt.list_nalloc = (size_t)0;
779     layout->storage.u.virt.list_nused = (size_t)0;
780     (void)HDmemset(layout->storage.u.virt.min_dims, 0, sizeof(layout->storage.u.virt.min_dims));
781 
782     /* Close access property lists */
783     if(layout->storage.u.virt.source_fapl >= 0) {
784         if(H5I_dec_ref(layout->storage.u.virt.source_fapl) < 0)
785             HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close source fapl")
786         layout->storage.u.virt.source_fapl = -1;
787     } /* end if */
788     if(layout->storage.u.virt.source_dapl >= 0) {
789         if(H5I_dec_ref(layout->storage.u.virt.source_dapl) < 0)
790             HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close source dapl")
791         layout->storage.u.virt.source_dapl = -1;
792     } /* end if */
793 
794     /* The list is no longer initialized */
795     layout->storage.u.virt.init = FALSE;
796 
797     /* Note the lack of a done: label.  This is because there are no HGOTO_ERROR
798      * calls.  If one is added, a done: label must also be added */
799     FUNC_LEAVE_NOAPI(ret_value)
800 } /* end H5D__virtual_reset_layout() */
801 
802 
803 /*-------------------------------------------------------------------------
804  * Function:    H5D__virtual_copy
805  *
806  * Purpose:     Copy virtual storage raw data from SRC file to DST file.
807  *
808  * Return:      Non-negative on success/Negative on failure
809  *
810  * Programmer:  Neil Fortner
811  *              February 6, 2015
812  *
813  *-------------------------------------------------------------------------
814  */
815 herr_t
H5D__virtual_copy(H5F_t * f_dst,H5O_layout_t * layout_dst)816 H5D__virtual_copy(H5F_t *f_dst, H5O_layout_t *layout_dst)
817 {
818     herr_t          ret_value = SUCCEED;
819 
820     FUNC_ENTER_PACKAGE
821 
822 #ifdef NOT_YET
823     /* Check for copy to the same file */
824     if(f_dst == f_src) {
825         /* Increase reference count on global heap object */
826         if((heap_rc = H5HG_link(f_dst, (H5HG_t *)&(layout_dst->u.virt.serial_list_hobjid), 1)) < 0)
827             HGOTO_ERROR(H5E_DATASET, H5E_CANTMODIFY, FAIL, "unable to adjust global heap reference count")
828     } /* end if */
829     else
830 #endif /* NOT_YET */
831     {
832         /* Reset global heap id */
833         layout_dst->storage.u.virt.serial_list_hobjid.addr = HADDR_UNDEF;
834         layout_dst->storage.u.virt.serial_list_hobjid.idx = (size_t)0;
835 
836         /* Write the VDS data to destination file's heap */
837         if(H5D__virtual_store_layout(f_dst, layout_dst) < 0)
838              HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to store VDS info")
839     } /* end block/else */
840 
841 done:
842     FUNC_LEAVE_NOAPI(ret_value)
843 } /* end H5D__virtual_copy() */
844 
845 
846 /*-------------------------------------------------------------------------
847  * Function:    H5D__virtual_delete
848  *
849  * Purpose:     Delete the file space for a virtual dataset
850  *
851  * Return:      Non-negative on success/Negative on failure
852  *
853  * Programmer:  Neil Fortner
854  *              February 6, 2015
855  *
856  *-------------------------------------------------------------------------
857  */
858 herr_t
H5D__virtual_delete(H5F_t * f,H5O_storage_t * storage)859 H5D__virtual_delete(H5F_t *f, H5O_storage_t *storage)
860 {
861 #ifdef NOT_YET
862     int heap_rc;                /* Reference count of global heap object */
863 #endif  /* NOT_YET */
864     herr_t ret_value = SUCCEED; /* Return value */
865 
866     FUNC_ENTER_PACKAGE
867 
868     /* check args */
869     HDassert(f);
870     HDassert(storage);
871     HDassert(storage->type == H5D_VIRTUAL);
872 
873     /* Check for global heap block */
874     if(storage->u.virt.serial_list_hobjid.addr != HADDR_UNDEF) {
875 #ifdef NOT_YET
876         /* Unlink the global heap block */
877         if((heap_rc = H5HG_link(f, (H5HG_t *)&(storage->u.virt.serial_list_hobjid), -1)) < 0)
878             HGOTO_ERROR(H5E_DATASET, H5E_CANTMODIFY, FAIL, "unable to adjust global heap reference count")
879         if(heap_rc == 0)
880 #endif /* NOT_YET */
881             /* Delete the global heap block */
882             if(H5HG_remove(f, (H5HG_t *)&(storage->u.virt.serial_list_hobjid)) < 0)
883                 HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to remove heap object")
884     } /* end if */
885 
886     /* Clear global heap ID in storage */
887     storage->u.virt.serial_list_hobjid.addr = HADDR_UNDEF;
888     storage->u.virt.serial_list_hobjid.idx = 0;
889 
890 done:
891     FUNC_LEAVE_NOAPI(ret_value)
892 } /* end H5D__virtual_delete */
893 
894 
895 /*-------------------------------------------------------------------------
896  * Function:    H5D__virtual_open_source_dset
897  *
898  * Purpose:     Attempts to open a source dataset.
899  *
900  * Return:      Non-negative on success/Negative on failure
901  *
902  * Programmer:  Neil Fortner
903  *              March 6, 2015
904  *
905  *-------------------------------------------------------------------------
906  */
907 static herr_t
H5D__virtual_open_source_dset(const H5D_t * vdset,H5O_storage_virtual_ent_t * virtual_ent,H5O_storage_virtual_srcdset_t * source_dset)908 H5D__virtual_open_source_dset(const H5D_t *vdset,
909     H5O_storage_virtual_ent_t *virtual_ent,
910     H5O_storage_virtual_srcdset_t *source_dset)
911 {
912     H5F_t       *src_file = NULL;       /* Source file */
913     hbool_t     src_file_open = FALSE;  /* Whether we have opened and need to close src_file */
914     herr_t      ret_value = SUCCEED;    /* Return value */
915 
916     FUNC_ENTER_STATIC
917 
918     /* Sanity check */
919     HDassert(vdset);
920     HDassert(source_dset);
921     HDassert(!source_dset->dset);
922     HDassert(source_dset->file_name);
923     HDassert(source_dset->dset_name);
924 
925     /* Check if we need to open the source file */
926     if(HDstrcmp(source_dset->file_name, ".")) {
927         unsigned    intent;                 /* File access permissions */
928 
929         /* Get the virtual dataset's file open flags ("intent") */
930         intent = H5F_INTENT(vdset->oloc.file);
931 
932         /* Try opening the file */
933         src_file = H5F_prefix_open_file(vdset->oloc.file, H5F_PREFIX_VDS, vdset->shared->vds_prefix, source_dset->file_name, intent, vdset->shared->layout.storage.u.virt.source_fapl);
934 
935         /* If we opened the source file here, we should close it when leaving */
936         if(src_file)
937             src_file_open = TRUE;
938         else
939             /* Reset the error stack */
940             H5E_clear_stack(NULL);
941     } /* end if */
942     else
943         /* Source file is ".", use the virtual dataset's file */
944         src_file = vdset->oloc.file;
945 
946     if(src_file) {
947         H5G_loc_t   src_root_loc;           /* Object location of source file root group */
948 
949         /* Set up the root group in the destination file */
950         if(NULL == (src_root_loc.oloc = H5G_oloc(H5G_rootof(src_file))))
951             HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to get object location for root group")
952         if(NULL == (src_root_loc.path = H5G_nameof(H5G_rootof(src_file))))
953             HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to get path for root group")
954 
955         /* Try opening the source dataset */
956         source_dset->dset = H5D__open_name(&src_root_loc, source_dset->dset_name, vdset->shared->layout.storage.u.virt.source_dapl);
957 
958         /* Dataset does not exist */
959         if(NULL == source_dset->dset) {
960             /* Reset the error stack */
961             H5E_clear_stack(NULL);
962 
963             source_dset->dset_exists = FALSE;
964         } /* end if */
965         else {
966             /* Dataset exists */
967             source_dset->dset_exists = TRUE;
968 
969             /* Patch the source selection if necessary */
970             if(virtual_ent->source_space_status != H5O_VIRTUAL_STATUS_CORRECT) {
971                 if(H5S_extent_copy(virtual_ent->source_select, source_dset->dset->shared->space) < 0)
972                     HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent")
973                 virtual_ent->source_space_status = H5O_VIRTUAL_STATUS_CORRECT;
974             } /* end if */
975         } /* end else */
976     } /* end if */
977 
978 done:
979     /* Release resources */
980     if(src_file_open)
981         if(H5F_efc_close(vdset->oloc.file, src_file) < 0)
982             HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "can't close source file")
983 
984     FUNC_LEAVE_NOAPI(ret_value)
985 } /* end H5D__virtual_open_source_dset() */
986 
987 
988 /*-------------------------------------------------------------------------
989  * Function:    H5D__virtual_reset_source_dset
990  *
991  * Purpose:     Frees space referenced by a source dataset struct.
992  *
993  * Return:      Non-negative on success/Negative on failure
994  *
995  * Programmer:  Neil Fortner
996  *              May 20, 2015
997  *
998  *-------------------------------------------------------------------------
999  */
1000 static herr_t
H5D__virtual_reset_source_dset(H5O_storage_virtual_ent_t * virtual_ent,H5O_storage_virtual_srcdset_t * source_dset)1001 H5D__virtual_reset_source_dset(H5O_storage_virtual_ent_t *virtual_ent,
1002     H5O_storage_virtual_srcdset_t *source_dset)
1003 {
1004     herr_t      ret_value = SUCCEED;    /* Return value */
1005 
1006     FUNC_ENTER_STATIC
1007 
1008     /* Sanity check */
1009     HDassert(source_dset);
1010 
1011     /* Free dataset */
1012     if(source_dset->dset) {
1013         if(H5D_close(source_dset->dset) < 0)
1014             HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to close source dataset")
1015         source_dset->dset = NULL;
1016     } /* end if */
1017 
1018     /* Free file name */
1019     if(virtual_ent->parsed_source_file_name
1020             && (source_dset->file_name
1021             != virtual_ent->parsed_source_file_name->name_segment))
1022         source_dset->file_name = (char *)H5MM_xfree(source_dset->file_name);
1023     else
1024         HDassert((source_dset->file_name == virtual_ent->source_file_name)
1025                 || (virtual_ent->parsed_source_file_name
1026                 && (source_dset->file_name
1027                 == virtual_ent->parsed_source_file_name->name_segment))
1028                 || !source_dset->file_name);
1029 
1030     /* Free dataset name */
1031     if(virtual_ent->parsed_source_dset_name
1032             && (source_dset->dset_name
1033             != virtual_ent->parsed_source_dset_name->name_segment))
1034         source_dset->dset_name = (char *)H5MM_xfree(source_dset->dset_name);
1035     else
1036         HDassert((source_dset->dset_name == virtual_ent->source_dset_name)
1037                 || (virtual_ent->parsed_source_dset_name
1038                 && (source_dset->dset_name
1039                 == virtual_ent->parsed_source_dset_name->name_segment))
1040                 || !source_dset->dset_name);
1041 
1042     /* Free clipped virtual selection */
1043     if(source_dset->clipped_virtual_select) {
1044         if(source_dset->clipped_virtual_select != source_dset->virtual_select)
1045             if(H5S_close(source_dset->clipped_virtual_select) < 0)
1046                 HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual selection")
1047         source_dset->clipped_virtual_select = NULL;
1048     } /* end if */
1049 
1050     /* Free virtual selection */
1051     if(source_dset->virtual_select) {
1052         if(H5S_close(source_dset->virtual_select) < 0)
1053             HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release virtual selection")
1054         source_dset->virtual_select = NULL;
1055     } /* end if */
1056 
1057     /* Free clipped source selection */
1058     if(source_dset->clipped_source_select) {
1059         if(source_dset->clipped_source_select != virtual_ent->source_select)
1060             if(H5S_close(source_dset->clipped_source_select) < 0)
1061                 HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source selection")
1062         source_dset->clipped_source_select = NULL;
1063     } /* end if */
1064 
1065     /* The projected memory space should never exist when this function is
1066      * called */
1067     HDassert(!source_dset->projected_mem_space);
1068 
1069     /* Note the lack of a done: label.  This is because there are no HGOTO_ERROR
1070      * calls.  If one is added, a done: label must also be added */
1071     FUNC_LEAVE_NOAPI(ret_value)
1072 } /* end H5D__virtual_reset_source_dset() */
1073 
1074 
1075 /*-------------------------------------------------------------------------
1076  * Function:    H5D__virtual_str_append
1077  *
1078  * Purpose:     Appends src_len bytes of the string src to the position *p
1079  *              in the buffer *buf (allocating *buf if necessary).
1080  *
1081  * Return:      Non-negative on success/Negative on failure
1082  *
1083  * Programmer:  Neil Fortner
1084  *              May 19, 2015
1085  *
1086  *-------------------------------------------------------------------------
1087  */
1088 static herr_t
H5D__virtual_str_append(const char * src,size_t src_len,char ** p,char ** buf,size_t * buf_size)1089 H5D__virtual_str_append(const char *src, size_t src_len, char **p, char **buf,
1090     size_t *buf_size)
1091 {
1092     herr_t      ret_value = SUCCEED;    /* Return value */
1093 
1094     FUNC_ENTER_STATIC
1095 
1096     /* Sanity check */
1097     HDassert(src);
1098     HDassert(src_len > 0);
1099     HDassert(p);
1100     HDassert(buf);
1101     HDassert(*p >= *buf);
1102     HDassert(buf_size);
1103 
1104     /* Allocate or extend buffer if necessary */
1105     if(!*buf) {
1106         HDassert(!*p);
1107         HDassert(*buf_size == 0);
1108 
1109         /* Allocate buffer */
1110         if(NULL == (*buf = (char *)H5MM_malloc(src_len + (size_t)1)))
1111             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
1112         *buf_size = src_len + (size_t)1;
1113         *p = *buf;
1114     } /* end if */
1115     else {
1116         size_t p_offset = (size_t)(*p - *buf); /* Offset of p within buf */
1117 
1118         /* Extend buffer if necessary */
1119         if((p_offset + src_len + (size_t)1) > *buf_size) {
1120             char *tmp_buf;
1121             size_t tmp_buf_size;
1122 
1123             /* Calculate new size of buffer */
1124             tmp_buf_size = MAX(p_offset + src_len + (size_t)1,
1125                     *buf_size * (size_t)2);
1126 
1127             /* Reallocate buffer */
1128             if(NULL == (tmp_buf = (char *)H5MM_realloc(*buf, tmp_buf_size)))
1129                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to reallocate name segment buffer")
1130             *buf = tmp_buf;
1131             *buf_size = tmp_buf_size;
1132             *p = *buf + p_offset;
1133         } /* end if */
1134     } /* end else */
1135 
1136     /* Copy string to *p.  Note that since src in not NULL terminated, we must
1137      * use memcpy */
1138     (void)HDmemcpy(*p, src, src_len);
1139 
1140     /* Advance *p */
1141     *p += src_len;
1142 
1143     /* Add NULL terminator */
1144     **p = '\0';
1145 
1146 done:
1147     FUNC_LEAVE_NOAPI(ret_value);
1148 } /* end H5D__virtual_str_append() */
1149 
1150 
1151 /*-------------------------------------------------------------------------
1152  * Function:    H5D_virtual_parse_source_name
1153  *
1154  * Purpose:     Parses a source file or dataset name.
1155  *
1156  * Return:      Non-negative on success/Negative on failure
1157  *
1158  * Programmer:  Neil Fortner
1159  *              May 18, 2015
1160  *
1161  *-------------------------------------------------------------------------
1162  */
1163 herr_t
H5D_virtual_parse_source_name(const char * source_name,H5O_storage_virtual_name_seg_t ** parsed_name,size_t * static_strlen,size_t * nsubs)1164 H5D_virtual_parse_source_name(const char *source_name,
1165     H5O_storage_virtual_name_seg_t **parsed_name, size_t *static_strlen,
1166     size_t *nsubs)
1167 {
1168     H5O_storage_virtual_name_seg_t *tmp_parsed_name = NULL;
1169     H5O_storage_virtual_name_seg_t **tmp_parsed_name_p = &tmp_parsed_name;
1170     size_t      tmp_static_strlen;
1171     size_t      tmp_strlen;
1172     size_t      tmp_nsubs = 0;
1173     const char  *p;
1174     const char  *pct;
1175     char        *name_seg_p = NULL;
1176     size_t      name_seg_size = 0;
1177     herr_t      ret_value = SUCCEED;    /* Return value */
1178 
1179     FUNC_ENTER_NOAPI(FAIL)
1180 
1181     /* Sanity check */
1182     HDassert(source_name);
1183     HDassert(parsed_name);
1184     HDassert(static_strlen);
1185     HDassert(nsubs);
1186 
1187     /* Initialize p and tmp_static_strlen */
1188     p = source_name;
1189     tmp_static_strlen = tmp_strlen = HDstrlen(source_name);
1190 
1191     /* Iterate over name */
1192     /* Note this will not work with UTF-8!  We should support this eventually
1193      * -NAF 5/18/2015 */
1194     while((pct = HDstrchr(p, '%'))) {
1195         HDassert(pct >= p);
1196 
1197         /* Allocate name segment struct if necessary */
1198         if(!*tmp_parsed_name_p)
1199             if(NULL == (*tmp_parsed_name_p = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
1200                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
1201 
1202         /* Check for type of format specifier */
1203         if(pct[1] == 'b') {
1204             /* Check for blank string before specifier */
1205             if(pct != p)
1206                 /* Append string to name segment */
1207                 if(H5D__virtual_str_append(p, (size_t)(pct - p), &name_seg_p, &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
1208                     HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment")
1209 
1210             /* Update other variables */
1211             tmp_parsed_name_p = &(*tmp_parsed_name_p)->next;
1212             tmp_static_strlen -= 2;
1213             tmp_nsubs++;
1214             name_seg_p = NULL;
1215             name_seg_size = 0;
1216         } /* end if */
1217         else if(pct[1] == '%') {
1218             /* Append string to name segment (include first '%') */
1219             if(H5D__virtual_str_append(p, (size_t)(pct - p) + (size_t)1, &name_seg_p, &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
1220                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment")
1221 
1222             /* Update other variables */
1223             tmp_static_strlen -= 1;
1224         } /* end else */
1225         else
1226             HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid format specifier")
1227 
1228         p = pct + 2;
1229     } /* end while */
1230 
1231     /* Copy last segment of name, if any, unless the parsed name was not
1232      * allocated */
1233     if(tmp_parsed_name) {
1234         HDassert(p >= source_name);
1235         if(*p == '\0')
1236             HDassert((size_t)(p - source_name) == tmp_strlen);
1237         else {
1238             HDassert((size_t)(p - source_name) < tmp_strlen);
1239 
1240             /* Allocate name segment struct if necessary */
1241             if(!*tmp_parsed_name_p)
1242                 if(NULL == (*tmp_parsed_name_p = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
1243                     HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
1244 
1245             /* Append string to name segment */
1246             if(H5D__virtual_str_append(p, tmp_strlen - (size_t)(p - source_name), &name_seg_p, &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
1247                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment")
1248         } /* end else */
1249     } /* end if */
1250 
1251     /* Set return values */
1252     *parsed_name = tmp_parsed_name;
1253     tmp_parsed_name = NULL;
1254     *static_strlen = tmp_static_strlen;
1255     *nsubs = tmp_nsubs;
1256 
1257 done:
1258     if(tmp_parsed_name) {
1259         HDassert(ret_value < 0);
1260         H5D_virtual_free_parsed_name(tmp_parsed_name);
1261     } /* end if */
1262 
1263     FUNC_LEAVE_NOAPI(ret_value)
1264 } /* end H5D_virtual_parse_source_name() */
1265 
1266 
1267 /*-------------------------------------------------------------------------
1268  * Function:    H5D__virtual_copy_parsed_name
1269  *
1270  * Purpose:     Deep copies a parsed source file or dataset name.
1271  *
1272  * Return:      Non-negative on success/Negative on failure
1273  *
1274  * Programmer:  Neil Fortner
1275  *              May 19, 2015
1276  *
1277  *-------------------------------------------------------------------------
1278  */
1279 static herr_t
H5D__virtual_copy_parsed_name(H5O_storage_virtual_name_seg_t ** dst,H5O_storage_virtual_name_seg_t * src)1280 H5D__virtual_copy_parsed_name(H5O_storage_virtual_name_seg_t **dst,
1281     H5O_storage_virtual_name_seg_t *src)
1282 {
1283     H5O_storage_virtual_name_seg_t *tmp_dst = NULL;
1284     H5O_storage_virtual_name_seg_t *p_src = src;
1285     H5O_storage_virtual_name_seg_t **p_dst = &tmp_dst;
1286     herr_t          ret_value = SUCCEED;
1287 
1288     FUNC_ENTER_STATIC
1289 
1290     /* Sanity check */
1291     HDassert(dst);
1292 
1293     /* Walk over parsed name, duplicating it */
1294     while(p_src) {
1295         /* Allocate name segment struct */
1296         if(NULL == (*p_dst = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
1297             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
1298 
1299         /* Duplicate name segment */
1300         if(p_src->name_segment) {
1301             if(NULL == ((*p_dst)->name_segment = H5MM_strdup(p_src->name_segment)))
1302                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to duplicate name segment")
1303         } /* end if */
1304 
1305         /* Advance pointers */
1306         p_src = p_src->next;
1307         p_dst = &(*p_dst)->next;
1308     } /* end while */
1309 
1310     /* Set dst */
1311     *dst = tmp_dst;
1312     tmp_dst = NULL;
1313 
1314 done:
1315     if(tmp_dst) {
1316         HDassert(ret_value < 0);
1317         H5D_virtual_free_parsed_name(tmp_dst);
1318     } /* end if */
1319 
1320     FUNC_LEAVE_NOAPI(ret_value)
1321 } /* end H5D__virtual_copy_parsed_name() */
1322 
1323 
1324 /*-------------------------------------------------------------------------
1325  * Function:    H5D_virtual_free_parsed_name
1326  *
1327  * Purpose:     Frees the provided parsed name.
1328  *
1329  * Return:      void
1330  *
1331  * Programmer:  Neil Fortner
1332  *              May 19, 2015
1333  *
1334  *-------------------------------------------------------------------------
1335  */
1336 herr_t
H5D_virtual_free_parsed_name(H5O_storage_virtual_name_seg_t * name_seg)1337 H5D_virtual_free_parsed_name(H5O_storage_virtual_name_seg_t *name_seg)
1338 {
1339     H5O_storage_virtual_name_seg_t *next_seg;
1340     herr_t ret_value = SUCCEED;         /* Return value */
1341 
1342     FUNC_ENTER_NOAPI(FAIL)
1343 
1344     /* Walk name segments, freeing them */
1345     while(name_seg) {
1346         (void)H5MM_xfree(name_seg->name_segment);
1347         next_seg = name_seg->next;
1348         (void)H5FL_FREE(H5O_storage_virtual_name_seg_t, name_seg);
1349         name_seg = next_seg;
1350     } /* end while */
1351 
1352 done:
1353     FUNC_LEAVE_NOAPI(ret_value)
1354 } /* end H5D_virtual_free_parsed_name() */
1355 
1356 
1357 /*-------------------------------------------------------------------------
1358  * Function:    H5D__virtual_build_source_name
1359  *
1360  * Purpose:     Builds a source file or dataset name from a parsed name.
1361  *
1362  * Return:      Non-negative on success/Negative on failure
1363  *
1364  * Programmer:  Neil Fortner
1365  *              May 18, 2015
1366  *
1367  *-------------------------------------------------------------------------
1368  */
1369 static herr_t
H5D__virtual_build_source_name(char * source_name,const H5O_storage_virtual_name_seg_t * parsed_name,size_t static_strlen,size_t nsubs,hsize_t blockno,char ** built_name)1370 H5D__virtual_build_source_name(char *source_name,
1371     const H5O_storage_virtual_name_seg_t *parsed_name, size_t static_strlen,
1372     size_t nsubs, hsize_t blockno, char **built_name)
1373 {
1374     char        *tmp_name = NULL;       /* Name buffer */
1375     herr_t      ret_value = SUCCEED;    /* Return value */
1376 
1377     FUNC_ENTER_STATIC
1378 
1379     /* Sanity check */
1380     HDassert(source_name);
1381     HDassert(built_name);
1382 
1383     /* Check for static name */
1384     if(nsubs == 0) {
1385         if(parsed_name)
1386             *built_name = parsed_name->name_segment;
1387         else
1388             *built_name = source_name;
1389     } /* end if */
1390     else {
1391         const H5O_storage_virtual_name_seg_t *name_seg = parsed_name;
1392         char *p;
1393         hsize_t blockno_down = blockno;
1394         size_t blockno_len = 1;
1395         size_t name_len;
1396         size_t name_len_rem;
1397         size_t seg_len;
1398         size_t nsubs_rem = nsubs;
1399 
1400         HDassert(parsed_name);
1401 
1402         /* Calculate length of printed block number */
1403         do {
1404             blockno_down /= (hsize_t)10;
1405             if(blockno_down == 0)
1406                 break;
1407             blockno_len++;
1408         } while(1);
1409 
1410         /* Calculate length of name buffer */
1411         name_len_rem = name_len = static_strlen + (nsubs * blockno_len) + (size_t)1;
1412 
1413         /* Allocate name buffer */
1414         if(NULL == (tmp_name = (char *)H5MM_malloc(name_len)))
1415             HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name buffer")
1416         p = tmp_name;
1417 
1418         /* Build name */
1419         do {
1420             /* Add name segment */
1421             if(name_seg->name_segment) {
1422                 seg_len = HDstrlen(name_seg->name_segment);
1423                 HDassert(seg_len > 0);
1424                 HDassert(seg_len < name_len_rem);
1425                 HDstrncpy(p, name_seg->name_segment, name_len_rem);
1426                 name_len_rem -= seg_len;
1427                 p += seg_len;
1428             } /* end if */
1429 
1430             /* Add block number */
1431             if(nsubs_rem > 0) {
1432                 HDassert(blockno_len < name_len_rem);
1433                 if(HDsnprintf(p, name_len_rem, "%llu", (long long unsigned)blockno) < 0)
1434                     HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write block number to string")
1435                 name_len_rem -= blockno_len;
1436                 p += blockno_len;
1437                 nsubs_rem--;
1438             } /* end if */
1439 
1440             /* Advance name_seg */
1441             name_seg = name_seg->next;
1442         } while(name_seg);
1443 
1444         /* Assign built_name */
1445         *built_name = tmp_name;
1446         tmp_name = NULL;
1447     } /* end else */
1448 
1449 done:
1450     if(tmp_name) {
1451         HDassert(ret_value < 0);
1452         H5MM_free(tmp_name);
1453     } /* end if */
1454 
1455     FUNC_LEAVE_NOAPI(ret_value)
1456 } /* end H5D__virtual_build_source_name() */
1457 
1458 
1459 /*-------------------------------------------------------------------------
1460  * Function:    H5D__virtual_set_extent_unlim
1461  *
1462  * Purpose:     Sets the extent of the virtual dataset by checking the
1463  *              extents of source datasets where an unlimited selection
1464  *              matching.  Dimensions that are not unlimited in any
1465  *              virtual mapping selections are not affected.
1466  *
1467  * Return:      Non-negative on success/Negative on failure
1468  *
1469  * Programmer:  Neil Fortner
1470  *              April 22, 2015
1471  *
1472  *-------------------------------------------------------------------------
1473  */
1474 herr_t
H5D__virtual_set_extent_unlim(const H5D_t * dset)1475 H5D__virtual_set_extent_unlim(const H5D_t *dset)
1476 {
1477     H5O_storage_virtual_t *storage;
1478     hsize_t     new_dims[H5S_MAX_RANK];
1479     hsize_t     curr_dims[H5S_MAX_RANK];
1480     hsize_t     clip_size;
1481     int         rank;
1482     hbool_t     changed = FALSE;        /* Whether the VDS extent changed */
1483     size_t      i, j;
1484     herr_t      ret_value = SUCCEED;    /* Return value */
1485 
1486     FUNC_ENTER_PACKAGE
1487 
1488     /* Sanity check */
1489     HDassert(dset);
1490     HDassert(dset->shared->layout.storage.type == H5D_VIRTUAL);
1491     storage = &dset->shared->layout.storage.u.virt;
1492     HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
1493 
1494     /* Get rank of VDS */
1495     if((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0)
1496         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
1497 
1498     /* Initialize new_dims to HSIZE_UNDEF */
1499     for(i = 0; i < (size_t)rank; i++)
1500         new_dims[i] = HSIZE_UNDEF;
1501 
1502     /* Iterate over mappings */
1503     for(i = 0; i < storage->list_nused; i++)
1504         /* Check for unlimited dimension */
1505         if(storage->list[i].unlim_dim_virtual >= 0) {
1506             /* Check for "printf" source dataset resolution */
1507             if(storage->list[i].unlim_dim_source >= 0 ) {
1508                 /* Non-printf mapping */
1509                 /* Open source dataset */
1510                 if(!storage->list[i].source_dset.dset)
1511                     if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].source_dset) < 0)
1512                         HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
1513 
1514                 /* Check if source dataset is open */
1515                 if(storage->list[i].source_dset.dset) {
1516                     /* Retrieve current source dataset extent and patch mapping
1517                      */
1518                     if(H5S_extent_copy(storage->list[i].source_select, storage->list[i].source_dset.dset->shared->space) < 0)
1519                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent")
1520 
1521                     /* Get source space dimenstions */
1522                     if(H5S_get_simple_extent_dims(storage->list[i].source_select, curr_dims, NULL) < 0)
1523                         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get source space dimensions")
1524 
1525                     /* Check if the source extent in the unlimited dimension
1526                      * changed since the last time the VDS extent/mapping
1527                      * was updated */
1528                     if(curr_dims[storage->list[i].unlim_dim_source]
1529                             == storage->list[i].unlim_extent_source)
1530                         /* Use cached result for clip size */
1531                         clip_size = storage->list[i].clip_size_virtual;
1532                     else {
1533                         /* Get size that virtual selection would be clipped to
1534                          * to match size of source selection within source
1535                          * extent */
1536                         clip_size = H5S_hyper_get_clip_extent_match(storage->list[i].source_dset.virtual_select, storage->list[i].source_select, curr_dims[storage->list[i].unlim_dim_source], storage->view == H5D_VDS_FIRST_MISSING);
1537 
1538                         /* If we are setting the extent by the last available
1539                          * data, clip virtual_select and source_select.  Note
1540                          * that if we used the cached clip_size above or it
1541                          * happens to be the same, the virtual selection will
1542                          * already be clipped to the correct size.  Likewise,
1543                          * if we used the cached clip_size the source selection
1544                          * will already be correct. */
1545                         if(storage->view == H5D_VDS_LAST_AVAILABLE) {
1546                             if(clip_size != storage->list[i].clip_size_virtual) {
1547                                 /* Close previous clipped virtual selection, if
1548                                  * any */
1549                                 if(storage->list[i].source_dset.clipped_virtual_select) {
1550                                     HDassert(storage->list[i].source_dset.clipped_virtual_select
1551                                             != storage->list[i].source_dset.virtual_select);
1552                                     if(H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
1553                                         HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
1554                                 } /* end if */
1555 
1556                                 /* Copy virtual selection */
1557                                 if(NULL == (storage->list[i].source_dset.clipped_virtual_select = H5S_copy(storage->list[i].source_dset.virtual_select, FALSE, TRUE)))
1558                                     HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
1559 
1560                                 /* Clip virtual selection */
1561                                 if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, clip_size))
1562                                     HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1563                             } /* end if */
1564 
1565                             /* Close previous clipped source selection, if any
1566                              */
1567                             if(storage->list[i].source_dset.clipped_source_select) {
1568                                 HDassert(storage->list[i].source_dset.clipped_source_select
1569                                         != storage->list[i].source_select);
1570                                 if(H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
1571                                     HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
1572                             } /* end if */
1573 
1574                             /* Copy source selection */
1575                             if(NULL == (storage->list[i].source_dset.clipped_source_select = H5S_copy(storage->list[i].source_select, FALSE, TRUE)))
1576                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
1577 
1578                             /* Clip source selection */
1579                             if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, curr_dims[storage->list[i].unlim_dim_source]))
1580                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1581                         } /* end if */
1582 
1583                         /* Update cached values unlim_extent_source and
1584                          * clip_size_virtual */
1585                         storage->list[i].unlim_extent_source = curr_dims[storage->list[i].unlim_dim_source];
1586                         storage->list[i].clip_size_virtual = clip_size;
1587                     } /* end else */
1588                 } /* end if */
1589                 else
1590                     clip_size = 0;
1591             } /* end if */
1592             else {
1593                 /* printf mapping */
1594                 hsize_t first_missing = 0;  /* First missing dataset in the current block of missing datasets */
1595 
1596                 /* Search for source datasets */
1597                 HDassert(storage->printf_gap != HSIZE_UNDEF);
1598                 for(j = 0; j <= (storage->printf_gap + first_missing); j++) {
1599                     /* Check for running out of space in sub_dset array */
1600                     if(j >= (hsize_t)storage->list[i].sub_dset_nalloc) {
1601                         if(storage->list[i].sub_dset_nalloc == 0) {
1602                             /* Allocate sub_dset */
1603                             if(NULL == (storage->list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_calloc(H5D_VIRTUAL_DEF_SUB_DSET_SIZE * sizeof(H5O_storage_virtual_srcdset_t))))
1604                                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate sub dataset array")
1605                             storage->list[i].sub_dset_nalloc = H5D_VIRTUAL_DEF_SUB_DSET_SIZE;
1606                         } /* end if */
1607                         else {
1608                             H5O_storage_virtual_srcdset_t *tmp_sub_dset;
1609 
1610                             /* Extend sub_dset */
1611                             if(NULL == (tmp_sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_realloc(storage->list[i].sub_dset, 2 * storage->list[i].sub_dset_nalloc * sizeof(H5O_storage_virtual_srcdset_t))))
1612                                 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend sub dataset array")
1613                             storage->list[i].sub_dset = tmp_sub_dset;
1614 
1615                             /* Clear new space in sub_dset */
1616                             (void)HDmemset(&storage->list[i].sub_dset[storage->list[i].sub_dset_nalloc], 0, storage->list[i].sub_dset_nalloc * sizeof(H5O_storage_virtual_srcdset_t));
1617 
1618                             /* Update sub_dset_nalloc */
1619                             storage->list[i].sub_dset_nalloc *= 2;
1620                         } /* end else */
1621                     } /* end if */
1622 
1623                     /* Check if the dataset was already opened */
1624                     if(storage->list[i].sub_dset[j].dset_exists)
1625                         first_missing = j + 1;
1626                     else {
1627                         /* Resolve file name */
1628                         if(!storage->list[i].sub_dset[j].file_name)
1629                             if(H5D__virtual_build_source_name(storage->list[i].source_file_name, storage->list[i].parsed_source_file_name, storage->list[i].psfn_static_strlen, storage->list[i].psfn_nsubs, j, &storage->list[i].sub_dset[j].file_name) < 0)
1630                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source file name")
1631 
1632                         /* Resolve dset name */
1633                         if(!storage->list[i].sub_dset[j].dset_name)
1634                             if(H5D__virtual_build_source_name(storage->list[i].source_dset_name, storage->list[i].parsed_source_dset_name, storage->list[i].psdn_static_strlen, storage->list[i].psdn_nsubs, j, &storage->list[i].sub_dset[j].dset_name) < 0)
1635                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source dataset name")
1636 
1637                         /* Resolve virtual selection for block */
1638                         if(!storage->list[i].sub_dset[j].virtual_select)
1639                             if(NULL == (storage->list[i].sub_dset[j].virtual_select = H5S_hyper_get_unlim_block(storage->list[i].source_dset.virtual_select, j)))
1640                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get block in unlimited selection")
1641 
1642                         /* Initialize clipped selections */
1643                         if(!storage->list[i].sub_dset[j].clipped_source_select)
1644                             storage->list[i].sub_dset[j].clipped_source_select = storage->list[i].source_select;
1645                         if(!storage->list[i].sub_dset[j].clipped_virtual_select)
1646                             storage->list[i].sub_dset[j].clipped_virtual_select = storage->list[i].sub_dset[j].virtual_select;
1647 
1648                         /* Open source dataset */
1649                         if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].sub_dset[j]) < 0)
1650                             HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
1651 
1652                         if(storage->list[i].sub_dset[j].dset) {
1653                             /* Update first_missing */
1654                             first_missing = j + 1;
1655 
1656                             /* Close source dataset so we don't have huge
1657                              * numbers of datasets open */
1658                             if(H5D_close(storage->list[i].sub_dset[j].dset) < 0)
1659                                 HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to close source dataset")
1660                             storage->list[i].sub_dset[j].dset = NULL;
1661                         } /* end if */
1662                     } /* end else */
1663                 } /* end for */
1664 
1665                 /* Check if the size changed */
1666                 if((first_missing == (hsize_t)storage->list[i].sub_dset_nused)
1667                         && (storage->list[i].clip_size_virtual != HSIZE_UNDEF))
1668                     /* Use cached clip_size */
1669                     clip_size = storage->list[i].clip_size_virtual;
1670                 else {
1671                     /* Check for no datasets */
1672                     if(first_missing == 0)
1673                         /* Set clip size to 0 */
1674                         clip_size = (hsize_t)0;
1675                     else {
1676                         hsize_t         bounds_start[H5S_MAX_RANK];
1677                         hsize_t         bounds_end[H5S_MAX_RANK];
1678 
1679                         /* Get clip size from selection */
1680                         if(storage->view == H5D_VDS_LAST_AVAILABLE) {
1681                             /* Get bounds from last valid virtual selection */
1682                             if(H5S_SELECT_BOUNDS(storage->list[i].sub_dset[first_missing - (hsize_t)1].virtual_select, bounds_start, bounds_end) < 0)
1683                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
1684 
1685                             /* Set clip_size to bounds_end in unlimited
1686                              * dimension */
1687                             clip_size = bounds_end[storage->list[i].unlim_dim_virtual] + (hsize_t)1;
1688                         } /* end if */
1689                         else {
1690                             /* Get bounds from first missing virtual selection
1691                              */
1692                             if(H5S_SELECT_BOUNDS(storage->list[i].sub_dset[first_missing].virtual_select, bounds_start, bounds_end) < 0)
1693                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
1694 
1695                             /* Set clip_size to bounds_start in unlimited
1696                              * dimension */
1697                             clip_size = bounds_start[storage->list[i].unlim_dim_virtual];
1698                         } /* end else */
1699                     } /* end else */
1700 
1701                     /* Set sub_dset_nused and clip_size_virtual */
1702                     storage->list[i].sub_dset_nused = (size_t)first_missing;
1703                     storage->list[i].clip_size_virtual = clip_size;
1704                 } /* end else */
1705             } /* end else */
1706 
1707             /* Update new_dims */
1708             if((new_dims[storage->list[i].unlim_dim_virtual] == HSIZE_UNDEF)
1709                     || (storage->view == H5D_VDS_FIRST_MISSING ? (clip_size < (hsize_t)new_dims[storage->list[i].unlim_dim_virtual])
1710                         : (clip_size > (hsize_t)new_dims[storage->list[i].unlim_dim_virtual])))
1711                 new_dims[storage->list[i].unlim_dim_virtual] = clip_size;
1712         } /* end if */
1713 
1714     /* Get current VDS dimensions */
1715     if(H5S_get_simple_extent_dims(dset->shared->space, curr_dims, NULL) < 0)
1716         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
1717 
1718     /* Calculate new extent */
1719     for(i = 0; i < (size_t)rank; i++) {
1720         if(new_dims[i] == HSIZE_UNDEF)
1721             new_dims[i] = curr_dims[i];
1722         else if(new_dims[i] < storage->min_dims[i])
1723             new_dims[i] = storage->min_dims[i];
1724         if(new_dims[i] != curr_dims[i])
1725             changed = TRUE;
1726     } /* end for */
1727 
1728     /* Update extent if it changed */
1729     if(changed) {
1730         /* Update VDS extent */
1731         if(H5S_set_extent(dset->shared->space, new_dims) < 0)
1732             HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
1733 
1734         /* Mark the space as dirty, for later writing to the file */
1735         if(H5F_INTENT(dset->oloc.file) & H5F_ACC_RDWR)
1736             if(H5D__mark(dset, H5D_MARK_SPACE) < 0)
1737                 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark dataspace as dirty")
1738     } /* end if */
1739 
1740     /* If we did not change the VDS dimensions, there is nothing more to update
1741      */
1742     if(changed || (!storage->init && (storage->view == H5D_VDS_FIRST_MISSING))) {
1743         /* Iterate over mappings again to update source selections and virtual
1744          * mapping extents */
1745         for(i = 0; i < storage->list_nused; i++) {
1746             /* If there is an unlimited dimension, we are setting extent by the
1747              * minimum of mappings, and the virtual extent in the unlimited
1748              * dimension has changed since the last time the VDS extent/mapping
1749              * was updated, we must adjust the selections */
1750             if((storage->list[i].unlim_dim_virtual >= 0)
1751                     && (storage->view == H5D_VDS_FIRST_MISSING)
1752                     && (new_dims[storage->list[i].unlim_dim_virtual]
1753                     != storage->list[i].unlim_extent_virtual)) {
1754                 /* Check for "printf" style mapping */
1755                 if(storage->list[i].unlim_dim_source >= 0) {
1756                     /* Non-printf mapping */
1757                     /* Close previous clipped virtual selection, if any */
1758                     if(storage->list[i].source_dset.clipped_virtual_select) {
1759                         HDassert(storage->list[i].source_dset.clipped_virtual_select
1760                             != storage->list[i].source_dset.virtual_select);
1761                         if(H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
1762                             HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
1763                     } /* end if */
1764 
1765                     /* Copy virtual selection */
1766                     if(NULL == (storage->list[i].source_dset.clipped_virtual_select = H5S_copy(storage->list[i].source_dset.virtual_select, FALSE, TRUE)))
1767                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
1768 
1769                     /* Clip space to virtual extent */
1770                     if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, new_dims[storage->list[i].unlim_dim_source]))
1771                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1772 
1773                     /* Get size that source selection will be clipped to to
1774                      * match size of virtual selection */
1775                     clip_size = H5S_hyper_get_clip_extent(storage->list[i].source_select, storage->list[i].source_dset.clipped_virtual_select, FALSE);
1776 
1777                     /* Check if the clip size changed */
1778                     if(clip_size != storage->list[i].clip_size_source) {
1779                         /* Close previous clipped source selection, if any */
1780                         if(storage->list[i].source_dset.clipped_source_select) {
1781                             HDassert(storage->list[i].source_dset.clipped_source_select
1782                                 != storage->list[i].source_select);
1783                             if(H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
1784                                 HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
1785                         } /* end if */
1786 
1787                         /* Copy source selection */
1788                         if(NULL == (storage->list[i].source_dset.clipped_source_select = H5S_copy(storage->list[i].source_select, FALSE, TRUE)))
1789                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
1790 
1791                         /* Clip source selection */
1792                         if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, clip_size))
1793                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1794 
1795                         /* Update cached value clip_size_source */
1796                         storage->list[i].clip_size_source = clip_size;
1797                     } /* end if */
1798                 } /* end if */
1799                 else {
1800                     /* printf mapping */
1801                     hsize_t first_inc_block;
1802                     hbool_t partial_block;
1803 
1804                     /* Get index of first incomplete block in virtual
1805                      * selection */
1806                     first_inc_block = H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, new_dims[storage->list[i].unlim_dim_virtual], &partial_block);
1807 
1808                     /* Iterate over sub datasets */
1809                     for(j = 0; j < storage->list[i].sub_dset_nalloc; j++) {
1810                         /* Close previous clipped source selection, if any */
1811                         if(storage->list[i].sub_dset[j].clipped_source_select
1812                                 != storage->list[i].source_select) {
1813                             if(storage->list[i].sub_dset[j].clipped_source_select)
1814                                 if(H5S_close(storage->list[i].sub_dset[j].clipped_source_select) < 0)
1815                                     HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
1816 
1817                             /* Initialize clipped source selection to point to
1818                              * base source selection */
1819                             storage->list[i].sub_dset[j].clipped_source_select = storage->list[i].source_select;
1820                         } /* end if */
1821 
1822                         /* Close previous clipped virtual selection, if any */
1823                         if(storage->list[i].sub_dset[j].clipped_virtual_select
1824                                 != storage->list[i].sub_dset[j].virtual_select) {
1825                             if(storage->list[i].sub_dset[j].clipped_virtual_select)
1826                                 if(H5S_close(storage->list[i].sub_dset[j].clipped_virtual_select) < 0)
1827                                     HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
1828 
1829                             /* Initialize clipped virtual selection to point to
1830                              * unclipped virtual selection */
1831                             storage->list[i].sub_dset[j].clipped_virtual_select = storage->list[i].sub_dset[j].virtual_select;
1832                         } /* end if */
1833 
1834                         /* Only initialize clipped selections if it is a
1835                          * complete block, for incomplete blocks defer to
1836                          * H5D__virtual_pre_io() as we may not have a valid
1837                          * source extent here.  For unused blocks we will never
1838                          * need clipped selections (until the extent is
1839                          * recalculated in this function). */
1840                         if(j >= (size_t)first_inc_block) {
1841                             /* Clear clipped source and virtual selections */
1842                             storage->list[i].sub_dset[j].clipped_source_select = NULL;
1843                             storage->list[i].sub_dset[j].clipped_virtual_select = NULL;
1844                         } /* end if */
1845                     } /* end for */
1846                 } /* end else */
1847 
1848                 /* Update cached value unlim_extent_virtual */
1849                 storage->list[i].unlim_extent_virtual = new_dims[storage->list[i].unlim_dim_virtual];
1850             } /* end if */
1851 
1852             /* Update top level virtual_select and clipped_virtual_select
1853              * extents */
1854             if(H5S_set_extent(storage->list[i].source_dset.virtual_select, new_dims) < 0)
1855                 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
1856             if((storage->list[i].source_dset.clipped_virtual_select
1857                     != storage->list[i].source_dset.virtual_select)
1858                     && storage->list[i].source_dset.clipped_virtual_select)
1859                 if(H5S_set_extent(storage->list[i].source_dset.clipped_virtual_select, new_dims) < 0)
1860                     HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
1861 
1862             /* Update sub dataset virtual_select and clipped_virtual_select
1863              * extents */
1864             for(j = 0; j < storage->list[i].sub_dset_nalloc; j++)
1865                 if(storage->list[i].sub_dset[j].virtual_select) {
1866                     if(H5S_set_extent(storage->list[i].sub_dset[j].virtual_select, new_dims) < 0)
1867                         HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
1868                     if((storage->list[i].sub_dset[j].clipped_virtual_select
1869                             != storage->list[i].sub_dset[j].virtual_select)
1870                             && storage->list[i].sub_dset[j].clipped_virtual_select)
1871                         if(H5S_set_extent(storage->list[i].sub_dset[j].clipped_virtual_select, new_dims) < 0)
1872                             HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
1873                 } /* end if */
1874                 else
1875                     HDassert(!storage->list[i].sub_dset[j].clipped_virtual_select);
1876         } /* end for */
1877     } /* end if */
1878 
1879     /* Mark layout as fully initialized */
1880     storage->init = TRUE;
1881 
1882 done:
1883     FUNC_LEAVE_NOAPI(ret_value)
1884 } /* end H5D__virtual_set_extent_unlim() */
1885 
1886 
1887 /*-------------------------------------------------------------------------
1888  * Function:    H5D__virtual_init_all
1889  *
1890  * Purpose:     Finishes initializing layout in preparation for I/O.
1891  *              Only necessary if H5D__virtual_set_extent_unlim() has not
1892  *              been called yet.  Initializes clipped_virtual_select and
1893  *              clipped_source_select for all mappings in this layout.
1894  *
1895  * Return:      Non-negative on success/Negative on failure
1896  *
1897  * Programmer:  Neil Fortner
1898  *              August 10, 2015
1899  *
1900  *-------------------------------------------------------------------------
1901  */
1902 static herr_t
H5D__virtual_init_all(const H5D_t * dset)1903 H5D__virtual_init_all(const H5D_t *dset)
1904 {
1905     H5O_storage_virtual_t *storage;
1906     hsize_t     virtual_dims[H5S_MAX_RANK];
1907     hsize_t     source_dims[H5S_MAX_RANK];
1908     hsize_t     clip_size;
1909     size_t      i, j;
1910     herr_t      ret_value = SUCCEED;    /* Return value */
1911 
1912     FUNC_ENTER_STATIC
1913 
1914     /* Sanity check */
1915     HDassert(dset);
1916     HDassert(dset->shared->layout.storage.type == H5D_VIRTUAL);
1917     storage = &dset->shared->layout.storage.u.virt;
1918     HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
1919 
1920     /* Get current VDS dimensions */
1921     if(H5S_get_simple_extent_dims(dset->shared->space, virtual_dims, NULL) < 0)
1922         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
1923 
1924     /* Iterate over mappings */
1925     for(i = 0; i < storage->list_nused; i++)
1926         /* Check for unlimited dimension */
1927         if(storage->list[i].unlim_dim_virtual >= 0) {
1928             /* Check for "printf" source dataset resolution */
1929             if(storage->list[i].unlim_dim_source >= 0 ) {
1930                 /* Non-printf mapping */
1931                 /* Open source dataset */
1932                 if(!storage->list[i].source_dset.dset)
1933                     if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].source_dset) < 0)
1934                         HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
1935 
1936                 /* Check if source dataset is open */
1937                 if(storage->list[i].source_dset.dset) {
1938                     /* Retrieve current source dataset extent and patch mapping
1939                      */
1940                     if(H5S_extent_copy(storage->list[i].source_select, storage->list[i].source_dset.dset->shared->space) < 0)
1941                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent")
1942 
1943                     /* Get source space dimenstions */
1944                     if(H5S_get_simple_extent_dims(storage->list[i].source_select, source_dims, NULL) < 0)
1945                         HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get source space dimensions")
1946 
1947                     /* Get size that source selection would be clipped to to
1948                      * match size of virtual selection */
1949                     clip_size = H5S_hyper_get_clip_extent_match(storage->list[i].source_select, storage->list[i].source_dset.virtual_select, virtual_dims[storage->list[i].unlim_dim_virtual], FALSE);
1950 
1951                     /* Close previous clipped virtual selection, if any */
1952                     if(storage->list[i].source_dset.clipped_virtual_select) {
1953                         HDassert(storage->list[i].source_dset.clipped_virtual_select
1954                                 != storage->list[i].source_dset.virtual_select);
1955                         if(H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
1956                             HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
1957                     } /* end if */
1958 
1959                     /* Copy virtual selection */
1960                     if(NULL == (storage->list[i].source_dset.clipped_virtual_select = H5S_copy(storage->list[i].source_dset.virtual_select, FALSE, TRUE)))
1961                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
1962 
1963                     /* Close previous clipped source selection, if any */
1964                     if(storage->list[i].source_dset.clipped_source_select) {
1965                         HDassert(storage->list[i].source_dset.clipped_source_select
1966                                 != storage->list[i].source_select);
1967                         if(H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
1968                             HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
1969                     } /* end if */
1970 
1971                     /* Copy source selection */
1972                     if(NULL == (storage->list[i].source_dset.clipped_source_select = H5S_copy(storage->list[i].source_select, FALSE, TRUE)))
1973                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
1974 
1975                     /* Check if the clip size is within the current extent of
1976                      * the source dataset */
1977                     if(clip_size <= source_dims[storage->list[i].unlim_dim_source]) {
1978                         /* Clip virtual selection to extent */
1979                         if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, virtual_dims[storage->list[i].unlim_dim_virtual]))
1980                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1981 
1982                         /* Clip source selection to clip_size */
1983                         if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, clip_size))
1984                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1985                     } /* end if */
1986                     else {
1987                         /* Get size that virtual selection will be clipped to to
1988                          * match size of source selection within source extent
1989                          */
1990                         clip_size = H5S_hyper_get_clip_extent_match(storage->list[i].source_dset.virtual_select, storage->list[i].source_select, source_dims[storage->list[i].unlim_dim_source], FALSE);
1991 
1992                         /* Clip virtual selection to clip_size */
1993                         if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, clip_size))
1994                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1995 
1996                         /* Clip source selection to extent */
1997                         if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, source_dims[storage->list[i].unlim_dim_source]))
1998                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
1999                     } /* end else */
2000                 } /* end if */
2001                 else {
2002                     HDassert(!storage->list[i].source_dset.clipped_virtual_select);
2003                     HDassert(!storage->list[i].source_dset.clipped_source_select);
2004                 } /* end else */
2005             } /* end if */
2006             else {
2007                 /* printf mapping */
2008                 size_t sub_dset_max;
2009                 hbool_t partial_block;
2010 
2011                 /* Get number of sub-source datasets in current extent */
2012                 sub_dset_max = (size_t)H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, virtual_dims[storage->list[i].unlim_dim_virtual], &partial_block);
2013                 if(partial_block)
2014                     sub_dset_max++;
2015 
2016                 /* Allocate or grow the sub_dset array if necessary */
2017                 if(!storage->list[i].sub_dset) {
2018                     /* Allocate sub_dset array */
2019                     if(NULL == (storage->list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_calloc(sub_dset_max * sizeof(H5O_storage_virtual_srcdset_t))))
2020                         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate sub dataset array")
2021 
2022                     /* Update sub_dset_nalloc */
2023                     storage->list[i].sub_dset_nalloc = sub_dset_max;
2024                 } /* end if */
2025                 else if(sub_dset_max > storage->list[i].sub_dset_nalloc) {
2026                     H5O_storage_virtual_srcdset_t *tmp_sub_dset;
2027 
2028                     /* Extend sub_dset array */
2029                     if(NULL == (tmp_sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_realloc(storage->list[i].sub_dset, sub_dset_max * sizeof(H5O_storage_virtual_srcdset_t))))
2030                         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend sub dataset array")
2031                     storage->list[i].sub_dset = tmp_sub_dset;
2032 
2033                     /* Clear new space in sub_dset */
2034                     (void)HDmemset(&storage->list[i].sub_dset[storage->list[i].sub_dset_nalloc], 0, (sub_dset_max - storage->list[i].sub_dset_nalloc) * sizeof(H5O_storage_virtual_srcdset_t));
2035 
2036                     /* Update sub_dset_nalloc */
2037                     storage->list[i].sub_dset_nalloc = sub_dset_max;
2038                 } /* end if */
2039 
2040                 /* Iterate over sub dsets */
2041                 for(j = 0; j < sub_dset_max; j++) {
2042                     /* Resolve file name */
2043                     if(!storage->list[i].sub_dset[j].file_name)
2044                         if(H5D__virtual_build_source_name(storage->list[i].source_file_name, storage->list[i].parsed_source_file_name, storage->list[i].psfn_static_strlen, storage->list[i].psfn_nsubs, j, &storage->list[i].sub_dset[j].file_name) < 0)
2045                             HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source file name")
2046 
2047                     /* Resolve dset name */
2048                     if(!storage->list[i].sub_dset[j].dset_name)
2049                         if(H5D__virtual_build_source_name(storage->list[i].source_dset_name, storage->list[i].parsed_source_dset_name, storage->list[i].psdn_static_strlen, storage->list[i].psdn_nsubs, j, &storage->list[i].sub_dset[j].dset_name) < 0)
2050                             HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source dataset name")
2051 
2052                     /* Resolve virtual selection for block */
2053                     if(!storage->list[i].sub_dset[j].virtual_select)
2054                         if(NULL == (storage->list[i].sub_dset[j].virtual_select = H5S_hyper_get_unlim_block(storage->list[i].source_dset.virtual_select, j)))
2055                             HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get block in unlimited selection")
2056 
2057                     /* Close previous clipped source selection, if any */
2058                     if(storage->list[i].sub_dset[j].clipped_source_select != storage->list[i].source_select) {
2059                         if(storage->list[i].sub_dset[j].clipped_source_select)
2060                             if(H5S_close(storage->list[i].sub_dset[j].clipped_source_select) < 0)
2061                                 HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
2062 
2063                         /* Initialize clipped source selection to point to base
2064                          * source selection */
2065                         storage->list[i].sub_dset[j].clipped_source_select = storage->list[i].source_select;
2066                     } /* end if */
2067 
2068                     /* Close previous clipped virtual selection, if any */
2069                     if(storage->list[i].sub_dset[j].clipped_virtual_select != storage->list[i].sub_dset[j].virtual_select) {
2070                         if(storage->list[i].sub_dset[j].clipped_virtual_select)
2071                             if(H5S_close(storage->list[i].sub_dset[j].clipped_virtual_select) < 0)
2072                                 HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
2073 
2074                         /* Initialize clipped virtual selection to point to
2075                          * unclipped virtual selection */
2076                         storage->list[i].sub_dset[j].clipped_virtual_select = storage->list[i].sub_dset[j].virtual_select;
2077                     } /* end if */
2078 
2079                     /* Clear clipped selections if this is a partial block,
2080                      * defer calculation of real clipped selections to
2081                      * H5D__virtual_pre_io() as we may not have a valid source
2082                      * extent here */
2083                     if((j == (sub_dset_max - 1)) && partial_block) {
2084                         /* Clear clipped source and virtual selections */
2085                         storage->list[i].sub_dset[j].clipped_source_select = NULL;
2086                         storage->list[i].sub_dset[j].clipped_virtual_select = NULL;
2087                     } /* end else */
2088                     /* Note we do not need to open the source file, this will
2089                      * happen later in H5D__virtual_pre_io() */
2090                 } /* end for */
2091 
2092                 /* Update sub_dset_nused */
2093                 storage->list[i].sub_dset_nused = sub_dset_max;
2094             } /* end else */
2095         } /* end if */
2096         else {
2097             /* Limited mapping, just make sure the clipped selections were
2098              * already set.  Again, no need to open the source file. */
2099             HDassert(storage->list[i].source_dset.clipped_virtual_select);
2100             HDassert(storage->list[i].source_dset.clipped_source_select);
2101         } /* end else */
2102 
2103     /* Mark layout as fully initialized */
2104     storage->init = TRUE;
2105 
2106 done:
2107     FUNC_LEAVE_NOAPI(ret_value)
2108 } /* end H5D__virtual_init_all() */
2109 
2110 
2111 /*-------------------------------------------------------------------------
2112  * Function:    H5D__virtual_init
2113  *
2114  * Purpose:     Initialize the virtual layout information for a dataset.
2115  *              This is called when the dataset is initialized.
2116  *
2117  * Return:      Non-negative on success/Negative on failure
2118  *
2119  * Programmer:  Neil Fortner
2120  *              Thursday, April 30, 2015
2121  *
2122  *-------------------------------------------------------------------------
2123  */
2124 herr_t
H5D__virtual_init(H5F_t * f,const H5D_t * dset,hid_t dapl_id)2125 H5D__virtual_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id)
2126 {
2127     H5O_storage_virtual_t *storage;     /* Convenience pointer */
2128     H5P_genplist_t *dapl;               /* Data access property list object pointer */
2129     hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset (unused) */
2130     size_t      i;                      /* Local index variables */
2131     herr_t      ret_value = SUCCEED;    /* Return value */
2132 
2133     FUNC_ENTER_PACKAGE
2134 
2135     /* Sanity check */
2136     HDassert(dset);
2137     storage = &dset->shared->layout.storage.u.virt;
2138     HDassert(storage->list || (storage->list_nused == 0));
2139 
2140     /* Check that the dimensions of the VDS are large enough */
2141     if(H5D_virtual_check_min_dims(dset) < 0)
2142         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual dataset dimensions not large enough to contain all limited dimensions in all selections")
2143 
2144     /* Patch the virtual selection dataspaces.  Note we always patch the space
2145      * status because this layout could be from an old version held in the
2146      * object header message code.  We cannot update that held message because
2147      * the layout message is constant, so just overwrite the values here (and
2148      * invalidate other fields by setting storage->init to FALSE below).  Also
2149      * remove offset from selections.  We only have to update
2150      * source_space_status and virtual_space_status because others will be based
2151      * on these and should therefore already have been normalized. */
2152     for(i = 0; i < storage->list_nused; i++) {
2153         HDassert(storage->list[i].sub_dset_nalloc == 0);
2154 
2155         /* Patch extent */
2156         if(H5S_extent_copy(storage->list[i].source_dset.virtual_select, dset->shared->space) < 0)
2157             HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy virtual dataspace extent")
2158         storage->list[i].virtual_space_status = H5O_VIRTUAL_STATUS_CORRECT;
2159 
2160         /* Mark source extent as invalid */
2161         storage->list[i].source_space_status = H5O_VIRTUAL_STATUS_INVALID;
2162 
2163         /* Normalize offsets, toss out old offset values */
2164         if(H5S_hyper_normalize_offset(storage->list[i].source_dset.virtual_select, old_offset) < 0)
2165             HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset")
2166         if(H5S_hyper_normalize_offset(storage->list[i].source_select, old_offset) < 0)
2167             HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset")
2168     } /* end for */
2169 
2170     /* Get dataset access property list */
2171     if(NULL == (dapl = (H5P_genplist_t *)H5I_object(dapl_id)))
2172         HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for dapl ID")
2173 
2174     /* Get view option */
2175     if(H5P_get(dapl, H5D_ACS_VDS_VIEW_NAME, &storage->view) < 0)
2176         HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get virtual view option")
2177 
2178     /* Get printf gap if view is H5D_VDS_LAST_AVAILABLE, otherwise set to 0 */
2179     if(storage->view == H5D_VDS_LAST_AVAILABLE) {
2180         if(H5P_get(dapl, H5D_ACS_VDS_PRINTF_GAP_NAME, &storage->printf_gap) < 0)
2181             HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get virtual printf gap")
2182     } /* end if */
2183     else
2184         storage->printf_gap = (hsize_t)0;
2185 
2186     /* Retrieve VDS file FAPL to layout */
2187     if(storage->source_fapl <= 0)
2188         if((storage->source_fapl = H5F_get_access_plist(f, FALSE)) < 0)
2189             HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get fapl")
2190 
2191     /* Copy DAPL to layout */
2192     if(storage->source_dapl <= 0)
2193         if((storage->source_dapl = H5P_copy_plist(dapl, FALSE)) < 0)
2194             HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dapl")
2195 
2196     /* Mark layout as not fully initialized (must be done prior to I/O for
2197      * unlimited/printf selections) */
2198     storage->init = FALSE;
2199 
2200 done:
2201     FUNC_LEAVE_NOAPI(ret_value)
2202 } /* end H5D__virtual_init() */
2203 
2204 
2205 /*-------------------------------------------------------------------------
2206  * Function:    H5D__virtual_is_space_alloc
2207  *
2208  * Purpose:     Query if space is allocated for layout
2209  *
2210  * Return:      TRUE if space is allocated
2211  *              FALSE if it is not
2212  *              Negative on failure
2213  *
2214  * Programmer:  Neil Fortner
2215  *              February 6, 2015
2216  *
2217  *-------------------------------------------------------------------------
2218  */
2219 hbool_t
H5D__virtual_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED * storage)2220 H5D__virtual_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage)
2221 {
2222     hbool_t ret_value;                  /* Return value */
2223 
2224     FUNC_ENTER_PACKAGE_NOERR
2225 
2226     /* Just return TRUE, since the global heap object containing the mappings is
2227      * created when the layout message is encoded, and nothing else needs to be
2228      * allocated for virtual datasets.  This also ensures that the library never
2229      * assumes (falsely) that no data is present in the dataset, causing errors.
2230      */
2231     ret_value = TRUE;
2232 
2233     FUNC_LEAVE_NOAPI(ret_value)
2234 } /* end H5D__virtual_is_space_alloc() */
2235 
2236 
2237 /*-------------------------------------------------------------------------
2238  * Function:    H5D__virtual_pre_io
2239  *
2240  * Purpose:     Project all virtual mappings onto mem_space, with the
2241  *              results stored in projected_mem_space for each mapping.
2242  *              Opens all source datasets if possible.  The total number
2243  *              of elements is stored in tot_nelmts.
2244  *
2245  * Return:      Non-negative on success/Negative on failure
2246  *
2247  * Programmer:  Neil Fortner
2248  *              June 3, 2015
2249  *
2250  *-------------------------------------------------------------------------
2251  */
2252 static herr_t
H5D__virtual_pre_io(H5D_io_info_t * io_info,H5O_storage_virtual_t * storage,const H5S_t * file_space,const H5S_t * mem_space,hsize_t * tot_nelmts)2253 H5D__virtual_pre_io(H5D_io_info_t *io_info,
2254     H5O_storage_virtual_t *storage, const H5S_t *file_space,
2255     const H5S_t *mem_space, hsize_t *tot_nelmts)
2256 {
2257     hssize_t    select_nelmts;              /* Number of elements in selection */
2258     hsize_t     bounds_start[H5S_MAX_RANK]; /* Selection bounds start */
2259     hsize_t     bounds_end[H5S_MAX_RANK];   /* Selection bounds end */
2260     int         rank;
2261     hbool_t     bounds_init = FALSE;        /* Whether bounds_start, bounds_end, and rank are valid */
2262     size_t      i, j, k;                    /* Local index variables */
2263     herr_t      ret_value = SUCCEED;        /* Return value */
2264 
2265     FUNC_ENTER_STATIC
2266 
2267     /* Sanity check */
2268     HDassert(storage);
2269     HDassert(mem_space);
2270     HDassert(file_space);
2271     HDassert(tot_nelmts);
2272 
2273     /* Initialize layout if necessary */
2274     if(!storage->init)
2275         if(H5D__virtual_init_all(io_info->dset) < 0)
2276             HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize virtual layout")
2277 
2278     /* Initialize tot_nelmts */
2279     *tot_nelmts = 0;
2280 
2281     /* Iterate over mappings */
2282     for(i = 0; i < storage->list_nused; i++) {
2283         /* Sanity check that the virtual space has been patched by now */
2284         HDassert(storage->list[i].virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
2285 
2286         /* Check for "printf" source dataset resolution */
2287         if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2288             hbool_t partial_block;
2289 
2290             HDassert(storage->list[i].unlim_dim_virtual >= 0);
2291 
2292             /* Get selection bounds if necessary */
2293             if(!bounds_init) {
2294                 /* Get rank of VDS */
2295                 if((rank = H5S_GET_EXTENT_NDIMS(io_info->dset->shared->space)) < 0)
2296                     HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
2297 
2298                 /* Get selection bounds */
2299                 if(H5S_SELECT_BOUNDS(file_space, bounds_start, bounds_end) < 0)
2300                     HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
2301 
2302                 /* Adjust bounds_end to represent the extent just enclosing them
2303                  * (add 1) */
2304                 for(j = 0; j < (size_t)rank; j++)
2305                     bounds_end[j]++;
2306 
2307                 /* Bounds are now initialized */
2308                 bounds_init = TRUE;
2309             } /* end if */
2310 
2311             /* Get index of first block in virtual selection */
2312             storage->list[i].sub_dset_io_start = (size_t)H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, bounds_start[storage->list[i].unlim_dim_virtual], NULL);
2313 
2314             /* Get index of first block outside of virtual selection */
2315             storage->list[i].sub_dset_io_end = (size_t)H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, bounds_end[storage->list[i].unlim_dim_virtual], &partial_block);
2316             if(partial_block)
2317                 storage->list[i].sub_dset_io_end++;
2318             if(storage->list[i].sub_dset_io_end > storage->list[i].sub_dset_nused)
2319                 storage->list[i].sub_dset_io_end = storage->list[i].sub_dset_nused;
2320 
2321             /* Iterate over sub-source dsets */
2322             for(j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++) {
2323                 /* Check for clipped virtual selection */
2324                 if(!storage->list[i].sub_dset[j].clipped_virtual_select) {
2325                     hsize_t start[H5S_MAX_RANK];
2326                     /* This should only be NULL if this is a partial block */
2327                     HDassert((j == (storage->list[i].sub_dset_io_end - 1)) && partial_block);
2328 
2329                     /* If the source space status is not correct, we must try to
2330                      * open the source dataset to patch it */
2331                     if(storage->list[i].source_space_status != H5O_VIRTUAL_STATUS_CORRECT) {
2332                         HDassert(!storage->list[i].sub_dset[j].dset);
2333                         if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].sub_dset[j]) < 0)
2334                             HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
2335                     } /* end if */
2336 
2337                     /* If we obtained a valid source space, we must create
2338                      * clipped source and virtual selections, otherwise we
2339                      * cannot do this and we will leave them NULL.  This doesn't
2340                      * hurt anything because we can't do I/O because the dataset
2341                      * must not have been found. */
2342                     if(storage->list[i].source_space_status == H5O_VIRTUAL_STATUS_CORRECT) {
2343                         hsize_t tmp_dims[H5S_MAX_RANK];
2344                         hsize_t vbounds_end[H5S_MAX_RANK];
2345 
2346                         /* Get bounds of virtual selection */
2347                         if(H5S_SELECT_BOUNDS(storage->list[i].sub_dset[j].virtual_select, tmp_dims, vbounds_end) < 0)
2348                             HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
2349 
2350                         HDassert(bounds_init);
2351 
2352                         /* Convert bounds to extent (add 1) */
2353                         for(k = 0; k < (size_t)rank; k++)
2354                             vbounds_end[k]++;
2355 
2356                         /* Temporarily set extent of virtual selection to bounds */
2357                         if(H5S_set_extent(storage->list[i].sub_dset[j].virtual_select, vbounds_end) < 0)
2358                             HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
2359 
2360                         /* Get current VDS dimensions */
2361                         if(H5S_get_simple_extent_dims(io_info->dset->shared->space, tmp_dims, NULL) < 0)
2362                             HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
2363 
2364                         /* Copy virtual selection */
2365                         if(NULL == (storage->list[i].sub_dset[j].clipped_virtual_select = H5S_copy(storage->list[i].sub_dset[j].virtual_select, FALSE, TRUE)))
2366                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
2367 
2368                         /* Clip virtual selection to real virtual extent */
2369                         (void)HDmemset(start, 0, sizeof(start));
2370                         if(H5S_select_hyperslab(storage->list[i].sub_dset[j].clipped_virtual_select, H5S_SELECT_AND, start, NULL, tmp_dims, NULL) < 0)
2371                             HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to clip hyperslab")
2372 
2373                         /* Project intersection of virtual space and clipped
2374                          * virtual space onto source space (create
2375                          * clipped_source_select) */
2376                         if(H5S_select_project_intersection(storage->list[i].sub_dset[j].virtual_select, storage->list[i].source_select, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].clipped_source_select) < 0)
2377                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space")
2378 
2379                         /* Set extents of virtual_select and
2380                          * clipped_virtual_select to virtual extent */
2381                         if(H5S_set_extent(storage->list[i].sub_dset[j].virtual_select, tmp_dims) < 0)
2382                             HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
2383                         if(H5S_set_extent(storage->list[i].sub_dset[j].clipped_virtual_select, tmp_dims) < 0)
2384                             HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
2385                     } /* end if */
2386                 } /* end if */
2387 
2388                 /* Only continue if we managed to obtain a
2389                  * clipped_virtual_select */
2390                 if(storage->list[i].sub_dset[j].clipped_virtual_select) {
2391                     /* Project intersection of file space and mapping virtual space
2392                      * onto memory space */
2393                     if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].projected_mem_space) < 0)
2394                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space")
2395 
2396                     /* Check number of elements selected */
2397                     if((select_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(storage->list[i].sub_dset[j].projected_mem_space)) < 0)
2398                         HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
2399 
2400                     /* Check if anything is selected */
2401                     if(select_nelmts > (hssize_t)0) {
2402                         /* Open source dataset */
2403                         if(!storage->list[i].sub_dset[j].dset)
2404                             /* Try to open dataset */
2405                             if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].sub_dset[j]) < 0)
2406                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
2407 
2408                         /* If the source dataset is not open, mark the selected
2409                          * elements as zero so projected_mem_space is freed */
2410                         if(!storage->list[i].sub_dset[j].dset)
2411                             select_nelmts = (hssize_t)0;
2412                     } /* end if */
2413 
2414                     /* If there are not elements selected in this mapping, free
2415                      * projected_mem_space, otherwise update tot_nelmts */
2416                     if(select_nelmts == (hssize_t)0) {
2417                         if(H5S_close(storage->list[i].sub_dset[j].projected_mem_space) < 0)
2418                             HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected memory space")
2419                         storage->list[i].sub_dset[j].projected_mem_space = NULL;
2420                     } /* end if */
2421                     else
2422                         *tot_nelmts += (hsize_t)select_nelmts;
2423                 } /* end if */
2424             } /* end for */
2425         } /* end if */
2426         else {
2427             if(storage->list[i].source_dset.clipped_virtual_select) {
2428                 /* Project intersection of file space and mapping virtual space onto
2429                  * memory space */
2430                 if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].source_dset.clipped_virtual_select, &storage->list[i].source_dset.projected_mem_space) < 0)
2431                     HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space")
2432 
2433                 /* Check number of elements selected, add to tot_nelmts */
2434                 if((select_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(storage->list[i].source_dset.projected_mem_space)) < 0)
2435                     HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
2436 
2437                 /* Check if anything is selected */
2438                 if(select_nelmts > (hssize_t)0) {
2439                     /* Open source dataset */
2440                     if(!storage->list[i].source_dset.dset)
2441                         /* Try to open dataset */
2442                         if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].source_dset) < 0)
2443                             HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
2444 
2445                     /* If the source dataset is not open, mark the selected elements
2446                      * as zero so projected_mem_space is freed */
2447                     if(!storage->list[i].source_dset.dset)
2448                         select_nelmts = (hssize_t)0;
2449                 } /* end if */
2450 
2451                 /* If there are not elements selected in this mapping, free
2452                  * projected_mem_space, otherwise update tot_nelmts */
2453                 if(select_nelmts == (hssize_t)0) {
2454                     if(H5S_close(storage->list[i].source_dset.projected_mem_space) < 0)
2455                         HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected memory space")
2456                     storage->list[i].source_dset.projected_mem_space = NULL;
2457                 } /* end if */
2458                 else
2459                     *tot_nelmts += (hsize_t)select_nelmts;
2460             } /* end if */
2461             else {
2462                 /* If there is no clipped_dim_virtual, this must be an unlimited
2463                  * selection whose dataset was not found in the last call to
2464                  * H5Dget_space().  Do not attempt to open it as this might
2465                  * affect the extent and we are not going to recalculate it
2466                  * here. */
2467                 HDassert(storage->list[i].unlim_dim_virtual >= 0);
2468                 HDassert(!storage->list[i].source_dset.dset);
2469             } /* end else */
2470         } /* end else */
2471     } /* end for */
2472 
2473 done:
2474     FUNC_LEAVE_NOAPI(ret_value)
2475 } /* end H5D__virtual_pre_io() */
2476 
2477 
2478 /*-------------------------------------------------------------------------
2479  * Function:    H5D__virtual_post_io
2480  *
2481  * Purpose:     Frees memory structures allocated by H5D__virtual_pre_io.
2482  *
2483  * Return:      Non-negative on success/Negative on failure
2484  *
2485  * Programmer:  Neil Fortner
2486  *              June 4, 2015
2487  *
2488  *-------------------------------------------------------------------------
2489  */
2490 static herr_t
H5D__virtual_post_io(H5O_storage_virtual_t * storage)2491 H5D__virtual_post_io(H5O_storage_virtual_t *storage)
2492 {
2493     size_t      i, j;                       /* Local index variables */
2494     herr_t      ret_value = SUCCEED;        /* Return value */
2495 
2496     FUNC_ENTER_STATIC
2497 
2498     /* Sanity check */
2499     HDassert(storage);
2500 
2501     /* Iterate over mappings */
2502     for(i = 0; i < storage->list_nused; i++)
2503         /* Check for "printf" source dataset resolution */
2504         if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2505             /* Iterate over sub-source dsets */
2506             for(j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++)
2507                 /* Close projected memory space */
2508                 if(storage->list[i].sub_dset[j].projected_mem_space) {
2509                     if(H5S_close(storage->list[i].sub_dset[j].projected_mem_space) < 0)
2510                         HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close temporary space")
2511                     storage->list[i].sub_dset[j].projected_mem_space = NULL;
2512                 } /* end if */
2513         } /* end if */
2514         else
2515             /* Close projected memory space */
2516             if(storage->list[i].source_dset.projected_mem_space) {
2517                 if(H5S_close(storage->list[i].source_dset.projected_mem_space) < 0)
2518                     HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close temporary space")
2519                 storage->list[i].source_dset.projected_mem_space = NULL;
2520             } /* end if */
2521 
2522     /* Note the lack of a done: label.  This is because there are no HGOTO_ERROR
2523      * calls.  If one is added, a done: label must also be added */
2524     FUNC_LEAVE_NOAPI(ret_value)
2525 } /* end H5D__virtual_post_io() */
2526 
2527 
2528 /*-------------------------------------------------------------------------
2529  * Function:    H5D__virtual_read_one
2530  *
2531  * Purpose:     Read from a singe source dataset in a virtual dataset.
2532  *
2533  * Return:      Non-negative on success/Negative on failure
2534  *
2535  * Programmer:  Neil Fortner
2536  *              May 15, 2015
2537  *
2538  *-------------------------------------------------------------------------
2539  */
2540 static herr_t
H5D__virtual_read_one(H5D_io_info_t * io_info,const H5D_type_info_t * type_info,const H5S_t * file_space,H5O_storage_virtual_srcdset_t * source_dset)2541 H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
2542     const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset)
2543 {
2544     H5S_t       *projected_src_space = NULL; /* File space for selection in a single source dataset */
2545     herr_t      ret_value = SUCCEED;        /* Return value */
2546 
2547     FUNC_ENTER_STATIC
2548 
2549     HDassert(source_dset);
2550 
2551     /* Only perform I/O if there is a projected memory space, otherwise there
2552      * were no elements in the projection or the source dataset could not be
2553      * opened */
2554     if(source_dset->projected_mem_space) {
2555         HDassert(source_dset->dset);
2556         HDassert(source_dset->clipped_source_select);
2557 
2558         /* Project intersection of file space and mapping virtual space onto
2559          * mapping source space */
2560         if(H5S_select_project_intersection(source_dset->clipped_virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0)
2561             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space")
2562 
2563         /* Perform read on source dataset */
2564         if(H5D__read(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, projected_src_space, io_info->u.rbuf) < 0)
2565             HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset")
2566 
2567         /* Close projected_src_space */
2568         if(H5S_close(projected_src_space) < 0)
2569             HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
2570         projected_src_space = NULL;
2571     } /* end if */
2572 
2573 done:
2574     /* Release allocated resources on failure */
2575     if(projected_src_space) {
2576         HDassert(ret_value < 0);
2577         if(H5S_close(projected_src_space) < 0)
2578             HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
2579     } /* end if */
2580 
2581     FUNC_LEAVE_NOAPI(ret_value)
2582 } /* end H5D__virtual_read_one() */
2583 
2584 
2585 /*-------------------------------------------------------------------------
2586  * Function:    H5D__virtual_read
2587  *
2588  * Purpose:     Read from a virtual dataset.
2589  *
2590  * Return:      Non-negative on success/Negative on failure
2591  *
2592  * Programmer:  Neil Fortner
2593  *              February 6, 2015
2594  *
2595  *-------------------------------------------------------------------------
2596  */
2597 static herr_t
H5D__virtual_read(H5D_io_info_t * io_info,const H5D_type_info_t * type_info,hsize_t nelmts,const H5S_t * file_space,const H5S_t * mem_space,H5D_chunk_map_t H5_ATTR_UNUSED * fm)2598 H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
2599     hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
2600     H5D_chunk_map_t H5_ATTR_UNUSED *fm)
2601 {
2602     H5O_storage_virtual_t *storage;         /* Convenient pointer into layout struct */
2603     hsize_t     tot_nelmts;                 /* Total number of elements mapped to mem_space */
2604     H5S_t       *fill_space = NULL;         /* Space to fill with fill value */
2605     size_t      i, j;                       /* Local index variables */
2606     herr_t      ret_value = SUCCEED;        /* Return value */
2607 
2608     FUNC_ENTER_STATIC
2609 
2610     /* Sanity check */
2611     HDassert(io_info);
2612     HDassert(io_info->u.rbuf);
2613     HDassert(type_info);
2614     HDassert(mem_space);
2615     HDassert(file_space);
2616 
2617     storage = &io_info->dset->shared->layout.storage.u.virt;
2618     HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
2619 
2620 #ifdef H5_HAVE_PARALLEL
2621     /* Parallel reads are not supported (yet) */
2622     if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI))
2623         HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel reads not supported on virtual datasets")
2624 #endif /* H5_HAVE_PARALLEL */
2625 
2626     /* Prepare for I/O operation */
2627     if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0)
2628         HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation")
2629 
2630     /* Iterate over mappings */
2631     for(i = 0; i < storage->list_nused; i++) {
2632         /* Sanity check that the virtual space has been patched by now */
2633         HDassert(storage->list[i].virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
2634 
2635         /* Check for "printf" source dataset resolution */
2636         if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2637             /* Iterate over sub-source dsets */
2638             for(j = storage->list[i].sub_dset_io_start;
2639                     j < storage->list[i].sub_dset_io_end; j++)
2640                 if(H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0)
2641                     HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset")
2642         } /* end if */
2643         else
2644             /* Read from source dataset */
2645             if(H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0)
2646                 HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset")
2647     } /* end for */
2648 
2649     /* Fill unmapped part of buffer with fill value */
2650     if(tot_nelmts < nelmts) {
2651         H5D_fill_value_t fill_status;       /* Fill value status */
2652 
2653         /* Check the fill value status */
2654         if(H5P_is_fill_value_defined(&io_info->dset->shared->dcpl_cache.fill, &fill_status) < 0)
2655             HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if fill value defined")
2656 
2657         /* Always write fill value to memory buffer unless it is undefined */
2658         if(fill_status != H5D_FILL_VALUE_UNDEFINED) {
2659             /* Start with fill space equal to memory space */
2660             if(NULL == (fill_space = H5S_copy(mem_space, FALSE, TRUE)))
2661                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy memory selection")
2662 
2663             /* Iterate over mappings */
2664             for(i = 0; i < storage->list_nused; i++)
2665                 /* Check for "printf" source dataset resolution */
2666                 if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2667                     /* Iterate over sub-source dsets */
2668                     for(j = storage->list[i].sub_dset_io_start;
2669                             j < storage->list[i].sub_dset_io_end; j++)
2670                         if(storage->list[i].sub_dset[j].projected_mem_space)
2671                             if(H5S_select_subtract(fill_space, storage->list[i].sub_dset[j].projected_mem_space) < 0)
2672                                 HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection")
2673                 } /* end if */
2674                 else
2675                     if(storage->list[i].source_dset.projected_mem_space)
2676                         /* Subtract projected memory space from fill space */
2677                         if(H5S_select_subtract(fill_space, storage->list[i].source_dset.projected_mem_space) < 0)
2678                             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection")
2679 
2680             /* Write fill values to memory buffer */
2681             if(H5D__fill(io_info->dset->shared->dcpl_cache.fill.buf, io_info->dset->shared->type, io_info->u.rbuf, type_info->mem_type, fill_space) < 0)
2682                 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "filling buf failed")
2683 
2684 #ifndef NDEBUG
2685             /* Make sure the total number of elements written (including fill
2686              * values) >= nelmts */
2687             {
2688                 hssize_t    select_nelmts;  /* Number of elements in selection */
2689 
2690                 /* Get number of elements in fill dataspace */
2691                 if((select_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(fill_space)) < 0)
2692                     HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
2693 
2694                 /* Verify number of elements is correct.  Note that since we
2695                  * don't check for overlap we can't assert that these are equal
2696                  */
2697                 HDassert((tot_nelmts + (hsize_t)select_nelmts) >= nelmts);
2698             } /* end block */
2699 #endif /* NDEBUG */
2700         } /* end if */
2701     } /* end if */
2702 
2703 done:
2704     /* Cleanup I/O operation */
2705     if(H5D__virtual_post_io(storage) < 0)
2706         HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't cleanup I/O operation")
2707 
2708     /* Close fill space */
2709     if(fill_space)
2710         if(H5S_close(fill_space) < 0)
2711             HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close fill space")
2712 
2713     FUNC_LEAVE_NOAPI(ret_value)
2714 } /* end H5D__virtual_read() */
2715 
2716 
2717 /*-------------------------------------------------------------------------
2718  * Function:    H5D__virtual_write_one
2719  *
2720  * Purpose:     Write to a singe source dataset in a virtual dataset.
2721  *
2722  * Return:      Non-negative on success/Negative on failure
2723  *
2724  * Programmer:  Neil Fortner
2725  *              May 15, 2015
2726  *
2727  *-------------------------------------------------------------------------
2728  */
2729 static herr_t
H5D__virtual_write_one(H5D_io_info_t * io_info,const H5D_type_info_t * type_info,const H5S_t * file_space,H5O_storage_virtual_srcdset_t * source_dset)2730 H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
2731     const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset)
2732 {
2733     H5S_t       *projected_src_space = NULL; /* File space for selection in a single source dataset */
2734     herr_t      ret_value = SUCCEED;        /* Return value */
2735 
2736     FUNC_ENTER_STATIC
2737 
2738     HDassert(source_dset);
2739 
2740     /* Only perform I/O if there is a projected memory space, otherwise there
2741      * were no elements in the projection */
2742     if(source_dset->projected_mem_space) {
2743         HDassert(source_dset->dset);
2744         HDassert(source_dset->clipped_source_select);
2745 
2746         /* In the future we may wish to extent this implementation to extend
2747          * source datasets if a write to a virtual dataset goes past the current
2748          * extent in the unlimited dimension.  -NAF */
2749         /* Project intersection of file space and mapping virtual space onto
2750          * mapping source space */
2751         if(H5S_select_project_intersection(source_dset->virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0)
2752             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space")
2753 
2754         /* Perform write on source dataset */
2755         if(H5D__write(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, projected_src_space, io_info->u.wbuf) < 0)
2756             HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write to source dataset")
2757 
2758         /* Close projected_src_space */
2759         if(H5S_close(projected_src_space) < 0)
2760             HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
2761         projected_src_space = NULL;
2762     } /* end if */
2763 
2764 done:
2765     /* Release allocated resources on failure */
2766     if(projected_src_space) {
2767         HDassert(ret_value < 0);
2768         if(H5S_close(projected_src_space) < 0)
2769             HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
2770     } /* end if */
2771 
2772     FUNC_LEAVE_NOAPI(ret_value)
2773 } /* end H5D__virtual_write_one() */
2774 
2775 
2776 /*-------------------------------------------------------------------------
2777  * Function:    H5D__virtual_write
2778  *
2779  * Purpose:     Write to a virtual dataset.
2780  *
2781  * Return:      Non-negative on success/Negative on failure
2782  *
2783  * Programmer:  Neil Fortner
2784  *              February 6, 2015
2785  *
2786  *-------------------------------------------------------------------------
2787  */
2788 static herr_t
H5D__virtual_write(H5D_io_info_t * io_info,const H5D_type_info_t * type_info,hsize_t nelmts,const H5S_t * file_space,const H5S_t * mem_space,H5D_chunk_map_t H5_ATTR_UNUSED * fm)2789 H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
2790     hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
2791     H5D_chunk_map_t H5_ATTR_UNUSED *fm)
2792 {
2793     H5O_storage_virtual_t *storage;         /* Convenient pointer into layout struct */
2794     hsize_t     tot_nelmts;                 /* Total number of elements mapped to mem_space */
2795     size_t      i, j;                       /* Local index variables */
2796     herr_t      ret_value = SUCCEED;        /* Return value */
2797 
2798     FUNC_ENTER_STATIC
2799 
2800     /* Sanity check */
2801     HDassert(io_info);
2802     HDassert(io_info->u.wbuf);
2803     HDassert(type_info);
2804     HDassert(mem_space);
2805     HDassert(file_space);
2806 
2807     storage = &io_info->dset->shared->layout.storage.u.virt;
2808     HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
2809 
2810 #ifdef H5_HAVE_PARALLEL
2811     /* Parallel writes are not supported (yet) */
2812     if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI))
2813         HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel writes not supported on virtual datasets")
2814 #endif /* H5_HAVE_PARALLEL */
2815 
2816     /* Prepare for I/O operation */
2817     if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0)
2818         HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation")
2819 
2820     /* Fail if there are unmapped parts of the selection as they would not be
2821      * written */
2822     if(tot_nelmts != nelmts)
2823         HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "write requested to unmapped portion of virtual dataset")
2824 
2825     /* Iterate over mappings */
2826     for(i = 0; i < storage->list_nused; i++) {
2827         /* Sanity check that virtual space has been patched by now */
2828         HDassert(storage->list[i].virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
2829 
2830         /* Check for "printf" source dataset resolution */
2831         if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2832             /* Iterate over sub-source dsets */
2833             for(j = storage->list[i].sub_dset_io_start;
2834                     j < storage->list[i].sub_dset_io_end; j++)
2835                 if(H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0)
2836                     HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset")
2837         } /* end if */
2838         else
2839             /* Write to source dataset */
2840             if(H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0)
2841                 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset")
2842     } /* end for */
2843 
2844 done:
2845     /* Cleanup I/O operation */
2846     if(H5D__virtual_post_io(storage) < 0)
2847         HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't cleanup I/O operation")
2848 
2849     FUNC_LEAVE_NOAPI(ret_value)
2850 } /* end H5D__virtual_write() */
2851 
2852 
2853 /*-------------------------------------------------------------------------
2854  * Function:    H5D__virtual_flush
2855  *
2856  * Purpose:     Writes all dirty data to disk.
2857  *
2858  * Return:      Non-negative on success/Negative on failure
2859  *
2860  * Programmer:  Neil Fortner
2861  *              February 6, 2015
2862  *
2863  *-------------------------------------------------------------------------
2864  */
2865 static herr_t
H5D__virtual_flush(H5D_t * dset)2866 H5D__virtual_flush(H5D_t *dset)
2867 {
2868     H5O_storage_virtual_t *storage;         /* Convenient pointer into layout struct */
2869     size_t      i, j;                       /* Local index variables */
2870     herr_t      ret_value = SUCCEED;        /* Return value */
2871 
2872     FUNC_ENTER_STATIC
2873 
2874     /* Sanity check */
2875     HDassert(dset);
2876 
2877     storage = &dset->shared->layout.storage.u.virt;
2878 
2879     /* Flush only open datasets */
2880     for(i = 0; i < storage->list_nused; i++)
2881         /* Check for "printf" source dataset resolution */
2882         if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2883             /* Iterate over sub-source dsets */
2884             for(j = 0; j < storage->list[i].sub_dset_nused; j++)
2885                 if(storage->list[i].sub_dset[j].dset)
2886                     /* Flush source dataset */
2887                     if(H5D__flush_real(storage->list[i].sub_dset[j].dset) < 0)
2888                         HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush source dataset")
2889         } /* end if */
2890         else
2891             if(storage->list[i].source_dset.dset)
2892                 /* Flush source dataset */
2893                 if(H5D__flush_real(storage->list[i].source_dset.dset) < 0)
2894                     HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to flush source dataset")
2895 
2896 done:
2897     FUNC_LEAVE_NOAPI(ret_value)
2898 } /* end H5D__virtual_flush() */
2899 
2900 
2901 /*-------------------------------------------------------------------------
2902  * Function:    H5D__virtual_hold_source_dset_files
2903  *
2904  * Purpose:     Hold open the source files that are open, during a refresh event
2905  *
2906  * Return:      Non-negative on success/Negative on failure
2907  *
2908  * Programmer:  Quincey Koziol
2909  *              November 7, 2015
2910  *
2911  *-------------------------------------------------------------------------
2912  */
2913 herr_t
H5D__virtual_hold_source_dset_files(const H5D_t * dset,H5D_virtual_held_file_t ** head)2914 H5D__virtual_hold_source_dset_files(const H5D_t *dset, H5D_virtual_held_file_t **head)
2915 {
2916     H5O_storage_virtual_t *storage;         /* Convenient pointer into layout struct */
2917     H5D_virtual_held_file_t *tmp;           /* Temporary held file node */
2918     size_t      i;                          /* Local index variable */
2919     herr_t      ret_value = SUCCEED;        /* Return value */
2920 
2921     FUNC_ENTER_PACKAGE
2922 
2923     /* Sanity check */
2924     HDassert(dset);
2925     HDassert(head && NULL == *head);
2926 
2927     /* Set the convenience pointer */
2928     storage = &dset->shared->layout.storage.u.virt;
2929 
2930     /* Hold only files for open datasets */
2931     for(i = 0; i < storage->list_nused; i++)
2932         /* Check for "printf" source dataset resolution */
2933         if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
2934             size_t      j;              /* Local index variable */
2935 
2936             /* Iterate over sub-source dsets */
2937             for(j = 0; j < storage->list[i].sub_dset_nused; j++)
2938                 if(storage->list[i].sub_dset[j].dset) {
2939                     /* Hold open the file */
2940                     H5F_INCR_NOPEN_OBJS(storage->list[i].sub_dset[j].dset->oloc.file);
2941 
2942                     /* Allocate a node for this file */
2943                     if(NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
2944                         HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node")
2945 
2946                     /* Set up node & connect to list */
2947                     tmp->file = storage->list[i].sub_dset[j].dset->oloc.file;
2948                     tmp->next = *head;
2949                     *head = tmp;
2950                 } /* end if */
2951         } /* end if */
2952         else
2953             if(storage->list[i].source_dset.dset) {
2954                 /* Hold open the file */
2955                 H5F_INCR_NOPEN_OBJS(storage->list[i].source_dset.dset->oloc.file);
2956 
2957                 /* Allocate a node for this file */
2958                 if(NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
2959                     HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node")
2960 
2961                 /* Set up node & connect to list */
2962                 tmp->file = storage->list[i].source_dset.dset->oloc.file;
2963                 tmp->next = *head;
2964                 *head = tmp;
2965             } /* end if */
2966 
2967 done:
2968     if(ret_value < 0)
2969         /* Release hold on files and delete list on error */
2970         if(*head && H5D__virtual_release_source_dset_files(*head) < 0)
2971             HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't release source datasets' files held open")
2972 
2973     FUNC_LEAVE_NOAPI(ret_value)
2974 } /* end H5D__virtual_hold_source_dset_files() */
2975 
2976 
2977 /*-------------------------------------------------------------------------
2978  * Function:    H5D__virtual_refresh_source_dset
2979  *
2980  * Purpose:     Refresh a source dataset
2981  *
2982  * Return:      Non-negative on success/Negative on failure
2983  *
2984  * Programmer:  Quincey Koziol
2985  *              November 7, 2015
2986  *
2987  *-------------------------------------------------------------------------
2988  */
2989 static herr_t
H5D__virtual_refresh_source_dset(H5D_t ** dset)2990 H5D__virtual_refresh_source_dset(H5D_t **dset)
2991 {
2992     hid_t       dset_id;                /* Temporary dataset identifier */
2993     herr_t      ret_value = SUCCEED;    /* Return value */
2994 
2995     FUNC_ENTER_STATIC
2996 
2997     /* Sanity check */
2998     HDassert(dset && *dset);
2999 
3000     /* Get a temporary identifier for this source dataset */
3001     if((dset_id = H5I_register(H5I_DATASET, *dset, FALSE)) < 0)
3002         HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "can't register source dataset ID")
3003 
3004     /* Refresh source dataset */
3005     if(H5D__refresh(dset_id, *dset) < 0)
3006         HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
3007 
3008     /* Discard the identifier & replace the dataset */
3009     if(NULL == (*dset = (H5D_t *)H5I_remove(dset_id)))
3010         HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't unregister source dataset ID")
3011 
3012 done:
3013     FUNC_LEAVE_NOAPI(ret_value)
3014 } /* end H5D__virtual_refresh_source_dsets() */
3015 
3016 
3017 /*-------------------------------------------------------------------------
3018  * Function:    H5D__virtual_refresh_source_dsets
3019  *
3020  * Purpose:     Refresh the source datasets
3021  *
3022  * Return:      Non-negative on success/Negative on failure
3023  *
3024  * Programmer:  Dana Robinson
3025  *              November, 2015
3026  *
3027  *-------------------------------------------------------------------------
3028  */
3029 herr_t
H5D__virtual_refresh_source_dsets(H5D_t * dset)3030 H5D__virtual_refresh_source_dsets(H5D_t *dset)
3031 {
3032     H5O_storage_virtual_t *storage;         /* Convenient pointer into layout struct */
3033     size_t      i;                          /* Local index variable */
3034     herr_t      ret_value = SUCCEED;        /* Return value */
3035 
3036     FUNC_ENTER_PACKAGE
3037 
3038     /* Sanity check */
3039     HDassert(dset);
3040 
3041     /* Set convenience pointer */
3042     storage = &dset->shared->layout.storage.u.virt;
3043 
3044     /* Refresh only open datasets */
3045     for(i = 0; i < storage->list_nused; i++)
3046         /* Check for "printf" source dataset resolution */
3047         if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
3048             size_t      j;              /* Local index variable */
3049 
3050             /* Iterate over sub-source datasets */
3051             for(j = 0; j < storage->list[i].sub_dset_nused; j++)
3052                 /* Check if sub-source dataset is open */
3053                 if(storage->list[i].sub_dset[j].dset)
3054                     /* Refresh sub-source dataset */
3055                     if(H5D__virtual_refresh_source_dset(&storage->list[i].sub_dset[j].dset) < 0)
3056                         HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
3057         } /* end if */
3058         else
3059             /* Check if source dataset is open */
3060             if(storage->list[i].source_dset.dset)
3061                 /* Refresh source dataset */
3062                 if(H5D__virtual_refresh_source_dset(&storage->list[i].source_dset.dset) < 0)
3063                     HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
3064 
3065 done:
3066     FUNC_LEAVE_NOAPI(ret_value)
3067 } /* end H5D__virtual_refresh_source_dsets() */
3068 
3069 
3070 /*-------------------------------------------------------------------------
3071  * Function:    H5D__virtual_release_source_dset_files
3072  *
3073  * Purpose:     Release the hold on source files that are open, during a refresh event
3074  *
3075  * Return:      Non-negative on success/Negative on failure
3076  *
3077  * Programmer:  Quincey Koziol
3078  *              November 7, 2015
3079  *
3080  *-------------------------------------------------------------------------
3081  */
3082 herr_t
H5D__virtual_release_source_dset_files(H5D_virtual_held_file_t * head)3083 H5D__virtual_release_source_dset_files(H5D_virtual_held_file_t *head)
3084 {
3085     herr_t      ret_value = SUCCEED;        /* Return value */
3086 
3087     FUNC_ENTER_PACKAGE
3088 
3089     /* Release hold on files and delete list */
3090     while(head) {
3091         H5D_virtual_held_file_t *tmp = head->next;      /* Temporary pointer to next node */
3092 
3093         /* Release hold on file */
3094         H5F_DECR_NOPEN_OBJS(head->file);
3095 
3096         /* Attempt to close the file */
3097         /* (Should always succeed, since the 'top' source file pointer is
3098          *      essentially "private" to the virtual dataset, since it wasn't
3099          *      opened through an API routine -QAK)
3100          */
3101         if(H5F_try_close(head->file, NULL) < 0)
3102             HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close")
3103 
3104         /* Delete node */
3105         (void)H5FL_FREE(H5D_virtual_held_file_t, head);
3106 
3107         /* Advance to next node */
3108         head = tmp;
3109     } /* end while */
3110 
3111 done:
3112     FUNC_LEAVE_NOAPI(ret_value)
3113 } /* end H5D__virtual_release_source_dset_files() */
3114 
3115