1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://www.hdfgroup.org/licenses. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /* Programmer: Quincey Koziol
15 * Thursday, April 24, 2008
16 *
17 * Purpose: Abstract indexed (chunked) I/O functions. The logical
18 * multi-dimensional dataspace is regularly partitioned into
19 * same-sized "chunks", the first of which is aligned with the
20 * logical origin. The chunks are indexed by different methods,
21 * that map a chunk index to disk address. Each chunk can be
22 * compressed independently and the chunks may move around in the
23 * file as their storage requirements change.
24 *
25 * Cache: Disk I/O is performed in units of chunks and H5MF_alloc()
26 * contains code to optionally align chunks on disk block
27 * boundaries for performance.
28 *
29 * The chunk cache is an extendible hash indexed by a function
30 * of storage B-tree address and chunk N-dimensional offset
31 * within the dataset. Collisions are not resolved -- one of
32 * the two chunks competing for the hash slot must be preempted
33 * from the cache. All entries in the hash also participate in
34 * a doubly-linked list and entries are penalized by moving them
35 * toward the front of the list. When a new chunk is about to
36 * be added to the cache the heap is pruned by preempting
37 * entries near the front of the list to make room for the new
38 * entry which is added to the end of the list.
39 */
40
41 /****************/
42 /* Module Setup */
43 /****************/
44
45 #include "H5Dmodule.h" /* This source code file is part of the H5D module */
46
47 /***********/
48 /* Headers */
49 /***********/
50 #include "H5private.h" /* Generic Functions */
51 #ifdef H5_HAVE_PARALLEL
52 #include "H5ACprivate.h" /* Metadata cache */
53 #endif /* H5_HAVE_PARALLEL */
54 #include "H5CXprivate.h" /* API Contexts */
55 #include "H5Dpkg.h" /* Dataset functions */
56 #include "H5Eprivate.h" /* Error handling */
57 #include "H5Fprivate.h" /* File functions */
58 #include "H5FLprivate.h" /* Free Lists */
59 #include "H5Iprivate.h" /* IDs */
60 #include "H5MMprivate.h" /* Memory management */
61 #include "H5MFprivate.h" /* File memory management */
62 #include "H5VMprivate.h" /* Vector and array functions */
63
64 /****************/
65 /* Local Macros */
66 /****************/
67
68 /* Macros for iterating over chunks to operate on */
69 #define H5D_CHUNK_GET_FIRST_NODE(map) (map->use_single ? (H5SL_node_t *)(1) : H5SL_first(map->sel_chunks))
70 #define H5D_CHUNK_GET_NODE_INFO(map, node) \
71 (map->use_single ? map->single_chunk_info : (H5D_chunk_info_t *)H5SL_item(node))
72 #define H5D_CHUNK_GET_NEXT_NODE(map, node) (map->use_single ? (H5SL_node_t *)NULL : H5SL_next(node))
73
74 /* Sanity check on chunk index types: commonly used by a lot of routines in this file */
75 #define H5D_CHUNK_STORAGE_INDEX_CHK(storage) \
76 HDassert((H5D_CHUNK_IDX_EARRAY == (storage)->idx_type && H5D_COPS_EARRAY == (storage)->ops) || \
77 (H5D_CHUNK_IDX_FARRAY == (storage)->idx_type && H5D_COPS_FARRAY == (storage)->ops) || \
78 (H5D_CHUNK_IDX_BT2 == (storage)->idx_type && H5D_COPS_BT2 == (storage)->ops) || \
79 (H5D_CHUNK_IDX_BTREE == (storage)->idx_type && H5D_COPS_BTREE == (storage)->ops) || \
80 (H5D_CHUNK_IDX_SINGLE == (storage)->idx_type && H5D_COPS_SINGLE == (storage)->ops) || \
81 (H5D_CHUNK_IDX_NONE == (storage)->idx_type && H5D_COPS_NONE == (storage)->ops));
82
83 /*
84 * Feature: If this constant is defined then every cache preemption and load
85 * causes a character to be printed on the standard error stream:
86 *
87 * `.': Entry was preempted because it has been completely read or
88 * completely written but not partially read and not partially
89 * written. This is often a good reason for preemption because such
90 * a chunk will be unlikely to be referenced in the near future.
91 *
92 * `:': Entry was preempted because it hasn't been used recently.
93 *
94 * `#': Entry was preempted because another chunk collided with it. This
95 * is usually a relatively bad thing. If there are too many of
96 * these then the number of entries in the cache can be increased.
97 *
98 * c: Entry was preempted because the file is closing.
99 *
100 * w: A chunk read operation was eliminated because the library is
101 * about to write new values to the entire chunk. This is a good
102 * thing, especially on files where the chunk size is the same as
103 * the disk block size, chunks are aligned on disk block boundaries,
104 * and the operating system can also eliminate a read operation.
105 */
106
107 /*#define H5D_CHUNK_DEBUG */
108
109 /* Flags for the "edge_chunk_state" field below */
110 #define H5D_RDCC_DISABLE_FILTERS 0x01u /* Disable filters on this chunk */
111 #define H5D_RDCC_NEWLY_DISABLED_FILTERS \
112 0x02u /* Filters have been disabled since \
113 * the last flush */
114
115 /******************/
116 /* Local Typedefs */
117 /******************/
118
119 /* Raw data chunks are cached. Each entry in the cache is: */
120 typedef struct H5D_rdcc_ent_t {
121 hbool_t locked; /*entry is locked in cache */
122 hbool_t dirty; /*needs to be written to disk? */
123 hbool_t deleted; /*chunk about to be deleted */
124 unsigned edge_chunk_state; /*states related to edge chunks (see above) */
125 hsize_t scaled[H5O_LAYOUT_NDIMS]; /*scaled chunk 'name' (coordinates) */
126 uint32_t rd_count; /*bytes remaining to be read */
127 uint32_t wr_count; /*bytes remaining to be written */
128 H5F_block_t chunk_block; /*offset/length of chunk in file */
129 hsize_t chunk_idx; /*index of chunk in dataset */
130 uint8_t * chunk; /*the unfiltered chunk data */
131 unsigned idx; /*index in hash table */
132 struct H5D_rdcc_ent_t *next; /*next item in doubly-linked list */
133 struct H5D_rdcc_ent_t *prev; /*previous item in doubly-linked list */
134 struct H5D_rdcc_ent_t *tmp_next; /*next item in temporary doubly-linked list */
135 struct H5D_rdcc_ent_t *tmp_prev; /*previous item in temporary doubly-linked list */
136 } H5D_rdcc_ent_t;
137 typedef H5D_rdcc_ent_t *H5D_rdcc_ent_ptr_t; /* For free lists */
138
139 /* Callback info for iteration to prune chunks */
140 typedef struct H5D_chunk_it_ud1_t {
141 H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
142 const H5D_chk_idx_info_t *idx_info; /* Chunked index info */
143 const H5D_io_info_t * io_info; /* I/O info for dataset operation */
144 const hsize_t * space_dim; /* New dataset dimensions */
145 const hbool_t * shrunk_dim; /* Dimensions which have been shrunk */
146 H5S_t * chunk_space; /* Dataspace for a chunk */
147 uint32_t elmts_per_chunk; /* Elements in chunk */
148 hsize_t * hyper_start; /* Starting location of hyperslab */
149 H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
150 hbool_t fb_info_init; /* Whether the fill value buffer has been initialized */
151 } H5D_chunk_it_ud1_t;
152
153 /* Callback info for iteration to obtain chunk address and the index of the chunk for all chunks in the
154 * B-tree. */
155 typedef struct H5D_chunk_it_ud2_t {
156 /* down */
157 H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
158
159 /* up */
160 haddr_t *chunk_addr; /* Array of chunk addresses to fill in */
161 } H5D_chunk_it_ud2_t;
162
163 /* Callback info for iteration to copy data */
164 typedef struct H5D_chunk_it_ud3_t {
165 H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
166 H5F_t * file_src; /* Source file for copy */
167 H5D_chk_idx_info_t * idx_info_dst; /* Dest. chunk index info object */
168 void * buf; /* Buffer to hold chunk data for read/write */
169 void * bkg; /* Buffer for background information during type conversion */
170 size_t buf_size; /* Buffer size */
171 hbool_t do_convert; /* Whether to perform type conversions */
172
173 /* needed for converting variable-length data */
174 hid_t tid_src; /* Datatype ID for source datatype */
175 hid_t tid_dst; /* Datatype ID for destination datatype */
176 hid_t tid_mem; /* Datatype ID for memory datatype */
177 const H5T_t *dt_src; /* Source datatype */
178 H5T_path_t * tpath_src_mem; /* Datatype conversion path from source file to memory */
179 H5T_path_t * tpath_mem_dst; /* Datatype conversion path from memory to dest. file */
180 void * reclaim_buf; /* Buffer for reclaiming data */
181 size_t reclaim_buf_size; /* Reclaim buffer size */
182 uint32_t nelmts; /* Number of elements in buffer */
183 H5S_t * buf_space; /* Dataspace describing buffer */
184
185 /* needed for compressed variable-length data */
186 const H5O_pline_t *pline; /* Filter pipeline */
187 unsigned dset_ndims; /* Number of dimensions in dataset */
188 const hsize_t * dset_dims; /* Dataset dimensions */
189
190 /* needed for copy object pointed by refs */
191 H5O_copy_t *cpy_info; /* Copy options */
192
193 /* needed for getting raw data from chunk cache */
194 hbool_t chunk_in_cache;
195 uint8_t *chunk; /* the unfiltered chunk data */
196 } H5D_chunk_it_ud3_t;
197
198 /* Callback info for iteration to dump index */
199 typedef struct H5D_chunk_it_ud4_t {
200 FILE * stream; /* Output stream */
201 hbool_t header_displayed; /* Node's header is displayed? */
202 unsigned ndims; /* Number of dimensions for chunk/dataset */
203 uint32_t *chunk_dim; /* Chunk dimensions */
204 } H5D_chunk_it_ud4_t;
205
206 /* Callback info for iteration to format convert chunks */
207 typedef struct H5D_chunk_it_ud5_t {
208 H5D_chk_idx_info_t *new_idx_info; /* Dest. chunk index info object */
209 unsigned dset_ndims; /* Number of dimensions in dataset */
210 hsize_t * dset_dims; /* Dataset dimensions */
211 } H5D_chunk_it_ud5_t;
212
213 /* Callback info for nonexistent readvv operation */
214 typedef struct H5D_chunk_readvv_ud_t {
215 unsigned char *rbuf; /* Read buffer to initialize */
216 const H5D_t * dset; /* Dataset to operate on */
217 } H5D_chunk_readvv_ud_t;
218
219 /* Typedef for chunk info iterator callback */
220 typedef struct H5D_chunk_info_iter_ud_t {
221 hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Logical offset of the chunk */
222 hsize_t ndims; /* Number of dimensions in the dataset */
223 uint32_t nbytes; /* Size of stored data in the chunk */
224 unsigned filter_mask; /* Excluded filters */
225 haddr_t chunk_addr; /* Address of the chunk in file */
226 hsize_t chunk_idx; /* Chunk index, where the iteration needs to stop */
227 hsize_t curr_idx; /* Current index, where the iteration is */
228 unsigned idx_hint; /* Index of chunk in cache, if present */
229 hbool_t found; /* Whether the chunk was found */
230 } H5D_chunk_info_iter_ud_t;
231
232 /* Callback info for file selection iteration */
233 typedef struct H5D_chunk_file_iter_ud_t {
234 H5D_chunk_map_t *fm; /* File->memory chunk mapping info */
235 #ifdef H5_HAVE_PARALLEL
236 const H5D_io_info_t *io_info; /* I/O info for operation */
237 #endif /* H5_HAVE_PARALLEL */
238 } H5D_chunk_file_iter_ud_t;
239
240 #ifdef H5_HAVE_PARALLEL
241 /* information to construct a collective I/O operation for filling chunks */
242 typedef struct H5D_chunk_coll_info_t {
243 size_t num_io; /* Number of write operations */
244 haddr_t *addr; /* array of the file addresses of the write operation */
245 } H5D_chunk_coll_info_t;
246 #endif /* H5_HAVE_PARALLEL */
247
248 /********************/
249 /* Local Prototypes */
250 /********************/
251
252 /* Chunked layout operation callbacks */
253 static herr_t H5D__chunk_construct(H5F_t *f, H5D_t *dset);
254 static herr_t H5D__chunk_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id);
255 static herr_t H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
256 hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
257 H5D_chunk_map_t *fm);
258 static herr_t H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
259 H5D_chunk_map_t *fm);
260 static herr_t H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
261 const H5S_t *file_space, const H5S_t *mem_space, H5D_chunk_map_t *fm);
262 static herr_t H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
263 const H5S_t *file_space, const H5S_t *mem_space, H5D_chunk_map_t *fm);
264 static herr_t H5D__chunk_flush(H5D_t *dset);
265 static herr_t H5D__chunk_io_term(const H5D_chunk_map_t *fm);
266 static herr_t H5D__chunk_dest(H5D_t *dset);
267
268 /* Chunk query operation callbacks */
269 static int H5D__get_num_chunks_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
270 static int H5D__get_chunk_info_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
271 static int H5D__get_chunk_info_by_coord_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
272
273 /* "Nonexistent" layout operation callback */
274 static ssize_t H5D__nonexistent_readvv(const H5D_io_info_t *io_info, size_t chunk_max_nseq,
275 size_t *chunk_curr_seq, size_t chunk_len_arr[],
276 hsize_t chunk_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq,
277 size_t mem_len_arr[], hsize_t mem_offset_arr[]);
278
279 /* Format convert cb */
280 static int H5D__chunk_format_convert_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
281
282 /* Helper routines */
283 static herr_t H5D__chunk_set_info_real(H5O_layout_chunk_t *layout, unsigned ndims, const hsize_t *curr_dims,
284 const hsize_t *max_dims);
285 static void * H5D__chunk_mem_alloc(size_t size, const H5O_pline_t *pline);
286 static void * H5D__chunk_mem_xfree(void *chk, const void *pline);
287 static void * H5D__chunk_mem_realloc(void *chk, size_t size, const H5O_pline_t *pline);
288 static herr_t H5D__chunk_cinfo_cache_reset(H5D_chunk_cached_t *last);
289 static herr_t H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t *last, const H5D_chunk_ud_t *udata);
290 static hbool_t H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last, H5D_chunk_ud_t *udata);
291 static herr_t H5D__free_chunk_info(void *item, void *key, void *opdata);
292 static herr_t H5D__create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t *io_info);
293 static herr_t H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, const H5D_io_info_t *io_info);
294 static herr_t H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t *io_info);
295 static herr_t H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t *fm);
296 static herr_t H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm);
297 static herr_t H5D__chunk_file_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords,
298 void *fm);
299 static herr_t H5D__chunk_mem_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords,
300 void *fm);
301 static unsigned H5D__chunk_hash_val(const H5D_shared_t *shared, const hsize_t *scaled);
302 static herr_t H5D__chunk_flush_entry(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t reset);
303 static herr_t H5D__chunk_cache_evict(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t flush);
304 static hbool_t H5D__chunk_is_partial_edge_chunk(unsigned dset_ndims, const uint32_t *chunk_dims,
305 const hsize_t *chunk_scaled, const hsize_t *dset_dims);
306 static void * H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax,
307 hbool_t prev_unfilt_chunk);
308 static herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbool_t dirty,
309 void *chunk, uint32_t naccessed);
310 static herr_t H5D__chunk_cache_prune(const H5D_t *dset, size_t size);
311 static herr_t H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk);
312 #ifdef H5_HAVE_PARALLEL
313 static herr_t H5D__chunk_collective_fill(const H5D_t *dset, H5D_chunk_coll_info_t *chunk_info,
314 size_t chunk_size, const void *fill_buf);
315 static int H5D__chunk_cmp_addr(const void *addr1, const void *addr2);
316 #endif /* H5_HAVE_PARALLEL */
317
318 /* Debugging helper routine callback */
319 static int H5D__chunk_dump_index_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
320
321 /*********************/
322 /* Package Variables */
323 /*********************/
324
325 /* Chunked storage layout I/O ops */
326 const H5D_layout_ops_t H5D_LOPS_CHUNK[1] = {
327 {H5D__chunk_construct, H5D__chunk_init, H5D__chunk_is_space_alloc, H5D__chunk_is_data_cached,
328 H5D__chunk_io_init, H5D__chunk_read, H5D__chunk_write,
329 #ifdef H5_HAVE_PARALLEL
330 H5D__chunk_collective_read, H5D__chunk_collective_write,
331 #endif /* H5_HAVE_PARALLEL */
332 NULL, NULL, H5D__chunk_flush, H5D__chunk_io_term, H5D__chunk_dest}};
333
334 /*******************/
335 /* Local Variables */
336 /*******************/
337
338 /* "nonexistent" storage layout I/O ops */
339 const H5D_layout_ops_t H5D_LOPS_NONEXISTENT[1] = {{NULL, NULL, NULL, NULL, NULL, NULL, NULL,
340 #ifdef H5_HAVE_PARALLEL
341 NULL, NULL,
342 #endif /* H5_HAVE_PARALLEL */
343 H5D__nonexistent_readvv, NULL, NULL, NULL, NULL}};
344
345 /* Declare a free list to manage the H5F_rdcc_ent_ptr_t sequence information */
346 H5FL_SEQ_DEFINE_STATIC(H5D_rdcc_ent_ptr_t);
347
348 /* Declare a free list to manage H5D_rdcc_ent_t objects */
349 H5FL_DEFINE_STATIC(H5D_rdcc_ent_t);
350
351 /* Declare a free list to manage the H5D_chunk_info_t struct */
352 H5FL_DEFINE(H5D_chunk_info_t);
353
354 /* Declare a free list to manage the chunk sequence information */
355 H5FL_BLK_DEFINE_STATIC(chunk);
356
357 /* Declare extern free list to manage the H5S_sel_iter_t struct */
358 H5FL_EXTERN(H5S_sel_iter_t);
359
360 /*-------------------------------------------------------------------------
361 * Function: H5D__chunk_direct_write
362 *
363 * Purpose: Internal routine to write a chunk directly into the file.
364 *
365 * Return: Non-negative on success/Negative on failure
366 *
367 * Programmer: Raymond Lu
368 * 30 July 2012
369 *
370 *-------------------------------------------------------------------------
371 */
372 herr_t
H5D__chunk_direct_write(const H5D_t * dset,uint32_t filters,hsize_t * offset,uint32_t data_size,const void * buf)373 H5D__chunk_direct_write(const H5D_t *dset, uint32_t filters, hsize_t *offset, uint32_t data_size,
374 const void *buf)
375 {
376 const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
377 H5D_chunk_ud_t udata; /* User data for querying chunk info */
378 H5F_block_t old_chunk; /* Offset/length of old chunk */
379 H5D_chk_idx_info_t idx_info; /* Chunked index info */
380 hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
381 hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
382 herr_t ret_value = SUCCEED; /* Return value */
383
384 FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr)
385
386 /* Sanity checks */
387 HDassert(layout->type == H5D_CHUNKED);
388
389 /* Allocate dataspace and initialize it if it hasn't been. */
390 if (!H5D__chunk_is_space_alloc(&layout->storage)) {
391 H5D_io_info_t io_info; /* to hold the dset info */
392
393 io_info.dset = dset;
394 io_info.f_sh = H5F_SHARED(dset->oloc.file);
395
396 /* Allocate storage */
397 if (H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, FALSE, NULL) < 0)
398 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
399 }
400
401 /* Calculate the index of this chunk */
402 H5VM_chunk_scaled(dset->shared->ndims, offset, layout->u.chunk.dim, scaled);
403 scaled[dset->shared->ndims] = 0;
404
405 /* Find out the file address of the chunk (if any) */
406 if (H5D__chunk_lookup(dset, scaled, &udata) < 0)
407 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
408
409 /* Sanity check */
410 HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
411 (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
412
413 /* Set the file block information for the old chunk */
414 /* (Which is only defined when overwriting an existing chunk) */
415 old_chunk.offset = udata.chunk_block.offset;
416 old_chunk.length = udata.chunk_block.length;
417
418 /* Check if the chunk needs to be inserted (it also could exist already
419 * and the chunk allocate operation could resize it)
420 */
421
422 /* Compose chunked index info struct */
423 idx_info.f = dset->oloc.file;
424 idx_info.pline = &(dset->shared->dcpl_cache.pline);
425 idx_info.layout = &(dset->shared->layout.u.chunk);
426 idx_info.storage = &(dset->shared->layout.storage.u.chunk);
427
428 /* Set up the size of chunk for user data */
429 udata.chunk_block.length = data_size;
430
431 if (0 == idx_info.pline->nused && H5F_addr_defined(old_chunk.offset))
432 /* If there are no filters and we are overwriting the chunk we can just set values */
433 need_insert = FALSE;
434 else {
435 /* Otherwise, create the chunk it if it doesn't exist, or reallocate the chunk
436 * if its size has changed.
437 */
438 if (H5D__chunk_file_alloc(&idx_info, &old_chunk, &udata.chunk_block, &need_insert, scaled) < 0)
439 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate chunk")
440
441 /* Cache the new chunk information */
442 H5D__chunk_cinfo_cache_update(&dset->shared->cache.chunk.last, &udata);
443 } /* end else */
444
445 /* Make sure the address of the chunk is returned. */
446 if (!H5F_addr_defined(udata.chunk_block.offset))
447 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk address isn't defined")
448
449 /* Evict the (old) entry from the cache if present, but do not flush
450 * it to disk */
451 if (UINT_MAX != udata.idx_hint) {
452 const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache */
453
454 if (H5D__chunk_cache_evict(dset, rdcc->slot[udata.idx_hint], FALSE) < 0)
455 HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to evict chunk")
456 } /* end if */
457
458 /* Write the data to the file */
459 if (H5F_shared_block_write(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW, udata.chunk_block.offset,
460 data_size, buf) < 0)
461 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
462
463 /* Insert the chunk record into the index */
464 if (need_insert && layout->storage.u.chunk.ops->insert) {
465 /* Set the chunk's filter mask to the new settings */
466 udata.filter_mask = filters;
467
468 if ((layout->storage.u.chunk.ops->insert)(&idx_info, &udata, dset) < 0)
469 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
470 } /* end if */
471
472 done:
473 FUNC_LEAVE_NOAPI_TAG(ret_value)
474 } /* end H5D__chunk_direct_write() */
475
476 /*-------------------------------------------------------------------------
477 * Function: H5D__chunk_direct_read
478 *
479 * Purpose: Internal routine to read a chunk directly from the file.
480 *
481 * Return: Non-negative on success/Negative on failure
482 *
483 * Programmer: Matthew Strong (GE Healthcare)
484 * 14 February 2016
485 *
486 *-------------------------------------------------------------------------
487 */
488 herr_t
H5D__chunk_direct_read(const H5D_t * dset,hsize_t * offset,uint32_t * filters,void * buf)489 H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, void *buf)
490 {
491 const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
492 const H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /* raw data chunk cache */
493 H5D_chunk_ud_t udata; /* User data for querying chunk info */
494 hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
495 herr_t ret_value = SUCCEED; /* Return value */
496
497 FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr)
498
499 /* Check args */
500 HDassert(dset && H5D_CHUNKED == layout->type);
501 HDassert(offset);
502 HDassert(filters);
503 HDassert(buf);
504
505 *filters = 0;
506
507 /* Allocate dataspace and initialize it if it hasn't been. */
508 if (!H5D__chunk_is_space_alloc(&layout->storage) && !H5D__chunk_is_data_cached(dset->shared))
509 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "storage is not initialized")
510
511 /* Calculate the index of this chunk */
512 H5VM_chunk_scaled(dset->shared->ndims, offset, layout->u.chunk.dim, scaled);
513 scaled[dset->shared->ndims] = 0;
514
515 /* Reset fields about the chunk we are looking for */
516 udata.filter_mask = 0;
517 udata.chunk_block.offset = HADDR_UNDEF;
518 udata.chunk_block.length = 0;
519 udata.idx_hint = UINT_MAX;
520
521 /* Find out the file address of the chunk */
522 if (H5D__chunk_lookup(dset, scaled, &udata) < 0)
523 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
524
525 /* Sanity check */
526 HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
527 (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
528
529 /* Check if the requested chunk exists in the chunk cache */
530 if (UINT_MAX != udata.idx_hint) {
531 H5D_rdcc_ent_t *ent = rdcc->slot[udata.idx_hint];
532 hbool_t flush;
533
534 /* Sanity checks */
535 HDassert(udata.idx_hint < rdcc->nslots);
536 HDassert(rdcc->slot[udata.idx_hint]);
537
538 flush = (ent->dirty == TRUE) ? TRUE : FALSE;
539
540 /* Flush the chunk to disk and clear the cache entry */
541 if (H5D__chunk_cache_evict(dset, rdcc->slot[udata.idx_hint], flush) < 0)
542 HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to evict chunk")
543
544 /* Reset fields about the chunk we are looking for */
545 udata.filter_mask = 0;
546 udata.chunk_block.offset = HADDR_UNDEF;
547 udata.chunk_block.length = 0;
548 udata.idx_hint = UINT_MAX;
549
550 /* Get the new file address / chunk size after flushing */
551 if (H5D__chunk_lookup(dset, scaled, &udata) < 0)
552 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
553 }
554
555 /* Make sure the address of the chunk is returned. */
556 if (!H5F_addr_defined(udata.chunk_block.offset))
557 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined")
558
559 /* Read the chunk data into the supplied buffer */
560 if (H5F_shared_block_read(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW, udata.chunk_block.offset,
561 udata.chunk_block.length, buf) < 0)
562 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
563
564 /* Return the filter mask */
565 *filters = udata.filter_mask;
566
567 done:
568 FUNC_LEAVE_NOAPI_TAG(ret_value)
569 } /* end H5D__chunk_direct_read() */
570
571 /*-------------------------------------------------------------------------
572 * Function: H5D__get_chunk_storage_size
573 *
574 * Purpose: Internal routine to read the storage size of a chunk on disk.
575 *
576 * Return: Non-negative on success/Negative on failure
577 *
578 * Programmer: Matthew Strong (GE Healthcare)
579 * 20 October 2016
580 *
581 *-------------------------------------------------------------------------
582 */
583 herr_t
H5D__get_chunk_storage_size(H5D_t * dset,const hsize_t * offset,hsize_t * storage_size)584 H5D__get_chunk_storage_size(H5D_t *dset, const hsize_t *offset, hsize_t *storage_size)
585 {
586 const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
587 const H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /* raw data chunk cache */
588 hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
589 H5D_chunk_ud_t udata; /* User data for querying chunk info */
590 herr_t ret_value = SUCCEED; /* Return value */
591
592 FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr)
593
594 /* Check args */
595 HDassert(dset && H5D_CHUNKED == layout->type);
596 HDassert(offset);
597 HDassert(storage_size);
598
599 *storage_size = 0;
600
601 /* Allocate dataspace and initialize it if it hasn't been. */
602 if (!(*layout->ops->is_space_alloc)(&layout->storage))
603 HGOTO_DONE(SUCCEED)
604
605 /* Calculate the index of this chunk */
606 H5VM_chunk_scaled(dset->shared->ndims, offset, layout->u.chunk.dim, scaled);
607 scaled[dset->shared->ndims] = 0;
608
609 /* Reset fields about the chunk we are looking for */
610 udata.chunk_block.offset = HADDR_UNDEF;
611 udata.chunk_block.length = 0;
612 udata.idx_hint = UINT_MAX;
613
614 /* Find out the file address of the chunk */
615 if (H5D__chunk_lookup(dset, scaled, &udata) < 0)
616 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
617
618 /* Sanity check */
619 HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
620 (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
621
622 /* The requested chunk is not in cache or on disk */
623 if (!H5F_addr_defined(udata.chunk_block.offset) && UINT_MAX == udata.idx_hint)
624 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk storage is not allocated")
625
626 /* Check if there are filters registered to the dataset */
627 if (dset->shared->dcpl_cache.pline.nused > 0) {
628 /* Check if the requested chunk exists in the chunk cache */
629 if (UINT_MAX != udata.idx_hint) {
630 H5D_rdcc_ent_t *ent = rdcc->slot[udata.idx_hint];
631
632 /* Sanity checks */
633 HDassert(udata.idx_hint < rdcc->nslots);
634 HDassert(rdcc->slot[udata.idx_hint]);
635
636 /* If the cached chunk is dirty, it must be flushed to get accurate size */
637 if (ent->dirty == TRUE) {
638 /* Flush the chunk to disk and clear the cache entry */
639 if (H5D__chunk_cache_evict(dset, rdcc->slot[udata.idx_hint], TRUE) < 0)
640 HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to evict chunk")
641
642 /* Reset fields about the chunk we are looking for */
643 udata.chunk_block.offset = HADDR_UNDEF;
644 udata.chunk_block.length = 0;
645 udata.idx_hint = UINT_MAX;
646
647 /* Get the new file address / chunk size after flushing */
648 if (H5D__chunk_lookup(dset, scaled, &udata) < 0)
649 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
650 }
651 }
652
653 /* Make sure the address of the chunk is returned. */
654 if (!H5F_addr_defined(udata.chunk_block.offset))
655 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined")
656
657 /* Return the chunk size on disk */
658 *storage_size = udata.chunk_block.length;
659 }
660 /* There are no filters registered, return the chunk size from the storage layout */
661 else
662 *storage_size = dset->shared->layout.u.chunk.size;
663
664 done:
665 FUNC_LEAVE_NOAPI_TAG(ret_value)
666 } /* H5D__get_chunk_storage_size */
667
668 /*-------------------------------------------------------------------------
669 * Function: H5D__chunk_set_info_real
670 *
671 * Purpose: Internal routine to set the information about chunks for a dataset
672 *
673 * Return: Non-negative on success/Negative on failure
674 *
675 * Programmer: Quincey Koziol
676 * Tuesday, June 30, 2009
677 *
678 *-------------------------------------------------------------------------
679 */
680 static herr_t
H5D__chunk_set_info_real(H5O_layout_chunk_t * layout,unsigned ndims,const hsize_t * curr_dims,const hsize_t * max_dims)681 H5D__chunk_set_info_real(H5O_layout_chunk_t *layout, unsigned ndims, const hsize_t *curr_dims,
682 const hsize_t *max_dims)
683 {
684 unsigned u; /* Local index variable */
685 herr_t ret_value = SUCCEED; /* Return value */
686
687 FUNC_ENTER_STATIC
688
689 /* Sanity checks */
690 HDassert(layout);
691 HDassert(ndims > 0);
692 HDassert(curr_dims);
693
694 /* Compute the # of chunks in dataset dimensions */
695 for (u = 0, layout->nchunks = 1, layout->max_nchunks = 1; u < ndims; u++) {
696 /* Round up to the next integer # of chunks, to accommodate partial chunks */
697 layout->chunks[u] = ((curr_dims[u] + layout->dim[u]) - 1) / layout->dim[u];
698 if (H5S_UNLIMITED == max_dims[u])
699 layout->max_chunks[u] = H5S_UNLIMITED;
700 else {
701 /* Sanity check */
702 if (layout->dim[u] == 0)
703 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "dimension size must be > 0, dim = %u ", u)
704
705 layout->max_chunks[u] = ((max_dims[u] + layout->dim[u]) - 1) / layout->dim[u];
706 }
707
708 /* Accumulate the # of chunks */
709 layout->nchunks *= layout->chunks[u];
710 layout->max_nchunks *= layout->max_chunks[u];
711 } /* end for */
712
713 /* Get the "down" sizes for each dimension */
714 H5VM_array_down(ndims, layout->chunks, layout->down_chunks);
715 H5VM_array_down(ndims, layout->max_chunks, layout->max_down_chunks);
716
717 done:
718 FUNC_LEAVE_NOAPI(ret_value)
719 } /* end H5D__chunk_set_info_real() */
720
721 /*-------------------------------------------------------------------------
722 * Function: H5D__chunk_set_info
723 *
724 * Purpose: Sets the information about chunks for a dataset
725 *
726 * Return: Non-negative on success/Negative on failure
727 *
728 * Programmer: Quincey Koziol
729 * Tuesday, June 30, 2009
730 *
731 *-------------------------------------------------------------------------
732 */
733 herr_t
H5D__chunk_set_info(const H5D_t * dset)734 H5D__chunk_set_info(const H5D_t *dset)
735 {
736 herr_t ret_value = SUCCEED; /* Return value */
737
738 FUNC_ENTER_PACKAGE
739
740 /* Sanity checks */
741 HDassert(dset);
742
743 /* Set the base layout information */
744 if (H5D__chunk_set_info_real(&dset->shared->layout.u.chunk, dset->shared->ndims, dset->shared->curr_dims,
745 dset->shared->max_dims) < 0)
746 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set layout's chunk info")
747
748 /* Call the index's "resize" callback */
749 if (dset->shared->layout.storage.u.chunk.ops->resize &&
750 (dset->shared->layout.storage.u.chunk.ops->resize)(&dset->shared->layout.u.chunk) < 0)
751 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to resize chunk index information")
752
753 done:
754 FUNC_LEAVE_NOAPI(ret_value)
755 } /* end H5D__chunk_set_info() */
756
757 /*-------------------------------------------------------------------------
758 * Function: H5D__chunk_set_sizes
759 *
760 * Purpose: Sets chunk and type sizes.
761 *
762 * Return: SUCCEED/FAIL
763 *
764 * Programmer: Dana Robinson
765 * December 2015
766 *
767 *-------------------------------------------------------------------------
768 */
769 herr_t
H5D__chunk_set_sizes(H5D_t * dset)770 H5D__chunk_set_sizes(H5D_t *dset)
771 {
772 uint64_t chunk_size; /* Size of chunk in bytes */
773 unsigned max_enc_bytes_per_dim; /* Max. number of bytes required to encode this dimension */
774 unsigned u; /* Iterator */
775 herr_t ret_value = SUCCEED; /* Return value */
776
777 FUNC_ENTER_NOAPI(FAIL)
778
779 /* Sanity checks */
780 HDassert(dset);
781
782 /* Increment # of chunk dimensions, to account for datatype size as last element */
783 dset->shared->layout.u.chunk.ndims++;
784
785 /* Set the last dimension of the chunk size to the size of the datatype */
786 dset->shared->layout.u.chunk.dim[dset->shared->layout.u.chunk.ndims - 1] =
787 (uint32_t)H5T_GET_SIZE(dset->shared->type);
788
789 /* Compute number of bytes to use for encoding chunk dimensions */
790 max_enc_bytes_per_dim = 0;
791 for (u = 0; u < (unsigned)dset->shared->layout.u.chunk.ndims; u++) {
792 unsigned enc_bytes_per_dim; /* Number of bytes required to encode this dimension */
793
794 /* Get encoded size of dim, in bytes */
795 enc_bytes_per_dim = (H5VM_log2_gen(dset->shared->layout.u.chunk.dim[u]) + 8) / 8;
796
797 /* Check if this is the largest value so far */
798 if (enc_bytes_per_dim > max_enc_bytes_per_dim)
799 max_enc_bytes_per_dim = enc_bytes_per_dim;
800 } /* end for */
801 HDassert(max_enc_bytes_per_dim > 0 && max_enc_bytes_per_dim <= 8);
802 dset->shared->layout.u.chunk.enc_bytes_per_dim = max_enc_bytes_per_dim;
803
804 /* Compute and store the total size of a chunk */
805 /* (Use 64-bit value to ensure that we can detect >4GB chunks) */
806 for (u = 1, chunk_size = (uint64_t)dset->shared->layout.u.chunk.dim[0];
807 u < dset->shared->layout.u.chunk.ndims; u++)
808 chunk_size *= (uint64_t)dset->shared->layout.u.chunk.dim[u];
809
810 /* Check for chunk larger than can be represented in 32-bits */
811 /* (Chunk size is encoded in 32-bit value in v1 B-tree records) */
812 if (chunk_size > (uint64_t)0xffffffff)
813 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "chunk size must be < 4GB")
814
815 H5_CHECKED_ASSIGN(dset->shared->layout.u.chunk.size, uint32_t, chunk_size, uint64_t);
816
817 done:
818 FUNC_LEAVE_NOAPI(ret_value)
819 } /* end H5D__chunk_set_sizes */
820
821 /*-------------------------------------------------------------------------
822 * Function: H5D__chunk_construct
823 *
824 * Purpose: Constructs new chunked layout information for dataset
825 *
826 * Return: Non-negative on success/Negative on failure
827 *
828 * Programmer: Quincey Koziol
829 * Thursday, May 22, 2008
830 *
831 *-------------------------------------------------------------------------
832 */
833 static herr_t
H5D__chunk_construct(H5F_t H5_ATTR_UNUSED * f,H5D_t * dset)834 H5D__chunk_construct(H5F_t H5_ATTR_UNUSED *f, H5D_t *dset)
835 {
836 unsigned u; /* Local index variable */
837 herr_t ret_value = SUCCEED; /* Return value */
838
839 FUNC_ENTER_STATIC
840
841 /* Sanity checks */
842 HDassert(f);
843 HDassert(dset);
844
845 /* Check for invalid chunk dimension rank */
846 if (0 == dset->shared->layout.u.chunk.ndims)
847 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "no chunk information set?")
848 if (dset->shared->layout.u.chunk.ndims != dset->shared->ndims)
849 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "dimensionality of chunks doesn't match the dataspace")
850
851 /* Set chunk sizes */
852 if (H5D__chunk_set_sizes(dset) < 0)
853 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to set chunk sizes")
854 HDassert((unsigned)(dset->shared->layout.u.chunk.ndims) <= NELMTS(dset->shared->layout.u.chunk.dim));
855
856 /* Chunked storage is not compatible with external storage (currently) */
857 if (dset->shared->dcpl_cache.efl.nused > 0)
858 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "external storage not supported with chunked layout")
859
860 /* Sanity check dimensions */
861 for (u = 0; u < dset->shared->layout.u.chunk.ndims - 1; u++) {
862 /* Don't allow zero-sized chunk dimensions */
863 if (0 == dset->shared->layout.u.chunk.dim[u])
864 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "chunk size must be > 0, dim = %u ", u)
865
866 /*
867 * The chunk size of a dimension with a fixed size cannot exceed
868 * the maximum dimension size. If any dimension size is zero, there
869 * will be no such restriction.
870 */
871 if (dset->shared->curr_dims[u] && dset->shared->max_dims[u] != H5S_UNLIMITED &&
872 dset->shared->max_dims[u] < dset->shared->layout.u.chunk.dim[u])
873 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
874 "chunk size must be <= maximum dimension size for fixed-sized dimensions")
875 } /* end for */
876
877 /* Reset address and pointer of the array struct for the chunked storage index */
878 if (H5D_chunk_idx_reset(&dset->shared->layout.storage.u.chunk, TRUE) < 0)
879 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to reset chunked storage index")
880
881 done:
882 FUNC_LEAVE_NOAPI(ret_value)
883 } /* end H5D__chunk_construct() */
884
885 /*-------------------------------------------------------------------------
886 * Function: H5D__chunk_init
887 *
888 * Purpose: Initialize the raw data chunk cache for a dataset. This is
889 * called when the dataset is initialized.
890 *
891 * Return: Non-negative on success/Negative on failure
892 *
893 * Programmer: Robb Matzke
894 * Monday, May 18, 1998
895 *
896 *-------------------------------------------------------------------------
897 */
898 static herr_t
H5D__chunk_init(H5F_t * f,const H5D_t * const dset,hid_t dapl_id)899 H5D__chunk_init(H5F_t *f, const H5D_t *const dset, hid_t dapl_id)
900 {
901 H5D_chk_idx_info_t idx_info; /* Chunked index info */
902 H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /* Convenience pointer to dataset's chunk cache */
903 H5P_genplist_t * dapl; /* Data access property list object pointer */
904 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
905 herr_t ret_value = SUCCEED; /* Return value */
906
907 FUNC_ENTER_STATIC
908
909 /* Sanity check */
910 HDassert(f);
911 HDassert(dset);
912 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
913
914 if (NULL == (dapl = (H5P_genplist_t *)H5I_object(dapl_id)))
915 HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for fapl ID")
916
917 /* Use the properties in dapl_id if they have been set, otherwise use the properties from the file */
918 if (H5P_get(dapl, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, &rdcc->nslots) < 0)
919 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get data cache number of slots")
920 if (rdcc->nslots == H5D_CHUNK_CACHE_NSLOTS_DEFAULT)
921 rdcc->nslots = H5F_RDCC_NSLOTS(f);
922
923 if (H5P_get(dapl, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, &rdcc->nbytes_max) < 0)
924 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get data cache byte size")
925 if (rdcc->nbytes_max == H5D_CHUNK_CACHE_NBYTES_DEFAULT)
926 rdcc->nbytes_max = H5F_RDCC_NBYTES(f);
927
928 if (H5P_get(dapl, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, &rdcc->w0) < 0)
929 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get preempt read chunks")
930 if (rdcc->w0 < 0)
931 rdcc->w0 = H5F_RDCC_W0(f);
932
933 /* If nbytes_max or nslots is 0, set them both to 0 and avoid allocating space */
934 if (!rdcc->nbytes_max || !rdcc->nslots)
935 rdcc->nbytes_max = rdcc->nslots = 0;
936 else {
937 rdcc->slot = H5FL_SEQ_CALLOC(H5D_rdcc_ent_ptr_t, rdcc->nslots);
938 if (NULL == rdcc->slot)
939 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
940
941 /* Reset any cached chunk info for this dataset */
942 H5D__chunk_cinfo_cache_reset(&(rdcc->last));
943 } /* end else */
944
945 /* Compute scaled dimension info, if dataset dims > 1 */
946 if (dset->shared->ndims > 1) {
947 unsigned u; /* Local index value */
948
949 for (u = 0; u < dset->shared->ndims; u++) {
950 hsize_t scaled_power2up; /* Scaled value, rounded to next power of 2 */
951
952 /* Initial scaled dimension sizes */
953 if (dset->shared->layout.u.chunk.dim[u] == 0)
954 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u)
955
956 /* Round up to the next integer # of chunks, to accommodate partial chunks */
957 rdcc->scaled_dims[u] = (dset->shared->curr_dims[u] + dset->shared->layout.u.chunk.dim[u] - 1) /
958 dset->shared->layout.u.chunk.dim[u];
959
960 if (!(scaled_power2up = H5VM_power2up(rdcc->scaled_dims[u])))
961 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get the next power of 2")
962
963 /* Inital 'power2up' values for scaled dimensions */
964 rdcc->scaled_power2up[u] = scaled_power2up;
965
966 /* Number of bits required to encode scaled dimension size */
967 rdcc->scaled_encode_bits[u] = H5VM_log2_gen(rdcc->scaled_power2up[u]);
968 } /* end for */
969 } /* end if */
970
971 /* Compose chunked index info struct */
972 idx_info.f = f;
973 idx_info.pline = &dset->shared->dcpl_cache.pline;
974 idx_info.layout = &dset->shared->layout.u.chunk;
975 idx_info.storage = sc;
976
977 /* Allocate any indexing structures */
978 if (sc->ops->init && (sc->ops->init)(&idx_info, dset->shared->space, dset->oloc.addr) < 0)
979 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize indexing information")
980
981 /* Set the number of chunks in dataset, etc. */
982 if (H5D__chunk_set_info(dset) < 0)
983 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set # of chunks for dataset")
984
985 done:
986 FUNC_LEAVE_NOAPI(ret_value)
987 } /* end H5D__chunk_init() */
988
989 /*-------------------------------------------------------------------------
990 * Function: H5D__chunk_is_space_alloc
991 *
992 * Purpose: Query if space is allocated for layout
993 *
994 * Return: Non-negative on success/Negative on failure
995 *
996 * Programmer: Quincey Koziol
997 * Thursday, January 15, 2009
998 *
999 *-------------------------------------------------------------------------
1000 */
1001 hbool_t
H5D__chunk_is_space_alloc(const H5O_storage_t * storage)1002 H5D__chunk_is_space_alloc(const H5O_storage_t *storage)
1003 {
1004 const H5O_storage_chunk_t *sc = &(storage->u.chunk);
1005 hbool_t ret_value = FALSE; /* Return value */
1006
1007 FUNC_ENTER_PACKAGE_NOERR
1008
1009 /* Sanity checks */
1010 HDassert(storage);
1011 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
1012
1013 /* Query index layer */
1014 ret_value = (sc->ops->is_space_alloc)(sc);
1015
1016 FUNC_LEAVE_NOAPI(ret_value)
1017 } /* end H5D__chunk_is_space_alloc() */
1018
1019 /*-------------------------------------------------------------------------
1020 * Function: H5D__chunk_is_data_cached
1021 *
1022 * Purpose: Query if raw data is cached for dataset
1023 *
1024 * Return: Non-negative on success/Negative on failure
1025 *
1026 * Programmer: Neil Fortner
1027 * Wednessday, March 6, 2016
1028 *
1029 *-------------------------------------------------------------------------
1030 */
1031 hbool_t
H5D__chunk_is_data_cached(const H5D_shared_t * shared_dset)1032 H5D__chunk_is_data_cached(const H5D_shared_t *shared_dset)
1033 {
1034 FUNC_ENTER_PACKAGE_NOERR
1035
1036 /* Sanity checks */
1037 HDassert(shared_dset);
1038
1039 FUNC_LEAVE_NOAPI(shared_dset->cache.chunk.nused > 0)
1040 } /* end H5D__chunk_is_data_cached() */
1041
1042 /*-------------------------------------------------------------------------
1043 * Function: H5D__chunk_io_init
1044 *
1045 * Purpose: Performs initialization before any sort of I/O on the raw data
1046 *
1047 * Return: Non-negative on success/Negative on failure
1048 *
1049 * Programmer: Quincey Koziol
1050 * Thursday, March 20, 2008
1051 *
1052 *-------------------------------------------------------------------------
1053 */
1054 static herr_t
H5D__chunk_io_init(const H5D_io_info_t * io_info,const H5D_type_info_t * type_info,hsize_t nelmts,const H5S_t * file_space,const H5S_t * mem_space,H5D_chunk_map_t * fm)1055 H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
1056 const H5S_t *file_space, const H5S_t *mem_space, H5D_chunk_map_t *fm)
1057 {
1058 const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */
1059 hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */
1060 htri_t file_space_normalized = FALSE; /* File dataspace was normalized */
1061 unsigned f_ndims; /* The number of dimensions of the file's dataspace */
1062 int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */
1063 unsigned u; /* Local index variable */
1064 herr_t ret_value = SUCCEED; /* Return value */
1065
1066 FUNC_ENTER_STATIC
1067
1068 /* Get layout for dataset */
1069 fm->layout = &(dataset->shared->layout);
1070 fm->nelmts = nelmts;
1071
1072 /* Check if the memory space is scalar & make equivalent memory space */
1073 if ((sm_ndims = H5S_GET_EXTENT_NDIMS(mem_space)) < 0)
1074 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number")
1075 /* Set the number of dimensions for the memory dataspace */
1076 H5_CHECKED_ASSIGN(fm->m_ndims, unsigned, sm_ndims, int);
1077
1078 /* Get rank for file dataspace */
1079 fm->f_ndims = f_ndims = dataset->shared->layout.u.chunk.ndims - 1;
1080
1081 /* Normalize hyperslab selections by adjusting them by the offset */
1082 /* (It might be worthwhile to normalize both the file and memory dataspaces
1083 * before any (contiguous, chunked, etc) file I/O operation, in order to
1084 * speed up hyperslab calculations by removing the extra checks and/or
1085 * additions involving the offset and the hyperslab selection -QAK)
1086 */
1087 if ((file_space_normalized = H5S_hyper_normalize_offset((H5S_t *)file_space, old_offset)) < 0)
1088 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to normalize selection")
1089
1090 /* Decide the number of chunks in each dimension */
1091 for (u = 0; u < f_ndims; u++)
1092 /* Keep the size of the chunk dimensions as hsize_t for various routines */
1093 fm->chunk_dim[u] = fm->layout->u.chunk.dim[u];
1094
1095 #ifdef H5_HAVE_PARALLEL
1096 /* Calculate total chunk in file map*/
1097 fm->select_chunk = NULL;
1098 if (io_info->using_mpi_vfd) {
1099 H5_CHECK_OVERFLOW(fm->layout->u.chunk.nchunks, hsize_t, size_t);
1100 if (fm->layout->u.chunk.nchunks)
1101 if (NULL == (fm->select_chunk = (H5D_chunk_info_t **)H5MM_calloc(
1102 (size_t)fm->layout->u.chunk.nchunks * sizeof(H5D_chunk_info_t *))))
1103 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info")
1104 } /* end if */
1105 #endif /* H5_HAVE_PARALLEL */
1106
1107 /* Initialize "last chunk" information */
1108 fm->last_index = (hsize_t)-1;
1109 fm->last_chunk_info = NULL;
1110
1111 /* Point at the dataspaces */
1112 fm->file_space = file_space;
1113 fm->mem_space = mem_space;
1114
1115 if (H5D__chunk_io_init_selections(io_info, type_info, fm) < 0)
1116 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file and memory chunk selections")
1117
1118 done:
1119 /* Reset the global dataspace info */
1120 fm->file_space = NULL;
1121 fm->mem_space = NULL;
1122
1123 if (file_space_normalized == TRUE)
1124 if (H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) <
1125 0) /* (Casting away const OK -QAK) */
1126 HDONE_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't denormalize selection")
1127
1128 FUNC_LEAVE_NOAPI(ret_value)
1129 } /* end H5D__chunk_io_init() */
1130
1131 /*-------------------------------------------------------------------------
1132 * Function: H5D__chunk_io_init_selections
1133 *
1134 * Purpose: Initialize the chunk mappings
1135 *
1136 * Return: Non-negative on success/Negative on failure
1137 *
1138 * Programmer: Quincey Koziol
1139 * Thursday, March 20, 2008
1140 *
1141 *-------------------------------------------------------------------------
1142 */
1143 static herr_t
H5D__chunk_io_init_selections(const H5D_io_info_t * io_info,const H5D_type_info_t * type_info,H5D_chunk_map_t * fm)1144 H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
1145 H5D_chunk_map_t *fm)
1146 {
1147 const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */
1148 const H5T_t *mem_type = type_info->mem_type; /* Local pointer to memory datatype */
1149 H5S_t * tmp_mspace = NULL; /* Temporary memory dataspace */
1150 H5T_t * file_type = NULL; /* Temporary copy of file datatype for iteration */
1151 hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */
1152 char bogus; /* "bogus" buffer to pass to selection iterator */
1153 herr_t ret_value = SUCCEED; /* Return value */
1154
1155 FUNC_ENTER_STATIC
1156
1157 /* Special case for only one element in selection */
1158 /* (usually appending a record) */
1159 if (fm->nelmts == 1
1160 #ifdef H5_HAVE_PARALLEL
1161 && !(io_info->using_mpi_vfd)
1162 #endif /* H5_HAVE_PARALLEL */
1163 && H5S_SEL_ALL != H5S_GET_SELECT_TYPE(fm->file_space)) {
1164 /* Initialize skip list for chunk selections */
1165 fm->sel_chunks = NULL;
1166 fm->use_single = TRUE;
1167
1168 /* Initialize single chunk dataspace */
1169 if (NULL == dataset->shared->cache.chunk.single_space) {
1170 /* Make a copy of the dataspace for the dataset */
1171 if ((dataset->shared->cache.chunk.single_space = H5S_copy(fm->file_space, TRUE, FALSE)) == NULL)
1172 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space")
1173
1174 /* Resize chunk's dataspace dimensions to size of chunk */
1175 if (H5S_set_extent_real(dataset->shared->cache.chunk.single_space, fm->chunk_dim) < 0)
1176 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust chunk dimensions")
1177
1178 /* Set the single chunk dataspace to 'all' selection */
1179 if (H5S_select_all(dataset->shared->cache.chunk.single_space, TRUE) < 0)
1180 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to set all selection")
1181 } /* end if */
1182 fm->single_space = dataset->shared->cache.chunk.single_space;
1183 HDassert(fm->single_space);
1184
1185 /* Allocate the single chunk information */
1186 if (NULL == dataset->shared->cache.chunk.single_chunk_info)
1187 if (NULL == (dataset->shared->cache.chunk.single_chunk_info = H5FL_MALLOC(H5D_chunk_info_t)))
1188 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info")
1189 fm->single_chunk_info = dataset->shared->cache.chunk.single_chunk_info;
1190 HDassert(fm->single_chunk_info);
1191
1192 /* Reset chunk template information */
1193 fm->mchunk_tmpl = NULL;
1194
1195 /* Set up chunk mapping for single element */
1196 if (H5D__create_chunk_map_single(fm, io_info) < 0)
1197 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
1198 "unable to create chunk selections for single element")
1199 } /* end if */
1200 else {
1201 hbool_t sel_hyper_flag; /* Whether file selection is a hyperslab */
1202
1203 /* Initialize skip list for chunk selections */
1204 if (NULL == dataset->shared->cache.chunk.sel_chunks)
1205 if (NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE, NULL)))
1206 HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for chunk selections")
1207 fm->sel_chunks = dataset->shared->cache.chunk.sel_chunks;
1208 HDassert(fm->sel_chunks);
1209
1210 /* We are not using single element mode */
1211 fm->use_single = FALSE;
1212
1213 /* Get type of selection on disk & in memory */
1214 if ((fm->fsel_type = H5S_GET_SELECT_TYPE(fm->file_space)) < H5S_SEL_NONE)
1215 HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection")
1216 if ((fm->msel_type = H5S_GET_SELECT_TYPE(fm->mem_space)) < H5S_SEL_NONE)
1217 HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection")
1218
1219 /* If the selection is NONE or POINTS, set the flag to FALSE */
1220 if (fm->fsel_type == H5S_SEL_POINTS || fm->fsel_type == H5S_SEL_NONE)
1221 sel_hyper_flag = FALSE;
1222 else
1223 sel_hyper_flag = TRUE;
1224
1225 /* Check if file selection is a not a hyperslab selection */
1226 if (sel_hyper_flag) {
1227 /* Build the file selection for each chunk */
1228 if (H5S_SEL_ALL == fm->fsel_type) {
1229 if (H5D__create_chunk_file_map_all(fm, io_info) < 0)
1230 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections")
1231 } /* end if */
1232 else {
1233 /* Sanity check */
1234 HDassert(fm->fsel_type == H5S_SEL_HYPERSLABS);
1235
1236 if (H5D__create_chunk_file_map_hyper(fm, io_info) < 0)
1237 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections")
1238 } /* end else */
1239 } /* end if */
1240 else {
1241 H5S_sel_iter_op_t iter_op; /* Operator for iteration */
1242 H5D_chunk_file_iter_ud_t udata; /* User data for iteration */
1243
1244 /* Create temporary datatypes for selection iteration */
1245 if (NULL == (file_type = H5T_copy(dataset->shared->type, H5T_COPY_ALL)))
1246 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "unable to copy file datatype")
1247
1248 /* Initialize the user data */
1249 udata.fm = fm;
1250 #ifdef H5_HAVE_PARALLEL
1251 udata.io_info = io_info;
1252 #endif /* H5_HAVE_PARALLEL */
1253
1254 iter_op.op_type = H5S_SEL_ITER_OP_LIB;
1255 iter_op.u.lib_op = H5D__chunk_file_cb;
1256
1257 /* Spaces might not be the same shape, iterate over the file selection directly */
1258 if (H5S_select_iterate(&bogus, file_type, fm->file_space, &iter_op, &udata) < 0)
1259 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections")
1260
1261 /* Reset "last chunk" info */
1262 fm->last_index = (hsize_t)-1;
1263 fm->last_chunk_info = NULL;
1264 } /* end else */
1265
1266 /* Build the memory selection for each chunk */
1267 if (sel_hyper_flag && H5S_SELECT_SHAPE_SAME(fm->file_space, fm->mem_space) == TRUE) {
1268 /* Reset chunk template information */
1269 fm->mchunk_tmpl = NULL;
1270
1271 /* If the selections are the same shape, use the file chunk information
1272 * to generate the memory chunk information quickly.
1273 */
1274 if (H5D__create_chunk_mem_map_hyper(fm) < 0)
1275 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections")
1276 } /* end if */
1277 else if (sel_hyper_flag && fm->f_ndims == 1 && fm->m_ndims == 1 &&
1278 H5S_SELECT_IS_REGULAR(fm->mem_space) && H5S_SELECT_IS_SINGLE(fm->mem_space)) {
1279 if (H5D__create_chunk_mem_map_1d(fm) < 0)
1280 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections")
1281 } /* end else-if */
1282 else {
1283 H5S_sel_iter_op_t iter_op; /* Operator for iteration */
1284 size_t elmt_size; /* Memory datatype size */
1285
1286 /* Make a copy of equivalent memory space */
1287 if ((tmp_mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL)
1288 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space")
1289
1290 /* De-select the mem space copy */
1291 if (H5S_select_none(tmp_mspace) < 0)
1292 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select memory space")
1293
1294 /* Save chunk template information */
1295 fm->mchunk_tmpl = tmp_mspace;
1296
1297 /* Create temporary datatypes for selection iteration */
1298 if (!file_type)
1299 if (NULL == (file_type = H5T_copy(dataset->shared->type, H5T_COPY_ALL)))
1300 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "unable to copy file datatype")
1301
1302 /* Create selection iterator for memory selection */
1303 if (0 == (elmt_size = H5T_get_size(mem_type)))
1304 HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "datatype size invalid")
1305 if (H5S_select_iter_init(&(fm->mem_iter), fm->mem_space, elmt_size, 0) < 0)
1306 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
1307 iter_init = TRUE; /* Selection iteration info has been initialized */
1308
1309 iter_op.op_type = H5S_SEL_ITER_OP_LIB;
1310 iter_op.u.lib_op = H5D__chunk_mem_cb;
1311
1312 /* Spaces aren't the same shape, iterate over the memory selection directly */
1313 if (H5S_select_iterate(&bogus, file_type, fm->file_space, &iter_op, fm) < 0)
1314 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections")
1315 } /* end else */
1316 } /* end else */
1317
1318 done:
1319 /* Release the [potentially partially built] chunk mapping information if an error occurs */
1320 if (ret_value < 0) {
1321 if (tmp_mspace && !fm->mchunk_tmpl)
1322 if (H5S_close(tmp_mspace) < 0)
1323 HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL,
1324 "can't release memory chunk dataspace template")
1325 if (H5D__chunk_io_term(fm) < 0)
1326 HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping")
1327 } /* end if */
1328
1329 if (iter_init && H5S_SELECT_ITER_RELEASE(&(fm->mem_iter)) < 0)
1330 HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
1331 if (file_type && (H5T_close_real(file_type) < 0))
1332 HDONE_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Can't free temporary datatype")
1333
1334 FUNC_LEAVE_NOAPI(ret_value)
1335 } /* end H5D__chunk_io_init_selections() */
1336
1337 /*-------------------------------------------------------------------------
1338 * Function: H5D__chunk_mem_alloc
1339 *
1340 * Purpose: Allocate space for a chunk in memory. This routine allocates
1341 * memory space for non-filtered chunks from a block free list
1342 * and uses malloc()/free() for filtered chunks.
1343 *
1344 * Return: Pointer to memory for chunk on success/NULL on failure
1345 *
1346 * Programmer: Quincey Koziol
1347 * April 22, 2004
1348 *
1349 *-------------------------------------------------------------------------
1350 */
1351 static void *
H5D__chunk_mem_alloc(size_t size,const H5O_pline_t * pline)1352 H5D__chunk_mem_alloc(size_t size, const H5O_pline_t *pline)
1353 {
1354 void *ret_value = NULL; /* Return value */
1355
1356 FUNC_ENTER_STATIC_NOERR
1357
1358 HDassert(size);
1359
1360 if (pline && pline->nused)
1361 ret_value = H5MM_malloc(size);
1362 else
1363 ret_value = H5FL_BLK_MALLOC(chunk, size);
1364
1365 FUNC_LEAVE_NOAPI(ret_value)
1366 } /* H5D__chunk_mem_alloc() */
1367
1368 /*-------------------------------------------------------------------------
1369 * Function: H5D__chunk_mem_xfree
1370 *
1371 * Purpose: Free space for a chunk in memory. This routine releases
1372 * memory space for non-filtered chunks from a block free list
1373 * and uses malloc()/free() for filtered chunks.
1374 *
1375 * Return: NULL (never fails)
1376 *
1377 * Programmer: Quincey Koziol
1378 * April 22, 2004
1379 *
1380 *-------------------------------------------------------------------------
1381 */
1382 static void *
H5D__chunk_mem_xfree(void * chk,const void * _pline)1383 H5D__chunk_mem_xfree(void *chk, const void *_pline)
1384 {
1385 const H5O_pline_t *pline = (const H5O_pline_t *)_pline;
1386
1387 FUNC_ENTER_STATIC_NOERR
1388
1389 if (chk) {
1390 if (pline && pline->nused)
1391 H5MM_xfree(chk);
1392 else
1393 chk = H5FL_BLK_FREE(chunk, chk);
1394 } /* end if */
1395
1396 FUNC_LEAVE_NOAPI(NULL)
1397 } /* H5D__chunk_mem_xfree() */
1398
1399 /*-------------------------------------------------------------------------
1400 * Function: H5D__chunk_mem_realloc
1401 *
1402 * Purpose: Reallocate space for a chunk in memory. This routine allocates
1403 * memory space for non-filtered chunks from a block free list
1404 * and uses malloc()/free() for filtered chunks.
1405 *
1406 * Return: Pointer to memory for chunk on success/NULL on failure
1407 *
1408 * Programmer: Neil Fortner
1409 * May 3, 2010
1410 *
1411 *-------------------------------------------------------------------------
1412 */
1413 static void *
H5D__chunk_mem_realloc(void * chk,size_t size,const H5O_pline_t * pline)1414 H5D__chunk_mem_realloc(void *chk, size_t size, const H5O_pline_t *pline)
1415 {
1416 void *ret_value = NULL; /* Return value */
1417
1418 FUNC_ENTER_STATIC_NOERR
1419
1420 HDassert(size);
1421 HDassert(pline);
1422
1423 if (pline->nused > 0)
1424 ret_value = H5MM_realloc(chk, size);
1425 else
1426 ret_value = H5FL_BLK_REALLOC(chunk, chk, size);
1427
1428 FUNC_LEAVE_NOAPI(ret_value)
1429 } /* H5D__chunk_mem_realloc() */
1430
1431 /*--------------------------------------------------------------------------
1432 NAME
1433 H5D__free_chunk_info
1434 PURPOSE
1435 Internal routine to destroy a chunk info node
1436 USAGE
1437 void H5D__free_chunk_info(chunk_info)
1438 void *chunk_info; IN: Pointer to chunk info to destroy
1439 RETURNS
1440 No return value
1441 DESCRIPTION
1442 Releases all the memory for a chunk info node. Called by H5SL_free
1443 GLOBAL VARIABLES
1444 COMMENTS, BUGS, ASSUMPTIONS
1445 EXAMPLES
1446 REVISION LOG
1447 --------------------------------------------------------------------------*/
1448 static herr_t
H5D__free_chunk_info(void * item,void H5_ATTR_UNUSED * key,void H5_ATTR_UNUSED * opdata)1449 H5D__free_chunk_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *opdata)
1450 {
1451 H5D_chunk_info_t *chunk_info = (H5D_chunk_info_t *)item;
1452
1453 FUNC_ENTER_STATIC_NOERR
1454
1455 HDassert(chunk_info);
1456
1457 /* Close the chunk's file dataspace, if it's not shared */
1458 if (!chunk_info->fspace_shared)
1459 (void)H5S_close(chunk_info->fspace);
1460 else
1461 H5S_select_all(chunk_info->fspace, TRUE);
1462
1463 /* Close the chunk's memory dataspace, if it's not shared */
1464 if (!chunk_info->mspace_shared && chunk_info->mspace)
1465 (void)H5S_close(chunk_info->mspace);
1466
1467 /* Free the actual chunk info */
1468 chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info);
1469
1470 FUNC_LEAVE_NOAPI(0)
1471 } /* H5D__free_chunk_info() */
1472
1473 /*-------------------------------------------------------------------------
1474 * Function: H5D__create_chunk_map_single
1475 *
1476 * Purpose: Create chunk selections when appending a single record
1477 *
1478 * Return: Non-negative on success/Negative on failure
1479 *
1480 * Programmer: Quincey Koziol
1481 * Tuesday, November 20, 2007
1482 *
1483 *-------------------------------------------------------------------------
1484 */
1485 static herr_t
H5D__create_chunk_map_single(H5D_chunk_map_t * fm,const H5D_io_info_t H5_ATTR_UNUSED * io_info)1486 H5D__create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t
1487 #ifndef H5_HAVE_PARALLEL
1488 H5_ATTR_UNUSED
1489 #endif /* H5_HAVE_PARALLEL */
1490 *io_info)
1491 {
1492 H5D_chunk_info_t *chunk_info; /* Chunk information to insert into skip list */
1493 hsize_t coords[H5O_LAYOUT_NDIMS]; /* Coordinates of chunk */
1494 hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */
1495 hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */
1496 unsigned u; /* Local index variable */
1497 herr_t ret_value = SUCCEED; /* Return value */
1498
1499 FUNC_ENTER_STATIC
1500
1501 /* Sanity check */
1502 HDassert(fm->f_ndims > 0);
1503
1504 /* Get coordinate for selection */
1505 if (H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0)
1506 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
1507
1508 /* Initialize the 'single chunk' file & memory chunk information */
1509 chunk_info = fm->single_chunk_info;
1510 chunk_info->chunk_points = 1;
1511
1512 /* Set chunk location & hyperslab size */
1513 for (u = 0; u < fm->f_ndims; u++) {
1514 /* Validate this chunk dimension */
1515 if (fm->layout->u.chunk.dim[u] == 0)
1516 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u)
1517 HDassert(sel_start[u] == sel_end[u]);
1518 chunk_info->scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u];
1519 coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u];
1520 } /* end for */
1521 chunk_info->scaled[fm->f_ndims] = 0;
1522
1523 /* Calculate the index of this chunk */
1524 chunk_info->index =
1525 H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, chunk_info->scaled);
1526
1527 /* Copy selection for file's dataspace into chunk dataspace */
1528 if (H5S_select_copy(fm->single_space, fm->file_space, FALSE) < 0)
1529 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file selection")
1530
1531 /* Move selection back to have correct offset in chunk */
1532 if (H5S_SELECT_ADJUST_U(fm->single_space, coords) < 0)
1533 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection")
1534
1535 #ifdef H5_HAVE_PARALLEL
1536 /* store chunk selection information */
1537 if (io_info->using_mpi_vfd)
1538 fm->select_chunk[chunk_info->index] = chunk_info;
1539 #endif /* H5_HAVE_PARALLEL */
1540
1541 /* Set the file dataspace for the chunk to the shared 'single' dataspace */
1542 chunk_info->fspace = fm->single_space;
1543
1544 /* Indicate that the chunk's file dataspace is shared */
1545 chunk_info->fspace_shared = TRUE;
1546
1547 /* Just point at the memory dataspace & selection */
1548 /* (Casting away const OK -QAK) */
1549 chunk_info->mspace = (H5S_t *)fm->mem_space;
1550
1551 /* Indicate that the chunk's memory dataspace is shared */
1552 chunk_info->mspace_shared = TRUE;
1553
1554 done:
1555 FUNC_LEAVE_NOAPI(ret_value)
1556 } /* end H5D__create_chunk_map_single() */
1557
1558 /*-------------------------------------------------------------------------
1559 * Function: H5D__create_chunk_file_map_all
1560 *
1561 * Purpose: Create all chunk selections in file, for an "all" selection.
1562 *
1563 * Return: Non-negative on success/Negative on failure
1564 *
1565 * Programmer: Quincey Koziol
1566 * Monday, January 21, 2019
1567 *
1568 *-------------------------------------------------------------------------
1569 */
1570 static herr_t
H5D__create_chunk_file_map_all(H5D_chunk_map_t * fm,const H5D_io_info_t H5_ATTR_UNUSED * io_info)1571 H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, const H5D_io_info_t
1572 #ifndef H5_HAVE_PARALLEL
1573 H5_ATTR_UNUSED
1574 #endif /* H5_HAVE_PARALLEL */
1575 *io_info)
1576 {
1577 H5S_t * tmp_fchunk = NULL; /* Temporary file dataspace */
1578 hsize_t file_dims[H5S_MAX_RANK]; /* File dataspace dims */
1579 hsize_t sel_points; /* Number of elements in file selection */
1580 hsize_t zeros[H5S_MAX_RANK]; /* All zero vector (for start parameter to setting hyperslab on partial
1581 chunks) */
1582 hsize_t coords[H5S_MAX_RANK]; /* Current coordinates of chunk */
1583 hsize_t end[H5S_MAX_RANK]; /* Final coordinates of chunk */
1584 hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
1585 hsize_t chunk_index; /* "Index" of chunk */
1586 hsize_t curr_partial_clip[H5S_MAX_RANK]; /* Current partial dimension sizes to clip against */
1587 hsize_t partial_dim_size[H5S_MAX_RANK]; /* Size of a partial dimension */
1588 hbool_t is_partial_dim[H5S_MAX_RANK]; /* Whether a dimension is currently a partial chunk */
1589 unsigned num_partial_dims; /* Current number of partial dimensions */
1590 unsigned u; /* Local index variable */
1591 herr_t ret_value = SUCCEED; /* Return value */
1592
1593 FUNC_ENTER_STATIC
1594
1595 /* Sanity check */
1596 HDassert(fm->f_ndims > 0);
1597
1598 /* Get number of elements selected in file */
1599 sel_points = fm->nelmts;
1600
1601 /* Get dataspace dimensions */
1602 if (H5S_get_simple_extent_dims(fm->file_space, file_dims, NULL) < 0)
1603 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
1604
1605 /* Set initial chunk location, partial dimensions, etc */
1606 num_partial_dims = 0;
1607 HDmemset(zeros, 0, sizeof(zeros));
1608 for (u = 0; u < fm->f_ndims; u++) {
1609 /* Validate this chunk dimension */
1610 if (fm->layout->u.chunk.dim[u] == 0)
1611 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u)
1612
1613 /* Set up start / end coordinates for first chunk */
1614 scaled[u] = 0;
1615 coords[u] = 0;
1616 end[u] = fm->chunk_dim[u] - 1;
1617
1618 /* Iniitialize partial chunk dimension information */
1619 partial_dim_size[u] = file_dims[u] % fm->chunk_dim[u];
1620 if (file_dims[u] < fm->chunk_dim[u]) {
1621 curr_partial_clip[u] = partial_dim_size[u];
1622 is_partial_dim[u] = TRUE;
1623 num_partial_dims++;
1624 } /* end if */
1625 else {
1626 curr_partial_clip[u] = fm->chunk_dim[u];
1627 is_partial_dim[u] = FALSE;
1628 } /* end else */
1629 } /* end for */
1630
1631 /* Set the index of this chunk */
1632 chunk_index = 0;
1633
1634 /* Create "temporary" chunk for selection operations (copy file space) */
1635 if (NULL == (tmp_fchunk = H5S_create_simple(fm->f_ndims, fm->chunk_dim, NULL)))
1636 HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create dataspace for chunk")
1637
1638 /* Iterate through each chunk in the dataset */
1639 while (sel_points) {
1640 H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */
1641 hsize_t chunk_points; /* Number of elements in chunk selection */
1642
1643 /* Add temporary chunk to the list of chunks */
1644
1645 /* Allocate the file & memory chunk information */
1646 if (NULL == (new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t)))
1647 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk info")
1648
1649 /* Initialize the chunk information */
1650
1651 /* Set the chunk index */
1652 new_chunk_info->index = chunk_index;
1653
1654 #ifdef H5_HAVE_PARALLEL
1655 /* Store chunk selection information, for multi-chunk I/O */
1656 if (io_info->using_mpi_vfd)
1657 fm->select_chunk[chunk_index] = new_chunk_info;
1658 #endif /* H5_HAVE_PARALLEL */
1659
1660 /* Set the file chunk dataspace */
1661 if (NULL == (new_chunk_info->fspace = H5S_copy(tmp_fchunk, TRUE, FALSE)))
1662 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy chunk dataspace")
1663 new_chunk_info->fspace_shared = FALSE;
1664
1665 /* If there are partial dimensions for this chunk, set the hyperslab for them */
1666 if (num_partial_dims > 0)
1667 if (H5S_select_hyperslab(new_chunk_info->fspace, H5S_SELECT_SET, zeros, NULL, curr_partial_clip,
1668 NULL) < 0)
1669 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk selection")
1670
1671 /* Set the memory chunk dataspace */
1672 new_chunk_info->mspace = NULL;
1673 new_chunk_info->mspace_shared = FALSE;
1674
1675 /* Copy the chunk's scaled coordinates */
1676 H5MM_memcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
1677 new_chunk_info->scaled[fm->f_ndims] = 0;
1678
1679 /* Insert the new chunk into the skip list */
1680 if (H5SL_insert(fm->sel_chunks, new_chunk_info, &new_chunk_info->index) < 0) {
1681 H5D__free_chunk_info(new_chunk_info, NULL, NULL);
1682 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list")
1683 } /* end if */
1684
1685 /* Get number of elements selected in chunk */
1686 chunk_points = H5S_GET_SELECT_NPOINTS(new_chunk_info->fspace);
1687 H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, chunk_points, hsize_t);
1688
1689 /* Decrement # of points left in file selection */
1690 sel_points -= chunk_points;
1691
1692 /* Advance to next chunk if we are not done */
1693 if (sel_points > 0) {
1694 int curr_dim; /* Current dimension to increment */
1695
1696 /* Increment chunk index */
1697 chunk_index++;
1698
1699 /* Set current increment dimension */
1700 curr_dim = (int)fm->f_ndims - 1;
1701
1702 /* Increment chunk location in fastest changing dimension */
1703 coords[curr_dim] += fm->chunk_dim[curr_dim];
1704 scaled[curr_dim]++;
1705 end[curr_dim] += fm->chunk_dim[curr_dim];
1706
1707 /* Bring chunk location back into bounds, if necessary */
1708 if (coords[curr_dim] >= file_dims[curr_dim]) {
1709 do {
1710 /* Reset current dimension's location to 0 */
1711 coords[curr_dim] = 0;
1712 scaled[curr_dim] = 0;
1713 end[curr_dim] = fm->chunk_dim[curr_dim] - 1;
1714
1715 /* Check for previous partial chunk in this dimension */
1716 if (is_partial_dim[curr_dim] && end[curr_dim] < file_dims[curr_dim]) {
1717 /* Sanity check */
1718 HDassert(num_partial_dims > 0);
1719
1720 /* Reset partial chunk information for this dimension */
1721 curr_partial_clip[curr_dim] = fm->chunk_dim[curr_dim];
1722 is_partial_dim[curr_dim] = FALSE;
1723 num_partial_dims--;
1724 } /* end if */
1725
1726 /* Decrement current dimension */
1727 curr_dim--;
1728
1729 /* Check for valid current dim */
1730 if (curr_dim >= 0) {
1731 /* Increment chunk location in current dimension */
1732 coords[curr_dim] += fm->chunk_dim[curr_dim];
1733 scaled[curr_dim]++;
1734 end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1;
1735 } /* end if */
1736 } while (curr_dim >= 0 && (coords[curr_dim] >= file_dims[curr_dim]));
1737 } /* end if */
1738
1739 /* Check for valid current dim */
1740 if (curr_dim >= 0) {
1741 /* Check for partial chunk in this dimension */
1742 if (!is_partial_dim[curr_dim] && file_dims[curr_dim] <= end[curr_dim]) {
1743 /* Set partial chunk information for this dimension */
1744 curr_partial_clip[curr_dim] = partial_dim_size[curr_dim];
1745 is_partial_dim[curr_dim] = TRUE;
1746 num_partial_dims++;
1747
1748 /* Sanity check */
1749 HDassert(num_partial_dims <= fm->f_ndims);
1750 } /* end if */
1751 } /* end if */
1752 } /* end if */
1753 } /* end while */
1754
1755 done:
1756 /* Clean up */
1757 if (tmp_fchunk && H5S_close(tmp_fchunk) < 0)
1758 HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't release temporary dataspace")
1759
1760 FUNC_LEAVE_NOAPI(ret_value)
1761 } /* end H5D__create_chunk_file_map_all() */
1762
1763 /*-------------------------------------------------------------------------
1764 * Function: H5D__create_chunk_file_map_hyper
1765 *
1766 * Purpose: Create all chunk selections in file, for a hyperslab selection.
1767 *
1768 * Return: Non-negative on success/Negative on failure
1769 *
1770 * Programmer: Quincey Koziol
1771 * Thursday, May 29, 2003
1772 *
1773 *-------------------------------------------------------------------------
1774 */
1775 static herr_t
H5D__create_chunk_file_map_hyper(H5D_chunk_map_t * fm,const H5D_io_info_t H5_ATTR_UNUSED * io_info)1776 H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t
1777 #ifndef H5_HAVE_PARALLEL
1778 H5_ATTR_UNUSED
1779 #endif /* H5_HAVE_PARALLEL */
1780 *io_info)
1781 {
1782 H5S_t * tmp_fchunk = NULL; /* Temporary file dataspace */
1783 hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */
1784 hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */
1785 hsize_t sel_points; /* Number of elements in file selection */
1786 hsize_t start_coords[H5O_LAYOUT_NDIMS]; /* Starting coordinates of selection */
1787 hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */
1788 hsize_t end[H5O_LAYOUT_NDIMS]; /* Final coordinates of chunk */
1789 hsize_t chunk_index; /* Index of chunk */
1790 hsize_t start_scaled[H5S_MAX_RANK]; /* Starting scaled coordinates of selection */
1791 hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
1792 int curr_dim; /* Current dimension to increment */
1793 unsigned u; /* Local index variable */
1794 herr_t ret_value = SUCCEED; /* Return value */
1795
1796 FUNC_ENTER_STATIC
1797
1798 /* Sanity check */
1799 HDassert(fm->f_ndims > 0);
1800
1801 /* Get number of elements selected in file */
1802 sel_points = fm->nelmts;
1803
1804 /* Get bounding box for selection (to reduce the number of chunks to iterate over) */
1805 if (H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0)
1806 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
1807
1808 /* Set initial chunk location & hyperslab size */
1809 for (u = 0; u < fm->f_ndims; u++) {
1810 /* Validate this chunk dimension */
1811 if (fm->layout->u.chunk.dim[u] == 0)
1812 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u)
1813 scaled[u] = start_scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u];
1814 coords[u] = start_coords[u] = scaled[u] * fm->layout->u.chunk.dim[u];
1815 end[u] = (coords[u] + fm->chunk_dim[u]) - 1;
1816 } /* end for */
1817
1818 /* Calculate the index of this chunk */
1819 chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled);
1820
1821 /* Iterate through each chunk in the dataset */
1822 while (sel_points) {
1823 /* Check for intersection of current chunk and file selection */
1824 /* (Casting away const OK - QAK) */
1825 if (TRUE == H5S_SELECT_INTERSECT_BLOCK(fm->file_space, coords, end)) {
1826 H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */
1827 hsize_t chunk_points; /* Number of elements in chunk selection */
1828
1829 /* Create dataspace for chunk, 'AND'ing the overall selection with
1830 * the current chunk.
1831 */
1832 if (H5S_combine_hyperslab(fm->file_space, H5S_SELECT_AND, coords, NULL, fm->chunk_dim, NULL,
1833 &tmp_fchunk) < 0)
1834 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL,
1835 "unable to combine file space selection with chunk block")
1836
1837 /* Resize chunk's dataspace dimensions to size of chunk */
1838 if (H5S_set_extent_real(tmp_fchunk, fm->chunk_dim) < 0)
1839 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't adjust chunk dimensions")
1840
1841 /* Move selection back to have correct offset in chunk */
1842 if (H5S_SELECT_ADJUST_U(tmp_fchunk, coords) < 0)
1843 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't adjust chunk selection")
1844
1845 /* Add temporary chunk to the list of chunks */
1846
1847 /* Allocate the file & memory chunk information */
1848 if (NULL == (new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t)))
1849 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk info")
1850
1851 /* Initialize the chunk information */
1852
1853 /* Set the chunk index */
1854 new_chunk_info->index = chunk_index;
1855
1856 #ifdef H5_HAVE_PARALLEL
1857 /* Store chunk selection information, for multi-chunk I/O */
1858 if (io_info->using_mpi_vfd)
1859 fm->select_chunk[chunk_index] = new_chunk_info;
1860 #endif /* H5_HAVE_PARALLEL */
1861
1862 /* Set the file chunk dataspace */
1863 new_chunk_info->fspace = tmp_fchunk;
1864 new_chunk_info->fspace_shared = FALSE;
1865 tmp_fchunk = NULL;
1866
1867 /* Set the memory chunk dataspace */
1868 new_chunk_info->mspace = NULL;
1869 new_chunk_info->mspace_shared = FALSE;
1870
1871 /* Copy the chunk's scaled coordinates */
1872 H5MM_memcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
1873 new_chunk_info->scaled[fm->f_ndims] = 0;
1874
1875 /* Insert the new chunk into the skip list */
1876 if (H5SL_insert(fm->sel_chunks, new_chunk_info, &new_chunk_info->index) < 0) {
1877 H5D__free_chunk_info(new_chunk_info, NULL, NULL);
1878 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list")
1879 } /* end if */
1880
1881 /* Get number of elements selected in chunk */
1882 chunk_points = H5S_GET_SELECT_NPOINTS(new_chunk_info->fspace);
1883 H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, chunk_points, hsize_t);
1884
1885 /* Decrement # of points left in file selection */
1886 sel_points -= chunk_points;
1887
1888 /* Leave if we are done */
1889 if (sel_points == 0)
1890 HGOTO_DONE(SUCCEED)
1891 } /* end if */
1892
1893 /* Increment chunk index */
1894 chunk_index++;
1895
1896 /* Set current increment dimension */
1897 curr_dim = (int)fm->f_ndims - 1;
1898
1899 /* Increment chunk location in fastest changing dimension */
1900 coords[curr_dim] += fm->chunk_dim[curr_dim];
1901 end[curr_dim] += fm->chunk_dim[curr_dim];
1902 scaled[curr_dim]++;
1903
1904 /* Bring chunk location back into bounds, if necessary */
1905 if (coords[curr_dim] > sel_end[curr_dim]) {
1906 do {
1907 /* Reset current dimension's location to 0 */
1908 scaled[curr_dim] = start_scaled[curr_dim];
1909 coords[curr_dim] =
1910 start_coords[curr_dim]; /*lint !e771 The start_coords will always be initialized */
1911 end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1;
1912
1913 /* Decrement current dimension */
1914 curr_dim--;
1915
1916 /* Check for valid current dim */
1917 if (curr_dim >= 0) {
1918 /* Increment chunk location in current dimension */
1919 scaled[curr_dim]++;
1920 coords[curr_dim] += fm->chunk_dim[curr_dim];
1921 end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1;
1922 } /* end if */
1923 } while (curr_dim >= 0 && (coords[curr_dim] > sel_end[curr_dim]));
1924
1925 /* Re-calculate the index of this chunk */
1926 chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled);
1927 } /* end if */
1928 } /* end while */
1929
1930 done:
1931 /* Clean up on failure */
1932 if (ret_value < 0)
1933 if (tmp_fchunk && H5S_close(tmp_fchunk) < 0)
1934 HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't release temporary dataspace")
1935
1936 FUNC_LEAVE_NOAPI(ret_value)
1937 } /* end H5D__create_chunk_file_map_hyper() */
1938
1939 /*-------------------------------------------------------------------------
1940 * Function: H5D__create_chunk_mem_map_hyper
1941 *
1942 * Purpose: Create all chunk selections in memory by copying the file
1943 * chunk selections and adjusting their offsets to be correct
1944 * for the memory.
1945 *
1946 * Return: Non-negative on success/Negative on failure
1947 *
1948 * Programmer: Quincey Koziol
1949 * Thursday, May 29, 2003
1950 *
1951 * Assumptions: That the file and memory selections are the same shape.
1952 *
1953 *-------------------------------------------------------------------------
1954 */
1955 static herr_t
H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t * fm)1956 H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm)
1957 {
1958 H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */
1959 H5SL_node_t * curr_node; /* Current node in skip list */
1960 hsize_t file_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */
1961 hsize_t file_sel_end[H5S_MAX_RANK]; /* Offset of high bound of file selection */
1962 hsize_t mem_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */
1963 hsize_t mem_sel_end[H5S_MAX_RANK]; /* Offset of high bound of file selection */
1964 hssize_t adjust[H5S_MAX_RANK]; /* Adjustment to make to all file chunks */
1965 unsigned u; /* Local index variable */
1966 herr_t ret_value = SUCCEED; /* Return value */
1967
1968 FUNC_ENTER_STATIC
1969
1970 /* Sanity check */
1971 HDassert(fm->f_ndims > 0);
1972
1973 /* Check for all I/O going to a single chunk */
1974 if (H5SL_count(fm->sel_chunks) == 1) {
1975 /* Get the node */
1976 curr_node = H5SL_first(fm->sel_chunks);
1977
1978 /* Get pointer to chunk's information */
1979 chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
1980 HDassert(chunk_info);
1981
1982 /* Just point at the memory dataspace & selection */
1983 /* (Casting away const OK -QAK) */
1984 chunk_info->mspace = (H5S_t *)fm->mem_space;
1985
1986 /* Indicate that the chunk's memory space is shared */
1987 chunk_info->mspace_shared = TRUE;
1988 } /* end if */
1989 else {
1990 /* Get bounding box for file selection */
1991 if (H5S_SELECT_BOUNDS(fm->file_space, file_sel_start, file_sel_end) < 0)
1992 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
1993
1994 /* Get bounding box for memory selection */
1995 if (H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0)
1996 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
1997
1998 /* Calculate the adjustment for memory selection from file selection */
1999 HDassert(fm->m_ndims == fm->f_ndims);
2000 for (u = 0; u < fm->f_ndims; u++) {
2001 H5_CHECK_OVERFLOW(file_sel_start[u], hsize_t, hssize_t);
2002 H5_CHECK_OVERFLOW(mem_sel_start[u], hsize_t, hssize_t);
2003 adjust[u] = (hssize_t)file_sel_start[u] - (hssize_t)mem_sel_start[u];
2004 } /* end for */
2005
2006 /* Iterate over each chunk in the chunk list */
2007 curr_node = H5SL_first(fm->sel_chunks);
2008 while (curr_node) {
2009 hsize_t coords[H5S_MAX_RANK]; /* Current coordinates of chunk */
2010 hssize_t chunk_adjust[H5S_MAX_RANK]; /* Adjustment to make to a particular chunk */
2011 H5S_sel_type chunk_sel_type; /* Chunk's selection type */
2012
2013 /* Get pointer to chunk's information */
2014 chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
2015 HDassert(chunk_info);
2016
2017 /* Compute the chunk coordinates from the scaled coordinates */
2018 for (u = 0; u < fm->f_ndims; u++)
2019 coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u];
2020
2021 /* Copy the information */
2022
2023 /* Copy the memory dataspace */
2024 if ((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL)
2025 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space")
2026
2027 /* Get the chunk's selection type */
2028 if ((chunk_sel_type = H5S_GET_SELECT_TYPE(chunk_info->fspace)) < H5S_SEL_NONE)
2029 HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection")
2030
2031 /* Set memory selection for "all" chunk selections */
2032 if (H5S_SEL_ALL == chunk_sel_type) {
2033 /* Adjust the chunk coordinates */
2034 for (u = 0; u < fm->f_ndims; u++)
2035 coords[u] = (hsize_t)((hssize_t)coords[u] - adjust[u]);
2036
2037 /* Set to same shape as chunk */
2038 if (H5S_select_hyperslab(chunk_info->mspace, H5S_SELECT_SET, coords, NULL, fm->chunk_dim,
2039 NULL) < 0)
2040 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk memory selection")
2041 } /* end if */
2042 else {
2043 /* Sanity check */
2044 HDassert(H5S_SEL_HYPERSLABS == chunk_sel_type);
2045
2046 /* Copy the file chunk's selection */
2047 if (H5S_SELECT_COPY(chunk_info->mspace, chunk_info->fspace, FALSE) < 0)
2048 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection")
2049
2050 /* Compute the adjustment for this chunk */
2051 for (u = 0; u < fm->f_ndims; u++) {
2052 /* Compensate for the chunk offset */
2053 H5_CHECK_OVERFLOW(coords[u], hsize_t, hssize_t);
2054 chunk_adjust[u] = adjust[u] - (hssize_t)coords[u];
2055 } /* end for */
2056
2057 /* Adjust the selection */
2058 if (H5S_SELECT_ADJUST_S(chunk_info->mspace, chunk_adjust) < 0)
2059 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to adjust selection")
2060 } /* end else */
2061
2062 /* Get the next chunk node in the skip list */
2063 curr_node = H5SL_next(curr_node);
2064 } /* end while */
2065 } /* end else */
2066
2067 done:
2068 FUNC_LEAVE_NOAPI(ret_value)
2069 } /* end H5D__create_chunk_mem_map_hyper() */
2070
2071 /*-------------------------------------------------------------------------
2072 * Function: H5D__create_mem_map_1d
2073 *
2074 * Purpose: Create all chunk selections for 1-dimensional regular memory space
2075 * that has only one single block in the selection
2076 *
2077 * Return: Non-negative on success/Negative on failure
2078 *
2079 * Programmer: Vailin Choi
2080 * Sept 18, 2019
2081 *
2082 *-------------------------------------------------------------------------
2083 */
2084 static herr_t
H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t * fm)2085 H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t *fm)
2086 {
2087 H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */
2088 H5SL_node_t * curr_node; /* Current node in skip list */
2089 herr_t ret_value = SUCCEED; /* Return value */
2090
2091 FUNC_ENTER_STATIC
2092
2093 /* Sanity check */
2094 HDassert(fm->f_ndims > 0);
2095
2096 /* Check for all I/O going to a single chunk */
2097 if (H5SL_count(fm->sel_chunks) == 1) {
2098 /* Get the node */
2099 curr_node = H5SL_first(fm->sel_chunks);
2100
2101 /* Get pointer to chunk's information */
2102 chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
2103 HDassert(chunk_info);
2104
2105 /* Just point at the memory dataspace & selection */
2106 /* (Casting away const OK -QAK) */
2107 chunk_info->mspace = (H5S_t *)fm->mem_space;
2108
2109 /* Indicate that the chunk's memory space is shared */
2110 chunk_info->mspace_shared = TRUE;
2111 } /* end if */
2112 else {
2113 hsize_t mem_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */
2114 hsize_t mem_sel_end[H5S_MAX_RANK]; /* Offset of high bound of file selection */
2115
2116 HDassert(fm->m_ndims == 1);
2117
2118 if (H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0)
2119 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
2120
2121 /* Iterate over each chunk in the chunk list */
2122 curr_node = H5SL_first(fm->sel_chunks);
2123 while (curr_node) {
2124 hsize_t chunk_points; /* Number of elements in chunk selection */
2125 hsize_t tmp_count = 1;
2126
2127 /* Get pointer to chunk's information */
2128 chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
2129 HDassert(chunk_info);
2130
2131 /* Copy the memory dataspace */
2132 if ((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL)
2133 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space")
2134
2135 chunk_points = H5S_GET_SELECT_NPOINTS(chunk_info->fspace);
2136
2137 if (H5S_select_hyperslab(chunk_info->mspace, H5S_SELECT_SET, mem_sel_start, NULL, &tmp_count,
2138 &chunk_points) < 0)
2139 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk memory selection")
2140
2141 mem_sel_start[0] += chunk_points;
2142
2143 /* Get the next chunk node in the skip list */
2144 curr_node = H5SL_next(curr_node);
2145 } /* end while */
2146 } /* end else */
2147
2148 done:
2149 FUNC_LEAVE_NOAPI(ret_value)
2150 } /* end H5D__create_chunk_mem_map_1d() */
2151
2152 /*-------------------------------------------------------------------------
2153 * Function: H5D__chunk_file_cb
2154 *
2155 * Purpose: Callback routine for file selection iterator. Used when
2156 * creating selections in file for each point selected.
2157 *
2158 * Return: Non-negative on success/Negative on failure
2159 *
2160 * Programmer: Quincey Koziol
2161 * Wednesday, July 23, 2003
2162 *
2163 *-------------------------------------------------------------------------
2164 */
2165 static herr_t
H5D__chunk_file_cb(void H5_ATTR_UNUSED * elem,const H5T_t H5_ATTR_UNUSED * type,unsigned ndims,const hsize_t * coords,void * _udata)2166 H5D__chunk_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims,
2167 const hsize_t *coords, void *_udata)
2168 {
2169 H5D_chunk_file_iter_ud_t *udata = (H5D_chunk_file_iter_ud_t *)_udata; /* User data for operation */
2170 H5D_chunk_map_t * fm = udata->fm; /* File<->memory chunk mapping info */
2171 H5D_chunk_info_t * chunk_info; /* Chunk information for current chunk */
2172 hsize_t coords_in_chunk[H5O_LAYOUT_NDIMS]; /* Coordinates of element in chunk */
2173 hsize_t chunk_index; /* Chunk index */
2174 hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
2175 unsigned u; /* Local index variable */
2176 herr_t ret_value = SUCCEED; /* Return value */
2177
2178 FUNC_ENTER_STATIC
2179
2180 /* Calculate the index of this chunk */
2181 chunk_index = H5VM_chunk_index_scaled(ndims, coords, fm->layout->u.chunk.dim,
2182 fm->layout->u.chunk.down_chunks, scaled);
2183
2184 /* Find correct chunk in file & memory skip list */
2185 if (chunk_index == fm->last_index) {
2186 /* If the chunk index is the same as the last chunk index we used,
2187 * get the cached info to operate on.
2188 */
2189 chunk_info = fm->last_chunk_info;
2190 } /* end if */
2191 else {
2192 /* If the chunk index is not the same as the last chunk index we used,
2193 * find the chunk in the skip list.
2194 */
2195 /* Get the chunk node from the skip list */
2196 if (NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) {
2197 H5S_t *fspace; /* Memory chunk's dataspace */
2198
2199 /* Allocate the file & memory chunk information */
2200 if (NULL == (chunk_info = H5FL_MALLOC(H5D_chunk_info_t)))
2201 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info")
2202
2203 /* Initialize the chunk information */
2204
2205 /* Set the chunk index */
2206 chunk_info->index = chunk_index;
2207
2208 /* Create a dataspace for the chunk */
2209 if ((fspace = H5S_create_simple(fm->f_ndims, fm->chunk_dim, NULL)) == NULL) {
2210 chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info);
2211 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create dataspace for chunk")
2212 } /* end if */
2213
2214 /* De-select the chunk space */
2215 if (H5S_select_none(fspace) < 0) {
2216 (void)H5S_close(fspace);
2217 chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info);
2218 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select dataspace")
2219 } /* end if */
2220
2221 /* Set the file chunk dataspace */
2222 chunk_info->fspace = fspace;
2223 chunk_info->fspace_shared = FALSE;
2224
2225 /* Set the memory chunk dataspace */
2226 chunk_info->mspace = NULL;
2227 chunk_info->mspace_shared = FALSE;
2228
2229 /* Set the number of selected elements in chunk to zero */
2230 chunk_info->chunk_points = 0;
2231
2232 /* Set the chunk's scaled coordinates */
2233 H5MM_memcpy(chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
2234 chunk_info->scaled[fm->f_ndims] = 0;
2235 H5MM_memcpy(chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
2236
2237 /* Insert the new chunk into the skip list */
2238 if (H5SL_insert(fm->sel_chunks, chunk_info, &chunk_info->index) < 0) {
2239 H5D__free_chunk_info(chunk_info, NULL, NULL);
2240 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list")
2241 } /* end if */
2242 } /* end if */
2243
2244 #ifdef H5_HAVE_PARALLEL
2245 /* Store chunk selection information, for collective multi-chunk I/O */
2246 if (udata->io_info->using_mpi_vfd)
2247 fm->select_chunk[chunk_index] = chunk_info;
2248 #endif /* H5_HAVE_PARALLEL */
2249
2250 /* Update the "last chunk seen" information */
2251 fm->last_index = chunk_index;
2252 fm->last_chunk_info = chunk_info;
2253 } /* end else */
2254
2255 /* Get the offset of the element within the chunk */
2256 for (u = 0; u < fm->f_ndims; u++)
2257 coords_in_chunk[u] = coords[u] - (scaled[u] * fm->layout->u.chunk.dim[u]);
2258
2259 /* Add point to file selection for chunk */
2260 if (H5S_select_elements(chunk_info->fspace, H5S_SELECT_APPEND, (size_t)1, coords_in_chunk) < 0)
2261 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element")
2262
2263 /* Increment the number of elemented selected in chunk */
2264 chunk_info->chunk_points++;
2265
2266 done:
2267 FUNC_LEAVE_NOAPI(ret_value)
2268 } /* end H5D__chunk_file_cb() */
2269
2270 /*-------------------------------------------------------------------------
2271 * Function: H5D__chunk_mem_cb
2272 *
2273 * Purpose: Callback routine for file selection iterator. Used when
2274 * creating selections in memory for each chunk.
2275 *
2276 * Return: Non-negative on success/Negative on failure
2277 *
2278 * Programmer: Raymond Lu
2279 * Thursday, April 10, 2003
2280 *
2281 *-------------------------------------------------------------------------
2282 */
2283 static herr_t
H5D__chunk_mem_cb(void H5_ATTR_UNUSED * elem,const H5T_t H5_ATTR_UNUSED * type,unsigned ndims,const hsize_t * coords,void * _fm)2284 H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims,
2285 const hsize_t *coords, void *_fm)
2286 {
2287 H5D_chunk_map_t * fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */
2288 H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */
2289 hsize_t coords_in_mem[H5S_MAX_RANK]; /* Coordinates of element in memory */
2290 hsize_t chunk_index; /* Chunk index */
2291 herr_t ret_value = SUCCEED; /* Return value */
2292
2293 FUNC_ENTER_STATIC
2294
2295 /* Calculate the index of this chunk */
2296 chunk_index = H5VM_chunk_index(ndims, coords, fm->layout->u.chunk.dim, fm->layout->u.chunk.down_chunks);
2297
2298 /* Find correct chunk in file & memory skip list */
2299 if (chunk_index == fm->last_index) {
2300 /* If the chunk index is the same as the last chunk index we used,
2301 * get the cached spaces to operate on.
2302 */
2303 chunk_info = fm->last_chunk_info;
2304 } /* end if */
2305 else {
2306 /* If the chunk index is not the same as the last chunk index we used,
2307 * find the chunk in the skip list.
2308 */
2309 /* Get the chunk node from the skip list */
2310 if (NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index)))
2311 HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, H5_ITER_ERROR, "can't locate chunk in skip list")
2312
2313 /* Check if the chunk already has a memory space */
2314 if (NULL == chunk_info->mspace)
2315 /* Copy the template memory chunk dataspace */
2316 if (NULL == (chunk_info->mspace = H5S_copy(fm->mchunk_tmpl, FALSE, FALSE)))
2317 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy file space")
2318
2319 /* Update the "last chunk seen" information */
2320 fm->last_index = chunk_index;
2321 fm->last_chunk_info = chunk_info;
2322 } /* end else */
2323
2324 /* Get coordinates of selection iterator for memory */
2325 if (H5S_SELECT_ITER_COORDS(&fm->mem_iter, coords_in_mem) < 0)
2326 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, H5_ITER_ERROR, "unable to get iterator coordinates")
2327
2328 /* Add point to memory selection for chunk */
2329 if (fm->msel_type == H5S_SEL_POINTS) {
2330 if (H5S_select_elements(chunk_info->mspace, H5S_SELECT_APPEND, (size_t)1, coords_in_mem) < 0)
2331 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, H5_ITER_ERROR, "unable to select element")
2332 } /* end if */
2333 else {
2334 if (H5S_hyper_add_span_element(chunk_info->mspace, fm->m_ndims, coords_in_mem) < 0)
2335 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, H5_ITER_ERROR, "unable to select element")
2336 } /* end else */
2337
2338 /* Move memory selection iterator to next element in selection */
2339 if (H5S_SELECT_ITER_NEXT(&fm->mem_iter, (size_t)1) < 0)
2340 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, H5_ITER_ERROR, "unable to move to next iterator location")
2341
2342 done:
2343 FUNC_LEAVE_NOAPI(ret_value)
2344 } /* end H5D__chunk_mem_cb() */
2345
2346 /*-------------------------------------------------------------------------
2347 * Function: H5D__chunk_cacheable
2348 *
2349 * Purpose: A small internal function to if it's possible to load the
2350 * chunk into cache.
2351 *
2352 * Return: TRUE or FALSE
2353 *
2354 * Programmer: Raymond Lu
2355 * 17 July 2007
2356 *
2357 *-------------------------------------------------------------------------
2358 */
2359 htri_t
H5D__chunk_cacheable(const H5D_io_info_t * io_info,haddr_t caddr,hbool_t write_op)2360 H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_op)
2361 {
2362 const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */
2363 hbool_t has_filters = FALSE; /* Whether there are filters on the chunk or not */
2364 htri_t ret_value = FAIL; /* Return value */
2365
2366 FUNC_ENTER_PACKAGE
2367
2368 /* Sanity check */
2369 HDassert(io_info);
2370 HDassert(dataset);
2371
2372 /* Must bring the whole chunk in if there are any filters on the chunk.
2373 * Make sure to check if filters are on the dataset but disabled for the
2374 * chunk because it is a partial edge chunk. */
2375 if (dataset->shared->dcpl_cache.pline.nused > 0) {
2376 if (dataset->shared->layout.u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) {
2377 has_filters = !H5D__chunk_is_partial_edge_chunk(
2378 io_info->dset->shared->ndims, io_info->dset->shared->layout.u.chunk.dim,
2379 io_info->store->chunk.scaled, io_info->dset->shared->curr_dims);
2380 } /* end if */
2381 else
2382 has_filters = TRUE;
2383 } /* end if */
2384
2385 if (has_filters)
2386 ret_value = TRUE;
2387 else {
2388 #ifdef H5_HAVE_PARALLEL
2389 /* If MPI based VFD is used and the file is opened for write access, must
2390 * bypass the chunk-cache scheme because other MPI processes could
2391 * be writing to other elements in the same chunk. Do a direct
2392 * write-through of only the elements requested.
2393 */
2394 if (io_info->using_mpi_vfd && (H5F_ACC_RDWR & H5F_INTENT(dataset->oloc.file)))
2395 ret_value = FALSE;
2396 else {
2397 #endif /* H5_HAVE_PARALLEL */
2398 /* If the chunk is too large to keep in the cache and if we don't
2399 * need to write the fill value, then don't load the chunk into the
2400 * cache, just write the data to it directly.
2401 */
2402 H5_CHECK_OVERFLOW(dataset->shared->layout.u.chunk.size, uint32_t, size_t);
2403 if ((size_t)dataset->shared->layout.u.chunk.size > dataset->shared->cache.chunk.nbytes_max) {
2404 if (write_op && !H5F_addr_defined(caddr)) {
2405 const H5O_fill_t *fill = &(dataset->shared->dcpl_cache.fill); /* Fill value info */
2406 H5D_fill_value_t fill_status; /* Fill value status */
2407
2408 /* Revtrieve the fill value status */
2409 if (H5P_is_fill_value_defined(fill, &fill_status) < 0)
2410 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
2411
2412 /* If the fill value needs to be written then we will need
2413 * to use the cache to write the fill value */
2414 if (fill->fill_time == H5D_FILL_TIME_ALLOC ||
2415 (fill->fill_time == H5D_FILL_TIME_IFSET &&
2416 (fill_status == H5D_FILL_VALUE_USER_DEFINED ||
2417 fill_status == H5D_FILL_VALUE_DEFAULT)))
2418 ret_value = TRUE;
2419 else
2420 ret_value = FALSE;
2421 }
2422 else
2423 ret_value = FALSE;
2424 }
2425 else
2426 ret_value = TRUE;
2427 #ifdef H5_HAVE_PARALLEL
2428 } /* end else */
2429 #endif /* H5_HAVE_PARALLEL */
2430 } /* end else */
2431
2432 done:
2433 FUNC_LEAVE_NOAPI(ret_value)
2434 } /* end H5D__chunk_cacheable() */
2435
2436 /*-------------------------------------------------------------------------
2437 * Function: H5D__chunk_read
2438 *
2439 * Purpose: Read from a chunked dataset.
2440 *
2441 * Return: Non-negative on success/Negative on failure
2442 *
2443 * Programmer: Raymond Lu
2444 * Thursday, April 10, 2003
2445 *
2446 *-------------------------------------------------------------------------
2447 */
2448 static herr_t
H5D__chunk_read(H5D_io_info_t * io_info,const H5D_type_info_t * type_info,hsize_t H5_ATTR_UNUSED nelmts,const H5S_t H5_ATTR_UNUSED * file_space,const H5S_t H5_ATTR_UNUSED * mem_space,H5D_chunk_map_t * fm)2449 H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t H5_ATTR_UNUSED nelmts,
2450 const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
2451 H5D_chunk_map_t *fm)
2452 {
2453 H5SL_node_t * chunk_node; /* Current node in chunk skip list */
2454 H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */
2455 H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
2456 H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
2457 H5D_io_info_t cpt_io_info; /* Compact I/O info object */
2458 H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
2459 hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
2460 uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */
2461 hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */
2462 herr_t ret_value = SUCCEED; /*return value */
2463
2464 FUNC_ENTER_STATIC
2465
2466 /* Sanity check */
2467 HDassert(io_info);
2468 HDassert(io_info->u.rbuf);
2469 HDassert(type_info);
2470 HDassert(fm);
2471
2472 /* Set up "nonexistent" I/O info object */
2473 H5MM_memcpy(&nonexistent_io_info, io_info, sizeof(nonexistent_io_info));
2474 nonexistent_io_info.layout_ops = *H5D_LOPS_NONEXISTENT;
2475
2476 /* Set up contiguous I/O info object */
2477 H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info));
2478 ctg_io_info.store = &ctg_store;
2479 ctg_io_info.layout_ops = *H5D_LOPS_CONTIG;
2480
2481 /* Initialize temporary contiguous storage info */
2482 H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size,
2483 uint32_t);
2484
2485 /* Set up compact I/O info object */
2486 H5MM_memcpy(&cpt_io_info, io_info, sizeof(cpt_io_info));
2487 cpt_io_info.store = &cpt_store;
2488 cpt_io_info.layout_ops = *H5D_LOPS_COMPACT;
2489
2490 /* Initialize temporary compact storage info */
2491 cpt_store.compact.dirty = &cpt_dirty;
2492
2493 {
2494 const H5O_fill_t *fill = &(io_info->dset->shared->dcpl_cache.fill); /* Fill value info */
2495 H5D_fill_value_t fill_status; /* Fill value status */
2496
2497 /* Check the fill value status */
2498 if (H5P_is_fill_value_defined(fill, &fill_status) < 0)
2499 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
2500
2501 /* If we are never to return fill values, or if we would return them
2502 * but they aren't set, set the flag to skip missing chunks.
2503 */
2504 if (fill->fill_time == H5D_FILL_TIME_NEVER ||
2505 (fill->fill_time == H5D_FILL_TIME_IFSET && fill_status != H5D_FILL_VALUE_USER_DEFINED &&
2506 fill_status != H5D_FILL_VALUE_DEFAULT))
2507 skip_missing_chunks = TRUE;
2508 }
2509
2510 /* Iterate through nodes in chunk skip list */
2511 chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
2512 while (chunk_node) {
2513 H5D_chunk_info_t *chunk_info; /* Chunk information */
2514 H5D_chunk_ud_t udata; /* Chunk index pass-through */
2515
2516 /* Get the actual chunk information from the skip list node */
2517 chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
2518
2519 /* Get the info for the chunk in the file */
2520 if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
2521 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
2522
2523 /* Sanity check */
2524 HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
2525 (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
2526
2527 /* Check for non-existant chunk & skip it if appropriate */
2528 if (H5F_addr_defined(udata.chunk_block.offset) || UINT_MAX != udata.idx_hint ||
2529 !skip_missing_chunks) {
2530 H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */
2531 void * chunk = NULL; /* Pointer to locked chunk buffer */
2532 htri_t cacheable; /* Whether the chunk is cacheable */
2533
2534 /* Set chunk's [scaled] coordinates */
2535 io_info->store->chunk.scaled = chunk_info->scaled;
2536
2537 /* Determine if we should use the chunk cache */
2538 if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, FALSE)) < 0)
2539 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
2540 if (cacheable) {
2541 /* Load the chunk into cache and lock it. */
2542
2543 /* Compute # of bytes accessed in chunk */
2544 H5_CHECK_OVERFLOW(type_info->src_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
2545 src_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->src_type_size;
2546
2547 /* Lock the chunk into the cache */
2548 if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE)))
2549 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
2550
2551 /* Set up the storage buffer information for this chunk */
2552 cpt_store.compact.buf = chunk;
2553
2554 /* Point I/O info at contiguous I/O info for this chunk */
2555 chk_io_info = &cpt_io_info;
2556 } /* end if */
2557 else if (H5F_addr_defined(udata.chunk_block.offset)) {
2558 /* Set up the storage address information for this chunk */
2559 ctg_store.contig.dset_addr = udata.chunk_block.offset;
2560
2561 /* Point I/O info at temporary I/O info for this chunk */
2562 chk_io_info = &ctg_io_info;
2563 } /* end else if */
2564 else {
2565 /* Point I/O info at "nonexistent" I/O info for this chunk */
2566 chk_io_info = &nonexistent_io_info;
2567 } /* end else */
2568
2569 /* Perform the actual read operation */
2570 if ((io_info->io_ops.single_read)(chk_io_info, type_info, (hsize_t)chunk_info->chunk_points,
2571 chunk_info->fspace, chunk_info->mspace) < 0)
2572 HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed")
2573
2574 /* Release the cache lock on the chunk. */
2575 if (chunk && H5D__chunk_unlock(io_info, &udata, FALSE, chunk, src_accessed_bytes) < 0)
2576 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
2577 } /* end if */
2578
2579 /* Advance to next chunk in list */
2580 chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
2581 } /* end while */
2582
2583 done:
2584 FUNC_LEAVE_NOAPI(ret_value)
2585 } /* H5D__chunk_read() */
2586
2587 /*-------------------------------------------------------------------------
2588 * Function: H5D__chunk_write
2589 *
2590 * Purpose: Writes to a chunked dataset.
2591 *
2592 * Return: Non-negative on success/Negative on failure
2593 *
2594 * Programmer: Raymond Lu
2595 * Thursday, April 10, 2003
2596 *
2597 *-------------------------------------------------------------------------
2598 */
2599 static herr_t
H5D__chunk_write(H5D_io_info_t * io_info,const H5D_type_info_t * type_info,hsize_t H5_ATTR_UNUSED nelmts,const H5S_t H5_ATTR_UNUSED * file_space,const H5S_t H5_ATTR_UNUSED * mem_space,H5D_chunk_map_t * fm)2600 H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t H5_ATTR_UNUSED nelmts,
2601 const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
2602 H5D_chunk_map_t *fm)
2603 {
2604 H5SL_node_t * chunk_node; /* Current node in chunk skip list */
2605 H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
2606 H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
2607 H5D_io_info_t cpt_io_info; /* Compact I/O info object */
2608 H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
2609 hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
2610 uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */
2611 herr_t ret_value = SUCCEED; /* Return value */
2612
2613 FUNC_ENTER_STATIC
2614
2615 /* Sanity check */
2616 HDassert(io_info);
2617 HDassert(io_info->u.wbuf);
2618 HDassert(type_info);
2619 HDassert(fm);
2620
2621 /* Set up contiguous I/O info object */
2622 H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info));
2623 ctg_io_info.store = &ctg_store;
2624 ctg_io_info.layout_ops = *H5D_LOPS_CONTIG;
2625
2626 /* Initialize temporary contiguous storage info */
2627 H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size,
2628 uint32_t);
2629
2630 /* Set up compact I/O info object */
2631 H5MM_memcpy(&cpt_io_info, io_info, sizeof(cpt_io_info));
2632 cpt_io_info.store = &cpt_store;
2633 cpt_io_info.layout_ops = *H5D_LOPS_COMPACT;
2634
2635 /* Initialize temporary compact storage info */
2636 cpt_store.compact.dirty = &cpt_dirty;
2637
2638 /* Iterate through nodes in chunk skip list */
2639 chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
2640 while (chunk_node) {
2641 H5D_chunk_info_t * chunk_info; /* Chunk information */
2642 H5D_chk_idx_info_t idx_info; /* Chunked index info */
2643 H5D_io_info_t * chk_io_info; /* Pointer to I/O info object for this chunk */
2644 void * chunk; /* Pointer to locked chunk buffer */
2645 H5D_chunk_ud_t udata; /* Index pass-through */
2646 htri_t cacheable; /* Whether the chunk is cacheable */
2647 hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
2648
2649 /* Get the actual chunk information from the skip list node */
2650 chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
2651
2652 /* Look up the chunk */
2653 if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
2654 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
2655
2656 /* Sanity check */
2657 HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
2658 (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
2659
2660 /* Set chunk's [scaled] coordinates */
2661 io_info->store->chunk.scaled = chunk_info->scaled;
2662
2663 /* Determine if we should use the chunk cache */
2664 if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0)
2665 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
2666 if (cacheable) {
2667 /* Load the chunk into cache. But if the whole chunk is written,
2668 * simply allocate space instead of load the chunk. */
2669 hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */
2670
2671 /* Compute # of bytes accessed in chunk */
2672 H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
2673 dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size;
2674
2675 /* Determine if we will access all the data in the chunk */
2676 if (dst_accessed_bytes != ctg_store.contig.dset_size ||
2677 (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size ||
2678 fm->fsel_type == H5S_SEL_POINTS)
2679 entire_chunk = FALSE;
2680
2681 /* Lock the chunk into the cache */
2682 if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE)))
2683 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
2684
2685 /* Set up the storage buffer information for this chunk */
2686 cpt_store.compact.buf = chunk;
2687
2688 /* Point I/O info at main I/O info for this chunk */
2689 chk_io_info = &cpt_io_info;
2690 } /* end if */
2691 else {
2692 /* If the chunk hasn't been allocated on disk, do so now. */
2693 if (!H5F_addr_defined(udata.chunk_block.offset)) {
2694 /* Compose chunked index info struct */
2695 idx_info.f = io_info->dset->oloc.file;
2696 idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline);
2697 idx_info.layout = &(io_info->dset->shared->layout.u.chunk);
2698 idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk);
2699
2700 /* Set up the size of chunk for user data */
2701 udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size;
2702
2703 /* Allocate the chunk */
2704 if (H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert,
2705 chunk_info->scaled) < 0)
2706 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL,
2707 "unable to insert/resize chunk on chunk level")
2708
2709 /* Make sure the address of the chunk is returned. */
2710 if (!H5F_addr_defined(udata.chunk_block.offset))
2711 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined")
2712
2713 /* Cache the new chunk information */
2714 H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata);
2715 } /* end if */
2716
2717 /* Set up the storage address information for this chunk */
2718 ctg_store.contig.dset_addr = udata.chunk_block.offset;
2719
2720 /* No chunk cached */
2721 chunk = NULL;
2722
2723 /* Point I/O info at temporary I/O info for this chunk */
2724 chk_io_info = &ctg_io_info;
2725 } /* end else */
2726
2727 /* Perform the actual write operation */
2728 if ((io_info->io_ops.single_write)(chk_io_info, type_info, (hsize_t)chunk_info->chunk_points,
2729 chunk_info->fspace, chunk_info->mspace) < 0)
2730 HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed")
2731
2732 /* Release the cache lock on the chunk, or insert chunk into index. */
2733 if (chunk) {
2734 if (H5D__chunk_unlock(io_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0)
2735 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
2736 } /* end if */
2737 else {
2738 if (need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert)
2739 if ((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) < 0)
2740 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
2741 } /* end else */
2742
2743 /* Advance to next chunk in list */
2744 chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
2745 } /* end while */
2746
2747 done:
2748 FUNC_LEAVE_NOAPI(ret_value)
2749 } /* H5D__chunk_write() */
2750
2751 /*-------------------------------------------------------------------------
2752 * Function: H5D__chunk_flush
2753 *
2754 * Purpose: Writes all dirty chunks to disk and optionally preempts them
2755 * from the cache.
2756 *
2757 * Return: Non-negative on success/Negative on failure
2758 *
2759 * Programmer: Robb Matzke
2760 * Thursday, May 21, 1998
2761 *
2762 *-------------------------------------------------------------------------
2763 */
2764 static herr_t
H5D__chunk_flush(H5D_t * dset)2765 H5D__chunk_flush(H5D_t *dset)
2766 {
2767 H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk);
2768 H5D_rdcc_ent_t *ent, *next;
2769 unsigned nerrors = 0; /* Count of any errors encountered when flushing chunks */
2770 herr_t ret_value = SUCCEED; /* Return value */
2771
2772 FUNC_ENTER_STATIC
2773
2774 /* Sanity check */
2775 HDassert(dset);
2776
2777 /* Loop over all entries in the chunk cache */
2778 for (ent = rdcc->head; ent; ent = next) {
2779 next = ent->next;
2780 if (H5D__chunk_flush_entry(dset, ent, FALSE) < 0)
2781 nerrors++;
2782 } /* end for */
2783 if (nerrors)
2784 HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks")
2785
2786 done:
2787 FUNC_LEAVE_NOAPI(ret_value)
2788 } /* end H5D__chunk_flush() */
2789
2790 /*-------------------------------------------------------------------------
2791 * Function: H5D__chunk_io_term
2792 *
2793 * Purpose: Destroy I/O operation information.
2794 *
2795 * Return: Non-negative on success/Negative on failure
2796 *
2797 * Programmer: Quincey Koziol
2798 * Saturday, May 17, 2003
2799 *
2800 *-------------------------------------------------------------------------
2801 */
2802 static herr_t
H5D__chunk_io_term(const H5D_chunk_map_t * fm)2803 H5D__chunk_io_term(const H5D_chunk_map_t *fm)
2804 {
2805 herr_t ret_value = SUCCEED; /*return value */
2806
2807 FUNC_ENTER_STATIC
2808
2809 /* Single element I/O vs. multiple element I/O cleanup */
2810 if (fm->use_single) {
2811 /* Sanity checks */
2812 HDassert(fm->sel_chunks == NULL);
2813 HDassert(fm->single_chunk_info);
2814 HDassert(fm->single_chunk_info->fspace_shared);
2815 HDassert(fm->single_chunk_info->mspace_shared);
2816
2817 /* Reset the selection for the single element I/O */
2818 H5S_select_all(fm->single_space, TRUE);
2819 } /* end if */
2820 else {
2821 /* Release the nodes on the list of selected chunks */
2822 if (fm->sel_chunks)
2823 if (H5SL_free(fm->sel_chunks, H5D__free_chunk_info, NULL) < 0)
2824 HGOTO_ERROR(H5E_PLIST, H5E_CANTNEXT, FAIL, "can't iterate over chunks")
2825 } /* end else */
2826
2827 /* Free the memory chunk dataspace template */
2828 if (fm->mchunk_tmpl)
2829 if (H5S_close(fm->mchunk_tmpl) < 0)
2830 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template")
2831 #ifdef H5_HAVE_PARALLEL
2832 if (fm->select_chunk)
2833 H5MM_xfree(fm->select_chunk);
2834 #endif /* H5_HAVE_PARALLEL */
2835
2836 done:
2837 FUNC_LEAVE_NOAPI(ret_value)
2838 } /* end H5D__chunk_io_term() */
2839
2840 /*-------------------------------------------------------------------------
2841 * Function: H5D__chunk_dest
2842 *
2843 * Purpose: Destroy the entire chunk cache by flushing dirty entries,
2844 * preempting all entries, and freeing the cache itself.
2845 *
2846 * Return: Non-negative on success/Negative on failure
2847 *
2848 * Programmer: Robb Matzke
2849 * Thursday, May 21, 1998
2850 *
2851 *-------------------------------------------------------------------------
2852 */
2853 static herr_t
H5D__chunk_dest(H5D_t * dset)2854 H5D__chunk_dest(H5D_t *dset)
2855 {
2856 H5D_chk_idx_info_t idx_info; /* Chunked index info */
2857 H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /* Dataset's chunk cache */
2858 H5D_rdcc_ent_t * ent = NULL, *next = NULL; /* Pointer to current & next cache entries */
2859 int nerrors = 0; /* Accumulated count of errors */
2860 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
2861 herr_t ret_value = SUCCEED; /* Return value */
2862
2863 FUNC_ENTER_STATIC_TAG(dset->oloc.addr)
2864
2865 /* Sanity checks */
2866 HDassert(dset);
2867 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
2868
2869 /* Flush all the cached chunks */
2870 for (ent = rdcc->head; ent; ent = next) {
2871 next = ent->next;
2872 if (H5D__chunk_cache_evict(dset, ent, TRUE) < 0)
2873 nerrors++;
2874 } /* end for */
2875
2876 /* Continue even if there are failures. */
2877 if (nerrors)
2878 HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks")
2879
2880 /* Release cache structures */
2881 if (rdcc->slot)
2882 rdcc->slot = H5FL_SEQ_FREE(H5D_rdcc_ent_ptr_t, rdcc->slot);
2883 HDmemset(rdcc, 0, sizeof(H5D_rdcc_t));
2884
2885 /* Compose chunked index info struct */
2886 idx_info.f = dset->oloc.file;
2887 idx_info.pline = &dset->shared->dcpl_cache.pline;
2888 idx_info.layout = &dset->shared->layout.u.chunk;
2889 idx_info.storage = sc;
2890
2891 /* Free any index structures */
2892 if (sc->ops->dest && (sc->ops->dest)(&idx_info) < 0)
2893 HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to release chunk index info")
2894
2895 done:
2896 FUNC_LEAVE_NOAPI_TAG(ret_value)
2897 } /* end H5D__chunk_dest() */
2898
2899 /*-------------------------------------------------------------------------
2900 * Function: H5D_chunk_idx_reset
2901 *
2902 * Purpose: Reset index information
2903 *
2904 * Return: Non-negative on success/Negative on failure
2905 *
2906 * Programmer: Quincey Koziol
2907 * Thursday, January 15, 2009
2908 *
2909 *-------------------------------------------------------------------------
2910 */
2911 herr_t
H5D_chunk_idx_reset(H5O_storage_chunk_t * storage,hbool_t reset_addr)2912 H5D_chunk_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
2913 {
2914 herr_t ret_value = SUCCEED; /* Return value */
2915
2916 FUNC_ENTER_NOAPI(FAIL)
2917
2918 /* Sanity checks */
2919 HDassert(storage);
2920 HDassert(storage->ops);
2921 H5D_CHUNK_STORAGE_INDEX_CHK(storage);
2922
2923 /* Reset index structures */
2924 if ((storage->ops->reset)(storage, reset_addr) < 0)
2925 HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset chunk index info")
2926
2927 done:
2928 FUNC_LEAVE_NOAPI(ret_value)
2929 } /* end H5D_chunk_idx_reset() */
2930
2931 /*-------------------------------------------------------------------------
2932 * Function: H5D__chunk_cinfo_cache_reset
2933 *
2934 * Purpose: Reset the cached chunk info
2935 *
2936 * Return: Non-negative on success/Negative on failure
2937 *
2938 * Programmer: Quincey Koziol
2939 * November 27, 2007
2940 *
2941 *-------------------------------------------------------------------------
2942 */
2943 static herr_t
H5D__chunk_cinfo_cache_reset(H5D_chunk_cached_t * last)2944 H5D__chunk_cinfo_cache_reset(H5D_chunk_cached_t *last)
2945 {
2946 FUNC_ENTER_STATIC_NOERR
2947
2948 /* Sanity check */
2949 HDassert(last);
2950
2951 /* Indicate that the cached info is not valid */
2952 last->valid = FALSE;
2953
2954 FUNC_LEAVE_NOAPI(SUCCEED)
2955 } /* H5D__chunk_cinfo_cache_reset() */
2956
2957 /*-------------------------------------------------------------------------
2958 * Function: H5D__chunk_cinfo_cache_update
2959 *
2960 * Purpose: Update the cached chunk info
2961 *
2962 * Return: Non-negative on success/Negative on failure
2963 *
2964 * Programmer: Quincey Koziol
2965 * November 27, 2007
2966 *
2967 *-------------------------------------------------------------------------
2968 */
2969 static herr_t
H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t * last,const H5D_chunk_ud_t * udata)2970 H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t *last, const H5D_chunk_ud_t *udata)
2971 {
2972 FUNC_ENTER_STATIC_NOERR
2973
2974 /* Sanity check */
2975 HDassert(last);
2976 HDassert(udata);
2977 HDassert(udata->common.layout);
2978 HDassert(udata->common.scaled);
2979
2980 /* Stored the information to cache */
2981 H5MM_memcpy(last->scaled, udata->common.scaled, sizeof(hsize_t) * udata->common.layout->ndims);
2982 last->addr = udata->chunk_block.offset;
2983 H5_CHECKED_ASSIGN(last->nbytes, uint32_t, udata->chunk_block.length, hsize_t);
2984 last->chunk_idx = udata->chunk_idx;
2985 last->filter_mask = udata->filter_mask;
2986
2987 /* Indicate that the cached info is valid */
2988 last->valid = TRUE;
2989
2990 FUNC_LEAVE_NOAPI(SUCCEED)
2991 } /* H5D__chunk_cinfo_cache_update() */
2992
2993 /*-------------------------------------------------------------------------
2994 * Function: H5D__chunk_cinfo_cache_found
2995 *
2996 * Purpose: Look for chunk info in cache
2997 *
2998 * Return: TRUE/FALSE/FAIL
2999 *
3000 * Programmer: Quincey Koziol
3001 * November 27, 2007
3002 *
3003 *-------------------------------------------------------------------------
3004 */
3005 static hbool_t
H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t * last,H5D_chunk_ud_t * udata)3006 H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last, H5D_chunk_ud_t *udata)
3007 {
3008 hbool_t ret_value = FALSE; /* Return value */
3009
3010 FUNC_ENTER_STATIC_NOERR
3011
3012 /* Sanity check */
3013 HDassert(last);
3014 HDassert(udata);
3015 HDassert(udata->common.layout);
3016 HDassert(udata->common.scaled);
3017
3018 /* Check if the cached information is what is desired */
3019 if (last->valid) {
3020 unsigned u; /* Local index variable */
3021
3022 /* Check that the scaled offset is the same */
3023 for (u = 0; u < udata->common.layout->ndims; u++)
3024 if (last->scaled[u] != udata->common.scaled[u])
3025 HGOTO_DONE(FALSE)
3026
3027 /* Retrieve the information from the cache */
3028 udata->chunk_block.offset = last->addr;
3029 udata->chunk_block.length = last->nbytes;
3030 udata->chunk_idx = last->chunk_idx;
3031 udata->filter_mask = last->filter_mask;
3032
3033 /* Indicate that the data was found */
3034 HGOTO_DONE(TRUE)
3035 } /* end if */
3036
3037 done:
3038 FUNC_LEAVE_NOAPI(ret_value)
3039 } /* H5D__chunk_cinfo_cache_found() */
3040
3041 /*-------------------------------------------------------------------------
3042 * Function: H5D__chunk_create
3043 *
3044 * Purpose: Creates a new chunked storage index and initializes the
3045 * layout information with information about the storage. The
3046 * layout info should be immediately written to the object header.
3047 *
3048 * Return: Non-negative on success (with the layout information initialized
3049 * and ready to write to an object header). Negative on failure.
3050 *
3051 * Programmer: Quincey Koziol
3052 * Thursday, May 22, 2008
3053 *
3054 *-------------------------------------------------------------------------
3055 */
3056 herr_t
H5D__chunk_create(const H5D_t * dset)3057 H5D__chunk_create(const H5D_t *dset /*in,out*/)
3058 {
3059 H5D_chk_idx_info_t idx_info; /* Chunked index info */
3060 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
3061 herr_t ret_value = SUCCEED; /* Return value */
3062
3063 FUNC_ENTER_PACKAGE
3064
3065 /* Check args */
3066 HDassert(dset);
3067 HDassert(H5D_CHUNKED == dset->shared->layout.type);
3068 HDassert(dset->shared->layout.u.chunk.ndims > 0 &&
3069 dset->shared->layout.u.chunk.ndims <= H5O_LAYOUT_NDIMS);
3070 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
3071
3072 #ifndef NDEBUG
3073 {
3074 unsigned u; /* Local index variable */
3075
3076 for (u = 0; u < dset->shared->layout.u.chunk.ndims; u++)
3077 HDassert(dset->shared->layout.u.chunk.dim[u] > 0);
3078 }
3079 #endif
3080
3081 /* Compose chunked index info struct */
3082 idx_info.f = dset->oloc.file;
3083 idx_info.pline = &dset->shared->dcpl_cache.pline;
3084 idx_info.layout = &dset->shared->layout.u.chunk;
3085 idx_info.storage = sc;
3086
3087 /* Create the index for the chunks */
3088 if ((sc->ops->create)(&idx_info) < 0)
3089 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create chunk index")
3090
3091 done:
3092 FUNC_LEAVE_NOAPI(ret_value)
3093 } /* end H5D__chunk_create() */
3094
3095 /*-------------------------------------------------------------------------
3096 * Function: H5D__chunk_hash_val
3097 *
3098 * Purpose: To calculate an index based on the dataset's scaled
3099 * coordinates and sizes of the faster dimensions.
3100 *
3101 * Return: Hash value index
3102 *
3103 * Programmer: Vailin Choi; Nov 2014
3104 *
3105 *-------------------------------------------------------------------------
3106 */
3107 static unsigned
H5D__chunk_hash_val(const H5D_shared_t * shared,const hsize_t * scaled)3108 H5D__chunk_hash_val(const H5D_shared_t *shared, const hsize_t *scaled)
3109 {
3110 hsize_t val; /* Intermediate value */
3111 unsigned ndims = shared->ndims; /* Rank of dataset */
3112 unsigned ret = 0; /* Value to return */
3113 unsigned u; /* Local index variable */
3114
3115 FUNC_ENTER_STATIC_NOERR
3116
3117 /* Sanity check */
3118 HDassert(shared);
3119 HDassert(scaled);
3120
3121 /* If the fastest changing dimension doesn't have enough entropy, use
3122 * other dimensions too
3123 */
3124 val = scaled[0];
3125 for (u = 1; u < ndims; u++) {
3126 val <<= shared->cache.chunk.scaled_encode_bits[u];
3127 val ^= scaled[u];
3128 } /* end for */
3129
3130 /* Modulo value against the number of array slots */
3131 ret = (unsigned)(val % shared->cache.chunk.nslots);
3132
3133 FUNC_LEAVE_NOAPI(ret)
3134 } /* H5D__chunk_hash_val() */
3135
3136 /*-------------------------------------------------------------------------
3137 * Function: H5D__chunk_lookup
3138 *
3139 * Purpose: Loops up a chunk in cache and on disk, and retrieves
3140 * information about that chunk.
3141 *
3142 * Return: Non-negative on success/Negative on failure
3143 *
3144 * Programmer: Albert Cheng
3145 * June 27, 1998
3146 *
3147 *-------------------------------------------------------------------------
3148 */
3149 herr_t
H5D__chunk_lookup(const H5D_t * dset,const hsize_t * scaled,H5D_chunk_ud_t * udata)3150 H5D__chunk_lookup(const H5D_t *dset, const hsize_t *scaled, H5D_chunk_ud_t *udata)
3151 {
3152 H5D_rdcc_ent_t * ent = NULL; /* Cache entry */
3153 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
3154 unsigned idx = 0; /* Index of chunk in cache, if present */
3155 hbool_t found = FALSE; /* In cache? */
3156 herr_t ret_value = SUCCEED; /* Return value */
3157
3158 FUNC_ENTER_PACKAGE
3159
3160 /* Sanity checks */
3161 HDassert(dset);
3162 HDassert(dset->shared->layout.u.chunk.ndims > 0);
3163 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
3164 HDassert(scaled);
3165 HDassert(udata);
3166
3167 /* Initialize the query information about the chunk we are looking for */
3168 udata->common.layout = &(dset->shared->layout.u.chunk);
3169 udata->common.storage = sc;
3170 udata->common.scaled = scaled;
3171
3172 /* Reset information about the chunk we are looking for */
3173 udata->chunk_block.offset = HADDR_UNDEF;
3174 udata->chunk_block.length = 0;
3175 udata->filter_mask = 0;
3176 udata->new_unfilt_chunk = FALSE;
3177
3178 /* Check for chunk in cache */
3179 if (dset->shared->cache.chunk.nslots > 0) {
3180 /* Determine the chunk's location in the hash table */
3181 idx = H5D__chunk_hash_val(dset->shared, scaled);
3182
3183 /* Get the chunk cache entry for that location */
3184 ent = dset->shared->cache.chunk.slot[idx];
3185 if (ent) {
3186 unsigned u; /* Counter */
3187
3188 /* Speculatively set the 'found' flag */
3189 found = TRUE;
3190
3191 /* Verify that the cache entry is the correct chunk */
3192 for (u = 0; u < dset->shared->ndims; u++)
3193 if (scaled[u] != ent->scaled[u]) {
3194 found = FALSE;
3195 break;
3196 } /* end if */
3197 } /* end if */
3198 } /* end if */
3199
3200 /* Retrieve chunk addr */
3201 if (found) {
3202 udata->idx_hint = idx;
3203 udata->chunk_block.offset = ent->chunk_block.offset;
3204 udata->chunk_block.length = ent->chunk_block.length;
3205 ;
3206 udata->chunk_idx = ent->chunk_idx;
3207 } /* end if */
3208 else {
3209 /* Invalidate idx_hint, to signal that the chunk is not in cache */
3210 udata->idx_hint = UINT_MAX;
3211
3212 /* Check for cached information */
3213 if (!H5D__chunk_cinfo_cache_found(&dset->shared->cache.chunk.last, udata)) {
3214 H5D_chk_idx_info_t idx_info; /* Chunked index info */
3215
3216 /* Compose chunked index info struct */
3217 idx_info.f = dset->oloc.file;
3218 idx_info.pline = &dset->shared->dcpl_cache.pline;
3219 idx_info.layout = &dset->shared->layout.u.chunk;
3220 idx_info.storage = sc;
3221
3222 #ifdef H5_HAVE_PARALLEL
3223 /* Disable collective metadata read for chunk indexes as it is
3224 * highly unlikely that users would read the same chunks from all
3225 * processes.
3226 */
3227 if (H5F_HAS_FEATURE(idx_info.f, H5FD_FEAT_HAS_MPI))
3228 H5CX_set_coll_metadata_read(FALSE);
3229 #endif /* H5_HAVE_PARALLEL */
3230
3231 /* Go get the chunk information */
3232 if ((sc->ops->get_addr)(&idx_info, udata) < 0)
3233 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query chunk address")
3234
3235 /*
3236 * Cache the information retrieved.
3237 *
3238 * Note that if we are writing to the dataset in parallel and filters
3239 * are involved, we skip caching this information as it is highly likely
3240 * that the chunk information will be invalidated as a result of the
3241 * filter operation (e.g. the chunk gets re-allocated to a different
3242 * address in the file and/or gets re-allocated with a different size).
3243 * If we were to cache this information, subsequent reads/writes would
3244 * retrieve the invalid information and cause a variety of issues.
3245 *
3246 * It has been verified that in the serial library, when writing to chunks
3247 * with the real chunk cache disabled and with filters involved, the
3248 * functions within this file are correctly called in such a manner that
3249 * this single chunk cache is always updated correctly. Therefore, this
3250 * check is not needed for the serial library.
3251 *
3252 * This is an ugly and potentially frail check, but the
3253 * H5D__chunk_cinfo_cache_reset() function is not currently available
3254 * to functions outside of this file, so outside functions can not
3255 * invalidate this single chunk cache. Even if the function were available,
3256 * this check prevents us from doing the work of going through and caching
3257 * each chunk in the write operation, when we're only going to invalidate
3258 * the cache at the end of a parallel write anyway.
3259 *
3260 * - JTH (7/13/2018)
3261 */
3262 #ifdef H5_HAVE_PARALLEL
3263 if (!((H5F_HAS_FEATURE(idx_info.f, H5FD_FEAT_HAS_MPI)) &&
3264 (H5F_INTENT(dset->oloc.file) & H5F_ACC_RDWR) && dset->shared->dcpl_cache.pline.nused))
3265 #endif
3266 H5D__chunk_cinfo_cache_update(&dset->shared->cache.chunk.last, udata);
3267 } /* end if */
3268 } /* end else */
3269
3270 done:
3271 FUNC_LEAVE_NOAPI(ret_value)
3272 } /* H5D__chunk_lookup() */
3273
3274 /*-------------------------------------------------------------------------
3275 * Function: H5D__chunk_flush_entry
3276 *
3277 * Purpose: Writes a chunk to disk. If RESET is non-zero then the
3278 * entry is cleared -- it's slightly faster to flush a chunk if
3279 * the RESET flag is turned on because it results in one fewer
3280 * memory copy.
3281 *
3282 * Return: Non-negative on success/Negative on failure
3283 *
3284 * Programmer: Robb Matzke
3285 * Thursday, May 21, 1998
3286 *
3287 *-------------------------------------------------------------------------
3288 */
3289 static herr_t
H5D__chunk_flush_entry(const H5D_t * dset,H5D_rdcc_ent_t * ent,hbool_t reset)3290 H5D__chunk_flush_entry(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t reset)
3291 {
3292 void * buf = NULL; /* Temporary buffer */
3293 hbool_t point_of_no_return = FALSE;
3294 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
3295 herr_t ret_value = SUCCEED; /* Return value */
3296
3297 FUNC_ENTER_STATIC
3298
3299 HDassert(dset);
3300 HDassert(dset->shared);
3301 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
3302 HDassert(ent);
3303 HDassert(!ent->locked);
3304
3305 buf = ent->chunk;
3306 if (ent->dirty) {
3307 H5D_chk_idx_info_t idx_info; /* Chunked index info */
3308 H5D_chunk_ud_t udata; /* pass through B-tree */
3309 hbool_t must_alloc = FALSE; /* Whether the chunk must be allocated */
3310 hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
3311
3312 /* Set up user data for index callbacks */
3313 udata.common.layout = &dset->shared->layout.u.chunk;
3314 udata.common.storage = sc;
3315 udata.common.scaled = ent->scaled;
3316 udata.chunk_block.offset = ent->chunk_block.offset;
3317 udata.chunk_block.length = dset->shared->layout.u.chunk.size;
3318 udata.filter_mask = 0;
3319 udata.chunk_idx = ent->chunk_idx;
3320
3321 /* Should the chunk be filtered before writing it to disk? */
3322 if (dset->shared->dcpl_cache.pline.nused && !(ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS)) {
3323 H5Z_EDC_t err_detect; /* Error detection info */
3324 H5Z_cb_t filter_cb; /* I/O filter callback function */
3325 size_t alloc = udata.chunk_block.length; /* Bytes allocated for BUF */
3326 size_t nbytes; /* Chunk size (in bytes) */
3327
3328 /* Retrieve filter settings from API context */
3329 if (H5CX_get_err_detect(&err_detect) < 0)
3330 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get error detection info")
3331 if (H5CX_get_filter_cb(&filter_cb) < 0)
3332 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get I/O filter callback function")
3333
3334 if (!reset) {
3335 /*
3336 * Copy the chunk to a new buffer before running it through
3337 * the pipeline because we'll want to save the original buffer
3338 * for later.
3339 */
3340 if (NULL == (buf = H5MM_malloc(alloc)))
3341 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline")
3342 H5MM_memcpy(buf, ent->chunk, alloc);
3343 } /* end if */
3344 else {
3345 /*
3346 * If we are resetting and something goes wrong after this
3347 * point then it's too late to recover because we may have
3348 * destroyed the original data by calling H5Z_pipeline().
3349 * The only safe option is to continue with the reset
3350 * even if we can't write the data to disk.
3351 */
3352 point_of_no_return = TRUE;
3353 ent->chunk = NULL;
3354 } /* end else */
3355 H5_CHECKED_ASSIGN(nbytes, size_t, udata.chunk_block.length, hsize_t);
3356 if (H5Z_pipeline(&(dset->shared->dcpl_cache.pline), 0, &(udata.filter_mask), err_detect,
3357 filter_cb, &nbytes, &alloc, &buf) < 0)
3358 HGOTO_ERROR(H5E_DATASET, H5E_CANTFILTER, FAIL, "output pipeline failed")
3359 #if H5_SIZEOF_SIZE_T > 4
3360 /* Check for the chunk expanding too much to encode in a 32-bit value */
3361 if (nbytes > ((size_t)0xffffffff))
3362 HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk too large for 32-bit length")
3363 #endif /* H5_SIZEOF_SIZE_T > 4 */
3364 H5_CHECKED_ASSIGN(udata.chunk_block.length, hsize_t, nbytes, size_t);
3365
3366 /* Indicate that the chunk must be allocated */
3367 must_alloc = TRUE;
3368 } /* end if */
3369 else if (!H5F_addr_defined(udata.chunk_block.offset)) {
3370 /* Indicate that the chunk must be allocated */
3371 must_alloc = TRUE;
3372
3373 /* This flag could be set for this chunk, just remove and ignore it
3374 */
3375 ent->edge_chunk_state &= ~H5D_RDCC_NEWLY_DISABLED_FILTERS;
3376 } /* end else */
3377 else if (ent->edge_chunk_state & H5D_RDCC_NEWLY_DISABLED_FILTERS) {
3378 /* Chunk on disk is still filtered, must insert to allocate correct
3379 * size */
3380 must_alloc = TRUE;
3381
3382 /* Set the disable filters field back to the standard disable
3383 * filters setting, as it no longer needs to be inserted with every
3384 * flush */
3385 ent->edge_chunk_state &= ~H5D_RDCC_NEWLY_DISABLED_FILTERS;
3386 } /* end else */
3387
3388 HDassert(!(ent->edge_chunk_state & H5D_RDCC_NEWLY_DISABLED_FILTERS));
3389
3390 /* Check if the chunk needs to be allocated (it also could exist already
3391 * and the chunk alloc operation could resize it)
3392 */
3393 if (must_alloc) {
3394 /* Compose chunked index info struct */
3395 idx_info.f = dset->oloc.file;
3396 idx_info.pline = &dset->shared->dcpl_cache.pline;
3397 idx_info.layout = &dset->shared->layout.u.chunk;
3398 idx_info.storage = sc;
3399
3400 /* Create the chunk it if it doesn't exist, or reallocate the chunk
3401 * if its size changed.
3402 */
3403 if (H5D__chunk_file_alloc(&idx_info, &(ent->chunk_block), &udata.chunk_block, &need_insert,
3404 ent->scaled) < 0)
3405 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert/resize chunk on chunk level")
3406
3407 /* Update the chunk entry's info, in case it was allocated or relocated */
3408 ent->chunk_block.offset = udata.chunk_block.offset;
3409 ent->chunk_block.length = udata.chunk_block.length;
3410 } /* end if */
3411
3412 /* Write the data to the file */
3413 HDassert(H5F_addr_defined(udata.chunk_block.offset));
3414 H5_CHECK_OVERFLOW(udata.chunk_block.length, hsize_t, size_t);
3415 if (H5F_shared_block_write(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW, udata.chunk_block.offset,
3416 (size_t)udata.chunk_block.length, buf) < 0)
3417 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
3418
3419 /* Insert the chunk record into the index */
3420 if (need_insert && sc->ops->insert)
3421 if ((sc->ops->insert)(&idx_info, &udata, dset) < 0)
3422 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
3423
3424 /* Cache the chunk's info, in case it's accessed again shortly */
3425 H5D__chunk_cinfo_cache_update(&dset->shared->cache.chunk.last, &udata);
3426
3427 /* Mark cache entry as clean */
3428 ent->dirty = FALSE;
3429
3430 /* Increment # of flushed entries */
3431 dset->shared->cache.chunk.stats.nflushes++;
3432 } /* end if */
3433
3434 /* Reset, but do not free or removed from list */
3435 if (reset) {
3436 point_of_no_return = FALSE;
3437 if (buf == ent->chunk)
3438 buf = NULL;
3439 if (ent->chunk != NULL)
3440 ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk,
3441 ((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS)
3442 ? NULL
3443 : &(dset->shared->dcpl_cache.pline)));
3444 } /* end if */
3445
3446 done:
3447 /* Free the temp buffer only if it's different than the entry chunk */
3448 if (buf != ent->chunk)
3449 H5MM_xfree(buf);
3450
3451 /*
3452 * If we reached the point of no return then we have no choice but to
3453 * reset the entry. This can only happen if RESET is true but the
3454 * output pipeline failed. Do not free the entry or remove it from the
3455 * list.
3456 */
3457 if (ret_value < 0 && point_of_no_return)
3458 if (ent->chunk)
3459 ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk,
3460 ((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS)
3461 ? NULL
3462 : &(dset->shared->dcpl_cache.pline)));
3463
3464 FUNC_LEAVE_NOAPI(ret_value)
3465 } /* end H5D__chunk_flush_entry() */
3466
3467 /*-------------------------------------------------------------------------
3468 * Function: H5D__chunk_cache_evict
3469 *
3470 * Purpose: Preempts the specified entry from the cache, flushing it to
3471 * disk if necessary.
3472 *
3473 * Return: Non-negative on success/Negative on failure
3474 *
3475 * Programmer: Robb Matzke
3476 * Thursday, May 21, 1998
3477 *
3478 *-------------------------------------------------------------------------
3479 */
3480 static herr_t
H5D__chunk_cache_evict(const H5D_t * dset,H5D_rdcc_ent_t * ent,hbool_t flush)3481 H5D__chunk_cache_evict(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t flush)
3482 {
3483 H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);
3484 herr_t ret_value = SUCCEED; /* Return value */
3485
3486 FUNC_ENTER_STATIC
3487
3488 /* Sanity checks */
3489 HDassert(dset);
3490 HDassert(ent);
3491 HDassert(!ent->locked);
3492 HDassert(ent->idx < rdcc->nslots);
3493
3494 if (flush) {
3495 /* Flush */
3496 if (H5D__chunk_flush_entry(dset, ent, TRUE) < 0)
3497 HDONE_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
3498 } /* end if */
3499 else {
3500 /* Don't flush, just free chunk */
3501 if (ent->chunk != NULL)
3502 ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk,
3503 ((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS)
3504 ? NULL
3505 : &(dset->shared->dcpl_cache.pline)));
3506 } /* end else */
3507
3508 /* Unlink from list */
3509 if (ent->prev)
3510 ent->prev->next = ent->next;
3511 else
3512 rdcc->head = ent->next;
3513 if (ent->next)
3514 ent->next->prev = ent->prev;
3515 else
3516 rdcc->tail = ent->prev;
3517 ent->prev = ent->next = NULL;
3518
3519 /* Unlink from temporary list */
3520 if (ent->tmp_prev) {
3521 HDassert(rdcc->tmp_head->tmp_next);
3522 ent->tmp_prev->tmp_next = ent->tmp_next;
3523 if (ent->tmp_next) {
3524 ent->tmp_next->tmp_prev = ent->tmp_prev;
3525 ent->tmp_next = NULL;
3526 } /* end if */
3527 ent->tmp_prev = NULL;
3528 } /* end if */
3529 else
3530 /* Only clear hash table slot if the chunk was not on the temporary list
3531 */
3532 rdcc->slot[ent->idx] = NULL;
3533
3534 /* Remove from cache */
3535 HDassert(rdcc->slot[ent->idx] != ent);
3536 ent->idx = UINT_MAX;
3537 rdcc->nbytes_used -= dset->shared->layout.u.chunk.size;
3538 --rdcc->nused;
3539
3540 /* Free */
3541 ent = H5FL_FREE(H5D_rdcc_ent_t, ent);
3542
3543 FUNC_LEAVE_NOAPI(ret_value)
3544 } /* end H5D__chunk_cache_evict() */
3545
3546 /*-------------------------------------------------------------------------
3547 * Function: H5D__chunk_cache_prune
3548 *
3549 * Purpose: Prune the cache by preempting some things until the cache has
3550 * room for something which is SIZE bytes. Only unlocked
3551 * entries are considered for preemption.
3552 *
3553 * Return: Non-negative on success/Negative on failure
3554 *
3555 * Programmer: Robb Matzke
3556 * Thursday, May 21, 1998
3557 *
3558 *-------------------------------------------------------------------------
3559 */
3560 static herr_t
H5D__chunk_cache_prune(const H5D_t * dset,size_t size)3561 H5D__chunk_cache_prune(const H5D_t *dset, size_t size)
3562 {
3563 const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);
3564 size_t total = rdcc->nbytes_max;
3565 const int nmeth = 2; /* Number of methods */
3566 int w[1]; /* Weighting as an interval */
3567 H5D_rdcc_ent_t * p[2], *cur; /* List pointers */
3568 H5D_rdcc_ent_t * n[2]; /* List next pointers */
3569 int nerrors = 0; /* Accumulated error count during preemptions */
3570 herr_t ret_value = SUCCEED; /* Return value */
3571
3572 FUNC_ENTER_STATIC
3573
3574 /*
3575 * Preemption is accomplished by having multiple pointers (currently two)
3576 * slide down the list beginning at the head. Pointer p(N+1) will start
3577 * traversing the list when pointer pN reaches wN percent of the original
3578 * list. In other words, preemption method N gets to consider entries in
3579 * approximate least recently used order w0 percent before method N+1
3580 * where 100% means tha method N will run to completion before method N+1
3581 * begins. The pointers participating in the list traversal are each
3582 * given a chance at preemption before any of the pointers are advanced.
3583 */
3584 w[0] = (int)(rdcc->nused * rdcc->w0);
3585 p[0] = rdcc->head;
3586 p[1] = NULL;
3587
3588 while ((p[0] || p[1]) && (rdcc->nbytes_used + size) > total) {
3589 int i; /* Local index variable */
3590
3591 /* Introduce new pointers */
3592 for (i = 0; i < nmeth - 1; i++)
3593 if (0 == w[i])
3594 p[i + 1] = rdcc->head;
3595
3596 /* Compute next value for each pointer */
3597 for (i = 0; i < nmeth; i++)
3598 n[i] = p[i] ? p[i]->next : NULL;
3599
3600 /* Give each method a chance */
3601 for (i = 0; i < nmeth && (rdcc->nbytes_used + size) > total; i++) {
3602 if (0 == i && p[0] && !p[0]->locked &&
3603 ((0 == p[0]->rd_count && 0 == p[0]->wr_count) ||
3604 (0 == p[0]->rd_count && dset->shared->layout.u.chunk.size == p[0]->wr_count) ||
3605 (dset->shared->layout.u.chunk.size == p[0]->rd_count && 0 == p[0]->wr_count))) {
3606 /*
3607 * Method 0: Preempt entries that have been completely written
3608 * and/or completely read but not entries that are partially
3609 * written or partially read.
3610 */
3611 cur = p[0];
3612 }
3613 else if (1 == i && p[1] && !p[1]->locked) {
3614 /*
3615 * Method 1: Preempt the entry without regard to
3616 * considerations other than being locked. This is the last
3617 * resort preemption.
3618 */
3619 cur = p[1];
3620 }
3621 else {
3622 /* Nothing to preempt at this point */
3623 cur = NULL;
3624 }
3625
3626 if (cur) {
3627 int j; /* Local index variable */
3628
3629 for (j = 0; j < nmeth; j++) {
3630 if (p[j] == cur)
3631 p[j] = NULL;
3632 if (n[j] == cur)
3633 n[j] = cur->next;
3634 } /* end for */
3635 if (H5D__chunk_cache_evict(dset, cur, TRUE) < 0)
3636 nerrors++;
3637 } /* end if */
3638 } /* end for */
3639
3640 /* Advance pointers */
3641 for (i = 0; i < nmeth; i++)
3642 p[i] = n[i];
3643 for (i = 0; i < nmeth - 1; i++)
3644 w[i] -= 1;
3645 } /* end while */
3646
3647 if (nerrors)
3648 HGOTO_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to preempt one or more raw data cache entry")
3649
3650 done:
3651 FUNC_LEAVE_NOAPI(ret_value)
3652 } /* end H5D__chunk_cache_prune() */
3653
3654 /*-------------------------------------------------------------------------
3655 * Function: H5D__chunk_lock
3656 *
3657 * Purpose: Return a pointer to a dataset chunk. The pointer points
3658 * directly into the chunk cache and should not be freed
3659 * by the caller but will be valid until it is unlocked. The
3660 * input value IDX_HINT is used to speed up cache lookups and
3661 * it's output value should be given to H5D__chunk_unlock().
3662 * IDX_HINT is ignored if it is out of range, and if it points
3663 * to the wrong entry then we fall back to the normal search
3664 * method.
3665 *
3666 * If RELAX is non-zero and the chunk isn't in the cache then
3667 * don't try to read it from the file, but just allocate an
3668 * uninitialized buffer to hold the result. This is intended
3669 * for output functions that are about to overwrite the entire
3670 * chunk.
3671 *
3672 * Return: Success: Ptr to a file chunk.
3673 *
3674 * Failure: NULL
3675 *
3676 * Programmer: Robb Matzke
3677 * Thursday, May 21, 1998
3678 *
3679 *-------------------------------------------------------------------------
3680 */
3681 static void *
H5D__chunk_lock(const H5D_io_info_t * io_info,H5D_chunk_ud_t * udata,hbool_t relax,hbool_t prev_unfilt_chunk)3682 H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax, hbool_t prev_unfilt_chunk)
3683 {
3684 const H5D_t * dset = io_info->dset; /* Local pointer to the dataset info */
3685 const H5O_pline_t *pline =
3686 &(dset->shared->dcpl_cache
3687 .pline); /* I/O pipeline info - always equal to the pline passed to H5D__chunk_mem_alloc */
3688 const H5O_pline_t * old_pline = pline; /* Old pipeline, i.e. pipeline used to read the chunk */
3689 const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
3690 const H5O_fill_t * fill = &(dset->shared->dcpl_cache.fill); /* Fill value info */
3691 H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
3692 hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
3693 H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache*/
3694 H5D_rdcc_ent_t * ent; /*cache entry */
3695 size_t chunk_size; /*size of a chunk */
3696 hbool_t disable_filters = FALSE; /* Whether to disable filters (when adding to cache) */
3697 void * chunk = NULL; /*the file chunk */
3698 void * ret_value = NULL; /* Return value */
3699
3700 FUNC_ENTER_STATIC
3701
3702 /* Sanity checks */
3703 HDassert(io_info);
3704 HDassert(io_info->store);
3705 HDassert(udata);
3706 HDassert(dset);
3707 HDassert(!(udata->new_unfilt_chunk && prev_unfilt_chunk));
3708 HDassert(!rdcc->tmp_head);
3709
3710 /* Get the chunk's size */
3711 HDassert(layout->u.chunk.size > 0);
3712 H5_CHECKED_ASSIGN(chunk_size, size_t, layout->u.chunk.size, uint32_t);
3713
3714 /* Check if the chunk is in the cache */
3715 if (UINT_MAX != udata->idx_hint) {
3716 /* Sanity check */
3717 HDassert(udata->idx_hint < rdcc->nslots);
3718 HDassert(rdcc->slot[udata->idx_hint]);
3719
3720 /* Get the entry */
3721 ent = rdcc->slot[udata->idx_hint];
3722
3723 #ifndef NDEBUG
3724 {
3725 unsigned u; /*counters */
3726
3727 /* Make sure this is the right chunk */
3728 for (u = 0; u < layout->u.chunk.ndims - 1; u++)
3729 HDassert(io_info->store->chunk.scaled[u] == ent->scaled[u]);
3730 }
3731 #endif /* NDEBUG */
3732
3733 /*
3734 * Already in the cache. Count a hit.
3735 */
3736 rdcc->stats.nhits++;
3737
3738 /* Make adjustments if the edge chunk status changed recently */
3739 if (pline->nused) {
3740 /* If the chunk recently became an unfiltered partial edge chunk
3741 * while in cache, we must make some changes to the entry */
3742 if (udata->new_unfilt_chunk) {
3743 /* If this flag is set then partial chunk filters must be
3744 * disabled, and the chunk must not have previously been a
3745 * partial chunk (with disabled filters) */
3746 HDassert(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
3747 HDassert(!(ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS));
3748 HDassert(old_pline->nused);
3749
3750 /* Disable filters. Set pline to NULL instead of just the
3751 * default pipeline to make a quick failure more likely if the
3752 * code is changed in an inappropriate/incomplete way. */
3753 pline = NULL;
3754
3755 /* Reallocate the chunk so H5D__chunk_mem_xfree doesn't get confused
3756 */
3757 if (NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
3758 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
3759 "memory allocation failed for raw data chunk")
3760 H5MM_memcpy(chunk, ent->chunk, chunk_size);
3761 ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk, old_pline);
3762 ent->chunk = (uint8_t *)chunk;
3763 chunk = NULL;
3764
3765 /* Mark the chunk as having filters disabled as well as "newly
3766 * disabled" so it is inserted on flush */
3767 ent->edge_chunk_state |= H5D_RDCC_DISABLE_FILTERS;
3768 ent->edge_chunk_state |= H5D_RDCC_NEWLY_DISABLED_FILTERS;
3769 } /* end if */
3770 else if (prev_unfilt_chunk) {
3771 /* If this flag is set then partial chunk filters must be
3772 * disabled, and the chunk must have previously been a partial
3773 * chunk (with disabled filters) */
3774 HDassert(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
3775 HDassert((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS));
3776 HDassert(pline->nused);
3777
3778 /* Mark the old pipeline as having been disabled */
3779 old_pline = NULL;
3780
3781 /* Reallocate the chunk so H5D__chunk_mem_xfree doesn't get confused
3782 */
3783 if (NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
3784 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
3785 "memory allocation failed for raw data chunk")
3786 H5MM_memcpy(chunk, ent->chunk, chunk_size);
3787
3788 ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk, old_pline);
3789 ent->chunk = (uint8_t *)chunk;
3790 chunk = NULL;
3791
3792 /* Mark the chunk as having filters enabled */
3793 ent->edge_chunk_state &= ~(H5D_RDCC_DISABLE_FILTERS | H5D_RDCC_NEWLY_DISABLED_FILTERS);
3794 } /* end else */
3795 } /* end if */
3796
3797 /*
3798 * If the chunk is not at the beginning of the cache; move it backward
3799 * by one slot. This is how we implement the LRU preemption
3800 * algorithm.
3801 */
3802 if (ent->next) {
3803 if (ent->next->next)
3804 ent->next->next->prev = ent;
3805 else
3806 rdcc->tail = ent;
3807 ent->next->prev = ent->prev;
3808 if (ent->prev)
3809 ent->prev->next = ent->next;
3810 else
3811 rdcc->head = ent->next;
3812 ent->prev = ent->next;
3813 ent->next = ent->next->next;
3814 ent->prev->next = ent;
3815 } /* end if */
3816 } /* end if */
3817 else {
3818 haddr_t chunk_addr; /* Address of chunk on disk */
3819 hsize_t chunk_alloc; /* Length of chunk on disk */
3820
3821 /* Save the chunk info so the cache stays consistent */
3822 chunk_addr = udata->chunk_block.offset;
3823 chunk_alloc = udata->chunk_block.length;
3824
3825 /* Check if we should disable filters on this chunk */
3826 if (pline->nused) {
3827 if (udata->new_unfilt_chunk) {
3828 HDassert(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
3829
3830 /* Disable the filters for writing */
3831 disable_filters = TRUE;
3832 pline = NULL;
3833 } /* end if */
3834 else if (prev_unfilt_chunk) {
3835 HDassert(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
3836
3837 /* Mark the filters as having been previously disabled (for the
3838 * chunk as currently on disk) - disable the filters for reading
3839 */
3840 old_pline = NULL;
3841 } /* end if */
3842 else if (layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) {
3843 /* Check if this is an edge chunk */
3844 if (H5D__chunk_is_partial_edge_chunk(io_info->dset->shared->ndims, layout->u.chunk.dim,
3845 io_info->store->chunk.scaled,
3846 io_info->dset->shared->curr_dims)) {
3847 /* Disable the filters for both writing and reading */
3848 disable_filters = TRUE;
3849 old_pline = NULL;
3850 pline = NULL;
3851 } /* end if */
3852 } /* end if */
3853 } /* end if */
3854
3855 if (relax) {
3856 /*
3857 * Not in the cache, but we're about to overwrite the whole thing
3858 * anyway, so just allocate a buffer for it but don't initialize that
3859 * buffer with the file contents. Count this as a hit instead of a
3860 * miss because we saved ourselves lots of work.
3861 */
3862 rdcc->stats.nhits++;
3863
3864 if (NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
3865 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk")
3866
3867 /* In the case that some dataset functions look through this data,
3868 * clear it to all 0s. */
3869 HDmemset(chunk, 0, chunk_size);
3870 } /* end if */
3871 else {
3872 /*
3873 * Not in the cache. Count this as a miss if it's in the file
3874 * or an init if it isn't.
3875 */
3876
3877 /* Check if the chunk exists on disk */
3878 if (H5F_addr_defined(chunk_addr)) {
3879 size_t my_chunk_alloc = chunk_alloc; /* Allocated buffer size */
3880 size_t buf_alloc = chunk_alloc; /* [Re-]allocated buffer size */
3881
3882 /* Chunk size on disk isn't [likely] the same size as the final chunk
3883 * size in memory, so allocate memory big enough. */
3884 if (NULL == (chunk = H5D__chunk_mem_alloc(my_chunk_alloc,
3885 (udata->new_unfilt_chunk ? old_pline : pline))))
3886 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
3887 "memory allocation failed for raw data chunk")
3888 if (H5F_shared_block_read(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW, chunk_addr,
3889 my_chunk_alloc, chunk) < 0)
3890 HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "unable to read raw data chunk")
3891
3892 if (old_pline && old_pline->nused) {
3893 H5Z_EDC_t err_detect; /* Error detection info */
3894 H5Z_cb_t filter_cb; /* I/O filter callback function */
3895
3896 /* Retrieve filter settings from API context */
3897 if (H5CX_get_err_detect(&err_detect) < 0)
3898 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't get error detection info")
3899 if (H5CX_get_filter_cb(&filter_cb) < 0)
3900 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't get I/O filter callback function")
3901
3902 if (H5Z_pipeline(old_pline, H5Z_FLAG_REVERSE, &(udata->filter_mask), err_detect,
3903 filter_cb, &my_chunk_alloc, &buf_alloc, &chunk) < 0)
3904 HGOTO_ERROR(H5E_DATASET, H5E_CANTFILTER, NULL, "data pipeline read failed")
3905
3906 /* Reallocate chunk if necessary */
3907 if (udata->new_unfilt_chunk) {
3908 void *tmp_chunk = chunk;
3909
3910 if (NULL == (chunk = H5D__chunk_mem_alloc(my_chunk_alloc, pline))) {
3911 (void)H5D__chunk_mem_xfree(tmp_chunk, old_pline);
3912 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
3913 "memory allocation failed for raw data chunk")
3914 } /* end if */
3915 H5MM_memcpy(chunk, tmp_chunk, chunk_size);
3916 (void)H5D__chunk_mem_xfree(tmp_chunk, old_pline);
3917 } /* end if */
3918 } /* end if */
3919
3920 /* Increment # of cache misses */
3921 rdcc->stats.nmisses++;
3922 } /* end if */
3923 else {
3924 H5D_fill_value_t fill_status;
3925
3926 /* Sanity check */
3927 HDassert(fill->alloc_time != H5D_ALLOC_TIME_EARLY);
3928
3929 /* Chunk size on disk isn't [likely] the same size as the final chunk
3930 * size in memory, so allocate memory big enough. */
3931 if (NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
3932 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
3933 "memory allocation failed for raw data chunk")
3934
3935 if (H5P_is_fill_value_defined(fill, &fill_status) < 0)
3936 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't tell if fill value defined")
3937
3938 if (fill->fill_time == H5D_FILL_TIME_ALLOC ||
3939 (fill->fill_time == H5D_FILL_TIME_IFSET &&
3940 (fill_status == H5D_FILL_VALUE_USER_DEFINED || fill_status == H5D_FILL_VALUE_DEFAULT))) {
3941 /*
3942 * The chunk doesn't exist in the file. Replicate the fill
3943 * value throughout the chunk, if the fill value is defined.
3944 */
3945
3946 /* Initialize the fill value buffer */
3947 /* (use the compact dataset storage buffer as the fill value buffer) */
3948 if (H5D__fill_init(&fb_info, chunk, NULL, NULL, NULL, NULL,
3949 &dset->shared->dcpl_cache.fill, dset->shared->type,
3950 dset->shared->type_id, (size_t)0, chunk_size) < 0)
3951 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't initialize fill buffer info")
3952 fb_info_init = TRUE;
3953
3954 /* Check for VL datatype & non-default fill value */
3955 if (fb_info.has_vlen_fill_type)
3956 /* Fill the buffer with VL datatype fill values */
3957 if (H5D__fill_refill_vl(&fb_info, fb_info.elmts_per_buf) < 0)
3958 HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, NULL, "can't refill fill value buffer")
3959 } /* end if */
3960 else
3961 HDmemset(chunk, 0, chunk_size);
3962
3963 /* Increment # of creations */
3964 rdcc->stats.ninits++;
3965 } /* end else */
3966 } /* end else */
3967
3968 /* See if the chunk can be cached */
3969 if (rdcc->nslots > 0 && chunk_size <= rdcc->nbytes_max) {
3970 /* Calculate the index */
3971 udata->idx_hint = H5D__chunk_hash_val(io_info->dset->shared, udata->common.scaled);
3972
3973 /* Add the chunk to the cache only if the slot is not already locked */
3974 ent = rdcc->slot[udata->idx_hint];
3975 if (!ent || !ent->locked) {
3976 /* Preempt enough things from the cache to make room */
3977 if (ent) {
3978 if (H5D__chunk_cache_evict(io_info->dset, ent, TRUE) < 0)
3979 HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk from cache")
3980 } /* end if */
3981 if (H5D__chunk_cache_prune(io_info->dset, chunk_size) < 0)
3982 HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk(s) from cache")
3983
3984 /* Create a new entry */
3985 if (NULL == (ent = H5FL_CALLOC(H5D_rdcc_ent_t)))
3986 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate raw data chunk entry")
3987
3988 ent->edge_chunk_state = disable_filters ? H5D_RDCC_DISABLE_FILTERS : 0;
3989 if (udata->new_unfilt_chunk)
3990 ent->edge_chunk_state |= H5D_RDCC_NEWLY_DISABLED_FILTERS;
3991
3992 /* Initialize the new entry */
3993 ent->chunk_block.offset = chunk_addr;
3994 ent->chunk_block.length = chunk_alloc;
3995 ent->chunk_idx = udata->chunk_idx;
3996 H5MM_memcpy(ent->scaled, udata->common.scaled, sizeof(hsize_t) * layout->u.chunk.ndims);
3997 H5_CHECKED_ASSIGN(ent->rd_count, uint32_t, chunk_size, size_t);
3998 H5_CHECKED_ASSIGN(ent->wr_count, uint32_t, chunk_size, size_t);
3999 ent->chunk = (uint8_t *)chunk;
4000
4001 /* Add it to the cache */
4002 HDassert(NULL == rdcc->slot[udata->idx_hint]);
4003 rdcc->slot[udata->idx_hint] = ent;
4004 ent->idx = udata->idx_hint;
4005 rdcc->nbytes_used += chunk_size;
4006 rdcc->nused++;
4007
4008 /* Add it to the linked list */
4009 if (rdcc->tail) {
4010 rdcc->tail->next = ent;
4011 ent->prev = rdcc->tail;
4012 rdcc->tail = ent;
4013 } /* end if */
4014 else
4015 rdcc->head = rdcc->tail = ent;
4016 ent->tmp_next = NULL;
4017 ent->tmp_prev = NULL;
4018
4019 } /* end if */
4020 else
4021 /* We did not add the chunk to cache */
4022 ent = NULL;
4023 } /* end else */
4024 else /* No cache set up, or chunk is too large: chunk is uncacheable */
4025 ent = NULL;
4026 } /* end else */
4027
4028 /* Lock the chunk into the cache */
4029 if (ent) {
4030 HDassert(!ent->locked);
4031 ent->locked = TRUE;
4032 chunk = ent->chunk;
4033 } /* end if */
4034 else
4035 /*
4036 * The chunk cannot be placed in cache so we don't cache it. This is the
4037 * reason all those arguments have to be repeated for the unlock
4038 * function.
4039 */
4040 udata->idx_hint = UINT_MAX;
4041
4042 /* Set return value */
4043 ret_value = chunk;
4044
4045 done:
4046 /* Release the fill buffer info, if it's been initialized */
4047 if (fb_info_init && H5D__fill_term(&fb_info) < 0)
4048 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, NULL, "Can't release fill buffer info")
4049
4050 /* Release the chunk allocated, on error */
4051 if (!ret_value)
4052 if (chunk)
4053 chunk = H5D__chunk_mem_xfree(chunk, pline);
4054
4055 FUNC_LEAVE_NOAPI(ret_value)
4056 } /* end H5D__chunk_lock() */
4057
4058 /*-------------------------------------------------------------------------
4059 * Function: H5D__chunk_unlock
4060 *
4061 * Purpose: Unlocks a previously locked chunk. The LAYOUT, COMP, and
4062 * OFFSET arguments should be the same as for H5D__chunk_lock().
4063 * The DIRTY argument should be set to non-zero if the chunk has
4064 * been modified since it was locked. The IDX_HINT argument is
4065 * the returned index hint from the lock operation and BUF is
4066 * the return value from the lock.
4067 *
4068 * The NACCESSED argument should be the number of bytes accessed
4069 * for reading or writing (depending on the value of DIRTY).
4070 * It's only purpose is to provide additional information to the
4071 * preemption policy.
4072 *
4073 * Return: Non-negative on success/Negative on failure
4074 *
4075 * Programmer: Robb Matzke
4076 * Thursday, May 21, 1998
4077 *
4078 *-------------------------------------------------------------------------
4079 */
4080 static herr_t
H5D__chunk_unlock(const H5D_io_info_t * io_info,const H5D_chunk_ud_t * udata,hbool_t dirty,void * chunk,uint32_t naccessed)4081 H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk,
4082 uint32_t naccessed)
4083 {
4084 const H5O_layout_t *layout = &(io_info->dset->shared->layout); /* Dataset layout */
4085 const H5D_rdcc_t * rdcc = &(io_info->dset->shared->cache.chunk);
4086 herr_t ret_value = SUCCEED; /* Return value */
4087
4088 FUNC_ENTER_STATIC
4089
4090 /* Sanity check */
4091 HDassert(io_info);
4092 HDassert(udata);
4093
4094 if (UINT_MAX == udata->idx_hint) {
4095 /*
4096 * It's not in the cache, probably because it's too big. If it's
4097 * dirty then flush it to disk. In any case, free the chunk.
4098 */
4099 hbool_t is_unfiltered_edge_chunk = FALSE; /* Whether the chunk is an unfiltered edge chunk */
4100
4101 /* Check if we should disable filters on this chunk */
4102 if (udata->new_unfilt_chunk) {
4103 HDassert(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
4104
4105 is_unfiltered_edge_chunk = TRUE;
4106 } /* end if */
4107 else if (layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) {
4108 /* Check if the chunk is an edge chunk, and disable filters if so */
4109 is_unfiltered_edge_chunk = H5D__chunk_is_partial_edge_chunk(
4110 io_info->dset->shared->ndims, layout->u.chunk.dim, io_info->store->chunk.scaled,
4111 io_info->dset->shared->curr_dims);
4112 } /* end if */
4113
4114 if (dirty) {
4115 H5D_rdcc_ent_t fake_ent; /* "fake" chunk cache entry */
4116
4117 HDmemset(&fake_ent, 0, sizeof(fake_ent));
4118 fake_ent.dirty = TRUE;
4119 if (is_unfiltered_edge_chunk)
4120 fake_ent.edge_chunk_state = H5D_RDCC_DISABLE_FILTERS;
4121 if (udata->new_unfilt_chunk)
4122 fake_ent.edge_chunk_state |= H5D_RDCC_NEWLY_DISABLED_FILTERS;
4123 H5MM_memcpy(fake_ent.scaled, udata->common.scaled, sizeof(hsize_t) * layout->u.chunk.ndims);
4124 HDassert(layout->u.chunk.size > 0);
4125 fake_ent.chunk_idx = udata->chunk_idx;
4126 fake_ent.chunk_block.offset = udata->chunk_block.offset;
4127 fake_ent.chunk_block.length = udata->chunk_block.length;
4128 fake_ent.chunk = (uint8_t *)chunk;
4129
4130 if (H5D__chunk_flush_entry(io_info->dset, &fake_ent, TRUE) < 0)
4131 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
4132 } /* end if */
4133 else {
4134 if (chunk)
4135 chunk = H5D__chunk_mem_xfree(
4136 chunk, (is_unfiltered_edge_chunk ? NULL : &(io_info->dset->shared->dcpl_cache.pline)));
4137 } /* end else */
4138 } /* end if */
4139 else {
4140 H5D_rdcc_ent_t *ent; /* Chunk's entry in the cache */
4141
4142 /* Sanity check */
4143 HDassert(udata->idx_hint < rdcc->nslots);
4144 HDassert(rdcc->slot[udata->idx_hint]);
4145 HDassert(rdcc->slot[udata->idx_hint]->chunk == chunk);
4146
4147 /*
4148 * It's in the cache so unlock it.
4149 */
4150 ent = rdcc->slot[udata->idx_hint];
4151 HDassert(ent->locked);
4152 if (dirty) {
4153 ent->dirty = TRUE;
4154 ent->wr_count -= MIN(ent->wr_count, naccessed);
4155 } /* end if */
4156 else
4157 ent->rd_count -= MIN(ent->rd_count, naccessed);
4158 ent->locked = FALSE;
4159 } /* end else */
4160
4161 done:
4162 FUNC_LEAVE_NOAPI(ret_value)
4163 } /* end H5D__chunk_unlock() */
4164
4165 /*-------------------------------------------------------------------------
4166 * Function: H5D__chunk_allocated_cb
4167 *
4168 * Purpose: Simply counts the number of chunks for a dataset.
4169 *
4170 * Return: Success: Non-negative
4171 * Failure: Negative
4172 *
4173 * Programmer: Robb Matzke
4174 * Wednesday, April 21, 1999
4175 *
4176 *-------------------------------------------------------------------------
4177 */
4178 static int
H5D__chunk_allocated_cb(const H5D_chunk_rec_t * chunk_rec,void * _udata)4179 H5D__chunk_allocated_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
4180 {
4181 hsize_t *nbytes = (hsize_t *)_udata;
4182
4183 FUNC_ENTER_STATIC_NOERR
4184
4185 *(hsize_t *)nbytes += chunk_rec->nbytes;
4186
4187 FUNC_LEAVE_NOAPI(H5_ITER_CONT)
4188 } /* H5D__chunk_allocated_cb() */
4189
4190 /*-------------------------------------------------------------------------
4191 * Function: H5D__chunk_allocated
4192 *
4193 * Purpose: Return the number of bytes allocated in the file for storage
4194 * of raw data in the chunked dataset
4195 *
4196 * Return: Success: Number of bytes stored in all chunks.
4197 * Failure: 0
4198 *
4199 * Programmer: Quincey Koziol
4200 * Tuesday, May 20, 2008
4201 *
4202 *-------------------------------------------------------------------------
4203 */
4204 herr_t
H5D__chunk_allocated(const H5D_t * dset,hsize_t * nbytes)4205 H5D__chunk_allocated(const H5D_t *dset, hsize_t *nbytes)
4206 {
4207 H5D_chk_idx_info_t idx_info; /* Chunked index info */
4208 const H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /* Raw data chunk cache */
4209 H5D_rdcc_ent_t * ent; /* Cache entry */
4210 hsize_t chunk_bytes = 0; /* Number of bytes allocated for chunks */
4211 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
4212 herr_t ret_value = SUCCEED; /* Return value */
4213
4214 FUNC_ENTER_PACKAGE
4215
4216 HDassert(dset);
4217 HDassert(dset->shared);
4218 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
4219
4220 /* Search for cached chunks that haven't been written out */
4221 for (ent = rdcc->head; ent; ent = ent->next)
4222 /* Flush the chunk out to disk, to make certain the size is correct later */
4223 if (H5D__chunk_flush_entry(dset, ent, FALSE) < 0)
4224 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
4225
4226 /* Compose chunked index info struct */
4227 idx_info.f = dset->oloc.file;
4228 idx_info.pline = &dset->shared->dcpl_cache.pline;
4229 idx_info.layout = &dset->shared->layout.u.chunk;
4230 idx_info.storage = sc;
4231
4232 /* Iterate over the chunks */
4233 if ((sc->ops->iterate)(&idx_info, H5D__chunk_allocated_cb, &chunk_bytes) < 0)
4234 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
4235 "unable to retrieve allocated chunk information from index")
4236
4237 /* Set number of bytes for caller */
4238 *nbytes = chunk_bytes;
4239
4240 done:
4241 FUNC_LEAVE_NOAPI(ret_value)
4242 } /* end H5D__chunk_allocated() */
4243
4244 /*-------------------------------------------------------------------------
4245 * Function: H5D__chunk_allocate
4246 *
4247 * Purpose: Allocate file space for all chunks that are not allocated yet.
4248 * Return SUCCEED if all needed allocation succeed, otherwise
4249 * FAIL.
4250 *
4251 * Return: Non-negative on success/Negative on failure
4252 *
4253 * Programmer: Albert Cheng
4254 * June 26, 1998
4255 *
4256 *-------------------------------------------------------------------------
4257 */
4258 herr_t
H5D__chunk_allocate(const H5D_io_info_t * io_info,hbool_t full_overwrite,const hsize_t old_dim[])4259 H5D__chunk_allocate(const H5D_io_info_t *io_info, hbool_t full_overwrite, const hsize_t old_dim[])
4260 {
4261 const H5D_t * dset = io_info->dset; /* the dataset pointer */
4262 H5D_chk_idx_info_t idx_info; /* Chunked index info */
4263 const H5D_chunk_ops_t *ops = dset->shared->layout.storage.u.chunk.ops; /* Chunk operations */
4264 hsize_t min_unalloc[H5O_LAYOUT_NDIMS]; /* First chunk in each dimension that is unallocated (in scaled
4265 coordinates) */
4266 hsize_t max_unalloc[H5O_LAYOUT_NDIMS]; /* Last chunk in each dimension that is unallocated (in scaled
4267 coordinates) */
4268 hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Offset of current chunk (in scaled coordinates) */
4269 size_t orig_chunk_size; /* Original size of chunk in bytes */
4270 size_t chunk_size; /* Actual size of chunk in bytes, possibly filtered */
4271 unsigned filter_mask = 0; /* Filter mask for chunks that have them */
4272 const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
4273 const H5O_pline_t * pline = &(dset->shared->dcpl_cache.pline); /* I/O pipeline info */
4274 const H5O_pline_t def_pline = H5O_CRT_PIPELINE_DEF; /* Default pipeline */
4275 const H5O_fill_t * fill = &(dset->shared->dcpl_cache.fill); /* Fill value info */
4276 H5D_fill_value_t fill_status; /* The fill value status */
4277 hbool_t should_fill = FALSE; /* Whether fill values should be written */
4278 void * unfilt_fill_buf = NULL; /* Unfiltered fill value buffer */
4279 void ** fill_buf = NULL; /* Pointer to the fill buffer to use for a chunk */
4280 #ifdef H5_HAVE_PARALLEL
4281 hbool_t blocks_written = FALSE; /* Flag to indicate that chunk was actually written */
4282 hbool_t using_mpi =
4283 FALSE; /* Flag to indicate that the file is being accessed with an MPI-capable file driver */
4284 H5D_chunk_coll_info_t chunk_info; /* chunk address information for doing I/O */
4285 #endif /* H5_HAVE_PARALLEL */
4286 hbool_t carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */
4287 unsigned space_ndims; /* Dataset's space rank */
4288 const hsize_t * space_dim; /* Dataset's dataspace dimensions */
4289 const uint32_t * chunk_dim = layout->u.chunk.dim; /* Convenience pointer to chunk dimensions */
4290 unsigned op_dim; /* Current operating dimension */
4291 H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
4292 hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
4293 hbool_t has_unfilt_edge_chunks = FALSE; /* Whether there are partial edge chunks with disabled filters */
4294 hbool_t unfilt_edge_chunk_dim[H5O_LAYOUT_NDIMS]; /* Whether there are unfiltered edge chunks at the edge
4295 of each dimension */
4296 hsize_t edge_chunk_scaled[H5O_LAYOUT_NDIMS]; /* Offset of the unfiltered edge chunks at the edge of each
4297 dimension */
4298 unsigned nunfilt_edge_chunk_dims = 0; /* Number of dimensions on an edge */
4299 H5O_storage_chunk_t *sc = &(layout->storage.u.chunk); /* Convenience variable */
4300 herr_t ret_value = SUCCEED; /* Return value */
4301
4302 FUNC_ENTER_PACKAGE
4303
4304 /* Check args */
4305 HDassert(dset && H5D_CHUNKED == layout->type);
4306 HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
4307 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
4308
4309 /* Retrieve the dataset dimensions */
4310 space_dim = dset->shared->curr_dims;
4311 space_ndims = dset->shared->ndims;
4312
4313 /* The last dimension in scaled chunk coordinates is always 0 */
4314 scaled[space_ndims] = (hsize_t)0;
4315
4316 /* Check if any space dimensions are 0, if so we do not have to do anything
4317 */
4318 for (op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++)
4319 if (space_dim[op_dim] == 0) {
4320 /* Reset any cached chunk info for this dataset */
4321 H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
4322 HGOTO_DONE(SUCCEED)
4323 } /* end if */
4324
4325 #ifdef H5_HAVE_PARALLEL
4326 /* Retrieve MPI parameters */
4327 if (H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI)) {
4328 /* Set the MPI-capable file driver flag */
4329 using_mpi = TRUE;
4330
4331 /* init chunk info stuff for collective I/O */
4332 chunk_info.num_io = 0;
4333 chunk_info.addr = NULL;
4334 } /* end if */
4335 #endif /* H5_HAVE_PARALLEL */
4336
4337 /* Calculate the minimum and maximum chunk offsets in each dimension, and
4338 * determine if there are any unfiltered partial edge chunks. Note that we
4339 * assume here that all elements of space_dim are > 0. This is checked at
4340 * the top of this function. */
4341 for (op_dim = 0; op_dim < space_ndims; op_dim++) {
4342 /* Validate this chunk dimension */
4343 if (chunk_dim[op_dim] == 0)
4344 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", op_dim)
4345 min_unalloc[op_dim] = (old_dim[op_dim] + chunk_dim[op_dim] - 1) / chunk_dim[op_dim];
4346 max_unalloc[op_dim] = (space_dim[op_dim] - 1) / chunk_dim[op_dim];
4347
4348 /* Calculate if there are unfiltered edge chunks at the edge of this
4349 * dimension. Note the edge_chunk_scaled is uninitialized for
4350 * dimensions where unfilt_edge_chunk_dim is FALSE. Also */
4351 if ((layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) && pline->nused > 0 &&
4352 space_dim[op_dim] % chunk_dim[op_dim] != 0) {
4353 has_unfilt_edge_chunks = TRUE;
4354 unfilt_edge_chunk_dim[op_dim] = TRUE;
4355 edge_chunk_scaled[op_dim] = max_unalloc[op_dim];
4356 } /* end if */
4357 else
4358 unfilt_edge_chunk_dim[op_dim] = FALSE;
4359 } /* end for */
4360
4361 /* Get original chunk size */
4362 H5_CHECKED_ASSIGN(orig_chunk_size, size_t, layout->u.chunk.size, uint32_t);
4363
4364 /* Check the dataset's fill-value status */
4365 if (H5P_is_fill_value_defined(fill, &fill_status) < 0)
4366 HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
4367
4368 /* If we are filling the dataset on allocation or "if set" and
4369 * the fill value _is_ set, _and_ we are not overwriting the new blocks,
4370 * or if there are any pipeline filters defined,
4371 * set the "should fill" flag
4372 */
4373 if ((!full_overwrite &&
4374 (fill->fill_time == H5D_FILL_TIME_ALLOC ||
4375 (fill->fill_time == H5D_FILL_TIME_IFSET &&
4376 (fill_status == H5D_FILL_VALUE_USER_DEFINED || fill_status == H5D_FILL_VALUE_DEFAULT)))) ||
4377 pline->nused > 0)
4378 should_fill = TRUE;
4379
4380 /* Check if fill values should be written to chunks */
4381 if (should_fill) {
4382 /* Initialize the fill value buffer */
4383 /* (delay allocating fill buffer for VL datatypes until refilling) */
4384 /* (casting away const OK - QAK) */
4385 if (H5D__fill_init(&fb_info, NULL, (H5MM_allocate_t)H5D__chunk_mem_alloc, (void *)pline,
4386 (H5MM_free_t)H5D__chunk_mem_xfree, (void *)pline, &dset->shared->dcpl_cache.fill,
4387 dset->shared->type, dset->shared->type_id, (size_t)0, orig_chunk_size) < 0)
4388 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
4389 fb_info_init = TRUE;
4390
4391 /* Initialize the fill_buf pointer to the buffer in fb_info. If edge
4392 * chunk filters are disabled, we will switch the buffer as appropriate
4393 * for each chunk. */
4394 fill_buf = &fb_info.fill_buf;
4395
4396 /* Check if there are filters which need to be applied to the chunk */
4397 /* (only do this in advance when the chunk info can be re-used (i.e.
4398 * it doesn't contain any non-default VL datatype fill values)
4399 */
4400 if (!fb_info.has_vlen_fill_type && pline->nused > 0) {
4401 H5Z_EDC_t err_detect; /* Error detection info */
4402 H5Z_cb_t filter_cb; /* I/O filter callback function */
4403 size_t buf_size = orig_chunk_size;
4404
4405 /* If the dataset has disabled partial chunk filters, create a copy
4406 * of the unfiltered fill_buf to use for partial chunks */
4407 if (has_unfilt_edge_chunks) {
4408 if (NULL == (unfilt_fill_buf = H5D__chunk_mem_alloc(orig_chunk_size, &def_pline)))
4409 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
4410 "memory allocation failed for raw data chunk")
4411 H5MM_memcpy(unfilt_fill_buf, fb_info.fill_buf, orig_chunk_size);
4412 } /* end if */
4413
4414 /* Retrieve filter settings from API context */
4415 if (H5CX_get_err_detect(&err_detect) < 0)
4416 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get error detection info")
4417 if (H5CX_get_filter_cb(&filter_cb) < 0)
4418 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get I/O filter callback function")
4419
4420 /* Push the chunk through the filters */
4421 if (H5Z_pipeline(pline, 0, &filter_mask, err_detect, filter_cb, &orig_chunk_size, &buf_size,
4422 &fb_info.fill_buf) < 0)
4423 HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "output pipeline failed")
4424 #if H5_SIZEOF_SIZE_T > 4
4425 /* Check for the chunk expanding too much to encode in a 32-bit value */
4426 if (orig_chunk_size > ((size_t)0xffffffff))
4427 HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk too large for 32-bit length")
4428 #endif /* H5_SIZEOF_SIZE_T > 4 */
4429 } /* end if */
4430 } /* end if */
4431
4432 /* Compose chunked index info struct */
4433 idx_info.f = dset->oloc.file;
4434 idx_info.pline = &dset->shared->dcpl_cache.pline;
4435 idx_info.layout = &dset->shared->layout.u.chunk;
4436 idx_info.storage = sc;
4437
4438 /* Loop over all chunks */
4439 /* The algorithm is:
4440 * For each dimension:
4441 * -Allocate all chunks in the new dataspace that are beyond the original
4442 * dataspace in the operating dimension, except those that have already
4443 * been allocated.
4444 *
4445 * This is accomplished mainly using the min_unalloc and max_unalloc arrays.
4446 * min_unalloc represents the lowest offset in each dimension of chunks that
4447 * have not been allocated (whether or not they need to be). max_unalloc
4448 * represents the highest offset in each dimension of chunks in the new
4449 * dataset that have not been allocated by this routine (they may have been
4450 * allocated previously).
4451 *
4452 * Every time the algorithm finishes allocating chunks allocated beyond a
4453 * certain dimension, max_unalloc is updated in order to avoid allocating
4454 * those chunks again.
4455 *
4456 * Note that min_unalloc & max_unalloc are in scaled coordinates.
4457 *
4458 */
4459 chunk_size = orig_chunk_size;
4460 for (op_dim = 0; op_dim < space_ndims; op_dim++) {
4461 H5D_chunk_ud_t udata; /* User data for querying chunk info */
4462 unsigned u; /* Local index variable */
4463 int i; /* Local index variable */
4464
4465 /* Check if allocation along this dimension is really necessary */
4466 if (min_unalloc[op_dim] > max_unalloc[op_dim])
4467 continue;
4468 else {
4469 /* Reset the chunk offset indices */
4470 HDmemset(scaled, 0, (space_ndims * sizeof(scaled[0])));
4471 scaled[op_dim] = min_unalloc[op_dim];
4472
4473 if (has_unfilt_edge_chunks) {
4474 /* Initialize nunfilt_edge_chunk_dims */
4475 nunfilt_edge_chunk_dims = 0;
4476 for (u = 0; u < space_ndims; u++)
4477 if (unfilt_edge_chunk_dim[u] && scaled[u] == edge_chunk_scaled[u])
4478 nunfilt_edge_chunk_dims++;
4479
4480 /* Initialize chunk_size and fill_buf */
4481 if (should_fill && !fb_info.has_vlen_fill_type) {
4482 HDassert(fb_info_init);
4483 HDassert(unfilt_fill_buf);
4484 if (nunfilt_edge_chunk_dims) {
4485 fill_buf = &unfilt_fill_buf;
4486 chunk_size = layout->u.chunk.size;
4487 } /* end if */
4488 else {
4489 fill_buf = &fb_info.fill_buf;
4490 chunk_size = orig_chunk_size;
4491 } /* end else */
4492 } /* end if */
4493 } /* end if */
4494
4495 carry = FALSE;
4496 } /* end else */
4497
4498 while (!carry) {
4499 hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
4500
4501 /* Look up this chunk */
4502 if (H5D__chunk_lookup(dset, scaled, &udata) < 0)
4503 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
4504 #ifndef NDEBUG
4505 /* None of the chunks should be allocated */
4506 if (H5D_CHUNK_IDX_NONE != sc->idx_type)
4507 HDassert(!H5F_addr_defined(udata.chunk_block.offset));
4508
4509 /* Make sure the chunk is really in the dataset and outside the
4510 * original dimensions */
4511 {
4512 unsigned v; /* Local index variable */
4513 hbool_t outside_orig = FALSE;
4514
4515 for (v = 0; v < space_ndims; v++) {
4516 HDassert((scaled[v] * chunk_dim[v]) < space_dim[v]);
4517 if ((scaled[v] * chunk_dim[v]) >= old_dim[v])
4518 outside_orig = TRUE;
4519 } /* end for */
4520 HDassert(outside_orig);
4521 } /* end block */
4522 #endif /* NDEBUG */
4523
4524 /* Check for VL datatype & non-default fill value */
4525 if (fb_info_init && fb_info.has_vlen_fill_type) {
4526 /* Sanity check */
4527 HDassert(should_fill);
4528 HDassert(!unfilt_fill_buf);
4529 #ifdef H5_HAVE_PARALLEL
4530 HDassert(!using_mpi); /* Can't write VL datatypes in parallel currently */
4531 #endif
4532
4533 /* Check to make sure the buffer is large enough. It is
4534 * possible (though ill-advised) for the filter to shrink the
4535 * buffer.
4536 */
4537 if (fb_info.fill_buf_size < orig_chunk_size) {
4538 if (NULL ==
4539 (fb_info.fill_buf = H5D__chunk_mem_realloc(fb_info.fill_buf, orig_chunk_size, pline)))
4540 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
4541 "memory reallocation failed for raw data chunk")
4542 fb_info.fill_buf_size = orig_chunk_size;
4543 } /* end if */
4544
4545 /* Fill the buffer with VL datatype fill values */
4546 if (H5D__fill_refill_vl(&fb_info, fb_info.elmts_per_buf) < 0)
4547 HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
4548
4549 /* Check if there are filters which need to be applied to the chunk */
4550 if ((pline->nused > 0) && !nunfilt_edge_chunk_dims) {
4551 H5Z_EDC_t err_detect; /* Error detection info */
4552 H5Z_cb_t filter_cb; /* I/O filter callback function */
4553 size_t nbytes = orig_chunk_size;
4554
4555 /* Retrieve filter settings from API context */
4556 if (H5CX_get_err_detect(&err_detect) < 0)
4557 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get error detection info")
4558 if (H5CX_get_filter_cb(&filter_cb) < 0)
4559 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get I/O filter callback function")
4560
4561 /* Push the chunk through the filters */
4562 if (H5Z_pipeline(pline, 0, &filter_mask, err_detect, filter_cb, &nbytes,
4563 &fb_info.fill_buf_size, &fb_info.fill_buf) < 0)
4564 HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "output pipeline failed")
4565
4566 #if H5_SIZEOF_SIZE_T > 4
4567 /* Check for the chunk expanding too much to encode in a 32-bit value */
4568 if (nbytes > ((size_t)0xffffffff))
4569 HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk too large for 32-bit length")
4570 #endif /* H5_SIZEOF_SIZE_T > 4 */
4571
4572 /* Keep the number of bytes the chunk turned in to */
4573 chunk_size = nbytes;
4574 } /* end if */
4575 else
4576 chunk_size = layout->u.chunk.size;
4577
4578 HDassert(*fill_buf == fb_info.fill_buf);
4579 } /* end if */
4580
4581 /* Initialize the chunk information */
4582 udata.common.layout = &layout->u.chunk;
4583 udata.common.storage = sc;
4584 udata.common.scaled = scaled;
4585 udata.chunk_block.offset = HADDR_UNDEF;
4586 H5_CHECKED_ASSIGN(udata.chunk_block.length, uint32_t, chunk_size, size_t);
4587 udata.filter_mask = filter_mask;
4588
4589 /* Allocate the chunk (with all processes) */
4590 if (H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert, scaled) < 0)
4591 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert/resize chunk on chunk level")
4592 HDassert(H5F_addr_defined(udata.chunk_block.offset));
4593
4594 /* Check if fill values should be written to chunks */
4595 if (should_fill) {
4596 /* Sanity check */
4597 HDassert(fb_info_init);
4598 HDassert(udata.chunk_block.length == chunk_size);
4599
4600 #ifdef H5_HAVE_PARALLEL
4601 /* Check if this file is accessed with an MPI-capable file driver */
4602 if (using_mpi) {
4603 /* collect all chunk addresses to be written to
4604 write collectively at the end */
4605 /* allocate/resize address array if no more space left */
4606 /* Note that if we add support for parallel filters we must
4607 * also store an array of chunk sizes and pass it to the
4608 * apporpriate collective write function */
4609 if (0 == chunk_info.num_io % 1024)
4610 if (NULL == (chunk_info.addr = (haddr_t *)H5MM_realloc(
4611 chunk_info.addr, (chunk_info.num_io + 1024) * sizeof(haddr_t))))
4612 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
4613 "memory allocation failed for chunk addresses")
4614
4615 /* Store the chunk's address for later */
4616 chunk_info.addr[chunk_info.num_io] = udata.chunk_block.offset;
4617 chunk_info.num_io++;
4618
4619 /* Indicate that blocks will be written */
4620 blocks_written = TRUE;
4621 } /* end if */
4622 else {
4623 #endif /* H5_HAVE_PARALLEL */
4624 if (H5F_shared_block_write(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW,
4625 udata.chunk_block.offset, chunk_size, *fill_buf) < 0)
4626 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
4627 #ifdef H5_HAVE_PARALLEL
4628 } /* end else */
4629 #endif /* H5_HAVE_PARALLEL */
4630 } /* end if */
4631
4632 /* Insert the chunk record into the index */
4633 if (need_insert && ops->insert)
4634 if ((ops->insert)(&idx_info, &udata, dset) < 0)
4635 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
4636
4637 /* Increment indices and adjust the edge chunk state */
4638 carry = TRUE;
4639 for (i = ((int)space_ndims - 1); i >= 0; --i) {
4640 scaled[i]++;
4641 if (scaled[i] > max_unalloc[i]) {
4642 if ((unsigned)i == op_dim)
4643 scaled[i] = min_unalloc[i];
4644 else
4645 scaled[i] = 0;
4646
4647 /* Check if we just left the edge in this dimension */
4648 if (unfilt_edge_chunk_dim[i] && edge_chunk_scaled[i] == max_unalloc[i] &&
4649 scaled[i] < edge_chunk_scaled[i]) {
4650 nunfilt_edge_chunk_dims--;
4651 if (should_fill && nunfilt_edge_chunk_dims == 0 && !fb_info.has_vlen_fill_type) {
4652 HDassert(
4653 !H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, scaled, space_dim));
4654 fill_buf = &fb_info.fill_buf;
4655 chunk_size = orig_chunk_size;
4656 } /* end if */
4657 } /* end if */
4658 } /* end if */
4659 else {
4660 /* Check if we just entered the edge in this dimension */
4661 if (unfilt_edge_chunk_dim[i] && scaled[i] == edge_chunk_scaled[i]) {
4662 HDassert(edge_chunk_scaled[i] == max_unalloc[i]);
4663 nunfilt_edge_chunk_dims++;
4664 if (should_fill && nunfilt_edge_chunk_dims == 1 && !fb_info.has_vlen_fill_type) {
4665 HDassert(
4666 H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, scaled, space_dim));
4667 fill_buf = &unfilt_fill_buf;
4668 chunk_size = layout->u.chunk.size;
4669 } /* end if */
4670 } /* end if */
4671
4672 carry = FALSE;
4673 break;
4674 } /* end else */
4675 } /* end for */
4676 } /* end while(!carry) */
4677
4678 /* Adjust max_unalloc so we don't allocate the same chunk twice. Also
4679 * check if this dimension started from 0 (and hence allocated all of
4680 * the chunks. */
4681 if (min_unalloc[op_dim] == 0)
4682 break;
4683 else
4684 max_unalloc[op_dim] = min_unalloc[op_dim] - 1;
4685 } /* end for(op_dim=0...) */
4686
4687 #ifdef H5_HAVE_PARALLEL
4688 /* do final collective I/O */
4689 if (using_mpi && blocks_written)
4690 if (H5D__chunk_collective_fill(dset, &chunk_info, chunk_size, fb_info.fill_buf) < 0)
4691 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
4692 #endif /* H5_HAVE_PARALLEL */
4693
4694 /* Reset any cached chunk info for this dataset */
4695 H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
4696
4697 done:
4698 /* Release the fill buffer info, if it's been initialized */
4699 if (fb_info_init && H5D__fill_term(&fb_info) < 0)
4700 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
4701
4702 /* Free the unfiltered fill value buffer */
4703 unfilt_fill_buf = H5D__chunk_mem_xfree(unfilt_fill_buf, &def_pline);
4704
4705 #ifdef H5_HAVE_PARALLEL
4706 if (using_mpi && chunk_info.addr)
4707 H5MM_free(chunk_info.addr);
4708 #endif
4709
4710 FUNC_LEAVE_NOAPI(ret_value)
4711 } /* end H5D__chunk_allocate() */
4712
4713 /*-------------------------------------------------------------------------
4714 * Function: H5D__chunk_update_old_edge_chunks
4715 *
4716 * Purpose: Update all chunks which were previously partial edge
4717 * chunks and are now complete. Determines exactly which
4718 * chunks need to be updated and locks each into cache using
4719 * the 'prev_unfilt_chunk' flag, then unlocks it, causing
4720 * filters to be applied as necessary.
4721 *
4722 * Return: Non-negative on success/Negative on failure
4723 *
4724 * Programmer: Neil Fortner
4725 * April 14, 2010
4726 *
4727 *-------------------------------------------------------------------------
4728 */
4729 herr_t
H5D__chunk_update_old_edge_chunks(H5D_t * dset,hsize_t old_dim[])4730 H5D__chunk_update_old_edge_chunks(H5D_t *dset, hsize_t old_dim[])
4731 {
4732 hsize_t old_edge_chunk_sc[H5O_LAYOUT_NDIMS]; /* Offset of first previously incomplete chunk in each
4733 dimension */
4734 hsize_t max_edge_chunk_sc[H5O_LAYOUT_NDIMS]; /* largest offset of chunks that might need to be modified in
4735 each dimension */
4736 hbool_t new_full_dim[H5O_LAYOUT_NDIMS]; /* Whether the plane of chunks in this dimension needs to be
4737 modified */
4738 const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
4739 hsize_t chunk_sc[H5O_LAYOUT_NDIMS]; /* Offset of current chunk */
4740 const uint32_t * chunk_dim = layout->u.chunk.dim; /* Convenience pointer to chunk dimensions */
4741 unsigned space_ndims; /* Dataset's space rank */
4742 const hsize_t * space_dim; /* Dataset's dataspace dimensions */
4743 unsigned op_dim; /* Current operationg dimension */
4744 H5D_io_info_t chk_io_info; /* Chunked I/O info object */
4745 H5D_chunk_ud_t chk_udata; /* User data for locking chunk */
4746 H5D_storage_t chk_store; /* Chunk storage information */
4747 void * chunk; /* The file chunk */
4748 hbool_t carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */
4749 herr_t ret_value = SUCCEED; /* Return value */
4750
4751 FUNC_ENTER_PACKAGE
4752
4753 /* Check args */
4754 HDassert(dset && H5D_CHUNKED == layout->type);
4755 HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
4756 H5D_CHUNK_STORAGE_INDEX_CHK(&layout->storage.u.chunk);
4757 HDassert(dset->shared->dcpl_cache.pline.nused > 0);
4758 HDassert(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
4759
4760 /* Retrieve the dataset dimensions */
4761 space_dim = dset->shared->curr_dims;
4762 space_ndims = dset->shared->ndims;
4763
4764 /* The last dimension in chunk_offset is always 0 */
4765 chunk_sc[space_ndims] = (hsize_t)0;
4766
4767 /* Check if any current dimensions are smaller than the chunk size, or if
4768 * any old dimensions are 0. If so we do not have to do anything. */
4769 for (op_dim = 0; op_dim < space_ndims; op_dim++)
4770 if ((space_dim[op_dim] < chunk_dim[op_dim]) || old_dim[op_dim] == 0) {
4771 /* Reset any cached chunk info for this dataset */
4772 H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
4773 HGOTO_DONE(SUCCEED)
4774 } /* end if */
4775
4776 /* Set up chunked I/O info object, for operations on chunks (in callback).
4777 * Note that we only need to set chunk_offset once, as the array's address
4778 * will never change. */
4779 chk_store.chunk.scaled = chunk_sc;
4780 H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, &chk_store, NULL);
4781
4782 /*
4783 * Determine the edges of the dataset which need to be modified
4784 */
4785 for (op_dim = 0; op_dim < space_ndims; op_dim++) {
4786 /* Start off with this dimension marked as not needing to be modified */
4787 new_full_dim[op_dim] = FALSE;
4788
4789 /* Validate this chunk dimension */
4790 if (chunk_dim[op_dim] == 0)
4791 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", op_dim)
4792
4793 /* Calculate offset of first previously incomplete chunk in this
4794 * dimension */
4795 old_edge_chunk_sc[op_dim] = (old_dim[op_dim] / chunk_dim[op_dim]);
4796
4797 /* Calculate the largest offset of chunks that might need to be
4798 * modified in this dimension */
4799 max_edge_chunk_sc[op_dim] = MIN((old_dim[op_dim] - 1) / chunk_dim[op_dim],
4800 MAX((space_dim[op_dim] / chunk_dim[op_dim]), 1) - 1);
4801
4802 /* Check for old_dim aligned with chunk boundary in this dimension, if
4803 * so we do not need to modify chunks along the edge in this dimension
4804 */
4805 if (old_dim[op_dim] % chunk_dim[op_dim] == 0)
4806 continue;
4807
4808 /* Check if the dataspace expanded enough to cause the old edge chunks
4809 * in this dimension to become full */
4810 if ((space_dim[op_dim] / chunk_dim[op_dim]) >= (old_edge_chunk_sc[op_dim] + 1))
4811 new_full_dim[op_dim] = TRUE;
4812 } /* end for */
4813
4814 /* Main loop: fix old edge chunks */
4815 for (op_dim = 0; op_dim < space_ndims; op_dim++) {
4816 /* Check if allocation along this dimension is really necessary */
4817 if (!new_full_dim[op_dim])
4818 continue;
4819 else {
4820 HDassert(max_edge_chunk_sc[op_dim] == old_edge_chunk_sc[op_dim]);
4821
4822 /* Reset the chunk offset indices */
4823 HDmemset(chunk_sc, 0, (space_ndims * sizeof(chunk_sc[0])));
4824 chunk_sc[op_dim] = old_edge_chunk_sc[op_dim];
4825
4826 carry = FALSE;
4827 } /* end if */
4828
4829 while (!carry) {
4830 int i; /* Local index variable */
4831
4832 /* Make sure the chunk is really a former edge chunk */
4833 HDassert(H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, chunk_sc, old_dim) &&
4834 !H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, chunk_sc, space_dim));
4835
4836 /* Lookup the chunk */
4837 if (H5D__chunk_lookup(dset, chunk_sc, &chk_udata) < 0)
4838 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
4839
4840 /* If this chunk does not exist in cache or on disk, no need to do
4841 * anything */
4842 if (H5F_addr_defined(chk_udata.chunk_block.offset) || (UINT_MAX != chk_udata.idx_hint)) {
4843 /* Lock the chunk into cache. H5D__chunk_lock will take care of
4844 * updating the chunk to no longer be an edge chunk. */
4845 if (NULL == (chunk = (void *)H5D__chunk_lock(&chk_io_info, &chk_udata, FALSE, TRUE)))
4846 HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk")
4847
4848 /* Unlock the chunk */
4849 if (H5D__chunk_unlock(&chk_io_info, &chk_udata, TRUE, chunk, (uint32_t)0) < 0)
4850 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to unlock raw data chunk")
4851 } /* end if */
4852
4853 /* Increment indices */
4854 carry = TRUE;
4855 for (i = ((int)space_ndims - 1); i >= 0; --i) {
4856 if ((unsigned)i != op_dim) {
4857 ++chunk_sc[i];
4858 if (chunk_sc[i] > (hsize_t)max_edge_chunk_sc[i])
4859 chunk_sc[i] = 0;
4860 else {
4861 carry = FALSE;
4862 break;
4863 } /* end else */
4864 } /* end if */
4865 } /* end for */
4866 } /* end while(!carry) */
4867
4868 /* Adjust max_edge_chunk_sc so we don't modify the same chunk twice.
4869 * Also check if this dimension started from 0 (and hence modified all
4870 * of the old edge chunks. */
4871 if (old_edge_chunk_sc[op_dim] == 0)
4872 break;
4873 else
4874 --max_edge_chunk_sc[op_dim];
4875 } /* end for(op_dim=0...) */
4876
4877 /* Reset any cached chunk info for this dataset */
4878 H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
4879
4880 done:
4881 FUNC_LEAVE_NOAPI(ret_value)
4882 } /* end H5D__chunk_update_old_edge_chunks() */
4883
4884 #ifdef H5_HAVE_PARALLEL
4885
4886 /*-------------------------------------------------------------------------
4887 * Function: H5D__chunk_collective_fill
4888 *
4889 * Purpose: Use MPIO collective write to fill the chunks (if number of
4890 * chunks to fill is greater than the number of MPI procs;
4891 * otherwise use independent I/O).
4892 *
4893 * Return: Non-negative on success/Negative on failure
4894 *
4895 * Programmer: Mohamad Chaarawi
4896 * July 30, 2014
4897 *
4898 *-------------------------------------------------------------------------
4899 */
4900 static herr_t
H5D__chunk_collective_fill(const H5D_t * dset,H5D_chunk_coll_info_t * chunk_info,size_t chunk_size,const void * fill_buf)4901 H5D__chunk_collective_fill(const H5D_t *dset, H5D_chunk_coll_info_t *chunk_info, size_t chunk_size,
4902 const void *fill_buf)
4903 {
4904 MPI_Comm mpi_comm = MPI_COMM_NULL; /* MPI communicator for file */
4905 int mpi_rank = (-1); /* This process's rank */
4906 int mpi_size = (-1); /* MPI Comm size */
4907 int mpi_code; /* MPI return code */
4908 size_t num_blocks; /* Number of blocks between processes. */
4909 size_t leftover_blocks; /* Number of leftover blocks to handle */
4910 int blocks, leftover, block_len; /* converted to int for MPI */
4911 MPI_Aint * chunk_disp_array = NULL;
4912 int * block_lens = NULL;
4913 MPI_Datatype mem_type = MPI_BYTE, file_type = MPI_BYTE;
4914 H5FD_mpio_xfer_t prev_xfer_mode; /* Previous data xfer mode */
4915 hbool_t have_xfer_mode = FALSE; /* Whether the previous xffer mode has been retrieved */
4916 hbool_t need_addr_sort = FALSE;
4917 int i; /* Local index variable */
4918 herr_t ret_value = SUCCEED; /* Return value */
4919
4920 FUNC_ENTER_STATIC
4921
4922 /* Get the MPI communicator */
4923 if (MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(dset->oloc.file)))
4924 HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI communicator")
4925
4926 /* Get the MPI rank */
4927 if ((mpi_rank = H5F_mpi_get_rank(dset->oloc.file)) < 0)
4928 HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI rank")
4929
4930 /* Get the MPI size */
4931 if ((mpi_size = H5F_mpi_get_size(dset->oloc.file)) < 0)
4932 HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI size")
4933
4934 /* Distribute evenly the number of blocks between processes. */
4935 if (mpi_size == 0)
4936 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Resulted in division by zero")
4937 num_blocks = (size_t)(chunk_info->num_io / (size_t)mpi_size); /* value should be the same on all procs */
4938
4939 /* After evenly distributing the blocks between processes, are there any
4940 * leftover blocks for each individual process (round-robin)?
4941 */
4942 leftover_blocks = (size_t)(chunk_info->num_io % (size_t)mpi_size);
4943
4944 /* Cast values to types needed by MPI */
4945 H5_CHECKED_ASSIGN(blocks, int, num_blocks, size_t);
4946 H5_CHECKED_ASSIGN(leftover, int, leftover_blocks, size_t);
4947 H5_CHECKED_ASSIGN(block_len, int, chunk_size, size_t);
4948
4949 /* Check if we have any chunks to write on this rank */
4950 if (num_blocks > 0 || (leftover && leftover > mpi_rank)) {
4951 /* Allocate buffers */
4952 /* (MSC - should not need block_lens if MPI_type_create_hindexed_block is working) */
4953 if (NULL == (block_lens = (int *)H5MM_malloc((size_t)(blocks + 1) * sizeof(int))))
4954 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk lengths buffer")
4955 if (NULL == (chunk_disp_array = (MPI_Aint *)H5MM_malloc((size_t)(blocks + 1) * sizeof(MPI_Aint))))
4956 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file displacement buffer")
4957
4958 for (i = 0; i < blocks; i++) {
4959 /* store the chunk address as an MPI_Aint */
4960 chunk_disp_array[i] = (MPI_Aint)(chunk_info->addr[i + (mpi_rank * blocks)]);
4961
4962 /* MSC - should not need this if MPI_type_create_hindexed_block is working */
4963 block_lens[i] = block_len;
4964
4965 /* Make sure that the addresses in the datatype are
4966 * monotonically non-decreasing
4967 */
4968 if (i && (chunk_disp_array[i] < chunk_disp_array[i - 1]))
4969 need_addr_sort = TRUE;
4970 } /* end for */
4971
4972 /* Calculate if there are any leftover blocks after evenly
4973 * distributing. If there are, then round-robin the distribution
4974 * to processes 0 -> leftover.
4975 */
4976 if (leftover && leftover > mpi_rank) {
4977 chunk_disp_array[blocks] = (MPI_Aint)chunk_info->addr[(blocks * mpi_size) + mpi_rank];
4978 if (blocks && (chunk_disp_array[blocks] < chunk_disp_array[blocks - 1]))
4979 need_addr_sort = TRUE;
4980 block_lens[blocks] = block_len;
4981 blocks++;
4982 }
4983
4984 /* Ensure that the blocks are sorted in monotonically non-decreasing
4985 * order of offset in the file.
4986 */
4987 if (need_addr_sort)
4988 HDqsort(chunk_disp_array, blocks, sizeof(MPI_Aint), H5D__chunk_cmp_addr);
4989
4990 /* MSC - should use this if MPI_type_create_hindexed block is working:
4991 * mpi_code = MPI_Type_create_hindexed_block(blocks, block_len, chunk_disp_array, MPI_BYTE,
4992 * &file_type);
4993 */
4994 mpi_code = MPI_Type_create_hindexed(blocks, block_lens, chunk_disp_array, MPI_BYTE, &file_type);
4995 if (mpi_code != MPI_SUCCESS)
4996 HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code)
4997 if (MPI_SUCCESS != (mpi_code = MPI_Type_commit(&file_type)))
4998 HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
4999
5000 mpi_code = MPI_Type_create_hvector(blocks, block_len, 0, MPI_BYTE, &mem_type);
5001 if (mpi_code != MPI_SUCCESS)
5002 HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hvector failed", mpi_code)
5003 if (MPI_SUCCESS != (mpi_code = MPI_Type_commit(&mem_type)))
5004 HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
5005 } /* end if */
5006
5007 /* Set MPI-IO VFD properties */
5008
5009 /* Set MPI datatypes for operation */
5010 if (H5CX_set_mpi_coll_datatypes(mem_type, file_type) < 0)
5011 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set MPI-I/O properties")
5012
5013 /* Get current transfer mode */
5014 if (H5CX_get_io_xfer_mode(&prev_xfer_mode) < 0)
5015 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set transfer mode")
5016 have_xfer_mode = TRUE;
5017
5018 /* Set transfer mode */
5019 if (H5CX_set_io_xfer_mode(H5FD_MPIO_COLLECTIVE) < 0)
5020 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set transfer mode")
5021
5022 /* Low-level write (collective) */
5023 if (H5F_shared_block_write(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW, (haddr_t)0,
5024 (blocks) ? (size_t)1 : (size_t)0, fill_buf) < 0)
5025 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
5026
5027 /* Barrier so processes don't race ahead */
5028 if (MPI_SUCCESS != (mpi_code = MPI_Barrier(mpi_comm)))
5029 HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code)
5030
5031 done:
5032 if (have_xfer_mode)
5033 /* Set transfer mode */
5034 if (H5CX_set_io_xfer_mode(prev_xfer_mode) < 0)
5035 HDONE_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set transfer mode")
5036
5037 /* free things */
5038 if (MPI_BYTE != file_type)
5039 if (MPI_SUCCESS != (mpi_code = MPI_Type_free(&file_type)))
5040 HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
5041 if (MPI_BYTE != mem_type)
5042 if (MPI_SUCCESS != (mpi_code = MPI_Type_free(&mem_type)))
5043 HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
5044 H5MM_xfree(chunk_disp_array);
5045 H5MM_xfree(block_lens);
5046
5047 FUNC_LEAVE_NOAPI(ret_value)
5048 } /* end H5D__chunk_collective_fill() */
5049
5050 static int
H5D__chunk_cmp_addr(const void * addr1,const void * addr2)5051 H5D__chunk_cmp_addr(const void *addr1, const void *addr2)
5052 {
5053 MPI_Aint _addr1 = (MPI_Aint)0, _addr2 = (MPI_Aint)0;
5054 int ret_value = 0;
5055
5056 FUNC_ENTER_STATIC_NOERR
5057
5058 _addr1 = *((const MPI_Aint *)addr1);
5059 _addr2 = *((const MPI_Aint *)addr2);
5060
5061 #if MPI_VERSION >= 3 && MPI_SUBVERSION >= 1
5062 {
5063 MPI_Aint diff = MPI_Aint_diff(_addr1, _addr2);
5064
5065 if (diff < (MPI_Aint)0)
5066 ret_value = -1;
5067 else if (diff > (MPI_Aint)0)
5068 ret_value = 1;
5069 else
5070 ret_value = 0;
5071 }
5072 #else
5073 ret_value = (_addr1 > _addr2) - (_addr1 < _addr2);
5074 #endif
5075
5076 FUNC_LEAVE_NOAPI(ret_value)
5077 } /* end H5D__chunk_cmp_addr() */
5078 #endif /* H5_HAVE_PARALLEL */
5079
5080 /*-------------------------------------------------------------------------
5081 * Function: H5D__chunk_prune_fill
5082 *
5083 * Purpose: Write the fill value to the parts of the chunk that are no
5084 * longer part of the dataspace
5085 *
5086 * Return: Non-negative on success/Negative on failure
5087 *
5088 * Programmer: Pedro Vicente
5089 * March 26, 2002
5090 *
5091 *-------------------------------------------------------------------------
5092 */
5093 static herr_t
H5D__chunk_prune_fill(H5D_chunk_it_ud1_t * udata,hbool_t new_unfilt_chunk)5094 H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk)
5095 {
5096 const H5D_io_info_t *io_info = udata->io_info; /* Local pointer to I/O info */
5097 const H5D_t * dset = io_info->dset; /* Local pointer to the dataset info */
5098 const H5O_layout_t * layout = &(dset->shared->layout); /* Dataset's layout */
5099 unsigned rank = udata->common.layout->ndims - 1; /* Dataset rank */
5100 const hsize_t * scaled = udata->common.scaled; /* Scaled chunk offset */
5101 H5S_sel_iter_t * chunk_iter = NULL; /* Memory selection iteration info */
5102 hbool_t chunk_iter_init = FALSE; /* Whether the chunk iterator has been initialized */
5103 hsize_t sel_nelmts; /* Number of elements in selection */
5104 hsize_t count[H5O_LAYOUT_NDIMS]; /* Element count of hyperslab */
5105 size_t chunk_size; /*size of a chunk */
5106 void * chunk; /* The file chunk */
5107 H5D_chunk_ud_t chk_udata; /* User data for locking chunk */
5108 uint32_t bytes_accessed; /* Bytes accessed in chunk */
5109 unsigned u; /* Local index variable */
5110 herr_t ret_value = SUCCEED; /* Return value */
5111
5112 FUNC_ENTER_STATIC
5113
5114 /* Get the chunk's size */
5115 HDassert(layout->u.chunk.size > 0);
5116 H5_CHECKED_ASSIGN(chunk_size, size_t, layout->u.chunk.size, uint32_t);
5117
5118 /* Get the info for the chunk in the file */
5119 if (H5D__chunk_lookup(dset, scaled, &chk_udata) < 0)
5120 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
5121 chk_udata.new_unfilt_chunk = new_unfilt_chunk;
5122
5123 /* If this chunk does not exist in cache or on disk, no need to do anything */
5124 if (!H5F_addr_defined(chk_udata.chunk_block.offset) && UINT_MAX == chk_udata.idx_hint)
5125 HGOTO_DONE(SUCCEED)
5126
5127 /* Initialize the fill value buffer, if necessary */
5128 if (!udata->fb_info_init) {
5129 H5_CHECK_OVERFLOW(udata->elmts_per_chunk, uint32_t, size_t);
5130 if (H5D__fill_init(&udata->fb_info, NULL, NULL, NULL, NULL, NULL, &dset->shared->dcpl_cache.fill,
5131 dset->shared->type, dset->shared->type_id, (size_t)udata->elmts_per_chunk,
5132 chunk_size) < 0)
5133 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
5134 udata->fb_info_init = TRUE;
5135 } /* end if */
5136
5137 /* Compute the # of elements to leave with existing value, in each dimension */
5138 for (u = 0; u < rank; u++) {
5139 count[u] = MIN(layout->u.chunk.dim[u], (udata->space_dim[u] - (scaled[u] * layout->u.chunk.dim[u])));
5140 HDassert(count[u] > 0);
5141 } /* end for */
5142
5143 /* Select all elements in chunk, to begin with */
5144 if (H5S_select_all(udata->chunk_space, TRUE) < 0)
5145 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to select space")
5146
5147 /* "Subtract out" the elements to keep */
5148 if (H5S_select_hyperslab(udata->chunk_space, H5S_SELECT_NOTB, udata->hyper_start, NULL, count, NULL) < 0)
5149 HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to select hyperslab")
5150
5151 /* Lock the chunk into the cache, to get a pointer to the chunk buffer */
5152 if (NULL == (chunk = (void *)H5D__chunk_lock(io_info, &chk_udata, FALSE, FALSE)))
5153 HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk")
5154
5155 /* Fill the selection in the memory buffer */
5156 /* Use the size of the elements in the chunk directly instead of */
5157 /* relying on the fill.size, which might be set to 0 if there is */
5158 /* no fill-value defined for the dataset -QAK */
5159
5160 /* Get the number of elements in the selection */
5161 sel_nelmts = H5S_GET_SELECT_NPOINTS(udata->chunk_space);
5162 H5_CHECK_OVERFLOW(sel_nelmts, hsize_t, size_t);
5163
5164 /* Check for VL datatype & non-default fill value */
5165 if (udata->fb_info.has_vlen_fill_type)
5166 /* Re-fill the buffer to use for this I/O operation */
5167 if (H5D__fill_refill_vl(&udata->fb_info, (size_t)sel_nelmts) < 0)
5168 HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
5169
5170 /* Allocate the chunk selection iterator */
5171 if (NULL == (chunk_iter = H5FL_MALLOC(H5S_sel_iter_t)))
5172 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk selection iterator")
5173
5174 /* Create a selection iterator for scattering the elements to memory buffer */
5175 if (H5S_select_iter_init(chunk_iter, udata->chunk_space, layout->u.chunk.dim[rank], 0) < 0)
5176 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunk selection information")
5177 chunk_iter_init = TRUE;
5178
5179 /* Scatter the data into memory */
5180 if (H5D__scatter_mem(udata->fb_info.fill_buf, chunk_iter, (size_t)sel_nelmts, chunk /*out*/) < 0)
5181 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed")
5182
5183 /* The number of bytes accessed in the chunk */
5184 /* (i.e. the bytes replaced with fill values) */
5185 H5_CHECK_OVERFLOW(sel_nelmts, hssize_t, uint32_t);
5186 bytes_accessed = (uint32_t)sel_nelmts * layout->u.chunk.dim[rank];
5187
5188 /* Release lock on chunk */
5189 if (H5D__chunk_unlock(io_info, &chk_udata, TRUE, chunk, bytes_accessed) < 0)
5190 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to unlock raw data chunk")
5191
5192 done:
5193 /* Release the selection iterator */
5194 if (chunk_iter_init && H5S_SELECT_ITER_RELEASE(chunk_iter) < 0)
5195 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
5196 if (chunk_iter)
5197 chunk_iter = H5FL_FREE(H5S_sel_iter_t, chunk_iter);
5198
5199 FUNC_LEAVE_NOAPI(ret_value)
5200 } /* H5D__chunk_prune_fill */
5201
5202 /*-------------------------------------------------------------------------
5203 * Function: H5D__chunk_prune_by_extent
5204 *
5205 * Purpose: This function searches for chunks that are no longer necessary
5206 * both in the raw data cache and in the chunk index.
5207 *
5208 * Return: Non-negative on success/Negative on failure
5209 *
5210 * Programmer: Pedro Vicente
5211 * Algorithm: Robb Matzke
5212 * March 27, 2002
5213 *
5214 * The algorithm is:
5215 *
5216 * For chunks that are no longer necessary:
5217 *
5218 * 1. Search in the raw data cache for each chunk
5219 * 2. If found then preempt it from the cache
5220 * 3. Search in the B-tree for each chunk
5221 * 4. If found then remove it from the B-tree and deallocate file storage for the chunk
5222 *
5223 * This example shows a 2d dataset of 90x90 with a chunk size of 20x20.
5224 *
5225 *
5226 * 0 20 40 60 80 90 100
5227 * 0 +---------+---------+---------+---------+-----+...+
5228 * |:::::X:::::::::::::: : : | :
5229 * |:::::::X:::::::::::: : : | : Key
5230 * |::::::::::X::::::::: : : | : --------
5231 * |::::::::::::X::::::: : : | : +-+ Dataset
5232 * 20+::::::::::::::::::::.........:.........:.....+...: | | Extent
5233 * | :::::X::::: : : | : +-+
5234 * | ::::::::::: : : | :
5235 * | ::::::::::: : : | : ... Chunk
5236 * | :::::::X::: : : | : : : Boundary
5237 * 40+.........:::::::::::.........:.........:.....+...: :.:
5238 * | : : : : | :
5239 * | : : : : | : ... Allocated
5240 * | : : : : | : ::: & Filled
5241 * | : : : : | : ::: Chunk
5242 * 60+.........:.........:.........:.........:.....+...:
5243 * | : :::::::X::: : | : X Element
5244 * | : ::::::::::: : | : Written
5245 * | : ::::::::::: : | :
5246 * | : ::::::::::: : | :
5247 * 80+.........:.........:::::::::::.........:.....+...: O Fill Val
5248 * | : : ::::::::::: | : Explicitly
5249 * | : : ::::::X:::: | : Written
5250 * 90+---------+---------+---------+---------+-----+ :
5251 * : : : ::::::::::: :
5252 * 100:.........:.........:.........:::::::::::.........:
5253 *
5254 *
5255 * We have 25 total chunks for this dataset, 5 of which have space
5256 * allocated in the file because they were written to one or more
5257 * elements. These five chunks (and only these five) also have entries in
5258 * the storage B-tree for this dataset.
5259 *
5260 * Now lets say we want to shrink the dataset down to 70x70:
5261 *
5262 *
5263 * 0 20 40 60 70 80 90 100
5264 * 0 +---------+---------+---------+----+----+-----+...+
5265 * |:::::X:::::::::::::: : | : | :
5266 * |:::::::X:::::::::::: : | : | : Key
5267 * |::::::::::X::::::::: : | : | : --------
5268 * |::::::::::::X::::::: : | : | : +-+ Dataset
5269 * 20+::::::::::::::::::::.........:....+....:.....|...: | | Extent
5270 * | :::::X::::: : | : | : +-+
5271 * | ::::::::::: : | : | :
5272 * | ::::::::::: : | : | : ... Chunk
5273 * | :::::::X::: : | : | : : : Boundary
5274 * 40+.........:::::::::::.........:....+....:.....|...: :.:
5275 * | : : : | : | :
5276 * | : : : | : | : ... Allocated
5277 * | : : : | : | : ::: & Filled
5278 * | : : : | : | : ::: Chunk
5279 * 60+.........:.........:.........:....+....:.....|...:
5280 * | : :::::::X::: | : | : X Element
5281 * | : ::::::::::: | : | : Written
5282 * +---------+---------+---------+----+ : | :
5283 * | : ::::::::::: : | :
5284 * 80+.........:.........:::::::::X:.........:.....|...: O Fill Val
5285 * | : : ::::::::::: | : Explicitly
5286 * | : : ::::::X:::: | : Written
5287 * 90+---------+---------+---------+---------+-----+ :
5288 * : : : ::::::::::: :
5289 * 100:.........:.........:.........:::::::::::.........:
5290 *
5291 *
5292 * That means that the nine chunks along the bottom and right side should
5293 * no longer exist. Of those nine chunks, (0,80), (20,80), (40,80),
5294 * (60,80), (80,80), (80,60), (80,40), (80,20), and (80,0), one is actually allocated
5295 * that needs to be released.
5296 * To release the chunks, we traverse the B-tree to obtain a list of unused
5297 * allocated chunks, and then call H5B_remove() for each chunk.
5298 *
5299 *-------------------------------------------------------------------------
5300 */
5301 herr_t
H5D__chunk_prune_by_extent(H5D_t * dset,const hsize_t * old_dim)5302 H5D__chunk_prune_by_extent(H5D_t *dset, const hsize_t *old_dim)
5303 {
5304 hsize_t min_mod_chunk_sc[H5O_LAYOUT_NDIMS]; /* Scaled offset of first chunk to modify in each dimension */
5305 hsize_t max_mod_chunk_sc[H5O_LAYOUT_NDIMS]; /* Scaled offset of last chunk to modify in each dimension */
5306 hssize_t max_fill_chunk_sc[H5O_LAYOUT_NDIMS]; /* Scaled offset of last chunk that might be filled in each
5307 dimension */
5308 hbool_t fill_dim[H5O_LAYOUT_NDIMS]; /* Whether the plane of edge chunks in this dimension needs to be
5309 filled */
5310 hsize_t min_partial_chunk_sc[H5O_LAYOUT_NDIMS]; /* Offset of first partial (or empty) chunk in each
5311 dimension */
5312 hbool_t new_unfilt_dim[H5O_LAYOUT_NDIMS]; /* Whether the plane of edge chunks in this dimension are newly
5313 unfiltered */
5314 H5D_chk_idx_info_t idx_info; /* Chunked index info */
5315 H5D_io_info_t chk_io_info; /* Chunked I/O info object */
5316 H5D_storage_t chk_store; /* Chunk storage information */
5317 const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset's layout */
5318 const H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache */
5319 unsigned space_ndims; /* Dataset's space rank */
5320 const hsize_t * space_dim; /* Current dataspace dimensions */
5321 unsigned op_dim; /* Current operating dimension */
5322 hbool_t shrunk_dim[H5O_LAYOUT_NDIMS]; /* Dimensions which have shrunk */
5323 H5D_chunk_it_ud1_t udata; /* Chunk index iterator user data */
5324 hbool_t udata_init = FALSE; /* Whether the chunk index iterator user data has been initialized */
5325 H5D_chunk_common_ud_t idx_udata; /* User data for index removal routine */
5326 H5S_t * chunk_space = NULL; /* Dataspace for a chunk */
5327 hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Chunk dimensions */
5328 hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Scaled offset of current chunk */
5329 hsize_t hyper_start[H5O_LAYOUT_NDIMS]; /* Starting location of hyperslab */
5330 uint32_t elmts_per_chunk; /* Elements in chunk */
5331 hbool_t disable_edge_filters = FALSE; /* Whether to disable filters on partial edge chunks */
5332 hbool_t new_unfilt_chunk = FALSE; /* Whether the chunk is newly unfiltered */
5333 unsigned u; /* Local index variable */
5334 const H5O_storage_chunk_t *sc = &(layout->storage.u.chunk);
5335 herr_t ret_value = SUCCEED; /* Return value */
5336
5337 FUNC_ENTER_PACKAGE
5338
5339 /* Check args */
5340 HDassert(dset && H5D_CHUNKED == layout->type);
5341 HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
5342 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
5343
5344 /* Go get the rank & dimensions (including the element size) */
5345 space_dim = dset->shared->curr_dims;
5346 space_ndims = dset->shared->ndims;
5347
5348 /* The last dimension in scaled is always 0 */
5349 scaled[space_ndims] = (hsize_t)0;
5350
5351 /* Check if any old dimensions are 0, if so we do not have to do anything */
5352 for (op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++)
5353 if (old_dim[op_dim] == 0) {
5354 /* Reset any cached chunk info for this dataset */
5355 H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
5356 HGOTO_DONE(SUCCEED)
5357 } /* end if */
5358
5359 /* Round up to the next integer # of chunks, to accommodate partial chunks */
5360 /* Use current dims because the indices have already been updated! -NAF */
5361 /* (also compute the number of elements per chunk) */
5362 /* (also copy the chunk dimensions into 'hsize_t' array for creating dataspace) */
5363 /* (also compute the dimensions which have been shrunk) */
5364 elmts_per_chunk = 1;
5365 for (u = 0; u < space_ndims; u++) {
5366 elmts_per_chunk *= layout->u.chunk.dim[u];
5367 chunk_dim[u] = layout->u.chunk.dim[u];
5368 shrunk_dim[u] = (space_dim[u] < old_dim[u]);
5369 } /* end for */
5370
5371 /* Create a dataspace for a chunk & set the extent */
5372 if (NULL == (chunk_space = H5S_create_simple(space_ndims, chunk_dim, NULL)))
5373 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
5374
5375 /* Reset hyperslab start array */
5376 /* (hyperslabs will always start from origin) */
5377 HDmemset(hyper_start, 0, sizeof(hyper_start));
5378
5379 /* Set up chunked I/O info object, for operations on chunks (in callback)
5380 * Note that we only need to set scaled once, as the array's address
5381 * will never change. */
5382 chk_store.chunk.scaled = scaled;
5383 H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, &chk_store, NULL);
5384
5385 /* Compose chunked index info struct */
5386 idx_info.f = dset->oloc.file;
5387 idx_info.pline = &dset->shared->dcpl_cache.pline;
5388 idx_info.layout = &dset->shared->layout.u.chunk;
5389 idx_info.storage = &dset->shared->layout.storage.u.chunk;
5390
5391 /* Initialize the user data for the iteration */
5392 HDmemset(&udata, 0, sizeof udata);
5393 udata.common.layout = &layout->u.chunk;
5394 udata.common.storage = sc;
5395 udata.common.scaled = scaled;
5396 udata.io_info = &chk_io_info;
5397 udata.idx_info = &idx_info;
5398 udata.space_dim = space_dim;
5399 udata.shrunk_dim = shrunk_dim;
5400 udata.elmts_per_chunk = elmts_per_chunk;
5401 udata.chunk_space = chunk_space;
5402 udata.hyper_start = hyper_start;
5403 udata_init = TRUE;
5404
5405 /* Initialize user data for removal */
5406 idx_udata.layout = &layout->u.chunk;
5407 idx_udata.storage = sc;
5408
5409 /* Determine if partial edge chunk filters are disabled */
5410 disable_edge_filters = (layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) &&
5411 (idx_info.pline->nused > 0);
5412
5413 /*
5414 * Determine the chunks which need to be filled or removed
5415 */
5416 HDmemset(min_mod_chunk_sc, 0, sizeof(min_mod_chunk_sc));
5417 HDmemset(max_mod_chunk_sc, 0, sizeof(max_mod_chunk_sc));
5418 for (op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++) {
5419 /* Validate this chunk dimension */
5420 if (chunk_dim[op_dim] == 0)
5421 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", op_dim)
5422
5423 /* Calculate the largest offset of chunks that might need to be
5424 * modified in this dimension */
5425 max_mod_chunk_sc[op_dim] = (old_dim[op_dim] - 1) / chunk_dim[op_dim];
5426
5427 /* Calculate the largest offset of chunks that might need to be
5428 * filled in this dimension */
5429 if (0 == space_dim[op_dim])
5430 max_fill_chunk_sc[op_dim] = -1;
5431 else
5432 max_fill_chunk_sc[op_dim] =
5433 (hssize_t)(((MIN(space_dim[op_dim], old_dim[op_dim]) - 1) / chunk_dim[op_dim]));
5434
5435 if (shrunk_dim[op_dim]) {
5436 /* Calculate the smallest offset of chunks that might need to be
5437 * modified in this dimension. Note that this array contains
5438 * garbage for all dimensions which are not shrunk. These locations
5439 * must not be read from! */
5440 min_mod_chunk_sc[op_dim] = space_dim[op_dim] / chunk_dim[op_dim];
5441
5442 /* Determine if we need to fill chunks in this dimension */
5443 if ((hssize_t)min_mod_chunk_sc[op_dim] == max_fill_chunk_sc[op_dim]) {
5444 fill_dim[op_dim] = TRUE;
5445
5446 /* If necessary, check if chunks in this dimension that need to
5447 * be filled are new partial edge chunks */
5448 if (disable_edge_filters && old_dim[op_dim] >= (min_mod_chunk_sc[op_dim] + 1))
5449 new_unfilt_dim[op_dim] = TRUE;
5450 else
5451 new_unfilt_dim[op_dim] = FALSE;
5452 } /* end if */
5453 else {
5454 fill_dim[op_dim] = FALSE;
5455 new_unfilt_dim[op_dim] = FALSE;
5456 } /* end else */
5457 } /* end if */
5458 else {
5459 fill_dim[op_dim] = FALSE;
5460 new_unfilt_dim[op_dim] = FALSE;
5461 } /* end else */
5462
5463 /* If necessary, calculate the smallest offset of non-previously full
5464 * chunks in this dimension, so we know these chunks were previously
5465 * unfiltered */
5466 if (disable_edge_filters)
5467 min_partial_chunk_sc[op_dim] = old_dim[op_dim] / chunk_dim[op_dim];
5468 } /* end for */
5469
5470 /* Main loop: fill or remove chunks */
5471 for (op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++) {
5472 hbool_t dims_outside_fill[H5O_LAYOUT_NDIMS]; /* Dimensions in chunk offset outside fill dimensions */
5473 int ndims_outside_fill; /* Number of dimensions in chunk offset outside fill dimensions */
5474 hbool_t carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */
5475
5476 /* Check if modification along this dimension is really necessary */
5477 if (!shrunk_dim[op_dim])
5478 continue;
5479 else {
5480 HDassert(max_mod_chunk_sc[op_dim] >= min_mod_chunk_sc[op_dim]);
5481
5482 /* Reset the chunk offset indices */
5483 HDmemset(scaled, 0, (space_ndims * sizeof(scaled[0])));
5484 scaled[op_dim] = min_mod_chunk_sc[op_dim];
5485
5486 /* Initialize "dims_outside_fill" array */
5487 ndims_outside_fill = 0;
5488 for (u = 0; u < space_ndims; u++)
5489 if ((hssize_t)scaled[u] > max_fill_chunk_sc[u]) {
5490 dims_outside_fill[u] = TRUE;
5491 ndims_outside_fill++;
5492 } /* end if */
5493 else
5494 dims_outside_fill[u] = FALSE;
5495 } /* end else */
5496
5497 carry = FALSE;
5498 while (!carry) {
5499 int i; /* Local index variable */
5500
5501 udata.common.scaled = scaled;
5502
5503 if (0 == ndims_outside_fill) {
5504 HDassert(fill_dim[op_dim]);
5505 HDassert(scaled[op_dim] == min_mod_chunk_sc[op_dim]);
5506
5507 /* Make sure this is an edge chunk */
5508 HDassert(
5509 H5D__chunk_is_partial_edge_chunk(space_ndims, layout->u.chunk.dim, scaled, space_dim));
5510
5511 /* Determine if the chunk just became an unfiltered chunk */
5512 if (new_unfilt_dim[op_dim]) {
5513 new_unfilt_chunk = TRUE;
5514 for (u = 0; u < space_ndims; u++)
5515 if (scaled[u] == min_partial_chunk_sc[u]) {
5516 new_unfilt_chunk = FALSE;
5517 break;
5518 } /* end if */
5519 } /* end if */
5520
5521 /* Make sure that, if we think this is a new unfiltered chunk,
5522 * it was previously not an edge chunk */
5523 HDassert(!new_unfilt_dim[op_dim] ||
5524 (!new_unfilt_chunk != !H5D__chunk_is_partial_edge_chunk(
5525 space_ndims, layout->u.chunk.dim, scaled, old_dim)));
5526 HDassert(!new_unfilt_chunk || new_unfilt_dim[op_dim]);
5527
5528 /* Fill the unused parts of the chunk */
5529 if (H5D__chunk_prune_fill(&udata, new_unfilt_chunk) < 0)
5530 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write fill value")
5531 } /* end if */
5532 else {
5533 H5D_chunk_ud_t chk_udata; /* User data for getting chunk info */
5534
5535 #ifndef NDEBUG
5536 /* Make sure this chunk is really outside the new dimensions */
5537 {
5538 hbool_t outside_dim = FALSE;
5539
5540 for (u = 0; u < space_ndims; u++)
5541 if ((scaled[u] * chunk_dim[u]) >= space_dim[u]) {
5542 outside_dim = TRUE;
5543 break;
5544 } /* end if */
5545 HDassert(outside_dim);
5546 } /* end block */
5547 #endif /* NDEBUG */
5548
5549 /* Check if the chunk exists in cache or on disk */
5550 if (H5D__chunk_lookup(dset, scaled, &chk_udata) < 0)
5551 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk")
5552
5553 /* Evict the entry from the cache if present, but do not flush
5554 * it to disk */
5555 if (UINT_MAX != chk_udata.idx_hint)
5556 if (H5D__chunk_cache_evict(dset, rdcc->slot[chk_udata.idx_hint], FALSE) < 0)
5557 HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to evict chunk")
5558
5559 /* Remove the chunk from disk, if present */
5560 if (H5F_addr_defined(chk_udata.chunk_block.offset)) {
5561 /* Update the offset in idx_udata */
5562 idx_udata.scaled = udata.common.scaled;
5563
5564 /* Remove the chunk from disk */
5565 if ((sc->ops->remove)(&idx_info, &idx_udata) < 0)
5566 HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL,
5567 "unable to remove chunk entry from index")
5568 } /* end if */
5569 } /* end else */
5570
5571 /* Increment indices */
5572 carry = TRUE;
5573 for (i = (int)(space_ndims - 1); i >= 0; --i) {
5574 scaled[i]++;
5575 if (scaled[i] > max_mod_chunk_sc[i]) {
5576 /* Left maximum dimensions, "wrap around" and check if this
5577 * dimension is no longer outside the fill dimension */
5578 if ((unsigned)i == op_dim) {
5579 scaled[i] = min_mod_chunk_sc[i];
5580 if (dims_outside_fill[i] && fill_dim[i]) {
5581 dims_outside_fill[i] = FALSE;
5582 ndims_outside_fill--;
5583 } /* end if */
5584 } /* end if */
5585 else {
5586 scaled[i] = 0;
5587 if (dims_outside_fill[i] && max_fill_chunk_sc[i] >= 0) {
5588 dims_outside_fill[i] = FALSE;
5589 ndims_outside_fill--;
5590 } /* end if */
5591 } /* end else */
5592 } /* end if */
5593 else {
5594 /* Check if we just went outside the fill dimension */
5595 if (!dims_outside_fill[i] && (hssize_t)scaled[i] > max_fill_chunk_sc[i]) {
5596 dims_outside_fill[i] = TRUE;
5597 ndims_outside_fill++;
5598 } /* end if */
5599
5600 /* We found the next chunk, so leave the loop */
5601 carry = FALSE;
5602 break;
5603 } /* end else */
5604 } /* end for */
5605 } /* end while(!carry) */
5606
5607 /* Adjust max_mod_chunk_sc so we don't modify the same chunk twice.
5608 * Also check if this dimension started from 0 (and hence removed all
5609 * of the chunks). */
5610 if (min_mod_chunk_sc[op_dim] == 0)
5611 break;
5612 else
5613 max_mod_chunk_sc[op_dim] = min_mod_chunk_sc[op_dim] - 1;
5614 } /* end for(op_dim=0...) */
5615
5616 /* Reset any cached chunk info for this dataset */
5617 H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
5618
5619 done:
5620 /* Release resources */
5621 if (chunk_space && H5S_close(chunk_space) < 0)
5622 HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
5623 if (udata_init)
5624 if (udata.fb_info_init && H5D__fill_term(&udata.fb_info) < 0)
5625 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
5626
5627 FUNC_LEAVE_NOAPI(ret_value)
5628 } /* end H5D__chunk_prune_by_extent() */
5629
5630 #ifdef H5_HAVE_PARALLEL
5631
5632 /*-------------------------------------------------------------------------
5633 * Function: H5D__chunk_addrmap_cb
5634 *
5635 * Purpose: Callback when obtaining the chunk addresses for all existing chunks
5636 *
5637 * Return: Success: Non-negative
5638 * Failure: Negative
5639 *
5640 * Programmer: Kent Yang
5641 * Tuesday, November 15, 2005
5642 *
5643 *-------------------------------------------------------------------------
5644 */
5645 static int
H5D__chunk_addrmap_cb(const H5D_chunk_rec_t * chunk_rec,void * _udata)5646 H5D__chunk_addrmap_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
5647 {
5648 H5D_chunk_it_ud2_t *udata = (H5D_chunk_it_ud2_t *)_udata; /* User data for callback */
5649 unsigned rank = udata->common.layout->ndims - 1; /* # of dimensions of dataset */
5650 hsize_t chunk_index;
5651
5652 FUNC_ENTER_STATIC_NOERR
5653
5654 /* Compute the index for this chunk */
5655 chunk_index = H5VM_array_offset_pre(rank, udata->common.layout->down_chunks, chunk_rec->scaled);
5656
5657 /* Set it in the userdata to return */
5658 udata->chunk_addr[chunk_index] = chunk_rec->chunk_addr;
5659
5660 FUNC_LEAVE_NOAPI(H5_ITER_CONT)
5661 } /* H5D__chunk_addrmap_cb() */
5662
5663 /*-------------------------------------------------------------------------
5664 * Function: H5D__chunk_addrmap
5665 *
5666 * Purpose: Obtain the chunk addresses for all existing chunks
5667 *
5668 * Return: Success: Non-negative on succeed.
5669 * Failure: negative value
5670 *
5671 * Programmer: Kent Yang
5672 * November 15, 2005
5673 *
5674 *-------------------------------------------------------------------------
5675 */
5676 herr_t
H5D__chunk_addrmap(const H5D_io_info_t * io_info,haddr_t chunk_addr[])5677 H5D__chunk_addrmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[])
5678 {
5679 H5D_chk_idx_info_t idx_info; /* Chunked index info */
5680 const H5D_t * dset = io_info->dset; /* Local pointer to dataset info */
5681 H5D_chunk_it_ud2_t udata; /* User data for iteration callback */
5682 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
5683 herr_t ret_value = SUCCEED; /* Return value */
5684
5685 FUNC_ENTER_PACKAGE
5686
5687 HDassert(dset);
5688 HDassert(dset->shared);
5689 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
5690 HDassert(chunk_addr);
5691
5692 /* Set up user data for B-tree callback */
5693 HDmemset(&udata, 0, sizeof(udata));
5694 udata.common.layout = &dset->shared->layout.u.chunk;
5695 udata.common.storage = sc;
5696 udata.chunk_addr = chunk_addr;
5697
5698 /* Compose chunked index info struct */
5699 idx_info.f = dset->oloc.file;
5700 idx_info.pline = &dset->shared->dcpl_cache.pline;
5701 idx_info.layout = &dset->shared->layout.u.chunk;
5702 idx_info.storage = sc;
5703
5704 /* Iterate over chunks to build mapping of chunk addresses */
5705 if ((sc->ops->iterate)(&idx_info, H5D__chunk_addrmap_cb, &udata) < 0)
5706 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to iterate over chunk index to build address map")
5707
5708 done:
5709 FUNC_LEAVE_NOAPI(ret_value)
5710 } /* end H5D__chunk_addrmap() */
5711 #endif /* H5_HAVE_PARALLEL */
5712
5713 /*-------------------------------------------------------------------------
5714 * Function: H5D__chunk_delete
5715 *
5716 * Purpose: Delete raw data storage for entire dataset (i.e. all chunks)
5717 *
5718 * Return: Success: Non-negative
5719 * Failure: negative
5720 *
5721 * Programmer: Quincey Koziol
5722 * Thursday, March 20, 2003
5723 *
5724 *-------------------------------------------------------------------------
5725 */
5726 herr_t
H5D__chunk_delete(H5F_t * f,H5O_t * oh,H5O_storage_t * storage)5727 H5D__chunk_delete(H5F_t *f, H5O_t *oh, H5O_storage_t *storage)
5728 {
5729 H5D_chk_idx_info_t idx_info; /* Chunked index info */
5730 H5O_layout_t layout; /* Dataset layout message */
5731 hbool_t layout_read = FALSE; /* Whether the layout message was read from the file */
5732 H5O_pline_t pline; /* I/O pipeline message */
5733 hbool_t pline_read = FALSE; /* Whether the I/O pipeline message was read from the file */
5734 htri_t exists; /* Flag if header message of interest exists */
5735 herr_t ret_value = SUCCEED; /* Return value */
5736
5737 FUNC_ENTER_PACKAGE
5738
5739 /* Sanity check */
5740 HDassert(f);
5741 HDassert(oh);
5742 HDassert(storage);
5743 H5D_CHUNK_STORAGE_INDEX_CHK(&storage->u.chunk);
5744
5745 /* Check for I/O pipeline message */
5746 if ((exists = H5O_msg_exists_oh(oh, H5O_PLINE_ID)) < 0)
5747 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to check for object header message")
5748 else if (exists) {
5749 if (NULL == H5O_msg_read_oh(f, oh, H5O_PLINE_ID, &pline))
5750 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get I/O pipeline message")
5751 pline_read = TRUE;
5752 } /* end else if */
5753 else
5754 HDmemset(&pline, 0, sizeof(pline));
5755
5756 /* Retrieve dataset layout message */
5757 if ((exists = H5O_msg_exists_oh(oh, H5O_LAYOUT_ID)) < 0)
5758 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to check for object header message")
5759 else if (exists) {
5760 if (NULL == H5O_msg_read_oh(f, oh, H5O_LAYOUT_ID, &layout))
5761 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get layout message")
5762 layout_read = TRUE;
5763 } /* end else if */
5764 else
5765 HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, FAIL, "can't find layout message")
5766
5767 /* Compose chunked index info struct */
5768 idx_info.f = f;
5769 idx_info.pline = &pline;
5770 idx_info.layout = &layout.u.chunk;
5771 idx_info.storage = &storage->u.chunk;
5772
5773 /* Delete the chunked storage information in the file */
5774 if ((storage->u.chunk.ops->idx_delete)(&idx_info) < 0)
5775 HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk index")
5776
5777 done:
5778 /* Clean up any messages read in */
5779 if (pline_read)
5780 if (H5O_msg_reset(H5O_PLINE_ID, &pline) < 0)
5781 HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset I/O pipeline message")
5782 if (layout_read)
5783 if (H5O_msg_reset(H5O_LAYOUT_ID, &layout) < 0)
5784 HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset layout message")
5785
5786 FUNC_LEAVE_NOAPI(ret_value)
5787 } /* end H5D__chunk_delete() */
5788
5789 /*-------------------------------------------------------------------------
5790 * Function: H5D__chunk_update_cache
5791 *
5792 * Purpose: Update any cached chunks index values after the dataspace
5793 * size has changed
5794 *
5795 * Return: Success: Non-negative
5796 * Failure: negative
5797 *
5798 * Programmer: Quincey Koziol
5799 * Saturday, May 29, 2004
5800 *
5801 *-------------------------------------------------------------------------
5802 */
5803 herr_t
H5D__chunk_update_cache(H5D_t * dset)5804 H5D__chunk_update_cache(H5D_t *dset)
5805 {
5806 H5D_rdcc_t * rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache */
5807 H5D_rdcc_ent_t *ent, *next; /*cache entry */
5808 H5D_rdcc_ent_t tmp_head; /* Sentinel entry for temporary entry list */
5809 H5D_rdcc_ent_t *tmp_tail; /* Tail pointer for temporary entry list */
5810 herr_t ret_value = SUCCEED; /* Return value */
5811
5812 FUNC_ENTER_PACKAGE
5813
5814 /* Check args */
5815 HDassert(dset && H5D_CHUNKED == dset->shared->layout.type);
5816 HDassert(dset->shared->layout.u.chunk.ndims > 0 &&
5817 dset->shared->layout.u.chunk.ndims <= H5O_LAYOUT_NDIMS);
5818
5819 /* Check the rank */
5820 HDassert((dset->shared->layout.u.chunk.ndims - 1) > 1);
5821
5822 /* Add temporary entry list to rdcc */
5823 (void)HDmemset(&tmp_head, 0, sizeof(tmp_head));
5824 rdcc->tmp_head = &tmp_head;
5825 tmp_tail = &tmp_head;
5826
5827 /* Recompute the index for each cached chunk that is in a dataset */
5828 for (ent = rdcc->head; ent; ent = next) {
5829 unsigned old_idx; /* Previous index number */
5830
5831 /* Get the pointer to the next cache entry */
5832 next = ent->next;
5833
5834 /* Compute the index for the chunk entry */
5835 old_idx = ent->idx; /* Save for later */
5836 ent->idx = H5D__chunk_hash_val(dset->shared, ent->scaled);
5837
5838 if (old_idx != ent->idx) {
5839 H5D_rdcc_ent_t *old_ent; /* Old cache entry */
5840
5841 /* Check if there is already a chunk at this chunk's new location */
5842 old_ent = rdcc->slot[ent->idx];
5843 if (old_ent != NULL) {
5844 HDassert(old_ent->locked == FALSE);
5845 HDassert(old_ent->deleted == FALSE);
5846
5847 /* Insert the old entry into the temporary list, but do not
5848 * evict (yet). Make sure we do not make any calls to the index
5849 * until all chunks have updated indices! */
5850 HDassert(!old_ent->tmp_next);
5851 HDassert(!old_ent->tmp_prev);
5852 tmp_tail->tmp_next = old_ent;
5853 old_ent->tmp_prev = tmp_tail;
5854 tmp_tail = old_ent;
5855 } /* end if */
5856
5857 /* Insert this chunk into correct location in hash table */
5858 rdcc->slot[ent->idx] = ent;
5859
5860 /* If this chunk was previously on the temporary list and therefore
5861 * not in the hash table, remove it from the temporary list.
5862 * Otherwise clear the old hash table slot. */
5863 if (ent->tmp_prev) {
5864 HDassert(tmp_head.tmp_next);
5865 HDassert(tmp_tail != &tmp_head);
5866 ent->tmp_prev->tmp_next = ent->tmp_next;
5867 if (ent->tmp_next) {
5868 ent->tmp_next->tmp_prev = ent->tmp_prev;
5869 ent->tmp_next = NULL;
5870 } /* end if */
5871 else {
5872 HDassert(tmp_tail == ent);
5873 tmp_tail = ent->tmp_prev;
5874 } /* end else */
5875 ent->tmp_prev = NULL;
5876 } /* end if */
5877 else
5878 rdcc->slot[old_idx] = NULL;
5879 } /* end if */
5880 } /* end for */
5881
5882 /* tmp_tail is no longer needed, and will be invalidated by
5883 * H5D_chunk_cache_evict anyways. */
5884 tmp_tail = NULL;
5885
5886 /* Evict chunks that are still on the temporary list */
5887 while (tmp_head.tmp_next) {
5888 ent = tmp_head.tmp_next;
5889
5890 /* Remove the old entry from the cache */
5891 if (H5D__chunk_cache_evict(dset, ent, TRUE) < 0)
5892 HGOTO_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks")
5893 } /* end while */
5894
5895 done:
5896 /* Remove temporary list from rdcc */
5897 rdcc->tmp_head = NULL;
5898
5899 FUNC_LEAVE_NOAPI(ret_value)
5900 } /* end H5D__chunk_update_cache() */
5901
5902 /*-------------------------------------------------------------------------
5903 * Function: H5D__chunk_copy_cb
5904 *
5905 * Purpose: Copy chunked raw data from source file and insert to the
5906 * index in the destination file
5907 *
5908 * Return: Non-negative on success/Negative on failure
5909 *
5910 * Programmer: Peter Cao
5911 * August 20, 2005
5912 *
5913 *-------------------------------------------------------------------------
5914 */
5915 static int
H5D__chunk_copy_cb(const H5D_chunk_rec_t * chunk_rec,void * _udata)5916 H5D__chunk_copy_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
5917 {
5918 H5D_chunk_it_ud3_t *udata = (H5D_chunk_it_ud3_t *)_udata; /* User data for callback */
5919 H5D_chunk_ud_t udata_dst; /* User data about new destination chunk */
5920 hbool_t is_vlen = FALSE; /* Whether datatype is variable-length */
5921 hbool_t fix_ref = FALSE; /* Whether to fix up references in the dest. file */
5922 hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
5923
5924 /* General information about chunk copy */
5925 void * bkg = udata->bkg; /* Background buffer for datatype conversion */
5926 void * buf = udata->buf; /* Chunk buffer for I/O & datatype conversions */
5927 size_t buf_size = udata->buf_size; /* Size of chunk buffer */
5928 const H5O_pline_t *pline = udata->pline; /* I/O pipeline for applying filters */
5929
5930 /* needed for commpressed variable length data */
5931 hbool_t must_filter = FALSE; /* Whether chunk must be filtered during copy */
5932 size_t nbytes; /* Size of chunk in file (in bytes) */
5933 H5Z_cb_t filter_cb; /* Filter failure callback struct */
5934 int ret_value = H5_ITER_CONT; /* Return value */
5935
5936 FUNC_ENTER_STATIC
5937
5938 /* Get 'size_t' local value for number of bytes in chunk */
5939 H5_CHECKED_ASSIGN(nbytes, size_t, chunk_rec->nbytes, uint32_t);
5940
5941 /* Initialize the filter callback struct */
5942 filter_cb.op_data = NULL;
5943 filter_cb.func = NULL; /* no callback function when failed */
5944
5945 /* Check for filtered chunks */
5946 /* Check for an edge chunk that is not filtered */
5947 if (pline && pline->nused) {
5948 must_filter = TRUE;
5949 if ((udata->common.layout->flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) &&
5950 H5D__chunk_is_partial_edge_chunk(udata->dset_ndims, udata->common.layout->dim, chunk_rec->scaled,
5951 udata->dset_dims))
5952 must_filter = FALSE;
5953 }
5954
5955 /* Check parameter for type conversion */
5956 if (udata->do_convert) {
5957 if (H5T_detect_class(udata->dt_src, H5T_VLEN, FALSE) > 0)
5958 is_vlen = TRUE;
5959 else if ((H5T_get_class(udata->dt_src, FALSE) == H5T_REFERENCE) &&
5960 (udata->file_src != udata->idx_info_dst->f))
5961 fix_ref = TRUE;
5962 else
5963 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy dataset elements")
5964 } /* end if */
5965
5966 /* Resize the buf if it is too small to hold the data */
5967 if (nbytes > buf_size) {
5968 void *new_buf; /* New buffer for data */
5969
5970 /* Re-allocate memory for copying the chunk */
5971 if (NULL == (new_buf = H5MM_realloc(udata->buf, nbytes)))
5972 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR,
5973 "memory allocation failed for raw data chunk")
5974 udata->buf = new_buf;
5975 if (udata->bkg) {
5976 if (NULL == (new_buf = H5MM_realloc(udata->bkg, nbytes)))
5977 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR,
5978 "memory allocation failed for raw data chunk")
5979 udata->bkg = new_buf;
5980 if (!udata->cpy_info->expand_ref)
5981 HDmemset((uint8_t *)udata->bkg + buf_size, 0, (size_t)(nbytes - buf_size));
5982
5983 bkg = udata->bkg;
5984 } /* end if */
5985
5986 buf = udata->buf;
5987 udata->buf_size = buf_size = nbytes;
5988 } /* end if */
5989
5990 if (udata->chunk_in_cache && udata->chunk) {
5991 HDassert(!H5F_addr_defined(chunk_rec->chunk_addr));
5992 H5MM_memcpy(buf, udata->chunk, nbytes);
5993 udata->chunk = NULL;
5994 }
5995 else {
5996 H5D_rdcc_ent_t *ent = NULL; /* Cache entry */
5997 unsigned idx; /* Index of chunk in cache, if present */
5998 unsigned u; /* Counter */
5999 H5D_shared_t * shared_fo = (H5D_shared_t *)udata->cpy_info->shared_fo;
6000
6001 /* See if the written chunk is in the chunk cache */
6002 if (shared_fo && shared_fo->cache.chunk.nslots > 0) {
6003 /* Determine the chunk's location in the hash table */
6004 idx = H5D__chunk_hash_val(shared_fo, chunk_rec->scaled);
6005
6006 /* Get the chunk cache entry for that location */
6007 ent = shared_fo->cache.chunk.slot[idx];
6008 if (ent) {
6009 /* Speculatively set the 'found' flag */
6010 udata->chunk_in_cache = TRUE;
6011
6012 /* Verify that the cache entry is the correct chunk */
6013 for (u = 0; u < shared_fo->ndims; u++)
6014 if (chunk_rec->scaled[u] != ent->scaled[u]) {
6015 udata->chunk_in_cache = FALSE;
6016 break;
6017 } /* end if */
6018 } /* end if */
6019 } /* end if */
6020
6021 if (udata->chunk_in_cache) {
6022 HDassert(H5F_addr_defined(chunk_rec->chunk_addr));
6023 HDassert(H5F_addr_defined(ent->chunk_block.offset));
6024
6025 H5_CHECKED_ASSIGN(nbytes, size_t, shared_fo->layout.u.chunk.size, uint32_t);
6026 H5MM_memcpy(buf, ent->chunk, nbytes);
6027 }
6028 else {
6029 /* read chunk data from the source file */
6030 if (H5F_block_read(udata->file_src, H5FD_MEM_DRAW, chunk_rec->chunk_addr, nbytes, buf) < 0)
6031 HGOTO_ERROR(H5E_IO, H5E_READERROR, H5_ITER_ERROR, "unable to read raw data chunk")
6032 }
6033 }
6034
6035 /* Need to uncompress filtered variable-length & reference data elements that are not found in chunk cache
6036 */
6037 if (must_filter && (is_vlen || fix_ref) && !udata->chunk_in_cache) {
6038 unsigned filter_mask = chunk_rec->filter_mask;
6039
6040 if (H5Z_pipeline(pline, H5Z_FLAG_REVERSE, &filter_mask, H5Z_NO_EDC, filter_cb, &nbytes, &buf_size,
6041 &buf) < 0)
6042 HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, H5_ITER_ERROR, "data pipeline read failed")
6043 } /* end if */
6044
6045 /* Perform datatype conversion, if necessary */
6046 if (is_vlen) {
6047 H5T_path_t *tpath_src_mem = udata->tpath_src_mem;
6048 H5T_path_t *tpath_mem_dst = udata->tpath_mem_dst;
6049 H5S_t * buf_space = udata->buf_space;
6050 hid_t tid_src = udata->tid_src;
6051 hid_t tid_dst = udata->tid_dst;
6052 hid_t tid_mem = udata->tid_mem;
6053 void * reclaim_buf = udata->reclaim_buf;
6054 size_t reclaim_buf_size = udata->reclaim_buf_size;
6055
6056 /* Convert from source file to memory */
6057 H5_CHECK_OVERFLOW(udata->nelmts, uint32_t, size_t);
6058 if (H5T_convert(tpath_src_mem, tid_src, tid_mem, (size_t)udata->nelmts, (size_t)0, (size_t)0, buf,
6059 bkg) < 0)
6060 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "datatype conversion failed")
6061
6062 /* Copy into another buffer, to reclaim memory later */
6063 H5MM_memcpy(reclaim_buf, buf, reclaim_buf_size);
6064
6065 /* Set background buffer to all zeros */
6066 HDmemset(bkg, 0, buf_size);
6067
6068 /* Convert from memory to destination file */
6069 if (H5T_convert(tpath_mem_dst, tid_mem, tid_dst, udata->nelmts, (size_t)0, (size_t)0, buf, bkg) < 0)
6070 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "datatype conversion failed")
6071
6072 /* Reclaim space from variable length data */
6073 if (H5T_reclaim(tid_mem, buf_space, reclaim_buf) < 0)
6074 HGOTO_ERROR(H5E_DATASET, H5E_BADITER, H5_ITER_ERROR, "unable to reclaim variable-length data")
6075 } /* end if */
6076 else if (fix_ref) {
6077 /* Check for expanding references */
6078 /* (background buffer has already been zeroed out, if not expanding) */
6079 if (udata->cpy_info->expand_ref) {
6080 /* Copy the reference elements */
6081 if (H5O_copy_expand_ref(udata->file_src, udata->tid_src, udata->dt_src, buf, nbytes,
6082 udata->idx_info_dst->f, bkg, udata->cpy_info) < 0)
6083 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy reference attribute")
6084 } /* end if */
6085
6086 /* After fix ref, copy the new reference elements to the buffer to write out */
6087 H5MM_memcpy(buf, bkg, buf_size);
6088 } /* end if */
6089
6090 /* Set up destination chunk callback information for insertion */
6091 udata_dst.common.layout = udata->idx_info_dst->layout;
6092 udata_dst.common.storage = udata->idx_info_dst->storage;
6093 udata_dst.common.scaled = chunk_rec->scaled;
6094 udata_dst.chunk_block.offset = HADDR_UNDEF;
6095 udata_dst.chunk_block.length = chunk_rec->nbytes;
6096 udata_dst.filter_mask = chunk_rec->filter_mask;
6097
6098 /* Need to compress variable-length or reference data elements or a chunk found in cache before writing to
6099 * file */
6100 if (must_filter && (is_vlen || fix_ref || udata->chunk_in_cache)) {
6101 if (H5Z_pipeline(pline, 0, &(udata_dst.filter_mask), H5Z_NO_EDC, filter_cb, &nbytes, &buf_size,
6102 &buf) < 0)
6103 HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, H5_ITER_ERROR, "output pipeline failed")
6104 #if H5_SIZEOF_SIZE_T > 4
6105 /* Check for the chunk expanding too much to encode in a 32-bit value */
6106 if (nbytes > ((size_t)0xffffffff))
6107 HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, H5_ITER_ERROR, "chunk too large for 32-bit length")
6108 #endif /* H5_SIZEOF_SIZE_T > 4 */
6109 H5_CHECKED_ASSIGN(udata_dst.chunk_block.length, uint32_t, nbytes, size_t);
6110 udata->buf = buf;
6111 udata->buf_size = buf_size;
6112 } /* end if */
6113
6114 udata->chunk_in_cache = FALSE;
6115
6116 udata_dst.chunk_idx =
6117 H5VM_array_offset_pre(udata_dst.common.layout->ndims - 1, udata_dst.common.layout->max_down_chunks,
6118 udata_dst.common.scaled);
6119
6120 /* Allocate chunk in the file */
6121 if (H5D__chunk_file_alloc(udata->idx_info_dst, NULL, &udata_dst.chunk_block, &need_insert,
6122 udata_dst.common.scaled) < 0)
6123 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert/resize chunk on chunk level")
6124
6125 /* Write chunk data to destination file */
6126 HDassert(H5F_addr_defined(udata_dst.chunk_block.offset));
6127 if (H5F_block_write(udata->idx_info_dst->f, H5FD_MEM_DRAW, udata_dst.chunk_block.offset, nbytes, buf) < 0)
6128 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, H5_ITER_ERROR, "unable to write raw data to file")
6129
6130 /* Set metadata tag in API context */
6131 H5_BEGIN_TAG(H5AC__COPIED_TAG);
6132
6133 /* Insert chunk record into index */
6134 if (need_insert && udata->idx_info_dst->storage->ops->insert)
6135 if ((udata->idx_info_dst->storage->ops->insert)(udata->idx_info_dst, &udata_dst, NULL) < 0)
6136 HGOTO_ERROR_TAG(H5E_DATASET, H5E_CANTINSERT, H5_ITER_ERROR,
6137 "unable to insert chunk addr into index")
6138
6139 /* Reset metadata tag in API context */
6140 H5_END_TAG
6141
6142 done:
6143 FUNC_LEAVE_NOAPI(ret_value)
6144 } /* end H5D__chunk_copy_cb() */
6145
6146 /*-------------------------------------------------------------------------
6147 * Function: H5D__chunk_copy
6148 *
6149 * Purpose: Copy chunked storage from SRC file to DST file.
6150 *
6151 * Return: Success: Non-negative
6152 * Failure: negative
6153 *
6154 * Programmer: Peter Cao
6155 * August 20, 2005
6156 *
6157 *-------------------------------------------------------------------------
6158 */
6159 herr_t
H5D__chunk_copy(H5F_t * f_src,H5O_storage_chunk_t * storage_src,H5O_layout_chunk_t * layout_src,H5F_t * f_dst,H5O_storage_chunk_t * storage_dst,const H5S_extent_t * ds_extent_src,H5T_t * dt_src,const H5O_pline_t * pline_src,H5O_copy_t * cpy_info)6160 H5D__chunk_copy(H5F_t *f_src, H5O_storage_chunk_t *storage_src, H5O_layout_chunk_t *layout_src, H5F_t *f_dst,
6161 H5O_storage_chunk_t *storage_dst, const H5S_extent_t *ds_extent_src, H5T_t *dt_src,
6162 const H5O_pline_t *pline_src, H5O_copy_t *cpy_info)
6163 {
6164 H5D_chunk_it_ud3_t udata; /* User data for iteration callback */
6165 H5D_chk_idx_info_t idx_info_dst; /* Dest. chunked index info */
6166 H5D_chk_idx_info_t idx_info_src; /* Source chunked index info */
6167 int sndims; /* Rank of dataspace */
6168 hsize_t curr_dims[H5O_LAYOUT_NDIMS]; /* Curr. size of dataset dimensions */
6169 hsize_t max_dims[H5O_LAYOUT_NDIMS]; /* Curr. size of dataset dimensions */
6170 H5O_pline_t _pline; /* Temporary pipeline info */
6171 const H5O_pline_t *pline; /* Pointer to pipeline info to use */
6172 H5T_path_t * tpath_src_mem = NULL, *tpath_mem_dst = NULL; /* Datatype conversion paths */
6173 hid_t tid_src = -1; /* Datatype ID for source datatype */
6174 hid_t tid_dst = -1; /* Datatype ID for destination datatype */
6175 hid_t tid_mem = -1; /* Datatype ID for memory datatype */
6176 size_t buf_size; /* Size of copy buffer */
6177 size_t reclaim_buf_size; /* Size of reclaim buffer */
6178 void * buf = NULL; /* Buffer for copying data */
6179 void * bkg = NULL; /* Buffer for background during type conversion */
6180 void * reclaim_buf = NULL; /* Buffer for reclaiming data */
6181 H5S_t * buf_space = NULL; /* Dataspace describing buffer */
6182 hid_t sid_buf = -1; /* ID for buffer dataspace */
6183 uint32_t nelmts = 0; /* Number of elements in buffer */
6184 hbool_t do_convert = FALSE; /* Indicate that type conversions should be performed */
6185 hbool_t copy_setup_done = FALSE; /* Indicate that 'copy setup' is done */
6186 herr_t ret_value = SUCCEED; /* Return value */
6187
6188 FUNC_ENTER_PACKAGE
6189
6190 /* Check args */
6191 HDassert(f_src);
6192 HDassert(storage_src);
6193 H5D_CHUNK_STORAGE_INDEX_CHK(storage_src);
6194 HDassert(layout_src);
6195 HDassert(f_dst);
6196 HDassert(storage_dst);
6197 H5D_CHUNK_STORAGE_INDEX_CHK(storage_dst);
6198 HDassert(ds_extent_src);
6199 HDassert(dt_src);
6200
6201 /* Initialize the temporary pipeline info */
6202 if (NULL == pline_src) {
6203 HDmemset(&_pline, 0, sizeof(_pline));
6204 pline = &_pline;
6205 } /* end if */
6206 else
6207 pline = pline_src;
6208
6209 /* Layout is not created in the destination file, reset index address */
6210 if (H5D_chunk_idx_reset(storage_dst, TRUE) < 0)
6211 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to reset chunked storage index in dest")
6212
6213 /* Initialize layout information */
6214 {
6215 unsigned ndims; /* Rank of dataspace */
6216
6217 /* Get the dim info for dataset */
6218 if ((sndims = H5S_extent_get_dims(ds_extent_src, curr_dims, max_dims)) < 0)
6219 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataspace dimensions")
6220 H5_CHECKED_ASSIGN(ndims, unsigned, sndims, int);
6221
6222 /* Set the source layout chunk information */
6223 if (H5D__chunk_set_info_real(layout_src, ndims, curr_dims, max_dims) < 0)
6224 HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set layout's chunk info")
6225 } /* end block */
6226
6227 /* Compose source & dest chunked index info structs */
6228 idx_info_src.f = f_src;
6229 idx_info_src.pline = pline;
6230 idx_info_src.layout = layout_src;
6231 idx_info_src.storage = storage_src;
6232
6233 idx_info_dst.f = f_dst;
6234 idx_info_dst.pline = pline; /* Use same I/O filter pipeline for dest. */
6235 idx_info_dst.layout = layout_src /* Use same layout for dest. */;
6236 idx_info_dst.storage = storage_dst;
6237
6238 /* Call the index-specific "copy setup" routine */
6239 if ((storage_src->ops->copy_setup)(&idx_info_src, &idx_info_dst) < 0)
6240 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
6241 "unable to set up index-specific chunk copying information")
6242 copy_setup_done = TRUE;
6243
6244 /* Create datatype ID for src datatype */
6245 if ((tid_src = H5I_register(H5I_DATATYPE, dt_src, FALSE)) < 0)
6246 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register source file datatype")
6247
6248 /* If there's a VLEN source datatype, set up type conversion information */
6249 if (H5T_detect_class(dt_src, H5T_VLEN, FALSE) > 0) {
6250 H5T_t * dt_dst; /* Destination datatype */
6251 H5T_t * dt_mem; /* Memory datatype */
6252 size_t mem_dt_size; /* Memory datatype size */
6253 size_t tmp_dt_size; /* Temp. datatype size */
6254 size_t max_dt_size; /* Max atatype size */
6255 hsize_t buf_dim; /* Dimension for buffer */
6256 unsigned u;
6257
6258 /* create a memory copy of the variable-length datatype */
6259 if (NULL == (dt_mem = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
6260 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
6261 if ((tid_mem = H5I_register(H5I_DATATYPE, dt_mem, FALSE)) < 0) {
6262 (void)H5T_close_real(dt_mem);
6263 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register memory datatype")
6264 } /* end if */
6265
6266 /* create variable-length datatype at the destinaton file */
6267 if (NULL == (dt_dst = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
6268 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
6269 if (H5T_set_loc(dt_dst, H5F_VOL_OBJ(f_dst), H5T_LOC_DISK) < 0) {
6270 (void)H5T_close_real(dt_dst);
6271 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "cannot mark datatype on disk")
6272 } /* end if */
6273 if ((tid_dst = H5I_register(H5I_DATATYPE, dt_dst, FALSE)) < 0) {
6274 (void)H5T_close_real(dt_dst);
6275 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register destination file datatype")
6276 } /* end if */
6277
6278 /* Set up the conversion functions */
6279 if (NULL == (tpath_src_mem = H5T_path_find(dt_src, dt_mem)))
6280 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between src and mem datatypes")
6281 if (NULL == (tpath_mem_dst = H5T_path_find(dt_mem, dt_dst)))
6282 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between mem and dst datatypes")
6283
6284 /* Determine largest datatype size */
6285 if (0 == (max_dt_size = H5T_get_size(dt_src)))
6286 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
6287 if (0 == (mem_dt_size = H5T_get_size(dt_mem)))
6288 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
6289 max_dt_size = MAX(max_dt_size, mem_dt_size);
6290 if (0 == (tmp_dt_size = H5T_get_size(dt_dst)))
6291 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
6292 max_dt_size = MAX(max_dt_size, tmp_dt_size);
6293
6294 /* Compute the number of elements per chunk */
6295 nelmts = 1;
6296 for (u = 0; u < (layout_src->ndims - 1); u++)
6297 nelmts *= layout_src->dim[u];
6298
6299 /* Create the space and set the initial extent */
6300 buf_dim = nelmts;
6301 if (NULL == (buf_space = H5S_create_simple((unsigned)1, &buf_dim, NULL)))
6302 HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
6303
6304 /* Atomize */
6305 if ((sid_buf = H5I_register(H5I_DATASPACE, buf_space, FALSE)) < 0) {
6306 (void)H5S_close(buf_space);
6307 HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
6308 } /* end if */
6309
6310 /* Set initial buffer sizes */
6311 buf_size = nelmts * max_dt_size;
6312 reclaim_buf_size = nelmts * mem_dt_size;
6313
6314 /* Allocate memory for reclaim buf */
6315 if (NULL == (reclaim_buf = H5MM_malloc(reclaim_buf_size)))
6316 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk")
6317
6318 /* Indicate that type conversion should be performed */
6319 do_convert = TRUE;
6320 } /* end if */
6321 else {
6322 if (H5T_get_class(dt_src, FALSE) == H5T_REFERENCE) {
6323 /* Indicate that type conversion should be performed */
6324 do_convert = TRUE;
6325 } /* end if */
6326
6327 H5_CHECKED_ASSIGN(buf_size, size_t, layout_src->size, uint32_t);
6328 reclaim_buf_size = 0;
6329 } /* end else */
6330
6331 /* Set up conversion buffer, if appropriate */
6332 if (do_convert) {
6333 /* Allocate background memory for converting the chunk */
6334 if (NULL == (bkg = H5MM_malloc(buf_size)))
6335 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk")
6336
6337 /* Check for reference datatype and no expanding references & clear background buffer */
6338 if (!cpy_info->expand_ref && ((H5T_get_class(dt_src, FALSE) == H5T_REFERENCE) && (f_src != f_dst)))
6339 /* Reset value to zero */
6340 HDmemset(bkg, 0, buf_size);
6341 } /* end if */
6342
6343 /* Allocate memory for copying the chunk */
6344 if (NULL == (buf = H5MM_malloc(buf_size)))
6345 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk")
6346
6347 /* Initialize the callback structure for the source */
6348 HDmemset(&udata, 0, sizeof udata);
6349 udata.common.layout = layout_src;
6350 udata.common.storage = storage_src;
6351 udata.file_src = f_src;
6352 udata.idx_info_dst = &idx_info_dst;
6353 udata.buf = buf;
6354 udata.bkg = bkg;
6355 udata.buf_size = buf_size;
6356 udata.tid_src = tid_src;
6357 udata.tid_mem = tid_mem;
6358 udata.tid_dst = tid_dst;
6359 udata.dt_src = dt_src;
6360 udata.do_convert = do_convert;
6361 udata.tpath_src_mem = tpath_src_mem;
6362 udata.tpath_mem_dst = tpath_mem_dst;
6363 udata.reclaim_buf = reclaim_buf;
6364 udata.reclaim_buf_size = reclaim_buf_size;
6365 udata.buf_space = buf_space;
6366 udata.nelmts = nelmts;
6367 udata.pline = pline;
6368 udata.dset_ndims = (unsigned)sndims;
6369 udata.dset_dims = curr_dims;
6370 udata.cpy_info = cpy_info;
6371 udata.chunk_in_cache = FALSE;
6372 udata.chunk = NULL;
6373
6374 /* Iterate over chunks to copy data */
6375 if ((storage_src->ops->iterate)(&idx_info_src, H5D__chunk_copy_cb, &udata) < 0)
6376 HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk index to copy data")
6377
6378 /* Iterate over the chunk cache to copy data for chunks with undefined address */
6379 if (udata.cpy_info->shared_fo) {
6380 H5D_rdcc_ent_t *ent, *next;
6381 H5D_chunk_rec_t chunk_rec;
6382 H5D_shared_t * shared_fo = (H5D_shared_t *)udata.cpy_info->shared_fo;
6383
6384 chunk_rec.nbytes = layout_src->size;
6385 chunk_rec.filter_mask = 0;
6386 chunk_rec.chunk_addr = HADDR_UNDEF;
6387
6388 for (ent = shared_fo->cache.chunk.head; ent; ent = next) {
6389 if (!H5F_addr_defined(ent->chunk_block.offset)) {
6390 H5MM_memcpy(chunk_rec.scaled, ent->scaled, sizeof(chunk_rec.scaled));
6391 udata.chunk = ent->chunk;
6392 udata.chunk_in_cache = TRUE;
6393 if (H5D__chunk_copy_cb(&chunk_rec, &udata) < 0)
6394 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy chunk data in cache")
6395 }
6396 next = ent->next;
6397 } /* end for */
6398 }
6399
6400 /* I/O buffers may have been re-allocated */
6401 buf = udata.buf;
6402 bkg = udata.bkg;
6403
6404 done:
6405 if (sid_buf > 0 && H5I_dec_ref(sid_buf) < 0)
6406 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't decrement temporary dataspace ID")
6407 if (tid_src > 0 && H5I_dec_ref(tid_src) < 0)
6408 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
6409 if (tid_dst > 0 && H5I_dec_ref(tid_dst) < 0)
6410 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
6411 if (tid_mem > 0 && H5I_dec_ref(tid_mem) < 0)
6412 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
6413 if (buf)
6414 H5MM_xfree(buf);
6415 if (bkg)
6416 H5MM_xfree(bkg);
6417 if (reclaim_buf)
6418 H5MM_xfree(reclaim_buf);
6419
6420 /* Clean up any index information */
6421 if (copy_setup_done)
6422 if (storage_src->ops->copy_shutdown &&
6423 (storage_src->ops->copy_shutdown)(storage_src, storage_dst) < 0)
6424 HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to shut down index copying info")
6425
6426 FUNC_LEAVE_NOAPI(ret_value)
6427 } /* end H5D__chunk_copy() */
6428
6429 /*-------------------------------------------------------------------------
6430 * Function: H5D__chunk_bh_info
6431 *
6432 * Purpose: Retrieve the amount of index storage for chunked dataset
6433 *
6434 * Return: Success: Non-negative
6435 * Failure: negative
6436 *
6437 * Programmer: Vailin Choi
6438 * June 8, 2007
6439 *
6440 *-------------------------------------------------------------------------
6441 */
6442 herr_t
H5D__chunk_bh_info(const H5O_loc_t * loc,H5O_t * oh,H5O_layout_t * layout,hsize_t * index_size)6443 H5D__chunk_bh_info(const H5O_loc_t *loc, H5O_t *oh, H5O_layout_t *layout, hsize_t *index_size)
6444 {
6445 H5D_chk_idx_info_t idx_info; /* Chunked index info */
6446 H5S_t * space = NULL; /* Dataset's dataspace */
6447 H5O_pline_t pline; /* I/O pipeline message */
6448 H5O_storage_chunk_t *sc = &(layout->storage.u.chunk);
6449 htri_t exists; /* Flag if header message of interest exists */
6450 hbool_t idx_info_init = FALSE; /* Whether the chunk index info has been initialized */
6451 hbool_t pline_read = FALSE; /* Whether the I/O pipeline message was read */
6452 herr_t ret_value = SUCCEED; /* Return value */
6453
6454 FUNC_ENTER_PACKAGE
6455
6456 /* Check args */
6457 HDassert(loc);
6458 HDassert(loc->file);
6459 HDassert(H5F_addr_defined(loc->addr));
6460 HDassert(layout);
6461 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
6462 HDassert(index_size);
6463
6464 /* Check for I/O pipeline message */
6465 if ((exists = H5O_msg_exists_oh(oh, H5O_PLINE_ID)) < 0)
6466 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read object header")
6467 else if (exists) {
6468 if (NULL == H5O_msg_read_oh(loc->file, oh, H5O_PLINE_ID, &pline))
6469 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't find I/O pipeline message")
6470 pline_read = TRUE;
6471 } /* end else if */
6472 else
6473 HDmemset(&pline, 0, sizeof(pline));
6474
6475 /* Compose chunked index info struct */
6476 idx_info.f = loc->file;
6477 idx_info.pline = &pline;
6478 idx_info.layout = &layout->u.chunk;
6479 idx_info.storage = sc;
6480
6481 /* Get the dataspace for the dataset */
6482 if (NULL == (space = H5S_read(loc)))
6483 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to load dataspace info from dataset header")
6484
6485 /* Allocate any indexing structures */
6486 if (sc->ops->init && (sc->ops->init)(&idx_info, space, loc->addr) < 0)
6487 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize indexing information")
6488 idx_info_init = TRUE;
6489
6490 /* Get size of index structure */
6491 if (sc->ops->size && (sc->ops->size)(&idx_info, index_size) < 0)
6492 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve chunk index info")
6493
6494 done:
6495 /* Free resources, if they've been initialized */
6496 if (idx_info_init && sc->ops->dest && (sc->ops->dest)(&idx_info) < 0)
6497 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to release chunk index info")
6498 if (pline_read && H5O_msg_reset(H5O_PLINE_ID, &pline) < 0)
6499 HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset I/O pipeline message")
6500 if (space && H5S_close(space) < 0)
6501 HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
6502
6503 FUNC_LEAVE_NOAPI(ret_value)
6504 } /* end H5D__chunk_bh_info() */
6505
6506 /*-------------------------------------------------------------------------
6507 * Function: H5D__chunk_dump_index_cb
6508 *
6509 * Purpose: If the UDATA.STREAM member is non-null then debugging
6510 * information is written to that stream.
6511 *
6512 * Return: Success: Non-negative
6513 *
6514 * Failure: Negative
6515 *
6516 * Programmer: Robb Matzke
6517 * Wednesday, April 21, 1999
6518 *
6519 *-------------------------------------------------------------------------
6520 */
6521 static int
H5D__chunk_dump_index_cb(const H5D_chunk_rec_t * chunk_rec,void * _udata)6522 H5D__chunk_dump_index_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
6523 {
6524 H5D_chunk_it_ud4_t *udata = (H5D_chunk_it_ud4_t *)_udata; /* User data from caller */
6525
6526 FUNC_ENTER_STATIC_NOERR
6527
6528 if (udata->stream) {
6529 unsigned u; /* Local index variable */
6530
6531 /* Print header if not already displayed */
6532 if (!udata->header_displayed) {
6533 HDfprintf(udata->stream, " Flags Bytes Address Logical Offset\n");
6534 HDfprintf(udata->stream,
6535 " ========== ======== ========== ==============================\n");
6536
6537 /* Set flag that the headers has been printed */
6538 udata->header_displayed = TRUE;
6539 } /* end if */
6540
6541 /* Print information about this chunk */
6542 HDfprintf(udata->stream, " 0x%08x %8" PRIu32 " %10" PRIuHADDR " [", chunk_rec->filter_mask,
6543 chunk_rec->nbytes, chunk_rec->chunk_addr);
6544 for (u = 0; u < udata->ndims; u++)
6545 HDfprintf(udata->stream, "%s%" PRIuHSIZE, (u ? ", " : ""),
6546 (chunk_rec->scaled[u] * udata->chunk_dim[u]));
6547 HDfputs("]\n", udata->stream);
6548 } /* end if */
6549
6550 FUNC_LEAVE_NOAPI(H5_ITER_CONT)
6551 } /* H5D__chunk_dump_index_cb() */
6552
6553 /*-------------------------------------------------------------------------
6554 * Function: H5D__chunk_dump_index
6555 *
6556 * Purpose: Prints information about the storage index to the specified
6557 * stream.
6558 *
6559 * Return: Success: Non-negative
6560 * Failure: negative
6561 *
6562 * Programmer: Robb Matzke
6563 * Wednesday, April 28, 1999
6564 *
6565 *-------------------------------------------------------------------------
6566 */
6567 herr_t
H5D__chunk_dump_index(H5D_t * dset,FILE * stream)6568 H5D__chunk_dump_index(H5D_t *dset, FILE *stream)
6569 {
6570 H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
6571 herr_t ret_value = SUCCEED; /* Return value */
6572
6573 FUNC_ENTER_PACKAGE
6574
6575 /* Sanity check */
6576 HDassert(dset);
6577 H5D_CHUNK_STORAGE_INDEX_CHK(sc);
6578
6579 /* Only display info if stream is defined */
6580 if (stream) {
6581 H5D_chk_idx_info_t idx_info; /* Chunked index info */
6582 H5D_chunk_it_ud4_t udata; /* User data for callback */
6583
6584 /* Display info for index */
6585 if ((sc->ops->dump)(sc, stream) < 0)
6586 HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to dump chunk index info")
6587
6588 /* Compose chunked index info struct */
6589 idx_info.f = dset->oloc.file;
6590 idx_info.pline = &dset->shared->dcpl_cache.pline;
6591 idx_info.layout = &dset->shared->layout.u.chunk;
6592 idx_info.storage = sc;
6593
6594 /* Set up user data for callback */
6595 udata.stream = stream;
6596 udata.header_displayed = FALSE;
6597 udata.ndims = dset->shared->layout.u.chunk.ndims;
6598 udata.chunk_dim = dset->shared->layout.u.chunk.dim;
6599
6600 /* Iterate over index and dump chunk info */
6601 if ((sc->ops->iterate)(&idx_info, H5D__chunk_dump_index_cb, &udata) < 0)
6602 HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL,
6603 "unable to iterate over chunk index to dump chunk info")
6604 } /* end if */
6605
6606 done:
6607 FUNC_LEAVE_NOAPI(ret_value)
6608 } /* end H5D__chunk_dump_index() */
6609
6610 #ifdef H5D_CHUNK_DEBUG
6611
6612 /*-------------------------------------------------------------------------
6613 * Function: H5D__chunk_stats
6614 *
6615 * Purpose: Print raw data cache statistics to the debug stream. If
6616 * HEADERS is non-zero then print table column headers,
6617 * otherwise assume that the H5AC layer has already printed them.
6618 *
6619 * Return: Non-negative on success/Negative on failure
6620 *
6621 * Programmer: Robb Matzke
6622 * Thursday, May 21, 1998
6623 *
6624 *-------------------------------------------------------------------------
6625 */
6626 herr_t
H5D__chunk_stats(const H5D_t * dset,hbool_t headers)6627 H5D__chunk_stats(const H5D_t *dset, hbool_t headers)
6628 {
6629 H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);
6630 double miss_rate;
6631 char ascii[32];
6632 herr_t ret_value = SUCCEED; /* Return value */
6633
6634 FUNC_ENTER_PACKAGE_NOERR
6635
6636 if (!H5DEBUG(AC))
6637 HGOTO_DONE(SUCCEED)
6638
6639 if (headers) {
6640 HDfprintf(H5DEBUG(AC), "H5D: raw data cache statistics\n");
6641 HDfprintf(H5DEBUG(AC), " %-18s %8s %8s %8s %8s+%-8s\n", "Layer", "Hits", "Misses", "MissRate",
6642 "Inits", "Flushes");
6643 HDfprintf(H5DEBUG(AC), " %-18s %8s %8s %8s %8s-%-8s\n", "-----", "----", "------", "--------",
6644 "-----", "-------");
6645 }
6646
6647 #ifdef H5AC_DEBUG
6648 if (H5DEBUG(AC))
6649 headers = TRUE;
6650 #endif
6651
6652 if (headers) {
6653 if (rdcc->stats.nhits > 0 || rdcc->stats.nmisses > 0) {
6654 miss_rate = 100.0 * rdcc->stats.nmisses / (rdcc->stats.nhits + rdcc->stats.nmisses);
6655 }
6656 else {
6657 miss_rate = 0.0;
6658 }
6659 if (miss_rate > 100) {
6660 HDsprintf(ascii, "%7d%%", (int)(miss_rate + 0.5));
6661 }
6662 else {
6663 HDsprintf(ascii, "%7.2f%%", miss_rate);
6664 }
6665
6666 HDfprintf(H5DEBUG(AC), " %-18s %8u %8u %7s %8d+%-9ld\n", "raw data chunks", rdcc->stats.nhits,
6667 rdcc->stats.nmisses, ascii, rdcc->stats.ninits,
6668 (long)(rdcc->stats.nflushes) - (long)(rdcc->stats.ninits));
6669 }
6670
6671 done:
6672 FUNC_LEAVE_NOAPI(ret_value)
6673 } /* end H5D__chunk_stats() */
6674 #endif /* H5D_CHUNK_DEBUG */
6675
6676 /*-------------------------------------------------------------------------
6677 * Function: H5D__nonexistent_readvv_cb
6678 *
6679 * Purpose: Callback operation for performing fill value I/O operation
6680 * on memory buffer.
6681 *
6682 * Note: This algorithm is pretty inefficient about initializing and
6683 * terminating the fill buffer info structure and it would be
6684 * faster to refactor this into a "real" initialization routine,
6685 * and a "vectorized fill" routine. -QAK
6686 *
6687 * Return: Non-negative on success/Negative on failure
6688 *
6689 * Programmer: Quincey Koziol
6690 * 30 Sep 2010
6691 *
6692 *-------------------------------------------------------------------------
6693 */
6694 static herr_t
H5D__nonexistent_readvv_cb(hsize_t H5_ATTR_UNUSED dst_off,hsize_t src_off,size_t len,void * _udata)6695 H5D__nonexistent_readvv_cb(hsize_t H5_ATTR_UNUSED dst_off, hsize_t src_off, size_t len, void *_udata)
6696 {
6697 H5D_chunk_readvv_ud_t *udata = (H5D_chunk_readvv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
6698 H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
6699 hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
6700 herr_t ret_value = SUCCEED; /* Return value */
6701
6702 FUNC_ENTER_STATIC
6703
6704 /* Initialize the fill value buffer */
6705 if (H5D__fill_init(&fb_info, (udata->rbuf + src_off), NULL, NULL, NULL, NULL,
6706 &udata->dset->shared->dcpl_cache.fill, udata->dset->shared->type,
6707 udata->dset->shared->type_id, (size_t)0, len) < 0)
6708 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
6709 fb_info_init = TRUE;
6710
6711 /* Check for VL datatype & fill the buffer with VL datatype fill values */
6712 if (fb_info.has_vlen_fill_type && H5D__fill_refill_vl(&fb_info, fb_info.elmts_per_buf) < 0)
6713 HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
6714
6715 done:
6716 /* Release the fill buffer info, if it's been initialized */
6717 if (fb_info_init && H5D__fill_term(&fb_info) < 0)
6718 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
6719
6720 FUNC_LEAVE_NOAPI(ret_value)
6721 } /* H5D__nonexistent_readvv_cb() */
6722
6723 /*-------------------------------------------------------------------------
6724 * Function: H5D__nonexistent_readvv
6725 *
6726 * Purpose: When the chunk doesn't exist on disk and the chunk is bigger
6727 * than the cache size, performs fill value I/O operation on
6728 * memory buffer, advancing through two I/O vectors, until one
6729 * runs out.
6730 *
6731 * Note: This algorithm is pretty inefficient about initializing and
6732 * terminating the fill buffer info structure and it would be
6733 * faster to refactor this into a "real" initialization routine,
6734 * and a "vectorized fill" routine. -QAK
6735 *
6736 * Return: Non-negative on success/Negative on failure
6737 *
6738 * Programmer: Raymond Lu
6739 * 6 Feb 2009
6740 *
6741 *-------------------------------------------------------------------------
6742 */
6743 static ssize_t
H5D__nonexistent_readvv(const H5D_io_info_t * io_info,size_t chunk_max_nseq,size_t * chunk_curr_seq,size_t chunk_len_arr[],hsize_t chunk_off_arr[],size_t mem_max_nseq,size_t * mem_curr_seq,size_t mem_len_arr[],hsize_t mem_off_arr[])6744 H5D__nonexistent_readvv(const H5D_io_info_t *io_info, size_t chunk_max_nseq, size_t *chunk_curr_seq,
6745 size_t chunk_len_arr[], hsize_t chunk_off_arr[], size_t mem_max_nseq,
6746 size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
6747 {
6748 H5D_chunk_readvv_ud_t udata; /* User data for H5VM_opvv() operator */
6749 ssize_t ret_value = -1; /* Return value */
6750
6751 FUNC_ENTER_STATIC
6752
6753 /* Check args */
6754 HDassert(io_info);
6755 HDassert(chunk_curr_seq);
6756 HDassert(chunk_len_arr);
6757 HDassert(chunk_off_arr);
6758 HDassert(mem_curr_seq);
6759 HDassert(mem_len_arr);
6760 HDassert(mem_off_arr);
6761
6762 /* Set up user data for H5VM_opvv() */
6763 udata.rbuf = (unsigned char *)io_info->u.rbuf;
6764 udata.dset = io_info->dset;
6765
6766 /* Call generic sequence operation routine */
6767 if ((ret_value = H5VM_opvv(chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_off_arr, mem_max_nseq,
6768 mem_curr_seq, mem_len_arr, mem_off_arr, H5D__nonexistent_readvv_cb, &udata)) <
6769 0)
6770 HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized fill value init")
6771
6772 done:
6773 FUNC_LEAVE_NOAPI(ret_value)
6774 } /* H5D__nonexistent_readvv() */
6775
6776 /*-------------------------------------------------------------------------
6777 * Function: H5D__chunk_is_partial_edge_chunk
6778 *
6779 * Purpose: Checks to see if the chunk is a partial edge chunk.
6780 * Either dset or (dset_dims and dset_ndims) must be
6781 * provided.
6782 *
6783 * Return: Non-negative on success/Negative on failure
6784 *
6785 * Programmer: Neil Fortner
6786 * 19 Nov 2009
6787 *
6788 *-------------------------------------------------------------------------
6789 */
6790 static hbool_t
H5D__chunk_is_partial_edge_chunk(unsigned dset_ndims,const uint32_t * chunk_dims,const hsize_t scaled[],const hsize_t * dset_dims)6791 H5D__chunk_is_partial_edge_chunk(unsigned dset_ndims, const uint32_t *chunk_dims, const hsize_t scaled[],
6792 const hsize_t *dset_dims)
6793 {
6794 unsigned u; /* Local index variable */
6795 hbool_t ret_value = FALSE; /* Return value */
6796
6797 FUNC_ENTER_STATIC_NOERR
6798
6799 /* Check args */
6800 HDassert(scaled);
6801 HDassert(dset_ndims > 0);
6802 HDassert(dset_dims);
6803 HDassert(chunk_dims);
6804
6805 /* check if this is a partial edge chunk */
6806 for (u = 0; u < dset_ndims; u++)
6807 if (((scaled[u] + 1) * chunk_dims[u]) > dset_dims[u])
6808 HGOTO_DONE(TRUE);
6809
6810 done:
6811 FUNC_LEAVE_NOAPI(ret_value)
6812 } /* H5D__chunk_is_partial_edge_chunk() */
6813
6814 /*-------------------------------------------------------------------------
6815 * Function: H5D__chunk_file_alloc()
6816 *
6817 * Purpose: Chunk allocation:
6818 * Create the chunk if it doesn't exist, or reallocate the
6819 * chunk if its size changed.
6820 * The coding is moved and modified from each index structure.
6821 *
6822 * Return: Non-negative on success/Negative on failure
6823 *
6824 * Programmer: Vailin Choi; June 2014
6825 *
6826 *-------------------------------------------------------------------------
6827 */
6828 herr_t
H5D__chunk_file_alloc(const H5D_chk_idx_info_t * idx_info,const H5F_block_t * old_chunk,H5F_block_t * new_chunk,hbool_t * need_insert,const hsize_t * scaled)6829 H5D__chunk_file_alloc(const H5D_chk_idx_info_t *idx_info, const H5F_block_t *old_chunk,
6830 H5F_block_t *new_chunk, hbool_t *need_insert, const hsize_t *scaled)
6831 {
6832 hbool_t alloc_chunk = FALSE; /* Whether to allocate chunk */
6833 herr_t ret_value = SUCCEED; /* Return value */
6834
6835 FUNC_ENTER_STATIC
6836
6837 /* Sanity check */
6838 HDassert(idx_info);
6839 HDassert(idx_info->f);
6840 HDassert(idx_info->pline);
6841 HDassert(idx_info->layout);
6842 HDassert(idx_info->storage);
6843 HDassert(new_chunk);
6844 HDassert(need_insert);
6845
6846 *need_insert = FALSE;
6847
6848 /* Check for filters on chunks */
6849 if (idx_info->pline->nused > 0) {
6850 /* Sanity/error checking block */
6851 HDassert(idx_info->storage->idx_type != H5D_CHUNK_IDX_NONE);
6852 {
6853 unsigned allow_chunk_size_len; /* Allowed size of encoded chunk size */
6854 unsigned new_chunk_size_len; /* Size of encoded chunk size */
6855
6856 /* Compute the size required for encoding the size of a chunk, allowing
6857 * for an extra byte, in case the filter makes the chunk larger.
6858 */
6859 allow_chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)(idx_info->layout->size)) + 8) / 8);
6860 if (allow_chunk_size_len > 8)
6861 allow_chunk_size_len = 8;
6862
6863 /* Compute encoded size of chunk */
6864 new_chunk_size_len = (H5VM_log2_gen((uint64_t)(new_chunk->length)) + 8) / 8;
6865 if (new_chunk_size_len > 8)
6866 HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "encoded chunk size is more than 8 bytes?!?")
6867
6868 /* Check if the chunk became too large to be encoded */
6869 if (new_chunk_size_len > allow_chunk_size_len)
6870 HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk size can't be encoded")
6871 } /* end block */
6872
6873 if (old_chunk && H5F_addr_defined(old_chunk->offset)) {
6874 /* Sanity check */
6875 HDassert(!H5F_addr_defined(new_chunk->offset) ||
6876 H5F_addr_eq(new_chunk->offset, old_chunk->offset));
6877
6878 /* Check for chunk being same size */
6879 if (new_chunk->length != old_chunk->length) {
6880 /* Release previous chunk */
6881 /* Only free the old location if not doing SWMR writes - otherwise
6882 * we must keep the old chunk around in case a reader has an
6883 * outdated version of the B-tree node
6884 */
6885 if (!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE))
6886 if (H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, old_chunk->offset, old_chunk->length) < 0)
6887 HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
6888 alloc_chunk = TRUE;
6889 } /* end if */
6890 else {
6891 /* Don't need to reallocate chunk, but send its address back up */
6892 if (!H5F_addr_defined(new_chunk->offset))
6893 new_chunk->offset = old_chunk->offset;
6894 } /* end else */
6895 } /* end if */
6896 else {
6897 HDassert(!H5F_addr_defined(new_chunk->offset));
6898 alloc_chunk = TRUE;
6899 } /* end else */
6900 } /* end if */
6901 else {
6902 HDassert(!H5F_addr_defined(new_chunk->offset));
6903 HDassert(new_chunk->length == idx_info->layout->size);
6904 alloc_chunk = TRUE;
6905 } /* end else */
6906
6907 /* Actually allocate space for the chunk in the file */
6908 if (alloc_chunk) {
6909 switch (idx_info->storage->idx_type) {
6910 case H5D_CHUNK_IDX_NONE: {
6911 H5D_chunk_ud_t udata;
6912
6913 udata.common.scaled = scaled;
6914 if ((idx_info->storage->ops->get_addr)(idx_info, &udata) < 0)
6915 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query chunk address")
6916 new_chunk->offset = udata.chunk_block.offset;
6917 HDassert(new_chunk->length == udata.chunk_block.length);
6918 break;
6919 }
6920
6921 case H5D_CHUNK_IDX_EARRAY:
6922 case H5D_CHUNK_IDX_FARRAY:
6923 case H5D_CHUNK_IDX_BT2:
6924 case H5D_CHUNK_IDX_BTREE:
6925 case H5D_CHUNK_IDX_SINGLE:
6926 HDassert(new_chunk->length > 0);
6927 H5_CHECK_OVERFLOW(new_chunk->length, /*From: */ uint32_t, /*To: */ hsize_t);
6928 new_chunk->offset = H5MF_alloc(idx_info->f, H5FD_MEM_DRAW, (hsize_t)new_chunk->length);
6929 if (!H5F_addr_defined(new_chunk->offset))
6930 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "file allocation failed")
6931 *need_insert = TRUE;
6932 break;
6933
6934 case H5D_CHUNK_IDX_NTYPES:
6935 default:
6936 HDassert(0 && "This should never be executed!");
6937 break;
6938 } /* end switch */
6939 } /* end if */
6940
6941 HDassert(H5F_addr_defined(new_chunk->offset));
6942
6943 done:
6944 FUNC_LEAVE_NOAPI(ret_value)
6945 } /* H5D__chunk_file_alloc() */
6946
6947 /*-------------------------------------------------------------------------
6948 * Function: H5D__chunk_format_convert_cb
6949 *
6950 * Purpose: Callback routine to insert chunk address into v1 B-tree
6951 * chunk index.
6952 *
6953 * Return: Success: Non-negative
6954 * Failure: Negative
6955 *
6956 * Programmer: Vailin Choi
6957 * Feb 2015
6958 *
6959 *-------------------------------------------------------------------------
6960 */
6961 static int
H5D__chunk_format_convert_cb(const H5D_chunk_rec_t * chunk_rec,void * _udata)6962 H5D__chunk_format_convert_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
6963 {
6964 H5D_chunk_it_ud5_t *udata = (H5D_chunk_it_ud5_t *)_udata; /* User data */
6965 H5D_chk_idx_info_t *new_idx_info; /* The new chunk index information */
6966 H5D_chunk_ud_t insert_udata; /* Chunk information to be inserted */
6967 haddr_t chunk_addr; /* Chunk address */
6968 size_t nbytes; /* Chunk size */
6969 void * buf = NULL; /* Pointer to buffer of chunk data */
6970 int ret_value = H5_ITER_CONT; /* Return value */
6971
6972 FUNC_ENTER_STATIC
6973
6974 /* Set up */
6975 new_idx_info = udata->new_idx_info;
6976 H5_CHECKED_ASSIGN(nbytes, size_t, chunk_rec->nbytes, uint32_t);
6977 chunk_addr = chunk_rec->chunk_addr;
6978
6979 if (new_idx_info->pline->nused &&
6980 (new_idx_info->layout->flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) &&
6981 (H5D__chunk_is_partial_edge_chunk(udata->dset_ndims, new_idx_info->layout->dim, chunk_rec->scaled,
6982 udata->dset_dims))) {
6983
6984 /* This is a partial non-filtered edge chunk */
6985 /* Convert the chunk to a filtered edge chunk for v1 B-tree chunk index */
6986
6987 unsigned filter_mask = chunk_rec->filter_mask;
6988 H5Z_cb_t filter_cb; /* Filter failure callback struct */
6989 size_t read_size = nbytes; /* Bytes to read */
6990
6991 HDassert(read_size == new_idx_info->layout->size);
6992
6993 /* Initialize the filter callback struct */
6994 filter_cb.op_data = NULL;
6995 filter_cb.func = NULL; /* no callback function when failed */
6996
6997 /* Allocate buffer for chunk data */
6998 if (NULL == (buf = H5MM_malloc(read_size)))
6999 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR,
7000 "memory allocation failed for raw data chunk")
7001
7002 /* Read the non-filtered edge chunk */
7003 if (H5F_block_read(new_idx_info->f, H5FD_MEM_DRAW, chunk_addr, read_size, buf) < 0)
7004 HGOTO_ERROR(H5E_IO, H5E_READERROR, H5_ITER_ERROR, "unable to read raw data chunk")
7005
7006 /* Pass the chunk through the pipeline */
7007 if (H5Z_pipeline(new_idx_info->pline, 0, &filter_mask, H5Z_NO_EDC, filter_cb, &nbytes, &read_size,
7008 &buf) < 0)
7009 HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, H5_ITER_ERROR, "output pipeline failed")
7010
7011 #if H5_SIZEOF_SIZE_T > 4
7012 /* Check for the chunk expanding too much to encode in a 32-bit value */
7013 if (nbytes > ((size_t)0xffffffff))
7014 HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, H5_ITER_ERROR, "chunk too large for 32-bit length")
7015 #endif /* H5_SIZEOF_SIZE_T > 4 */
7016
7017 /* Allocate space for the filtered chunk */
7018 if ((chunk_addr = H5MF_alloc(new_idx_info->f, H5FD_MEM_DRAW, (hsize_t)nbytes)) == HADDR_UNDEF)
7019 HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, H5_ITER_ERROR, "file allocation failed for filtered chunk")
7020 HDassert(H5F_addr_defined(chunk_addr));
7021
7022 /* Write the filtered chunk to disk */
7023 if (H5F_block_write(new_idx_info->f, H5FD_MEM_DRAW, chunk_addr, nbytes, buf) < 0)
7024 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, H5_ITER_ERROR, "unable to write raw data to file")
7025 } /* end if */
7026
7027 /* Set up chunk information for insertion to chunk index */
7028 insert_udata.chunk_block.offset = chunk_addr;
7029 insert_udata.chunk_block.length = nbytes;
7030 insert_udata.filter_mask = chunk_rec->filter_mask;
7031 insert_udata.common.scaled = chunk_rec->scaled;
7032 insert_udata.common.layout = new_idx_info->layout;
7033 insert_udata.common.storage = new_idx_info->storage;
7034
7035 /* Insert chunk into the v1 B-tree chunk index */
7036 if ((new_idx_info->storage->ops->insert)(new_idx_info, &insert_udata, NULL) < 0)
7037 HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, H5_ITER_ERROR, "unable to insert chunk addr into index")
7038
7039 done:
7040 if (buf)
7041 H5MM_xfree(buf);
7042
7043 FUNC_LEAVE_NOAPI(ret_value)
7044 } /* H5D__chunk_format_convert_cb() */
7045
7046 /*-------------------------------------------------------------------------
7047 * Function: H5D__chunk_format_convert
7048 *
7049 * Purpose: Iterate over the chunks for the current chunk index and insert the
7050 * the chunk addresses into v1 B-tree chunk index via callback.
7051 *
7052 * Return: Non-negative on success/Negative on failure
7053 *
7054 * Programmer: Vailin Choi
7055 * Feb 2015
7056 *
7057 *-------------------------------------------------------------------------
7058 */
7059 herr_t
H5D__chunk_format_convert(H5D_t * dset,H5D_chk_idx_info_t * idx_info,H5D_chk_idx_info_t * new_idx_info)7060 H5D__chunk_format_convert(H5D_t *dset, H5D_chk_idx_info_t *idx_info, H5D_chk_idx_info_t *new_idx_info)
7061 {
7062 H5D_chunk_it_ud5_t udata; /* User data */
7063 herr_t ret_value = SUCCEED; /* Return value */
7064
7065 FUNC_ENTER_PACKAGE
7066
7067 /* Check args */
7068 HDassert(dset);
7069
7070 /* Set up user data */
7071 udata.new_idx_info = new_idx_info;
7072 udata.dset_ndims = dset->shared->ndims;
7073 udata.dset_dims = dset->shared->curr_dims;
7074
7075 /* Iterate over the chunks in the current index and insert the chunk addresses into version 1 B-tree index
7076 */
7077 if ((idx_info->storage->ops->iterate)(idx_info, H5D__chunk_format_convert_cb, &udata) < 0)
7078 HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk index to chunk info")
7079
7080 done:
7081 FUNC_LEAVE_NOAPI(ret_value)
7082 } /* end H5D__chunk_format_convert() */
7083
7084 /*-------------------------------------------------------------------------
7085 * Function: H5D__get_num_chunks_cb
7086 *
7087 * Purpose: Callback function that increments the number of written
7088 * chunks in the dataset.
7089 *
7090 * Note: Currently, this function only gets the number of all written
7091 * chunks, regardless the dataspace.
7092 *
7093 * Return: H5_ITER_CONT
7094 *
7095 * Programmer: Binh-Minh Ribler
7096 * June 2019 (HDFFV-10677)
7097 *
7098 *-------------------------------------------------------------------------
7099 */
7100 static int
H5D__get_num_chunks_cb(const H5D_chunk_rec_t H5_ATTR_UNUSED * chunk_rec,void * _udata)7101 H5D__get_num_chunks_cb(const H5D_chunk_rec_t H5_ATTR_UNUSED *chunk_rec, void *_udata)
7102 {
7103 hsize_t *num_chunks = (hsize_t *)_udata;
7104 int ret_value = H5_ITER_CONT; /* Callback return value */
7105
7106 FUNC_ENTER_STATIC_NOERR
7107
7108 HDassert(num_chunks);
7109
7110 (*num_chunks)++;
7111
7112 FUNC_LEAVE_NOAPI(ret_value)
7113 } /* H5D__get_num_chunks_cb() */
7114
7115 /*-------------------------------------------------------------------------
7116 * Function: H5D__get_num_chunks
7117 *
7118 * Purpose: Gets the number of written chunks in a dataset.
7119 *
7120 * Note: Currently, this function only gets the number of all written
7121 * chunks, regardless the dataspace.
7122 *
7123 * Return: Success: Non-negative
7124 * Failure: Negative
7125 *
7126 * Programmer: Binh-Minh Ribler
7127 * June 2019 (HDFFV-10677)
7128 *
7129 *-------------------------------------------------------------------------
7130 */
7131 herr_t
H5D__get_num_chunks(const H5D_t * dset,const H5S_t H5_ATTR_UNUSED * space,hsize_t * nchunks)7132 H5D__get_num_chunks(const H5D_t *dset, const H5S_t H5_ATTR_UNUSED *space, hsize_t *nchunks)
7133 {
7134 H5D_chk_idx_info_t idx_info; /* Chunked index info */
7135 hsize_t num_chunks = 0; /* Number of written chunks */
7136 H5D_rdcc_ent_t * ent; /* Cache entry */
7137 const H5D_rdcc_t * rdcc = NULL; /* Raw data chunk cache */
7138 herr_t ret_value = SUCCEED; /* Return value */
7139
7140 FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr)
7141
7142 HDassert(dset);
7143 HDassert(dset->shared);
7144 HDassert(space);
7145 HDassert(nchunks);
7146
7147 rdcc = &(dset->shared->cache.chunk); /* raw data chunk cache */
7148 HDassert(rdcc);
7149
7150 /* Search for cached chunks that haven't been written out */
7151 for (ent = rdcc->head; ent; ent = ent->next)
7152 /* Flush the chunk out to disk, to make certain the size is correct later */
7153 if (H5D__chunk_flush_entry(dset, ent, FALSE) < 0)
7154 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
7155
7156 /* Compose chunked index info struct */
7157 idx_info.f = dset->oloc.file;
7158 idx_info.pline = &dset->shared->dcpl_cache.pline;
7159 idx_info.layout = &dset->shared->layout.u.chunk;
7160 idx_info.storage = &dset->shared->layout.storage.u.chunk;
7161
7162 /* If the dataset is not written, number of chunks will be 0 */
7163 if (!H5F_addr_defined(idx_info.storage->idx_addr))
7164 *nchunks = 0;
7165 else {
7166 /* Iterate over the allocated chunks */
7167 if ((dset->shared->layout.storage.u.chunk.ops->iterate)(&idx_info, H5D__get_num_chunks_cb,
7168 &num_chunks) < 0)
7169 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
7170 "unable to retrieve allocated chunk information from index")
7171 *nchunks = num_chunks;
7172 }
7173
7174 done:
7175 FUNC_LEAVE_NOAPI_TAG(ret_value)
7176 } /* end H5D__get_num_chunks() */
7177
7178 /*-------------------------------------------------------------------------
7179 * Function: H5D__get_chunk_info_cb
7180 *
7181 * Purpose: Get the chunk info of the queried chunk, given by its index.
7182 *
7183 * Return: Success: H5_ITER_CONT or H5_ITER_STOP
7184 * H5_ITER_STOP indicates the queried chunk is found
7185 * Failure: Negative (H5_ITER_ERROR)
7186 *
7187 * Programmer: Binh-Minh Ribler
7188 * June 2019 (HDFFV-10677)
7189 *
7190 *-------------------------------------------------------------------------
7191 */
7192 static int
H5D__get_chunk_info_cb(const H5D_chunk_rec_t * chunk_rec,void * _udata)7193 H5D__get_chunk_info_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
7194 {
7195 H5D_chunk_info_iter_ud_t *chunk_info = (H5D_chunk_info_iter_ud_t *)_udata;
7196 int ret_value = H5_ITER_CONT; /* Callback return value */
7197
7198 FUNC_ENTER_STATIC_NOERR
7199
7200 /* Check args */
7201 HDassert(chunk_rec);
7202 HDassert(chunk_info);
7203
7204 /* If this is the queried chunk, retrieve its info and stop iterating */
7205 if (chunk_info->curr_idx == chunk_info->chunk_idx) {
7206 hsize_t ii = 0; /* Dimension index */
7207
7208 /* Copy info */
7209 chunk_info->filter_mask = chunk_rec->filter_mask;
7210 chunk_info->chunk_addr = chunk_rec->chunk_addr;
7211 chunk_info->nbytes = chunk_rec->nbytes;
7212 for (ii = 0; ii < chunk_info->ndims; ii++)
7213 chunk_info->scaled[ii] = chunk_rec->scaled[ii];
7214 chunk_info->found = TRUE;
7215
7216 /* Stop iterating */
7217 ret_value = H5_ITER_STOP;
7218 }
7219 /* Go to the next chunk */
7220 else
7221 chunk_info->curr_idx++;
7222
7223 FUNC_LEAVE_NOAPI(ret_value)
7224 } /* H5D__get_chunk_info_cb() */
7225
7226 /*-------------------------------------------------------------------------
7227 * Function: H5D__get_chunk_info
7228 *
7229 * Purpose: Iterate over the chunks in the dataset to get the info
7230 * of the desired chunk.
7231 *
7232 * Note: Currently, the domain of the index in this function is of all
7233 * the written chunks, regardless the dataspace.
7234 *
7235 * Return: Success: SUCCEED
7236 * Failure: FAIL
7237 *
7238 * Programmer: Binh-Minh Ribler
7239 * June 2019 (HDFFV-10677)
7240 *
7241 *-------------------------------------------------------------------------
7242 */
7243 herr_t
H5D__get_chunk_info(const H5D_t * dset,const H5S_t H5_ATTR_UNUSED * space,hsize_t chk_index,hsize_t * offset,unsigned * filter_mask,haddr_t * addr,hsize_t * size)7244 H5D__get_chunk_info(const H5D_t *dset, const H5S_t H5_ATTR_UNUSED *space, hsize_t chk_index, hsize_t *offset,
7245 unsigned *filter_mask, haddr_t *addr, hsize_t *size)
7246 {
7247 H5D_chk_idx_info_t idx_info; /* Chunked index info */
7248 H5D_chunk_info_iter_ud_t udata; /* User data for callback */
7249 const H5D_rdcc_t * rdcc = NULL; /* Raw data chunk cache */
7250 H5D_rdcc_ent_t * ent; /* Cache entry index */
7251 hsize_t ii = 0; /* Dimension index */
7252 herr_t ret_value = SUCCEED; /* Return value */
7253
7254 FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr)
7255
7256 HDassert(dset);
7257 HDassert(dset->shared);
7258 HDassert(space);
7259
7260 /* Get the raw data chunk cache */
7261 rdcc = &(dset->shared->cache.chunk);
7262 HDassert(rdcc);
7263
7264 /* Search for cached chunks that haven't been written out */
7265 for (ent = rdcc->head; ent; ent = ent->next)
7266 /* Flush the chunk out to disk, to make certain the size is correct later */
7267 if (H5D__chunk_flush_entry(dset, ent, FALSE) < 0)
7268 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
7269
7270 /* Compose chunked index info struct */
7271 idx_info.f = dset->oloc.file;
7272 idx_info.pline = &dset->shared->dcpl_cache.pline;
7273 idx_info.layout = &dset->shared->layout.u.chunk;
7274 idx_info.storage = &dset->shared->layout.storage.u.chunk;
7275
7276 /* Set addr & size for when dset is not written or queried chunk is not found */
7277 if (addr)
7278 *addr = HADDR_UNDEF;
7279 if (size)
7280 *size = 0;
7281
7282 /* If the chunk is written, get its info, otherwise, return without error */
7283 if (H5F_addr_defined(idx_info.storage->idx_addr)) {
7284 /* Initialize before iteration */
7285 udata.chunk_idx = chk_index;
7286 udata.curr_idx = 0;
7287 udata.ndims = dset->shared->ndims;
7288 udata.nbytes = 0;
7289 udata.filter_mask = 0;
7290 udata.chunk_addr = HADDR_UNDEF;
7291 udata.found = FALSE;
7292
7293 /* Iterate over the allocated chunks */
7294 if ((dset->shared->layout.storage.u.chunk.ops->iterate)(&idx_info, H5D__get_chunk_info_cb, &udata) <
7295 0)
7296 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
7297 "unable to retrieve allocated chunk information from index")
7298
7299 /* Obtain requested info if the chunk is found */
7300 if (udata.found) {
7301 if (filter_mask)
7302 *filter_mask = udata.filter_mask;
7303 if (addr)
7304 *addr = udata.chunk_addr;
7305 if (size)
7306 *size = udata.nbytes;
7307 if (offset)
7308 for (ii = 0; ii < udata.ndims; ii++)
7309 offset[ii] = udata.scaled[ii] * dset->shared->layout.u.chunk.dim[ii];
7310 } /* end if */
7311 } /* end if H5F_addr_defined */
7312
7313 done:
7314 FUNC_LEAVE_NOAPI_TAG(ret_value)
7315 } /* end H5D__get_chunk_info() */
7316
7317 /*-------------------------------------------------------------------------
7318 * Function: H5D__get_chunk_info_by_coord_cb
7319 *
7320 * Purpose: Get the chunk info of the desired chunk, given its offset
7321 * coordinates.
7322 *
7323 * Return: Success: H5_ITER_CONT or H5_ITER_STOP
7324 * Failure: Negative (H5_ITER_ERROR)
7325 *
7326 * Programmer: Binh-Minh Ribler
7327 * June 2019 (HDFFV-10677)
7328 *
7329 *-------------------------------------------------------------------------
7330 */
7331 static int
H5D__get_chunk_info_by_coord_cb(const H5D_chunk_rec_t * chunk_rec,void * _udata)7332 H5D__get_chunk_info_by_coord_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
7333 {
7334 H5D_chunk_info_iter_ud_t *chunk_info = (H5D_chunk_info_iter_ud_t *)_udata;
7335 hbool_t different = FALSE; /* TRUE when a scaled value pair mismatch */
7336 hsize_t ii; /* Local index value */
7337 int ret_value = H5_ITER_CONT; /* Callback return value */
7338
7339 FUNC_ENTER_STATIC_NOERR
7340
7341 /* Check args */
7342 HDassert(chunk_rec);
7343 HDassert(chunk_info);
7344
7345 /* Going through the scaled, stop when a mismatch is found */
7346 for (ii = 0; ii < chunk_info->ndims && !different; ii++)
7347 if (chunk_info->scaled[ii] != chunk_rec->scaled[ii])
7348 different = TRUE;
7349
7350 /* Same scaled coords means the chunk is found, copy the chunk info */
7351 if (!different) {
7352 chunk_info->nbytes = chunk_rec->nbytes;
7353 chunk_info->filter_mask = chunk_rec->filter_mask;
7354 chunk_info->chunk_addr = chunk_rec->chunk_addr;
7355 chunk_info->found = TRUE;
7356
7357 /* Stop iterating */
7358 ret_value = H5_ITER_STOP;
7359 }
7360
7361 FUNC_LEAVE_NOAPI(ret_value)
7362 } /* H5D__get_chunk_info_by_coord_cb() */
7363
7364 /*-------------------------------------------------------------------------
7365 * Function: H5D__get_chunk_info_by_coord
7366 *
7367 * Purpose: Iterate over the chunks in the dataset to get the info
7368 * of the desired chunk, given by its offset coordinates.
7369 *
7370 * Return: Success: Non-negative
7371 * Failure: Negative
7372 *
7373 * Programmer: Binh-Minh Ribler
7374 * June 2019 (HDFFV-10677)
7375 *
7376 *-------------------------------------------------------------------------
7377 */
7378 herr_t
H5D__get_chunk_info_by_coord(const H5D_t * dset,const hsize_t * offset,unsigned * filter_mask,haddr_t * addr,hsize_t * size)7379 H5D__get_chunk_info_by_coord(const H5D_t *dset, const hsize_t *offset, unsigned *filter_mask, haddr_t *addr,
7380 hsize_t *size)
7381 {
7382 const H5O_layout_t * layout = NULL; /* Dataset layout */
7383 const H5D_rdcc_t * rdcc = NULL; /* Raw data chunk cache */
7384 H5D_rdcc_ent_t * ent; /* Cache entry index */
7385 H5D_chk_idx_info_t idx_info; /* Chunked index info */
7386 H5D_chunk_info_iter_ud_t udata; /* User data for callback */
7387 herr_t ret_value = SUCCEED; /* Return value */
7388
7389 FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr)
7390
7391 /* Check args */
7392 HDassert(dset);
7393 HDassert(dset->shared);
7394 HDassert(offset);
7395
7396 /* Get dataset layout and raw data chunk cache */
7397 layout = &(dset->shared->layout);
7398 rdcc = &(dset->shared->cache.chunk);
7399 HDassert(layout);
7400 HDassert(rdcc);
7401 HDassert(H5D_CHUNKED == layout->type);
7402
7403 /* Search for cached chunks that haven't been written out */
7404 for (ent = rdcc->head; ent; ent = ent->next)
7405 /* Flush the chunk out to disk, to make certain the size is correct later */
7406 if (H5D__chunk_flush_entry(dset, ent, FALSE) < 0)
7407 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
7408
7409 /* Set addr & size for when dset is not written or queried chunk is not found */
7410 if (addr)
7411 *addr = HADDR_UNDEF;
7412 if (size)
7413 *size = 0;
7414
7415 /* Compose chunked index info struct */
7416 idx_info.f = dset->oloc.file;
7417 idx_info.pline = &dset->shared->dcpl_cache.pline;
7418 idx_info.layout = &dset->shared->layout.u.chunk;
7419 idx_info.storage = &dset->shared->layout.storage.u.chunk;
7420
7421 /* If the dataset is not written, return without errors */
7422 if (H5F_addr_defined(idx_info.storage->idx_addr)) {
7423 /* Calculate the scaled of this chunk */
7424 H5VM_chunk_scaled(dset->shared->ndims, offset, layout->u.chunk.dim, udata.scaled);
7425 udata.scaled[dset->shared->ndims] = 0;
7426
7427 /* Initialize before iteration */
7428 udata.ndims = dset->shared->ndims;
7429 udata.nbytes = 0;
7430 udata.filter_mask = 0;
7431 udata.chunk_addr = HADDR_UNDEF;
7432 udata.found = FALSE;
7433
7434 /* Iterate over the allocated chunks to find the requested chunk */
7435 if ((dset->shared->layout.storage.u.chunk.ops->iterate)(&idx_info, H5D__get_chunk_info_by_coord_cb,
7436 &udata) < 0)
7437 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
7438 "unable to retrieve information of the chunk by its scaled coordinates")
7439
7440 /* Obtain requested info if the chunk is found */
7441 if (udata.found) {
7442 if (filter_mask)
7443 *filter_mask = udata.filter_mask;
7444 if (addr)
7445 *addr = udata.chunk_addr;
7446 if (size)
7447 *size = udata.nbytes;
7448 } /* end if */
7449 } /* end if H5F_addr_defined */
7450
7451 done:
7452 FUNC_LEAVE_NOAPI_TAG(ret_value)
7453 } /* end H5D__get_chunk_info_by_coord() */
7454