summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNeil Fortner <fortnern@gmail.com>2022-03-26 19:30:53 (GMT)
committerGitHub <noreply@github.com>2022-03-26 19:30:53 (GMT)
commit42b767fc67ad1e13735e3cee2077f2e108f9463e (patch)
tree42267295f94bb67dca39ba6dd2dd9d1ac89ee0bd /src
parent25ef608e2f1678c04a81b11ed9443768cdbd9dbd (diff)
downloadhdf5-42b767fc67ad1e13735e3cee2077f2e108f9463e.zip
hdf5-42b767fc67ad1e13735e3cee2077f2e108f9463e.tar.gz
hdf5-42b767fc67ad1e13735e3cee2077f2e108f9463e.tar.bz2
Merge initial version of selection I/O feature into develop (#1367)
Diffstat (limited to 'src')
-rw-r--r--src/H5.c13
-rw-r--r--src/H5Dchunk.c777
-rw-r--r--src/H5Dcompact.c6
-rw-r--r--src/H5Dcontig.c110
-rw-r--r--src/H5Defl.c8
-rw-r--r--src/H5Dio.c21
-rw-r--r--src/H5Dpkg.h7
-rw-r--r--src/H5FD.c368
-rw-r--r--src/H5FDcore.c5
-rw-r--r--src/H5FDdevelop.h24
-rw-r--r--src/H5FDdirect.c5
-rw-r--r--src/H5FDfamily.c5
-rw-r--r--src/H5FDhdfs.c5
-rw-r--r--src/H5FDint.c1977
-rw-r--r--src/H5FDlog.c75
-rw-r--r--src/H5FDmirror.c5
-rw-r--r--src/H5FDmpio.c1135
-rw-r--r--src/H5FDmulti.c5
-rw-r--r--src/H5FDprivate.h24
-rw-r--r--src/H5FDros3.c5
-rw-r--r--src/H5FDsec2.c5
-rw-r--r--src/H5FDsplitter.c5
-rw-r--r--src/H5FDstdio.c75
-rw-r--r--src/H5Fio.c91
-rw-r--r--src/H5Fprivate.h9
-rw-r--r--src/H5Gprivate.h2
-rw-r--r--src/H5PB.c69
-rw-r--r--src/H5PBprivate.h1
-rw-r--r--src/H5Tprivate.h20
-rw-r--r--src/H5private.h15
30 files changed, 4528 insertions, 344 deletions
diff --git a/src/H5.c b/src/H5.c
index 1585dd3..7142234 100644
--- a/src/H5.c
+++ b/src/H5.c
@@ -83,6 +83,8 @@ hbool_t H5_libinit_g = FALSE; /* Library hasn't been initialized */
hbool_t H5_libterm_g = FALSE; /* Library isn't being shutdown */
#endif
+hbool_t H5_use_selection_io_g = FALSE;
+
#ifdef H5_HAVE_MPE
hbool_t H5_MPEinit_g = FALSE; /* MPE Library hasn't been initialized */
#endif
@@ -144,7 +146,8 @@ herr_t
H5_init_library(void)
{
size_t i;
- herr_t ret_value = SUCCEED;
+ char * env_use_select_io = NULL;
+ herr_t ret_value = SUCCEED;
FUNC_ENTER_NOAPI(FAIL)
@@ -288,6 +291,14 @@ H5_init_library(void)
}
/* clang-format on */
+ /* Check for HDF5_USE_SELECTION_IO env variable */
+ env_use_select_io = HDgetenv("HDF5_USE_SELECTION_IO");
+ if (NULL != env_use_select_io && HDstrcmp(env_use_select_io, "") && HDstrcmp(env_use_select_io, "0") &&
+ HDstrcmp(env_use_select_io, "no") && HDstrcmp(env_use_select_io, "No") &&
+ HDstrcmp(env_use_select_io, "NO") && HDstrcmp(env_use_select_io, "false") &&
+ HDstrcmp(env_use_select_io, "False") && HDstrcmp(env_use_select_io, "FALSE"))
+ H5_use_selection_io_g = TRUE;
+
/* Debugging? */
H5__debug_mask("-all");
H5__debug_mask(HDgetenv("HDF5_DEBUG"));
diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c
index e4d8706..8374b17 100644
--- a/src/H5Dchunk.c
+++ b/src/H5Dchunk.c
@@ -59,6 +59,7 @@
#include "H5Iprivate.h" /* IDs */
#include "H5MMprivate.h" /* Memory management */
#include "H5MFprivate.h" /* File memory management */
+#include "H5PBprivate.h" /* Page Buffer */
#include "H5VMprivate.h" /* Vector and array functions */
/****************/
@@ -70,6 +71,7 @@
#define H5D_CHUNK_GET_NODE_INFO(map, node) \
(map->use_single ? map->single_chunk_info : (H5D_chunk_info_t *)H5SL_item(node))
#define H5D_CHUNK_GET_NEXT_NODE(map, node) (map->use_single ? (H5SL_node_t *)NULL : H5SL_next(node))
+#define H5D_CHUNK_GET_NODE_COUNT(map) (map->use_single ? (size_t)1 : H5SL_count(map->sel_chunks))
/* Sanity check on chunk index types: commonly used by a lot of routines in this file */
#define H5D_CHUNK_STORAGE_INDEX_CHK(storage) \
@@ -261,8 +263,8 @@ typedef struct H5D_chunk_iter_ud_t {
/* Chunked layout operation callbacks */
static herr_t H5D__chunk_construct(H5F_t *f, H5D_t *dset);
static herr_t H5D__chunk_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id);
-static herr_t H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
- hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm);
+static herr_t H5D__chunk_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
+ H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm);
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);
static herr_t H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
@@ -304,6 +306,7 @@ static herr_t H5D__chunk_file_cb(void *elem, const H5T_t *type, unsigned ndims
void *fm);
static herr_t H5D__chunk_mem_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords,
void *fm);
+static htri_t H5D__chunk_may_use_select_io(const H5D_io_info_t *io_info);
static unsigned H5D__chunk_hash_val(const H5D_shared_t *shared, const hsize_t *scaled);
static herr_t H5D__chunk_flush_entry(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t reset);
static herr_t H5D__chunk_cache_evict(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t flush);
@@ -1065,16 +1068,17 @@ H5D__chunk_is_data_cached(const H5D_shared_t *shared_dset)
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
+H5D__chunk_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm)
{
const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */
hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */
htri_t file_space_normalized = FALSE; /* File dataspace was normalized */
unsigned f_ndims; /* The number of dimensions of the file's dataspace */
- int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */
- unsigned u; /* Local index variable */
- herr_t ret_value = SUCCEED; /* Return value */
+ int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */
+ htri_t use_selection_io = FALSE; /* Whether to use selection I/O */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
@@ -1128,6 +1132,11 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf
if (H5D__chunk_io_init_selections(io_info, type_info, fm) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file and memory chunk selections")
+ /* Check if we're performing selection I/O and save the result */
+ if ((use_selection_io = H5D__chunk_may_use_select_io(io_info)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible")
+ io_info->use_select_io = (hbool_t)use_selection_io;
+
done:
/* Reset the global dataspace info */
fm->file_space = NULL;
@@ -2459,6 +2468,78 @@ done:
} /* end H5D__chunk_cacheable() */
/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_may_use_select_io
+ *
+ * Purpose: A small internal function to if it may be possible to use
+ * selection I/O.
+ *
+ * Return: TRUE or FALSE
+ *
+ * Programmer: Neil Fortner
+ * 4 May 2021
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5D__chunk_may_use_select_io(const H5D_io_info_t *io_info)
+{
+ const H5D_t *dataset = NULL; /* Local pointer to dataset info */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(io_info);
+
+ dataset = io_info->dset;
+ HDassert(dataset);
+
+ /* Don't use selection I/O if it's globally disabled, there is a type
+ * conversion, or if there are filters on the dataset (for now) */
+ if (!H5_use_selection_io_g || io_info->io_ops.single_read != H5D__select_read ||
+ dataset->shared->dcpl_cache.pline.nused > 0)
+ ret_value = FALSE;
+ else {
+ hbool_t page_buf_enabled;
+
+ HDassert(io_info->io_ops.single_write == H5D__select_write);
+
+ /* Check if the page buffer is enabled */
+ if (H5PB_enabled(io_info->f_sh, H5FD_MEM_DRAW, &page_buf_enabled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if page buffer is enabled")
+ if (page_buf_enabled)
+ ret_value = FALSE;
+ else {
+ /* Check if chunks in this dataset may be cached, if so don't use
+ * selection I/O (for now). Note that chunks temporarily cached for
+ * the purpose of writing the fill value don't count, since they are
+ * immediately evicted. */
+#ifdef H5_HAVE_PARALLEL
+ /* If MPI based VFD is used and the file is opened for write access,
+ * must bypass the chunk-cache scheme because other MPI processes
+ * could be writing to other elements in the same chunk.
+ */
+ if (io_info->using_mpi_vfd && (H5F_ACC_RDWR & H5F_INTENT(dataset->oloc.file)))
+ ret_value = TRUE;
+ else {
+#endif /* H5_HAVE_PARALLEL */
+ /* Check if the chunk is too large to keep in the cache */
+ H5_CHECK_OVERFLOW(dataset->shared->layout.u.chunk.size, uint32_t, size_t);
+ if ((size_t)dataset->shared->layout.u.chunk.size > dataset->shared->cache.chunk.nbytes_max)
+ ret_value = TRUE;
+ else
+ ret_value = FALSE;
+#ifdef H5_HAVE_PARALLEL
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_may_use_select_io() */
+
+/*-------------------------------------------------------------------------
* Function: H5D__chunk_read
*
* Purpose: Read from a chunked dataset.
@@ -2474,16 +2555,17 @@ 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,
H5S_t H5_ATTR_UNUSED *file_space, H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t *fm)
{
- H5SL_node_t * chunk_node; /* Current node in chunk skip list */
- H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */
- H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
- H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
- H5D_io_info_t cpt_io_info; /* Compact I/O info object */
- H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
- hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
- uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */
- hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */
- herr_t ret_value = SUCCEED; /*return value */
+ H5SL_node_t * chunk_node; /* Current node in chunk skip list */
+ H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */
+ uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */
+ hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */
+ H5S_t ** chunk_mem_spaces = NULL; /* Array of chunk memory spaces */
+ H5S_t * chunk_mem_spaces_static[8]; /* Static buffer for chunk_mem_spaces */
+ H5S_t ** chunk_file_spaces = NULL; /* Array of chunk file spaces */
+ H5S_t * chunk_file_spaces_static[8]; /* Static buffer for chunk_file_spaces */
+ haddr_t * chunk_addrs = NULL; /* Array of chunk addresses */
+ haddr_t chunk_addrs_static[8]; /* Static buffer for chunk_addrs */
+ herr_t ret_value = SUCCEED; /*return value */
FUNC_ENTER_STATIC
@@ -2497,23 +2579,6 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_
H5MM_memcpy(&nonexistent_io_info, io_info, sizeof(nonexistent_io_info));
nonexistent_io_info.layout_ops = *H5D_LOPS_NONEXISTENT;
- /* Set up contiguous I/O info object */
- H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info));
- ctg_io_info.store = &ctg_store;
- ctg_io_info.layout_ops = *H5D_LOPS_CONTIG;
-
- /* Initialize temporary contiguous storage info */
- H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size,
- uint32_t);
-
- /* Set up compact I/O info object */
- H5MM_memcpy(&cpt_io_info, io_info, sizeof(cpt_io_info));
- cpt_io_info.store = &cpt_store;
- cpt_io_info.layout_ops = *H5D_LOPS_COMPACT;
-
- /* Initialize temporary compact storage info */
- cpt_store.compact.dirty = &cpt_dirty;
-
{
const H5O_fill_t *fill = &(io_info->dset->shared->dcpl_cache.fill); /* Fill value info */
H5D_fill_value_t fill_status; /* Fill value status */
@@ -2531,80 +2596,215 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_
skip_missing_chunks = TRUE;
}
- /* Iterate through nodes in chunk skip list */
- chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
- while (chunk_node) {
- H5D_chunk_info_t *chunk_info; /* Chunk information */
- H5D_chunk_ud_t udata; /* Chunk index pass-through */
+ /* Different blocks depending on whether we're using selection I/O */
+ if (io_info->use_select_io) {
+ size_t num_chunks;
+ size_t element_sizes[2] = {type_info->dst_type_size, 0};
+ void * bufs[2] = {io_info->u.rbuf, NULL};
+
+ /* Cache number of chunks */
+ num_chunks = H5D_CHUNK_GET_NODE_COUNT(fm);
+
+ /* Allocate arrays of dataspaces and offsets for use with selection I/O,
+ * or point to static buffers */
+ HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) ==
+ sizeof(chunk_file_spaces_static) / sizeof(chunk_file_spaces_static[0]));
+ HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) ==
+ sizeof(chunk_addrs_static) / sizeof(chunk_addrs_static[0]));
+ if (num_chunks > (sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]))) {
+ if (NULL == (chunk_mem_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for memory space list")
+ if (NULL == (chunk_file_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
+ if (NULL == (chunk_addrs = H5MM_malloc(num_chunks * sizeof(haddr_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for chunk address list")
+ } /* end if */
+ else {
+ chunk_mem_spaces = chunk_mem_spaces_static;
+ chunk_file_spaces = chunk_file_spaces_static;
+ chunk_addrs = chunk_addrs_static;
+ } /* end else */
- /* Get the actual chunk information from the skip list node */
- chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
+ /* Reset num_chunks */
+ num_chunks = 0;
- /* Get the info for the chunk in the file */
- if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+ /* Iterate through nodes in chunk skip list */
+ chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
+ while (chunk_node) {
+ H5D_chunk_info_t *chunk_info; /* Chunk information */
+ H5D_chunk_ud_t udata; /* Chunk index pass-through */
- /* Sanity check */
- HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
- (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
+ /* Get the actual chunk information from the skip list node */
+ chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
- /* Check for non-existent chunk & skip it if appropriate */
- if (H5F_addr_defined(udata.chunk_block.offset) || UINT_MAX != udata.idx_hint ||
- !skip_missing_chunks) {
- H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */
- void * chunk = NULL; /* Pointer to locked chunk buffer */
- htri_t cacheable; /* Whether the chunk is cacheable */
+ /* Get the info for the chunk in the file */
+ if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
- /* Set chunk's [scaled] coordinates */
- io_info->store->chunk.scaled = chunk_info->scaled;
+ /* There should be no chunks cached */
+ HDassert(UINT_MAX == udata.idx_hint);
- /* Determine if we should use the chunk cache */
- if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, FALSE)) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
- if (cacheable) {
- /* Load the chunk into cache and lock it. */
+ /* Sanity check */
+ HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
+ (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
+
+ /* Check for non-existent chunk & skip it if appropriate */
+ if (H5F_addr_defined(udata.chunk_block.offset)) {
+ /* Add chunk to list for selection I/O */
+ chunk_mem_spaces[num_chunks] = chunk_info->mspace;
+ chunk_file_spaces[num_chunks] = chunk_info->fspace;
+ chunk_addrs[num_chunks] = udata.chunk_block.offset;
+ num_chunks++;
+ } /* end if */
+ else if (!skip_missing_chunks) {
+ /* Perform the actual read operation from the nonexistent chunk
+ */
+ if ((io_info->io_ops.single_read)(&nonexistent_io_info, type_info,
+ (hsize_t)chunk_info->chunk_points, chunk_info->fspace,
+ chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed")
+ } /* end if */
- /* Compute # of bytes accessed in chunk */
- H5_CHECK_OVERFLOW(type_info->src_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
- src_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->src_type_size;
+ /* Advance to next chunk in list */
+ chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
+ } /* end while */
- /* Lock the chunk into the cache */
- if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE)))
- HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
+ /* Issue selection I/O call (we can skip the page buffer because we've
+ * already verified it won't be used, and the metadata accumulator
+ * because this is raw data) */
+ if (H5F_shared_select_read(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, (uint32_t)num_chunks,
+ chunk_mem_spaces, chunk_file_spaces, chunk_addrs, element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunk selection read failed")
+
+ /* Clean up memory */
+ if (chunk_mem_spaces != chunk_mem_spaces_static) {
+ HDassert(chunk_mem_spaces);
+ HDassert(chunk_file_spaces != chunk_file_spaces_static);
+ HDassert(chunk_addrs != chunk_addrs_static);
+ H5MM_free(chunk_mem_spaces);
+ chunk_mem_spaces = NULL;
+ H5MM_free(chunk_file_spaces);
+ chunk_file_spaces = NULL;
+ H5MM_free(chunk_addrs);
+ chunk_addrs = NULL;
+ } /* end if */
+ } /* end if */
+ else {
+ H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
+ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
+ H5D_io_info_t cpt_io_info; /* Compact I/O info object */
+ H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
+ hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
+
+ /* Set up contiguous I/O info object */
+ H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info));
+ ctg_io_info.store = &ctg_store;
+ ctg_io_info.layout_ops = *H5D_LOPS_CONTIG;
+
+ /* Initialize temporary contiguous storage info */
+ H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size,
+ uint32_t);
+
+ /* Set up compact I/O info object */
+ H5MM_memcpy(&cpt_io_info, io_info, sizeof(cpt_io_info));
+ cpt_io_info.store = &cpt_store;
+ cpt_io_info.layout_ops = *H5D_LOPS_COMPACT;
+
+ /* Initialize temporary compact storage info */
+ cpt_store.compact.dirty = &cpt_dirty;
+
+ /* Iterate through nodes in chunk skip list */
+ chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
+ while (chunk_node) {
+ H5D_chunk_info_t *chunk_info; /* Chunk information */
+ H5D_chunk_ud_t udata; /* Chunk index pass-through */
+ htri_t cacheable; /* Whether the chunk is cacheable */
+
+ /* Get the actual chunk information from the skip list node */
+ chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
+
+ /* Get the info for the chunk in the file */
+ if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
- /* Set up the storage buffer information for this chunk */
- cpt_store.compact.buf = chunk;
+ /* Sanity check */
+ HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
+ (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
- /* Point I/O info at contiguous I/O info for this chunk */
- chk_io_info = &cpt_io_info;
- } /* end if */
- else if (H5F_addr_defined(udata.chunk_block.offset)) {
- /* Set up the storage address information for this chunk */
- ctg_store.contig.dset_addr = udata.chunk_block.offset;
+ /* Check for non-existent chunk & skip it if appropriate */
+ if (H5F_addr_defined(udata.chunk_block.offset) || UINT_MAX != udata.idx_hint ||
+ !skip_missing_chunks) {
+ H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */
+ void * chunk = NULL; /* Pointer to locked chunk buffer */
- /* Point I/O info at temporary I/O info for this chunk */
- chk_io_info = &ctg_io_info;
- } /* end else if */
- else {
- /* Point I/O info at "nonexistent" I/O info for this chunk */
- chk_io_info = &nonexistent_io_info;
- } /* end else */
+ /* Set chunk's [scaled] coordinates */
+ io_info->store->chunk.scaled = chunk_info->scaled;
- /* Perform the actual read operation */
- if ((io_info->io_ops.single_read)(chk_io_info, type_info, (hsize_t)chunk_info->chunk_points,
- chunk_info->fspace, chunk_info->mspace) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed")
+ /* Determine if we should use the chunk cache */
+ if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
+ if (cacheable) {
+ /* Load the chunk into cache and lock it. */
- /* Release the cache lock on the chunk. */
- if (chunk && H5D__chunk_unlock(io_info, &udata, FALSE, chunk, src_accessed_bytes) < 0)
- HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
- } /* end if */
+ /* Compute # of bytes accessed in chunk */
+ H5_CHECK_OVERFLOW(type_info->src_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
+ src_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->src_type_size;
- /* Advance to next chunk in list */
- chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
- } /* end while */
+ /* Lock the chunk into the cache */
+ if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE)))
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
+
+ /* Set up the storage buffer information for this chunk */
+ cpt_store.compact.buf = chunk;
+
+ /* Point I/O info at contiguous I/O info for this chunk */
+ chk_io_info = &cpt_io_info;
+ } /* end if */
+ else if (H5F_addr_defined(udata.chunk_block.offset)) {
+ /* Set up the storage address information for this chunk */
+ ctg_store.contig.dset_addr = udata.chunk_block.offset;
+
+ /* Point I/O info at temporary I/O info for this chunk */
+ chk_io_info = &ctg_io_info;
+ } /* end else if */
+ else {
+ /* Point I/O info at "nonexistent" I/O info for this chunk */
+ chk_io_info = &nonexistent_io_info;
+ } /* end else */
+
+ /* Perform the actual read operation */
+ if ((io_info->io_ops.single_read)(chk_io_info, type_info, (hsize_t)chunk_info->chunk_points,
+ chunk_info->fspace, chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed")
+
+ /* Release the cache lock on the chunk. */
+ if (chunk && H5D__chunk_unlock(io_info, &udata, FALSE, chunk, src_accessed_bytes) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
+ } /* end if */
+
+ /* Advance to next chunk in list */
+ chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
+ } /* end while */
+ } /* end else */
done:
+ /* Cleanup on failure */
+ if (ret_value < 0) {
+ if (chunk_mem_spaces != chunk_mem_spaces_static)
+ chunk_mem_spaces = H5MM_xfree(chunk_mem_spaces);
+ if (chunk_file_spaces != chunk_file_spaces_static)
+ chunk_file_spaces = H5MM_xfree(chunk_file_spaces);
+ if (chunk_addrs != chunk_addrs_static)
+ chunk_addrs = H5MM_xfree(chunk_addrs);
+ } /* end if */
+
+ /* Make sure we cleaned up */
+ HDassert(!chunk_mem_spaces || chunk_mem_spaces == chunk_mem_spaces_static);
+ HDassert(!chunk_file_spaces || chunk_file_spaces == chunk_file_spaces_static);
+ HDassert(!chunk_addrs || chunk_addrs == chunk_addrs_static);
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5D__chunk_read() */
@@ -2624,14 +2824,20 @@ 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,
H5S_t H5_ATTR_UNUSED *file_space, H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t *fm)
{
- H5SL_node_t * chunk_node; /* Current node in chunk skip list */
- H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
- H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
- H5D_io_info_t cpt_io_info; /* Compact I/O info object */
- H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
- hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
- uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */
- herr_t ret_value = SUCCEED; /* Return value */
+ H5SL_node_t * chunk_node; /* Current node in chunk skip list */
+ H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
+ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
+ H5D_io_info_t cpt_io_info; /* Compact I/O info object */
+ H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
+ hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
+ uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */
+ H5S_t ** chunk_mem_spaces = NULL; /* Array of chunk memory spaces */
+ H5S_t * chunk_mem_spaces_static[8]; /* Static buffer for chunk_mem_spaces */
+ H5S_t ** chunk_file_spaces = NULL; /* Array of chunk file spaces */
+ H5S_t * chunk_file_spaces_static[8]; /* Static buffer for chunk_file_spaces */
+ haddr_t * chunk_addrs = NULL; /* Array of chunk addresses */
+ haddr_t chunk_addrs_static[8]; /* Static buffer for chunk_addrs */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
@@ -2658,116 +2864,295 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize
/* Initialize temporary compact storage info */
cpt_store.compact.dirty = &cpt_dirty;
- /* Iterate through nodes in chunk skip list */
- chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
- while (chunk_node) {
- H5D_chunk_info_t * chunk_info; /* Chunk information */
- H5D_chk_idx_info_t idx_info; /* Chunked index info */
- H5D_io_info_t * chk_io_info; /* Pointer to I/O info object for this chunk */
- void * chunk; /* Pointer to locked chunk buffer */
- H5D_chunk_ud_t udata; /* Index pass-through */
- htri_t cacheable; /* Whether the chunk is cacheable */
- hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
+ /* Different blocks depending on whether we're using selection I/O */
+ if (io_info->use_select_io) {
+ size_t num_chunks;
+ size_t element_sizes[2] = {type_info->dst_type_size, 0};
+ const void *bufs[2] = {io_info->u.wbuf, NULL};
+
+ /* Cache number of chunks */
+ num_chunks = H5D_CHUNK_GET_NODE_COUNT(fm);
+
+ /* Allocate arrays of dataspaces and offsets for use with selection I/O,
+ * or point to static buffers */
+ HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) ==
+ sizeof(chunk_file_spaces_static) / sizeof(chunk_file_spaces_static[0]));
+ HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) ==
+ sizeof(chunk_addrs_static) / sizeof(chunk_addrs_static[0]));
+ if (num_chunks > (sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]))) {
+ if (NULL == (chunk_mem_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for memory space list")
+ if (NULL == (chunk_file_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
+ if (NULL == (chunk_addrs = H5MM_malloc(num_chunks * sizeof(haddr_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for chunk address list")
+ } /* end if */
+ else {
+ chunk_mem_spaces = chunk_mem_spaces_static;
+ chunk_file_spaces = chunk_file_spaces_static;
+ chunk_addrs = chunk_addrs_static;
+ } /* end else */
- /* Get the actual chunk information from the skip list node */
- chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
+ /* Reset num_chunks */
+ num_chunks = 0;
- /* Look up the chunk */
- if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+ /* Iterate through nodes in chunk skip list */
+ chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
+ while (chunk_node) {
+ H5D_chunk_info_t * chunk_info; /* Chunk information */
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_chunk_ud_t udata; /* Index pass-through */
+ htri_t cacheable; /* Whether the chunk is cacheable */
+ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
- /* Sanity check */
- HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
- (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
-
- /* Set chunk's [scaled] coordinates */
- io_info->store->chunk.scaled = chunk_info->scaled;
-
- /* Determine if we should use the chunk cache */
- if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
- if (cacheable) {
- /* Load the chunk into cache. But if the whole chunk is written,
- * simply allocate space instead of load the chunk. */
- hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */
-
- /* Compute # of bytes accessed in chunk */
- H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
- dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size;
-
- /* Determine if we will access all the data in the chunk */
- if (dst_accessed_bytes != ctg_store.contig.dset_size ||
- (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size ||
- fm->fsel_type == H5S_SEL_POINTS)
- entire_chunk = FALSE;
-
- /* Lock the chunk into the cache */
- if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE)))
- HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
-
- /* Set up the storage buffer information for this chunk */
- cpt_store.compact.buf = chunk;
-
- /* Point I/O info at main I/O info for this chunk */
- chk_io_info = &cpt_io_info;
+ /* Get the actual chunk information from the skip list node */
+ chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
+
+ /* Get the info for the chunk in the file */
+ if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+
+ /* There should be no chunks cached */
+ HDassert(UINT_MAX == udata.idx_hint);
+
+ /* Sanity check */
+ HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
+ (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
+
+ /* Set chunk's [scaled] coordinates */
+ io_info->store->chunk.scaled = chunk_info->scaled;
+
+ /* Determine if we should use the chunk cache */
+ if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
+ if (cacheable) {
+ /* Load the chunk into cache. But if the whole chunk is written,
+ * simply allocate space instead of load the chunk. */
+ void * chunk; /* Pointer to locked chunk buffer */
+ hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */
+
+ /* Compute # of bytes accessed in chunk */
+ H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
+ dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size;
+
+ /* Determine if we will access all the data in the chunk */
+ if (dst_accessed_bytes != ctg_store.contig.dset_size ||
+ (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size ||
+ fm->fsel_type == H5S_SEL_POINTS)
+ entire_chunk = FALSE;
+
+ /* Lock the chunk into the cache */
+ if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE)))
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
+
+ /* Set up the storage buffer information for this chunk */
+ cpt_store.compact.buf = chunk;
+
+ /* Perform the actual write operation */
+ if ((io_info->io_ops.single_write)(&cpt_io_info, type_info, (hsize_t)chunk_info->chunk_points,
+ chunk_info->fspace, chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed")
+
+ /* Release the cache lock on the chunk */
+ if (H5D__chunk_unlock(io_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
+ } /* end if */
+ else {
+ /* If the chunk hasn't been allocated on disk, do so now. */
+ if (!H5F_addr_defined(udata.chunk_block.offset)) {
+ /* Compose chunked index info struct */
+ idx_info.f = io_info->dset->oloc.file;
+ idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline);
+ idx_info.layout = &(io_info->dset->shared->layout.u.chunk);
+ idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk);
+
+ /* Set up the size of chunk for user data */
+ udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size;
+
+ /* Allocate the chunk */
+ if (H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert,
+ chunk_info->scaled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL,
+ "unable to insert/resize chunk on chunk level")
+
+ /* Make sure the address of the chunk is returned. */
+ if (!H5F_addr_defined(udata.chunk_block.offset))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined")
+
+ /* Cache the new chunk information */
+ H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata);
+
+ /* Insert chunk into index */
+ if (need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert)
+ if ((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata,
+ NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL,
+ "unable to insert chunk addr into index")
+ } /* end if */
+
+ /* Add chunk to list for selection I/O */
+ chunk_mem_spaces[num_chunks] = chunk_info->mspace;
+ chunk_file_spaces[num_chunks] = chunk_info->fspace;
+ chunk_addrs[num_chunks] = udata.chunk_block.offset;
+ num_chunks++;
+ } /* end else */
+
+ /* Advance to next chunk in list */
+ chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
+ } /* end while */
+
+ /* Issue selection I/O call (we can skip the page buffer because we've
+ * already verified it won't be used, and the metadata accumulator
+ * because this is raw data) */
+ if (H5F_shared_select_write(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, (uint32_t)num_chunks,
+ chunk_mem_spaces, chunk_file_spaces, chunk_addrs, element_sizes,
+ bufs) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunk selection read failed")
+
+ /* Clean up memory */
+ if (chunk_mem_spaces != chunk_mem_spaces_static) {
+ HDassert(chunk_mem_spaces);
+ HDassert(chunk_file_spaces != chunk_file_spaces_static);
+ HDassert(chunk_addrs != chunk_addrs_static);
+ H5MM_free(chunk_mem_spaces);
+ chunk_mem_spaces = NULL;
+ H5MM_free(chunk_file_spaces);
+ chunk_file_spaces = NULL;
+ H5MM_free(chunk_addrs);
+ chunk_addrs = NULL;
} /* end if */
- else {
- /* If the chunk hasn't been allocated on disk, do so now. */
- if (!H5F_addr_defined(udata.chunk_block.offset)) {
- /* Compose chunked index info struct */
- idx_info.f = io_info->dset->oloc.file;
- idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline);
- idx_info.layout = &(io_info->dset->shared->layout.u.chunk);
- idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk);
-
- /* Set up the size of chunk for user data */
- udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size;
-
- /* Allocate the chunk */
- if (H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert,
- chunk_info->scaled) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL,
- "unable to insert/resize chunk on chunk level")
-
- /* Make sure the address of the chunk is returned. */
- if (!H5F_addr_defined(udata.chunk_block.offset))
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined")
-
- /* Cache the new chunk information */
- H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata);
+ } /* end if */
+ else {
+ /* Iterate through nodes in chunk skip list */
+ chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
+ while (chunk_node) {
+ H5D_chunk_info_t * chunk_info; /* Chunk information */
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_io_info_t * chk_io_info; /* Pointer to I/O info object for this chunk */
+ void * chunk; /* Pointer to locked chunk buffer */
+ H5D_chunk_ud_t udata; /* Index pass-through */
+ htri_t cacheable; /* Whether the chunk is cacheable */
+ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
+
+ /* Get the actual chunk information from the skip list node */
+ chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
+
+ /* Look up the chunk */
+ if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+
+ /* Sanity check */
+ HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
+ (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
+
+ /* Set chunk's [scaled] coordinates */
+ io_info->store->chunk.scaled = chunk_info->scaled;
+
+ /* Determine if we should use the chunk cache */
+ if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
+ if (cacheable) {
+ /* Load the chunk into cache. But if the whole chunk is written,
+ * simply allocate space instead of load the chunk. */
+ hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */
+
+ /* Compute # of bytes accessed in chunk */
+ H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
+ dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size;
+
+ /* Determine if we will access all the data in the chunk */
+ if (dst_accessed_bytes != ctg_store.contig.dset_size ||
+ (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size ||
+ fm->fsel_type == H5S_SEL_POINTS)
+ entire_chunk = FALSE;
+
+ /* Lock the chunk into the cache */
+ if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE)))
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
+
+ /* Set up the storage buffer information for this chunk */
+ cpt_store.compact.buf = chunk;
+
+ /* Point I/O info at main I/O info for this chunk */
+ chk_io_info = &cpt_io_info;
} /* end if */
+ else {
+ /* If the chunk hasn't been allocated on disk, do so now. */
+ if (!H5F_addr_defined(udata.chunk_block.offset)) {
+ /* Compose chunked index info struct */
+ idx_info.f = io_info->dset->oloc.file;
+ idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline);
+ idx_info.layout = &(io_info->dset->shared->layout.u.chunk);
+ idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk);
+
+ /* Set up the size of chunk for user data */
+ udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size;
+
+ /* Allocate the chunk */
+ if (H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert,
+ chunk_info->scaled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL,
+ "unable to insert/resize chunk on chunk level")
+
+ /* Make sure the address of the chunk is returned. */
+ if (!H5F_addr_defined(udata.chunk_block.offset))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined")
+
+ /* Cache the new chunk information */
+ H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata);
+ } /* end if */
- /* Set up the storage address information for this chunk */
- ctg_store.contig.dset_addr = udata.chunk_block.offset;
+ /* Set up the storage address information for this chunk */
+ ctg_store.contig.dset_addr = udata.chunk_block.offset;
- /* No chunk cached */
- chunk = NULL;
+ /* No chunk cached */
+ chunk = NULL;
- /* Point I/O info at temporary I/O info for this chunk */
- chk_io_info = &ctg_io_info;
- } /* end else */
+ /* Point I/O info at temporary I/O info for this chunk */
+ chk_io_info = &ctg_io_info;
+ } /* end else */
- /* Perform the actual write operation */
- if ((io_info->io_ops.single_write)(chk_io_info, type_info, (hsize_t)chunk_info->chunk_points,
- chunk_info->fspace, chunk_info->mspace) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed")
+ /* Perform the actual write operation */
+ if ((io_info->io_ops.single_write)(chk_io_info, type_info, (hsize_t)chunk_info->chunk_points,
+ chunk_info->fspace, chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed")
- /* Release the cache lock on the chunk, or insert chunk into index. */
- if (chunk) {
- if (H5D__chunk_unlock(io_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0)
- HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
- } /* end if */
- else {
- if (need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert)
- if ((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
- } /* end else */
+ /* Release the cache lock on the chunk, or insert chunk into index. */
+ if (chunk) {
+ if (H5D__chunk_unlock(io_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
+ } /* end if */
+ else {
+ if (need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert)
+ if ((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) <
+ 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL,
+ "unable to insert chunk addr into index")
+ } /* end else */
- /* Advance to next chunk in list */
- chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
- } /* end while */
+ /* Advance to next chunk in list */
+ chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
+ } /* end while */
+ } /* end else */
done:
+ /* Cleanup on failure */
+ if (ret_value < 0) {
+ if (chunk_mem_spaces != chunk_mem_spaces_static)
+ chunk_mem_spaces = H5MM_xfree(chunk_mem_spaces);
+ if (chunk_file_spaces != chunk_file_spaces_static)
+ chunk_file_spaces = H5MM_xfree(chunk_file_spaces);
+ if (chunk_addrs != chunk_addrs_static)
+ chunk_addrs = H5MM_xfree(chunk_addrs);
+ } /* end if */
+
+ /* Make sure we cleaned up */
+ HDassert(!chunk_mem_spaces || chunk_mem_spaces == chunk_mem_spaces_static);
+ HDassert(!chunk_file_spaces || chunk_file_spaces == chunk_file_spaces_static);
+ HDassert(!chunk_addrs || chunk_addrs == chunk_addrs_static);
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5D__chunk_write() */
diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c
index 356a54e..1ac1267 100644
--- a/src/H5Dcompact.c
+++ b/src/H5Dcompact.c
@@ -63,8 +63,8 @@ typedef struct H5D_compact_iovv_memmanage_ud_t {
/* Layout operation callbacks */
static herr_t H5D__compact_construct(H5F_t *f, H5D_t *dset);
static hbool_t H5D__compact_is_space_alloc(const H5O_storage_t *storage);
-static herr_t H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
- hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm);
+static herr_t H5D__compact_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
+ H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm);
static herr_t H5D__compact_iovv_memmanage_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata);
static ssize_t H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq,
size_t dset_size_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq,
@@ -247,7 +247,7 @@ H5D__compact_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage)
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+H5D__compact_io_init(H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space,
H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *cm)
{
diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c
index 3828e8e..840c7ec 100644
--- a/src/H5Dcontig.c
+++ b/src/H5Dcontig.c
@@ -43,6 +43,7 @@
#include "H5FOprivate.h" /* File objects */
#include "H5Oprivate.h" /* Object headers */
#include "H5Pprivate.h" /* Property lists */
+#include "H5PBprivate.h" /* Page Buffer */
#include "H5VMprivate.h" /* Vector and array functions */
/****************/
@@ -90,8 +91,8 @@ typedef struct H5D_contig_writevv_ud_t {
/* Layout operation callbacks */
static herr_t H5D__contig_construct(H5F_t *f, H5D_t *dset);
static herr_t H5D__contig_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id);
-static herr_t H5D__contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
- hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm);
+static herr_t H5D__contig_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
+ H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm);
static ssize_t H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq,
size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq,
size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
@@ -102,6 +103,7 @@ static herr_t H5D__contig_flush(H5D_t *dset);
/* Helper routines */
static herr_t H5D__contig_write_one(H5D_io_info_t *io_info, hsize_t offset, size_t size);
+static htri_t H5D__contig_may_use_select_io(const H5D_io_info_t *io_info, H5D_io_op_type_t op_type);
/*********************/
/* Package Variables */
@@ -566,19 +568,81 @@ H5D__contig_is_data_cached(const H5D_shared_t *shared_dset)
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+H5D__contig_io_init(H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space,
H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *cm)
{
- FUNC_ENTER_STATIC_NOERR
+ htri_t use_selection_io = FALSE; /* Whether to use selection I/O */
+ htri_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
io_info->store->contig.dset_addr = io_info->dset->shared->layout.storage.u.contig.addr;
io_info->store->contig.dset_size = io_info->dset->shared->layout.storage.u.contig.size;
- FUNC_LEAVE_NOAPI(SUCCEED)
+ /* Check if we're performing selection I/O */
+ if ((use_selection_io = H5D__contig_may_use_select_io(io_info, H5D_IO_OP_READ)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible")
+ io_info->use_select_io = (hbool_t)use_selection_io;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__contig_io_init() */
/*-------------------------------------------------------------------------
+ * Function: H5D__contig_may_use_select_io
+ *
+ * Purpose: A small internal function to if it may be possible to use
+ * selection I/O.
+ *
+ * Return: TRUE/FALSE/FAIL
+ *
+ * Programmer: Neil Fortner
+ * 3 August 2021
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5D__contig_may_use_select_io(const H5D_io_info_t *io_info, H5D_io_op_type_t op_type)
+{
+ const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(dataset);
+ HDassert(op_type == H5D_IO_OP_READ || op_type == H5D_IO_OP_WRITE);
+
+ /* Don't use selection I/O if it's globally disabled, if there is a type
+ * conversion, or if it's not a contiguous dataset, or if the sieve buffer
+ * exists (write) or is dirty (read) */
+ if (!H5_use_selection_io_g || io_info->io_ops.single_read != H5D__select_read ||
+ io_info->layout_ops.readvv != H5D__contig_readvv ||
+ (op_type == H5D_IO_OP_READ && io_info->dset->shared->cache.contig.sieve_dirty) ||
+ (op_type == H5D_IO_OP_WRITE && io_info->dset->shared->cache.contig.sieve_buf))
+ ret_value = FALSE;
+ else {
+ hbool_t page_buf_enabled;
+
+ HDassert(io_info->io_ops.single_write == H5D__select_write);
+ HDassert(io_info->layout_ops.writevv == H5D__contig_writevv);
+
+ /* Check if the page buffer is enabled */
+ if (H5PB_enabled(io_info->f_sh, H5FD_MEM_DRAW, &page_buf_enabled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if page buffer is enabled")
+ if (page_buf_enabled)
+ ret_value = FALSE;
+ else
+ ret_value = TRUE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_may_use_select_io() */
+
+/*-------------------------------------------------------------------------
* Function: H5D__contig_read
*
* Purpose: Read from a contiguous dataset.
@@ -594,7 +658,7 @@ herr_t
H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, H5S_t *file_space,
H5S_t *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *fm)
{
- herr_t ret_value = SUCCEED; /*return value */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_PACKAGE
@@ -605,8 +669,20 @@ H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize
HDassert(mem_space);
HDassert(file_space);
- /* Read data */
- if ((io_info->io_ops.single_read)(io_info, type_info, nelmts, file_space, mem_space) < 0)
+ if (io_info->use_select_io) {
+ size_t dst_type_size = type_info->dst_type_size;
+
+ /* Issue selection I/O call (we can skip the page buffer because we've
+ * already verified it won't be used, and the metadata accumulator
+ * because this is raw data) */
+ if (H5F_shared_select_read(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, nelmts > 0 ? 1 : 0,
+ &mem_space, &file_space, &(io_info->store->contig.dset_addr),
+ &dst_type_size, &(io_info->u.rbuf)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous selection read failed")
+ } /* end if */
+ else
+ /* Read data through legacy (non-selection I/O) pathway */
+ if ((io_info->io_ops.single_read)(io_info, type_info, nelmts, file_space, mem_space) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous read failed")
done:
@@ -629,7 +705,7 @@ herr_t
H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, H5S_t *file_space,
H5S_t *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *fm)
{
- herr_t ret_value = SUCCEED; /*return value */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_PACKAGE
@@ -640,8 +716,20 @@ H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsiz
HDassert(mem_space);
HDassert(file_space);
- /* Write data */
- if ((io_info->io_ops.single_write)(io_info, type_info, nelmts, file_space, mem_space) < 0)
+ if (io_info->use_select_io) {
+ size_t dst_type_size = type_info->dst_type_size;
+
+ /* Issue selection I/O call (we can skip the page buffer because we've
+ * already verified it won't be used, and the metadata accumulator
+ * because this is raw data) */
+ if (H5F_shared_select_write(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, nelmts > 0 ? 1 : 0,
+ &mem_space, &file_space, &(io_info->store->contig.dset_addr),
+ &dst_type_size, &(io_info->u.wbuf)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous selection write failed")
+ } /* end if */
+ else
+ /* Write data through legacy (non-selection I/O) pathway */
+ if ((io_info->io_ops.single_write)(io_info, type_info, nelmts, file_space, mem_space) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous write failed")
done:
diff --git a/src/H5Defl.c b/src/H5Defl.c
index a30955b..b22c6de 100644
--- a/src/H5Defl.c
+++ b/src/H5Defl.c
@@ -60,9 +60,9 @@ typedef struct H5D_efl_writevv_ud_t {
/********************/
/* Layout operation callbacks */
-static herr_t H5D__efl_construct(H5F_t *f, H5D_t *dset);
-static herr_t H5D__efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
- H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm);
+static herr_t H5D__efl_construct(H5F_t *f, H5D_t *dset);
+static herr_t H5D__efl_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
+ H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm);
static ssize_t H5D__efl_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq,
size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq,
size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
@@ -209,7 +209,7 @@ H5D__efl_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage)
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+H5D__efl_io_init(H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space,
H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *cm)
{
diff --git a/src/H5Dio.c b/src/H5Dio.c
index e226a0a..cb61b71 100644
--- a/src/H5Dio.c
+++ b/src/H5Dio.c
@@ -576,6 +576,10 @@ H5D__ioinfo_init(H5D_t *dset, const H5D_type_info_t *type_info, H5D_storage_t *s
io_info->io_ops.single_write = H5D__scatgath_write;
} /* end else */
+ /* Start with selection I/O off, layout callback will turn it on if
+ * appropriate */
+ io_info->use_select_io = FALSE;
+
#ifdef H5_HAVE_PARALLEL
/* Determine if the file was opened with an MPI VFD */
io_info->using_mpi_vfd = H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI);
@@ -814,12 +818,17 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_
/* Check if we can use the optimized parallel I/O routines */
if (opt == TRUE) {
- /* Override the I/O op pointers to the MPI-specific routines */
- io_info->io_ops.multi_read = dset->shared->layout.ops->par_read;
- io_info->io_ops.multi_write = dset->shared->layout.ops->par_write;
- io_info->io_ops.single_read = H5D__mpio_select_read;
- io_info->io_ops.single_write = H5D__mpio_select_write;
- } /* end if */
+ /* Override the I/O op pointers to the MPI-specific routines, unless
+ * selection I/O is to be used - in this case the file driver will
+ * handle collective I/O */
+ /* Check for selection/vector support in file driver? -NAF */
+ if (!io_info->use_select_io) {
+ io_info->io_ops.multi_read = dset->shared->layout.ops->par_read;
+ io_info->io_ops.multi_write = dset->shared->layout.ops->par_write;
+ io_info->io_ops.single_read = H5D__mpio_select_read;
+ io_info->io_ops.single_write = H5D__mpio_select_write;
+ } /* end if */
+ } /* end if */
else {
/* Check if there are any filters in the pipeline. If there are,
* we cannot break to independent I/O if this is a write operation
diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h
index a424929..0e0eb08 100644
--- a/src/H5Dpkg.h
+++ b/src/H5Dpkg.h
@@ -121,9 +121,9 @@ typedef herr_t (*H5D_layout_construct_func_t)(H5F_t *f, H5D_t *dset);
typedef herr_t (*H5D_layout_init_func_t)(H5F_t *f, const H5D_t *dset, hid_t dapl_id);
typedef hbool_t (*H5D_layout_is_space_alloc_func_t)(const H5O_storage_t *storage);
typedef hbool_t (*H5D_layout_is_data_cached_func_t)(const H5D_shared_t *shared_dset);
-typedef herr_t (*H5D_layout_io_init_func_t)(const struct H5D_io_info_t *io_info,
- const H5D_type_info_t *type_info, hsize_t nelmts,
- H5S_t *file_space, H5S_t *mem_space, struct H5D_chunk_map_t *cm);
+typedef herr_t (*H5D_layout_io_init_func_t)(struct H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space,
+ struct H5D_chunk_map_t *cm);
typedef herr_t (*H5D_layout_read_func_t)(struct H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space,
struct H5D_chunk_map_t *fm);
@@ -222,6 +222,7 @@ typedef struct H5D_io_info_t {
H5D_layout_ops_t layout_ops; /* Dataset layout I/O operation function pointers */
H5D_io_ops_t io_ops; /* I/O operation function pointers */
H5D_io_op_type_t op_type;
+ hbool_t use_select_io; /* Whether to use selection I/O */
union {
void * rbuf; /* Pointer to buffer for read */
const void *wbuf; /* Pointer to buffer to write */
diff --git a/src/H5FD.c b/src/H5FD.c
index 20f69cb..1887e18 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -214,6 +214,8 @@ H5FDregister(const H5FD_class_t *cls)
/* Check arguments */
if (!cls)
HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID, "null class pointer is disallowed")
+ if (cls->version != H5FD_CLASS_VERSION)
+ HGOTO_ERROR(H5E_ARGS, H5E_VERSION, H5I_INVALID_HID, "wrong file driver version #")
if (!cls->open || !cls->close)
HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID,
"'open' and/or 'close' methods are not defined")
@@ -1480,6 +1482,370 @@ done:
} /* end H5FDwrite() */
/*-------------------------------------------------------------------------
+ * Function: H5FDread_vector
+ *
+ * Purpose: Perform count reads from the specified file at the offsets
+ * provided in the addrs array, with the lengths and memory
+ * types provided in the sizes and types arrays. Data read
+ * is returned in the buffers provided in the bufs array.
+ *
+ * All reads are done according to the data transfer property
+ * list dxpl_id (which may be the constant H5P_DEFAULT).
+ *
+ * Return: Success: SUCCEED
+ * All reads have completed successfully, and
+ * the results havce been into the supplied
+ * buffers.
+ *
+ * Failure: FAIL
+ * The contents of supplied buffers are undefined.
+ *
+ * Programmer: JRM -- 6/10/20
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDread_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[], haddr_t addrs[],
+ size_t sizes[], void *bufs[] /* out */)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "*#iIu*Mt*a*zx", file, dxpl_id, count, types, addrs, sizes, bufs);
+
+ /* Check arguments */
+ if (!file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL")
+
+ if (!file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file class pointer cannot be NULL")
+
+ if ((!types) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "types parameter can't be NULL if count is positive")
+
+ if ((!addrs) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addrs parameter can't be NULL if count is positive")
+
+ if ((!sizes) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes parameter can't be NULL if count is positive")
+
+ if ((!bufs) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs parameter can't be NULL if count is positive")
+
+ if ((count > 0) && (sizes[0] == 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes[0] can't be 0")
+
+ if ((count > 0) && (types[0] == H5FD_MEM_NOLIST))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "count[0] can't be H5FD_MEM_NOLIST")
+
+ /* Get the default dataset transfer property list if the user
+ * didn't provide one
+ */
+ if (H5P_DEFAULT == dxpl_id) {
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ }
+ else {
+ if (TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+ }
+
+ /* Set DXPL for operation */
+ H5CX_set_dxpl(dxpl_id);
+
+ /* Call private function */
+ /* (Note compensating for base addresses addition in internal routine) */
+ if (H5FD_read_vector(file, count, types, addrs, sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file vector read request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDread_vector() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDwrite_vector
+ *
+ * Purpose: Perform count writes to the specified file at the offsets
+ * provided in the addrs array, with the lengths and memory
+ * types provided in the sizes and types arrays. Data to be
+ * written is in the buffers provided in the bufs array.
+ *
+ * All writes are done according to the data transfer property
+ * list dxpl_id (which may be the constant H5P_DEFAULT).
+ *
+ * Return: Success: SUCCEED
+ * All writes have completed successfully
+ *
+ * Failure: FAIL
+ * One or more of the writes failed.
+ *
+ * Programmer: JRM -- 6/10/20
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDwrite_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[], haddr_t addrs[],
+ size_t sizes[], const void *bufs[] /* in */)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "*#iIu*Mt*a*z**x", file, dxpl_id, count, types, addrs, sizes, bufs);
+
+ /* Check arguments */
+ if (!file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL")
+
+ if (!file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file class pointer cannot be NULL")
+
+ if ((!types) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "types parameter can't be NULL if count is positive")
+
+ if ((!addrs) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addrs parameter can't be NULL if count is positive")
+
+ if ((!sizes) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes parameter can't be NULL if count is positive")
+
+ if ((!bufs) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs parameter can't be NULL if count is positive")
+
+ if ((count > 0) && (sizes[0] == 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes[0] can't be 0")
+
+ if ((count > 0) && (types[0] == H5FD_MEM_NOLIST))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "count[0] can't be H5FD_MEM_NOLIST")
+
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if (H5P_DEFAULT == dxpl_id) {
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ }
+ else {
+ if (TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+ }
+
+ /* Set DXPL for operation */
+ H5CX_set_dxpl(dxpl_id);
+
+ /* Call private function */
+ /* (Note compensating for base address addition in internal routine) */
+ if (H5FD_write_vector(file, count, types, addrs, sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file vector write request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDwrite_vector() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDread_selection
+ *
+ * Purpose: Perform count reads from the specified file at the
+ * locations selected in the dataspaces in the file_spaces
+ * array, with each of those dataspaces starting at the file
+ * address specified by the corresponding element of the
+ * offsets array, and with the size of each element in the
+ * dataspace specified by the corresponding element of the
+ * element_sizes array. The memory type provided by type is
+ * the same for all selections. Data read is returned in
+ * the locations selected in the dataspaces in the
+ * mem_spaces array, within the buffers provided in the
+ * corresponding elements of the bufs array.
+ *
+ * If i > 0 and element_sizes[i] == 0, presume
+ * element_sizes[n] = element_sizes[i-1] for all n >= i and
+ * < count.
+ *
+ * If the underlying VFD supports selection reads, pass the
+ * call through directly.
+ *
+ * If it doesn't, convert the selection read into a sequence
+ * of individual reads.
+ *
+ * All reads are done according to the data transfer property
+ * list dxpl_id (which may be the constant H5P_DEFAULT).
+ *
+ * Return: Success: SUCCEED
+ * All reads have completed successfully, and
+ * the results havce been into the supplied
+ * buffers.
+ *
+ * Failure: FAIL
+ * The contents of supplied buffers are undefined.
+ *
+ * Programmer: NAF -- 5/19/21
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDread_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, hid_t mem_space_ids[],
+ hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE9("e", "*#MtiIu*i*i*a*zx", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets,
+ element_sizes, bufs);
+
+ /* Check arguments */
+ if (!file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL")
+
+ if (!file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file class pointer cannot be NULL")
+
+ if ((!mem_space_ids) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_spaces parameter can't be NULL if count is positive")
+
+ if ((!file_space_ids) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_spaces parameter can't be NULL if count is positive")
+
+ if ((!offsets) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offsets parameter can't be NULL if count is positive")
+
+ if ((!element_sizes) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
+ "element_sizes parameter can't be NULL if count is positive")
+
+ if ((!bufs) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs parameter can't be NULL if count is positive")
+
+ if ((count > 0) && (element_sizes[0] == 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes[0] can't be 0")
+
+ if ((count > 0) && (bufs[0] == NULL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs[0] can't be NULL")
+
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if (H5P_DEFAULT == dxpl_id) {
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ }
+ else {
+ if (TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+ }
+
+ /* Set DXPL for operation */
+ H5CX_set_dxpl(dxpl_id);
+
+ /* Call private function */
+ /* (Note compensating for base address addition in internal routine) */
+ if (H5FD_read_selection_id(file, type, count, mem_space_ids, file_space_ids, offsets, element_sizes,
+ bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file selection read request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDread_selection() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDwrite_selection
+ *
+ * Purpose: Perform count writes to the specified file at the
+ * locations selected in the dataspaces in the file_spaces
+ * array, with each of those dataspaces starting at the file
+ * address specified by the corresponding element of the
+ * offsets array, and with the size of each element in the
+ * dataspace specified by the corresponding element of the
+ * element_sizes array. The memory type provided by type is
+ * the same for all selections. Data write is from
+ * the locations selected in the dataspaces in the
+ * mem_spaces array, within the buffers provided in the
+ * corresponding elements of the bufs array.
+ *
+ * If i > 0 and element_sizes[i] == 0, presume
+ * element_sizes[n] = element_sizes[i-1] for all n >= i and
+ * < count.
+ *
+ * If the underlying VFD supports selection writes, pass the
+ * call through directly.
+ *
+ * If it doesn't, convert the selection write into a sequence
+ * of individual writes.
+ *
+ * All writes are done according to the data transfer property
+ * list dxpl_id (which may be the constant H5P_DEFAULT).
+ *
+ * Return: Success: SUCCEED
+ * All writes have completed successfully
+ *
+ * Failure: FAIL
+ * One or more of the writes failed.
+ *
+ * Programmer: NAF -- 5/14/21
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDwrite_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, hid_t mem_space_ids[],
+ hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], const void *bufs[])
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE9("e", "*#MtiIu*i*i*a*z**x", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets,
+ element_sizes, bufs);
+
+ /* Check arguments */
+ if (!file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL")
+
+ if (!file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file class pointer cannot be NULL")
+
+ if ((!mem_space_ids) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_spaces parameter can't be NULL if count is positive")
+
+ if ((!file_space_ids) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_spaces parameter can't be NULL if count is positive")
+
+ if ((!offsets) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offsets parameter can't be NULL if count is positive")
+
+ if ((!element_sizes) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
+ "element_sizes parameter can't be NULL if count is positive")
+
+ if ((!bufs) && (count > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs parameter can't be NULL if count is positive")
+
+ if ((count > 0) && (element_sizes[0] == 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes[0] can't be 0")
+
+ if ((count > 0) && (bufs[0] == NULL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs[0] can't be NULL")
+
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if (H5P_DEFAULT == dxpl_id) {
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ }
+ else {
+ if (TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+ }
+
+ /* Set DXPL for operation */
+ H5CX_set_dxpl(dxpl_id);
+
+ /* Call private function */
+ /* (Note compensating for base address addition in internal routine) */
+ if (H5FD_write_selection_id(file, type, count, mem_space_ids, file_space_ids, offsets, element_sizes,
+ bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file selection write request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDwrite_selection() */
+
+/*-------------------------------------------------------------------------
* Function: H5FDflush
*
* Purpose: Notify driver to flush all cached data. If the driver has no
@@ -1827,7 +2193,7 @@ H5FD_ctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void
else if (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG) {
HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL,
- "VFD ctl request failed (no ctl callback and fail if unknown flag is set)")
+ "VFD ctl request failed (no ctl and fail if unknown flag is set)")
}
done:
diff --git a/src/H5FDcore.c b/src/H5FDcore.c
index a1750ee..0604316 100644
--- a/src/H5FDcore.c
+++ b/src/H5FDcore.c
@@ -152,6 +152,7 @@ static herr_t H5FD__core_delete(const char *filename, hid_t fapl_id);
static inline const H5FD_core_fapl_t *H5FD__core_get_default_config(void);
static const H5FD_class_t H5FD_core_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_CORE_VALUE, /* value */
"core", /* name */
MAXADDR, /* maxaddr */
@@ -180,6 +181,10 @@ static const H5FD_class_t H5FD_core_g = {
H5FD__core_get_handle, /* get_handle */
H5FD__core_read, /* read */
H5FD__core_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
H5FD__core_flush, /* flush */
H5FD__core_truncate, /* truncate */
H5FD__core_lock, /* lock */
diff --git a/src/H5FDdevelop.h b/src/H5FDdevelop.h
index be3b545..f5b32ed 100644
--- a/src/H5FDdevelop.h
+++ b/src/H5FDdevelop.h
@@ -25,6 +25,9 @@
/* Public Macros */
/*****************/
+/* H5FD_class_t struct version */
+#define H5FD_CLASS_VERSION 0x01 /* File driver struct version */
+
/* Map "fractal heap" header blocks to 'ohdr' type file memory, since its
* a fair amount of work to add a new kind of file memory and they are similar
* enough to object headers and probably too minor to deserve their own type.
@@ -160,6 +163,7 @@ typedef struct H5FD_t H5FD_t;
/* Class information for each file driver */
typedef struct H5FD_class_t {
+ unsigned version; /**< File driver class struct version # */
H5FD_class_value_t value;
const char * name;
haddr_t maxaddr;
@@ -188,6 +192,16 @@ typedef struct H5FD_class_t {
herr_t (*get_handle)(H5FD_t *file, hid_t fapl, void **file_handle);
herr_t (*read)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, void *buffer);
herr_t (*write)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, const void *buffer);
+ herr_t (*read_vector)(H5FD_t *file, hid_t dxpl, uint32_t count, H5FD_mem_t types[], haddr_t addrs[],
+ size_t sizes[], void *bufs[]);
+ herr_t (*write_vector)(H5FD_t *file, hid_t dxpl, uint32_t count, H5FD_mem_t types[], haddr_t addrs[],
+ size_t sizes[], const void *bufs[]);
+ herr_t (*read_selection)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, size_t count, hid_t mem_spaces[],
+ hid_t file_spaces[], haddr_t offsets[], size_t element_sizes[],
+ void *bufs[] /*out*/);
+ herr_t (*write_selection)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, size_t count, hid_t mem_spaces[],
+ hid_t file_spaces[], haddr_t offsets[], size_t element_sizes[],
+ const void *bufs[] /*in*/);
herr_t (*flush)(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
herr_t (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
herr_t (*lock)(H5FD_t *file, hbool_t rw);
@@ -257,6 +271,16 @@ H5_DLL herr_t H5FDread(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t ad
void *buf /*out*/);
H5_DLL herr_t H5FDwrite(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
const void *buf);
+H5_DLL herr_t H5FDread_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[],
+ haddr_t addrs[], size_t sizes[], void *bufs[] /* out */);
+H5_DLL herr_t H5FDwrite_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[],
+ haddr_t addrs[], size_t sizes[], const void *bufs[] /* in */);
+H5_DLL herr_t H5FDread_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count,
+ hid_t mem_spaces[], hid_t file_spaces[], haddr_t offsets[],
+ size_t element_sizes[], void *bufs[] /* out */);
+H5_DLL herr_t H5FDwrite_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count,
+ hid_t mem_spaces[], hid_t file_spaces[], haddr_t offsets[],
+ size_t element_sizes[], const void *bufs[]);
H5_DLL herr_t H5FDflush(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
H5_DLL herr_t H5FDtruncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
H5_DLL herr_t H5FDlock(H5FD_t *file, hbool_t rw);
diff --git a/src/H5FDdirect.c b/src/H5FDdirect.c
index 7a43117..25ee970 100644
--- a/src/H5FDdirect.c
+++ b/src/H5FDdirect.c
@@ -142,6 +142,7 @@ static herr_t H5FD__direct_unlock(H5FD_t *_file);
static herr_t H5FD__direct_delete(const char *filename, hid_t fapl_id);
static const H5FD_class_t H5FD_direct_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_DIRECT_VALUE, /* value */
"direct", /* name */
MAXADDR, /* maxaddr */
@@ -170,6 +171,10 @@ static const H5FD_class_t H5FD_direct_g = {
H5FD__direct_get_handle, /* get_handle */
H5FD__direct_read, /* read */
H5FD__direct_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
NULL, /* flush */
H5FD__direct_truncate, /* truncate */
H5FD__direct_lock, /* lock */
diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c
index 3f0080e..66a1a68 100644
--- a/src/H5FDfamily.c
+++ b/src/H5FDfamily.c
@@ -112,6 +112,7 @@ static herr_t H5FD__family_delete(const char *filename, hid_t fapl_id);
/* The class struct */
static const H5FD_class_t H5FD_family_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_FAMILY_VALUE, /* value */
"family", /* name */
HADDR_MAX, /* maxaddr */
@@ -140,6 +141,10 @@ static const H5FD_class_t H5FD_family_g = {
H5FD__family_get_handle, /* get_handle */
H5FD__family_read, /* read */
H5FD__family_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
H5FD__family_flush, /* flush */
H5FD__family_truncate, /* truncate */
H5FD__family_lock, /* lock */
diff --git a/src/H5FDhdfs.c b/src/H5FDhdfs.c
index 4927a40..f0ffb62 100644
--- a/src/H5FDhdfs.c
+++ b/src/H5FDhdfs.c
@@ -278,6 +278,7 @@ static herr_t H5FD__hdfs_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing
static herr_t H5FD__hdfs_validate_config(const H5FD_hdfs_fapl_t *fa);
static const H5FD_class_t H5FD_hdfs_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_HDFS_VALUE, /* value */
"hdfs", /* name */
MAXADDR, /* maxaddr */
@@ -306,6 +307,10 @@ static const H5FD_class_t H5FD_hdfs_g = {
H5FD__hdfs_get_handle, /* get_handle */
H5FD__hdfs_read, /* read */
H5FD__hdfs_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
NULL, /* flush */
H5FD__hdfs_truncate, /* truncate */
NULL, /* lock */
diff --git a/src/H5FDint.c b/src/H5FDint.c
index d7fe33c..0c3fe9e 100644
--- a/src/H5FDint.c
+++ b/src/H5FDint.c
@@ -34,6 +34,7 @@
#include "H5Eprivate.h" /* Error handling */
#include "H5Fprivate.h" /* File access */
#include "H5FDpkg.h" /* File Drivers */
+#include "H5FLprivate.h" /* Free Lists */
#include "H5Iprivate.h" /* IDs */
#include "H5PLprivate.h" /* Plugins */
@@ -41,10 +42,51 @@
/* Local Macros */
/****************/
+/* Length of sequence lists requested from dataspace selections */
+#define H5FD_SEQ_LIST_LEN 128
+
+/* Length of stack allocated arrays for building vector I/O operations.
+ * Corresponds to the number of contiguous blocks in a selection I/O operation.
+ * If more space is needed dynamic allocation will be used instead. */
+#define H5FD_LOCAL_VECTOR_LEN 8
+
+/* Length of stack allocated arrays for dataspace IDs/structs for selection I/O
+ * operations. Corresponds to the number of file selection/memory selection
+ * pairs (along with addresses, etc.) in a selection I/O operation. If more
+ * space is needed dynamic allocation will be used instead */
+#define H5FD_LOCAL_SEL_ARR_LEN 8
+
/******************/
/* Local Typedefs */
/******************/
+/*************************************************************************
+ *
+ * H5FD_vsrt_tmp_t
+ *
+ * Structure used to store vector I/O request addresses and the associated
+ * indexes in the addrs[] array for the purpose of determine the sorted
+ * order.
+ *
+ * This is done by allocating an array of H5FD_vsrt_tmp_t of length
+ * count, loading it with the contents of the addrs[] array and the
+ * associated indices, and then sorting it.
+ *
+ * This sorted array of H5FD_vsrt_tmp_t is then used to populate sorted
+ * versions of the types[], addrs[], sizes[] and bufs[] vectors.
+ *
+ * addr: haddr_t containing the value of addrs[i],
+ *
+ * index: integer containing the value of i used to obtain the
+ * value of the addr field from the addrs[] vector.
+ *
+ *************************************************************************/
+
+typedef struct H5FD_vsrt_tmp_t {
+ haddr_t addr;
+ int index;
+} H5FD_vsrt_tmp_t;
+
/* Information needed for iterating over the registered VFD hid_t IDs.
* The name or value of the new VFD that is being registered is stored
* in the name (or value) field and the found_id field is initialized to
@@ -66,7 +108,13 @@ typedef struct H5FD_get_driver_ud_t {
/********************/
/* Local Prototypes */
/********************/
-static int H5FD__get_driver_cb(void *obj, hid_t id, void *_op_data);
+static int H5FD__get_driver_cb(void *obj, hid_t id, void *_op_data);
+static herr_t H5FD__read_selection_translate(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count,
+ H5S_t **mem_spaces, H5S_t **file_spaces, haddr_t offsets[],
+ size_t element_sizes[], void *bufs[] /* out */);
+static herr_t H5FD__write_selection_translate(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count,
+ H5S_t **mem_spaces, H5S_t **file_spaces, haddr_t offsets[],
+ size_t element_sizes[], const void *bufs[]);
/*********************/
/* Package Variables */
@@ -80,6 +128,9 @@ static int H5FD__get_driver_cb(void *obj, hid_t id, void *_op_data);
/* Local Variables */
/*******************/
+/* Declare extern free list to manage the H5S_sel_iter_t struct */
+H5FL_EXTERN(H5S_sel_iter_t);
+
/*-------------------------------------------------------------------------
* Function: H5FD_locate_signature
*
@@ -260,6 +311,1689 @@ done:
} /* end H5FD_write() */
/*-------------------------------------------------------------------------
+ * Function: H5FD_read_vector
+ *
+ * Purpose: Private version of H5FDread_vector()
+ *
+ * Perform count reads from the specified file at the offsets
+ * provided in the addrs array, with the lengths and memory
+ * types provided in the sizes and types arrays. Data read
+ * is returned in the buffers provided in the bufs array.
+ *
+ * If i > 0 and sizes[i] == 0, presume sizes[n] = sizes[i-1]
+ * for all n >= i and < count.
+ *
+ * Similarly, if i > 0 and types[i] == H5FD_MEM_NOLIST,
+ * presume types[n] = types[i-1] for all n >= i and < count.
+ *
+ * If the underlying VFD supports vector reads, pass the
+ * call through directly.
+ *
+ * If it doesn't, convert the vector read into a sequence
+ * of individual reads.
+ *
+ * Note that it is not in general possible to convert a
+ * vector read into a selection read, because each element
+ * in the vector read may have a different memory type.
+ * In contrast, selection reads are of a single type.
+ *
+ * Return: Success: SUCCEED
+ * All reads have completed successfully, and
+ * the results havce been into the supplied
+ * buffers.
+ *
+ * Failure: FAIL
+ * The contents of supplied buffers are undefined.
+ *
+ * Programmer: JRM -- 6/10/20
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[],
+ void *bufs[] /* out */)
+{
+ hbool_t addrs_cooked = FALSE;
+ hbool_t extend_sizes = FALSE;
+ hbool_t extend_types = FALSE;
+ uint32_t i;
+ size_t size;
+ H5FD_mem_t type;
+ hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert((types) || (count == 0));
+ HDassert((addrs) || (count == 0));
+ HDassert((sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* verify that the first elements of the sizes and types arrays are
+ * valid.
+ */
+ HDassert((count == 0) || (sizes[0] != 0));
+ HDassert((count == 0) || (types[0] != H5FD_MEM_NOLIST));
+
+ /* Get proper DXPL for I/O */
+ dxpl_id = H5CX_get_dxpl();
+
+#ifndef H5_HAVE_PARALLEL
+ /* The no-op case
+ *
+ * Do not return early for Parallel mode since the I/O could be a
+ * collective transfer.
+ */
+ if (0 == count) {
+ HGOTO_DONE(SUCCEED)
+ }
+#endif /* H5_HAVE_PARALLEL */
+
+ if (file->base_addr > 0) {
+
+ /* apply the base_addr offset to the addrs array. Must undo before
+ * we return.
+ */
+ for (i = 0; i < count; i++) {
+
+ addrs[i] += file->base_addr;
+ }
+ addrs_cooked = TRUE;
+ }
+
+ /* If the file is open for SWMR read access, allow access to data past
+ * the end of the allocated space (the 'eoa'). This is done because the
+ * eoa stored in the file's superblock might be out of sync with the
+ * objects being written within the file by the application performing
+ * SWMR write operations.
+ */
+ if ((!(file->access_flags & H5F_ACC_SWMR_READ)) && (count > 0)) {
+ haddr_t eoa;
+
+ extend_sizes = FALSE;
+ extend_types = FALSE;
+
+ for (i = 0; i < count; i++) {
+
+ if (!extend_sizes) {
+
+ if (sizes[i] == 0) {
+
+ extend_sizes = TRUE;
+ size = sizes[i - 1];
+ }
+ else {
+
+ size = sizes[i];
+ }
+ }
+
+ if (!extend_types) {
+
+ if (types[i] == H5FD_MEM_NOLIST) {
+
+ extend_types = TRUE;
+ type = types[i - 1];
+ }
+ else {
+
+ type = types[i];
+ }
+ }
+
+ if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+
+ if ((addrs[i] + size) > eoa)
+
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL,
+ "addr overflow, addrs[%d] = %llu, sizes[%d] = %llu, eoa = %llu", (int)i,
+ (unsigned long long)(addrs[i]), (int)i, (unsigned long long)size,
+ (unsigned long long)eoa)
+ }
+ }
+
+ /* if the underlying VFD supports vector read, make the call */
+ if (file->cls->read_vector) {
+
+ if ((file->cls->read_vector)(file, dxpl_id, count, types, addrs, sizes, bufs) < 0)
+
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read vector request failed")
+ }
+ else {
+
+ /* otherwise, implement the vector read as a sequence of regular
+ * read calls.
+ */
+ extend_sizes = FALSE;
+ extend_types = FALSE;
+
+ for (i = 0; i < count; i++) {
+
+ /* we have already verified that sizes[0] != 0 and
+ * types[0] != H5FD_MEM_NOLIST
+ */
+
+ if (!extend_sizes) {
+
+ if (sizes[i] == 0) {
+
+ extend_sizes = TRUE;
+ size = sizes[i - 1];
+ }
+ else {
+
+ size = sizes[i];
+ }
+ }
+
+ if (!extend_types) {
+
+ if (types[i] == H5FD_MEM_NOLIST) {
+
+ extend_types = TRUE;
+ type = types[i - 1];
+ }
+ else {
+
+ type = types[i];
+ }
+ }
+
+ if ((file->cls->read)(file, type, dxpl_id, addrs[i], size, bufs[i]) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed")
+ }
+ }
+
+done:
+ /* undo the base addr offset to the addrs array if necessary */
+ if (addrs_cooked) {
+
+ HDassert(file->base_addr > 0);
+
+ for (i = 0; i < count; i++) {
+
+ addrs[i] -= file->base_addr;
+ }
+ }
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_read_vector() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_write_vector
+ *
+ * Purpose: Private version of H5FDwrite_vector()
+ *
+ * Perform count writes to the specified file at the offsets
+ * provided in the addrs array, with the lengths and memory
+ * types provided in the sizes and types arrays. Data written
+ * is taken from the buffers provided in the bufs array.
+ *
+ * If i > 0 and sizes[i] == 0, presume sizes[n] = sizes[i-1]
+ * for all n >= i and < count.
+ *
+ * Similarly, if i > 0 and types[i] == H5FD_MEM_NOLIST,
+ * presume types[n] = types[i-1] for all n >= i and < count.
+ *
+ * If the underlying VFD supports vector writes, pass the
+ * call through directly.
+ *
+ * If it doesn't, convert the vector write into a sequence
+ * of individual writes.
+ *
+ * Note that it is not in general possible to convert a
+ * vector write into a selection write, because each element
+ * in the vector write may have a different memory type.
+ * In contrast, selection writes are of a single type.
+ *
+ * Return: Success: SUCCEED
+ * All writes have completed successfully.
+ *
+ * Failure: FAIL
+ * One or more writes failed.
+ *
+ * Programmer: JRM -- 6/10/20
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[],
+ const void *bufs[])
+{
+ hbool_t addrs_cooked = FALSE;
+ hbool_t extend_sizes = FALSE;
+ hbool_t extend_types = FALSE;
+ uint32_t i;
+ size_t size;
+ H5FD_mem_t type;
+ hid_t dxpl_id; /* DXPL for operation */
+ haddr_t eoa = HADDR_UNDEF; /* EOA for file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert((types) || (count == 0));
+ HDassert((addrs) || (count == 0));
+ HDassert((sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* verify that the first elements of the sizes and types arrays are
+ * valid.
+ */
+ HDassert((count == 0) || (sizes[0] != 0));
+ HDassert((count == 0) || (types[0] != H5FD_MEM_NOLIST));
+
+ /* Get proper DXPL for I/O */
+ dxpl_id = H5CX_get_dxpl();
+
+#ifndef H5_HAVE_PARALLEL
+ /* The no-op case
+ *
+ * Do not return early for Parallel mode since the I/O could be a
+ * collective transfer.
+ */
+ if (0 == count)
+ HGOTO_DONE(SUCCEED)
+#endif /* H5_HAVE_PARALLEL */
+
+ if (file->base_addr > 0) {
+
+ /* apply the base_addr offset to the addrs array. Must undo before
+ * we return.
+ */
+ for (i = 0; i < count; i++) {
+
+ addrs[i] += file->base_addr;
+ }
+ addrs_cooked = TRUE;
+ }
+
+ extend_sizes = FALSE;
+ extend_types = FALSE;
+
+ for (i = 0; i < count; i++) {
+
+ if (!extend_sizes) {
+
+ if (sizes[i] == 0) {
+
+ extend_sizes = TRUE;
+ size = sizes[i - 1];
+ }
+ else {
+
+ size = sizes[i];
+ }
+ }
+
+ if (!extend_types) {
+
+ if (types[i] == H5FD_MEM_NOLIST) {
+
+ extend_types = TRUE;
+ type = types[i - 1];
+ }
+ else {
+
+ type = types[i];
+ }
+ }
+
+ if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+
+ if ((addrs[i] + size) > eoa)
+
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addrs[%d] = %llu, sizes[%d] = %llu, \
+ eoa = %llu",
+ (int)i, (unsigned long long)(addrs[i]), (int)i, (unsigned long long)size,
+ (unsigned long long)eoa)
+ }
+
+ /* if the underlying VFD supports vector write, make the call */
+ if (file->cls->write_vector) {
+
+ if ((file->cls->write_vector)(file, dxpl_id, count, types, addrs, sizes, bufs) < 0)
+
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write vector request failed")
+ }
+ else {
+ /* otherwise, implement the vector write as a sequence of regular
+ * write calls.
+ */
+ extend_sizes = FALSE;
+ extend_types = FALSE;
+
+ for (i = 0; i < count; i++) {
+
+ /* we have already verified that sizes[0] != 0 and
+ * types[0] != H5FD_MEM_NOLIST
+ */
+
+ if (!extend_sizes) {
+
+ if (sizes[i] == 0) {
+
+ extend_sizes = TRUE;
+ size = sizes[i - 1];
+ }
+ else {
+
+ size = sizes[i];
+ }
+ }
+
+ if (!extend_types) {
+
+ if (types[i] == H5FD_MEM_NOLIST) {
+
+ extend_types = TRUE;
+ type = types[i - 1];
+ }
+ else {
+
+ type = types[i];
+ }
+ }
+
+ if ((file->cls->write)(file, type, dxpl_id, addrs[i], size, bufs[i]) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver write request failed")
+ }
+ }
+
+done:
+ /* undo the base addr offset to the addrs array if necessary */
+ if (addrs_cooked) {
+
+ HDassert(file->base_addr > 0);
+
+ for (i = 0; i < count; i++) {
+
+ addrs[i] -= file->base_addr;
+ }
+ }
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_write_vector() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__read_selection_translate
+ *
+ * Purpose: Translates a selection read call to a vector read call if
+ * vector reads are supported, or a series of scalar read
+ * calls otherwise.
+ *
+ * Return: Success: SUCCEED
+ * All reads have completed successfully, and
+ * the results havce been into the supplied
+ * buffers.
+ *
+ * Failure: FAIL
+ * The contents of supplied buffers are undefined.
+ *
+ * Programmer: NAF -- 5/13/21
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__read_selection_translate(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count,
+ H5S_t **mem_spaces, H5S_t **file_spaces, haddr_t offsets[],
+ size_t element_sizes[], void *bufs[] /* out */)
+{
+ hbool_t extend_sizes = FALSE;
+ hbool_t extend_bufs = FALSE;
+ uint32_t i;
+ size_t element_size;
+ void * buf;
+ hbool_t use_vector = FALSE;
+ haddr_t addrs_local[H5FD_LOCAL_VECTOR_LEN];
+ haddr_t * addrs = addrs_local;
+ size_t sizes_local[H5FD_LOCAL_VECTOR_LEN];
+ size_t * sizes = sizes_local;
+ void * vec_bufs_local[H5FD_LOCAL_VECTOR_LEN];
+ void ** vec_bufs = vec_bufs_local;
+ hsize_t file_off[H5FD_SEQ_LIST_LEN];
+ size_t file_len[H5FD_SEQ_LIST_LEN];
+ hsize_t mem_off[H5FD_SEQ_LIST_LEN];
+ size_t mem_len[H5FD_SEQ_LIST_LEN];
+ size_t file_seq_i;
+ size_t mem_seq_i;
+ size_t file_nseq;
+ size_t mem_nseq;
+ size_t io_len;
+ size_t nelmts;
+ hssize_t hss_nelmts;
+ size_t seq_nelem;
+ H5S_sel_iter_t *file_iter = NULL;
+ H5S_sel_iter_t *mem_iter = NULL;
+ hbool_t file_iter_init = FALSE;
+ hbool_t mem_iter_init = FALSE;
+ H5FD_mem_t types[2] = {type, H5FD_MEM_NOLIST};
+ size_t vec_arr_nalloc = H5FD_LOCAL_VECTOR_LEN;
+ size_t vec_arr_nused = 0;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(mem_spaces);
+ HDassert(file_spaces);
+ HDassert(offsets);
+ HDassert(element_sizes);
+ HDassert(bufs);
+
+ /* Verify that the first elements of the element_sizes and bufs arrays are
+ * valid. */
+ HDassert(element_sizes[0] != 0);
+ HDassert(bufs[0] != NULL);
+
+ /* Check if we're using vector I/O */
+ use_vector = file->cls->read_vector != NULL;
+
+ /* Allocate sequence lists for memory and file spaces */
+ if (NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "couldn't allocate file selection iterator")
+ if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "couldn't allocate memory selection iterator")
+
+ /* Loop over dataspaces */
+ for (i = 0; i < count; i++) {
+
+ /* we have already verified that element_sizes[0] != 0 and bufs[0]
+ * != NULL */
+
+ if (!extend_sizes) {
+
+ if (element_sizes[i] == 0) {
+
+ extend_sizes = TRUE;
+ element_size = element_sizes[i - 1];
+ }
+ else {
+
+ element_size = element_sizes[i];
+ }
+ }
+
+ if (!extend_bufs) {
+
+ if (bufs[i] == NULL) {
+
+ extend_bufs = TRUE;
+ buf = bufs[i - 1];
+ }
+ else {
+
+ buf = bufs[i];
+ }
+ }
+
+ /* Initialize sequence lists for memory and file spaces */
+ if (H5S_select_iter_init(file_iter, file_spaces[i], element_size, 0) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for file space")
+ file_iter_init = TRUE;
+ if (H5S_select_iter_init(mem_iter, mem_spaces[i], element_size, 0) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for memory space")
+ mem_iter_init = TRUE;
+
+ /* Get the number of elements in selection */
+ if ((hss_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(file_spaces[i])) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+ H5_CHECKED_ASSIGN(nelmts, size_t, hss_nelmts, hssize_t);
+
+#ifndef NDEBUG
+ /* Verify mem space has the same number of elements */
+ {
+ if ((hss_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(mem_spaces[i])) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+ HDassert((hssize_t)nelmts == hss_nelmts);
+ }
+#endif /* NDEBUG */
+
+ /* Initialize values so sequence lists are retrieved on the first
+ * iteration */
+ file_seq_i = H5FD_SEQ_LIST_LEN;
+ mem_seq_i = H5FD_SEQ_LIST_LEN;
+ file_nseq = 0;
+ mem_nseq = 0;
+
+ /* Loop until all elements are processed */
+ while (file_seq_i < file_nseq || nelmts > 0) {
+ /* Fill/refill file sequence list if necessary */
+ if (file_seq_i == H5FD_SEQ_LIST_LEN) {
+ if (H5S_SELECT_ITER_GET_SEQ_LIST(file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq,
+ &seq_nelem, file_off, file_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ HDassert(file_nseq > 0);
+
+ nelmts -= seq_nelem;
+ file_seq_i = 0;
+ }
+ HDassert(file_seq_i < file_nseq);
+
+ /* Fill/refill memory sequence list if necessary */
+ if (mem_seq_i == H5FD_SEQ_LIST_LEN) {
+ if (H5S_SELECT_ITER_GET_SEQ_LIST(mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, &seq_nelem,
+ mem_off, mem_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ HDassert(mem_nseq > 0);
+
+ mem_seq_i = 0;
+ }
+ HDassert(mem_seq_i < mem_nseq);
+
+ /* Calculate length of this IO */
+ io_len = MIN(file_len[file_seq_i], mem_len[mem_seq_i]);
+
+ /* Check if we're using vector I/O */
+ if (use_vector) {
+ /* Check if we need to extend the arrays */
+ if (vec_arr_nused == vec_arr_nalloc) {
+ /* Check if we're using the static arrays */
+ if (addrs == addrs_local) {
+ HDassert(sizes == sizes_local);
+ HDassert(vec_bufs == vec_bufs_local);
+
+ /* Allocate dynamic arrays */
+ if (NULL == (addrs = H5MM_malloc(sizeof(addrs_local) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for address list")
+ if (NULL == (sizes = H5MM_malloc(sizeof(sizes_local) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for size list")
+ if (NULL == (vec_bufs = H5MM_malloc(sizeof(vec_bufs_local) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for buffer list")
+
+ /* Copy the existing data */
+ (void)H5MM_memcpy(addrs, addrs_local, sizeof(addrs_local));
+ (void)H5MM_memcpy(sizes, sizes_local, sizeof(sizes_local));
+ (void)H5MM_memcpy(vec_bufs, vec_bufs_local, sizeof(vec_bufs_local));
+ }
+ else {
+ void *tmp_ptr;
+
+ /* Reallocate arrays */
+ if (NULL == (tmp_ptr = H5MM_realloc(addrs, vec_arr_nalloc * sizeof(*addrs) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory reallocation failed for address list")
+ addrs = tmp_ptr;
+ if (NULL == (tmp_ptr = H5MM_realloc(sizes, vec_arr_nalloc * sizeof(*sizes) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory reallocation failed for size list")
+ sizes = tmp_ptr;
+ if (NULL ==
+ (tmp_ptr = H5MM_realloc(vec_bufs, vec_arr_nalloc * sizeof(*vec_bufs) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory reallocation failed for buffer list")
+ vec_bufs = tmp_ptr;
+ }
+
+ /* Record that we've doubled the array sizes */
+ vec_arr_nalloc *= 2;
+ }
+
+ /* Add this segment to vector read list */
+ addrs[vec_arr_nused] = offsets[i] + file_off[file_seq_i];
+ sizes[vec_arr_nused] = io_len;
+ vec_bufs[vec_arr_nused] = (void *)((uint8_t *)buf + mem_off[mem_seq_i]);
+ vec_arr_nused++;
+ }
+ else
+ /* Issue scalar read call */
+ if ((file->cls->read)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len,
+ (void *)((uint8_t *)buf + mem_off[mem_seq_i])) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed")
+
+ /* Update file sequence */
+ if (io_len == file_len[file_seq_i])
+ file_seq_i++;
+ else {
+ file_off[file_seq_i] += io_len;
+ file_len[file_seq_i] -= io_len;
+ }
+
+ /* Update memory sequence */
+ if (io_len == mem_len[mem_seq_i])
+ mem_seq_i++;
+ else {
+ mem_off[mem_seq_i] += io_len;
+ mem_len[mem_seq_i] -= io_len;
+ }
+ }
+
+ /* Make sure both memory and file sequences terminated at the same time */
+ if (mem_seq_i < mem_nseq)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "file selection terminated before memory selection")
+
+ /* Terminate iterators */
+ if (H5S_SELECT_ITER_RELEASE(file_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator")
+ file_iter_init = FALSE;
+ if (H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator")
+ mem_iter_init = FALSE;
+ }
+
+ /* Issue vector read call if appropriate */
+ if (use_vector) {
+ H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t)
+ if ((file->cls->read_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, vec_bufs) <
+ 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read vector request failed")
+ }
+
+done:
+ /* Terminate and free iterators */
+ if (file_iter) {
+ if (file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator")
+ file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
+ }
+ if (mem_iter) {
+ if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator")
+ mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
+ }
+
+ /* Cleanup vector arrays */
+ if (use_vector) {
+ if (addrs != addrs_local)
+ addrs = H5MM_xfree(addrs);
+ if (sizes != sizes_local)
+ sizes = H5MM_xfree(sizes);
+ if (vec_bufs != vec_bufs_local)
+ vec_bufs = H5MM_xfree(vec_bufs);
+ }
+
+ /* Make sure we cleaned up */
+ HDassert(!addrs || addrs == addrs_local);
+ HDassert(!sizes || sizes == sizes_local);
+ HDassert(!vec_bufs || vec_bufs == vec_bufs_local);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__read_selection_translate() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_read_selection
+ *
+ * Purpose: Private version of H5FDread_selection()
+ *
+ * Perform count reads from the specified file at the
+ * locations selected in the dataspaces in the file_spaces
+ * array, with each of those dataspaces starting at the file
+ * address specified by the corresponding element of the
+ * offsets array, and with the size of each element in the
+ * dataspace specified by the corresponding element of the
+ * element_sizes array. The memory type provided by type is
+ * the same for all selections. Data read is returned in
+ * the locations selected in the dataspaces in the
+ * mem_spaces array, within the buffers provided in the
+ * corresponding elements of the bufs array.
+ *
+ * If i > 0 and element_sizes[i] == 0, presume
+ * element_sizes[n] = element_sizes[i-1] for all n >= i and
+ * < count.
+ *
+ * If the underlying VFD supports selection reads, pass the
+ * call through directly.
+ *
+ * If it doesn't, convert the vector read into a sequence
+ * of individual reads.
+ *
+ * Return: Success: SUCCEED
+ * All reads have completed successfully, and
+ * the results havce been into the supplied
+ * buffers.
+ *
+ * Failure: FAIL
+ * The contents of supplied buffers are undefined.
+ *
+ * Programmer: NAF -- 3/29/21
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_spaces, H5S_t **file_spaces,
+ haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */)
+{
+ hbool_t offsets_cooked = FALSE;
+ hid_t mem_space_ids_local[H5FD_LOCAL_SEL_ARR_LEN];
+ hid_t * mem_space_ids = mem_space_ids_local;
+ hid_t file_space_ids_local[H5FD_LOCAL_SEL_ARR_LEN];
+ hid_t * file_space_ids = file_space_ids_local;
+ uint32_t num_spaces = 0;
+ hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */
+ uint32_t i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert((mem_spaces) || (count == 0));
+ HDassert((file_spaces) || (count == 0));
+ HDassert((offsets) || (count == 0));
+ HDassert((element_sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* Verify that the first elements of the element_sizes and bufs arrays are
+ * valid. */
+ HDassert((count == 0) || (element_sizes[0] != 0));
+ HDassert((count == 0) || (bufs[0] != NULL));
+
+ /* Get proper DXPL for I/O */
+ dxpl_id = H5CX_get_dxpl();
+
+#ifndef H5_HAVE_PARALLEL
+ /* The no-op case
+ *
+ * Do not return early for Parallel mode since the I/O could be a
+ * collective transfer.
+ */
+ if (0 == count) {
+ HGOTO_DONE(SUCCEED)
+ }
+#endif /* H5_HAVE_PARALLEL */
+
+ if (file->base_addr > 0) {
+
+ /* apply the base_addr offset to the offsets array. Must undo before
+ * we return.
+ */
+ for (i = 0; i < count; i++) {
+
+ offsets[i] += file->base_addr;
+ }
+ offsets_cooked = TRUE;
+ }
+
+ /* If the file is open for SWMR read access, allow access to data past
+ * the end of the allocated space (the 'eoa'). This is done because the
+ * eoa stored in the file's superblock might be out of sync with the
+ * objects being written within the file by the application performing
+ * SWMR write operations.
+ */
+ /* For now at least, only check that the offset is not past the eoa, since
+ * looking into the highest offset in the selection (different from the
+ * bounds) is potentially expensive.
+ */
+ if (!(file->access_flags & H5F_ACC_SWMR_READ)) {
+ haddr_t eoa;
+
+ if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+
+ for (i = 0; i < count; i++) {
+
+ if ((offsets[i]) > eoa)
+
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu",
+ (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa)
+ }
+ }
+
+ /* if the underlying VFD supports selection read, make the call */
+ if (file->cls->read_selection) {
+ /* Allocate array of space IDs if necessary, otherwise use local
+ * buffers */
+ if (count > sizeof(mem_space_ids_local) / sizeof(mem_space_ids_local[0])) {
+ if (NULL == (mem_space_ids = H5MM_malloc(count * sizeof(hid_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ if (NULL == (file_space_ids = H5MM_malloc(count * sizeof(hid_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ }
+
+ /* Create IDs for all dataspaces */
+ for (; num_spaces < count; num_spaces++) {
+ if ((mem_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, mem_spaces[num_spaces], TRUE)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+
+ if ((file_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, file_spaces[num_spaces], TRUE)) <
+ 0) {
+ if (H5I_dec_app_ref(mem_space_ids[num_spaces]) < 0)
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id")
+ HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+ }
+ }
+
+ if ((file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read selection request failed")
+ }
+ else
+ /* Otherwise, implement the selection read as a sequence of regular
+ * or vector read calls.
+ */
+ if (H5FD__read_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "translation to vector or scalar read failed")
+
+done:
+ /* undo the base addr offset to the offsets array if necessary */
+ if (offsets_cooked) {
+
+ HDassert(file->base_addr > 0);
+
+ for (i = 0; i < count; i++) {
+
+ offsets[i] -= file->base_addr;
+ }
+ }
+
+ /* Cleanup dataspace arrays */
+ for (i = 0; i < num_spaces; i++) {
+ if (H5I_dec_app_ref(mem_space_ids[i]) < 0)
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id")
+ if (H5I_dec_app_ref(file_space_ids[i]) < 0)
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id")
+ }
+ if (mem_space_ids != mem_space_ids_local)
+ mem_space_ids = H5MM_xfree(mem_space_ids);
+ if (file_space_ids != file_space_ids_local)
+ file_space_ids = H5MM_xfree(file_space_ids);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_read_selection() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_read_selection_id
+ *
+ * Purpose: Like H5FD_read_selection(), but takes hid_t arrays instead
+ * of H5S_t * arrays for the dataspaces.
+ *
+ * Return: Success: SUCCEED
+ * All reads have completed successfully, and
+ * the results havce been into the supplied
+ * buffers.
+ *
+ * Failure: FAIL
+ * The contents of supplied buffers are undefined.
+ *
+ * Programmer: NAF -- 5/19/21
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_read_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[],
+ hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[],
+ void *bufs[] /* out */)
+{
+ hbool_t offsets_cooked = FALSE;
+ H5S_t * mem_spaces_local[H5FD_LOCAL_SEL_ARR_LEN];
+ H5S_t ** mem_spaces = mem_spaces_local;
+ H5S_t * file_spaces_local[H5FD_LOCAL_SEL_ARR_LEN];
+ H5S_t ** file_spaces = file_spaces_local;
+ hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */
+ uint32_t i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert((mem_space_ids) || (count == 0));
+ HDassert((file_space_ids) || (count == 0));
+ HDassert((offsets) || (count == 0));
+ HDassert((element_sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* Verify that the first elements of the element_sizes and bufs arrays are
+ * valid. */
+ HDassert((count == 0) || (element_sizes[0] != 0));
+ HDassert((count == 0) || (bufs[0] != NULL));
+
+ /* Get proper DXPL for I/O */
+ dxpl_id = H5CX_get_dxpl();
+
+#ifndef H5_HAVE_PARALLEL
+ /* The no-op case
+ *
+ * Do not return early for Parallel mode since the I/O could be a
+ * collective transfer.
+ */
+ if (0 == count) {
+ HGOTO_DONE(SUCCEED)
+ }
+#endif /* H5_HAVE_PARALLEL */
+
+ if (file->base_addr > 0) {
+
+ /* apply the base_addr offset to the offsets array. Must undo before
+ * we return.
+ */
+ for (i = 0; i < count; i++) {
+
+ offsets[i] += file->base_addr;
+ }
+ offsets_cooked = TRUE;
+ }
+
+ /* If the file is open for SWMR read access, allow access to data past
+ * the end of the allocated space (the 'eoa'). This is done because the
+ * eoa stored in the file's superblock might be out of sync with the
+ * objects being written within the file by the application performing
+ * SWMR write operations.
+ */
+ /* For now at least, only check that the offset is not past the eoa, since
+ * looking into the highest offset in the selection (different from the
+ * bounds) is potentially expensive.
+ */
+ if (!(file->access_flags & H5F_ACC_SWMR_READ)) {
+ haddr_t eoa;
+
+ if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+
+ for (i = 0; i < count; i++) {
+
+ if ((offsets[i]) > eoa)
+
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu",
+ (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa)
+ }
+ }
+
+ /* if the underlying VFD supports selection read, make the call */
+ if (file->cls->read_selection) {
+ if ((file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read selection request failed")
+ }
+ else {
+ /* Otherwise, implement the selection read as a sequence of regular
+ * or vector read calls.
+ */
+
+ /* Allocate arrays of space objects if necessary, otherwise use local
+ * buffers */
+ if (count > sizeof(mem_spaces_local) / sizeof(mem_spaces_local[0])) {
+ if (NULL == (mem_spaces = H5MM_malloc(count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ if (NULL == (file_spaces = H5MM_malloc(count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ }
+
+ /* Get object pointers for all dataspaces */
+ for (i = 0; i < count; i++) {
+ if (NULL == (mem_spaces[i] = (H5S_t *)H5I_object_verify(mem_space_ids[i], H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve memory dataspace from ID")
+ if (NULL == (file_spaces[i] = (H5S_t *)H5I_object_verify(file_space_ids[i], H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve file dataspace from ID")
+ }
+
+ /* Translate to vector or scalar I/O */
+ if (H5FD__read_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "translation to vector or scalar read failed")
+ }
+
+done:
+ /* undo the base addr offset to the offsets array if necessary */
+ if (offsets_cooked) {
+
+ HDassert(file->base_addr > 0);
+
+ for (i = 0; i < count; i++) {
+
+ offsets[i] -= file->base_addr;
+ }
+ }
+
+ /* Cleanup dataspace arrays */
+ if (mem_spaces != mem_spaces_local)
+ mem_spaces = H5MM_xfree(mem_spaces);
+ if (file_spaces != file_spaces_local)
+ file_spaces = H5MM_xfree(file_spaces);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_read_selection_id() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__write_selection_translate
+ *
+ * Purpose: Translates a selection write call to a vector write call
+ * if vector writes are supported, or a series of scalar
+ * write calls otherwise.
+ *
+ * Return: Success: SUCCEED
+ * All writes have completed successfully.
+ *
+ * Failure: FAIL
+ * One or more writes failed.
+ *
+ * Programmer: NAF -- 5/13/21
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__write_selection_translate(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count,
+ H5S_t **mem_spaces, H5S_t **file_spaces, haddr_t offsets[],
+ size_t element_sizes[], const void *bufs[])
+{
+ hbool_t extend_sizes = FALSE;
+ hbool_t extend_bufs = FALSE;
+ uint32_t i;
+ size_t element_size;
+ const void * buf;
+ hbool_t use_vector = FALSE;
+ haddr_t addrs_local[H5FD_LOCAL_VECTOR_LEN];
+ haddr_t * addrs = addrs_local;
+ size_t sizes_local[H5FD_LOCAL_VECTOR_LEN];
+ size_t * sizes = sizes_local;
+ const void * vec_bufs_local[H5FD_LOCAL_VECTOR_LEN];
+ const void ** vec_bufs = vec_bufs_local;
+ hsize_t file_off[H5FD_SEQ_LIST_LEN];
+ size_t file_len[H5FD_SEQ_LIST_LEN];
+ hsize_t mem_off[H5FD_SEQ_LIST_LEN];
+ size_t mem_len[H5FD_SEQ_LIST_LEN];
+ size_t file_seq_i;
+ size_t mem_seq_i;
+ size_t file_nseq;
+ size_t mem_nseq;
+ size_t io_len;
+ size_t nelmts;
+ hssize_t hss_nelmts;
+ size_t seq_nelem;
+ H5S_sel_iter_t *file_iter = NULL;
+ H5S_sel_iter_t *mem_iter = NULL;
+ hbool_t file_iter_init = FALSE;
+ hbool_t mem_iter_init = FALSE;
+ H5FD_mem_t types[2] = {type, H5FD_MEM_NOLIST};
+ size_t vec_arr_nalloc = H5FD_LOCAL_VECTOR_LEN;
+ size_t vec_arr_nused = 0;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(mem_spaces);
+ HDassert(file_spaces);
+ HDassert(offsets);
+ HDassert(element_sizes);
+ HDassert(bufs);
+
+ /* Verify that the first elements of the element_sizes and bufs arrays are
+ * valid. */
+ HDassert(element_sizes[0] != 0);
+ HDassert(bufs[0] != NULL);
+
+ /* Check if we're using vector I/O */
+ use_vector = file->cls->write_vector != NULL;
+
+ /* Allocate sequence lists for memory and file spaces */
+ if (NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "couldn't allocate file selection iterator")
+ if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "couldn't allocate memory selection iterator")
+
+ /* Loop over dataspaces */
+ for (i = 0; i < count; i++) {
+
+ /* we have already verified that element_sizes[0] != 0 and bufs[0]
+ * != NULL */
+
+ if (!extend_sizes) {
+
+ if (element_sizes[i] == 0) {
+
+ extend_sizes = TRUE;
+ element_size = element_sizes[i - 1];
+ }
+ else {
+
+ element_size = element_sizes[i];
+ }
+ }
+
+ if (!extend_bufs) {
+
+ if (bufs[i] == NULL) {
+
+ extend_bufs = TRUE;
+ buf = bufs[i - 1];
+ }
+ else {
+
+ buf = bufs[i];
+ }
+ }
+
+ /* Initialize sequence lists for memory and file spaces */
+ if (H5S_select_iter_init(file_iter, file_spaces[i], element_size, 0) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for file space")
+ file_iter_init = TRUE;
+ if (H5S_select_iter_init(mem_iter, mem_spaces[i], element_size, 0) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for memory space")
+ mem_iter_init = TRUE;
+
+ /* Get the number of elements in selection */
+ if ((hss_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(file_spaces[i])) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+ H5_CHECKED_ASSIGN(nelmts, size_t, hss_nelmts, hssize_t);
+
+#ifndef NDEBUG
+ /* Verify mem space has the same number of elements */
+ {
+ if ((hss_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(mem_spaces[i])) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+ HDassert((hssize_t)nelmts == hss_nelmts);
+ }
+#endif /* NDEBUG */
+
+ /* Initialize values so sequence lists are retrieved on the first
+ * iteration */
+ file_seq_i = H5FD_SEQ_LIST_LEN;
+ mem_seq_i = H5FD_SEQ_LIST_LEN;
+ file_nseq = 0;
+ mem_nseq = 0;
+
+ /* Loop until all elements are processed */
+ while (file_seq_i < file_nseq || nelmts > 0) {
+ /* Fill/refill file sequence list if necessary */
+ if (file_seq_i == H5FD_SEQ_LIST_LEN) {
+ if (H5S_SELECT_ITER_GET_SEQ_LIST(file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq,
+ &seq_nelem, file_off, file_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ HDassert(file_nseq > 0);
+
+ nelmts -= seq_nelem;
+ file_seq_i = 0;
+ }
+ HDassert(file_seq_i < file_nseq);
+
+ /* Fill/refill memory sequence list if necessary */
+ if (mem_seq_i == H5FD_SEQ_LIST_LEN) {
+ if (H5S_SELECT_ITER_GET_SEQ_LIST(mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, &seq_nelem,
+ mem_off, mem_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ HDassert(mem_nseq > 0);
+
+ mem_seq_i = 0;
+ }
+ HDassert(mem_seq_i < mem_nseq);
+
+ /* Calculate length of this IO */
+ io_len = MIN(file_len[file_seq_i], mem_len[mem_seq_i]);
+
+ /* Check if we're using vector I/O */
+ if (use_vector) {
+ /* Check if we need to extend the arrays */
+ if (vec_arr_nused == vec_arr_nalloc) {
+ /* Check if we're using the static arrays */
+ if (addrs == addrs_local) {
+ HDassert(sizes == sizes_local);
+ HDassert(vec_bufs == vec_bufs_local);
+
+ /* Allocate dynamic arrays */
+ if (NULL == (addrs = H5MM_malloc(sizeof(addrs_local) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for address list")
+ if (NULL == (sizes = H5MM_malloc(sizeof(sizes_local) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for size list")
+ if (NULL == (vec_bufs = H5MM_malloc(sizeof(vec_bufs_local) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for buffer list")
+
+ /* Copy the existing data */
+ (void)H5MM_memcpy(addrs, addrs_local, sizeof(addrs_local));
+ (void)H5MM_memcpy(sizes, sizes_local, sizeof(sizes_local));
+ (void)H5MM_memcpy(vec_bufs, vec_bufs_local, sizeof(vec_bufs_local));
+ }
+ else {
+ void *tmp_ptr;
+
+ /* Reallocate arrays */
+ if (NULL == (tmp_ptr = H5MM_realloc(addrs, vec_arr_nalloc * sizeof(*addrs) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory reallocation failed for address list")
+ addrs = tmp_ptr;
+ if (NULL == (tmp_ptr = H5MM_realloc(sizes, vec_arr_nalloc * sizeof(*sizes) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory reallocation failed for size list")
+ sizes = tmp_ptr;
+ if (NULL ==
+ (tmp_ptr = H5MM_realloc(vec_bufs, vec_arr_nalloc * sizeof(*vec_bufs) * 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory reallocation failed for buffer list")
+ vec_bufs = tmp_ptr;
+ }
+
+ /* Record that we've doubled the array sizes */
+ vec_arr_nalloc *= 2;
+ }
+
+ /* Add this segment to vector write list */
+ addrs[vec_arr_nused] = offsets[i] + file_off[file_seq_i];
+ sizes[vec_arr_nused] = io_len;
+ vec_bufs[vec_arr_nused] = (const void *)((const uint8_t *)buf + mem_off[mem_seq_i]);
+ vec_arr_nused++;
+ }
+ else
+ /* Issue scalar write call */
+ if ((file->cls->write)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len,
+ (const void *)((const uint8_t *)buf + mem_off[mem_seq_i])) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write request failed")
+
+ /* Update file sequence */
+ if (io_len == file_len[file_seq_i])
+ file_seq_i++;
+ else {
+ file_off[file_seq_i] += io_len;
+ file_len[file_seq_i] -= io_len;
+ }
+
+ /* Update memory sequence */
+ if (io_len == mem_len[mem_seq_i])
+ mem_seq_i++;
+ else {
+ mem_off[mem_seq_i] += io_len;
+ mem_len[mem_seq_i] -= io_len;
+ }
+ }
+
+ /* Make sure both memory and file sequences terminated at the same time */
+ if (mem_seq_i < mem_nseq)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "file selection terminated before memory selection")
+
+ /* Terminate iterators */
+ if (H5S_SELECT_ITER_RELEASE(file_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator")
+ file_iter_init = FALSE;
+ if (H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator")
+ mem_iter_init = FALSE;
+ }
+
+ /* Issue vector write call if appropriate */
+ if (use_vector) {
+ H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t)
+ if ((file->cls->write_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, vec_bufs) <
+ 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write vector request failed")
+ }
+
+done:
+ /* Terminate and free iterators */
+ if (file_iter) {
+ if (file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator")
+ file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
+ }
+ if (mem_iter) {
+ if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator")
+ mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
+ }
+
+ /* Cleanup vector arrays */
+ if (use_vector) {
+ if (addrs != addrs_local)
+ addrs = H5MM_xfree(addrs);
+ if (sizes != sizes_local)
+ sizes = H5MM_xfree(sizes);
+ if (vec_bufs != vec_bufs_local)
+ vec_bufs = H5MM_xfree(vec_bufs);
+ }
+
+ /* Make sure we cleaned up */
+ HDassert(!addrs || addrs == addrs_local);
+ HDassert(!sizes || sizes == sizes_local);
+ HDassert(!vec_bufs || vec_bufs == vec_bufs_local);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__write_selection_translate() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_write_selection
+ *
+ * Purpose: Private version of H5FDwrite_selection()
+ *
+ * Perform count writes to the specified file at the
+ * locations selected in the dataspaces in the file_spaces
+ * array, with each of those dataspaces starting at the file
+ * address specified by the corresponding element of the
+ * offsets array, and with the size of each element in the
+ * dataspace specified by the corresponding element of the
+ * element_sizes array. The memory type provided by type is
+ * the same for all selections. Data write is from
+ * the locations selected in the dataspaces in the
+ * mem_spaces array, within the buffers provided in the
+ * corresponding elements of the bufs array.
+ *
+ * If i > 0 and element_sizes[i] == 0, presume
+ * element_sizes[n] = element_sizes[i-1] for all n >= i and
+ * < count.
+ *
+ * If the underlying VFD supports selection writes, pass the
+ * call through directly.
+ *
+ * If it doesn't, convert the vector write into a sequence
+ * of individual writes.
+ *
+ * Return: Success: SUCCEED
+ * All writes have completed successfully.
+ *
+ * Failure: FAIL
+ * One or more writes failed.
+ *
+ * Programmer: NAF -- 3/29/21
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_spaces, H5S_t **file_spaces,
+ haddr_t offsets[], size_t element_sizes[], const void *bufs[])
+{
+ hbool_t offsets_cooked = FALSE;
+ hid_t mem_space_ids_local[H5FD_LOCAL_SEL_ARR_LEN];
+ hid_t * mem_space_ids = mem_space_ids_local;
+ hid_t file_space_ids_local[H5FD_LOCAL_SEL_ARR_LEN];
+ hid_t * file_space_ids = file_space_ids_local;
+ uint32_t num_spaces = 0;
+ hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */
+ uint32_t i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert((mem_spaces) || (count == 0));
+ HDassert((file_spaces) || (count == 0));
+ HDassert((offsets) || (count == 0));
+ HDassert((element_sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* Verify that the first elements of the element_sizes and bufs arrays are
+ * valid. */
+ HDassert((count == 0) || (element_sizes[0] != 0));
+ HDassert((count == 0) || (bufs[0] != NULL));
+
+ /* Get proper DXPL for I/O */
+ dxpl_id = H5CX_get_dxpl();
+
+#ifndef H5_HAVE_PARALLEL
+ /* The no-op case
+ *
+ * Do not return early for Parallel mode since the I/O could be a
+ * collective transfer.
+ */
+ if (0 == count) {
+ HGOTO_DONE(SUCCEED)
+ }
+#endif /* H5_HAVE_PARALLEL */
+
+ if (file->base_addr > 0) {
+
+ /* apply the base_addr offset to the offsets array. Must undo before
+ * we return.
+ */
+ for (i = 0; i < count; i++) {
+
+ offsets[i] += file->base_addr;
+ }
+ offsets_cooked = TRUE;
+ }
+
+ /* For now at least, only check that the offset is not past the eoa, since
+ * looking into the highest offset in the selection (different from the
+ * bounds) is potentially expensive.
+ */
+ {
+ haddr_t eoa;
+
+ if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+
+ for (i = 0; i < count; i++) {
+
+ if ((offsets[i]) > eoa)
+
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu",
+ (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa)
+ }
+ }
+
+ /* if the underlying VFD supports selection write, make the call */
+ if (file->cls->write_selection) {
+ /* Allocate array of space IDs if necessary, otherwise use local
+ * buffers */
+ if (count > sizeof(mem_space_ids_local) / sizeof(mem_space_ids_local[0])) {
+ if (NULL == (mem_space_ids = H5MM_malloc(count * sizeof(hid_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ if (NULL == (file_space_ids = H5MM_malloc(count * sizeof(hid_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ }
+
+ /* Create IDs for all dataspaces */
+ for (; num_spaces < count; num_spaces++) {
+ if ((mem_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, mem_spaces[num_spaces], TRUE)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+
+ if ((file_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, file_spaces[num_spaces], TRUE)) <
+ 0) {
+ if (H5I_dec_app_ref(mem_space_ids[num_spaces]) < 0)
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id")
+ HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+ }
+ }
+
+ if ((file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write selection request failed")
+ }
+ else
+ /* Otherwise, implement the selection write as a sequence of regular
+ * or vector write calls.
+ */
+ if (H5FD__write_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "translation to vector or scalar write failed")
+
+done:
+ /* undo the base addr offset to the offsets array if necessary */
+ if (offsets_cooked) {
+
+ HDassert(file->base_addr > 0);
+
+ for (i = 0; i < count; i++) {
+
+ offsets[i] -= file->base_addr;
+ }
+ }
+
+ /* Cleanup dataspace arrays */
+ for (i = 0; i < num_spaces; i++) {
+ if (H5I_dec_app_ref(mem_space_ids[i]) < 0)
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id")
+ if (H5I_dec_app_ref(file_space_ids[i]) < 0)
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id")
+ }
+ if (mem_space_ids != mem_space_ids_local)
+ mem_space_ids = H5MM_xfree(mem_space_ids);
+ if (file_space_ids != file_space_ids_local)
+ file_space_ids = H5MM_xfree(file_space_ids);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_write_selection() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_write_selection_id
+ *
+ * Purpose: Like H5FD_write_selection(), but takes hid_t arrays
+ * instead of H5S_t * arrays for the dataspaces.
+ *
+ * Return: Success: SUCCEED
+ * All writes have completed successfully.
+ *
+ * Failure: FAIL
+ * One or more writes failed.
+ *
+ * Programmer: NAF -- 5/19/21
+ *
+ * Changes: None
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_write_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[],
+ hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], const void *bufs[])
+{
+ hbool_t offsets_cooked = FALSE;
+ H5S_t * mem_spaces_local[H5FD_LOCAL_SEL_ARR_LEN];
+ H5S_t ** mem_spaces = mem_spaces_local;
+ H5S_t * file_spaces_local[H5FD_LOCAL_SEL_ARR_LEN];
+ H5S_t ** file_spaces = file_spaces_local;
+ hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */
+ uint32_t i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert((mem_space_ids) || (count == 0));
+ HDassert((file_space_ids) || (count == 0));
+ HDassert((offsets) || (count == 0));
+ HDassert((element_sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* Verify that the first elements of the element_sizes and bufs arrays are
+ * valid. */
+ HDassert((count == 0) || (element_sizes[0] != 0));
+ HDassert((count == 0) || (bufs[0] != NULL));
+
+ /* Get proper DXPL for I/O */
+ dxpl_id = H5CX_get_dxpl();
+
+#ifndef H5_HAVE_PARALLEL
+ /* The no-op case
+ *
+ * Do not return early for Parallel mode since the I/O could be a
+ * collective transfer.
+ */
+ if (0 == count) {
+ HGOTO_DONE(SUCCEED)
+ }
+#endif /* H5_HAVE_PARALLEL */
+
+ if (file->base_addr > 0) {
+
+ /* apply the base_addr offset to the offsets array. Must undo before
+ * we return.
+ */
+ for (i = 0; i < count; i++) {
+
+ offsets[i] += file->base_addr;
+ }
+ offsets_cooked = TRUE;
+ }
+
+ /* For now at least, only check that the offset is not past the eoa, since
+ * looking into the highest offset in the selection (different from the
+ * bounds) is potentially expensive.
+ */
+ {
+ haddr_t eoa;
+
+ if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+
+ for (i = 0; i < count; i++) {
+
+ if ((offsets[i]) > eoa)
+
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu",
+ (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa)
+ }
+ }
+
+ /* if the underlying VFD supports selection write, make the call */
+ if (file->cls->write_selection) {
+ if ((file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write selection request failed")
+ }
+ else {
+ /* Otherwise, implement the selection write as a sequence of regular
+ * or vector write calls.
+ */
+
+ /* Allocate arrays of space objects if necessary, otherwise use local
+ * buffers */
+ if (count > sizeof(mem_spaces_local) / sizeof(mem_spaces_local[0])) {
+ if (NULL == (mem_spaces = H5MM_malloc(count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ if (NULL == (file_spaces = H5MM_malloc(count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list")
+ }
+
+ /* Get object pointers for all dataspaces */
+ for (i = 0; i < count; i++) {
+ if (NULL == (mem_spaces[i] = (H5S_t *)H5I_object_verify(mem_space_ids[i], H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve memory dataspace from ID")
+ if (NULL == (file_spaces[i] = (H5S_t *)H5I_object_verify(file_space_ids[i], H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve file dataspace from ID")
+ }
+
+ /* Translate to vector or scalar I/O */
+ if (H5FD__write_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets,
+ element_sizes, bufs) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "translation to vector or scalar write failed")
+ }
+
+done:
+ /* undo the base addr offset to the offsets array if necessary */
+ if (offsets_cooked) {
+
+ HDassert(file->base_addr > 0);
+
+ for (i = 0; i < count; i++) {
+
+ offsets[i] -= file->base_addr;
+ }
+ }
+
+ /* Cleanup dataspace arrays */
+ if (mem_spaces != mem_spaces_local)
+ mem_spaces = H5MM_xfree(mem_spaces);
+ if (file_spaces != file_spaces_local)
+ file_spaces = H5MM_xfree(file_spaces);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_write_selection_id() */
+
+/*-------------------------------------------------------------------------
* Function: H5FD_set_eoa
*
* Purpose: Private version of H5FDset_eoa()
@@ -399,6 +2133,246 @@ H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags /*out*/)
} /* end H5FD_driver_query() */
/*-------------------------------------------------------------------------
+ * Function: H5FD_sort_vector_io_req
+ *
+ * Purpose: Determine whether the supplied vector I/O request is
+ * sorted.
+ *
+ * if is is, set *vector_was_sorted to TRUE, set:
+ *
+ * *s_types_ptr = types
+ * *s_addrs_ptr = addrs
+ * *s_sizes_ptr = sizes
+ * *s_bufs_ptr = bufs
+ *
+ * and return.
+ *
+ * If it is not sorted, duplicate the type, addrs, sizes,
+ * and bufs vectors, storing the base addresses of the new
+ * vectors in *s_types_ptr, *s_addrs_ptr, *s_sizes_ptr, and
+ * *s_bufs_ptr respectively. Determine the sorted order
+ * of the vector I/O request, and load it into the new
+ * vectors in sorted order.
+ *
+ * Note that in this case, it is the callers responsibility
+ * to free the sorted vectors.
+ *
+ * JRM -- 3/15/21
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int
+H5FD__vsrt_tmp_cmp(const void *element_1, const void *element_2)
+{
+ haddr_t addr_1 = ((const H5FD_vsrt_tmp_t *)element_1)->addr;
+ haddr_t addr_2 = ((const H5FD_vsrt_tmp_t *)element_2)->addr;
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(H5F_addr_defined(addr_1));
+ HDassert(H5F_addr_defined(addr_2));
+
+ /* Compare the addresses */
+ if (H5F_addr_gt(addr_1, addr_2))
+ ret_value = 1;
+ else if (H5F_addr_lt(addr_1, addr_2))
+ ret_value = -1;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__vsrt_tmp_cmp() */
+
+herr_t
+H5FD_sort_vector_io_req(hbool_t *vector_was_sorted, uint32_t _count, H5FD_mem_t types[], haddr_t addrs[],
+ size_t sizes[], H5_flexible_const_ptr_t bufs[], H5FD_mem_t **s_types_ptr,
+ haddr_t **s_addrs_ptr, size_t **s_sizes_ptr, H5_flexible_const_ptr_t **s_bufs_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ size_t count = (size_t)_count;
+ size_t i;
+ struct H5FD_vsrt_tmp_t *srt_tmp = NULL;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+
+ HDassert(vector_was_sorted);
+
+ HDassert((types) || (count == 0));
+ HDassert((addrs) || (count == 0));
+ HDassert((sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* verify that the first elements of the sizes and types arrays are
+ * valid.
+ */
+ HDassert((count == 0) || (sizes[0] != 0));
+ HDassert((count == 0) || (types[0] != H5FD_MEM_NOLIST));
+
+ HDassert((count == 0) || ((s_types_ptr) && (NULL == *s_types_ptr)));
+ HDassert((count == 0) || ((s_addrs_ptr) && (NULL == *s_addrs_ptr)));
+ HDassert((count == 0) || ((s_sizes_ptr) && (NULL == *s_sizes_ptr)));
+ HDassert((count == 0) || ((s_bufs_ptr) && (NULL == *s_bufs_ptr)));
+
+ /* scan the addrs array to see if it is sorted */
+ for (i = 1; i < count; i++) {
+ HDassert(H5F_addr_defined(addrs[i - 1]));
+
+ if (H5F_addr_gt(addrs[i - 1], addrs[i]))
+ break;
+ else if (H5F_addr_eq(addrs[i - 1], addrs[i]))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "duplicate addr in vector")
+ }
+
+ /* if we traversed the entire array without breaking out, then
+ * the array was already sorted */
+ if (i >= count)
+ *vector_was_sorted = TRUE;
+ else
+ *vector_was_sorted = FALSE;
+
+ if (*vector_was_sorted) {
+
+ *s_types_ptr = types;
+ *s_addrs_ptr = addrs;
+ *s_sizes_ptr = sizes;
+ *s_bufs_ptr = bufs;
+ }
+ else {
+
+ /* must sort the addrs array in increasing addr order, while
+ * maintaining the association between each addr, and the
+ * sizes[], types[], and bufs[] values at the same index.
+ *
+ * Do this by allocating an array of struct H5FD_vsrt_tmp_t, where
+ * each instance of H5FD_vsrt_tmp_t has two fields, addr and index.
+ * Load the array with the contents of the addrs array and
+ * the index of the associated entry. Sort the array, allocate
+ * the s_types_ptr, s_addrs_ptr, s_sizes_ptr, and s_bufs_ptr
+ * arrays and populate them using the mapping provided by
+ * the sorted array of H5FD_vsrt_tmp_t.
+ */
+ int j;
+ size_t fixed_size_index = count;
+ size_t fixed_type_index = count;
+ size_t srt_tmp_size;
+
+ srt_tmp_size = (count * sizeof(struct H5FD_vsrt_tmp_t));
+
+ if (NULL == (srt_tmp = (H5FD_vsrt_tmp_t *)HDmalloc(srt_tmp_size)))
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't alloc srt_tmp")
+
+ for (i = 0; i < count; i++) {
+ HDassert(i == (size_t)((int)i));
+
+ srt_tmp[i].addr = addrs[i];
+ srt_tmp[i].index = (int)i;
+ }
+
+ /* sort the srt_tmp array */
+ HDqsort(srt_tmp, count, sizeof(struct H5FD_vsrt_tmp_t), H5FD__vsrt_tmp_cmp);
+
+ /* verify no duplicate entries */
+ i = 1;
+
+ for (i = 1; i < count; i++) {
+ HDassert(H5F_addr_lt(srt_tmp[i - 1].addr, srt_tmp[i].addr));
+
+ if (H5F_addr_eq(addrs[i - 1], addrs[i]))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "duplicate addr in vector")
+ }
+
+ if ((NULL == (*s_types_ptr = (H5FD_mem_t *)HDmalloc(count * sizeof(H5FD_mem_t)))) ||
+ (NULL == (*s_addrs_ptr = (haddr_t *)HDmalloc(count * sizeof(haddr_t)))) ||
+ (NULL == (*s_sizes_ptr = (size_t *)HDmalloc(count * sizeof(size_t)))) ||
+ (NULL ==
+ (*s_bufs_ptr = (H5_flexible_const_ptr_t *)HDmalloc(count * sizeof(H5_flexible_const_ptr_t))))) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't alloc sorted vector(s)")
+ }
+
+ HDassert(sizes[0] != 0);
+ HDassert(types[0] != H5FD_MEM_NOLIST);
+
+ /* Scan the sizes and types vectors to determine if the fixed size / type
+ * optimization is in use, and if so, to determine the index of the last
+ * valid value on each vector. We have already verified that the first
+ * elements of these arrays are valid so we can start at the second
+ * element (if it exists).
+ */
+ for (i = 1; i < count && ((fixed_size_index == count) || (fixed_type_index == count)); i++) {
+ if ((fixed_size_index == count) && (sizes[i] == 0))
+ fixed_size_index = i - 1;
+ if ((fixed_type_index == count) && (types[i] == H5FD_MEM_NOLIST))
+ fixed_type_index = i - 1;
+ }
+
+ HDassert(fixed_size_index <= count);
+ HDassert(fixed_type_index <= count);
+
+ /* populate the sorted vectors */
+ for (i = 0; i < count; i++) {
+
+ j = srt_tmp[i].index;
+
+ (*s_types_ptr)[j] = types[MIN(i, fixed_type_index)];
+ (*s_addrs_ptr)[j] = addrs[i];
+ (*s_sizes_ptr)[j] = sizes[MIN(i, fixed_size_index)];
+ (*s_bufs_ptr)[j] = bufs[i];
+ }
+ }
+
+done:
+ if (srt_tmp) {
+
+ HDfree(srt_tmp);
+ srt_tmp = NULL;
+ }
+
+ /* On failure, free the sorted vectors if they were allocated.
+ * Note that we only allocate these vectors if the original array
+ * was not sorted -- thus we check both for failure, and for
+ * the flag indicating that the original vector was not sorted
+ * in increasing address order.
+ */
+ if ((ret_value != SUCCEED) && (!(*vector_was_sorted))) {
+
+ /* free space allocated for sorted vectors */
+ if (*s_types_ptr) {
+
+ HDfree(*s_types_ptr);
+ *s_types_ptr = NULL;
+ }
+
+ if (*s_addrs_ptr) {
+
+ HDfree(*s_addrs_ptr);
+ *s_addrs_ptr = NULL;
+ }
+
+ if (*s_sizes_ptr) {
+
+ HDfree(*s_sizes_ptr);
+ *s_sizes_ptr = NULL;
+ }
+
+ if (*s_bufs_ptr) {
+
+ HDfree(*s_bufs_ptr);
+ *s_bufs_ptr = NULL;
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5FD_sort_vector_io_req() */
+
+/*-------------------------------------------------------------------------
* Function: H5FD_delete
*
* Purpose: Private version of H5FDdelete()
@@ -418,6 +2392,7 @@ H5FD_delete(const char *filename, hid_t fapl_id)
FUNC_ENTER_NOAPI(FAIL)
/* Sanity checks */
+
HDassert(filename);
/* Get file access property list */
diff --git a/src/H5FDlog.c b/src/H5FDlog.c
index af34682..4d2e705 100644
--- a/src/H5FDlog.c
+++ b/src/H5FDlog.c
@@ -180,41 +180,46 @@ static herr_t H5FD__log_unlock(H5FD_t *_file);
static herr_t H5FD__log_delete(const char *filename, hid_t fapl_id);
static const H5FD_class_t H5FD_log_g = {
- H5FD_LOG_VALUE, /* value */
- "log", /* name */
- MAXADDR, /* maxaddr */
- H5F_CLOSE_WEAK, /* fc_degree */
- H5FD__log_term, /* terminate */
- NULL, /* sb_size */
- NULL, /* sb_encode */
- NULL, /* sb_decode */
- sizeof(H5FD_log_fapl_t), /* fapl_size */
- H5FD__log_fapl_get, /* fapl_get */
- H5FD__log_fapl_copy, /* fapl_copy */
- H5FD__log_fapl_free, /* fapl_free */
- 0, /* dxpl_size */
- NULL, /* dxpl_copy */
- NULL, /* dxpl_free */
- H5FD__log_open, /* open */
- H5FD__log_close, /* close */
- H5FD__log_cmp, /* cmp */
- H5FD__log_query, /* query */
- NULL, /* get_type_map */
- H5FD__log_alloc, /* alloc */
- H5FD__log_free, /* free */
- H5FD__log_get_eoa, /* get_eoa */
- H5FD__log_set_eoa, /* set_eoa */
- H5FD__log_get_eof, /* get_eof */
- H5FD__log_get_handle, /* get_handle */
- H5FD__log_read, /* read */
- H5FD__log_write, /* write */
- NULL, /* flush */
- H5FD__log_truncate, /* truncate */
- H5FD__log_lock, /* lock */
- H5FD__log_unlock, /* unlock */
- H5FD__log_delete, /* del */
- NULL, /* ctl */
- H5FD_FLMAP_DICHOTOMY /* fl_map */
+ H5FD_CLASS_VERSION, /* struct version */
+ H5FD_LOG_VALUE, /* value */
+ "log", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD__log_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ sizeof(H5FD_log_fapl_t), /* fapl_size */
+ H5FD__log_fapl_get, /* fapl_get */
+ H5FD__log_fapl_copy, /* fapl_copy */
+ H5FD__log_fapl_free, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD__log_open, /* open */
+ H5FD__log_close, /* close */
+ H5FD__log_cmp, /* cmp */
+ H5FD__log_query, /* query */
+ NULL, /* get_type_map */
+ H5FD__log_alloc, /* alloc */
+ H5FD__log_free, /* free */
+ H5FD__log_get_eoa, /* get_eoa */
+ H5FD__log_set_eoa, /* set_eoa */
+ H5FD__log_get_eof, /* get_eof */
+ H5FD__log_get_handle, /* get_handle */
+ H5FD__log_read, /* read */
+ H5FD__log_write, /* write */
+ NULL, /* read vector */
+ NULL, /* write vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
+ NULL, /* flush */
+ H5FD__log_truncate, /* truncate */
+ H5FD__log_lock, /* lock */
+ H5FD__log_unlock, /* unlock */
+ H5FD__log_delete, /* del */
+ NULL, /* ctl */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
};
/* Default configuration, if none provided */
diff --git a/src/H5FDmirror.c b/src/H5FDmirror.c
index e74901a..0ab5345 100644
--- a/src/H5FDmirror.c
+++ b/src/H5FDmirror.c
@@ -160,6 +160,7 @@ static herr_t H5FD__mirror_unlock(H5FD_t *_file);
static herr_t H5FD__mirror_verify_reply(H5FD_mirror_t *file);
static const H5FD_class_t H5FD_mirror_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_MIRROR_VALUE, /* value */
"mirror", /* name */
MAXADDR, /* maxaddr */
@@ -188,6 +189,10 @@ static const H5FD_class_t H5FD_mirror_g = {
NULL, /* get_handle */
H5FD__mirror_read, /* read */
H5FD__mirror_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
NULL, /* flush */
H5FD__mirror_truncate, /* truncate */
H5FD__mirror_lock, /* lock */
diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c
index 4aa8a96..6b639f9 100644
--- a/src/H5FDmpio.c
+++ b/src/H5FDmpio.c
@@ -87,49 +87,66 @@ static herr_t H5FD__mpio_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, ha
void *buf);
static herr_t H5FD__mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
const void *buf);
+static herr_t H5FD__mpio_read_vector(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, uint32_t count,
+ H5FD_mem_t types[], haddr_t addrs[], size_t sizes[], void *bufs[]);
+static herr_t H5FD__mpio_write_vector(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, uint32_t count,
+ H5FD_mem_t types[], haddr_t addrs[], size_t sizes[],
+ const void *bufs[]);
static herr_t H5FD__mpio_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
static herr_t H5FD__mpio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
static herr_t H5FD__mpio_delete(const char *filename, hid_t fapl_id);
static herr_t H5FD__mpio_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input,
void **output);
+/* Other functions */
+static herr_t H5FD__mpio_vector_build_types(
+ uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[], H5_flexible_const_ptr_t bufs[],
+ haddr_t *s_addrs[], size_t *s_sizes[], H5_flexible_const_ptr_t *s_bufs[], hbool_t *vector_was_sorted,
+ MPI_Offset *mpi_off, H5_flexible_const_ptr_t *mpi_bufs_base, int *size_i, MPI_Datatype *buf_type,
+ hbool_t *buf_type_created, MPI_Datatype *file_type, hbool_t *file_type_created, char *unused);
+
/* The MPIO file driver information */
static const H5FD_class_t H5FD_mpio_g = {
- H5_VFD_MPIO, /* value */
- "mpio", /* name */
- HADDR_MAX, /* maxaddr */
- H5F_CLOSE_SEMI, /* fc_degree */
- H5FD__mpio_term, /* terminate */
- NULL, /* sb_size */
- NULL, /* sb_encode */
- NULL, /* sb_decode */
- 0, /* fapl_size */
- NULL, /* fapl_get */
- NULL, /* fapl_copy */
- NULL, /* fapl_free */
- 0, /* dxpl_size */
- NULL, /* dxpl_copy */
- NULL, /* dxpl_free */
- H5FD__mpio_open, /* open */
- H5FD__mpio_close, /* close */
- NULL, /* cmp */
- H5FD__mpio_query, /* query */
- NULL, /* get_type_map */
- NULL, /* alloc */
- NULL, /* free */
- H5FD__mpio_get_eoa, /* get_eoa */
- H5FD__mpio_set_eoa, /* set_eoa */
- H5FD__mpio_get_eof, /* get_eof */
- H5FD__mpio_get_handle, /* get_handle */
- H5FD__mpio_read, /* read */
- H5FD__mpio_write, /* write */
- H5FD__mpio_flush, /* flush */
- H5FD__mpio_truncate, /* truncate */
- NULL, /* lock */
- NULL, /* unlock */
- H5FD__mpio_delete, /* del */
- H5FD__mpio_ctl, /* ctl */
- H5FD_FLMAP_DICHOTOMY /* fl_map */
+ H5FD_CLASS_VERSION, /* struct version */
+ H5_VFD_MPIO, /* value */
+ "mpio", /* name */
+ HADDR_MAX, /* maxaddr */
+ H5F_CLOSE_SEMI, /* fc_degree */
+ H5FD__mpio_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ 0, /* fapl_size */
+ NULL, /* fapl_get */
+ NULL, /* fapl_copy */
+ NULL, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD__mpio_open, /* open */
+ H5FD__mpio_close, /* close */
+ NULL, /* cmp */
+ H5FD__mpio_query, /* query */
+ NULL, /* get_type_map */
+ NULL, /* alloc */
+ NULL, /* free */
+ H5FD__mpio_get_eoa, /* get_eoa */
+ H5FD__mpio_set_eoa, /* set_eoa */
+ H5FD__mpio_get_eof, /* get_eof */
+ H5FD__mpio_get_handle, /* get_handle */
+ H5FD__mpio_read, /* read */
+ H5FD__mpio_write, /* write */
+ H5FD__mpio_read_vector, /* read_vector */
+ H5FD__mpio_write_vector, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
+ H5FD__mpio_flush, /* flush */
+ H5FD__mpio_truncate, /* truncate */
+ NULL, /* lock */
+ NULL, /* unlock */
+ H5FD__mpio_delete, /* del */
+ H5FD__mpio_ctl, /* ctl */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
};
#ifdef H5FDmpio_DEBUG
@@ -1415,7 +1432,7 @@ H5FD__mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNU
#ifdef H5FDmpio_DEBUG
if (H5FD_mpio_debug_r_flag)
HDfprintf(stderr, "%s: (%d) mpi_off = %ld bytes_read = %lld type = %s\n", __func__, file->mpi_rank,
- (long)mpi_off, bytes_read, H5FD__mem_t_to_str(type));
+ (long)mpi_off, (long long)bytes_read, H5FD__mem_t_to_str(type));
#endif
/*
@@ -1636,7 +1653,7 @@ H5FD__mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, h
#ifdef H5FDmpio_DEBUG
if (H5FD_mpio_debug_w_flag)
HDfprintf(stderr, "%s: (%d) mpi_off = %ld bytes_written = %lld type = %s\n", __func__,
- file->mpi_rank, (long)mpi_off, bytes_written, H5FD__mem_t_to_str(type));
+ file->mpi_rank, (long)mpi_off, (long long)bytes_written, H5FD__mem_t_to_str(type));
#endif
/* Each process will keep track of its perceived EOF value locally, and
@@ -1663,6 +1680,1050 @@ done:
} /* end H5FD__mpio_write() */
/*-------------------------------------------------------------------------
+ * Function: H5FD__mpio_vector_build_types
+ *
+ * Purpose: Build MPI datatypes and calculate offset, base buffer, and
+ * size for MPIO vector I/O. Spun off from common code in
+ * H5FD__mpio_vector_read() and H5FD__mpio_vector_write().
+ *
+ * Return: Success: SUCCEED.
+ * Failure: FAIL.
+ *
+ * Programmer: Neil Fortner
+ * March 14, 2022
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__mpio_vector_build_types(uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[],
+ H5_flexible_const_ptr_t bufs[], haddr_t *s_addrs[], size_t *s_sizes[],
+ H5_flexible_const_ptr_t *s_bufs[], hbool_t *vector_was_sorted,
+ MPI_Offset *mpi_off, H5_flexible_const_ptr_t *mpi_bufs_base, int *size_i,
+ MPI_Datatype *buf_type, hbool_t *buf_type_created, MPI_Datatype *file_type,
+ hbool_t *file_type_created, char *unused)
+{
+ hsize_t bigio_count; /* Transition point to create derived type */
+ hbool_t fixed_size = FALSE;
+ size_t size;
+ H5FD_mem_t * s_types = NULL;
+ int * mpi_block_lengths = NULL;
+ MPI_Aint mpi_bufs_base_Aint;
+ MPI_Aint * mpi_bufs = NULL;
+ MPI_Aint * mpi_displacements = NULL;
+ MPI_Datatype *sub_types = NULL;
+ uint8_t * sub_types_created = NULL;
+ int i;
+ int j;
+ int mpi_code; /* MPI return code */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(s_sizes);
+ HDassert(s_bufs);
+ HDassert(vector_was_sorted);
+ HDassert(*vector_was_sorted);
+ HDassert(mpi_off);
+ HDassert(mpi_bufs_base);
+ HDassert(size_i);
+ HDassert(buf_type);
+ HDassert(buf_type_created);
+ HDassert(!*buf_type_created);
+ HDassert(file_type);
+ HDassert(file_type_created);
+ HDassert(!*file_type_created);
+ HDassert(unused);
+
+ /* Get bio I/O transition point (may be lower than 2G for testing) */
+ bigio_count = H5_mpi_get_bigio_count();
+
+ if (count == 1) {
+ /* Single block. Just use a series of MPI_BYTEs for the file view.
+ */
+ *size_i = (int)sizes[0];
+ *buf_type = MPI_BYTE;
+ *file_type = MPI_BYTE;
+ *mpi_bufs_base = bufs[0];
+
+ /* Setup s_addrs, s_sizes and s_bufs (needed for incomplete read filling code and eof
+ * calculation code) */
+ *s_addrs = addrs;
+ *s_sizes = sizes;
+ *s_bufs = bufs;
+
+ /* some numeric conversions */
+ if (H5FD_mpi_haddr_to_MPIOff(addrs[0], mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't set MPI offset")
+
+ /* Check for size overflow */
+ if (sizes[0] > bigio_count) {
+ /* We need to work around the integer size limit of 2GB. The input size_t size
+ * variable cannot fit into an integer, but we can get around that limitation by
+ * creating a different datatype and then setting the integer size (or element
+ * count) to 1 when using the derived_type. */
+
+ if (H5_mpio_create_large_type(sizes[0], 0, MPI_BYTE, buf_type) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTGET, FAIL, "can't create MPI-I/O datatype")
+ *buf_type_created = TRUE;
+
+ if (H5_mpio_create_large_type(sizes[0], 0, MPI_BYTE, file_type) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTGET, FAIL, "can't create MPI-I/O datatype")
+ *file_type_created = TRUE;
+
+ *size_i = 1;
+ }
+ }
+ else if (count > 0) { /* create MPI derived types describing the vector write */
+
+ /* sort the vector I/O request into increasing address order if required
+ *
+ * If the vector is already sorted, the base addresses of types, addrs, sizes,
+ * and bufs will be returned in s_types, s_addrs, s_sizes, and s_bufs respectively.
+ *
+ * If the vector was not already sorted, new, sorted versions of types, addrs, sizes, and bufs
+ * are allocated, populated, and returned in s_types, s_addrs, s_sizes, and s_bufs respectively.
+ * In this case, this function must free the memory allocated for the sorted vectors.
+ */
+ if (H5FD_sort_vector_io_req(vector_was_sorted, count, types, addrs, sizes, bufs, &s_types, s_addrs,
+ s_sizes, s_bufs) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't sort vector I/O request")
+
+ if ((NULL == (mpi_block_lengths = (int *)HDmalloc((size_t)count * sizeof(int)))) ||
+ (NULL == (mpi_displacements = (MPI_Aint *)HDmalloc((size_t)count * sizeof(MPI_Aint)))) ||
+ (NULL == (mpi_bufs = (MPI_Aint *)HDmalloc((size_t)count * sizeof(MPI_Aint))))) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't alloc mpi block lengths / displacement")
+ }
+
+ /* when we setup mpi_bufs[] below, all addresses are offsets from
+ * mpi_bufs_base.
+ *
+ * Since these offsets must all be positive, we must scan through
+ * s_bufs[] to find the smallest value, and choose that for
+ * mpi_bufs_base.
+ */
+
+ j = 0; /* guess at the index of the smallest value of s_bufs[] */
+
+ for (i = 1; i < (int)count; i++) {
+
+ if ((*s_bufs)[i].cvp < (*s_bufs)[j].cvp) {
+
+ j = i;
+ }
+ }
+
+ *mpi_bufs_base = (*s_bufs)[j];
+
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_address(mpi_bufs_base->cvp, &mpi_bufs_base_Aint)))
+
+ HMPI_GOTO_ERROR(FAIL, "MPI_Get_address for s_bufs[] to mpi_bufs_base failed", mpi_code)
+
+ *size_i = 1;
+
+ fixed_size = FALSE;
+
+ /* load the mpi_block_lengths and mpi_displacements arrays */
+ for (i = 0; i < (int)count; i++) {
+ /* Determine size of this vector element */
+ if (!fixed_size) {
+ if ((*s_sizes)[i] == 0) {
+ HDassert(vector_was_sorted);
+ fixed_size = TRUE;
+ size = sizes[i - 1];
+ }
+ else {
+ size = (*s_sizes)[i];
+ }
+ }
+
+ /* Add to block lengths and displacements arrays */
+ mpi_block_lengths[i] = (int)size;
+ mpi_displacements[i] = (MPI_Aint)(*s_addrs)[i];
+
+ /* convert s_bufs[i] to MPI_Aint... */
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_address((*s_bufs)[i].cvp, &(mpi_bufs[i]))))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Get_address for s_bufs[] - mpi_bufs_base failed", mpi_code)
+
+ /*... and then subtract mpi_bufs_base_Aint from it. */
+#if ((MPI_VERSION > 3) || ((MPI_VERSION == 3) && (MPI_SUBVERSION >= 1)))
+ mpi_bufs[i] = MPI_Aint_diff(mpi_bufs[i], mpi_bufs_base_Aint);
+#else
+ mpi_bufs[i] = mpi_bufs[i] - mpi_bufs_base_Aint;
+#endif
+
+ /* Check for size overflow */
+ if (size > bigio_count) {
+ /* We need to work around the integer size limit of 2GB. The input size_t size
+ * variable cannot fit into an integer, but we can get around that limitation by
+ * creating a different datatype and then setting the integer size (or element
+ * count) to 1 when using the derived_type. */
+
+ /* Allocate arrays to keep track of types and whether they were created, if
+ * necessary */
+ if (!sub_types) {
+ HDassert(!sub_types_created);
+
+ if (NULL == (sub_types = (int *)HDmalloc((size_t)count * sizeof(MPI_Datatype))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't alloc sub types array")
+ if (NULL == (sub_types_created = (uint8_t *)HDcalloc((size_t)count, 1))) {
+ H5MM_free(sub_types);
+ sub_types = NULL;
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't alloc sub types created array")
+ }
+
+ /* Initialize sub_types to all MPI_BYTE */
+ for (j = 0; j < (int)count; j++)
+ sub_types[j] = MPI_BYTE;
+ }
+ HDassert(sub_types_created);
+
+ /* Create type for large block */
+ if (H5_mpio_create_large_type(size, 0, MPI_BYTE, &sub_types[i]) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTGET, FAIL, "can't create MPI-I/O datatype")
+ sub_types_created[i] = TRUE;
+
+ /* Only one of these large types for this vector element */
+ mpi_block_lengths[i] = 1;
+ }
+ else
+ HDassert(size == (size_t)mpi_block_lengths[i]);
+ }
+
+ /* create the memory MPI derived types */
+ if (sub_types) {
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)count, mpi_block_lengths, mpi_bufs,
+ sub_types, buf_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct for buf_type failed", mpi_code)
+ }
+ else if (MPI_SUCCESS != (mpi_code = MPI_Type_create_hindexed((int)count, mpi_block_lengths, mpi_bufs,
+ MPI_BYTE, buf_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed for buf_type failed", mpi_code)
+
+ *buf_type_created = TRUE;
+
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_commit(buf_type)))
+
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit for buf_type failed", mpi_code)
+
+ /* create the file MPI derived type */
+ if (sub_types) {
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)count, mpi_block_lengths,
+ mpi_displacements, sub_types, file_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct for file_type failed", mpi_code)
+ }
+ else if (MPI_SUCCESS != (mpi_code = MPI_Type_create_hindexed((int)count, mpi_block_lengths,
+ mpi_displacements, MPI_BYTE, file_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed for file_type failed", mpi_code)
+
+ *file_type_created = TRUE;
+
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_commit(file_type)))
+
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit for file_type failed", mpi_code)
+
+ /* Free up memory used to build types */
+ HDassert(mpi_block_lengths);
+ HDfree(mpi_block_lengths);
+ mpi_block_lengths = NULL;
+
+ HDassert(mpi_displacements);
+ HDfree(mpi_displacements);
+ mpi_displacements = NULL;
+
+ HDassert(mpi_bufs);
+ HDfree(mpi_bufs);
+ mpi_bufs = NULL;
+
+ if (sub_types) {
+ HDassert(sub_types);
+
+ for (i = 0; i < (int)count; i++)
+ if (sub_types_created[i])
+ MPI_Type_free(&sub_types[i]);
+
+ HDfree(sub_types);
+ sub_types = NULL;
+ HDfree(sub_types_created);
+ sub_types_created = NULL;
+ }
+
+ /* some numeric conversions */
+ if (H5FD_mpi_haddr_to_MPIOff((haddr_t)0, mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't set MPI off to 0")
+ }
+ else {
+ /* setup for null participation in the collective operation. */
+ *buf_type = MPI_BYTE;
+ *file_type = MPI_BYTE;
+
+ /* Set non-NULL pointer for I/O operation */
+ mpi_bufs_base->vp = unused;
+
+ /* MPI count to read */
+ *size_i = 0;
+
+ /* some numeric conversions */
+ if (H5FD_mpi_haddr_to_MPIOff((haddr_t)0, mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't set MPI off to 0")
+ }
+
+done:
+ /* free sorted vectors if they exist */
+ if (!vector_was_sorted)
+ if (s_types) {
+ HDfree(s_types);
+ s_types = NULL;
+ }
+
+ /* Clean up on error */
+ if (ret_value < 0) {
+ if (mpi_block_lengths) {
+ HDfree(mpi_block_lengths);
+ mpi_block_lengths = NULL;
+ }
+
+ if (mpi_displacements) {
+ HDfree(mpi_displacements);
+ mpi_displacements = NULL;
+ }
+
+ if (mpi_bufs) {
+ HDfree(mpi_bufs);
+ mpi_bufs = NULL;
+ }
+
+ if (sub_types) {
+ HDassert(sub_types_created);
+
+ for (i = 0; i < (int)count; i++)
+ if (sub_types_created[i])
+ MPI_Type_free(&sub_types[i]);
+
+ HDfree(sub_types);
+ sub_types = NULL;
+ HDfree(sub_types_created);
+ sub_types_created = NULL;
+ }
+ }
+
+ /* Make sure we cleaned up */
+ HDassert(!mpi_block_lengths);
+ HDassert(!mpi_displacements);
+ HDassert(!mpi_bufs);
+ HDassert(!sub_types);
+ HDassert(!sub_types_created);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__mpio_vector_build_types() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__mpio_read_vector()
+ *
+ * Purpose: The behaviour of this function dependes on the value of
+ * the io_xfer_mode obtained from the context.
+ *
+ * If it is H5FD_MPIO_COLLECTIVE, this is a collective
+ * operation, which allows us to use MPI_File_set_view, and
+ * then perform the entire vector read in a single MPI call.
+ *
+ * Do this (if count is positive), by constructing memory
+ * and file derived types from the supplied vector, using
+ * file type to set the file view, and then reading the
+ * the memory type from file. Note that this read is
+ * either independent or collective depending on the
+ * value of mpio_coll_opt -- again obtained from the context.
+ *
+ * If count is zero, participate in the collective read
+ * (if so configured) with an empty read.
+ *
+ * Finally, set the file view back to its default state.
+ *
+ * In contrast, if io_xfer_mode is H5FD_MPIO_INDEPENDENT,
+ * this call is independent, and thus we cannot use
+ * MPI_File_set_view().
+ *
+ * In this case, simply walk the vector, and issue an
+ * independent read for each entry.
+ *
+ * Return: Success: SUCCEED.
+ * Failure: FAIL.
+ *
+ * Programmer: John Mainzer
+ * March 15, 2021
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__mpio_read_vector(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, uint32_t count, H5FD_mem_t types[],
+ haddr_t addrs[], size_t sizes[], void *bufs[])
+{
+ H5FD_mpio_t * file = (H5FD_mpio_t *)_file;
+ hbool_t vector_was_sorted = TRUE;
+ haddr_t * s_addrs = NULL;
+ size_t * s_sizes = NULL;
+ void ** s_bufs = NULL;
+ char unused = 0; /* Unused, except for non-NULL pointer value */
+ void * mpi_bufs_base = NULL;
+ MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */
+ hbool_t buf_type_created = FALSE;
+ MPI_Datatype file_type = MPI_BYTE; /* MPI description of the selection in file */
+ hbool_t file_type_created = FALSE;
+ int i;
+ int mpi_code; /* MPI return code */
+ MPI_Offset mpi_off = 0;
+ MPI_Status mpi_stat; /* Status from I/O operation */
+ H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode */
+ H5FD_mpio_collective_opt_t coll_opt_mode; /* whether we are doing collective or independent I/O */
+ int size_i;
+#if MPI_VERSION >= 3
+ MPI_Count bytes_read = 0; /* Number of bytes read in */
+ MPI_Count type_size; /* MPI datatype used for I/O's size */
+ MPI_Count io_size; /* Actual number of bytes requested */
+ MPI_Count n;
+#else
+ int bytes_read = 0; /* Number of bytes read in */
+ int type_size; /* MPI datatype used for I/O's size */
+ int io_size; /* Actual number of bytes requested */
+ int n;
+#endif
+ hbool_t rank0_bcast = FALSE; /* If read-with-rank0-and-bcast flag was used */
+#ifdef H5FDmpio_DEBUG
+ hbool_t H5FD_mpio_debug_t_flag = (H5FD_mpio_debug_flags_s[(int)'t'] && H5FD_MPIO_TRACE_THIS_RANK(file));
+ hbool_t H5FD_mpio_debug_r_flag = (H5FD_mpio_debug_flags_s[(int)'r'] && H5FD_MPIO_TRACE_THIS_RANK(file));
+#endif
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_t_flag)
+ HDfprintf(stderr, "%s: (%d) Entering\n", __func__, file->mpi_rank);
+#endif
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(H5FD_MPIO == file->pub.driver_id);
+ HDassert((types) || (count == 0));
+ HDassert((addrs) || (count == 0));
+ HDassert((sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* verify that the first elements of the sizes and types arrays are
+ * valid.
+ */
+ HDassert((count == 0) || (sizes[0] != 0));
+ HDassert((count == 0) || (types[0] != H5FD_MEM_NOLIST));
+
+ /* Get the transfer mode from the API context
+ *
+ * This flag is set to H5FD_MPIO_COLLECTIVE if the API call is
+ * collective, and to H5FD_MPIO_INDEPENDENT if it is not.
+ *
+ * While this doesn't mean that we are actually about to do a collective
+ * read, it does mean that all ranks are here, so we can use MPI_File_set_view().
+ */
+ if (H5CX_get_io_xfer_mode(&xfer_mode) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")
+
+ if (xfer_mode == H5FD_MPIO_COLLECTIVE) {
+ /* Build MPI types, etc. */
+ if (H5FD__mpio_vector_build_types(count, types, addrs, sizes, (H5_flexible_const_ptr_t *)bufs,
+ &s_addrs, &s_sizes, (H5_flexible_const_ptr_t **)&s_bufs,
+ &vector_was_sorted, &mpi_off,
+ (H5_flexible_const_ptr_t *)&mpi_bufs_base, &size_i, &buf_type,
+ &buf_type_created, &file_type, &file_type_created, &unused) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't build MPI datatypes for I/O")
+
+ /* free sorted addrs vector if it exists */
+ if (!vector_was_sorted)
+ if (s_addrs) {
+ HDfree(s_addrs);
+ s_addrs = NULL;
+ }
+
+ /* Portably initialize MPI status variable */
+ HDmemset(&mpi_stat, 0, sizeof(mpi_stat));
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_r_flag)
+ HDfprintf(stdout, "%s: mpi_off = %ld size_i = %d\n", __func__, (long)mpi_off, size_i);
+#endif
+
+ /* Setup the file view. */
+ if (MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, mpi_off, MPI_BYTE, file_type,
+ H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+
+ /* Reset mpi_off to 0 since the view now starts at the data offset */
+ if (H5FD_mpi_haddr_to_MPIOff((haddr_t)0, &mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't set MPI off to 0")
+
+ /* Get the collective_opt property to check whether the application wants to do IO individually.
+ */
+ if (H5CX_get_mpio_coll_opt(&coll_opt_mode) < 0)
+
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI-I/O collective_op property")
+
+ /* Read the data. */
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_r_flag)
+ HDfprintf(stdout, "%s: using MPIO collective mode\n", __func__);
+#endif
+ if (coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO) {
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_r_flag)
+ HDfprintf(stdout, "%s: doing MPI collective IO\n", __func__);
+#endif
+ /* Check whether we should read from rank 0 and broadcast to other ranks */
+ if (H5CX_get_mpio_rank0_bcast()) {
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_r_flag)
+ HDfprintf(stdout, "%s: doing read-rank0-and-MPI_Bcast\n", __func__);
+#endif
+ /* Indicate path we've taken */
+ rank0_bcast = TRUE;
+
+ /* Read on rank 0 Bcast to other ranks */
+ if (file->mpi_rank == 0)
+ if (MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, mpi_bufs_base, size_i,
+ buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code)
+ if (MPI_SUCCESS != (mpi_code = MPI_Bcast(mpi_bufs_base, size_i, buf_type, 0, file->comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_code)
+ } /* end if */
+ else if (MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(file->f, mpi_off, mpi_bufs_base, size_i,
+ buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code)
+ } /* end if */
+ else if (size_i > 0) {
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_r_flag)
+ HDfprintf(stdout, "%s: doing MPI independent IO\n", __func__);
+#endif
+
+ if (MPI_SUCCESS !=
+ (mpi_code = MPI_File_read_at(file->f, mpi_off, mpi_bufs_base, size_i, buf_type, &mpi_stat)))
+
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code)
+
+ } /* end else */
+
+ /* Reset the file view */
+ if (MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, (MPI_Offset)0, MPI_BYTE, MPI_BYTE,
+ H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+
+ /* Only retrieve bytes read if this rank _actually_ participated in I/O */
+ if (!rank0_bcast || (rank0_bcast && file->mpi_rank == 0)) {
+ /* How many bytes were actually read? */
+#if MPI_VERSION >= 3
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, buf_type, &bytes_read)))
+#else
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_read)))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Get_elements failed", mpi_code)
+ } /* end if */
+
+ /* If the rank0-bcast feature was used, broadcast the # of bytes read to
+ * other ranks, which didn't perform any I/O.
+ */
+ /* NOTE: This could be optimized further to be combined with the broadcast
+ * of the data. (QAK - 2019/1/2)
+ * Or have rank 0 clear the unread parts of the buffer prior to
+ * the bcast. (NAF - 2021/9/15)
+ */
+ if (rank0_bcast)
+#if MPI_VERSION >= 3
+ if (MPI_SUCCESS != MPI_Bcast(&bytes_read, 1, MPI_COUNT, 0, file->comm))
+#else
+ if (MPI_SUCCESS != MPI_Bcast(&bytes_read, 1, MPI_INT, 0, file->comm))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", 0)
+
+ /* Get the type's size */
+#if MPI_VERSION >= 3
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_size_x(buf_type, &type_size)))
+#else
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size)))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code)
+
+ /* Compute the actual number of bytes requested */
+ io_size = type_size * size_i;
+
+ /* Check for read failure */
+ if (bytes_read < 0 || bytes_read > io_size)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
+
+ /* Check for incomplete read */
+ n = io_size - bytes_read;
+ if (n > 0) {
+ i = (int)count - 1;
+
+ /* Iterate over sorted array in reverse, filling in zeroes to
+ * sections of the buffers that were not read to */
+ do {
+ HDassert(i >= 0);
+
+#if MPI_VERSION >= 3
+ io_size = MIN(n, (MPI_Count)s_sizes[i]);
+ bytes_read = (MPI_Count)s_sizes[i] - io_size;
+#else
+ io_size = MIN(n, (int)s_sizes[i]);
+ bytes_read = (int)s_sizes[i] - io_size;
+#endif
+ HDassert(bytes_read >= 0);
+
+ HDmemset((char *)s_bufs[i] + bytes_read, 0, (size_t)io_size);
+
+ n -= io_size;
+ i--;
+ } while (n > 0);
+ }
+ }
+ else if (count > 0) {
+ haddr_t max_addr = HADDR_MAX;
+ hbool_t fixed_size = FALSE;
+ size_t size;
+
+ /* The read is part of an independent operation. As a result,
+ * we can't use MPI_File_set_view() (since it it a collective operation),
+ * and thus we can't use the above code to construct the MPI datatypes.
+ * In the future, we could write code to detect when a contiguous slab
+ * in the file selection spans multiple vector elements and construct a
+ * memory datatype to match this larger block in the file, but for now
+ * just read in each element of the vector in a separate
+ * MPI_File_read_at() call.
+ *
+ * We could also just detect the case when the entire file selection is
+ * contiguous, which would allow us to use
+ * H5FD__mpio_vector_build_types() to construct the memory datatype.
+ */
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_r_flag)
+ HDfprintf(stdout, "%s: doing MPI independent IO\n", __func__);
+#endif
+
+ /* Loop over vector elements */
+ for (i = 0; i < (int)count; i++) {
+ /* Convert address to mpi offset */
+ if (H5FD_mpi_haddr_to_MPIOff(addrs[i], &mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from haddr to MPI off")
+
+ /* Calculate I/O size */
+ if (!fixed_size) {
+ if (sizes[i] == 0) {
+ fixed_size = TRUE;
+ size = sizes[i - 1];
+ }
+ else {
+ size = sizes[i];
+ }
+ }
+ size_i = (int)size;
+
+ if (size != (size_t)size_i) {
+ /* If HERE, then we need to work around the integer size limit
+ * of 2GB. The input size_t size variable cannot fit into an integer,
+ * but we can get around that limitation by creating a different datatype
+ * and then setting the integer size (or element count) to 1 when using
+ * the derived_type.
+ */
+
+ if (H5_mpio_create_large_type(size, 0, MPI_BYTE, &buf_type) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTGET, FAIL, "can't create MPI-I/O datatype")
+
+ buf_type_created = TRUE;
+ size_i = 1;
+ }
+
+ /* Check if we actually need to do I/O */
+ if (addrs[i] < max_addr) {
+ /* Portably initialize MPI status variable */
+ HDmemset(&mpi_stat, 0, sizeof(mpi_stat));
+
+ /* Issue read */
+ if (MPI_SUCCESS !=
+ (mpi_code = MPI_File_read_at(file->f, mpi_off, bufs[i], size_i, buf_type, &mpi_stat)))
+
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code)
+
+ /* How many bytes were actually read? */
+#if MPI_VERSION >= 3
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, MPI_BYTE, &bytes_read)))
+#else
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_read)))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Get_elements failed", mpi_code)
+
+ /* Compute the actual number of bytes requested */
+#if MPI_VERSION >= 3
+ io_size = (MPI_Count)size;
+#else
+ io_size = (int)size;
+#endif
+
+ /* Check for read failure */
+ if (bytes_read < 0 || bytes_read > io_size)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
+
+ /*
+ * If we didn't read the entire I/O, fill in zeroes beyond end of
+ * the physical MPI file and don't issue any more reads at higher
+ * addresses.
+ */
+ if ((n = (io_size - bytes_read)) > 0) {
+ HDmemset((char *)bufs[i] + bytes_read, 0, (size_t)n);
+ max_addr = addrs[i] + (haddr_t)bytes_read;
+ }
+ }
+ else {
+ /* Read is past the max address, fill in zeroes */
+ HDmemset((char *)bufs[i], 0, size);
+ }
+ }
+ }
+
+done:
+ if (buf_type_created) {
+ MPI_Type_free(&buf_type);
+ }
+
+ if (file_type_created) {
+ MPI_Type_free(&file_type);
+ }
+
+ /* free sorted vectors if they exist */
+ if (!vector_was_sorted) {
+ if (s_addrs) {
+ HDfree(s_addrs);
+ s_addrs = NULL;
+ }
+ if (s_sizes) {
+ HDfree(s_sizes);
+ s_sizes = NULL;
+ }
+ if (s_bufs) {
+ HDfree(s_bufs);
+ s_bufs = NULL;
+ }
+ }
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_t_flag)
+ HDfprintf(stdout, "%s: Leaving, proc %d: ret_value = %d\n", __func__, file->mpi_rank, ret_value);
+#endif
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5FD__mpio_read_vector() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__mpio_write_vector
+ *
+ * Purpose: The behaviour of this function dependes on the value of
+ * the io_xfer_mode obtained from the context.
+ *
+ * If it is H5FD_MPIO_COLLECTIVE, this is a collective
+ * operation, which allows us to use MPI_File_set_view, and
+ * then perform the entire vector write in a single MPI call.
+ *
+ * Do this (if count is positive), by constructing memory
+ * and file derived types from the supplied vector, using
+ * file type to set the file view, and then writing the
+ * the memory type to file. Note that this write is
+ * either independent or collective depending on the
+ * value of mpio_coll_opt -- again obtained from the context.
+ *
+ * If count is zero, participate in the collective write
+ * (if so configured) with an empty write.
+ *
+ * Finally, set the file view back to its default state.
+ *
+ * In contrast, if io_xfer_mode is H5FD_MPIO_INDEPENDENT,
+ * this call is independent, and thus we cannot use
+ * MPI_File_set_view().
+ *
+ * In this case, simply walk the vector, and issue an
+ * independent write for each entry.
+ *
+ * Return: Success: SUCCEED.
+ * Failure: FAIL.
+ *
+ * Programmer: John Mainzer
+ * March 15, 2021
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__mpio_write_vector(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, uint32_t count, H5FD_mem_t types[],
+ haddr_t addrs[], size_t sizes[], const void *bufs[])
+{
+ H5FD_mpio_t * file = (H5FD_mpio_t *)_file;
+ hbool_t vector_was_sorted = TRUE;
+ haddr_t * s_addrs = NULL;
+ size_t * s_sizes = NULL;
+ const void ** s_bufs = NULL;
+ char unused = 0; /* Unused, except for non-NULL pointer value */
+ const void * mpi_bufs_base = NULL;
+ MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */
+ hbool_t buf_type_created = FALSE;
+ MPI_Datatype file_type = MPI_BYTE; /* MPI description of the selection in file */
+ hbool_t file_type_created = FALSE;
+ int i;
+ int mpi_code; /* MPI return code */
+ MPI_Offset mpi_off = 0;
+ MPI_Status mpi_stat; /* Status from I/O operation */
+ H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode */
+ H5FD_mpio_collective_opt_t coll_opt_mode; /* whether we are doing collective or independent I/O */
+ int size_i;
+#ifdef H5FDmpio_DEBUG
+ hbool_t H5FD_mpio_debug_t_flag = (H5FD_mpio_debug_flags_s[(int)'t'] && H5FD_MPIO_TRACE_THIS_RANK(file));
+ hbool_t H5FD_mpio_debug_w_flag = (H5FD_mpio_debug_flags_s[(int)'w'] && H5FD_MPIO_TRACE_THIS_RANK(file));
+#endif
+ haddr_t max_addr = 0;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_t_flag)
+ HDfprintf(stderr, "%s: (%d) Entering\n", __func__, file->mpi_rank);
+#endif
+
+ /* Sanity checks */
+ HDassert(file);
+ HDassert(H5FD_MPIO == file->pub.driver_id);
+ HDassert((types) || (count == 0));
+ HDassert((addrs) || (count == 0));
+ HDassert((sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* verify that the first elements of the sizes and types arrays are
+ * valid.
+ */
+ HDassert((count == 0) || (sizes[0] != 0));
+ HDassert((count == 0) || (types[0] != H5FD_MEM_NOLIST));
+
+ /* Verify that no data is written when between MPI_Barrier()s during file flush */
+
+ HDassert(!H5CX_get_mpi_file_flushing());
+
+ /* Get the transfer mode from the API context
+ *
+ * This flag is set to H5FD_MPIO_COLLECTIVE if the API call is
+ * collective, and to H5FD_MPIO_INDEPENDENT if it is not.
+ *
+ * While this doesn't mean that we are actually about to do a collective
+ * write, it does mean that all ranks are here, so we can use MPI_File_set_view().
+ */
+ if (H5CX_get_io_xfer_mode(&xfer_mode) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")
+
+ if (xfer_mode == H5FD_MPIO_COLLECTIVE) {
+ /* Build MPI types, etc. */
+ if (H5FD__mpio_vector_build_types(count, types, addrs, sizes, (H5_flexible_const_ptr_t *)bufs,
+ &s_addrs, &s_sizes, (H5_flexible_const_ptr_t **)&s_bufs,
+ &vector_was_sorted, &mpi_off,
+ (H5_flexible_const_ptr_t *)&mpi_bufs_base, &size_i, &buf_type,
+ &buf_type_created, &file_type, &file_type_created, &unused) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't build MPI datatypes for I/O")
+
+ /* Compute max addr writted to */
+ if (count > 0)
+ max_addr = s_addrs[count - 1] + (haddr_t)(s_sizes[count - 1]);
+
+ /* free sorted vectors if they exist */
+ if (!vector_was_sorted) {
+ if (s_addrs) {
+ HDfree(s_addrs);
+ s_addrs = NULL;
+ }
+ if (s_sizes) {
+ HDfree(s_sizes);
+ s_sizes = NULL;
+ }
+ if (s_bufs) {
+ HDfree(s_bufs);
+ s_bufs = NULL;
+ }
+ }
+
+ /* Portably initialize MPI status variable */
+ HDmemset(&mpi_stat, 0, sizeof(MPI_Status));
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_w_flag)
+ HDfprintf(stdout, "%s: mpi_off = %ld size_i = %d\n", __func__, (long)mpi_off, size_i);
+#endif
+
+ /* Setup the file view. */
+ if (MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, mpi_off, MPI_BYTE, file_type,
+ H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+
+ /* Reset mpi_off to 0 since the view now starts at the data offset */
+ if (H5FD_mpi_haddr_to_MPIOff((haddr_t)0, &mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't set MPI off to 0")
+
+ /* Get the collective_opt property to check whether the application wants to do IO individually.
+ */
+ if (H5CX_get_mpio_coll_opt(&coll_opt_mode) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI-I/O collective_op property")
+
+ /* Write the data. */
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_w_flag)
+ HDfprintf(stdout, "%s: using MPIO collective mode\n", __func__);
+#endif
+
+ if (coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO) {
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_w_flag)
+ HDfprintf(stdout, "%s: doing MPI collective IO\n", __func__);
+#endif
+
+ if (MPI_SUCCESS != (mpi_code = MPI_File_write_at_all(file->f, mpi_off, mpi_bufs_base, size_i,
+ buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at_all failed", mpi_code)
+ } /* end if */
+ else if (size_i > 0) {
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_w_flag)
+ HDfprintf(stdout, "%s: doing MPI independent IO\n", __func__);
+#endif
+
+ if (MPI_SUCCESS !=
+ (mpi_code = MPI_File_write_at(file->f, mpi_off, mpi_bufs_base, size_i, buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at failed", mpi_code)
+ } /* end else */
+
+ /* Reset the file view */
+ if (MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, (MPI_Offset)0, MPI_BYTE, MPI_BYTE,
+ H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+ }
+ else if (count > 0) {
+ hbool_t fixed_size = FALSE;
+ size_t size;
+
+ /* The read is part of an independent operation. As a result,
+ * we can't use MPI_File_set_view() (since it it a collective operation),
+ * and thus we can't use the above code to construct the MPI datatypes.
+ * In the future, we could write code to detect when a contiguous slab
+ * in the file selection spans multiple vector elements and construct a
+ * memory datatype to match this larger block in the file, but for now
+ * just read in each element of the vector in a separate
+ * MPI_File_read_at() call.
+ *
+ * We could also just detect the case when the entire file selection is
+ * contiguous, which would allow us to use
+ * H5FD__mpio_vector_build_types() to construct the memory datatype.
+ */
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_w_flag)
+ HDfprintf(stdout, "%s: doing MPI independent IO\n", __func__);
+#endif
+
+ /* Loop over vector elements */
+ for (i = 0; i < (int)count; i++) {
+ /* Convert address to mpi offset */
+ if (H5FD_mpi_haddr_to_MPIOff(addrs[i], &mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from haddr to MPI off")
+
+ /* Calculate I/O size */
+ if (!fixed_size) {
+ if (sizes[i] == 0) {
+ fixed_size = TRUE;
+ size = sizes[i - 1];
+ }
+ else {
+ size = sizes[i];
+ }
+ }
+ size_i = (int)size;
+
+ if (size != (size_t)size_i) {
+ /* If HERE, then we need to work around the integer size limit
+ * of 2GB. The input size_t size variable cannot fit into an integer,
+ * but we can get around that limitation by creating a different datatype
+ * and then setting the integer size (or element count) to 1 when using
+ * the derived_type.
+ */
+
+ if (H5_mpio_create_large_type(size, 0, MPI_BYTE, &buf_type) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTGET, FAIL, "can't create MPI-I/O datatype")
+
+ buf_type_created = TRUE;
+ size_i = 1;
+ }
+
+ /* Perform write */
+ if (MPI_SUCCESS !=
+ (mpi_code = MPI_File_write_at(file->f, mpi_off, bufs[i], size_i, buf_type, &mpi_stat)))
+
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at failed", mpi_code)
+
+ /* Check if this is the highest address written to so far */
+ if (addrs[i] + size > max_addr)
+ max_addr = addrs[i] + size;
+ }
+ }
+
+ /* Each process will keep track of its perceived EOF value locally, and
+ * ultimately we will reduce this value to the maximum amongst all
+ * processes, but until then keep the actual eof at HADDR_UNDEF just in
+ * case something bad happens before that point. (rather have a value
+ * we know is wrong sitting around rather than one that could only
+ * potentially be wrong.)
+ */
+ file->eof = HADDR_UNDEF;
+
+ /* check to see if the local eof has changed been extended, and update if so */
+ if (max_addr > file->local_eof)
+ file->local_eof = max_addr;
+
+done:
+ if (buf_type_created)
+ MPI_Type_free(&buf_type);
+
+ if (file_type_created)
+ MPI_Type_free(&file_type);
+
+ /* Cleanup on error */
+ if (ret_value < 0 && !vector_was_sorted) {
+ if (s_addrs) {
+ HDfree(s_addrs);
+ s_addrs = NULL;
+ }
+ if (s_sizes) {
+ HDfree(s_sizes);
+ s_sizes = NULL;
+ }
+ if (s_bufs) {
+ HDfree(s_bufs);
+ s_bufs = NULL;
+ }
+ }
+
+ /* Make sure we cleaned up */
+ HDassert(vector_was_sorted || !s_addrs);
+ HDassert(vector_was_sorted || !s_sizes);
+ HDassert(vector_was_sorted || !s_bufs);
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_debug_t_flag)
+ HDfprintf(stdout, "%s: Leaving, proc %d: ret_value = %d\n", __func__, file->mpi_rank, ret_value);
+#endif
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__mpio_write_vector() */
+
+/*-------------------------------------------------------------------------
* Function: H5FD__mpio_flush
*
* Purpose: Makes sure that all data is on disk. This is collective.
diff --git a/src/H5FDmulti.c b/src/H5FDmulti.c
index d9a6ce9..20c538f 100644
--- a/src/H5FDmulti.c
+++ b/src/H5FDmulti.c
@@ -176,6 +176,7 @@ static herr_t H5FD_multi_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, c
/* The class struct */
static const H5FD_class_t H5FD_multi_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5_VFD_MULTI, /* value */
"multi", /* name */
HADDR_MAX, /* maxaddr */
@@ -204,6 +205,10 @@ static const H5FD_class_t H5FD_multi_g = {
H5FD_multi_get_handle, /* get_handle */
H5FD_multi_read, /* read */
H5FD_multi_write, /* write */
+ NULL, /*read_vector */
+ NULL, /*write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
H5FD_multi_flush, /* flush */
H5FD_multi_truncate, /* truncate */
H5FD_multi_lock, /* lock */
diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h
index 61b4c60..bcbc693 100644
--- a/src/H5FDprivate.h
+++ b/src/H5FDprivate.h
@@ -24,6 +24,7 @@
/* Private headers needed by this file */
#include "H5Pprivate.h" /* Property lists */
+#include "H5Sprivate.h" /* Dataspaces */
/*
* The MPI drivers are needed because there are
@@ -94,6 +95,9 @@ typedef enum H5FD_get_driver_kind_t {
H5FD_GET_DRIVER_BY_VALUE /* Value field is set */
} H5FD_get_driver_kind_t;
+/* Forward declarations for prototype arguments */
+struct H5S_t;
+
/*****************************/
/* Library Private Variables */
/*****************************/
@@ -140,6 +144,22 @@ H5_DLL herr_t H5FD_set_feature_flags(H5FD_t *file, unsigned long feature_flags)
H5_DLL herr_t H5FD_get_fs_type_map(const H5FD_t *file, H5FD_mem_t *type_map);
H5_DLL herr_t H5FD_read(H5FD_t *file, H5FD_mem_t type, haddr_t addr, size_t size, void *buf /*out*/);
H5_DLL herr_t H5FD_write(H5FD_t *file, H5FD_mem_t type, haddr_t addr, size_t size, const void *buf);
+H5_DLL herr_t H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs[],
+ size_t sizes[], void *bufs[] /* out */);
+H5_DLL herr_t H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs[],
+ size_t sizes[], const void *bufs[] /* out */);
+H5_DLL herr_t H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, struct H5S_t **mem_spaces,
+ struct H5S_t **file_spaces, haddr_t offsets[], size_t element_sizes[],
+ void *bufs[] /* out */);
+H5_DLL herr_t H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, struct H5S_t **mem_spaces,
+ struct H5S_t **file_spaces, haddr_t offsets[], size_t element_sizes[],
+ const void *bufs[]);
+H5_DLL herr_t H5FD_read_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[],
+ hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[],
+ void *bufs[] /* out */);
+H5_DLL herr_t H5FD_write_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[],
+ hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[],
+ const void *bufs[]);
H5_DLL herr_t H5FD_flush(H5FD_t *file, hbool_t closing);
H5_DLL herr_t H5FD_truncate(H5FD_t *file, hbool_t closing);
H5_DLL herr_t H5FD_lock(H5FD_t *file, hbool_t rw);
@@ -152,6 +172,10 @@ H5_DLL herr_t H5FD_set_base_addr(H5FD_t *file, haddr_t base_addr);
H5_DLL haddr_t H5FD_get_base_addr(const H5FD_t *file);
H5_DLL herr_t H5FD_set_paged_aggr(H5FD_t *file, hbool_t paged);
+H5_DLL herr_t H5FD_sort_vector_io_req(hbool_t *vector_was_sorted, uint32_t count, H5FD_mem_t types[],
+ haddr_t addrs[], size_t sizes[], H5_flexible_const_ptr_t bufs[],
+ H5FD_mem_t **s_types_ptr, haddr_t **s_addrs_ptr, size_t **s_sizes_ptr,
+ H5_flexible_const_ptr_t **s_bufs_ptr);
H5_DLL herr_t H5FD_init(void);
/* Function prototypes for MPI based VFDs*/
diff --git a/src/H5FDros3.c b/src/H5FDros3.c
index 922dac5..fcce76d 100644
--- a/src/H5FDros3.c
+++ b/src/H5FDros3.c
@@ -237,6 +237,7 @@ static herr_t H5FD__ros3_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing
static herr_t H5FD__ros3_validate_config(const H5FD_ros3_fapl_t *fa);
static const H5FD_class_t H5FD_ros3_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_ROS3_VALUE, /* value */
"ros3", /* name */
MAXADDR, /* maxaddr */
@@ -265,6 +266,10 @@ static const H5FD_class_t H5FD_ros3_g = {
H5FD__ros3_get_handle, /* get_handle */
H5FD__ros3_read, /* read */
H5FD__ros3_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
NULL, /* flush */
H5FD__ros3_truncate, /* truncate */
NULL, /* lock */
diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c
index 46f5fd4..cc417070 100644
--- a/src/H5FDsec2.c
+++ b/src/H5FDsec2.c
@@ -143,6 +143,7 @@ static herr_t H5FD__sec2_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, c
void **output);
static const H5FD_class_t H5FD_sec2_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_SEC2_VALUE, /* value */
"sec2", /* name */
MAXADDR, /* maxaddr */
@@ -171,6 +172,10 @@ static const H5FD_class_t H5FD_sec2_g = {
H5FD__sec2_get_handle, /* get_handle */
H5FD__sec2_read, /* read */
H5FD__sec2_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
NULL, /* flush */
H5FD__sec2_truncate, /* truncate */
H5FD__sec2_lock, /* lock */
diff --git a/src/H5FDsplitter.c b/src/H5FDsplitter.c
index 509c18e..124c54f 100644
--- a/src/H5FDsplitter.c
+++ b/src/H5FDsplitter.c
@@ -138,6 +138,7 @@ static herr_t H5FD__splitter_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flag
void **output);
static const H5FD_class_t H5FD_splitter_g = {
+ H5FD_CLASS_VERSION, /* struct version */
H5FD_SPLITTER_VALUE, /* value */
"splitter", /* name */
MAXADDR, /* maxaddr */
@@ -166,6 +167,10 @@ static const H5FD_class_t H5FD_splitter_g = {
H5FD__splitter_get_handle, /* get_handle */
H5FD__splitter_read, /* read */
H5FD__splitter_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
H5FD__splitter_flush, /* flush */
H5FD__splitter_truncate, /* truncate */
H5FD__splitter_lock, /* lock */
diff --git a/src/H5FDstdio.c b/src/H5FDstdio.c
index 122379a..6624685 100644
--- a/src/H5FDstdio.c
+++ b/src/H5FDstdio.c
@@ -183,41 +183,46 @@ static herr_t H5FD_stdio_unlock(H5FD_t *_file);
static herr_t H5FD_stdio_delete(const char *filename, hid_t fapl_id);
static const H5FD_class_t H5FD_stdio_g = {
- H5_VFD_STDIO, /* value */
- "stdio", /* name */
- MAXADDR, /* maxaddr */
- H5F_CLOSE_WEAK, /* fc_degree */
- H5FD_stdio_term, /* terminate */
- NULL, /* sb_size */
- NULL, /* sb_encode */
- NULL, /* sb_decode */
- 0, /* fapl_size */
- NULL, /* fapl_get */
- NULL, /* fapl_copy */
- NULL, /* fapl_free */
- 0, /* dxpl_size */
- NULL, /* dxpl_copy */
- NULL, /* dxpl_free */
- H5FD_stdio_open, /* open */
- H5FD_stdio_close, /* close */
- H5FD_stdio_cmp, /* cmp */
- H5FD_stdio_query, /* query */
- NULL, /* get_type_map */
- H5FD_stdio_alloc, /* alloc */
- NULL, /* free */
- H5FD_stdio_get_eoa, /* get_eoa */
- H5FD_stdio_set_eoa, /* set_eoa */
- H5FD_stdio_get_eof, /* get_eof */
- H5FD_stdio_get_handle, /* get_handle */
- H5FD_stdio_read, /* read */
- H5FD_stdio_write, /* write */
- H5FD_stdio_flush, /* flush */
- H5FD_stdio_truncate, /* truncate */
- H5FD_stdio_lock, /* lock */
- H5FD_stdio_unlock, /* unlock */
- H5FD_stdio_delete, /* del */
- NULL, /* ctl */
- H5FD_FLMAP_DICHOTOMY /* fl_map */
+ H5FD_CLASS_VERSION, /* struct version */
+ H5_VFD_STDIO, /* value */
+ "stdio", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_stdio_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ 0, /* fapl_size */
+ NULL, /* fapl_get */
+ NULL, /* fapl_copy */
+ NULL, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD_stdio_open, /* open */
+ H5FD_stdio_close, /* close */
+ H5FD_stdio_cmp, /* cmp */
+ H5FD_stdio_query, /* query */
+ NULL, /* get_type_map */
+ H5FD_stdio_alloc, /* alloc */
+ NULL, /* free */
+ H5FD_stdio_get_eoa, /* get_eoa */
+ H5FD_stdio_set_eoa, /* set_eoa */
+ H5FD_stdio_get_eof, /* get_eof */
+ H5FD_stdio_get_handle, /* get_handle */
+ H5FD_stdio_read, /* read */
+ H5FD_stdio_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* read_selection */
+ NULL, /* write_selection */
+ H5FD_stdio_flush, /* flush */
+ H5FD_stdio_truncate, /* truncate */
+ H5FD_stdio_lock, /* lock */
+ H5FD_stdio_unlock, /* unlock */
+ H5FD_stdio_delete, /* del */
+ NULL, /* ctl */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
};
/*-------------------------------------------------------------------------
diff --git a/src/H5Fio.c b/src/H5Fio.c
index 5a9d2c1..53fec97 100644
--- a/src/H5Fio.c
+++ b/src/H5Fio.c
@@ -233,12 +233,101 @@ H5F_block_write(H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size, const void
/* Pass through page buffer layer */
if (H5PB_write(f->shared, map_type, addr, size, buf) < 0)
HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write through page buffer failed")
-
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5F_block_write() */
/*-------------------------------------------------------------------------
+ * Function: H5F_shared_select_read
+ *
+ * Purpose: Reads some data from a file/server/etc into a buffer.
+ * The location of the data is defined by the mem_spaces and
+ * file_spaces dataspace arrays, along with the offsets
+ * array. The addresses is relative to the base address for
+ * the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 3 2021
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_shared_select_read(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count, H5S_t **mem_spaces,
+ H5S_t **file_spaces, haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */)
+{
+ H5FD_mem_t map_type; /* Mapped memory type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f_sh);
+ HDassert((mem_spaces) || (count == 0));
+ HDassert((file_spaces) || (count == 0));
+ HDassert((offsets) || (count == 0));
+ HDassert((element_sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* Treat global heap as raw data */
+ map_type = (type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type;
+
+ /* Pass down to file driver layer (bypass page buffer for now) */
+ if (H5FD_read_selection(f_sh->lf, map_type, count, mem_spaces, file_spaces, offsets, element_sizes,
+ bufs) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "selection read through file driver failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_shared_select_read() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_shared_select_write
+ *
+ * Purpose: Writes some data from a buffer to a file/server/etc.
+ * The location of the data is defined by the mem_spaces and
+ * file_spaces dataspace arrays, along with the offsets
+ * array. The addresses is relative to the base address for
+ * the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 4 2021
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_shared_select_write(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count, H5S_t **mem_spaces,
+ H5S_t **file_spaces, haddr_t offsets[], size_t element_sizes[], const void *bufs[])
+{
+ H5FD_mem_t map_type; /* Mapped memory type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f_sh);
+ HDassert((mem_spaces) || (count == 0));
+ HDassert((file_spaces) || (count == 0));
+ HDassert((offsets) || (count == 0));
+ HDassert((element_sizes) || (count == 0));
+ HDassert((bufs) || (count == 0));
+
+ /* Treat global heap as raw data */
+ map_type = (type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type;
+
+ /* Pass down to file driver layer (bypass page buffer for now) */
+ if (H5FD_write_selection(f_sh->lf, map_type, count, mem_spaces, file_spaces, offsets, element_sizes,
+ bufs) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "selection write through file driver failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_shared_select_write() */
+
+/*-------------------------------------------------------------------------
* Function: H5F_flush_tagged_metadata
*
* Purpose: Flushes metadata with specified tag in the metadata cache
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index 67e153e..629aee1 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -758,6 +758,7 @@ struct H5O_loc_t;
struct H5HG_heap_t;
struct H5VL_class_t;
struct H5P_genplist_t;
+struct H5S_t;
/* Forward declarations for anonymous H5F objects */
@@ -923,6 +924,14 @@ H5_DLL herr_t H5F_shared_block_write(H5F_shared_t *f_sh, H5FD_mem_t type, haddr_
const void *buf);
H5_DLL herr_t H5F_block_write(H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size, const void *buf);
+/* Functions that operate on selections of elements in the file */
+H5_DLL herr_t H5F_shared_select_read(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count,
+ struct H5S_t **mem_spaces, struct H5S_t **file_spaces, haddr_t offsets[],
+ size_t element_sizes[], void *bufs[] /* out */);
+H5_DLL herr_t H5F_shared_select_write(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count,
+ struct H5S_t **mem_spaces, struct H5S_t **file_spaces,
+ haddr_t offsets[], size_t element_sizes[], const void *bufs[]);
+
/* Functions that flush or evict */
H5_DLL herr_t H5F_flush_tagged_metadata(H5F_t *f, haddr_t tag);
H5_DLL herr_t H5F_evict_tagged_metadata(H5F_t *f, haddr_t tag);
diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h
index 4cf4623..d1725f6 100644
--- a/src/H5Gprivate.h
+++ b/src/H5Gprivate.h
@@ -130,7 +130,7 @@ typedef enum {
typedef int H5G_own_loc_t;
/* Structure to store information about the name an object was opened with */
-typedef struct {
+typedef struct H5G_name_t {
H5RS_str_t *full_path_r; /* Path to object, as seen from root of current file mounting hierarchy */
H5RS_str_t *user_path_r; /* Path to object, as opened by user */
unsigned obj_hidden; /* Whether the object is visible in group hier. */
diff --git a/src/H5PB.c b/src/H5PB.c
index 9ab87b0..ce8336b 100644
--- a/src/H5PB.c
+++ b/src/H5PB.c
@@ -1303,6 +1303,75 @@ done:
} /* end H5PB_write() */
/*-------------------------------------------------------------------------
+ * Function: H5PB_enabled
+ *
+ * Purpose: Check if the page buffer may be enabled for the specified
+ * file and data access type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_enabled(H5F_shared_t *f_sh, H5FD_mem_t type, hbool_t *enabled)
+{
+ H5PB_t *page_buf; /* Page buffering info for this file */
+ hbool_t bypass_pb = FALSE; /* Whether to bypass page buffering */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity checks */
+ HDassert(f_sh);
+
+ /* Get pointer to page buffer info for this file */
+ page_buf = f_sh->page_buf;
+
+#ifdef H5_HAVE_PARALLEL
+ if (H5F_SHARED_HAS_FEATURE(f_sh, H5FD_FEAT_HAS_MPI)) {
+#if 1
+ bypass_pb = TRUE;
+#else
+ /* MSC - why this stopped working ? */
+ int mpi_size;
+
+ if ((mpi_size = H5F_shared_mpi_get_size(f_sh)) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTGET, FAIL, "can't retrieve MPI communicator size")
+ if (1 != mpi_size)
+ bypass_pb = TRUE;
+#endif
+ } /* end if */
+#endif
+
+ /* If page buffering is disabled, or if this is a parallel raw data access,
+ * bypass page buffering. Note that page buffering may still be disabled for
+ * large metadata access or large non-parallel raw data access, but this
+ * function doesn't take I/O size into account so if it returns TRUE the
+ * page buffer may still be disabled for some I/O. If it returns FALSE it is
+ * always disabled for this access type.
+ */
+ if (NULL == page_buf || (bypass_pb && H5FD_MEM_DRAW == type)) {
+ /* Update statistics, since wherever this function is called, if it
+ * returns FALSE, the calling function performs I/O avoiding the page
+ * buffer layer */
+ if (page_buf) {
+ HDassert(type == H5FD_MEM_DRAW);
+ page_buf->bypasses[1]++;
+ } /* end if */
+
+ /* Page buffer is disabled, at least for this data access type */
+ *enabled = FALSE;
+ } /* end if */
+ else
+ /* Page buffer may be enabled */
+ *enabled = TRUE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PB_enabled() */
+
+/*-------------------------------------------------------------------------
* Function: H5PB__insert_entry()
*
* Purpose: This function was created without documentation.
diff --git a/src/H5PBprivate.h b/src/H5PBprivate.h
index e0197bf..f5d4536 100644
--- a/src/H5PBprivate.h
+++ b/src/H5PBprivate.h
@@ -91,6 +91,7 @@ H5_DLL herr_t H5PB_update_entry(H5PB_t *page_buf, haddr_t addr, size_t size, con
H5_DLL herr_t H5PB_remove_entry(const H5F_shared_t *f_sh, haddr_t addr);
H5_DLL herr_t H5PB_read(H5F_shared_t *f_sh, H5FD_mem_t type, haddr_t addr, size_t size, void *buf /*out*/);
H5_DLL herr_t H5PB_write(H5F_shared_t *f_sh, H5FD_mem_t type, haddr_t addr, size_t size, const void *buf);
+H5_DLL herr_t H5PB_enabled(H5F_shared_t *f_sh, H5FD_mem_t type, hbool_t *enabled);
/* Statistics routines */
H5_DLL herr_t H5PB_reset_stats(H5PB_t *page_buf);
diff --git a/src/H5Tprivate.h b/src/H5Tprivate.h
index 6624096..9731379 100644
--- a/src/H5Tprivate.h
+++ b/src/H5Tprivate.h
@@ -101,6 +101,8 @@ typedef struct H5T_subset_info_t {
} H5T_subset_info_t;
/* Forward declarations for prototype arguments */
+struct H5G_loc_t;
+struct H5G_name_t;
struct H5O_shared_t;
/* The native endianness of the platform */
@@ -120,14 +122,14 @@ H5_DLL size_t H5T_get_size(const H5T_t *dt);
H5_DLL hbool_t H5T_get_force_conv(const H5T_t *dt);
H5_DLL int H5T_cmp(const H5T_t *dt1, const H5T_t *dt2, hbool_t superset);
H5_DLL herr_t H5T_encode(H5T_t *obj, unsigned char *buf, size_t *nalloc);
-H5_DLL H5T_t * H5T_decode(size_t buf_size, const unsigned char *buf);
-H5_DLL herr_t H5T_debug(const H5T_t *dt, FILE *stream);
-H5_DLL struct H5O_loc_t *H5T_oloc(H5T_t *dt);
-H5_DLL H5G_name_t *H5T_nameof(const H5T_t *dt);
-H5_DLL htri_t H5T_is_immutable(const H5T_t *dt);
-H5_DLL htri_t H5T_is_named(const H5T_t *dt);
-H5_DLL herr_t H5T_convert_committed_datatype(H5T_t *dt, H5F_t *f);
-H5_DLL htri_t H5T_is_relocatable(const H5T_t *dt);
+H5_DLL H5T_t * H5T_decode(size_t buf_size, const unsigned char *buf);
+H5_DLL herr_t H5T_debug(const H5T_t *dt, FILE *stream);
+H5_DLL struct H5O_loc_t * H5T_oloc(H5T_t *dt);
+H5_DLL struct H5G_name_t *H5T_nameof(const H5T_t *dt);
+H5_DLL htri_t H5T_is_immutable(const H5T_t *dt);
+H5_DLL htri_t H5T_is_named(const H5T_t *dt);
+H5_DLL herr_t H5T_convert_committed_datatype(H5T_t *dt, H5F_t *f);
+H5_DLL htri_t H5T_is_relocatable(const H5T_t *dt);
H5_DLL H5T_path_t *H5T_path_find(const H5T_t *src, const H5T_t *dst);
H5_DLL hbool_t H5T_path_noop(const H5T_path_t *p);
H5_DLL H5T_bkg_t H5T_path_bkg(const H5T_path_t *p);
@@ -159,7 +161,7 @@ H5_DLL herr_t H5T_invoke_vol_optional(H5T_t *dt, H5VL_optional_args_t *args, hi
H5_DLL H5R_type_t H5T_get_ref_type(const H5T_t *dt);
/* Operations on named datatypes */
-H5_DLL H5T_t *H5T_open(const H5G_loc_t *loc);
+H5_DLL H5T_t *H5T_open(const struct H5G_loc_t *loc);
H5_DLL int H5T_link(const H5T_t *type, int adjust);
H5_DLL herr_t H5T_update_shared(H5T_t *type);
diff --git a/src/H5private.h b/src/H5private.h
index d4c055e..a83ecf0 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -1979,6 +1979,11 @@ extern hbool_t H5_libterm_g; /* Is the library being shutdown? */
#endif /* H5_HAVE_THREADSAFE */
+/* Extern global to determine if we should use selection I/O if available (this
+ * variable should be removed once selection I/O performs as well as the
+ * previous scalar I/O implementation */
+extern hbool_t H5_use_selection_io_g;
+
#ifdef H5_HAVE_CODESTACK
/* Include required function stack header */
@@ -2473,6 +2478,16 @@ H5_DLL herr_t H5CX_pop(hbool_t update_dxpl_props);
#define HDcompile_assert(e) do { typedef struct { unsigned int b: (e); } x; } while(0)
*/
+/* Private typedefs */
+
+/* Union for const/non-const pointer for use by functions that manipulate
+ * pointers but do not write to their targets or return pointers to const
+ * specified locations. This helps us avoid compiler warnings. */
+typedef union {
+ void * vp;
+ const void *cvp;
+} H5_flexible_const_ptr_t;
+
/* Private functions, not part of the publicly documented API */
H5_DLL herr_t H5_init_library(void);
H5_DLL void H5_term_library(void);