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