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