/src/hdf5/src/H5Dcontig.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 | | * Contiguous dataset I/O functions. These routines are similar to |
16 | | * the H5D_chunk_* routines and really only an abstract way of dealing |
17 | | * with the data sieve buffer from H5F_seq_read/write. |
18 | | */ |
19 | | |
20 | | /****************/ |
21 | | /* Module Setup */ |
22 | | /****************/ |
23 | | |
24 | | #include "H5Dmodule.h" /* This source code file is part of the H5D module */ |
25 | | |
26 | | /***********/ |
27 | | /* Headers */ |
28 | | /***********/ |
29 | | #include "H5private.h" /* Generic Functions */ |
30 | | #include "H5CXprivate.h" /* API Contexts */ |
31 | | #include "H5Dpkg.h" /* Dataset functions */ |
32 | | #include "H5Eprivate.h" /* Error handling */ |
33 | | #include "H5Fprivate.h" /* Files */ |
34 | | #include "H5FDprivate.h" /* File drivers */ |
35 | | #include "H5FLprivate.h" /* Free Lists */ |
36 | | #include "H5Iprivate.h" /* IDs */ |
37 | | #include "H5MFprivate.h" /* File memory management */ |
38 | | #include "H5MMprivate.h" /* Memory management */ |
39 | | #include "H5Oprivate.h" /* Object headers */ |
40 | | #include "H5PBprivate.h" /* Page Buffer */ |
41 | | #include "H5VMprivate.h" /* Vector and array functions */ |
42 | | |
43 | | /****************/ |
44 | | /* Local Macros */ |
45 | | /****************/ |
46 | | |
47 | | /******************/ |
48 | | /* Local Typedefs */ |
49 | | /******************/ |
50 | | |
51 | | /* Callback info for sieve buffer readvv operation */ |
52 | | typedef struct H5D_contig_readvv_sieve_ud_t { |
53 | | H5F_shared_t *f_sh; /* Shared file for dataset */ |
54 | | H5D_rdcdc_t *dset_contig; /* Cached information about contiguous data */ |
55 | | const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */ |
56 | | unsigned char *rbuf; /* Pointer to buffer to fill */ |
57 | | } H5D_contig_readvv_sieve_ud_t; |
58 | | |
59 | | /* Callback info for [plain] readvv operation */ |
60 | | typedef struct H5D_contig_readvv_ud_t { |
61 | | H5F_shared_t *f_sh; /* Shared file for dataset */ |
62 | | haddr_t dset_addr; /* Address of dataset */ |
63 | | unsigned char *rbuf; /* Pointer to buffer to fill */ |
64 | | } H5D_contig_readvv_ud_t; |
65 | | |
66 | | /* Callback info for sieve buffer writevv operation */ |
67 | | typedef struct H5D_contig_writevv_sieve_ud_t { |
68 | | H5F_shared_t *f_sh; /* Shared file for dataset */ |
69 | | H5D_rdcdc_t *dset_contig; /* Cached information about contiguous data */ |
70 | | const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */ |
71 | | const unsigned char *wbuf; /* Pointer to buffer to write */ |
72 | | } H5D_contig_writevv_sieve_ud_t; |
73 | | |
74 | | /* Callback info for [plain] writevv operation */ |
75 | | typedef struct H5D_contig_writevv_ud_t { |
76 | | H5F_shared_t *f_sh; /* Shared file for dataset */ |
77 | | haddr_t dset_addr; /* Address of dataset */ |
78 | | const unsigned char *wbuf; /* Pointer to buffer to write */ |
79 | | } H5D_contig_writevv_ud_t; |
80 | | |
81 | | /********************/ |
82 | | /* Local Prototypes */ |
83 | | /********************/ |
84 | | |
85 | | /* Layout operation callbacks */ |
86 | | static herr_t H5D__contig_construct(H5F_t *f, H5D_t *dset); |
87 | | static herr_t H5D__contig_init(H5F_t *f, H5D_t *dset, hid_t dapl_id, bool open_op); |
88 | | static herr_t H5D__contig_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); |
89 | | static herr_t H5D__contig_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); |
90 | | static ssize_t H5D__contig_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dinfo, |
91 | | size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], |
92 | | hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, |
93 | | size_t mem_len_arr[], hsize_t mem_offset_arr[]); |
94 | | static ssize_t H5D__contig_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dinfo, |
95 | | size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], |
96 | | hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, |
97 | | size_t mem_len_arr[], hsize_t mem_offset_arr[]); |
98 | | static herr_t H5D__contig_flush(H5D_t *dset); |
99 | | static herr_t H5D__contig_io_term(H5D_io_info_t *io_info, H5D_dset_io_info_t *di); |
100 | | |
101 | | /* Helper routines */ |
102 | | static herr_t H5D__contig_write_one(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hsize_t offset, |
103 | | size_t size); |
104 | | static herr_t H5D__contig_may_use_select_io(H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, |
105 | | H5D_io_op_type_t op_type); |
106 | | |
107 | | /*********************/ |
108 | | /* Package Variables */ |
109 | | /*********************/ |
110 | | |
111 | | /* Contiguous storage layout I/O ops */ |
112 | | const H5D_layout_ops_t H5D_LOPS_CONTIG[1] = {{ |
113 | | H5D__contig_construct, /* construct */ |
114 | | H5D__contig_init, /* init */ |
115 | | H5D__contig_is_space_alloc, /* is_space_alloc */ |
116 | | H5D__contig_is_data_cached, /* is_data_cached */ |
117 | | H5D__contig_io_init, /* io_init */ |
118 | | H5D__contig_mdio_init, /* mdio_init */ |
119 | | H5D__contig_read, /* ser_read */ |
120 | | H5D__contig_write, /* ser_write */ |
121 | | H5D__contig_readvv, /* readvv */ |
122 | | H5D__contig_writevv, /* writevv */ |
123 | | H5D__contig_flush, /* flush */ |
124 | | H5D__contig_io_term, /* io_term */ |
125 | | NULL /* dest */ |
126 | | }}; |
127 | | |
128 | | /*******************/ |
129 | | /* Local Variables */ |
130 | | /*******************/ |
131 | | |
132 | | /* Declare a PQ free list to manage the sieve buffer information */ |
133 | | H5FL_BLK_DEFINE(sieve_buf); |
134 | | |
135 | | /* Declare extern the free list to manage blocks of type conversion data */ |
136 | | H5FL_BLK_EXTERN(type_conv); |
137 | | |
138 | | /* Declare extern the free list to manage the H5D_piece_info_t struct */ |
139 | | H5FL_EXTERN(H5D_piece_info_t); |
140 | | |
141 | | /*------------------------------------------------------------------------- |
142 | | * Function: H5D__contig_alloc |
143 | | * |
144 | | * Purpose: Allocate file space for a contiguously stored dataset |
145 | | * |
146 | | * Return: Non-negative on success/Negative on failure |
147 | | * |
148 | | *------------------------------------------------------------------------- |
149 | | */ |
150 | | herr_t |
151 | | H5D__contig_alloc(H5F_t *f, H5O_storage_contig_t *storage /*out */) |
152 | 0 | { |
153 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
154 | |
|
155 | 0 | FUNC_ENTER_PACKAGE |
156 | | |
157 | | /* check args */ |
158 | 0 | assert(f); |
159 | 0 | assert(storage); |
160 | | |
161 | | /* Allocate space for the contiguous data */ |
162 | 0 | if (HADDR_UNDEF == (storage->addr = H5MF_alloc(f, H5FD_MEM_DRAW, storage->size))) |
163 | 0 | HGOTO_ERROR(H5E_IO, H5E_NOSPACE, FAIL, "unable to reserve file space"); |
164 | | |
165 | 0 | done: |
166 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
167 | 0 | } /* end H5D__contig_alloc */ |
168 | | |
169 | | /*------------------------------------------------------------------------- |
170 | | * Function: H5D__contig_fill |
171 | | * |
172 | | * Purpose: Write fill values to a contiguously stored dataset. |
173 | | * |
174 | | * Return: Non-negative on success/Negative on failure |
175 | | * |
176 | | *------------------------------------------------------------------------- |
177 | | */ |
178 | | herr_t |
179 | | H5D__contig_fill(H5D_t *dset) |
180 | 0 | { |
181 | 0 | H5D_io_info_t ioinfo; /* Dataset I/O info */ |
182 | 0 | H5D_dset_io_info_t dset_info; /* Dset info */ |
183 | 0 | H5D_storage_t store; /* Union of storage info for dataset */ |
184 | 0 | hssize_t snpoints; /* Number of points in space (for error checking) */ |
185 | 0 | size_t npoints; /* Number of points in space */ |
186 | 0 | hsize_t offset; /* Offset of dataset */ |
187 | 0 | size_t max_temp_buf; /* Maximum size of temporary buffer */ |
188 | | #ifdef H5_HAVE_PARALLEL |
189 | | MPI_Comm mpi_comm = MPI_COMM_NULL; /* MPI communicator for file */ |
190 | | int mpi_rank = (-1); /* This process's rank */ |
191 | | int mpi_code; /* MPI return code */ |
192 | | bool blocks_written = false; /* Flag to indicate that chunk was actually written */ |
193 | | bool using_mpi = |
194 | | false; /* Flag to indicate that the file is being accessed with an MPI-capable file driver */ |
195 | | #endif /* H5_HAVE_PARALLEL */ |
196 | 0 | H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */ |
197 | 0 | bool fb_info_init = false; /* Whether the fill value buffer has been initialized */ |
198 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
199 | |
|
200 | 0 | FUNC_ENTER_PACKAGE |
201 | | |
202 | | /* Check args */ |
203 | 0 | assert(dset && H5D_CONTIGUOUS == dset->shared->layout.type); |
204 | 0 | assert(H5_addr_defined(dset->shared->layout.storage.u.contig.addr)); |
205 | 0 | assert(dset->shared->layout.storage.u.contig.size > 0); |
206 | 0 | assert(dset->shared->space); |
207 | 0 | assert(dset->shared->type); |
208 | |
|
209 | | #ifdef H5_HAVE_PARALLEL |
210 | | /* Retrieve MPI parameters */ |
211 | | if (H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI)) { |
212 | | /* Get the MPI communicator */ |
213 | | if (MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(dset->oloc.file))) |
214 | | HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI communicator"); |
215 | | |
216 | | /* Get the MPI rank */ |
217 | | if ((mpi_rank = H5F_mpi_get_rank(dset->oloc.file)) < 0) |
218 | | HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI rank"); |
219 | | |
220 | | /* Set the MPI-capable file driver flag */ |
221 | | using_mpi = true; |
222 | | } /* end if */ |
223 | | #endif /* H5_HAVE_PARALLEL */ |
224 | | |
225 | | /* Initialize storage info for this dataset */ |
226 | 0 | store.contig.dset_addr = dset->shared->layout.storage.u.contig.addr; |
227 | 0 | store.contig.dset_size = dset->shared->layout.storage.u.contig.size; |
228 | | |
229 | | /* Get the number of elements in the dataset's dataspace */ |
230 | 0 | if ((snpoints = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0) |
231 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "dataset has negative number of elements"); |
232 | 0 | H5_CHECKED_ASSIGN(npoints, size_t, snpoints, hssize_t); |
233 | | |
234 | | /* Get the maximum size of temporary buffers */ |
235 | 0 | if (H5CX_get_max_temp_buf(&max_temp_buf) < 0) |
236 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size"); |
237 | | |
238 | | /* Initialize the fill value buffer */ |
239 | 0 | if (H5D__fill_init(&fb_info, NULL, NULL, NULL, NULL, NULL, &dset->shared->dcpl_cache.fill, |
240 | 0 | dset->shared->type, npoints, max_temp_buf) < 0) |
241 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info"); |
242 | 0 | fb_info_init = true; |
243 | | |
244 | | /* Start at the beginning of the dataset */ |
245 | 0 | offset = 0; |
246 | | |
247 | | /* Simple setup for dataset I/O info struct */ |
248 | 0 | ioinfo.op_type = H5D_IO_OP_WRITE; |
249 | |
|
250 | 0 | dset_info.dset = (H5D_t *)dset; |
251 | 0 | dset_info.store = &store; |
252 | 0 | dset_info.buf.cvp = fb_info.fill_buf; |
253 | 0 | dset_info.mem_space = NULL; |
254 | 0 | ioinfo.dsets_info = &dset_info; |
255 | 0 | ioinfo.f_sh = H5F_SHARED(dset->oloc.file); |
256 | | |
257 | | /* |
258 | | * Fill the entire current extent with the fill value. We can do |
259 | | * this quite efficiently by making sure we copy the fill value |
260 | | * in relatively large pieces. |
261 | | */ |
262 | | |
263 | | /* Loop through writing the fill value to the dataset */ |
264 | 0 | while (npoints > 0) { |
265 | 0 | size_t curr_points; /* Number of elements to write on this iteration of the loop */ |
266 | 0 | size_t size; /* Size of buffer to write */ |
267 | | |
268 | | /* Compute # of elements and buffer size to write for this iteration */ |
269 | 0 | curr_points = MIN(fb_info.elmts_per_buf, npoints); |
270 | 0 | size = curr_points * fb_info.file_elmt_size; |
271 | | |
272 | | /* Check for VL datatype & non-default fill value */ |
273 | 0 | if (fb_info.has_vlen_fill_type) |
274 | | /* Re-fill the buffer to use for this I/O operation */ |
275 | 0 | if (H5D__fill_refill_vl(&fb_info, curr_points) < 0) |
276 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer"); |
277 | | |
278 | | #ifdef H5_HAVE_PARALLEL |
279 | | /* Check if this file is accessed with an MPI-capable file driver */ |
280 | | if (using_mpi) { |
281 | | /* Write the chunks out from only one process */ |
282 | | /* !! Use the internal "independent" DXPL!! -QAK */ |
283 | | if (H5_PAR_META_WRITE == mpi_rank) { |
284 | | if (H5D__contig_write_one(&ioinfo, &dset_info, offset, size) < 0) { |
285 | | /* If writing fails, push an error and stop writing, but |
286 | | * still participate in following MPI_Barrier. |
287 | | */ |
288 | | blocks_written = true; |
289 | | HDONE_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset"); |
290 | | break; |
291 | | } |
292 | | } |
293 | | |
294 | | /* Indicate that blocks are being written */ |
295 | | blocks_written = true; |
296 | | } /* end if */ |
297 | | else { |
298 | | #endif /* H5_HAVE_PARALLEL */ |
299 | 0 | H5_CHECK_OVERFLOW(size, size_t, hsize_t); |
300 | 0 | if (H5D__contig_write_one(&ioinfo, &dset_info, offset, size) < 0) |
301 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset"); |
302 | | #ifdef H5_HAVE_PARALLEL |
303 | | } /* end else */ |
304 | | #endif /* H5_HAVE_PARALLEL */ |
305 | | |
306 | 0 | npoints -= curr_points; |
307 | 0 | offset += size; |
308 | 0 | } /* end while */ |
309 | | |
310 | | #ifdef H5_HAVE_PARALLEL |
311 | | /* Only need to block at the barrier if we actually wrote fill values */ |
312 | | /* And if we are using an MPI-capable file driver */ |
313 | | if (using_mpi && blocks_written) { |
314 | | /* Wait at barrier to avoid race conditions where some processes are |
315 | | * still writing out fill values and other processes race ahead to data |
316 | | * in, getting bogus data. |
317 | | */ |
318 | | if (MPI_SUCCESS != (mpi_code = MPI_Barrier(mpi_comm))) |
319 | | HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code) |
320 | | } /* end if */ |
321 | | #endif /* H5_HAVE_PARALLEL */ |
322 | | |
323 | 0 | done: |
324 | | /* Release the fill buffer info, if it's been initialized */ |
325 | 0 | if (fb_info_init && H5D__fill_term(&fb_info) < 0) |
326 | 0 | HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info"); |
327 | |
|
328 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
329 | 0 | } /* end H5D__contig_fill() */ |
330 | | |
331 | | /*------------------------------------------------------------------------- |
332 | | * Function: H5D__contig_delete |
333 | | * |
334 | | * Purpose: Delete the file space for a contiguously stored dataset |
335 | | * |
336 | | * Return: Non-negative on success/Negative on failure |
337 | | * |
338 | | *------------------------------------------------------------------------- |
339 | | */ |
340 | | herr_t |
341 | | H5D__contig_delete(H5F_t *f, const H5O_storage_t *storage) |
342 | 0 | { |
343 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
344 | |
|
345 | 0 | FUNC_ENTER_PACKAGE |
346 | | |
347 | | /* check args */ |
348 | 0 | assert(f); |
349 | 0 | assert(storage); |
350 | | |
351 | | /* Free the file space for the chunk */ |
352 | 0 | if (H5MF_xfree(f, H5FD_MEM_DRAW, storage->u.contig.addr, storage->u.contig.size) < 0) |
353 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free contiguous storage space"); |
354 | | |
355 | 0 | done: |
356 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
357 | 0 | } /* end H5D__contig_delete */ |
358 | | |
359 | | /*------------------------------------------------------------------------- |
360 | | * Function: H5D__contig_check |
361 | | * |
362 | | * Purpose: Sanity check the contiguous info for a dataset. |
363 | | * |
364 | | * Return: Non-negative on success/Negative on failure |
365 | | * |
366 | | *------------------------------------------------------------------------- |
367 | | */ |
368 | | herr_t |
369 | | H5D__contig_check(const H5F_t *f, const H5O_layout_t *layout, const H5S_extent_t *extent, const H5T_t *dt) |
370 | 18 | { |
371 | 18 | hsize_t nelmts; /* Number of elements in dataspace */ |
372 | 18 | size_t dt_size; /* Size of datatype */ |
373 | 18 | hsize_t data_size; /* Raw data size */ |
374 | 18 | herr_t ret_value = SUCCEED; /* Return value */ |
375 | | |
376 | 18 | FUNC_ENTER_PACKAGE |
377 | | |
378 | | /* Sanity check */ |
379 | 18 | assert(f); |
380 | 18 | assert(layout); |
381 | 18 | assert(extent); |
382 | 18 | assert(dt); |
383 | | |
384 | | /* Retrieve the number of elements in the dataspace */ |
385 | 18 | nelmts = H5S_extent_nelem(extent); |
386 | | |
387 | | /* Get the datatype's size */ |
388 | 18 | if (0 == (dt_size = H5T_GET_SIZE(dt))) |
389 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype"); |
390 | | |
391 | | /* Compute the size of the dataset's contiguous storage */ |
392 | 18 | data_size = nelmts * dt_size; |
393 | | |
394 | | /* Check for overflow during multiplication */ |
395 | 18 | if (nelmts != (data_size / dt_size)) |
396 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "size of dataset's storage overflowed"); |
397 | | |
398 | | /* Check for invalid (corrupted in the file, probably) dimensions */ |
399 | 18 | if (H5_addr_defined(layout->storage.u.contig.addr)) { |
400 | 15 | haddr_t rel_eoa; /* Relative end of file address */ |
401 | | |
402 | 15 | if (HADDR_UNDEF == (rel_eoa = H5F_get_eoa(f, H5FD_MEM_DRAW))) |
403 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size"); |
404 | | |
405 | | /* Check for invalid dataset size (from bad dimensions) putting the |
406 | | * dataset elements off the end of the file |
407 | | */ |
408 | 15 | if (H5_addr_le((layout->storage.u.contig.addr + data_size), layout->storage.u.contig.addr)) |
409 | 1 | HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "invalid dataset size, likely file corruption"); |
410 | 14 | if (H5_addr_gt((layout->storage.u.contig.addr + data_size), rel_eoa)) |
411 | 8 | HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "invalid dataset size, likely file corruption"); |
412 | 14 | } |
413 | | |
414 | 18 | done: |
415 | 18 | FUNC_LEAVE_NOAPI(ret_value) |
416 | 18 | } /* end H5D__contig_check() */ |
417 | | |
418 | | /*------------------------------------------------------------------------- |
419 | | * Function: H5D__contig_construct |
420 | | * |
421 | | * Purpose: Constructs new contiguous layout information for dataset |
422 | | * and upgrades layout version if appropriate |
423 | | * |
424 | | * Return: Non-negative on success/Negative on failure |
425 | | * |
426 | | *------------------------------------------------------------------------- |
427 | | */ |
428 | | static herr_t |
429 | | H5D__contig_construct(H5F_t *f, H5D_t *dset) |
430 | 0 | { |
431 | 0 | hssize_t snelmts; /* Temporary holder for number of elements in dataspace */ |
432 | 0 | hsize_t nelmts; /* Number of elements in dataspace */ |
433 | 0 | size_t dt_size; /* Size of datatype */ |
434 | 0 | hsize_t tmp_size; /* Temporary holder for raw data size */ |
435 | 0 | size_t tmp_sieve_buf_size; /* Temporary holder for sieve buffer size */ |
436 | 0 | unsigned version; /* Message version */ |
437 | 0 | unsigned u; /* Local index variable */ |
438 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
439 | |
|
440 | 0 | FUNC_ENTER_PACKAGE |
441 | | |
442 | | /* Sanity checks */ |
443 | 0 | assert(f); |
444 | 0 | assert(dset); |
445 | 0 | assert(dset->shared); |
446 | | |
447 | | /* |
448 | | * The maximum size of the dataset cannot exceed the storage size. |
449 | | * Also, only the slowest varying dimension of a simple dataspace |
450 | | * can be extendible (currently only for external data storage). |
451 | | */ |
452 | | |
453 | | /* Check for invalid dataset dimensions */ |
454 | 0 | for (u = 0; u < dset->shared->ndims; u++) |
455 | 0 | if (dset->shared->max_dims[u] > dset->shared->curr_dims[u]) |
456 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, |
457 | 0 | "extendible contiguous non-external dataset not allowed"); |
458 | | |
459 | | /* Retrieve the number of elements in the dataspace */ |
460 | 0 | if ((snelmts = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0) |
461 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve number of elements in dataspace"); |
462 | 0 | nelmts = (hsize_t)snelmts; |
463 | | |
464 | | /* Get the datatype's size */ |
465 | 0 | if (0 == (dt_size = H5T_GET_SIZE(dset->shared->type))) |
466 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype"); |
467 | | |
468 | | /* Compute the size of the dataset's contiguous storage */ |
469 | 0 | tmp_size = nelmts * dt_size; |
470 | | |
471 | | /* Check for overflow during multiplication */ |
472 | 0 | if (nelmts != (tmp_size / dt_size)) |
473 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "size of dataset's storage overflowed"); |
474 | | |
475 | | /* Assign the dataset's contiguous storage size */ |
476 | 0 | dset->shared->layout.storage.u.contig.size = tmp_size; |
477 | | |
478 | | /* Get the sieve buffer size for the file */ |
479 | 0 | tmp_sieve_buf_size = H5F_SIEVE_BUF_SIZE(f); |
480 | | |
481 | | /* Adjust the sieve buffer size to the smaller one between the dataset size and the buffer size |
482 | | * from the file access property. (SLU - 2012/3/30) */ |
483 | 0 | if (tmp_size < tmp_sieve_buf_size) |
484 | 0 | dset->shared->cache.contig.sieve_buf_size = tmp_size; |
485 | 0 | else |
486 | 0 | dset->shared->cache.contig.sieve_buf_size = tmp_sieve_buf_size; |
487 | | |
488 | | /* If the layout is below version 3, upgrade to version 3 if allowed. Do not upgrade past version 3 since |
489 | | * there is no benefit. */ |
490 | 0 | if (dset->shared->layout.version < H5O_LAYOUT_VERSION_3) { |
491 | 0 | version = MAX(dset->shared->layout.version, |
492 | 0 | MIN(H5O_layout_ver_bounds[H5F_LOW_BOUND(f)], H5O_LAYOUT_VERSION_3)); |
493 | | |
494 | | /* Version bounds check */ |
495 | 0 | if (version > H5O_layout_ver_bounds[H5F_HIGH_BOUND(f)]) |
496 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "layout version out of bounds"); |
497 | | |
498 | 0 | dset->shared->layout.version = version; |
499 | 0 | } |
500 | | |
501 | 0 | done: |
502 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
503 | 0 | } /* end H5D__contig_construct() */ |
504 | | |
505 | | /*------------------------------------------------------------------------- |
506 | | * Function: H5D__contig_init |
507 | | * |
508 | | * Purpose: Initialize the contiguous info for a dataset. This is |
509 | | * called when the dataset is initialized. |
510 | | * |
511 | | * Return: Non-negative on success/Negative on failure |
512 | | * |
513 | | *------------------------------------------------------------------------- |
514 | | */ |
515 | | static herr_t |
516 | | H5D__contig_init(H5F_t *f, H5D_t *dset, hid_t H5_ATTR_UNUSED dapl_id, bool H5_ATTR_UNUSED open_op) |
517 | 18 | { |
518 | 18 | size_t tmp_sieve_buf_size; /* Temporary holder for sieve buffer size */ |
519 | 18 | herr_t ret_value = SUCCEED; /* Return value */ |
520 | | |
521 | 18 | FUNC_ENTER_PACKAGE |
522 | | |
523 | | /* Sanity check */ |
524 | 18 | assert(f); |
525 | 18 | assert(dset); |
526 | | |
527 | | /* Sanity check the dataset's info */ |
528 | 18 | if (H5D__contig_check(f, &dset->shared->layout, H5S_GET_EXTENT(dset->shared->space), dset->shared->type) < |
529 | 18 | 0) |
530 | 9 | HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "invalid dataset info"); |
531 | | |
532 | | /* Compute the size of the contiguous storage for versions of the |
533 | | * layout message less than version 3 because versions 1 & 2 would |
534 | | * truncate the dimension sizes to 32-bits of information. - QAK 5/26/04 |
535 | | */ |
536 | 9 | if (dset->shared->layout.version < 3) { |
537 | 7 | hssize_t snelmts; /* Temporary holder for number of elements in dataspace */ |
538 | 7 | hsize_t nelmts; /* Number of elements in dataspace */ |
539 | 7 | size_t dt_size; /* Size of datatype */ |
540 | | |
541 | | /* Retrieve the number of elements in the dataspace */ |
542 | 7 | if ((snelmts = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0) |
543 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve number of elements in dataspace"); |
544 | 7 | nelmts = (hsize_t)snelmts; |
545 | | |
546 | | /* Get the datatype's size */ |
547 | 7 | if (0 == (dt_size = H5T_GET_SIZE(dset->shared->type))) |
548 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype"); |
549 | | |
550 | | /* Compute the size of the dataset's contiguous storage */ |
551 | 7 | dset->shared->layout.storage.u.contig.size = nelmts * dt_size; |
552 | 7 | } |
553 | | |
554 | | /* Get the sieve buffer size for the file */ |
555 | 9 | tmp_sieve_buf_size = H5F_SIEVE_BUF_SIZE(dset->oloc.file); |
556 | | |
557 | | /* Adjust the sieve buffer size to the smaller one between the dataset size and the buffer size |
558 | | * from the file access property. (SLU - 2012/3/30) */ |
559 | 9 | if (dset->shared->layout.storage.u.contig.size < tmp_sieve_buf_size) |
560 | 6 | dset->shared->cache.contig.sieve_buf_size = dset->shared->layout.storage.u.contig.size; |
561 | 3 | else |
562 | 3 | dset->shared->cache.contig.sieve_buf_size = tmp_sieve_buf_size; |
563 | | |
564 | 18 | done: |
565 | 18 | FUNC_LEAVE_NOAPI(ret_value) |
566 | 18 | } /* end H5D__contig_init() */ |
567 | | |
568 | | /*------------------------------------------------------------------------- |
569 | | * Function: H5D__contig_is_space_alloc |
570 | | * |
571 | | * Purpose: Query if space is allocated for layout |
572 | | * |
573 | | * Return: Non-negative on success/Negative on failure |
574 | | * |
575 | | *------------------------------------------------------------------------- |
576 | | */ |
577 | | bool |
578 | | H5D__contig_is_space_alloc(const H5O_storage_t *storage) |
579 | 5 | { |
580 | 5 | bool ret_value = false; /* Return value */ |
581 | | |
582 | 5 | FUNC_ENTER_PACKAGE_NOERR |
583 | | |
584 | | /* Sanity checks */ |
585 | 5 | assert(storage); |
586 | | |
587 | | /* Set return value */ |
588 | 5 | ret_value = (bool)H5_addr_defined(storage->u.contig.addr); |
589 | | |
590 | 5 | FUNC_LEAVE_NOAPI(ret_value) |
591 | 5 | } /* end H5D__contig_is_space_alloc() */ |
592 | | |
593 | | /*------------------------------------------------------------------------- |
594 | | * Function: H5D__contig_is_data_cached |
595 | | * |
596 | | * Purpose: Query if raw data is cached for dataset |
597 | | * |
598 | | * Return: Non-negative on success/Negative on failure |
599 | | * |
600 | | *------------------------------------------------------------------------- |
601 | | */ |
602 | | bool |
603 | | H5D__contig_is_data_cached(const H5D_shared_t *shared_dset) |
604 | 0 | { |
605 | 0 | FUNC_ENTER_PACKAGE_NOERR |
606 | | |
607 | | /* Sanity checks */ |
608 | 0 | assert(shared_dset); |
609 | |
|
610 | 0 | FUNC_LEAVE_NOAPI(shared_dset->cache.contig.sieve_size > 0) |
611 | 0 | } /* end H5D__contig_is_data_cached() */ |
612 | | |
613 | | /*------------------------------------------------------------------------- |
614 | | * Function: H5D__contig_io_init |
615 | | * |
616 | | * Purpose: Performs initialization before any sort of I/O on the raw data |
617 | | * |
618 | | * Return: Non-negative on success/Negative on failure |
619 | | * |
620 | | *------------------------------------------------------------------------- |
621 | | */ |
622 | | static herr_t |
623 | | H5D__contig_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) |
624 | 0 | { |
625 | 0 | H5D_t *dataset = dinfo->dset; /* Local pointer to dataset info */ |
626 | |
|
627 | 0 | hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ |
628 | 0 | htri_t file_space_normalized = false; /* File dataspace was normalized */ |
629 | |
|
630 | 0 | int sf_ndims; /* The number of dimensions of the file dataspace (signed) */ |
631 | |
|
632 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
633 | |
|
634 | 0 | FUNC_ENTER_PACKAGE |
635 | |
|
636 | 0 | dinfo->store->contig.dset_addr = dataset->shared->layout.storage.u.contig.addr; |
637 | 0 | dinfo->store->contig.dset_size = dataset->shared->layout.storage.u.contig.size; |
638 | | |
639 | | /* Initialize piece info */ |
640 | 0 | dinfo->layout_io_info.contig_piece_info = NULL; |
641 | | |
642 | | /* Get layout for dataset */ |
643 | 0 | dinfo->layout = &(dataset->shared->layout); |
644 | | |
645 | | /* Get dim number and dimensionality for each dataspace */ |
646 | 0 | if ((sf_ndims = H5S_GET_EXTENT_NDIMS(dinfo->file_space)) < 0) |
647 | 0 | HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number"); |
648 | | |
649 | | /* Normalize hyperslab selections by adjusting them by the offset */ |
650 | | /* (It might be worthwhile to normalize both the file and memory dataspaces |
651 | | * before any (contiguous, chunked, etc) file I/O operation, in order to |
652 | | * speed up hyperslab calculations by removing the extra checks and/or |
653 | | * additions involving the offset and the hyperslab selection -QAK) |
654 | | */ |
655 | 0 | if ((file_space_normalized = H5S_hyper_normalize_offset(dinfo->file_space, old_offset)) < 0) |
656 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset"); |
657 | | |
658 | | /* if selected elements exist */ |
659 | 0 | if (dinfo->nelmts) { |
660 | 0 | int u; |
661 | 0 | H5D_piece_info_t *new_piece_info; /* piece information to insert into skip list */ |
662 | | |
663 | | /* Get copy of dset file_space, so it can be changed temporarily |
664 | | * purpose |
665 | | * This tmp_fspace allows multiple write before close dset */ |
666 | 0 | H5S_t *tmp_fspace; /* Temporary file dataspace */ |
667 | | |
668 | | /* Create "temporary" chunk for selection operations (copy file space) */ |
669 | 0 | if (NULL == (tmp_fspace = H5S_copy(dinfo->file_space, true, false))) |
670 | 0 | HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space"); |
671 | | |
672 | | /* Add temporary chunk to the list of pieces */ |
673 | | /* collect piece_info into Skip List */ |
674 | | /* Allocate the file & memory chunk information */ |
675 | 0 | if (NULL == (new_piece_info = H5FL_MALLOC(H5D_piece_info_t))) { |
676 | 0 | (void)H5S_close(tmp_fspace); |
677 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info"); |
678 | 0 | } /* end if */ |
679 | | |
680 | | /* Set the piece index */ |
681 | 0 | new_piece_info->index = 0; |
682 | | |
683 | | /* Set the file chunk dataspace */ |
684 | 0 | new_piece_info->fspace = tmp_fspace; |
685 | 0 | new_piece_info->fspace_shared = false; |
686 | | |
687 | | /* Set the memory chunk dataspace */ |
688 | | /* same as one chunk, just use dset mem space */ |
689 | 0 | new_piece_info->mspace = dinfo->mem_space; |
690 | | |
691 | | /* set true for sharing mem space with dset, which means |
692 | | * fspace gets free by application H5Sclose(), and |
693 | | * doesn't require providing layout_ops.io_term() for H5D_LOPS_CONTIG. |
694 | | */ |
695 | 0 | new_piece_info->mspace_shared = true; |
696 | | |
697 | | /* Set the number of points */ |
698 | 0 | new_piece_info->piece_points = dinfo->nelmts; |
699 | | |
700 | | /* Copy the piece's coordinates */ |
701 | 0 | for (u = 0; u < sf_ndims; u++) |
702 | 0 | new_piece_info->scaled[u] = 0; |
703 | 0 | new_piece_info->scaled[sf_ndims] = 0; |
704 | | |
705 | | /* make connection to related dset info from this piece_info */ |
706 | 0 | new_piece_info->dset_info = dinfo; |
707 | | |
708 | | /* get dset file address for piece */ |
709 | 0 | new_piece_info->faddr = dinfo->dset->shared->layout.storage.u.contig.addr; |
710 | | |
711 | | /* Initialize in-place type conversion info. Start with it disabled. */ |
712 | 0 | new_piece_info->in_place_tconv = false; |
713 | 0 | new_piece_info->buf_off = 0; |
714 | |
|
715 | 0 | new_piece_info->filtered_dset = dinfo->dset->shared->dcpl_cache.pline.nused > 0; |
716 | | |
717 | | /* Calculate type conversion buffer size and check for in-place conversion if necessary. Currently |
718 | | * only implemented for selection I/O. */ |
719 | 0 | if (io_info->use_select_io != H5D_SELECTION_IO_MODE_OFF && |
720 | 0 | !(dinfo->type_info.is_xform_noop && dinfo->type_info.is_conv_noop)) |
721 | 0 | H5D_INIT_PIECE_TCONV(io_info, dinfo, new_piece_info) |
722 | | |
723 | | /* Save piece to dataset info struct so it is freed at the end of the |
724 | | * operation */ |
725 | 0 | dinfo->layout_io_info.contig_piece_info = new_piece_info; |
726 | | |
727 | | /* Add piece to piece_count */ |
728 | 0 | io_info->piece_count++; |
729 | 0 | } /* end if */ |
730 | | |
731 | | /* Check if we're performing selection I/O if it hasn't been disabled |
732 | | * already */ |
733 | 0 | if (io_info->use_select_io != H5D_SELECTION_IO_MODE_OFF) |
734 | 0 | if (H5D__contig_may_use_select_io(io_info, dinfo, io_info->op_type) < 0) |
735 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible"); |
736 | | |
737 | 0 | done: |
738 | 0 | if (ret_value < 0) { |
739 | 0 | if (H5D__contig_io_term(io_info, dinfo) < 0) |
740 | 0 | HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataset I/O info"); |
741 | 0 | } /* end if */ |
742 | |
|
743 | 0 | if (file_space_normalized) { |
744 | | /* (Casting away const OK -QAK) */ |
745 | 0 | if (H5S_hyper_denormalize_offset(dinfo->file_space, old_offset) < 0) |
746 | 0 | HDONE_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset"); |
747 | 0 | } /* end if */ |
748 | |
|
749 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
750 | 0 | } /* end H5D__contig_io_init() */ |
751 | | |
752 | | /*------------------------------------------------------------------------- |
753 | | * Function: H5D__contig_mdio_init |
754 | | * |
755 | | * Purpose: Performs second phase of initialization for multi-dataset |
756 | | * I/O. Currently just adds data block to sel_pieces. |
757 | | * |
758 | | * Return: Non-negative on success/Negative on failure |
759 | | * |
760 | | *------------------------------------------------------------------------- |
761 | | */ |
762 | | static herr_t |
763 | | H5D__contig_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) |
764 | 0 | { |
765 | 0 | FUNC_ENTER_PACKAGE_NOERR |
766 | | |
767 | | /* Add piece if it exists */ |
768 | 0 | if (dinfo->layout_io_info.contig_piece_info) { |
769 | 0 | assert(io_info->sel_pieces); |
770 | 0 | assert(io_info->pieces_added < io_info->piece_count); |
771 | | |
772 | | /* Add contiguous data block to sel_pieces */ |
773 | 0 | io_info->sel_pieces[io_info->pieces_added] = dinfo->layout_io_info.contig_piece_info; |
774 | | |
775 | | /* Update pieces_added */ |
776 | 0 | io_info->pieces_added++; |
777 | 0 | } |
778 | |
|
779 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
780 | 0 | } /* end H5D__contig_mdio_init() */ |
781 | | |
782 | | /*------------------------------------------------------------------------- |
783 | | * Function: H5D__contig_may_use_select_io |
784 | | * |
785 | | * Purpose: A small internal function to if it may be possible to use |
786 | | * selection I/O. |
787 | | * |
788 | | * Return: true/false/FAIL |
789 | | * |
790 | | *------------------------------------------------------------------------- |
791 | | */ |
792 | | static herr_t |
793 | | H5D__contig_may_use_select_io(H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, |
794 | | H5D_io_op_type_t op_type) |
795 | 0 | { |
796 | 0 | const H5D_t *dataset = NULL; /* Local pointer to dataset info */ |
797 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
798 | |
|
799 | 0 | FUNC_ENTER_PACKAGE |
800 | | |
801 | | /* Sanity check */ |
802 | 0 | assert(io_info); |
803 | 0 | assert(dset_info); |
804 | 0 | assert(dset_info->dset); |
805 | 0 | assert(op_type == H5D_IO_OP_READ || op_type == H5D_IO_OP_WRITE); |
806 | |
|
807 | 0 | dataset = dset_info->dset; |
808 | | |
809 | | /* None of the reasons this function might disable selection I/O are relevant to parallel, so no need to |
810 | | * update no_selection_io_cause since we're only keeping track of the reason for no selection I/O in |
811 | | * parallel (for now) */ |
812 | | |
813 | | /* Don't use selection I/O if it's globally disabled, if it's not a contiguous dataset, or if the sieve |
814 | | * buffer exists (write) or is dirty (read) */ |
815 | 0 | if (dset_info->layout_ops.readvv != H5D__contig_readvv) { |
816 | 0 | io_info->use_select_io = H5D_SELECTION_IO_MODE_OFF; |
817 | 0 | io_info->no_selection_io_cause |= H5D_SEL_IO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; |
818 | 0 | } |
819 | 0 | else if ((op_type == H5D_IO_OP_READ && dataset->shared->cache.contig.sieve_dirty) || |
820 | 0 | (op_type == H5D_IO_OP_WRITE && dataset->shared->cache.contig.sieve_buf)) { |
821 | 0 | io_info->use_select_io = H5D_SELECTION_IO_MODE_OFF; |
822 | 0 | io_info->no_selection_io_cause |= H5D_SEL_IO_CONTIGUOUS_SIEVE_BUFFER; |
823 | 0 | } |
824 | 0 | else { |
825 | 0 | bool page_buf_enabled; |
826 | |
|
827 | 0 | assert(dset_info->layout_ops.writevv == H5D__contig_writevv); |
828 | | |
829 | | /* Check if the page buffer is enabled */ |
830 | 0 | if (H5PB_enabled(io_info->f_sh, H5FD_MEM_DRAW, &page_buf_enabled) < 0) |
831 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if page buffer is enabled"); |
832 | 0 | if (page_buf_enabled) { |
833 | 0 | io_info->use_select_io = H5D_SELECTION_IO_MODE_OFF; |
834 | 0 | io_info->no_selection_io_cause |= H5D_SEL_IO_PAGE_BUFFER; |
835 | 0 | } |
836 | 0 | } /* end else */ |
837 | | |
838 | 0 | done: |
839 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
840 | 0 | } /* end H5D__contig_may_use_select_io() */ |
841 | | |
842 | | /*------------------------------------------------------------------------- |
843 | | * Function: H5D__contig_read |
844 | | * |
845 | | * Purpose: Read from a contiguous dataset. |
846 | | * |
847 | | * Return: Non-negative on success/Negative on failure |
848 | | * |
849 | | *------------------------------------------------------------------------- |
850 | | */ |
851 | | herr_t |
852 | | H5D__contig_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) |
853 | 0 | { |
854 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
855 | |
|
856 | 0 | FUNC_ENTER_PACKAGE |
857 | | |
858 | | /* Sanity check */ |
859 | 0 | assert(io_info); |
860 | 0 | assert(dinfo); |
861 | 0 | assert(dinfo->buf.vp); |
862 | 0 | assert(dinfo->mem_space); |
863 | 0 | assert(dinfo->file_space); |
864 | |
|
865 | 0 | if (io_info->use_select_io == H5D_SELECTION_IO_MODE_ON) { |
866 | | /* Only perform I/O if not performing multi dataset I/O or type conversion, |
867 | | * otherwise the higher level will handle it after all datasets |
868 | | * have been processed */ |
869 | 0 | if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { |
870 | 0 | size_t dst_type_size = dinfo->type_info.dst_type_size; |
871 | | |
872 | | /* Issue selection I/O call (we can skip the page buffer because we've |
873 | | * already verified it won't be used, and the metadata accumulator |
874 | | * because this is raw data) */ |
875 | 0 | if (H5F_shared_select_read(H5F_SHARED(dinfo->dset->oloc.file), H5FD_MEM_DRAW, |
876 | 0 | dinfo->nelmts > 0 ? 1 : 0, &dinfo->mem_space, &dinfo->file_space, |
877 | 0 | &(dinfo->store->contig.dset_addr), &dst_type_size, |
878 | 0 | &(dinfo->buf.vp)) < 0) |
879 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous selection read failed"); |
880 | 0 | } |
881 | 0 | else { |
882 | 0 | if (dinfo->layout_io_info.contig_piece_info) { |
883 | | /* Add to mdset selection I/O arrays */ |
884 | 0 | assert(io_info->mem_spaces); |
885 | 0 | assert(io_info->file_spaces); |
886 | 0 | assert(io_info->addrs); |
887 | 0 | assert(io_info->element_sizes); |
888 | 0 | assert(io_info->rbufs); |
889 | 0 | assert(io_info->pieces_added < io_info->piece_count); |
890 | |
|
891 | 0 | io_info->mem_spaces[io_info->pieces_added] = dinfo->mem_space; |
892 | 0 | io_info->file_spaces[io_info->pieces_added] = dinfo->file_space; |
893 | 0 | io_info->addrs[io_info->pieces_added] = dinfo->store->contig.dset_addr; |
894 | 0 | io_info->element_sizes[io_info->pieces_added] = dinfo->type_info.src_type_size; |
895 | 0 | io_info->rbufs[io_info->pieces_added] = dinfo->buf.vp; |
896 | 0 | if (io_info->sel_pieces) |
897 | 0 | io_info->sel_pieces[io_info->pieces_added] = dinfo->layout_io_info.contig_piece_info; |
898 | 0 | io_info->pieces_added++; |
899 | 0 | } |
900 | 0 | } |
901 | |
|
902 | | #ifdef H5_HAVE_PARALLEL |
903 | | /* Report that collective contiguous I/O was used */ |
904 | | io_info->actual_io_mode |= H5D_MPIO_CONTIGUOUS_COLLECTIVE; |
905 | | #endif /* H5_HAVE_PARALLEL */ |
906 | 0 | } /* end if */ |
907 | 0 | else |
908 | | /* Read data through legacy (non-selection I/O) pathway */ |
909 | 0 | if ((dinfo->io_ops.single_read)(io_info, dinfo) < 0) |
910 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous read failed"); |
911 | | |
912 | 0 | done: |
913 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
914 | 0 | } /* end H5D__contig_read() */ |
915 | | |
916 | | /*------------------------------------------------------------------------- |
917 | | * Function: H5D__contig_write |
918 | | * |
919 | | * Purpose: Write to a contiguous dataset. |
920 | | * |
921 | | * Return: Non-negative on success/Negative on failure |
922 | | * |
923 | | *------------------------------------------------------------------------- |
924 | | */ |
925 | | herr_t |
926 | | H5D__contig_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) |
927 | 0 | { |
928 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
929 | |
|
930 | 0 | FUNC_ENTER_PACKAGE |
931 | | |
932 | | /* Sanity check */ |
933 | 0 | assert(io_info); |
934 | 0 | assert(dinfo); |
935 | 0 | assert(dinfo->buf.cvp); |
936 | 0 | assert(dinfo->mem_space); |
937 | 0 | assert(dinfo->file_space); |
938 | |
|
939 | 0 | if (io_info->use_select_io == H5D_SELECTION_IO_MODE_ON) { |
940 | | /* Only perform I/O if not performing multi dataset I/O or type conversion, |
941 | | * otherwise the higher level will handle it after all datasets |
942 | | * have been processed */ |
943 | 0 | if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { |
944 | 0 | size_t dst_type_size = dinfo->type_info.dst_type_size; |
945 | | |
946 | | /* Issue selection I/O call (we can skip the page buffer because we've |
947 | | * already verified it won't be used, and the metadata accumulator |
948 | | * because this is raw data) */ |
949 | 0 | if (H5F_shared_select_write(H5F_SHARED(dinfo->dset->oloc.file), H5FD_MEM_DRAW, |
950 | 0 | dinfo->nelmts > 0 ? 1 : 0, &dinfo->mem_space, &dinfo->file_space, |
951 | 0 | &(dinfo->store->contig.dset_addr), &dst_type_size, |
952 | 0 | &(dinfo->buf.cvp)) < 0) |
953 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous selection write failed"); |
954 | 0 | } |
955 | 0 | else { |
956 | 0 | if (dinfo->layout_io_info.contig_piece_info) { |
957 | | /* Add to mdset selection I/O arrays */ |
958 | 0 | assert(io_info->mem_spaces); |
959 | 0 | assert(io_info->file_spaces); |
960 | 0 | assert(io_info->addrs); |
961 | 0 | assert(io_info->element_sizes); |
962 | 0 | assert(io_info->wbufs); |
963 | 0 | assert(io_info->pieces_added < io_info->piece_count); |
964 | |
|
965 | 0 | io_info->mem_spaces[io_info->pieces_added] = dinfo->mem_space; |
966 | 0 | io_info->file_spaces[io_info->pieces_added] = dinfo->file_space; |
967 | 0 | io_info->addrs[io_info->pieces_added] = dinfo->store->contig.dset_addr; |
968 | 0 | io_info->element_sizes[io_info->pieces_added] = dinfo->type_info.dst_type_size; |
969 | 0 | io_info->wbufs[io_info->pieces_added] = dinfo->buf.cvp; |
970 | 0 | if (io_info->sel_pieces) |
971 | 0 | io_info->sel_pieces[io_info->pieces_added] = dinfo->layout_io_info.contig_piece_info; |
972 | 0 | io_info->pieces_added++; |
973 | 0 | } |
974 | 0 | } |
975 | |
|
976 | | #ifdef H5_HAVE_PARALLEL |
977 | | /* Report that collective contiguous I/O was used */ |
978 | | io_info->actual_io_mode |= H5D_MPIO_CONTIGUOUS_COLLECTIVE; |
979 | | #endif /* H5_HAVE_PARALLEL */ |
980 | 0 | } /* end if */ |
981 | 0 | else |
982 | | /* Write data through legacy (non-selection I/O) pathway */ |
983 | 0 | if ((dinfo->io_ops.single_write)(io_info, dinfo) < 0) |
984 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous write failed"); |
985 | | |
986 | 0 | done: |
987 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
988 | 0 | } /* end H5D__contig_write() */ |
989 | | |
990 | | /*------------------------------------------------------------------------- |
991 | | * Function: H5D__contig_write_one |
992 | | * |
993 | | * Purpose: Writes some data from a dataset into a buffer. |
994 | | * The data is contiguous. The address is relative to the base |
995 | | * address for the file. |
996 | | * |
997 | | * Return: Non-negative on success/Negative on failure |
998 | | * |
999 | | *------------------------------------------------------------------------- |
1000 | | */ |
1001 | | static herr_t |
1002 | | H5D__contig_write_one(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hsize_t offset, size_t size) |
1003 | 0 | { |
1004 | 0 | hsize_t dset_off = offset; /* Offset in dataset */ |
1005 | 0 | size_t dset_len = size; /* Length in dataset */ |
1006 | 0 | size_t dset_curr_seq = 0; /* "Current sequence" in dataset */ |
1007 | 0 | hsize_t mem_off = 0; /* Offset in memory */ |
1008 | 0 | size_t mem_len = size; /* Length in memory */ |
1009 | 0 | size_t mem_curr_seq = 0; /* "Current sequence" in memory */ |
1010 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1011 | |
|
1012 | 0 | FUNC_ENTER_PACKAGE |
1013 | |
|
1014 | 0 | assert(io_info); |
1015 | |
|
1016 | 0 | if (H5D__contig_writevv(io_info, dset_info, (size_t)1, &dset_curr_seq, &dset_len, &dset_off, (size_t)1, |
1017 | 0 | &mem_curr_seq, &mem_len, &mem_off) < 0) |
1018 | 0 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vector write failed"); |
1019 | | |
1020 | 0 | done: |
1021 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1022 | 0 | } /* end H5D__contig_write_one() */ |
1023 | | |
1024 | | /*------------------------------------------------------------------------- |
1025 | | * Function: H5D__contig_readvv_sieve_cb |
1026 | | * |
1027 | | * Purpose: Callback operator for H5D__contig_readvv() with sieve buffer. |
1028 | | * |
1029 | | * Return: Non-negative on success/Negative on failure |
1030 | | * |
1031 | | *------------------------------------------------------------------------- |
1032 | | */ |
1033 | | static herr_t |
1034 | | H5D__contig_readvv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) |
1035 | 0 | { |
1036 | 0 | H5D_contig_readvv_sieve_ud_t *udata = |
1037 | 0 | (H5D_contig_readvv_sieve_ud_t *)_udata; /* User data for H5VM_opvv() operator */ |
1038 | 0 | H5F_shared_t *f_sh = udata->f_sh; /* Shared file for dataset */ |
1039 | 0 | H5D_rdcdc_t *dset_contig = udata->dset_contig; /* Cached information about contiguous data */ |
1040 | 0 | const H5D_contig_storage_t *store_contig = |
1041 | 0 | udata->store_contig; /* Contiguous storage info for this I/O operation */ |
1042 | 0 | unsigned char *buf; /* Pointer to buffer to fill */ |
1043 | 0 | haddr_t addr; /* Actual address to read */ |
1044 | 0 | haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */ |
1045 | 0 | haddr_t contig_end; /* End locations of block to write */ |
1046 | 0 | size_t sieve_size = (size_t)-1; /* Size of sieve buffer */ |
1047 | 0 | haddr_t rel_eoa; /* Relative end of file address */ |
1048 | 0 | hsize_t max_data; /* Actual maximum size of data to cache */ |
1049 | 0 | hsize_t min; /* temporary minimum value (avoids some ugly macro nesting) */ |
1050 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1051 | |
|
1052 | 0 | FUNC_ENTER_PACKAGE |
1053 | | |
1054 | | /* Stash local copies of these value */ |
1055 | 0 | if (dset_contig->sieve_buf != NULL) { |
1056 | 0 | sieve_start = dset_contig->sieve_loc; |
1057 | 0 | sieve_size = dset_contig->sieve_size; |
1058 | 0 | sieve_end = sieve_start + sieve_size; |
1059 | 0 | } /* end if */ |
1060 | | |
1061 | | /* Compute offset on disk */ |
1062 | 0 | addr = store_contig->dset_addr + dst_off; |
1063 | | |
1064 | | /* Compute offset in memory */ |
1065 | 0 | buf = udata->rbuf + src_off; |
1066 | | |
1067 | | /* Check if the sieve buffer is allocated yet */ |
1068 | 0 | if (NULL == dset_contig->sieve_buf) { |
1069 | | /* Check if we can actually hold the I/O request in the sieve buffer */ |
1070 | 0 | if (len > dset_contig->sieve_buf_size) { |
1071 | 0 | if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0) |
1072 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed"); |
1073 | 0 | } /* end if */ |
1074 | 0 | else { |
1075 | | /* Allocate room for the data sieve buffer */ |
1076 | 0 | if (NULL == (dset_contig->sieve_buf = H5FL_BLK_CALLOC(sieve_buf, dset_contig->sieve_buf_size))) |
1077 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
1078 | | |
1079 | | /* Determine the new sieve buffer size & location */ |
1080 | 0 | dset_contig->sieve_loc = addr; |
1081 | | |
1082 | | /* Make certain we don't read off the end of the file */ |
1083 | 0 | if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW))) |
1084 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size"); |
1085 | | |
1086 | | /* Set up the buffer parameters */ |
1087 | 0 | max_data = store_contig->dset_size - dst_off; |
1088 | | |
1089 | | /* Compute the size of the sieve buffer */ |
1090 | 0 | min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size); |
1091 | 0 | H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t); |
1092 | | |
1093 | | /* Read the new sieve buffer */ |
1094 | 0 | if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, |
1095 | 0 | dset_contig->sieve_buf) < 0) |
1096 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed"); |
1097 | | |
1098 | | /* Grab the data out of the buffer (must be first piece of data in buffer ) */ |
1099 | 0 | H5MM_memcpy(buf, dset_contig->sieve_buf, len); |
1100 | | |
1101 | | /* Reset sieve buffer dirty flag */ |
1102 | 0 | dset_contig->sieve_dirty = false; |
1103 | 0 | } /* end else */ |
1104 | 0 | } /* end if */ |
1105 | 0 | else { |
1106 | | /* Compute end of sequence to retrieve */ |
1107 | 0 | contig_end = addr + len - 1; |
1108 | | |
1109 | | /* If entire read is within the sieve buffer, read it from the buffer */ |
1110 | 0 | if (addr >= sieve_start && contig_end < sieve_end) { |
1111 | 0 | unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start); |
1112 | | |
1113 | | /* Grab the data out of the buffer */ |
1114 | 0 | H5MM_memcpy(buf, base_sieve_buf, len); |
1115 | 0 | } /* end if */ |
1116 | | /* Entire request is not within this data sieve buffer */ |
1117 | 0 | else { |
1118 | | /* Check if we can actually hold the I/O request in the sieve buffer */ |
1119 | 0 | if (len > dset_contig->sieve_buf_size) { |
1120 | | /* Check for any overlap with the current sieve buffer */ |
1121 | 0 | if ((sieve_start >= addr && sieve_start < (contig_end + 1)) || |
1122 | 0 | ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) { |
1123 | | /* Flush the sieve buffer, if it's dirty */ |
1124 | 0 | if (dset_contig->sieve_dirty) { |
1125 | | /* Write to file */ |
1126 | 0 | if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size, |
1127 | 0 | dset_contig->sieve_buf) < 0) |
1128 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1129 | | |
1130 | | /* Reset sieve buffer dirty flag */ |
1131 | 0 | dset_contig->sieve_dirty = false; |
1132 | 0 | } /* end if */ |
1133 | 0 | } /* end if */ |
1134 | | |
1135 | | /* Read directly into the user's buffer */ |
1136 | 0 | if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0) |
1137 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed"); |
1138 | 0 | } /* end if */ |
1139 | | /* Element size fits within the buffer size */ |
1140 | 0 | else { |
1141 | | /* Flush the sieve buffer if it's dirty */ |
1142 | 0 | if (dset_contig->sieve_dirty) { |
1143 | | /* Write to file */ |
1144 | 0 | if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size, |
1145 | 0 | dset_contig->sieve_buf) < 0) |
1146 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1147 | | |
1148 | | /* Reset sieve buffer dirty flag */ |
1149 | 0 | dset_contig->sieve_dirty = false; |
1150 | 0 | } /* end if */ |
1151 | | |
1152 | | /* Determine the new sieve buffer size & location */ |
1153 | 0 | dset_contig->sieve_loc = addr; |
1154 | | |
1155 | | /* Make certain we don't read off the end of the file */ |
1156 | 0 | if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW))) |
1157 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size"); |
1158 | | |
1159 | | /* Only need this when resizing sieve buffer */ |
1160 | 0 | max_data = store_contig->dset_size - dst_off; |
1161 | | |
1162 | | /* Compute the size of the sieve buffer. |
1163 | | * Don't read off the end of the file, don't read past |
1164 | | * the end of the data element, and don't read more than |
1165 | | * the buffer size. |
1166 | | */ |
1167 | 0 | min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size); |
1168 | 0 | H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t); |
1169 | | |
1170 | | /* Read the new sieve buffer */ |
1171 | 0 | if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc, |
1172 | 0 | dset_contig->sieve_size, dset_contig->sieve_buf) < 0) |
1173 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed"); |
1174 | | |
1175 | | /* Grab the data out of the buffer (must be first piece of data in buffer ) */ |
1176 | 0 | H5MM_memcpy(buf, dset_contig->sieve_buf, len); |
1177 | | |
1178 | | /* Reset sieve buffer dirty flag */ |
1179 | 0 | dset_contig->sieve_dirty = false; |
1180 | 0 | } /* end else */ |
1181 | 0 | } /* end else */ |
1182 | 0 | } /* end else */ |
1183 | | |
1184 | 0 | done: |
1185 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1186 | 0 | } /* end H5D__contig_readvv_sieve_cb() */ |
1187 | | |
1188 | | /*------------------------------------------------------------------------- |
1189 | | * Function: H5D__contig_readvv_cb |
1190 | | * |
1191 | | * Purpose: Callback operator for H5D__contig_readvv() without sieve buffer. |
1192 | | * |
1193 | | * Return: Non-negative on success/Negative on failure |
1194 | | * |
1195 | | *------------------------------------------------------------------------- |
1196 | | */ |
1197 | | static herr_t |
1198 | | H5D__contig_readvv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) |
1199 | 0 | { |
1200 | 0 | H5D_contig_readvv_ud_t *udata = (H5D_contig_readvv_ud_t *)_udata; /* User data for H5VM_opvv() operator */ |
1201 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1202 | |
|
1203 | 0 | FUNC_ENTER_PACKAGE |
1204 | | |
1205 | | /* Write data */ |
1206 | 0 | if (H5F_shared_block_read(udata->f_sh, H5FD_MEM_DRAW, (udata->dset_addr + dst_off), len, |
1207 | 0 | (udata->rbuf + src_off)) < 0) |
1208 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1209 | | |
1210 | 0 | done: |
1211 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1212 | 0 | } /* end H5D__contig_readvv_cb() */ |
1213 | | |
1214 | | /*------------------------------------------------------------------------- |
1215 | | * Function: H5D__contig_readvv |
1216 | | * |
1217 | | * Purpose: Reads some data vectors from a dataset into a buffer. |
1218 | | * The data is contiguous. The address is the start of the dataset, |
1219 | | * relative to the base address for the file and the offsets and |
1220 | | * sequence lengths are in bytes. |
1221 | | * |
1222 | | * Return: Non-negative on success/Negative on failure |
1223 | | * |
1224 | | * Notes: |
1225 | | * Offsets in the sequences must be monotonically increasing |
1226 | | * |
1227 | | *------------------------------------------------------------------------- |
1228 | | */ |
1229 | | static ssize_t |
1230 | | H5D__contig_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq, |
1231 | | size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, |
1232 | | size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) |
1233 | 0 | { |
1234 | 0 | ssize_t ret_value = -1; /* Return value */ |
1235 | |
|
1236 | 0 | FUNC_ENTER_PACKAGE |
1237 | | |
1238 | | /* Check args */ |
1239 | 0 | assert(io_info); |
1240 | 0 | assert(dset_info); |
1241 | 0 | assert(dset_curr_seq); |
1242 | 0 | assert(dset_len_arr); |
1243 | 0 | assert(dset_off_arr); |
1244 | 0 | assert(mem_curr_seq); |
1245 | 0 | assert(mem_len_arr); |
1246 | 0 | assert(mem_off_arr); |
1247 | | |
1248 | | /* Check if data sieving is enabled */ |
1249 | 0 | if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_DATA_SIEVE)) { |
1250 | 0 | H5D_contig_readvv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */ |
1251 | | |
1252 | | /* Set up user data for H5VM_opvv() */ |
1253 | 0 | udata.f_sh = io_info->f_sh; |
1254 | 0 | udata.dset_contig = &(dset_info->dset->shared->cache.contig); |
1255 | 0 | udata.store_contig = &(dset_info->store->contig); |
1256 | 0 | udata.rbuf = (unsigned char *)dset_info->buf.vp; |
1257 | | |
1258 | | /* Call generic sequence operation routine */ |
1259 | 0 | if ((ret_value = |
1260 | 0 | H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, |
1261 | 0 | mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_readvv_sieve_cb, &udata)) < 0) |
1262 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer read"); |
1263 | 0 | } /* end if */ |
1264 | 0 | else { |
1265 | 0 | H5D_contig_readvv_ud_t udata; /* User data for H5VM_opvv() operator */ |
1266 | | |
1267 | | /* Set up user data for H5VM_opvv() */ |
1268 | 0 | udata.f_sh = io_info->f_sh; |
1269 | 0 | udata.dset_addr = dset_info->store->contig.dset_addr; |
1270 | 0 | udata.rbuf = (unsigned char *)dset_info->buf.vp; |
1271 | | |
1272 | | /* Call generic sequence operation routine */ |
1273 | 0 | if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, |
1274 | 0 | mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_readvv_cb, &udata)) < |
1275 | 0 | 0) |
1276 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read"); |
1277 | 0 | } /* end else */ |
1278 | | |
1279 | 0 | done: |
1280 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1281 | 0 | } /* end H5D__contig_readvv() */ |
1282 | | |
1283 | | /*------------------------------------------------------------------------- |
1284 | | * Function: H5D__contig_writevv_sieve_cb |
1285 | | * |
1286 | | * Purpose: Callback operator for H5D__contig_writevv() with sieve buffer. |
1287 | | * |
1288 | | * Return: Non-negative on success/Negative on failure |
1289 | | * |
1290 | | *------------------------------------------------------------------------- |
1291 | | */ |
1292 | | static herr_t |
1293 | | H5D__contig_writevv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) |
1294 | 0 | { |
1295 | 0 | H5D_contig_writevv_sieve_ud_t *udata = |
1296 | 0 | (H5D_contig_writevv_sieve_ud_t *)_udata; /* User data for H5VM_opvv() operator */ |
1297 | 0 | H5F_shared_t *f_sh = udata->f_sh; /* Shared file for dataset */ |
1298 | 0 | H5D_rdcdc_t *dset_contig = udata->dset_contig; /* Cached information about contiguous data */ |
1299 | 0 | const H5D_contig_storage_t *store_contig = |
1300 | 0 | udata->store_contig; /* Contiguous storage info for this I/O operation */ |
1301 | 0 | const unsigned char *buf; /* Pointer to buffer to fill */ |
1302 | 0 | haddr_t addr; /* Actual address to read */ |
1303 | 0 | haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */ |
1304 | 0 | haddr_t contig_end; /* End locations of block to write */ |
1305 | 0 | size_t sieve_size = (size_t)-1; /* size of sieve buffer */ |
1306 | 0 | haddr_t rel_eoa; /* Relative end of file address */ |
1307 | 0 | hsize_t max_data; /* Actual maximum size of data to cache */ |
1308 | 0 | hsize_t min; /* temporary minimum value (avoids some ugly macro nesting) */ |
1309 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1310 | |
|
1311 | 0 | FUNC_ENTER_PACKAGE |
1312 | | |
1313 | | /* Stash local copies of these values */ |
1314 | 0 | if (dset_contig->sieve_buf != NULL) { |
1315 | 0 | sieve_start = dset_contig->sieve_loc; |
1316 | 0 | sieve_size = dset_contig->sieve_size; |
1317 | 0 | sieve_end = sieve_start + sieve_size; |
1318 | 0 | } /* end if */ |
1319 | | |
1320 | | /* Compute offset on disk */ |
1321 | 0 | addr = store_contig->dset_addr + dst_off; |
1322 | | |
1323 | | /* Compute offset in memory */ |
1324 | 0 | buf = udata->wbuf + src_off; |
1325 | | |
1326 | | /* No data sieve buffer yet, go allocate one */ |
1327 | 0 | if (NULL == dset_contig->sieve_buf) { |
1328 | | /* Check if we can actually hold the I/O request in the sieve buffer */ |
1329 | 0 | if (len > dset_contig->sieve_buf_size) { |
1330 | 0 | if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0) |
1331 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1332 | 0 | } /* end if */ |
1333 | 0 | else { |
1334 | | /* Allocate room for the data sieve buffer */ |
1335 | 0 | if (NULL == (dset_contig->sieve_buf = H5FL_BLK_CALLOC(sieve_buf, dset_contig->sieve_buf_size))) |
1336 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
1337 | | |
1338 | | /* Clear memory */ |
1339 | 0 | if (dset_contig->sieve_size > len) |
1340 | 0 | memset(dset_contig->sieve_buf + len, 0, (dset_contig->sieve_size - len)); |
1341 | | |
1342 | | /* Determine the new sieve buffer size & location */ |
1343 | 0 | dset_contig->sieve_loc = addr; |
1344 | | |
1345 | | /* Make certain we don't read off the end of the file */ |
1346 | 0 | if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW))) |
1347 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size"); |
1348 | | |
1349 | | /* Set up the buffer parameters */ |
1350 | 0 | max_data = store_contig->dset_size - dst_off; |
1351 | | |
1352 | | /* Compute the size of the sieve buffer */ |
1353 | 0 | min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size); |
1354 | 0 | H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t); |
1355 | | |
1356 | | /* Check if there is any point in reading the data from the file */ |
1357 | 0 | if (dset_contig->sieve_size > len) { |
1358 | | /* Read the new sieve buffer */ |
1359 | 0 | if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc, |
1360 | 0 | dset_contig->sieve_size, dset_contig->sieve_buf) < 0) |
1361 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed"); |
1362 | 0 | } /* end if */ |
1363 | | |
1364 | | /* Grab the data out of the buffer (must be first piece of data in buffer ) */ |
1365 | 0 | H5MM_memcpy(dset_contig->sieve_buf, buf, len); |
1366 | | |
1367 | | /* Set sieve buffer dirty flag */ |
1368 | 0 | dset_contig->sieve_dirty = true; |
1369 | | |
1370 | | /* Stash local copies of these values */ |
1371 | 0 | sieve_start = dset_contig->sieve_loc; |
1372 | 0 | sieve_size = dset_contig->sieve_size; |
1373 | 0 | sieve_end = sieve_start + sieve_size; |
1374 | 0 | } /* end else */ |
1375 | 0 | } /* end if */ |
1376 | 0 | else { |
1377 | | /* Compute end of sequence to retrieve */ |
1378 | 0 | contig_end = addr + len - 1; |
1379 | | |
1380 | | /* If entire write is within the sieve buffer, write it to the buffer */ |
1381 | 0 | if (addr >= sieve_start && contig_end < sieve_end) { |
1382 | 0 | unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start); |
1383 | | |
1384 | | /* Put the data into the sieve buffer */ |
1385 | 0 | H5MM_memcpy(base_sieve_buf, buf, len); |
1386 | | |
1387 | | /* Set sieve buffer dirty flag */ |
1388 | 0 | dset_contig->sieve_dirty = true; |
1389 | 0 | } /* end if */ |
1390 | | /* Entire request is not within this data sieve buffer */ |
1391 | 0 | else { |
1392 | | /* Check if we can actually hold the I/O request in the sieve buffer */ |
1393 | 0 | if (len > dset_contig->sieve_buf_size) { |
1394 | | /* Check for any overlap with the current sieve buffer */ |
1395 | 0 | if ((sieve_start >= addr && sieve_start < (contig_end + 1)) || |
1396 | 0 | ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) { |
1397 | | /* Flush the sieve buffer, if it's dirty */ |
1398 | 0 | if (dset_contig->sieve_dirty) { |
1399 | | /* Write to file */ |
1400 | 0 | if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size, |
1401 | 0 | dset_contig->sieve_buf) < 0) |
1402 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1403 | | |
1404 | | /* Reset sieve buffer dirty flag */ |
1405 | 0 | dset_contig->sieve_dirty = false; |
1406 | 0 | } /* end if */ |
1407 | | |
1408 | | /* Force the sieve buffer to be re-read the next time */ |
1409 | 0 | dset_contig->sieve_loc = HADDR_UNDEF; |
1410 | 0 | dset_contig->sieve_size = 0; |
1411 | 0 | } /* end if */ |
1412 | | |
1413 | | /* Write directly from the user's buffer */ |
1414 | 0 | if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0) |
1415 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1416 | 0 | } /* end if */ |
1417 | | /* Element size fits within the buffer size */ |
1418 | 0 | else { |
1419 | | /* Check if it is possible to (exactly) prepend or append to existing (dirty) sieve buffer */ |
1420 | 0 | if (((addr + len) == sieve_start || addr == sieve_end) && |
1421 | 0 | (len + sieve_size) <= dset_contig->sieve_buf_size && dset_contig->sieve_dirty) { |
1422 | | /* Prepend to existing sieve buffer */ |
1423 | 0 | if ((addr + len) == sieve_start) { |
1424 | | /* Move existing sieve information to correct location */ |
1425 | 0 | memmove(dset_contig->sieve_buf + len, dset_contig->sieve_buf, |
1426 | 0 | dset_contig->sieve_size); |
1427 | | |
1428 | | /* Copy in new information (must be first in sieve buffer) */ |
1429 | 0 | H5MM_memcpy(dset_contig->sieve_buf, buf, len); |
1430 | | |
1431 | | /* Adjust sieve location */ |
1432 | 0 | dset_contig->sieve_loc = addr; |
1433 | |
|
1434 | 0 | } /* end if */ |
1435 | | /* Append to existing sieve buffer */ |
1436 | 0 | else { |
1437 | | /* Copy in new information */ |
1438 | 0 | H5MM_memcpy(dset_contig->sieve_buf + sieve_size, buf, len); |
1439 | 0 | } /* end else */ |
1440 | | |
1441 | | /* Adjust sieve size */ |
1442 | 0 | dset_contig->sieve_size += len; |
1443 | 0 | } /* end if */ |
1444 | | /* Can't add the new data onto the existing sieve buffer */ |
1445 | 0 | else { |
1446 | | /* Flush the sieve buffer if it's dirty */ |
1447 | 0 | if (dset_contig->sieve_dirty) { |
1448 | | /* Write to file */ |
1449 | 0 | if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size, |
1450 | 0 | dset_contig->sieve_buf) < 0) |
1451 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1452 | | |
1453 | | /* Reset sieve buffer dirty flag */ |
1454 | 0 | dset_contig->sieve_dirty = false; |
1455 | 0 | } /* end if */ |
1456 | | |
1457 | | /* Determine the new sieve buffer size & location */ |
1458 | 0 | dset_contig->sieve_loc = addr; |
1459 | | |
1460 | | /* Make certain we don't read off the end of the file */ |
1461 | 0 | if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW))) |
1462 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size"); |
1463 | | |
1464 | | /* Only need this when resizing sieve buffer */ |
1465 | 0 | max_data = store_contig->dset_size - dst_off; |
1466 | | |
1467 | | /* Compute the size of the sieve buffer. |
1468 | | * Don't read off the end of the file, don't read past |
1469 | | * the end of the data element, and don't read more than |
1470 | | * the buffer size. |
1471 | | */ |
1472 | 0 | min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size); |
1473 | 0 | H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t); |
1474 | | |
1475 | | /* Check if there is any point in reading the data from the file */ |
1476 | 0 | if (dset_contig->sieve_size > len) { |
1477 | | /* Read the new sieve buffer */ |
1478 | 0 | if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc, |
1479 | 0 | dset_contig->sieve_size, dset_contig->sieve_buf) < 0) |
1480 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed"); |
1481 | 0 | } /* end if */ |
1482 | | |
1483 | | /* Grab the data out of the buffer (must be first piece of data in buffer ) */ |
1484 | 0 | H5MM_memcpy(dset_contig->sieve_buf, buf, len); |
1485 | | |
1486 | | /* Set sieve buffer dirty flag */ |
1487 | 0 | dset_contig->sieve_dirty = true; |
1488 | 0 | } /* end else */ |
1489 | 0 | } /* end else */ |
1490 | 0 | } /* end else */ |
1491 | 0 | } /* end else */ |
1492 | | |
1493 | 0 | done: |
1494 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1495 | 0 | } /* end H5D__contig_writevv_sieve_cb() */ |
1496 | | |
1497 | | /*------------------------------------------------------------------------- |
1498 | | * Function: H5D__contig_writevv_cb |
1499 | | * |
1500 | | * Purpose: Callback operator for H5D__contig_writevv(). |
1501 | | * |
1502 | | * Return: Non-negative on success/Negative on failure |
1503 | | * |
1504 | | *------------------------------------------------------------------------- |
1505 | | */ |
1506 | | static herr_t |
1507 | | H5D__contig_writevv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) |
1508 | 0 | { |
1509 | 0 | H5D_contig_writevv_ud_t *udata = |
1510 | 0 | (H5D_contig_writevv_ud_t *)_udata; /* User data for H5VM_opvv() operator */ |
1511 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1512 | |
|
1513 | 0 | FUNC_ENTER_PACKAGE |
1514 | | |
1515 | | /* Write data */ |
1516 | 0 | if (H5F_shared_block_write(udata->f_sh, H5FD_MEM_DRAW, (udata->dset_addr + dst_off), len, |
1517 | 0 | (udata->wbuf + src_off)) < 0) |
1518 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed"); |
1519 | | |
1520 | 0 | done: |
1521 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1522 | 0 | } /* end H5D__contig_writevv_cb() */ |
1523 | | |
1524 | | /*------------------------------------------------------------------------- |
1525 | | * Function: H5D__contig_writevv |
1526 | | * |
1527 | | * Purpose: Writes some data vectors into a dataset from vectors into a |
1528 | | * buffer. The address is the start of the dataset, |
1529 | | * relative to the base address for the file and the offsets and |
1530 | | * sequence lengths are in bytes. |
1531 | | * |
1532 | | * Return: Non-negative on success/Negative on failure |
1533 | | * |
1534 | | * Notes: |
1535 | | * Offsets in the sequences must be monotonically increasing |
1536 | | * |
1537 | | *------------------------------------------------------------------------- |
1538 | | */ |
1539 | | static ssize_t |
1540 | | H5D__contig_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq, |
1541 | | size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, |
1542 | | size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) |
1543 | 0 | { |
1544 | 0 | ssize_t ret_value = -1; /* Return value (Size of sequence in bytes) */ |
1545 | |
|
1546 | 0 | FUNC_ENTER_PACKAGE |
1547 | | |
1548 | | /* Check args */ |
1549 | 0 | assert(io_info); |
1550 | 0 | assert(dset_info); |
1551 | 0 | assert(dset_curr_seq); |
1552 | 0 | assert(dset_len_arr); |
1553 | 0 | assert(dset_off_arr); |
1554 | 0 | assert(mem_curr_seq); |
1555 | 0 | assert(mem_len_arr); |
1556 | 0 | assert(mem_off_arr); |
1557 | | |
1558 | | /* Check if data sieving is enabled */ |
1559 | 0 | if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_DATA_SIEVE)) { |
1560 | 0 | H5D_contig_writevv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */ |
1561 | | |
1562 | | /* Set up user data for H5VM_opvv() */ |
1563 | 0 | udata.f_sh = io_info->f_sh; |
1564 | 0 | udata.dset_contig = &(dset_info->dset->shared->cache.contig); |
1565 | 0 | udata.store_contig = &(dset_info->store->contig); |
1566 | 0 | udata.wbuf = (const unsigned char *)dset_info->buf.cvp; |
1567 | | |
1568 | | /* Call generic sequence operation routine */ |
1569 | 0 | if ((ret_value = |
1570 | 0 | H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, |
1571 | 0 | mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_writevv_sieve_cb, &udata)) < 0) |
1572 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer write"); |
1573 | 0 | } /* end if */ |
1574 | 0 | else { |
1575 | 0 | H5D_contig_writevv_ud_t udata; /* User data for H5VM_opvv() operator */ |
1576 | | |
1577 | | /* Set up user data for H5VM_opvv() */ |
1578 | 0 | udata.f_sh = io_info->f_sh; |
1579 | 0 | udata.dset_addr = dset_info->store->contig.dset_addr; |
1580 | 0 | udata.wbuf = (const unsigned char *)dset_info->buf.cvp; |
1581 | | |
1582 | | /* Call generic sequence operation routine */ |
1583 | 0 | if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, |
1584 | 0 | mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_writevv_cb, &udata)) < |
1585 | 0 | 0) |
1586 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read"); |
1587 | 0 | } /* end else */ |
1588 | | |
1589 | 0 | done: |
1590 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1591 | 0 | } /* end H5D__contig_writevv() */ |
1592 | | |
1593 | | /*------------------------------------------------------------------------- |
1594 | | * Function: H5D__contig_flush |
1595 | | * |
1596 | | * Purpose: Writes all dirty data to disk. |
1597 | | * |
1598 | | * Return: Non-negative on success/Negative on failure |
1599 | | * |
1600 | | *------------------------------------------------------------------------- |
1601 | | */ |
1602 | | static herr_t |
1603 | | H5D__contig_flush(H5D_t *dset) |
1604 | 5 | { |
1605 | 5 | herr_t ret_value = SUCCEED; /* Return value */ |
1606 | | |
1607 | 5 | FUNC_ENTER_PACKAGE |
1608 | | |
1609 | | /* Sanity check */ |
1610 | 5 | assert(dset); |
1611 | | |
1612 | | /* Flush any data in sieve buffer */ |
1613 | 5 | if (H5D__flush_sieve_buf(dset) < 0) |
1614 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush sieve buffer"); |
1615 | | |
1616 | 5 | done: |
1617 | 5 | FUNC_LEAVE_NOAPI(ret_value) |
1618 | 5 | } /* end H5D__contig_flush() */ |
1619 | | |
1620 | | /*------------------------------------------------------------------------- |
1621 | | * Function: H5D__contig_io_term |
1622 | | * |
1623 | | * Purpose: Destroy I/O operation information. |
1624 | | * |
1625 | | * Return: Non-negative on success/Negative on failure |
1626 | | * |
1627 | | *------------------------------------------------------------------------- |
1628 | | */ |
1629 | | static herr_t |
1630 | | H5D__contig_io_term(H5D_io_info_t H5_ATTR_UNUSED *io_info, H5D_dset_io_info_t *di) |
1631 | 0 | { |
1632 | 0 | herr_t ret_value = SUCCEED; /*return value */ |
1633 | |
|
1634 | 0 | FUNC_ENTER_PACKAGE |
1635 | |
|
1636 | 0 | assert(di); |
1637 | | |
1638 | | /* Free piece info */ |
1639 | 0 | if (di->layout_io_info.contig_piece_info) { |
1640 | 0 | if (H5D__free_piece_info(di->layout_io_info.contig_piece_info, NULL, NULL) < 0) |
1641 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free piece info"); |
1642 | 0 | di->layout_io_info.contig_piece_info = NULL; |
1643 | 0 | } |
1644 | | |
1645 | 0 | done: |
1646 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1647 | 0 | } /* end H5D__contig_io_term() */ |
1648 | | |
1649 | | /*------------------------------------------------------------------------- |
1650 | | * Function: H5D__contig_copy |
1651 | | * |
1652 | | * Purpose: Copy contiguous storage raw data from SRC file to DST file. |
1653 | | * |
1654 | | * Return: Non-negative on success, negative on failure. |
1655 | | * |
1656 | | *------------------------------------------------------------------------- |
1657 | | */ |
1658 | | herr_t |
1659 | | H5D__contig_copy(H5F_t *f_src, const H5O_storage_contig_t *storage_src, H5F_t *f_dst, |
1660 | | H5O_storage_contig_t *storage_dst, H5T_t *dt_src, H5O_copy_t *cpy_info) |
1661 | 0 | { |
1662 | 0 | haddr_t addr_src; /* File offset in source dataset */ |
1663 | 0 | haddr_t addr_dst; /* File offset in destination dataset */ |
1664 | 0 | H5T_path_t *tpath_src_mem = NULL, *tpath_mem_dst = NULL; /* Datatype conversion paths */ |
1665 | 0 | H5T_t *dt_dst = NULL; /* Destination datatype */ |
1666 | 0 | H5T_t *dt_mem = NULL; /* Memory datatype */ |
1667 | 0 | size_t src_dt_size = 0; /* Source datatype size */ |
1668 | 0 | size_t mem_dt_size = 0; /* Memory datatype size */ |
1669 | 0 | size_t dst_dt_size = 0; /* Destination datatype size */ |
1670 | 0 | size_t max_dt_size; /* Max. datatype size */ |
1671 | 0 | size_t nelmts = 0; /* Number of elements in buffer */ |
1672 | 0 | size_t src_nbytes; /* Number of bytes to read from source */ |
1673 | 0 | size_t mem_nbytes; /* Number of bytes to convert in memory */ |
1674 | 0 | size_t dst_nbytes; /* Number of bytes to write to destination */ |
1675 | 0 | hsize_t total_src_nbytes; /* Total number of bytes to copy */ |
1676 | 0 | size_t buf_size; /* Size of copy buffer */ |
1677 | 0 | void *buf = NULL; /* Buffer for copying data */ |
1678 | 0 | void *bkg = NULL; /* Temporary buffer for copying data */ |
1679 | 0 | void *reclaim_buf = NULL; /* Buffer for reclaiming data */ |
1680 | 0 | H5S_t *buf_space = NULL; /* Dataspace describing buffer */ |
1681 | 0 | hsize_t buf_dim[1] = {0}; /* Dimension for buffer */ |
1682 | 0 | bool is_vlen = false; /* Flag to indicate that VL type conversion should occur */ |
1683 | 0 | bool fix_ref = false; /* Flag to indicate that ref values should be fixed */ |
1684 | 0 | H5D_shared_t *shared_fo = |
1685 | 0 | (H5D_shared_t *)cpy_info->shared_fo; /* Pointer to the shared struct for dataset object */ |
1686 | 0 | bool try_sieve = false; /* Try to get data from the sieve buffer */ |
1687 | 0 | haddr_t sieve_start = HADDR_UNDEF; /* Start location of sieve buffer */ |
1688 | 0 | haddr_t sieve_end = HADDR_UNDEF; /* End locations of sieve buffer */ |
1689 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1690 | |
|
1691 | 0 | FUNC_ENTER_PACKAGE |
1692 | | |
1693 | | /* Check args */ |
1694 | 0 | assert(f_src); |
1695 | 0 | assert(storage_src); |
1696 | 0 | assert(f_dst); |
1697 | 0 | assert(storage_dst); |
1698 | 0 | assert(dt_src); |
1699 | | |
1700 | | /* Allocate space for destination raw data */ |
1701 | 0 | if (H5D__contig_alloc(f_dst, storage_dst) < 0) |
1702 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to allocate contiguous storage"); |
1703 | | |
1704 | | /* Set up number of bytes to copy, and initial buffer size */ |
1705 | | /* (actually use the destination size, which has been fixed up, if necessary) */ |
1706 | 0 | total_src_nbytes = storage_dst->size; |
1707 | 0 | H5_CHECK_OVERFLOW(total_src_nbytes, hsize_t, size_t); |
1708 | 0 | buf_size = MIN(H5D_TEMP_BUF_SIZE, (size_t)total_src_nbytes); |
1709 | | |
1710 | | /* If there's a VLEN source datatype, set up type conversion information */ |
1711 | 0 | if (H5T_detect_class(dt_src, H5T_VLEN, false) > 0) { |
1712 | | /* create a memory copy of the variable-length datatype */ |
1713 | 0 | if (NULL == (dt_mem = H5T_copy(dt_src, H5T_COPY_TRANSIENT))) |
1714 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy"); |
1715 | | |
1716 | | /* create variable-length datatype at the destination file */ |
1717 | 0 | if (NULL == (dt_dst = H5T_copy(dt_src, H5T_COPY_TRANSIENT))) |
1718 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to copy"); |
1719 | 0 | if (H5T_set_loc(dt_dst, H5F_VOL_OBJ(f_dst), H5T_LOC_DISK) < 0) { |
1720 | 0 | (void)H5T_close_real(dt_dst); |
1721 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "cannot mark datatype on disk"); |
1722 | 0 | } /* end if */ |
1723 | | |
1724 | | /* Set up the conversion functions */ |
1725 | 0 | if (NULL == (tpath_src_mem = H5T_path_find(dt_src, dt_mem))) |
1726 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between src and mem datatypes"); |
1727 | 0 | if (NULL == (tpath_mem_dst = H5T_path_find(dt_mem, dt_dst))) |
1728 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between mem and dst datatypes"); |
1729 | | |
1730 | | /* Determine largest datatype size */ |
1731 | 0 | if (0 == (src_dt_size = H5T_get_size(dt_src))) |
1732 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size"); |
1733 | 0 | if (0 == (mem_dt_size = H5T_get_size(dt_mem))) |
1734 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size"); |
1735 | 0 | max_dt_size = MAX(src_dt_size, mem_dt_size); |
1736 | 0 | if (0 == (dst_dt_size = H5T_get_size(dt_dst))) |
1737 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size"); |
1738 | 0 | max_dt_size = MAX(max_dt_size, dst_dt_size); |
1739 | | |
1740 | | /* Set maximum number of whole elements that fit in buffer */ |
1741 | 0 | if (0 == (nelmts = buf_size / max_dt_size)) |
1742 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "element size too large"); |
1743 | | |
1744 | | /* Set the number of bytes to transfer */ |
1745 | 0 | src_nbytes = nelmts * src_dt_size; |
1746 | 0 | dst_nbytes = nelmts * dst_dt_size; |
1747 | 0 | mem_nbytes = nelmts * mem_dt_size; |
1748 | | |
1749 | | /* Adjust buffer size to be multiple of elements */ |
1750 | 0 | buf_size = nelmts * max_dt_size; |
1751 | | |
1752 | | /* Create dataspace for number of elements in buffer */ |
1753 | 0 | buf_dim[0] = nelmts; |
1754 | | |
1755 | | /* Create the space and set the initial extent */ |
1756 | 0 | if (NULL == (buf_space = H5S_create_simple((unsigned)1, buf_dim, NULL))) |
1757 | 0 | HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace"); |
1758 | | |
1759 | | /* Set flag to do type conversion */ |
1760 | 0 | is_vlen = true; |
1761 | 0 | } /* end if */ |
1762 | 0 | else { |
1763 | | /* Check for reference datatype */ |
1764 | 0 | if (H5T_get_class(dt_src, false) == H5T_REFERENCE) { |
1765 | | /* Need to fix values of references when copying across files */ |
1766 | 0 | if (f_src != f_dst) |
1767 | 0 | fix_ref = true; |
1768 | 0 | } /* end if */ |
1769 | | |
1770 | | /* Set the number of bytes to read & write to the buffer size */ |
1771 | 0 | src_nbytes = dst_nbytes = mem_nbytes = buf_size; |
1772 | 0 | } /* end else */ |
1773 | | |
1774 | | /* Allocate space for copy buffer */ |
1775 | 0 | assert(buf_size); |
1776 | 0 | if (NULL == (buf = H5FL_BLK_MALLOC(type_conv, buf_size))) |
1777 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer"); |
1778 | | |
1779 | | /* Need extra buffer for datatype conversions, to prevent stranding/leaking memory */ |
1780 | 0 | if (is_vlen || fix_ref) { |
1781 | 0 | if (NULL == (reclaim_buf = H5FL_BLK_MALLOC(type_conv, buf_size))) |
1782 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer"); |
1783 | | |
1784 | | /* allocate temporary bkg buff for data conversion */ |
1785 | 0 | if (NULL == (bkg = H5FL_BLK_MALLOC(type_conv, buf_size))) |
1786 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer"); |
1787 | 0 | } /* end if */ |
1788 | | |
1789 | | /* Loop over copying data */ |
1790 | 0 | addr_src = storage_src->addr; |
1791 | 0 | addr_dst = storage_dst->addr; |
1792 | | |
1793 | | /* If data sieving is enabled and the dataset is open in the file, |
1794 | | set up to copy data out of the sieve buffer if deemed possible later */ |
1795 | 0 | if (H5F_HAS_FEATURE(f_src, H5FD_FEAT_DATA_SIEVE) && shared_fo && shared_fo->cache.contig.sieve_buf) { |
1796 | 0 | try_sieve = true; |
1797 | 0 | sieve_start = shared_fo->cache.contig.sieve_loc; |
1798 | 0 | sieve_end = sieve_start + shared_fo->cache.contig.sieve_size; |
1799 | 0 | } |
1800 | |
|
1801 | 0 | while (total_src_nbytes > 0) { |
1802 | | /* Check if we should reduce the number of bytes to transfer */ |
1803 | 0 | if (total_src_nbytes < src_nbytes) { |
1804 | | /* Adjust bytes to transfer */ |
1805 | 0 | src_nbytes = (size_t)total_src_nbytes; |
1806 | | |
1807 | | /* Adjust dataspace describing buffer */ |
1808 | 0 | if (is_vlen) { |
1809 | | /* Adjust destination & memory bytes to transfer */ |
1810 | 0 | nelmts = src_nbytes / src_dt_size; |
1811 | 0 | dst_nbytes = nelmts * dst_dt_size; |
1812 | 0 | mem_nbytes = nelmts * mem_dt_size; |
1813 | | |
1814 | | /* Adjust size of buffer's dataspace dimension */ |
1815 | 0 | buf_dim[0] = nelmts; |
1816 | | |
1817 | | /* Adjust size of buffer's dataspace */ |
1818 | 0 | if (H5S_set_extent_real(buf_space, buf_dim) < 0) |
1819 | 0 | HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "unable to change buffer dataspace size"); |
1820 | 0 | } /* end if */ |
1821 | 0 | else |
1822 | | /* Adjust destination & memory bytes to transfer */ |
1823 | 0 | dst_nbytes = mem_nbytes = src_nbytes; |
1824 | 0 | } /* end if */ |
1825 | | |
1826 | | /* If the entire copy is within the sieve buffer, copy data from the sieve buffer */ |
1827 | 0 | if (try_sieve && (addr_src >= sieve_start) && ((addr_src + src_nbytes - 1) < sieve_end)) { |
1828 | 0 | unsigned char *base_sieve_buf = shared_fo->cache.contig.sieve_buf + (addr_src - sieve_start); |
1829 | |
|
1830 | 0 | H5MM_memcpy(buf, base_sieve_buf, src_nbytes); |
1831 | 0 | } |
1832 | 0 | else |
1833 | | /* Read raw data from source file */ |
1834 | 0 | if (H5F_block_read(f_src, H5FD_MEM_DRAW, addr_src, src_nbytes, buf) < 0) |
1835 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read raw data"); |
1836 | | |
1837 | | /* Perform datatype conversion, if necessary */ |
1838 | 0 | if (is_vlen) { |
1839 | | /* Convert from source file to memory */ |
1840 | 0 | if (H5T_convert(tpath_src_mem, dt_src, dt_mem, nelmts, (size_t)0, (size_t)0, buf, bkg) < 0) |
1841 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "datatype conversion failed"); |
1842 | | |
1843 | | /* Copy into another buffer, to reclaim memory later */ |
1844 | 0 | H5MM_memcpy(reclaim_buf, buf, mem_nbytes); |
1845 | | |
1846 | | /* Set background buffer to all zeros */ |
1847 | 0 | memset(bkg, 0, buf_size); |
1848 | | |
1849 | | /* Convert from memory to destination file */ |
1850 | 0 | if (H5T_convert(tpath_mem_dst, dt_mem, dt_dst, nelmts, (size_t)0, (size_t)0, buf, bkg) < 0) |
1851 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "datatype conversion failed"); |
1852 | | |
1853 | | /* Reclaim space from variable length data */ |
1854 | 0 | if (H5T_reclaim(dt_mem, buf_space, reclaim_buf) < 0) |
1855 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reclaim variable-length data"); |
1856 | 0 | } /* end if */ |
1857 | 0 | else if (fix_ref) { |
1858 | | /* Check for expanding references */ |
1859 | 0 | if (cpy_info->expand_ref) { |
1860 | | /* Copy the reference elements */ |
1861 | 0 | if (H5O_copy_expand_ref(f_src, dt_src, buf, buf_size, f_dst, bkg, cpy_info) < 0) |
1862 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy reference attribute"); |
1863 | | |
1864 | | /* After fix ref, copy the new reference elements to the buffer to write out */ |
1865 | 0 | H5MM_memcpy(buf, bkg, buf_size); |
1866 | 0 | } /* end if */ |
1867 | 0 | else |
1868 | | /* Reset value to zero */ |
1869 | 0 | memset(buf, 0, src_nbytes); |
1870 | 0 | } /* end if */ |
1871 | | |
1872 | | /* Write raw data to destination file */ |
1873 | 0 | if (H5F_block_write(f_dst, H5FD_MEM_DRAW, addr_dst, dst_nbytes, buf) < 0) |
1874 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write raw data"); |
1875 | | |
1876 | | /* Adjust loop variables */ |
1877 | 0 | addr_src += src_nbytes; |
1878 | 0 | addr_dst += dst_nbytes; |
1879 | 0 | total_src_nbytes -= src_nbytes; |
1880 | 0 | } /* end while */ |
1881 | | |
1882 | 0 | done: |
1883 | 0 | if (dt_dst && (H5T_close(dt_dst) < 0)) |
1884 | 0 | HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary datatype"); |
1885 | 0 | if (dt_mem && (H5T_close(dt_mem) < 0)) |
1886 | 0 | HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary datatype"); |
1887 | 0 | if (buf_space && H5S_close(buf_space) < 0) |
1888 | 0 | HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary dataspace"); |
1889 | 0 | if (buf) |
1890 | 0 | buf = H5FL_BLK_FREE(type_conv, buf); |
1891 | 0 | if (reclaim_buf) |
1892 | 0 | reclaim_buf = H5FL_BLK_FREE(type_conv, reclaim_buf); |
1893 | 0 | if (bkg) |
1894 | 0 | bkg = H5FL_BLK_FREE(type_conv, bkg); |
1895 | |
|
1896 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1897 | 0 | } /* end H5D__contig_copy() */ |