summaryrefslogtreecommitdiffstats
path: root/src/H5Dio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Dio.c')
-rw-r--r--src/H5Dio.c1365
1 files changed, 870 insertions, 495 deletions
diff --git a/src/H5Dio.c b/src/H5Dio.c
index c1427d1..0b52208 100644
--- a/src/H5Dio.c
+++ b/src/H5Dio.c
@@ -44,15 +44,14 @@
/********************/
/* Setup/teardown routines */
-static herr_t H5D__ioinfo_init(H5D_t *dset, const H5D_type_info_t *type_info, H5D_storage_t *store,
- H5D_io_info_t *io_info);
-static herr_t H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write,
- H5D_type_info_t *type_info);
+static herr_t H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info);
+static herr_t H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store);
+static herr_t H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id);
+static herr_t H5D__typeinfo_init_phase2(H5D_io_info_t *io_info);
#ifdef H5_HAVE_PARALLEL
-static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_space,
- const H5S_t *mem_space, const H5D_type_info_t *type_info);
+static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info);
#endif /* H5_HAVE_PARALLEL */
-static herr_t H5D__typeinfo_term(const H5D_type_info_t *type_info);
+static herr_t H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init);
/*********************/
/* Package Variables */
@@ -65,66 +64,63 @@ static herr_t H5D__typeinfo_term(const H5D_type_info_t *type_info);
/* Declare a free list to manage blocks of type conversion data */
H5FL_BLK_DEFINE(type_conv);
-/* Declare a free list to manage the H5D_chunk_map_t struct */
-H5FL_DEFINE(H5D_chunk_map_t);
-
/*-------------------------------------------------------------------------
* Function: H5D__read
*
- * Purpose: Reads (part of) a DATASET into application memory BUF. See
- * H5Dread() for complete details.
+ * Purpose: Reads multiple (parts of) DATASETs into application memory BUFs.
+ * See H5Dread_multi() for complete details.
*
* Return: Non-negative on success/Negative on failure
*
- * Programmer: Robb Matzke
- * Thursday, December 4, 1997
- *
*-------------------------------------------------------------------------
*/
herr_t
-H5D__read(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space, void *buf /*out*/)
+H5D__read(size_t count, H5D_dset_io_info_t *dset_info)
{
- H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */
- H5D_io_info_t io_info; /* Dataset I/O info */
- H5D_type_info_t type_info; /* Datatype info for operation */
- H5D_layout_t layout_type; /* Dataset's layout type (contig, chunked, compact, etc.) */
- hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */
- H5S_t *projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */
- /* projection of the supplied mem_space to a new */
- /* dataspace with rank equal to that of */
- /* file_space. */
- /* */
- /* This field is only used if */
- /* H5S_select_shape_same() returns TRUE when */
- /* comparing the mem_space and the data_space, */
- /* and the mem_space have different rank. */
- /* */
- /* Note that if this variable is used, the */
- /* projected mem space must be discarded at the */
- /* end of the function to avoid a memory leak. */
- H5D_storage_t store; /* union of EFL and chunk pointer in file space */
- hsize_t nelmts; /* total number of elmts */
- hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */
- char fake_char; /* Temporary variable for NULL buffer pointers */
- herr_t ret_value = SUCCEED; /* Return value */
-
- FUNC_ENTER_PACKAGE_TAG(dataset->oloc.addr)
+ H5D_io_info_t io_info; /* Dataset I/O info for multi dsets */
+ size_t type_info_init = 0; /* Number of datatype info structs that have been initialized */
+ H5S_t *orig_mem_space_local; /* Local buffer for orig_mem_space */
+ H5S_t **orig_mem_space = NULL; /* If not NULL, ptr to an array of dataspaces */
+ /* containing the original memory spaces contained */
+ /* in dset_info. This is needed in order to */
+ /* restore the original state of dset_info if we */
+ /* replaced any mem spaces with equivalents */
+ /* projected to a rank equal to that of file_space. */
+ /* */
+ /* This field is only used if */
+ /* H5S_select_shape_same() returns TRUE when */
+ /* comparing at least one mem_space and data_space, */
+ /* and the mem_space has a different rank. */
+ /* */
+ /* Note that this is a temporary variable - the */
+ /* projected memory space is stored in dset_info, */
+ /* and will be freed when that structure is */
+ /* freed. */
+ H5D_storage_t store_local; /* Local buffer for store */
+ H5D_storage_t *store = &store_local; /* Union of EFL and chunk pointer in file space */
+ size_t io_op_init = 0; /* Number I/O ops that have been initialized */
+ size_t io_skipped =
+ 0; /* Number I/O ops that have been skipped (due to the dataset not being allocated) */
+ size_t i; /* Local index variable */
+ char fake_char; /* Temporary variable for NULL buffer pointers */
+ herr_t ret_value = SUCCEED; /* Return value */
- /* check args */
- HDassert(dataset && dataset->oloc.file);
- HDassert(file_space);
- HDassert(mem_space);
+ FUNC_ENTER_NOAPI(FAIL)
- layout_type = dataset->shared->layout.type;
+ /* Init io_info */
+ if (H5D__ioinfo_init(count, dset_info, &io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
+ io_info.op_type = H5D_IO_OP_READ;
- /* Set up datatype info for operation */
- if (H5D__typeinfo_init(dataset, mem_type_id, FALSE, &type_info) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
- type_info_init = TRUE;
+ /* Allocate store buffer if necessary */
+ if (count > 1)
+ if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer")
#ifdef H5_HAVE_PARALLEL
- /* Check for non-MPI-based VFD */
- if (!(H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI))) {
+ /* Check for non-MPI-based VFD. Only need to check first dataset since all
+ * share the same file. */
+ if (!(H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI))) {
H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */
/* Get I/O transfer mode */
@@ -137,363 +133,626 @@ H5D__read(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space
} /* end if */
#endif /*H5_HAVE_PARALLEL*/
- /* Make certain that the number of elements in each selection is the same */
- nelmts = H5S_GET_SELECT_NPOINTS(mem_space);
- if (nelmts != H5S_GET_SELECT_NPOINTS(file_space))
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
- "src and dest dataspaces have different number of elements selected")
-
- /* Check for a NULL buffer */
- if (NULL == buf) {
- /* Check for any elements selected (which is invalid) */
- if (nelmts > 0)
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")
-
- /* If the buffer is nil, and 0 element is selected, make a fake buffer.
- * This is for some MPI package like ChaMPIon on NCSA's tungsten which
- * doesn't support this feature.
- */
- buf = &fake_char;
- } /* end if */
-
- /* Make sure that both selections have their extents set */
- if (!(H5S_has_extent(file_space)))
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
- if (!(H5S_has_extent(mem_space)))
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")
+ /* iterate over all dsets and construct I/O information necessary to do I/O */
+ for (i = 0; i < count; i++) {
+ haddr_t prev_tag = HADDR_UNDEF;
+
+ /* check args */
+ if (NULL == dset_info[i].dset)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if (NULL == dset_info[i].dset->oloc.file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* set metadata tagging with dset oheader addr */
+ H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);
+
+ /* Set up datatype info for operation */
+ if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
+ type_info_init++;
+
+ /* Make certain that the number of elements in each selection is the same, and cache nelmts in
+ * dset_info */
+ dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space);
+ if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
+ "src and dest dataspaces have different number of elements selected")
+
+ /* Check for a NULL buffer */
+ if (NULL == dset_info[i].buf.vp) {
+ /* Check for any elements selected (which is invalid) */
+ if (dset_info[i].nelmts > 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")
+
+ /* If the buffer is nil, and 0 element is selected, make a fake buffer.
+ * This is for some MPI package like ChaMPIon on NCSA's tungsten which
+ * doesn't support this feature.
+ */
+ dset_info[i].buf.vp = &fake_char;
+ } /* end if */
- /* H5S_select_shape_same() has been modified to accept topologically identical
- * selections with different rank as having the same shape (if the most
- * rapidly changing coordinates match up), but the I/O code still has
- * difficulties with the notion.
- *
- * To solve this, we check to see if H5S_select_shape_same() returns true,
- * and if the ranks of the mem and file spaces are different. If they are,
- * construct a new mem space that is equivalent to the old mem space, and
- * use that instead.
- *
- * Note that in general, this requires us to touch up the memory buffer as
- * well.
- */
- if (nelmts > 0 && TRUE == H5S_SELECT_SHAPE_SAME(mem_space, file_space) &&
- H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) {
- ptrdiff_t buf_adj = 0;
-
- /* Attempt to construct projected dataspace for memory dataspace */
- if (H5S_select_construct_projection(mem_space, &projected_mem_space,
- (unsigned)H5S_GET_EXTENT_NDIMS(file_space),
- type_info.dst_type_size, &buf_adj) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
- HDassert(projected_mem_space);
-
- /* Adjust the buffer by the given amount */
- buf = (void *)(((uint8_t *)buf) + buf_adj);
-
- /* Switch to using projected memory dataspace & adjusted buffer */
- mem_space = projected_mem_space;
- } /* end if */
+ /* Make sure that both selections have their extents set */
+ if (!(H5S_has_extent(dset_info[i].file_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
+ if (!(H5S_has_extent(dset_info[i].mem_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")
+
+ /* H5S_select_shape_same() has been modified to accept topologically identical
+ * selections with different rank as having the same shape (if the most
+ * rapidly changing coordinates match up), but the I/O code still has
+ * difficulties with the notion.
+ *
+ * To solve this, we check to see if H5S_select_shape_same() returns true,
+ * and if the ranks of the mem and file spaces are different. If they are,
+ * construct a new mem space that is equivalent to the old mem space, and
+ * use that instead.
+ *
+ * Note that in general, this requires us to touch up the memory buffer as
+ * well.
+ */
+ if (dset_info[i].nelmts > 0 &&
+ TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) &&
+ H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) {
+ ptrdiff_t buf_adj = 0;
+
+ /* Allocate original memory space buffer if necessary */
+ if (!orig_mem_space) {
+ if (count > 1) {
+ /* Allocate buffer */
+ if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
+ "couldn't allocate original memory space array buffer")
+ }
+ else
+ /* Use local buffer */
+ orig_mem_space = &orig_mem_space_local;
+ }
- /* Retrieve dataset properties */
- /* <none needed in the general case> */
+ /* Save original memory space */
+ orig_mem_space[i] = dset_info[i].mem_space;
+ dset_info[i].mem_space = NULL;
- /* If space hasn't been allocated and not using external storage,
- * return fill value to buffer if fill time is upon allocation, or
- * do nothing if fill time is never. If the dataset is compact and
- * fill time is NEVER, there is no way to tell whether part of data
- * has been overwritten. So just proceed in reading.
- */
- if (nelmts > 0 && dataset->shared->dcpl_cache.efl.nused == 0 &&
- !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage) &&
- !(dataset->shared->layout.ops->is_data_cached &&
- (*dataset->shared->layout.ops->is_data_cached)(dataset->shared))) {
- H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */
-
- /* Retrieve dataset's fill-value properties */
- if (H5P_is_fill_value_defined(&dataset->shared->dcpl_cache.fill, &fill_status) < 0)
- HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
-
- /* Should be impossible, but check anyway... */
- if (fill_status == H5D_FILL_VALUE_UNDEFINED &&
- (dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC ||
- dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET))
- HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL,
- "read failed: dataset doesn't exist, no data can be read")
-
- /* If we're never going to fill this dataset, just leave the junk in the user's buffer */
- if (dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_NEVER)
- HGOTO_DONE(SUCCEED)
-
- /* Go fill the user's selection with the dataset's fill value */
- if (H5D__fill(dataset->shared->dcpl_cache.fill.buf, dataset->shared->type, buf, type_info.mem_type,
- mem_space) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed")
- else
- HGOTO_DONE(SUCCEED)
- } /* end if */
+ /* Attempt to construct projected dataspace for memory dataspace */
+ if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space,
+ (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space),
+ (hsize_t)dset_info[i].type_info.dst_type_size, &buf_adj) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
+ HDassert(dset_info[i].mem_space);
- /* Set up I/O operation */
- io_info.op_type = H5D_IO_OP_READ;
- io_info.u.rbuf = buf;
- if (H5D__ioinfo_init(dataset, &type_info, &store, &io_info) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation")
-
- /* Sanity check that space is allocated, if there are elements */
- if (nelmts > 0)
- HDassert((*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage) ||
- (dataset->shared->layout.ops->is_data_cached &&
- (*dataset->shared->layout.ops->is_data_cached)(dataset->shared)) ||
- dataset->shared->dcpl_cache.efl.nused > 0 || layout_type == H5D_COMPACT);
-
- /* Allocate the chunk map */
- if (H5D_CONTIGUOUS != layout_type && H5D_COMPACT != layout_type) {
- if (NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t)))
- HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map")
- }
+ /* Adjust the buffer by the given amount */
+ dset_info[i].buf.vp = (void *)(((uint8_t *)dset_info[i].buf.vp) + buf_adj);
+ } /* end if */
- /* Call storage method's I/O initialization routine */
- if (io_info.layout_ops.io_init &&
- (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
- io_op_init = TRUE;
+ /* If space hasn't been allocated and not using external storage,
+ * return fill value to buffer if fill time is upon allocation, or
+ * do nothing if fill time is never. If the dataset is compact and
+ * fill time is NEVER, there is no way to tell whether part of data
+ * has been overwritten. So just proceed in reading.
+ */
+ if (dset_info[i].nelmts > 0 && dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 &&
+ !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
+ &dset_info[i].dset->shared->layout.storage) &&
+ !(dset_info[i].dset->shared->layout.ops->is_data_cached &&
+ (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared))) {
+ H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */
+
+ /* Retrieve dataset's fill-value properties */
+ if (H5P_is_fill_value_defined(&dset_info[i].dset->shared->dcpl_cache.fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* Should be impossible, but check anyway... */
+ if (fill_status == H5D_FILL_VALUE_UNDEFINED &&
+ (dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC ||
+ dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET))
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL,
+ "read failed: dataset doesn't exist, no data can be read")
+
+ /* If we're never going to fill this dataset, just leave the junk in the user's buffer */
+ if (dset_info[i].dset->shared->dcpl_cache.fill.fill_time != H5D_FILL_TIME_NEVER)
+ /* Go fill the user's selection with the dataset's fill value */
+ if (H5D__fill(dset_info[i].dset->shared->dcpl_cache.fill.buf, dset_info[i].dset->shared->type,
+ dset_info[i].buf.vp, dset_info[i].type_info.mem_type,
+ dset_info[i].mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed")
+
+ /* No need to perform any more I/O for this dataset */
+ dset_info[i].skip_io = TRUE;
+ io_skipped++;
+ } /* end if */
+ else {
+ /* Set up I/O operation */
+ if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation")
+
+ /* Sanity check that space is allocated, if there are elements */
+ if (dset_info[i].nelmts > 0)
+ HDassert(
+ (*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
+ &dset_info[i].dset->shared->layout.storage) ||
+ (dset_info[i].dset->shared->layout.ops->is_data_cached &&
+ (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared)) ||
+ dset_info[i].dset->shared->dcpl_cache.efl.nused > 0 ||
+ dset_info[i].dset->shared->layout.type == H5D_COMPACT);
+
+ /* Call storage method's I/O initialization routine */
+ if (dset_info[i].layout_ops.io_init &&
+ (dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
+ dset_info[i].skip_io = FALSE;
+ io_op_init++;
+
+ /* Reset metadata tagging */
+ H5AC_tag(prev_tag, NULL);
+ }
+ } /* end of for loop */
+
+ HDassert(type_info_init == count);
+ HDassert(io_op_init + io_skipped == count);
+
+ /* If no datasets have I/O, we're done */
+ if (io_op_init == 0)
+ HGOTO_DONE(SUCCEED)
+
+ /* Perform second phase of type info initialization */
+ if (H5D__typeinfo_init_phase2(&io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)")
#ifdef H5_HAVE_PARALLEL
/* Adjust I/O info for any parallel I/O */
- if (H5D__ioinfo_adjust(&io_info, dataset, file_space, mem_space, &type_info) < 0)
+ if (H5D__ioinfo_adjust(&io_info) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
#endif /*H5_HAVE_PARALLEL*/
- /* Invoke correct "high level" I/O routine */
- if ((*io_info.io_ops.multi_read)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")
+ /* If multi dataset I/O callback is not provided, perform read IO via
+ * single-dset path with looping */
+ if (io_info.md_io_ops.multi_read_md) {
+ /* Create sel_pieces array if any pieces are selected */
+ if (io_info.piece_count > 0) {
+ HDassert(!io_info.sel_pieces);
+ HDassert(io_info.pieces_added == 0);
+
+ /* Allocate sel_pieces array */
+ if (NULL ==
+ (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0]))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces")
+ }
+
+ /* MDIO-specific second phase initialization */
+ for (i = 0; i < count; i++)
+ if (dset_info[i].layout_ops.mdio_init) {
+ haddr_t prev_tag = HADDR_UNDEF;
+
+ /* set metadata tagging with dset oheader addr */
+ H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);
+
+ /* Make second phase IO init call */
+ if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces")
+
+ /* Reset metadata tagging */
+ H5AC_tag(prev_tag, NULL);
+ }
+
+ /* Invoke correct "high level" I/O routine */
+ if ((*io_info.md_io_ops.multi_read_md)(&io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")
+ } /* end if */
+ else {
+ haddr_t prev_tag = HADDR_UNDEF;
+
+ if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) {
+ if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for memory space list")
+ if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
+ if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for piece address list")
+ if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for element size list")
+ if (NULL == (io_info.rbufs = H5MM_malloc(io_info.piece_count * sizeof(void *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for read buffer list")
+ }
+
+ /* Loop with serial & single-dset read IO path */
+ for (i = 0; i < count; i++) {
+ /* Check for skipped I/O */
+ if (dset_info[i].skip_io)
+ continue;
+
+ /* set metadata tagging with dset oheader addr */
+ H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);
+
+ /* Invoke correct "high level" I/O routine */
+ if ((*dset_info[i].io_ops.multi_read)(&io_info, &dset_info[i]) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")
+
+ /* Reset metadata tagging */
+ H5AC_tag(prev_tag, NULL);
+ }
+
+ /* Make final multi dataset selection I/O call if we are using both
+ * features - in this case the multi_read callbacks did not perform the
+ * actual I/O */
+ H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t)
+ if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info))
+ if (H5F_shared_select_read(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added,
+ io_info.mem_spaces, io_info.file_spaces, io_info.addrs,
+ io_info.element_sizes, io_info.rbufs) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "selection read failed")
+ }
done:
/* Shut down the I/O op information */
- if (io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0)
- HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
- if (fm)
- fm = H5FL_FREE(H5D_chunk_map_t, fm);
+ for (i = 0; i < io_op_init; i++)
+ if (!dset_info[i].skip_io && dset_info[i].layout_ops.io_term &&
+ (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
/* Shut down datatype info for operation */
- if (type_info_init && H5D__typeinfo_term(&type_info) < 0)
+ if (H5D__typeinfo_term(&io_info, type_info_init) < 0)
HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")
- /* discard projected mem space if it was created */
- if (NULL != projected_mem_space)
- if (H5S_close(projected_mem_space) < 0)
- HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace")
+ /* Discard projected mem spaces and restore originals */
+ if (orig_mem_space) {
+ for (i = 0; i < count; i++)
+ if (orig_mem_space[i]) {
+ if (H5S_close(dset_info[i].mem_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL,
+ "unable to shut down projected memory dataspace")
+ dset_info[i].mem_space = orig_mem_space[i];
+ }
+
+ /* Free orig_mem_space array if it was allocated */
+ if (orig_mem_space != &orig_mem_space_local)
+ H5MM_free(orig_mem_space);
+ }
+
+ /* Free global piece array */
+ H5MM_xfree(io_info.sel_pieces);
+
+ /* Free selection I/O arrays */
+ H5MM_xfree(io_info.mem_spaces);
+ H5MM_xfree(io_info.file_spaces);
+ H5MM_xfree(io_info.addrs);
+ H5MM_xfree(io_info.element_sizes);
+ H5MM_xfree(io_info.rbufs);
- FUNC_LEAVE_NOAPI_TAG(ret_value)
+ /* Free store array if it was allocated */
+ if (store != &store_local)
+ H5MM_free(store);
+
+ FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__read() */
/*-------------------------------------------------------------------------
* Function: H5D__write
*
- * Purpose: Writes (part of) a DATASET to a file from application memory
- * BUF. See H5Dwrite() for complete details.
+ * Purpose: Writes multiple (part of) DATASETs to a file from application
+ * memory BUFs. See H5Dwrite_multi() for complete details.
*
- * Return: Non-negative on success/Negative on failure
+ * This was referred from H5D__write for multi-dset work.
*
- * Programmer: Robb Matzke
- * Thursday, December 4, 1997
+ * Return: Non-negative on success/Negative on failure
*
*-------------------------------------------------------------------------
*/
herr_t
-H5D__write(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space, const void *buf)
+H5D__write(size_t count, H5D_dset_io_info_t *dset_info)
{
- H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */
- H5D_io_info_t io_info; /* Dataset I/O info */
- H5D_type_info_t type_info; /* Datatype info for operation */
- H5D_layout_t layout_type; /* Dataset's layout type (contig, chunked, compact, etc.) */
- hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */
- hbool_t should_alloc_space = FALSE; /* Whether or not to initialize dataset's storage */
- H5S_t *projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */
- /* projection of the supplied mem_space to a new */
- /* dataspace with rank equal to that of */
- /* file_space. */
- /* */
- /* This field is only used if */
- /* H5S_select_shape_same() returns TRUE when */
- /* comparing the mem_space and the data_space, */
- /* and the mem_space have different rank. */
- /* */
- /* Note that if this variable is used, the */
- /* projected mem space must be discarded at the */
- /* end of the function to avoid a memory leak. */
- H5D_storage_t store; /* union of EFL and chunk pointer in file space */
- hsize_t nelmts; /* total number of elmts */
- hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */
- char fake_char; /* Temporary variable for NULL buffer pointers */
- herr_t ret_value = SUCCEED; /* Return value */
-
- FUNC_ENTER_PACKAGE_TAG(dataset->oloc.addr)
+ H5D_io_info_t io_info; /* Dataset I/O info for multi dsets */
+ size_t type_info_init = 0; /* Number of datatype info structs that have been initialized */
+ H5S_t *orig_mem_space_local; /* Local buffer for orig_mem_space */
+ H5S_t **orig_mem_space = NULL; /* If not NULL, ptr to an array of dataspaces */
+ /* containing the original memory spaces contained */
+ /* in dset_info. This is needed in order to */
+ /* restore the original state of dset_info if we */
+ /* replaced any mem spaces with equivalents */
+ /* projected to a rank equal to that of file_space. */
+ /* */
+ /* This field is only used if */
+ /* H5S_select_shape_same() returns TRUE when */
+ /* comparing at least one mem_space and data_space, */
+ /* and the mem_space has a different rank. */
+ /* */
+ /* Note that this is a temporary variable - the */
+ /* projected memory space is stored in dset_info, */
+ /* and will be freed when that structure is */
+ /* freed. */
+ H5D_storage_t store_local; /* Local buffer for store */
+ H5D_storage_t *store = &store_local; /* Union of EFL and chunk pointer in file space */
+ size_t io_op_init = 0; /* Number I/O ops that have been initialized */
+ size_t i; /* Local index variable */
+ char fake_char; /* Temporary variable for NULL buffer pointers */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Init io_info */
+ if (H5D__ioinfo_init(count, dset_info, &io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
+ io_info.op_type = H5D_IO_OP_WRITE;
- /* check args */
- HDassert(dataset && dataset->oloc.file);
- HDassert(file_space);
- HDassert(mem_space);
+ /* Allocate store buffer if necessary */
+ if (count > 1)
+ if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer")
- layout_type = dataset->shared->layout.type;
+ /* iterate over all dsets and construct I/O information */
+ for (i = 0; i < count; i++) {
+ hbool_t should_alloc_space = FALSE; /* Whether or not to initialize dataset's storage */
+ haddr_t prev_tag = HADDR_UNDEF;
- /* All filters in the DCPL must have encoding enabled. */
- if (!dataset->shared->checked_filters) {
- if (H5Z_can_apply(dataset->shared->dcpl_id, dataset->shared->type_id) < 0)
- HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters")
+ /* check args */
+ if (NULL == dset_info[i].dset)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if (NULL == dset_info[i].dset->oloc.file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
- dataset->shared->checked_filters = TRUE;
- } /* end if */
+ /* set metadata tagging with dset oheader addr */
+ H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);
+
+ /* All filters in the DCPL must have encoding enabled. */
+ if (!dset_info[i].dset->shared->checked_filters) {
+ if (H5Z_can_apply(dset_info[i].dset->shared->dcpl_id, dset_info[i].dset->shared->type_id) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters")
- /* Check if we are allowed to write to this file */
- if (0 == (H5F_INTENT(dataset->oloc.file) & H5F_ACC_RDWR))
- HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file")
+ dset_info[i].dset->shared->checked_filters = TRUE;
+ } /* end if */
+
+ /* Check if we are allowed to write to this file */
+ if (0 == (H5F_INTENT(dset_info[i].dset->oloc.file) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file")
- /* Set up datatype info for operation */
- if (H5D__typeinfo_init(dataset, mem_type_id, TRUE, &type_info) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
- type_info_init = TRUE;
+ /* Set up datatype info for operation */
+ if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
+ type_info_init++;
- /* Various MPI based checks */
+ /* Various MPI based checks */
#ifdef H5_HAVE_PARALLEL
- if (H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI)) {
- /* If MPI based VFD is used, no VL or region reference datatype support yet. */
- /* This is because they use the global heap in the file and we don't */
- /* support parallel access of that yet */
- if (H5T_is_vl_storage(type_info.mem_type) > 0)
- HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
- "Parallel IO does not support writing VL or region reference datatypes yet")
- } /* end if */
- else {
- H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */
+ if (H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI)) {
+ /* If MPI based VFD is used, no VL or region reference datatype support yet. */
+ /* This is because they use the global heap in the file and we don't */
+ /* support parallel access of that yet */
+ if (H5T_is_vl_storage(dset_info[i].type_info.mem_type) > 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
+ "Parallel IO does not support writing VL or region reference datatypes yet")
+ } /* end if */
+ else {
+ H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */
+
+ /* Get I/O transfer mode */
+ if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")
+
+ /* Collective access is not permissible without a MPI based VFD */
+ if (io_xfer_mode == H5FD_MPIO_COLLECTIVE)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only")
+ } /* end else */
+#endif /*H5_HAVE_PARALLEL*/
+
+ /* Make certain that the number of elements in each selection is the same, and cache nelmts in
+ * dset_info */
+ dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space);
+ if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
+ "src and dest dataspaces have different number of elements selected")
+
+ /* Check for a NULL buffer */
+ if (NULL == dset_info[i].buf.cvp) {
+ /* Check for any elements selected (which is invalid) */
+ if (dset_info[i].nelmts > 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")
+
+ /* If the buffer is nil, and 0 element is selected, make a fake buffer.
+ * This is for some MPI package like ChaMPIon on NCSA's tungsten which
+ * doesn't support this feature.
+ */
+ dset_info[i].buf.cvp = &fake_char;
+ } /* end if */
- /* Get I/O transfer mode */
- if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")
+ /* Make sure that both selections have their extents set */
+ if (!(H5S_has_extent(dset_info[i].file_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
+ if (!(H5S_has_extent(dset_info[i].mem_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")
+
+ /* H5S_select_shape_same() has been modified to accept topologically
+ * identical selections with different rank as having the same shape
+ * (if the most rapidly changing coordinates match up), but the I/O
+ * code still has difficulties with the notion.
+ *
+ * To solve this, we check to see if H5S_select_shape_same() returns
+ * true, and if the ranks of the mem and file spaces are different.
+ * If they are, construct a new mem space that is equivalent to the
+ * old mem space, and use that instead.
+ *
+ * Note that in general, this requires us to touch up the memory buffer
+ * as well.
+ */
+ if (dset_info[i].nelmts > 0 &&
+ TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) &&
+ H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) {
+ ptrdiff_t buf_adj = 0;
+
+ /* Allocate original memory space buffer if necessary */
+ if (!orig_mem_space) {
+ if (count > 1) {
+ /* Allocate buffer */
+ if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
+ "couldn't allocate original memory space array buffer")
+ }
+ else
+ /* Use local buffer */
+ orig_mem_space = &orig_mem_space_local;
+ }
- /* Collective access is not permissible without a MPI based VFD */
- if (io_xfer_mode == H5FD_MPIO_COLLECTIVE)
- HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only")
- } /* end else */
-#endif /*H5_HAVE_PARALLEL*/
+ /* Save original memory space */
+ orig_mem_space[i] = dset_info[i].mem_space;
+ dset_info[i].mem_space = NULL;
+
+ /* Attempt to construct projected dataspace for memory dataspace */
+ if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space,
+ (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space),
+ dset_info[i].type_info.src_type_size, &buf_adj) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
+ HDassert(dset_info[i].mem_space);
+
+ /* Adjust the buffer by the given amount */
+ dset_info[i].buf.cvp = (const void *)(((const uint8_t *)dset_info[i].buf.cvp) + buf_adj);
+ } /* end if */
- /* Make certain that the number of elements in each selection is the same */
- nelmts = H5S_GET_SELECT_NPOINTS(mem_space);
- if (nelmts != H5S_GET_SELECT_NPOINTS(file_space))
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
- "src and dest dataspaces have different number of elements selected")
-
- /* Check for a NULL buffer */
- if (NULL == buf) {
- /* Check for any elements selected (which is invalid) */
- if (nelmts > 0)
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")
-
- /* If the buffer is nil, and 0 element is selected, make a fake buffer.
- * This is for some MPI package like ChaMPIon on NCSA's tungsten which
- * doesn't support this feature.
+ /* Retrieve dataset properties */
+ /* <none needed currently> */
+
+ /* Set up I/O operation */
+ if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation")
+
+ /* Allocate dataspace and initialize it if it hasn't been. */
+ should_alloc_space = dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 &&
+ !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
+ &dset_info[i].dset->shared->layout.storage);
+
+ /*
+ * If not using an MPI-based VFD, we only need to allocate
+ * and initialize storage if there's a selection in the
+ * dataset's dataspace. Otherwise, we always need to participate
+ * in the storage allocation since this may use collective
+ * operations and we will hang if we don't participate.
*/
- buf = &fake_char;
- } /* end if */
+ if (!H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI))
+ should_alloc_space = should_alloc_space && (dset_info[i].nelmts > 0);
- /* Make sure that both selections have their extents set */
- if (!(H5S_has_extent(file_space)))
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
- if (!(H5S_has_extent(mem_space)))
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")
+ if (should_alloc_space) {
+ hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */
+ hbool_t full_overwrite; /* Whether we are over-writing all the elements */
- /* H5S_select_shape_same() has been modified to accept topologically
- * identical selections with different rank as having the same shape
- * (if the most rapidly changing coordinates match up), but the I/O
- * code still has difficulties with the notion.
- *
- * To solve this, we check to see if H5S_select_shape_same() returns
- * true, and if the ranks of the mem and file spaces are different.
- * If the are, construct a new mem space that is equivalent to the
- * old mem space, and use that instead.
- *
- * Note that in general, this requires us to touch up the memory buffer
- * as well.
- */
- if (nelmts > 0 && TRUE == H5S_SELECT_SHAPE_SAME(mem_space, file_space) &&
- H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) {
- ptrdiff_t buf_adj = 0;
-
- /* Attempt to construct projected dataspace for memory dataspace */
- if (H5S_select_construct_projection(mem_space, &projected_mem_space,
- (unsigned)H5S_GET_EXTENT_NDIMS(file_space),
- type_info.src_type_size, &buf_adj) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
- HDassert(projected_mem_space);
-
- /* Adjust the buffer by the given amount */
- buf = (const void *)(((const uint8_t *)buf) + buf_adj);
-
- /* Switch to using projected memory dataspace & adjusted buffer */
- mem_space = projected_mem_space;
- } /* end if */
+ /* Get the number of elements in file dataset's dataspace */
+ if ((file_nelmts = H5S_GET_EXTENT_NPOINTS(dset_info[i].file_space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL,
+ "can't retrieve number of elements in file dataset")
- /* Retrieve dataset properties */
- /* <none needed currently> */
+ /* Always allow fill values to be written if the dataset has a VL datatype */
+ if (H5T_detect_class(dset_info[i].dset->shared->type, H5T_VLEN, FALSE))
+ full_overwrite = FALSE;
+ else
+ full_overwrite = (hbool_t)((hsize_t)file_nelmts == dset_info[i].nelmts ? TRUE : FALSE);
- /* Set up I/O operation */
- io_info.op_type = H5D_IO_OP_WRITE;
- io_info.u.wbuf = buf;
- if (H5D__ioinfo_init(dataset, &type_info, &store, &io_info) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation")
+ /* Allocate storage */
+ if (H5D__alloc_storage(dset_info[i].dset, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
+ } /* end if */
- /* Allocate dataspace and initialize it if it hasn't been. */
- should_alloc_space = dataset->shared->dcpl_cache.efl.nused == 0 &&
- !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage);
+ /* Call storage method's I/O initialization routine */
+ /* Init io_info.dset_info[] and generate piece_info in skip list */
+ if (dset_info[i].layout_ops.io_init &&
+ (*dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
+ dset_info[i].skip_io = FALSE;
+ io_op_init++;
- /*
- * If not using an MPI-based VFD, we only need to allocate
- * and initialize storage if there's a selection in the
- * dataset's dataspace. Otherwise, we always need to participate
- * in the storage allocation since this may use collective
- * operations and we will hang if we don't participate.
- */
- if (!H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI))
- should_alloc_space = should_alloc_space && (nelmts > 0);
-
- if (should_alloc_space) {
- hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */
- hbool_t full_overwrite; /* Whether we are over-writing all the elements */
-
- /* Get the number of elements in file dataset's dataspace */
- if ((file_nelmts = H5S_GET_EXTENT_NPOINTS(file_space)) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "can't retrieve number of elements in file dataset")
-
- /* Always allow fill values to be written if the dataset has a VL datatype */
- if (H5T_detect_class(dataset->shared->type, H5T_VLEN, FALSE))
- full_overwrite = FALSE;
- else
- full_overwrite = (hbool_t)((hsize_t)file_nelmts == nelmts ? TRUE : FALSE);
-
- /* Allocate storage */
- if (H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
- } /* end if */
+ /* Reset metadata tagging */
+ H5AC_tag(prev_tag, NULL);
+ } /* end of for loop */
- /* Allocate the chunk map */
- if (H5D_CONTIGUOUS != layout_type && H5D_COMPACT != layout_type) {
- if (NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t)))
- HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map")
- }
+ HDassert(type_info_init == count);
+ HDassert(io_op_init == count);
- /* Call storage method's I/O initialization routine */
- if (io_info.layout_ops.io_init &&
- (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
- io_op_init = TRUE;
+ /* Perform second phase of type info initialization */
+ if (H5D__typeinfo_init_phase2(&io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)")
#ifdef H5_HAVE_PARALLEL
/* Adjust I/O info for any parallel I/O */
- if (H5D__ioinfo_adjust(&io_info, dataset, file_space, mem_space, &type_info) < 0)
+ if (H5D__ioinfo_adjust(&io_info) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
#endif /*H5_HAVE_PARALLEL*/
- /* Invoke correct "high level" I/O routine */
- if ((*io_info.io_ops.multi_write)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")
+ /* If multi dataset I/O callback is not provided, perform write IO via
+ * single-dset path with looping */
+ if (io_info.md_io_ops.multi_write_md) {
+ /* Create sel_pieces array if any pieces are selected */
+ if (io_info.piece_count > 0) {
+ HDassert(!io_info.sel_pieces);
+ HDassert(io_info.pieces_added == 0);
+
+ /* Allocate sel_pieces array */
+ if (NULL ==
+ (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0]))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces")
+ }
+
+ /* MDIO-specific second phase initialization */
+ for (i = 0; i < count; i++)
+ if (dset_info[i].layout_ops.mdio_init) {
+ haddr_t prev_tag = HADDR_UNDEF;
+
+ /* set metadata tagging with dset oheader addr */
+ H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);
+
+ /* Make second phase IO init call */
+ if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces")
+
+ /* Reset metadata tagging */
+ H5AC_tag(prev_tag, NULL);
+ }
+
+ /* Invoke correct "high level" I/O routine */
+ if ((*io_info.md_io_ops.multi_write_md)(&io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")
+ } /* end if */
+ else {
+ haddr_t prev_tag = HADDR_UNDEF;
+
+ if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) {
+ if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for memory space list")
+ if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
+ if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for piece address list")
+ if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for element size list")
+ if (NULL == (io_info.wbufs = H5MM_malloc(io_info.piece_count * sizeof(const void *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
+ "memory allocation failed for read buffer list")
+ }
+
+ /* loop with serial & single-dset write IO path */
+ for (i = 0; i < count; i++) {
+ HDassert(!dset_info[i].skip_io);
+
+ /* set metadata tagging with dset oheader addr */
+ H5AC_tag(dset_info->dset->oloc.addr, &prev_tag);
+
+ /* Invoke correct "high level" I/O routine */
+ if ((*dset_info[i].io_ops.multi_write)(&io_info, &dset_info[i]) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")
+
+ /* Reset metadata tagging */
+ H5AC_tag(prev_tag, NULL);
+ }
+
+ /* Make final multi dataset selection I/O call if we are using both
+ * features - in this case the multi_write callbacks did not perform the
+ * actual I/O */
+ H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t)
+ if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info))
+ if (H5F_shared_select_write(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added,
+ io_info.mem_spaces, io_info.file_spaces, io_info.addrs,
+ io_info.element_sizes, io_info.wbufs) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "selection write failed")
+ }
#ifdef OLD_WAY
/*
@@ -515,88 +774,138 @@ H5D__write(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_spac
done:
/* Shut down the I/O op information */
- if (io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0)
- HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
- if (fm)
- fm = H5FL_FREE(H5D_chunk_map_t, fm);
+ for (i = 0; i < io_op_init; i++) {
+ HDassert(!dset_info[i].skip_io);
+ if (dset_info[i].layout_ops.io_term &&
+ (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
+ }
/* Shut down datatype info for operation */
- if (type_info_init && H5D__typeinfo_term(&type_info) < 0)
+ if (H5D__typeinfo_term(&io_info, type_info_init) < 0)
HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")
- /* discard projected mem space if it was created */
- if (NULL != projected_mem_space)
- if (H5S_close(projected_mem_space) < 0)
- HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace")
+ /* Discard projected mem spaces and restore originals */
+ if (orig_mem_space) {
+ for (i = 0; i < count; i++)
+ if (orig_mem_space[i]) {
+ if (H5S_close(dset_info[i].mem_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL,
+ "unable to shut down projected memory dataspace")
+ dset_info[i].mem_space = orig_mem_space[i];
+ }
+
+ /* Free orig_mem_space array if it was allocated */
+ if (orig_mem_space != &orig_mem_space_local)
+ H5MM_free(orig_mem_space);
+ }
+
+ /* Free global piece array */
+ H5MM_xfree(io_info.sel_pieces);
- FUNC_LEAVE_NOAPI_TAG(ret_value)
-} /* end H5D__write() */
+ /* Free store array if it was allocated */
+ if (store != &store_local)
+ H5MM_free(store);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__write */
/*-------------------------------------------------------------------------
* Function: H5D__ioinfo_init
*
- * Purpose: Routine for determining correct I/O operations for
- * each I/O action.
+ * Purpose: General setup for H5D_io_info_t struct
*
* Return: Non-negative on success/Negative on failure
*
- * Programmer: Quincey Koziol
- * Thursday, September 30, 2004
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* check args */
+ HDassert(count > 0);
+ HDassert(dset_info);
+ HDassert(dset_info[0].dset->oloc.file);
+ HDassert(io_info);
+
+ /* Zero out struct */
+ HDmemset(io_info, 0, sizeof(*io_info));
+
+ /* Set up simple fields */
+ io_info->f_sh = count > 0 ? H5F_SHARED(dset_info[0].dset->oloc.file) : NULL;
+ io_info->count = count;
+
+ /* Start without multi-dataset I/O ops. If we're not using the collective
+ * I/O path then we will call the single dataset callbacks in a loop. */
+
+ /* Use provided dset_info */
+ io_info->dsets_info = dset_info;
+
+ /* Start with selection I/O on if the global is on, layout callback will
+ * turn it off if appropriate */
+ io_info->use_select_io = H5_use_selection_io_g;
+
+#ifdef H5_HAVE_PARALLEL
+ /* Determine if the file was opened with an MPI VFD */
+ if (count > 0)
+ io_info->using_mpi_vfd = H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI);
+#endif /* H5_HAVE_PARALLEL */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__ioinfo_init() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__dset_ioinfo_init
+ *
+ * Purpose: Routine for determining correct I/O operations for each I/O action.
+ *
+ * Return: Non-negative on success/Negative on failure
*
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__ioinfo_init(H5D_t *dset, const H5D_type_info_t *type_info, H5D_storage_t *store, H5D_io_info_t *io_info)
+H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store)
{
FUNC_ENTER_PACKAGE_NOERR
/* check args */
HDassert(dset);
HDassert(dset->oloc.file);
- HDassert(type_info);
- HDassert(type_info->tpath);
- HDassert(io_info);
+ HDassert(dset_info->type_info.tpath);
/* Set up "normal" I/O fields */
- io_info->dset = dset;
- io_info->f_sh = H5F_SHARED(dset->oloc.file);
- io_info->store = store;
+ dset_info->dset = dset;
+ dset_info->store = store;
/* Set I/O operations to initial values */
- io_info->layout_ops = *dset->shared->layout.ops;
+ dset_info->layout_ops = *dset->shared->layout.ops;
/* Set the "high-level" I/O operations for the dataset */
- io_info->io_ops.multi_read = dset->shared->layout.ops->ser_read;
- io_info->io_ops.multi_write = dset->shared->layout.ops->ser_write;
+ dset_info->io_ops.multi_read = dset->shared->layout.ops->ser_read;
+ dset_info->io_ops.multi_write = dset->shared->layout.ops->ser_write;
/* Set the I/O operations for reading/writing single blocks on disk */
- if (type_info->is_xform_noop && type_info->is_conv_noop) {
+ if (dset_info->type_info.is_xform_noop && dset_info->type_info.is_conv_noop) {
/*
- * If there is no data transform or type conversion then read directly into
- * the application's buffer. This saves at least one mem-to-mem copy.
+ * If there is no data transform or type conversion then read directly
+ * into the application's buffer.
+ * This saves at least one mem-to-mem copy.
*/
- io_info->io_ops.single_read = H5D__select_read;
- io_info->io_ops.single_write = H5D__select_write;
+ dset_info->io_ops.single_read = H5D__select_read;
+ dset_info->io_ops.single_write = H5D__select_write;
} /* end if */
else {
/*
* This is the general case (type conversion, usually).
*/
- io_info->io_ops.single_read = H5D__scatgath_read;
- io_info->io_ops.single_write = H5D__scatgath_write;
+ dset_info->io_ops.single_read = H5D__scatgath_read;
+ dset_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);
-#endif /* H5_HAVE_PARALLEL */
-
FUNC_LEAVE_NOAPI(SUCCEED)
-} /* end H5D__ioinfo_init() */
+} /* end H5D__dset_ioinfo_init() */
/*-------------------------------------------------------------------------
* Function: H5D__typeinfo_init
@@ -612,8 +921,10 @@ H5D__ioinfo_init(H5D_t *dset, const H5D_type_info_t *type_info, H5D_storage_t *s
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_type_info_t *type_info)
+H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id)
{
+ H5D_type_info_t *type_info;
+ const H5D_t *dset;
const H5T_t *src_type; /* Source datatype */
const H5T_t *dst_type; /* Destination datatype */
H5Z_data_xform_t *data_transform; /* Data transform info */
@@ -622,7 +933,12 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t
FUNC_ENTER_PACKAGE
/* check args */
- HDassert(type_info);
+ HDassert(io_info);
+ HDassert(dset_info);
+
+ /* Set convenience pointers */
+ type_info = &dset_info->type_info;
+ dset = dset_info->dset;
HDassert(dset);
/* Patch the top level file pointer for dt->shared->u.vlen.f if needed */
@@ -637,7 +953,7 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
type_info->dset_type = dset->shared->type;
- if (do_write) {
+ if (io_info->op_type == H5D_IO_OP_WRITE) {
src_type = type_info->mem_type;
dst_type = dset->shared->type;
type_info->src_type_id = mem_type_id;
@@ -667,7 +983,6 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t
/* Precompute some useful information */
type_info->src_type_size = H5T_get_size(src_type);
type_info->dst_type_size = H5T_get_size(dst_type);
- type_info->max_type_size = MAX(type_info->src_type_size, type_info->dst_type_size);
type_info->is_conv_noop = H5T_path_noop(type_info->tpath);
type_info->is_xform_noop = H5Z_xform_noop(data_transform);
if (type_info->is_xform_noop && type_info->is_conv_noop) {
@@ -675,27 +990,21 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t
type_info->need_bkg = H5T_BKG_NO;
} /* end if */
else {
- void *tconv_buf; /* Temporary conversion buffer pointer */
- void *bkgr_buf; /* Background conversion buffer pointer */
- size_t max_temp_buf; /* Maximum temporary buffer size */
H5T_bkg_t bkgr_buf_type; /* Background buffer type */
- size_t target_size; /* Desired buffer size */
/* Get info from API context */
- if (H5CX_get_max_temp_buf(&max_temp_buf) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size")
- if (H5CX_get_tconv_buf(&tconv_buf) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve temp. conversion buffer pointer")
- if (H5CX_get_bkgr_buf(&bkgr_buf) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background conversion buffer pointer")
if (H5CX_get_bkgr_buf_type(&bkgr_buf_type) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background buffer type")
/* Check if the datatypes are compound subsets of one another */
type_info->cmpd_subset = H5T_path_compound_subset(type_info->tpath);
+ /* Update io_info->max_type_size */
+ io_info->max_type_size =
+ MAX3(io_info->max_type_size, type_info->src_type_size, type_info->dst_type_size);
+
/* Check if we need a background buffer */
- if (do_write && H5T_detect_class(dset->shared->type, H5T_VLEN, FALSE))
+ if ((io_info->op_type == H5D_IO_OP_WRITE) && H5T_detect_class(dset->shared->type, H5T_VLEN, FALSE))
type_info->need_bkg = H5T_BKG_YES;
else {
H5T_bkg_t path_bkg; /* Type conversion's background info */
@@ -708,13 +1017,54 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t
else
type_info->need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
} /* end else */
+ } /* end else */
- /* Set up datatype conversion/background buffers */
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__typeinfo_init() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__typeinfo_init_phase2
+ *
+ * Purpose: Finish initializing type info for all datasets after
+ * calculating the max type size across all datasets.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__typeinfo_init_phase2(H5D_io_info_t *io_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(io_info);
+
+ /* Check if we need to allocate a shared type conversion buffer */
+ if (io_info->max_type_size) {
+ void *tconv_buf; /* Temporary conversion buffer pointer */
+ void *bkgr_buf; /* Background conversion buffer pointer */
+ size_t max_temp_buf; /* Maximum temporary buffer size */
+ size_t target_size; /* Desired buffer size */
+ size_t i; /* Local index variable */
+
+ /* Get info from API context */
+ if (H5CX_get_max_temp_buf(&max_temp_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size")
+ if (H5CX_get_tconv_buf(&tconv_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve temp. conversion buffer pointer")
+ if (H5CX_get_bkgr_buf(&bkgr_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background conversion buffer pointer")
+ /* Set up datatype conversion/background buffers */
target_size = max_temp_buf;
- /* If the buffer is too small to hold even one element, try to make it bigger */
- if (target_size < type_info->max_type_size) {
+ /* If the buffer is too small to hold even one element (in the dataset with the largest , try to make
+ * it bigger */
+ if (target_size < io_info->max_type_size) {
hbool_t default_buffer_info; /* Whether the buffer information are the defaults */
/* Detect if we have all default settings for buffers */
@@ -724,50 +1074,64 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t
/* Check if we are using the default buffer info */
if (default_buffer_info)
/* OK to get bigger for library default settings */
- target_size = type_info->max_type_size;
+ target_size = io_info->max_type_size;
else
/* Don't get bigger than the application has requested */
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")
} /* end if */
- /* Compute the number of elements that will fit into buffer */
- type_info->request_nelmts = target_size / type_info->max_type_size;
-
- /* Sanity check elements in temporary buffer */
- if (type_info->request_nelmts == 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")
-
/* Get a temporary buffer for type conversion unless the app has already
* supplied one through the xfer properties. Instead of allocating a
- * buffer which is the exact size, we allocate the target size.
- */
- if (NULL == (type_info->tconv_buf = (uint8_t *)tconv_buf)) {
+ * buffer which is the exact size, we allocate the target size. This
+ * buffer is shared among all datasets in the operation, unlike for the
+ * background buffer, where each dataset gets its own. */
+ if (NULL == (io_info->tconv_buf = (uint8_t *)tconv_buf)) {
/* Allocate temporary buffer */
- if (NULL == (type_info->tconv_buf = H5FL_BLK_CALLOC(type_conv, target_size)))
+ if (NULL == (io_info->tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
- type_info->tconv_buf_allocated = TRUE;
- } /* end if */
- if (type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)bkgr_buf)) {
- size_t bkg_size; /* Desired background buffer size */
-
- /* Compute the background buffer size */
- /* (don't try to use buffers smaller than the default size) */
- bkg_size = type_info->request_nelmts * type_info->dst_type_size;
- if (bkg_size < max_temp_buf)
- bkg_size = max_temp_buf;
-
- /* Allocate background buffer */
- /* (Need calloc()-like call since memory needs to be initialized) */
- if (NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "memory allocation failed for background conversion")
- type_info->bkg_buf_allocated = TRUE;
+ io_info->tconv_buf_allocated = TRUE;
} /* end if */
- } /* end else */
+
+ /* Don't use API provided background buffer if there's more than one dataset, since each
+ * dataset needs its own */
+ if (io_info->count > 1)
+ bkgr_buf = NULL;
+
+ /* Iterate over datasets */
+ for (i = 0; i < io_info->count; i++) {
+ H5D_type_info_t *type_info = &io_info->dsets_info[i].type_info;
+
+ /* Compute the number of elements that will fit into buffer */
+ type_info->request_nelmts = target_size / MAX(type_info->src_type_size, type_info->dst_type_size);
+ ;
+
+ /* Sanity check elements in temporary buffer */
+ if (type_info->request_nelmts == 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")
+
+ /* Allocate background buffer if necessary */
+ if (type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)bkgr_buf)) {
+ size_t bkg_size; /* Desired background buffer size */
+
+ /* Compute the background buffer size */
+ /* (don't try to use buffers smaller than the default size) */
+ bkg_size = type_info->request_nelmts * type_info->dst_type_size;
+ if (bkg_size < max_temp_buf)
+ bkg_size = max_temp_buf;
+
+ /* Allocate background buffer */
+ /* (Need calloc()-like call since memory needs to be initialized) */
+ if (NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
+ "memory allocation failed for background conversion")
+ type_info->bkg_buf_allocated = TRUE;
+ } /* end if */
+ }
+ }
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5D__typeinfo_init() */
+} /* end H5D__typeinfo_init_phase2() */
#ifdef H5_HAVE_PARALLEL
@@ -776,30 +1140,28 @@ done:
*
* Purpose: Adjust operation's I/O info for any parallel I/O
*
- * Return: Non-negative on success/Negative on failure
+ * This was derived from H5D__ioinfo_adjust for multi-dset work.
*
- * Programmer: Quincey Koziol
- * Thursday, March 27, 2008
+ * Return: Non-negative on success/Negative on failure
*
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_space, const H5S_t *mem_space,
- const H5D_type_info_t *type_info)
+H5D__ioinfo_adjust(H5D_io_info_t *io_info)
{
+ H5D_t *dset0; /* only the first dset , also for single dsets case */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_PACKAGE
/* check args */
- HDassert(dset);
- HDassert(dset->oloc.file);
- HDassert(mem_space);
- HDassert(file_space);
- HDassert(type_info);
- HDassert(type_info->tpath);
HDassert(io_info);
+ /* check the first dset, should exist either single or multi dset cases */
+ HDassert(io_info->dsets_info[0].dset);
+ dset0 = io_info->dsets_info[0].dset;
+ HDassert(dset0->oloc.file);
+
/* Reset the actual io mode properties to the default values in case
* the DXPL (if it's non-default) was previously used in a collective
* I/O operation.
@@ -819,11 +1181,11 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")
/* Get MPI communicator */
- if (MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset->oloc.file)))
+ if (MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset0->oloc.file)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator")
/* Check if we can set direct MPI-IO read/write functions */
- if ((opt = H5D__mpio_opt_possible(io_info, file_space, mem_space, type_info)) < 0)
+ if ((opt = H5D__mpio_opt_possible(io_info)) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace ")
/* Check if we can use the optimized parallel I/O routines */
@@ -833,10 +1195,10 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_
* 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;
+ io_info->md_io_ops.multi_read_md = H5D__collective_read;
+ io_info->md_io_ops.multi_write_md = H5D__collective_write;
+ io_info->md_io_ops.single_read_md = H5D__mpio_select_read;
+ io_info->md_io_ops.single_write_md = H5D__mpio_select_write;
} /* end if */
} /* end if */
else {
@@ -857,28 +1219,38 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_
* with multiple ranks involved; otherwise, there will be metadata
* inconsistencies in the file.
*/
- if (io_info->op_type == H5D_IO_OP_WRITE && io_info->dset->shared->dcpl_cache.pline.nused > 0) {
- int comm_size = 0;
-
- /* Retrieve size of MPI communicator used for file */
- if ((comm_size = H5F_shared_mpi_get_size(io_info->f_sh)) < 0)
- HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MPI communicator size")
-
- if (comm_size > 1) {
- char local_no_coll_cause_string[512];
- char global_no_coll_cause_string[512];
-
- if (H5D__mpio_get_no_coll_cause_strings(local_no_coll_cause_string, 512,
- global_no_coll_cause_string, 512) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
- "can't get reasons for breaking collective I/O")
-
- HGOTO_ERROR(H5E_IO, H5E_NO_INDEPENDENT, FAIL,
- "Can't perform independent write with filters in pipeline.\n"
- " The following caused a break from collective I/O:\n"
- " Local causes: %s\n"
- " Global causes: %s",
- local_no_coll_cause_string, global_no_coll_cause_string);
+ if (io_info->op_type == H5D_IO_OP_WRITE) {
+ size_t i;
+
+ /* Check all datasets for filters */
+ for (i = 0; i < io_info->count; i++)
+ if (io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused > 0)
+ break;
+
+ /* If the above loop didn't complete at least one dataset has a filter */
+ if (i < io_info->count) {
+ int comm_size = 0;
+
+ /* Retrieve size of MPI communicator used for file */
+ if ((comm_size = H5F_shared_mpi_get_size(io_info->f_sh)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MPI communicator size")
+
+ if (comm_size > 1) {
+ char local_no_coll_cause_string[512];
+ char global_no_coll_cause_string[512];
+
+ if (H5D__mpio_get_no_coll_cause_strings(local_no_coll_cause_string, 512,
+ global_no_coll_cause_string, 512) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
+ "can't get reasons for breaking collective I/O")
+
+ HGOTO_ERROR(H5E_IO, H5E_NO_INDEPENDENT, FAIL,
+ "Can't perform independent write with filters in pipeline.\n"
+ " The following caused a break from collective I/O:\n"
+ " Local causes: %s\n"
+ " Global causes: %s",
+ local_no_coll_cause_string, global_no_coll_cause_string);
+ }
}
}
@@ -899,31 +1271,34 @@ done:
#endif /* H5_HAVE_PARALLEL */
/*-------------------------------------------------------------------------
- * Function: H5D__typeinfo_term
+ * Function: H5D__typeinfo_term
*
- * Purpose: Common logic for terminating a type info object
+ * Purpose: Common logic for terminating a type info object
*
- * Return: Non-negative on success/Negative on failure
+ * Return: Non-negative on success/Negative on failure
*
- * Programmer: Quincey Koziol
- * Thursday, March 6, 2008
+ * Programmer: Quincey Koziol
+ * Thursday, March 6, 2008
*
*-------------------------------------------------------------------------
*/
static herr_t
-H5D__typeinfo_term(const H5D_type_info_t *type_info)
+H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init)
{
+ size_t i;
+
FUNC_ENTER_PACKAGE_NOERR
/* Check for releasing datatype conversion & background buffers */
- if (type_info->tconv_buf_allocated) {
- HDassert(type_info->tconv_buf);
- (void)H5FL_BLK_FREE(type_conv, type_info->tconv_buf);
- } /* end if */
- if (type_info->bkg_buf_allocated) {
- HDassert(type_info->bkg_buf);
- (void)H5FL_BLK_FREE(type_conv, type_info->bkg_buf);
+ if (io_info->tconv_buf_allocated) {
+ HDassert(io_info->tconv_buf);
+ (void)H5FL_BLK_FREE(type_conv, io_info->tconv_buf);
} /* end if */
+ for (i = 0; i < type_info_init; i++)
+ if (io_info->dsets_info[i].type_info.bkg_buf_allocated) {
+ HDassert(io_info->dsets_info[i].type_info.bkg_buf);
+ (void)H5FL_BLK_FREE(type_conv, io_info->dsets_info[i].type_info.bkg_buf);
+ } /* end if */
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__typeinfo_term() */