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