Bug fix
Description:
Correct typo which didn't show up during my previous testing in production
mode.
Platforms tested:
FreeBSD 4.8 (sleipnir)
h5committest not necessary.
2685 lines
111 KiB
C
2685 lines
111 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* Copyright by the Board of Trustees of the University of Illinois. *
|
||
* All rights reserved. *
|
||
* *
|
||
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
||
* terms governing use, modification, and redistribution, is contained in *
|
||
* the files COPYING and Copyright.html. COPYING can be found at the root *
|
||
* of the source code distribution tree; Copyright.html can be found at the *
|
||
* root level of an installed copy of the electronic HDF5 document set and *
|
||
* is linked from the top-level documents page. It can also be found at *
|
||
* http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
||
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
#define H5D_PACKAGE /*suppress error about including H5Dpkg */
|
||
|
||
#include "H5private.h" /* Generic Functions */
|
||
#include "H5Dpkg.h" /* Dataset functions */
|
||
#include "H5Eprivate.h" /* Error handling */
|
||
#include "H5FLprivate.h" /* Free Lists */
|
||
#include "H5Iprivate.h" /* IDs */
|
||
#include "H5MMprivate.h" /* Memory management */
|
||
#include "H5Sprivate.h" /* Dataspace functions */
|
||
#include "H5TBprivate.h" /* Threaded, balanced, binary trees (TBBTs) */
|
||
#include "H5Vprivate.h" /* Vector and array functions */
|
||
|
||
/*#define H5D_DEBUG*/
|
||
|
||
/*
|
||
* The MPIO, MPIPOSIX, & FPHDF5 drivers are needed because there are
|
||
* file and places where we check for things that aren't handled by these
|
||
* drivers.
|
||
*/
|
||
#include "H5FDfphdf5.h"
|
||
#include "H5FDmpio.h"
|
||
#include "H5FDmpiposix.h"
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/* Remove this if H5R_DATASET_REGION is no longer used in this file */
|
||
# include "H5Rpublic.h"
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
/* Pablo information */
|
||
#define PABLO_MASK H5Dio_mask
|
||
|
||
/* Local typedefs */
|
||
|
||
/* Information for mapping between file space and memory space */
|
||
|
||
/* Structure holding information about a file chunk's selection for mapping */
|
||
typedef struct H5D_fchunk_info_t {
|
||
hsize_t index; /* "Index" of chunk in dataset (must be first for TBBT routines) */
|
||
H5S_t *space; /* Dataspace describing chunk & selection in it */
|
||
hssize_t coords[H5O_LAYOUT_NDIMS]; /* Coordinates of chunk in file dataset's dataspace */
|
||
} H5D_fchunk_info_t;
|
||
|
||
/* Structure holding information about a memory chunk's selection for mapping */
|
||
typedef struct H5D_mchunk_info_t {
|
||
hsize_t index; /* "Index" of chunk in dataset (must be first for TBBT routines) */
|
||
H5S_t *space; /* Dataspace describing chunk & selection in it */
|
||
} H5D_mchunk_info_t;
|
||
|
||
/* Main structure holding the mapping between file chunks and memory */
|
||
typedef struct fm_map {
|
||
H5TB_TREE *fsel; /* TBBT containing file dataspaces for all chunks */
|
||
H5TB_TREE *msel; /* TBBT containing memory dataspaces for all chunks */
|
||
hsize_t last_index; /* Index of last chunk operated on */
|
||
H5S_t *last_fchunk; /* Pointer to last file chunk's dataspace */
|
||
H5S_t *last_mchunk; /* Pointer to last memory chunk's dataspace */
|
||
H5S_t *fchunk_tmpl; /* Dataspace template for new file chunks */
|
||
H5S_t *mchunk_tmpl; /* Dataspace template for new memory chunks */
|
||
unsigned f_ndims; /* Number of dimensions for file dataspace */
|
||
H5S_sel_iter_t mem_iter; /* Iterator for elements in memory selection */
|
||
unsigned m_ndims; /* Number of dimensions for memory dataspace */
|
||
hsize_t chunks[H5O_LAYOUT_NDIMS]; /* Number of chunks in each dimension */
|
||
hsize_t down_chunks[H5O_LAYOUT_NDIMS]; /* "down" size of number of chunks in each dimension */
|
||
H5O_layout_t *layout; /* Dataset layout information*/
|
||
} fm_map;
|
||
|
||
/* Interface initialization */
|
||
static int interface_initialize_g = 0;
|
||
#define INTERFACE_INIT NULL
|
||
|
||
/* Local functions */
|
||
static herr_t H5D_read(H5D_t *dataset, const H5T_t *mem_type,
|
||
const H5S_t *mem_space, const H5S_t *file_space,
|
||
hid_t dset_xfer_plist, void *buf/*out*/);
|
||
static herr_t H5D_write(H5D_t *dataset, const H5T_t *mem_type,
|
||
const H5S_t *mem_space, const H5S_t *file_space,
|
||
hid_t dset_xfer_plist, const void *buf);
|
||
static herr_t
|
||
H5D_contig_read(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t doing_mpio, H5FD_mpio_xfer_t xfer_mode,
|
||
hid_t src_id, hid_t dst_id, void *buf/*out*/);
|
||
static herr_t
|
||
H5D_contig_write(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t doing_mpio, H5FD_mpio_xfer_t xfer_mode,
|
||
hid_t src_id, hid_t dst_id, const void *buf);
|
||
static herr_t
|
||
H5D_chunk_read(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t doing_mpio, H5FD_mpio_xfer_t xfer_mode,
|
||
hid_t src_id, hid_t dst_id, void *buf/*out*/);
|
||
static herr_t
|
||
H5D_chunk_write(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t doing_mpio, H5FD_mpio_xfer_t xfer_mode,
|
||
hid_t src_id, hid_t dst_id, const void *buf);
|
||
#ifdef H5_HAVE_PARALLEL
|
||
static herr_t
|
||
H5D_io_assist_mpio(H5P_genplist_t *dx_plist, hbool_t doing_mpio, H5FD_mpio_xfer_t xfer_mode,
|
||
hbool_t *xfer_mode_changed);
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
static herr_t H5D_create_chunk_map(H5D_t *dataset, const H5T_t *mem_type,
|
||
const H5S_t *file_space, const H5S_t *mem_space, fm_map *fm);
|
||
static herr_t H5D_destroy_chunk_map(fm_map *fm);
|
||
static void H5D_free_fchunk_info(void *fchunk_info);
|
||
static void H5D_free_mchunk_info(void *mchunk_info);
|
||
static herr_t H5D_chunk_coords_assist(hssize_t *coords, size_t ndims,
|
||
hsize_t chunks[], hsize_t chunk_idx);
|
||
static herr_t H5D_chunk_cb(void *elem, hid_t type_id, hsize_t ndims,
|
||
hssize_t *coords, void *fm);
|
||
static herr_t H5D_fill(const void *fill, const H5T_t *fill_type, void *buf,
|
||
const H5T_t *buf_type, const H5S_t *space, hid_t dxpl_id);
|
||
|
||
|
||
/* Declare a free list to manage blocks of single datatype element data */
|
||
H5FL_BLK_DEFINE(type_elem);
|
||
|
||
/* Declare a free list to manage blocks of type conversion data */
|
||
H5FL_BLK_DEFINE(type_conv);
|
||
|
||
/* Declare a free list to manage the H5D_fchunk_info_t struct */
|
||
H5FL_DEFINE_STATIC(H5D_fchunk_info_t);
|
||
|
||
/* Declare a free list to manage the H5D_mchunk_info_t struct */
|
||
H5FL_DEFINE_STATIC(H5D_mchunk_info_t);
|
||
|
||
|
||
/*--------------------------------------------------------------------------
|
||
NAME
|
||
H5Dfill
|
||
PURPOSE
|
||
Fill a selection in memory with a value
|
||
USAGE
|
||
herr_t H5Dfill(fill, fill_type, space, buf, buf_type)
|
||
const void *fill; IN: Pointer to fill value to use
|
||
hid_t fill_type_id; IN: Datatype of the fill value
|
||
void *buf; IN/OUT: Memory buffer to fill selection within
|
||
hid_t buf_type_id; IN: Datatype of the elements in buffer
|
||
hid_t space_id; IN: Dataspace describing memory buffer &
|
||
containing selection to use.
|
||
RETURNS
|
||
Non-negative on success/Negative on failure.
|
||
DESCRIPTION
|
||
Use the selection in the dataspace to fill elements in a memory buffer.
|
||
GLOBAL VARIABLES
|
||
COMMENTS, BUGS, ASSUMPTIONS
|
||
If "fill" parameter is NULL, use all zeros as fill value
|
||
EXAMPLES
|
||
REVISION LOG
|
||
--------------------------------------------------------------------------*/
|
||
herr_t
|
||
H5Dfill(const void *fill, hid_t fill_type_id, void *buf, hid_t buf_type_id, hid_t space_id)
|
||
{
|
||
H5S_t *space; /* Dataspace */
|
||
H5T_t *fill_type; /* Fill-value datatype */
|
||
H5T_t *buf_type; /* Buffer datatype */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_API(H5Dfill, FAIL);
|
||
H5TRACE5("e","xixii",fill,fill_type_id,buf,buf_type_id,space_id);
|
||
|
||
/* Check args */
|
||
if (buf==NULL)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid buffer");
|
||
if (NULL == (space=H5I_object_verify(space_id, H5I_DATASPACE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a dataspace");
|
||
if (NULL == (fill_type=H5I_object_verify(fill_type_id, H5I_DATATYPE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a datatype");
|
||
if (NULL == (buf_type=H5I_object_verify(buf_type_id, H5I_DATATYPE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a datatype");
|
||
|
||
/* Fill the selection in the memory buffer */
|
||
if(H5D_fill(fill,fill_type,buf,buf_type,space, H5AC_dxpl_id)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed");
|
||
|
||
done:
|
||
FUNC_LEAVE_API(ret_value);
|
||
} /* H5Dfill() */
|
||
|
||
|
||
/*--------------------------------------------------------------------------
|
||
NAME
|
||
H5D_fill
|
||
PURPOSE
|
||
Fill a selection in memory with a value (internal version)
|
||
USAGE
|
||
herr_t H5D_fill(fill, fill_type, buf, buf_type, space)
|
||
const void *fill; IN: Pointer to fill value to use
|
||
H5T_t *fill_type; IN: Datatype of the fill value
|
||
void *buf; IN/OUT: Memory buffer to fill selection within
|
||
H5T_t *buf_type; IN: Datatype of the elements in buffer
|
||
H5S_t *space; IN: Dataspace describing memory buffer &
|
||
containing selection to use.
|
||
RETURNS
|
||
Non-negative on success/Negative on failure.
|
||
DESCRIPTION
|
||
Use the selection in the dataspace to fill elements in a memory buffer.
|
||
GLOBAL VARIABLES
|
||
COMMENTS, BUGS, ASSUMPTIONS
|
||
If "fill" parameter is NULL, use all zeros as fill value. If "fill_type"
|
||
parameter is NULL, use "buf_type" for the fill value datatype.
|
||
EXAMPLES
|
||
REVISION LOG
|
||
--------------------------------------------------------------------------*/
|
||
static herr_t
|
||
H5D_fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_type, const H5S_t *space, hid_t dxpl_id)
|
||
{
|
||
H5T_path_t *tpath = NULL; /* Conversion information*/
|
||
uint8_t *tconv_buf = NULL; /* Data type conv buffer */
|
||
uint8_t *bkg_buf = NULL; /* Temp conversion buffer */
|
||
hid_t src_id = -1, dst_id = -1; /* Temporary type IDs */
|
||
size_t src_type_size; /* Size of source type */
|
||
size_t dst_type_size; /* Size of destination type*/
|
||
size_t buf_size; /* Desired buffer size */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_fill);
|
||
|
||
/* Check args */
|
||
assert(buf);
|
||
assert(buf_type);
|
||
assert(space);
|
||
|
||
/* Check for "default" fill value */
|
||
if(fill_type==NULL)
|
||
fill_type=buf_type;
|
||
|
||
/* Get the memory and file datatype sizes */
|
||
src_type_size = H5T_get_size(fill_type);
|
||
dst_type_size = H5T_get_size(buf_type);
|
||
|
||
/* Get the maximum buffer size needed and allocate it */
|
||
buf_size=MAX(src_type_size,dst_type_size);
|
||
if (NULL==(tconv_buf = H5FL_BLK_MALLOC(type_elem,buf_size)) || NULL==(bkg_buf = H5FL_BLK_CALLOC(type_elem,buf_size)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
|
||
/* Copy the user's data into the buffer for conversion */
|
||
if(fill==NULL)
|
||
HDmemset(tconv_buf,0,src_type_size);
|
||
else
|
||
HDmemcpy(tconv_buf,fill,src_type_size);
|
||
|
||
/* Convert memory buffer into disk buffer */
|
||
/* Set up type conversion function */
|
||
if (NULL == (tpath = H5T_path_find(fill_type, buf_type, NULL, NULL, dxpl_id))) {
|
||
HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types");
|
||
} else if (!H5T_path_noop(tpath)) {
|
||
if ((src_id = H5I_register(H5I_DATATYPE, H5T_copy(fill_type, H5T_COPY_ALL)))<0 ||
|
||
(dst_id = H5I_register(H5I_DATATYPE, H5T_copy(buf_type, H5T_COPY_ALL)))<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion");
|
||
}
|
||
|
||
/* Perform data type conversion */
|
||
if (H5T_convert(tpath, src_id, dst_id, (hsize_t)1, 0, 0, tconv_buf, bkg_buf, dxpl_id)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "data type conversion failed");
|
||
|
||
/* Fill the selection in the memory buffer */
|
||
if(H5S_select_fill(tconv_buf, dst_type_size, space, buf)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed");
|
||
|
||
done:
|
||
if (tconv_buf)
|
||
H5FL_BLK_FREE(type_elem,tconv_buf);
|
||
if (bkg_buf)
|
||
H5FL_BLK_FREE(type_elem,bkg_buf);
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* H5D_fill() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5Dread
|
||
*
|
||
* Purpose: Reads (part of) a DSET from the file into application
|
||
* memory BUF. The part of the dataset to read is defined with
|
||
* MEM_SPACE_ID and FILE_SPACE_ID. The data points are
|
||
* converted from their file type to the MEM_TYPE_ID specified.
|
||
* Additional miscellaneous data transfer properties can be
|
||
* passed to this function with the PLIST_ID argument.
|
||
*
|
||
* The FILE_SPACE_ID can be the constant H5S_ALL which indicates
|
||
* that the entire file data space is to be referenced.
|
||
*
|
||
* The MEM_SPACE_ID can be the constant H5S_ALL in which case
|
||
* the memory data space is the same as the file data space
|
||
* defined when the dataset was created.
|
||
*
|
||
* The number of elements in the memory data space must match
|
||
* the number of elements in the file data space.
|
||
*
|
||
* The PLIST_ID can be the constant H5P_DEFAULT in which
|
||
* case the default data transfer properties are used.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Errors:
|
||
* ARGS BADTYPE Not a data space.
|
||
* ARGS BADTYPE Not a data type.
|
||
* ARGS BADTYPE Not a dataset.
|
||
* ARGS BADTYPE Not xfer parms.
|
||
* ARGS BADVALUE No output buffer.
|
||
* DATASET READERROR Can't read data.
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, December 4, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id,
|
||
hid_t file_space_id, hid_t plist_id, void *buf/*out*/)
|
||
{
|
||
H5D_t *dset = NULL;
|
||
const H5T_t *mem_type = NULL;
|
||
const H5S_t *mem_space = NULL;
|
||
const H5S_t *file_space = NULL;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_API(H5Dread, FAIL);
|
||
H5TRACE6("e","iiiiix",dset_id,mem_type_id,mem_space_id,file_space_id,
|
||
plist_id,buf);
|
||
|
||
/* check arguments */
|
||
if (NULL == (dset = H5I_object_verify(dset_id, H5I_DATASET)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset");
|
||
if (NULL == dset->ent.file)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset");
|
||
if (NULL == (mem_type = H5I_object_verify(mem_type_id, H5I_DATATYPE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type");
|
||
if (H5S_ALL != mem_space_id) {
|
||
if (NULL == (mem_space = H5I_object_verify(mem_space_id, H5I_DATASPACE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
|
||
|
||
/* Check for valid selection */
|
||
if(H5S_select_valid(mem_space)!=TRUE)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent");
|
||
}
|
||
if (H5S_ALL != file_space_id) {
|
||
if (NULL == (file_space = H5I_object_verify(file_space_id, H5I_DATASPACE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
|
||
|
||
/* Check for valid selection */
|
||
if(H5S_select_valid(file_space)!=TRUE)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent");
|
||
}
|
||
|
||
/* Get the default dataset transfer property list if the user didn't provide one */
|
||
if (H5P_DEFAULT == plist_id)
|
||
plist_id= H5P_DATASET_XFER_DEFAULT;
|
||
else
|
||
if (TRUE!=H5P_isa_class(plist_id,H5P_DATASET_XFER))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms");
|
||
if (!buf)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer");
|
||
|
||
/* read raw data */
|
||
if (H5D_read(dset, mem_type, mem_space, file_space, plist_id, buf/*out*/) < 0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data");
|
||
|
||
done:
|
||
FUNC_LEAVE_API(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5Dwrite
|
||
*
|
||
* Purpose: Writes (part of) a DSET from application memory BUF to the
|
||
* file. The part of the dataset to write is defined with the
|
||
* MEM_SPACE_ID and FILE_SPACE_ID arguments. The data points
|
||
* are converted from their current type (MEM_TYPE_ID) to their
|
||
* file data type. Additional miscellaneous data transfer
|
||
* properties can be passed to this function with the
|
||
* PLIST_ID argument.
|
||
*
|
||
* The FILE_SPACE_ID can be the constant H5S_ALL which indicates
|
||
* that the entire file data space is to be referenced.
|
||
*
|
||
* The MEM_SPACE_ID can be the constant H5S_ALL in which case
|
||
* the memory data space is the same as the file data space
|
||
* defined when the dataset was created.
|
||
*
|
||
* The number of elements in the memory data space must match
|
||
* the number of elements in the file data space.
|
||
*
|
||
* The PLIST_ID can be the constant H5P_DEFAULT in which
|
||
* case the default data transfer properties are used.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Errors:
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, December 4, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id,
|
||
hid_t file_space_id, hid_t plist_id, const void *buf)
|
||
{
|
||
H5D_t *dset = NULL;
|
||
const H5T_t *mem_type = NULL;
|
||
const H5S_t *mem_space = NULL;
|
||
const H5S_t *file_space = NULL;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_API(H5Dwrite, FAIL);
|
||
H5TRACE6("e","iiiiix",dset_id,mem_type_id,mem_space_id,file_space_id,
|
||
plist_id,buf);
|
||
|
||
/* check arguments */
|
||
if (NULL == (dset = H5I_object_verify(dset_id, H5I_DATASET)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset");
|
||
if (NULL == dset->ent.file)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset");
|
||
if (NULL == (mem_type = H5I_object_verify(mem_type_id, H5I_DATATYPE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type");
|
||
if (H5S_ALL != mem_space_id) {
|
||
if (NULL == (mem_space = H5I_object_verify(mem_space_id, H5I_DATASPACE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
|
||
|
||
/* Check for valid selection */
|
||
if (H5S_select_valid(mem_space)!=TRUE)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent");
|
||
}
|
||
if (H5S_ALL != file_space_id) {
|
||
if (NULL == (file_space = H5I_object_verify(file_space_id, H5I_DATASPACE)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
|
||
|
||
/* Check for valid selection */
|
||
if (H5S_select_valid(file_space)!=TRUE)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent");
|
||
}
|
||
|
||
/* Get the default dataset transfer property list if the user didn't provide one */
|
||
if (H5P_DEFAULT == plist_id)
|
||
plist_id= H5P_DATASET_XFER_DEFAULT;
|
||
else
|
||
if (TRUE!=H5P_isa_class(plist_id,H5P_DATASET_XFER))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms");
|
||
if (!buf)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer");
|
||
|
||
/* write raw data */
|
||
if (H5D_write(dset, mem_type, mem_space, file_space, plist_id, buf) < 0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data");
|
||
|
||
done:
|
||
FUNC_LEAVE_API(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_read
|
||
*
|
||
* Purpose: Reads (part of) a DATASET into application memory BUF. See
|
||
* H5Dread() for complete details.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, December 4, 1997
|
||
*
|
||
* Modifications:
|
||
* Robb Matzke, 1998-06-09
|
||
* The data space is no longer cached in the dataset struct.
|
||
*
|
||
* Robb Matzke, 1998-08-11
|
||
* Added timing calls around all the data space I/O functions.
|
||
*
|
||
* rky, 1998-09-18
|
||
* Added must_convert to do non-optimized read when necessary.
|
||
*
|
||
* Quincey Koziol, 1999-07-02
|
||
* Changed xfer_parms parameter to xfer plist parameter, so it
|
||
* could be passed to H5T_convert.
|
||
*
|
||
* Albert Cheng, 2000-11-21
|
||
* Added the code that when it detects it is not safe to process a
|
||
* COLLECTIVE read request without hanging, it changes it to
|
||
* INDEPENDENT calls.
|
||
*
|
||
* Albert Cheng, 2000-11-27
|
||
* Changed to use the optimized MPIO transfer for Collective calls only.
|
||
*
|
||
* Raymond Lu, 2001-10-2
|
||
* Changed the way to retrieve property for generic property list.
|
||
*
|
||
* Raymond Lu, 2002-2-26
|
||
* For the new fill value design, data space can either be allocated
|
||
* or not allocated at this stage. Fill value or data from space is
|
||
* returned to outgoing buffer.
|
||
*
|
||
* QAK - 2002/04/02
|
||
* Removed the must_convert parameter and move preconditions to
|
||
* H5S_<foo>_opt_possible() routine
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_read(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, hid_t dxpl_id, void *buf/*out*/)
|
||
{
|
||
hssize_t snelmts; /*total number of elmts (signed) */
|
||
hsize_t nelmts; /*total number of elmts */
|
||
H5T_path_t *tpath = NULL; /*type conversion info */
|
||
hid_t src_id = -1, dst_id = -1;/*temporary type atoms */
|
||
H5S_conv_t *sconv=NULL; /*space conversion funcs*/
|
||
H5FD_mpio_xfer_t xfer_mode=H5FD_MPIO_INDEPENDENT; /*xfer_mode for this request */
|
||
hbool_t doing_mpio=0; /*This is an MPIO access */
|
||
H5P_genplist_t *dx_plist=NULL; /* Data transfer property list */
|
||
H5P_genplist_t *dc_plist; /* Dataset creation roperty list */
|
||
unsigned sconv_flags=0; /* Flags for the space conversion */
|
||
H5S_sel_type fsel_type; /* Selection type on disk */
|
||
H5S_sel_type msel_type; /* Selection type in memory */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_read);
|
||
|
||
/* check args */
|
||
assert(dataset && dataset->ent.file);
|
||
assert(mem_type);
|
||
assert(buf);
|
||
|
||
/* Get the dataset's creation property list */
|
||
if (NULL == (dc_plist = H5I_object(dataset->dcpl_id)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list");
|
||
|
||
/* Get the dataset transfer property list */
|
||
if (NULL == (dx_plist = H5I_object(dxpl_id)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list");
|
||
|
||
if (!file_space)
|
||
file_space = dataset->space;
|
||
if (!mem_space)
|
||
mem_space = file_space;
|
||
if((snelmts = H5S_get_select_npoints(mem_space))<0)
|
||
HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "src dataspace has invalid selection");
|
||
nelmts=snelmts;
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/* Collect Parallel I/O information for possible later use */
|
||
if (H5FD_MPIO==H5P_peek_hid_t(dx_plist,H5D_XFER_VFL_ID_NAME)) {
|
||
doing_mpio++;
|
||
xfer_mode=(H5FD_mpio_xfer_t)H5P_peek_unsigned(dx_plist, H5D_XFER_IO_XFER_MODE_NAME);
|
||
} /* end if */
|
||
/* Collective access is not permissible without the MPIO or MPIPOSIX driver */
|
||
if (doing_mpio && xfer_mode==H5FD_MPIO_COLLECTIVE &&
|
||
!(IS_H5FD_MPIO(dataset->ent.file) || IS_H5FD_MPIPOSIX(dataset->ent.file) || IS_H5FD_FPHDF5(dataset->ent.file)))
|
||
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPIO & MPIPOSIX drivers only");
|
||
|
||
/* Set the "parallel I/O possible" flag, for H5S_find() */
|
||
if (H5S_mpi_opt_types_g && IS_H5FD_MPIO(dataset->ent.file)) {
|
||
/* Only collective write should call this since it eventually
|
||
* calls MPI_File_set_view which is a collective call.
|
||
* See H5S_mpio_spaces_xfer() for details.
|
||
*/
|
||
if (doing_mpio && xfer_mode==H5FD_MPIO_COLLECTIVE)
|
||
sconv_flags |= H5S_CONV_PAR_IO_POSSIBLE;
|
||
} /* end if */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
/* Make certain that the number of elements in each selection is the same */
|
||
if (nelmts!=(hsize_t)H5S_get_select_npoints(file_space))
|
||
HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest data spaces have different sizes");
|
||
|
||
/* Retrieve dataset properties */
|
||
/* <none needed in the general case> */
|
||
|
||
/* 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->efl.nused==0 && dataset->layout.type!=H5D_COMPACT
|
||
&& dataset->layout.addr==HADDR_UNDEF) {
|
||
H5O_fill_t fill; /* Fill value info */
|
||
H5D_fill_time_t fill_time; /* When to write the fill values */
|
||
H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */
|
||
|
||
/* Retrieve dataset's fill-value properties */
|
||
if(H5P_fill_value_defined(dc_plist, &fill_status)<0)
|
||
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined");
|
||
if((fill_status==H5D_FILL_VALUE_DEFAULT || fill_status==H5D_FILL_VALUE_USER_DEFINED)
|
||
&& H5P_get(dc_plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,"can't retrieve fill value");
|
||
if(H5P_get(dc_plist, H5D_CRT_FILL_TIME_NAME, &fill_time) < 0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,"can't retrieve fill time");
|
||
|
||
/* Should be impossible, but check anyway... */
|
||
if(fill_status == H5D_FILL_VALUE_UNDEFINED && fill_time == H5D_FILL_TIME_ALLOC)
|
||
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(fill_time == H5D_FILL_TIME_NEVER)
|
||
HGOTO_DONE(SUCCEED);
|
||
|
||
/* Go fill the user's selection with the dataset's fill value */
|
||
if(H5D_fill(fill.buf,fill.type,buf,mem_type,mem_space, dxpl_id)<0) {
|
||
HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed");
|
||
} else
|
||
HGOTO_DONE(SUCCEED);
|
||
} /* end if */
|
||
|
||
/*
|
||
* Locate the type conversion function and data space conversion
|
||
* functions, and set up the element numbering information. If a data
|
||
* type conversion is necessary then register data type atoms. Data type
|
||
* conversion is necessary if the user has set the `need_bkg' to a high
|
||
* enough value in xfer_parms since turning off data type conversion also
|
||
* turns off background preservation.
|
||
*/
|
||
if (NULL==(tpath=H5T_path_find(dataset->type, mem_type, NULL, NULL, dxpl_id))) {
|
||
HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types");
|
||
} else if (!H5T_path_noop(tpath)) {
|
||
if ((src_id=H5I_register(H5I_DATATYPE, H5T_copy(dataset->type, H5T_COPY_ALL)))<0 ||
|
||
(dst_id=H5I_register(H5I_DATATYPE, H5T_copy(mem_type, H5T_COPY_ALL)))<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion");
|
||
} /* end if */
|
||
|
||
/* Set the storage flags for the space conversion check */
|
||
switch(dataset->layout.type) {
|
||
case H5D_COMPACT:
|
||
sconv_flags |= H5S_CONV_STORAGE_COMPACT;
|
||
break;
|
||
|
||
case H5D_CONTIGUOUS:
|
||
sconv_flags |= H5S_CONV_STORAGE_CONTIGUOUS;
|
||
break;
|
||
|
||
case H5D_CHUNKED:
|
||
sconv_flags |= H5S_CONV_STORAGE_CHUNKED;
|
||
break;
|
||
|
||
default:
|
||
assert(0 && "Unhandled layout type!");
|
||
} /* end switch */
|
||
|
||
/* Get dataspace functions */
|
||
if (NULL==(sconv=H5S_find(mem_space, file_space, sconv_flags)))
|
||
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert from file to memory data space");
|
||
|
||
/* Get type of selection on disk & in memory */
|
||
if((fsel_type=H5S_get_select_type(file_space))<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_BADSELECT, FAIL, "unable to convert from file to memory data space");
|
||
if((msel_type=H5S_get_select_type(mem_space))<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_BADSELECT, FAIL, "unable to convert from file to memory data space");
|
||
|
||
/* Determine correct I/O routine to invoke */
|
||
if((fsel_type==H5S_SEL_POINTS || msel_type==H5S_SEL_POINTS) ||
|
||
dataset->layout.type!=H5D_CHUNKED) {
|
||
/* Must use "contiguous" code for point selections,
|
||
* since order of I/O accesses can be different from that of the
|
||
* other kinds of selections
|
||
*/
|
||
if(H5D_contig_read(nelmts, dataset, mem_type, mem_space, file_space, tpath, sconv, dc_plist,
|
||
dx_plist, dxpl_id, doing_mpio, xfer_mode, src_id, dst_id, buf)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data");
|
||
} /* end if */
|
||
else {
|
||
if(H5D_chunk_read(nelmts, dataset, mem_type, mem_space, file_space, tpath, sconv, dc_plist,
|
||
dx_plist, dxpl_id, doing_mpio, xfer_mode, src_id, dst_id, buf)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data");
|
||
} /* end else */
|
||
|
||
done:
|
||
if (src_id >= 0)
|
||
H5I_dec_ref(src_id);
|
||
if (dst_id >= 0)
|
||
H5I_dec_ref(dst_id);
|
||
|
||
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.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, December 4, 1997
|
||
*
|
||
* Modifications:
|
||
* Robb Matzke, 9 Jun 1998
|
||
* The data space is no longer cached in the dataset struct.
|
||
*
|
||
* rky 980918
|
||
* Added must_convert to do non-optimized read when necessary.
|
||
*
|
||
* Quincey Koziol, 2 July 1999
|
||
* Changed xfer_parms parameter to xfer plist parameter, so it could
|
||
* be passed to H5T_convert
|
||
*
|
||
* Albert Cheng, 2000-11-21
|
||
* Added the code that when it detects it is not safe to process a
|
||
* COLLECTIVE write request without hanging, it changes it to
|
||
* INDEPENDENT calls.
|
||
*
|
||
* Albert Cheng, 2000-11-27
|
||
* Changed to use the optimized MPIO transfer for Collective calls only.
|
||
*
|
||
* Raymond Lu, 2001-10-2
|
||
* Changed the way to retrieve property for generic property list.
|
||
*
|
||
* Raymond Lu, 2002-2-26
|
||
* For the new fill value design, space may not be allocated until
|
||
* this function is called. Allocate and initialize space if it
|
||
* hasn't been.
|
||
*
|
||
* QAK - 2002/04/02
|
||
* Removed the must_convert parameter and move preconditions to
|
||
* H5S_<foo>_opt_possible() routine
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_write(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, hid_t dxpl_id, const void *buf)
|
||
{
|
||
hssize_t snelmts; /*total number of elmts (signed) */
|
||
hsize_t nelmts; /*total number of elmts */
|
||
H5T_path_t *tpath = NULL; /*type conversion info */
|
||
hid_t src_id = -1, dst_id = -1;/*temporary type atoms */
|
||
H5S_conv_t *sconv=NULL; /*space conversion funcs*/
|
||
H5FD_mpio_xfer_t xfer_mode=H5FD_MPIO_INDEPENDENT; /*xfer_mode for this request */
|
||
hbool_t doing_mpio=0; /*This is an MPIO access */
|
||
H5P_genplist_t *dx_plist=NULL; /* Data transfer property list */
|
||
H5P_genplist_t *dc_plist; /* Dataset creation roperty list */
|
||
unsigned sconv_flags=0; /* Flags for the space conversion */
|
||
H5S_sel_type fsel_type; /* Selection type on disk */
|
||
H5S_sel_type msel_type; /* Selection type in memory */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_write);
|
||
|
||
/* check args */
|
||
assert(dataset && dataset->ent.file);
|
||
assert(mem_type);
|
||
assert(buf);
|
||
|
||
/* If MPIO, MPIPOSIX, or FPHDF5 is used, no VL 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 ( (IS_H5FD_MPIO(dataset->ent.file) || IS_H5FD_MPIPOSIX(dataset->ent.file) || IS_H5FD_FPHDF5(dataset->ent.file)) &&
|
||
H5T_get_class(mem_type)==H5T_VLEN)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing VL datatypes yet");
|
||
/* If MPIO, MPIPOSIX, or FPHDF5 is used, no dataset 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 ((IS_H5FD_MPIO(dataset->ent.file) || IS_H5FD_MPIPOSIX(dataset->ent.file) || IS_H5FD_FPHDF5(dataset->ent.file)) &&
|
||
H5T_get_class(mem_type)==H5T_REFERENCE &&
|
||
H5T_get_ref_type(mem_type)==H5R_DATASET_REGION)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing region reference datatypes yet");
|
||
|
||
/* Check if we are allowed to write to this file */
|
||
if (0==(H5F_get_intent(dataset->ent.file) & H5F_ACC_RDWR))
|
||
HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file");
|
||
|
||
/* Get the dataset's creation property list */
|
||
if (NULL == (dc_plist = H5I_object(dataset->dcpl_id)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list");
|
||
|
||
/* Get the dataset transfer property list */
|
||
if (NULL == (dx_plist = H5I_object(dxpl_id)))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list");
|
||
|
||
if (!file_space)
|
||
file_space = dataset->space;
|
||
if (!mem_space)
|
||
mem_space = file_space;
|
||
if((snelmts = H5S_get_select_npoints(mem_space))<0)
|
||
HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "src dataspace has invalid selection");
|
||
nelmts=snelmts;
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/* Collect Parallel I/O information for possible later use */
|
||
if (H5FD_MPIO==H5P_peek_hid_t(dx_plist,H5D_XFER_VFL_ID_NAME)) {
|
||
doing_mpio++;
|
||
xfer_mode=(H5FD_mpio_xfer_t)H5P_peek_unsigned(dx_plist, H5D_XFER_IO_XFER_MODE_NAME);
|
||
} /* end if */
|
||
|
||
/* Collective access is not permissible without the MPIO or MPIPOSIX driver */
|
||
if (doing_mpio && xfer_mode==H5FD_MPIO_COLLECTIVE &&
|
||
!(IS_H5FD_MPIO(dataset->ent.file) || IS_H5FD_MPIPOSIX(dataset->ent.file) || IS_H5FD_FPHDF5(dataset->ent.file)))
|
||
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPIO driver only");
|
||
|
||
/* If dataset is compact, collective access is only allowed when file space
|
||
* selection is H5S_ALL */
|
||
if(doing_mpio && xfer_mode==H5FD_MPIO_COLLECTIVE
|
||
&& dataset->layout.type==H5D_COMPACT) {
|
||
if(H5S_get_select_type(file_space) != H5S_SEL_ALL)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access to compact dataset doesn't support partial access");
|
||
}
|
||
|
||
/* Set the "parallel I/O possible" flag, for H5S_find() */
|
||
if (H5S_mpi_opt_types_g && IS_H5FD_MPIO(dataset->ent.file)) {
|
||
/* Only collective write should call this since it eventually
|
||
* calls MPI_File_set_view which is a collective call.
|
||
* See H5S_mpio_spaces_xfer() for details.
|
||
*/
|
||
if (doing_mpio && xfer_mode==H5FD_MPIO_COLLECTIVE)
|
||
sconv_flags |= H5S_CONV_PAR_IO_POSSIBLE;
|
||
} /* end if */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
/* Make certain that the number of elements in each selection is the same */
|
||
if (nelmts!=(hsize_t)H5S_get_select_npoints(file_space))
|
||
HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest data spaces have different sizes");
|
||
|
||
/* Retrieve dataset properties */
|
||
/* <none needed currently> */
|
||
|
||
/* Allocate data space and initialize it if it hasn't been. */
|
||
if(nelmts > 0 && dataset->efl.nused==0 && dataset->layout.type!=H5D_COMPACT
|
||
&& dataset->layout.addr==HADDR_UNDEF) {
|
||
hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */
|
||
|
||
/* Get the number of elements in file dataset's dataspace */
|
||
if((file_nelmts=H5S_get_simple_extent_npoints(file_space))<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_BADVALUE, FAIL, "can't retrieve number of elements in file dataset");
|
||
|
||
/* Allocate storage */
|
||
if(H5D_alloc_storage(dataset->ent.file,dxpl_id,dataset,H5D_ALLOC_WRITE, TRUE, (hbool_t)((hsize_t)file_nelmts==nelmts ? TRUE : FALSE))<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage");
|
||
} /* end if */
|
||
|
||
/*
|
||
* Locate the type conversion function and data space conversion
|
||
* functions, and set up the element numbering information. If a data
|
||
* type conversion is necessary then register data type atoms. Data type
|
||
* conversion is necessary if the user has set the `need_bkg' to a high
|
||
* enough value in xfer_parms since turning off data type conversion also
|
||
* turns off background preservation.
|
||
*/
|
||
if (NULL==(tpath=H5T_path_find(mem_type, dataset->type, NULL, NULL, dxpl_id))) {
|
||
HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types");
|
||
} else if (!H5T_path_noop(tpath)) {
|
||
if ((src_id = H5I_register(H5I_DATATYPE, H5T_copy(mem_type, H5T_COPY_ALL)))<0 ||
|
||
(dst_id = H5I_register(H5I_DATATYPE, H5T_copy(dataset->type, H5T_COPY_ALL)))<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion");
|
||
} /* end if */
|
||
|
||
/* Set the storage flags for the space conversion check */
|
||
switch(dataset->layout.type) {
|
||
case H5D_COMPACT:
|
||
sconv_flags |= H5S_CONV_STORAGE_COMPACT;
|
||
break;
|
||
|
||
case H5D_CONTIGUOUS:
|
||
sconv_flags |= H5S_CONV_STORAGE_CONTIGUOUS;
|
||
break;
|
||
|
||
case H5D_CHUNKED:
|
||
sconv_flags |= H5S_CONV_STORAGE_CHUNKED;
|
||
break;
|
||
|
||
default:
|
||
assert(0 && "Unhandled layout type!");
|
||
} /* end switch */
|
||
|
||
/* Get dataspace functions */
|
||
if (NULL==(sconv=H5S_find(mem_space, file_space, sconv_flags)))
|
||
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert from memory to file data space");
|
||
|
||
/* Get type of selection on disk & in memory */
|
||
if((fsel_type=H5S_get_select_type(file_space))<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_BADSELECT, FAIL, "unable to convert from file to memory data space");
|
||
if((msel_type=H5S_get_select_type(mem_space))<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_BADSELECT, FAIL, "unable to convert from file to memory data space");
|
||
|
||
/* Determine correct I/O routine to invoke */
|
||
if((fsel_type==H5S_SEL_POINTS || msel_type==H5S_SEL_POINTS) ||
|
||
dataset->layout.type!=H5D_CHUNKED) {
|
||
/* Must use "contiguous" code for point selections,
|
||
* since order of I/O accesses can be different from that of the
|
||
* other kinds of selections
|
||
*/
|
||
if(H5D_contig_write(nelmts, dataset, mem_type, mem_space, file_space, tpath, sconv, dc_plist,
|
||
dx_plist, dxpl_id, doing_mpio, xfer_mode, src_id, dst_id, buf)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data");
|
||
} /* end if */
|
||
else {
|
||
if(H5D_chunk_write(nelmts, dataset, mem_type, mem_space, file_space, tpath, sconv, dc_plist,
|
||
dx_plist, dxpl_id, doing_mpio, xfer_mode, src_id, dst_id, buf)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data");
|
||
} /* end else */
|
||
|
||
/*
|
||
* Update modification time. We have to do this explicitly because
|
||
* writing to a dataset doesn't necessarily change the object header.
|
||
*/
|
||
if (H5O_touch(&(dataset->ent), FALSE, dxpl_id)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update modification time");
|
||
|
||
done:
|
||
if (src_id >= 0)
|
||
H5I_dec_ref(src_id);
|
||
if (dst_id >= 0)
|
||
H5I_dec_ref(dst_id);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5D_write() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_contig_read
|
||
*
|
||
* Purpose: Read from a contiguous dataset.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
* QAK - 2003/04/17
|
||
* Hacked on it a lot. :-)
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_contig_read(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
doing_mpio, H5FD_mpio_xfer_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
xfer_mode,
|
||
hid_t src_id, hid_t dst_id, void *buf/*out*/)
|
||
{
|
||
herr_t status; /*function return status*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_t timer;
|
||
#endif
|
||
size_t src_type_size; /*size of source type */
|
||
size_t dst_type_size; /*size of destination type*/
|
||
size_t target_size; /*desired buffer size */
|
||
hsize_t request_nelmts; /*requested strip mine */
|
||
H5S_sel_iter_t mem_iter; /*memory selection iteration info*/
|
||
hbool_t mem_iter_init=0; /*memory selection iteration info has been initialized */
|
||
H5S_sel_iter_t bkg_iter; /*background iteration info*/
|
||
hbool_t bkg_iter_init=0; /*background iteration info has been initialized */
|
||
H5S_sel_iter_t file_iter; /*file selection iteration info*/
|
||
hbool_t file_iter_init=0; /*file selection iteration info has been initialized */
|
||
H5T_bkg_t need_bkg; /*type of background buf*/
|
||
uint8_t *tconv_buf = NULL; /*data type conv buffer */
|
||
uint8_t *bkg_buf = NULL; /*background buffer */
|
||
hsize_t smine_start; /*strip mine start loc */
|
||
hsize_t n, smine_nelmts; /*elements per strip */
|
||
#ifdef H5_HAVE_PARALLEL
|
||
hbool_t xfer_mode_changed; /* Whether the transfer mode was changed */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
herr_t ret_value = SUCCEED; /*return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_contig_read);
|
||
|
||
/*
|
||
* If there is no type conversion then read directly into the
|
||
* application's buffer. This saves at least one mem-to-mem copy.
|
||
*/
|
||
if (H5T_path_noop(tpath)) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
/* Sanity check dataset, then read it */
|
||
assert(dataset->layout.addr!=HADDR_UNDEF || dataset->efl.nused>0 ||
|
||
dataset->layout.type==H5D_COMPACT);
|
||
status = (sconv->read)(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, (H5D_storage_t *)&(dataset->efl), H5T_get_size(dataset->type),
|
||
file_space, mem_space, dxpl_id, buf/*out*/);
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].read_timer), &timer);
|
||
sconv->stats[1].read_nbytes += nelmts * H5T_get_size(dataset->type);
|
||
sconv->stats[1].read_ncalls++;
|
||
#endif
|
||
|
||
/* Check return value from optimized read */
|
||
if (status<0) {
|
||
HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed");
|
||
} else
|
||
/* direct xfer accomplished successfully */
|
||
HGOTO_DONE(SUCCEED);
|
||
} /* end if */
|
||
|
||
/*
|
||
* This is the general case(type conversion).
|
||
*/
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
H5D_io_assist_mpio(dx_plist, doing_mpio, xfer_mode, &xfer_mode_changed);
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
/* Compute element sizes and other parameters */
|
||
src_type_size = H5T_get_size(dataset->type);
|
||
dst_type_size = H5T_get_size(mem_type);
|
||
target_size = H5P_peek_size_t(dx_plist,H5D_XFER_MAX_TEMP_BUF_NAME);
|
||
/* XXX: This could cause a problem if the user sets their buffer size
|
||
* to the same size as the default, and then the dataset elements are
|
||
* too large for the buffer... - QAK
|
||
*/
|
||
if(target_size==H5D_XFER_MAX_TEMP_BUF_DEF &&
|
||
target_size<MAX(src_type_size, dst_type_size))
|
||
target_size = MAX(src_type_size, dst_type_size);
|
||
request_nelmts = target_size / MAX(src_type_size, dst_type_size);
|
||
|
||
/* Sanity check elements in temporary buffer */
|
||
if (request_nelmts<=0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small");
|
||
|
||
/* Figure out the strip mine size. */
|
||
if (H5S_select_iter_init(&file_iter, file_space, src_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information");
|
||
file_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&mem_iter, mem_space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information");
|
||
mem_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&bkg_iter, mem_space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information");
|
||
bkg_iter_init=1; /*file selection iteration info has been initialized */
|
||
|
||
/*
|
||
* 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. The
|
||
* malloc() is usually less resource-intensive if we allocate/free the
|
||
* same size over and over.
|
||
*/
|
||
if (H5T_path_bkg(tpath)) {
|
||
/* Retrieve the bkgr buffer property */
|
||
if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &need_bkg)<0)
|
||
HGOTO_ERROR (H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer type");
|
||
need_bkg = MAX(H5T_path_bkg(tpath), need_bkg);
|
||
} else {
|
||
need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
|
||
} /* end else */
|
||
if (NULL==(tconv_buf=H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))) {
|
||
/* Allocate temporary buffer */
|
||
if((tconv_buf=H5FL_BLK_MALLOC(type_conv,target_size))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion");
|
||
} /* end if */
|
||
if (need_bkg && NULL==(bkg_buf=H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))) {
|
||
/* Allocate background buffer */
|
||
H5_CHECK_OVERFLOW((request_nelmts*dst_type_size),hsize_t,size_t);
|
||
if((bkg_buf=H5FL_BLK_MALLOC(type_conv,(size_t)(request_nelmts*dst_type_size)))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion");
|
||
} /* end if */
|
||
|
||
/* Start strip mining... */
|
||
for (smine_start=0; smine_start<nelmts; smine_start+=smine_nelmts) {
|
||
/* Go figure out how many elements to read from the file */
|
||
assert(H5S_select_iter_nelmts(&file_iter)==(nelmts-smine_start));
|
||
smine_nelmts = MIN(request_nelmts, (nelmts-smine_start));
|
||
|
||
/*
|
||
* Gather the data from disk into the data type conversion
|
||
* buffer. Also gather data from application to background buffer
|
||
* if necessary.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
/* Sanity check that space is allocated, then read data from it */
|
||
assert(dataset->layout.addr!=HADDR_UNDEF || dataset->efl.nused>0 ||
|
||
dataset->layout.type==H5D_COMPACT);
|
||
n = H5S_select_fgath(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, (H5D_storage_t *)&dataset->efl, src_type_size, file_space,
|
||
&file_iter, smine_nelmts, dxpl_id, tconv_buf/*out*/);
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].gath_timer), &timer);
|
||
sconv->stats[1].gath_nbytes += n * src_type_size;
|
||
sconv->stats[1].gath_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed");
|
||
|
||
if (need_bkg) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
n = H5S_select_mgath(buf, dst_type_size, mem_space, &bkg_iter,
|
||
smine_nelmts, dxpl_id, bkg_buf/*out*/);
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].bkg_timer), &timer);
|
||
sconv->stats[1].bkg_nbytes += n * dst_type_size;
|
||
sconv->stats[1].bkg_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR (H5E_IO, H5E_READERROR, FAIL, "mem gather failed");
|
||
} /* end if */
|
||
|
||
/*
|
||
* Perform data type conversion.
|
||
*/
|
||
if (H5T_convert(tpath, src_id, dst_id, smine_nelmts, 0, 0, tconv_buf, bkg_buf, dxpl_id)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "data type conversion failed");
|
||
|
||
/*
|
||
* Scatter the data into memory.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
status = H5S_select_mscat(tconv_buf, dst_type_size, mem_space,
|
||
&mem_iter, smine_nelmts, dxpl_id, buf/*out*/);
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].scat_timer), &timer);
|
||
sconv->stats[1].scat_nbytes += smine_nelmts * dst_type_size;
|
||
sconv->stats[1].scat_ncalls++;
|
||
#endif
|
||
if (status<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_READERROR, FAIL, "scatter failed");
|
||
|
||
} /* end for */
|
||
|
||
done:
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/* restore xfer_mode due to the kludge */
|
||
if (doing_mpio && xfer_mode_changed) {
|
||
#ifdef H5D_DEBUG
|
||
if (H5DEBUG(D))
|
||
fprintf (H5DEBUG(D), "H5D: dx->xfer_mode was COLLECTIVE, restored to INDEPENDENT\n");
|
||
#endif
|
||
xfer_mode = H5FD_MPIO_COLLECTIVE;
|
||
if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
|
||
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode");
|
||
} /* end if */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
/* Release selection iterators */
|
||
if(file_iter_init)
|
||
H5S_select_iter_release(&file_iter);
|
||
if(mem_iter_init)
|
||
H5S_select_iter_release(&mem_iter);
|
||
if(bkg_iter_init)
|
||
H5S_select_iter_release(&bkg_iter);
|
||
|
||
assert(dx_plist);
|
||
if (tconv_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,tconv_buf);
|
||
if (bkg_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,bkg_buf);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5D_contig_read() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_contig_write
|
||
*
|
||
* Purpose: Write to a contiguous dataset.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
* QAK - 2003/04/17
|
||
* Hacked on it a lot. :-)
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_contig_write(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
doing_mpio, H5FD_mpio_xfer_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
xfer_mode,
|
||
hid_t src_id, hid_t dst_id, const void *buf)
|
||
{
|
||
herr_t status; /*function return status*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_t timer;
|
||
#endif
|
||
size_t src_type_size; /*size of source type */
|
||
size_t dst_type_size; /*size of destination type*/
|
||
size_t target_size; /*desired buffer size */
|
||
hsize_t request_nelmts; /*requested strip mine */
|
||
H5S_sel_iter_t mem_iter; /*memory selection iteration info*/
|
||
hbool_t mem_iter_init=0; /*memory selection iteration info has been initialized */
|
||
H5S_sel_iter_t bkg_iter; /*background iteration info*/
|
||
hbool_t bkg_iter_init=0; /*background iteration info has been initialized */
|
||
H5S_sel_iter_t file_iter; /*file selection iteration info*/
|
||
hbool_t file_iter_init=0; /*file selection iteration info has been initialized */
|
||
H5T_bkg_t need_bkg; /*type of background buf*/
|
||
uint8_t *tconv_buf = NULL; /*data type conv buffer */
|
||
uint8_t *bkg_buf = NULL; /*background buffer */
|
||
hsize_t smine_start; /*strip mine start loc */
|
||
hsize_t n, smine_nelmts; /*elements per strip */
|
||
#ifdef H5_HAVE_PARALLEL
|
||
hbool_t xfer_mode_changed; /* Whether the transfer mode was changed */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
herr_t ret_value = SUCCEED; /*return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_contig_write);
|
||
|
||
/*
|
||
* If there is no type conversion then write directly from the
|
||
* application's buffer. This saves at least one mem-to-mem copy.
|
||
*/
|
||
if (H5T_path_noop(tpath)) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
status = (sconv->write)(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, (H5D_storage_t *)&(dataset->efl), H5T_get_size(dataset->type),
|
||
file_space, mem_space, dxpl_id, buf);
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[0].write_timer), &timer);
|
||
sconv->stats[0].write_nbytes += nelmts * H5T_get_size(mem_type);
|
||
sconv->stats[0].write_ncalls++;
|
||
#endif
|
||
|
||
/* Check return value from optimized write */
|
||
if (status<0) {
|
||
HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed");
|
||
} else
|
||
/* direct xfer accomplished successfully */
|
||
HGOTO_DONE(SUCCEED);
|
||
} /* end if */
|
||
|
||
/*
|
||
* This is the general case.
|
||
*/
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
H5D_io_assist_mpio(dx_plist, doing_mpio, xfer_mode, &xfer_mode_changed);
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
/* Compute element sizes and other parameters */
|
||
src_type_size = H5T_get_size(mem_type);
|
||
dst_type_size = H5T_get_size(dataset->type);
|
||
target_size = H5P_peek_size_t(dx_plist,H5D_XFER_MAX_TEMP_BUF_NAME);
|
||
/* XXX: This could cause a problem if the user sets their buffer size
|
||
* to the same size as the default, and then the dataset elements are
|
||
* too large for the buffer... - QAK
|
||
*/
|
||
if(target_size==H5D_XFER_MAX_TEMP_BUF_DEF &&
|
||
target_size<MAX(src_type_size, dst_type_size))
|
||
target_size = MAX(src_type_size, dst_type_size);
|
||
request_nelmts = target_size / MAX (src_type_size, dst_type_size);
|
||
|
||
/* Sanity check elements in temporary buffer */
|
||
if (request_nelmts<=0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small");
|
||
|
||
/* Figure out the strip mine size. */
|
||
if (H5S_select_iter_init(&file_iter, file_space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information");
|
||
file_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&mem_iter, mem_space, src_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information");
|
||
mem_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&bkg_iter, file_space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information");
|
||
bkg_iter_init=1; /*file selection iteration info has been initialized */
|
||
|
||
/*
|
||
* 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. The
|
||
* malloc() is usually less resource-intensive if we allocate/free the
|
||
* same size over and over.
|
||
*/
|
||
if (H5T_path_bkg(tpath)) {
|
||
/* Retrieve the bkgr buffer property */
|
||
if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &need_bkg)<0)
|
||
HGOTO_ERROR (H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer type");
|
||
need_bkg = MAX (H5T_path_bkg(tpath), need_bkg);
|
||
} else if(H5T_detect_class(dataset->type, H5T_VLEN)) {
|
||
/* Old data is retrieved into background buffer for VL datatype. The
|
||
* data is used later for freeing heap objects. */
|
||
need_bkg = H5T_BKG_YES;
|
||
} else {
|
||
need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
|
||
} /* end else */
|
||
if (NULL==(tconv_buf=H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))) {
|
||
/* Allocate temporary buffer */
|
||
if((tconv_buf=H5FL_BLK_MALLOC(type_conv,target_size))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion");
|
||
} /* end if */
|
||
if (need_bkg && NULL==(bkg_buf=H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))) {
|
||
/* Allocate background buffer */
|
||
H5_CHECK_OVERFLOW((request_nelmts*dst_type_size),hsize_t,size_t);
|
||
if((bkg_buf=H5FL_BLK_CALLOC(type_conv,(size_t)(request_nelmts*dst_type_size)))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion");
|
||
} /* end if */
|
||
|
||
/* Start strip mining... */
|
||
for (smine_start=0; smine_start<nelmts; smine_start+=smine_nelmts) {
|
||
/* Go figure out how many elements to read from the file */
|
||
assert(H5S_select_iter_nelmts(&file_iter)==(nelmts-smine_start));
|
||
smine_nelmts = MIN(request_nelmts, (nelmts-smine_start));
|
||
|
||
/*
|
||
* Gather data from application buffer into the data type conversion
|
||
* buffer. Also gather data from the file into the background buffer
|
||
* if necessary.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
n = H5S_select_mgath(buf, src_type_size, mem_space, &mem_iter,
|
||
smine_nelmts, dxpl_id, tconv_buf/*out*/);
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[0].gath_timer), &timer);
|
||
sconv->stats[0].gath_nbytes += n * src_type_size;
|
||
sconv->stats[0].gath_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed");
|
||
|
||
if (need_bkg) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
n = H5S_select_fgath(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, (H5D_storage_t *)&(dataset->efl), dst_type_size, file_space,
|
||
&bkg_iter, smine_nelmts, dxpl_id, bkg_buf/*out*/);
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[0].bkg_timer), &timer);
|
||
sconv->stats[0].bkg_nbytes += n * dst_type_size;
|
||
sconv->stats[0].bkg_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed");
|
||
} /* end if */
|
||
|
||
/*
|
||
* Perform data type conversion.
|
||
*/
|
||
if (H5T_convert(tpath, src_id, dst_id, smine_nelmts, 0, 0, tconv_buf, bkg_buf, dxpl_id)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "data type conversion failed");
|
||
|
||
/*
|
||
* Scatter the data out to the file.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
status = H5S_select_fscat(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, (H5D_storage_t *)&(dataset->efl), dst_type_size, file_space, &file_iter,
|
||
smine_nelmts, dxpl_id, tconv_buf);
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[0].scat_timer), &timer);
|
||
sconv->stats[0].scat_nbytes += smine_nelmts * dst_type_size;
|
||
sconv->stats[0].scat_ncalls++;
|
||
#endif
|
||
if (status<0)
|
||
HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "scatter failed");
|
||
} /* end for */
|
||
|
||
done:
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/* restore xfer_mode due to the kludge */
|
||
if (doing_mpio && xfer_mode_changed) {
|
||
#ifdef H5D_DEBUG
|
||
if (H5DEBUG(D))
|
||
fprintf (H5DEBUG(D), "H5D: dx->xfer_mode was COLLECTIVE, restored to INDEPENDENT\n");
|
||
#endif
|
||
xfer_mode = H5FD_MPIO_COLLECTIVE;
|
||
if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
|
||
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode");
|
||
} /* end if */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
/* Release selection iterators */
|
||
if(file_iter_init)
|
||
H5S_select_iter_release(&file_iter);
|
||
if(mem_iter_init)
|
||
H5S_select_iter_release(&mem_iter);
|
||
if(bkg_iter_init)
|
||
H5S_select_iter_release(&bkg_iter);
|
||
|
||
assert(dx_plist);
|
||
if (tconv_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,tconv_buf);
|
||
if (bkg_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,bkg_buf);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5D_contig_write() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_chunk_read
|
||
*
|
||
* Purpose: Read from a chunked dataset.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
* QAK - 2003/04/17
|
||
* Hacked on it a lot. :-)
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_chunk_read(hsize_t
|
||
#ifdef NDEBUG
|
||
UNUSED
|
||
#endif /* NDEBUG */
|
||
nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
doing_mpio, H5FD_mpio_xfer_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
xfer_mode, hid_t src_id, hid_t dst_id, void *buf/*out*/)
|
||
{
|
||
fm_map fm; /* File<->memory mapping */
|
||
H5TB_NODE *fchunk_node; /* Current node in file chunk TBBT */
|
||
H5TB_NODE *mchunk_node; /* Current node in memory chunk TBBT */
|
||
herr_t status; /*function return status*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_t timer;
|
||
#endif
|
||
size_t src_type_size; /*size of source type */
|
||
size_t dst_type_size; /*size of destination type*/
|
||
size_t target_size; /*desired buffer size */
|
||
hsize_t request_nelmts; /*requested strip mine */
|
||
hsize_t chunk_nelmts; /* Number of elements selected in current chunk */
|
||
hsize_t smine_start; /*strip mine start loc */
|
||
hsize_t n, smine_nelmts; /*elements per strip */
|
||
H5S_sel_iter_t mem_iter; /*memory selection iteration info*/
|
||
hbool_t mem_iter_init=0; /*memory selection iteration info has been initialized */
|
||
H5S_sel_iter_t bkg_iter; /*background iteration info*/
|
||
hbool_t bkg_iter_init=0; /*background iteration info has been initialized */
|
||
H5S_sel_iter_t file_iter; /*file selection iteration info*/
|
||
hbool_t file_iter_init=0; /*file selection iteration info has been initialized */
|
||
H5T_bkg_t need_bkg; /*type of background buf*/
|
||
uint8_t *tconv_buf = NULL; /*data type conv buffer */
|
||
uint8_t *bkg_buf = NULL; /*background buffer */
|
||
H5D_storage_t store; /*union of EFL and chunk pointer in file space */
|
||
#ifdef H5_HAVE_PARALLEL
|
||
hbool_t xfer_mode_changed; /* Whether the transfer mode was changed */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
herr_t ret_value = SUCCEED; /*return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_chunk_read);
|
||
|
||
/* Map elements between file and memory for each chunk*/
|
||
if(H5D_create_chunk_map(dataset, mem_type, file_space, mem_space, &fm)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't build chunk mapping");
|
||
|
||
/*
|
||
* If there is no type conversion then read directly into the
|
||
* application's buffer. This saves at least one mem-to-mem copy.
|
||
*/
|
||
if (H5T_path_noop(tpath)) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
/* Sanity check dataset, then read it */
|
||
assert(dataset->layout.addr!=HADDR_UNDEF || dataset->efl.nused>0 ||
|
||
dataset->layout.type==H5D_COMPACT);
|
||
|
||
/* Get first node in chunk trees */
|
||
fchunk_node=H5TB_first(fm.fsel->root);
|
||
mchunk_node=H5TB_first(fm.msel->root);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
|
||
/* Iterate through chunks to be operated on */
|
||
while(fchunk_node) {
|
||
H5D_fchunk_info_t *fchunk_info; /* File chunk information */
|
||
H5D_mchunk_info_t *mchunk_info; /* Memory chunk information */
|
||
|
||
/* Get the actual chunk information from the tree nodes */
|
||
fchunk_info=fchunk_node->data;
|
||
mchunk_info=mchunk_node->data;
|
||
|
||
#ifdef H5S_DEBUG
|
||
/* Get the number of elements selected in this chunk */
|
||
chunk_nelmts=H5S_get_select_npoints(fchunk_info->space);
|
||
assert(chunk_nelmts<=nelmts);
|
||
#endif /* H5S_DEBUG */
|
||
|
||
/* Pass in chunk's coordinates in a union. */
|
||
store.chunk_coords = fchunk_info->coords;
|
||
|
||
/* Perform the actual read operation */
|
||
status = (sconv->read)(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, &store, H5T_get_size(dataset->type),
|
||
fchunk_info->space, mchunk_info->space, dxpl_id, buf);
|
||
|
||
/* Check return value from optimized read */
|
||
if (status<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed");
|
||
|
||
/* Get the next chunk nodes in the trees */
|
||
fchunk_node=H5TB_next(fchunk_node);
|
||
mchunk_node=H5TB_next(mchunk_node);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
} /* end while */
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].read_timer), &timer);
|
||
sconv->stats[1].read_nbytes += nelmts * H5T_get_size(dataset->type);
|
||
sconv->stats[1].read_ncalls++;
|
||
#endif
|
||
|
||
/* direct xfer accomplished successfully */
|
||
HGOTO_DONE(SUCCEED);
|
||
} /* end if */
|
||
|
||
/*
|
||
* This is the general case(type conversion).
|
||
*/
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
H5D_io_assist_mpio(dx_plist, doing_mpio, xfer_mode, &xfer_mode_changed);
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
/* Compute element sizes and other parameters */
|
||
src_type_size = H5T_get_size(dataset->type);
|
||
dst_type_size = H5T_get_size(mem_type);
|
||
target_size = H5P_peek_size_t(dx_plist,H5D_XFER_MAX_TEMP_BUF_NAME);
|
||
/* XXX: This could cause a problem if the user sets their buffer size
|
||
* to the same size as the default, and then the dataset elements are
|
||
* too large for the buffer... - QAK
|
||
*/
|
||
if(target_size==H5D_XFER_MAX_TEMP_BUF_DEF &&
|
||
target_size<MAX(src_type_size, dst_type_size))
|
||
target_size = MAX(src_type_size, dst_type_size);
|
||
request_nelmts = target_size / MAX (src_type_size, dst_type_size);
|
||
|
||
/* Sanity check elements in temporary buffer */
|
||
if (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. The
|
||
* malloc() is usually less resource-intensive if we allocate/free the
|
||
* same size over and over.
|
||
*/
|
||
if (H5T_path_bkg(tpath)) {
|
||
/* Retrieve the bkgr buffer property */
|
||
if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &need_bkg)<0)
|
||
HGOTO_ERROR (H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer type");
|
||
need_bkg = MAX(H5T_path_bkg(tpath), need_bkg);
|
||
} else {
|
||
need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
|
||
} /* end else */
|
||
if (NULL==(tconv_buf=H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))) {
|
||
/* Allocate temporary buffer */
|
||
if((tconv_buf=H5FL_BLK_MALLOC(type_conv,target_size))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion");
|
||
} /* end if */
|
||
if (need_bkg && NULL==(bkg_buf=H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))) {
|
||
/* Allocate background buffer */
|
||
H5_CHECK_OVERFLOW((request_nelmts*dst_type_size),hsize_t,size_t);
|
||
if((bkg_buf=H5FL_BLK_MALLOC(type_conv,(size_t)(request_nelmts*dst_type_size)))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion");
|
||
} /* end if */
|
||
|
||
/* Loop over all the chunks, performing I/O on each */
|
||
|
||
/* Get first node in chunk trees */
|
||
fchunk_node=H5TB_first(fm.fsel->root);
|
||
mchunk_node=H5TB_first(fm.msel->root);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
|
||
/* Iterate through chunks to be operated on */
|
||
while(fchunk_node) {
|
||
H5D_fchunk_info_t *fchunk_info; /* File chunk information */
|
||
H5D_mchunk_info_t *mchunk_info; /* Memory chunk information */
|
||
|
||
/* Get the actual chunk information from the tree nodes */
|
||
fchunk_info=fchunk_node->data;
|
||
mchunk_info=mchunk_node->data;
|
||
|
||
/* Get the number of elements selected in this chunk */
|
||
chunk_nelmts=H5S_get_select_npoints(fchunk_info->space);
|
||
assert(chunk_nelmts<=nelmts);
|
||
|
||
/* initialize selection iterator */
|
||
if (H5S_select_iter_init(&file_iter, fchunk_info->space, src_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information");
|
||
file_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&mem_iter, mchunk_info->space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information");
|
||
mem_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&bkg_iter, mchunk_info->space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information");
|
||
bkg_iter_init=1; /*file selection iteration info has been initialized */
|
||
|
||
/* Pass in chunk's coordinates in a union*/
|
||
store.chunk_coords = fchunk_info->coords;
|
||
|
||
for (smine_start=0; smine_start<chunk_nelmts; smine_start+=smine_nelmts) {
|
||
/* Go figure out how many elements to read from the file */
|
||
assert(H5S_select_iter_nelmts(&file_iter)==(chunk_nelmts-smine_start));
|
||
smine_nelmts = MIN(request_nelmts, (chunk_nelmts-smine_start));
|
||
|
||
/*
|
||
* Gather the data from disk into the data type conversion
|
||
* buffer. Also gather data from application to background buffer
|
||
* if necessary.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
/* Sanity check that space is allocated, then read data from it */
|
||
assert(dataset->layout.addr!=HADDR_UNDEF || dataset->efl.nused>0 ||
|
||
dataset->layout.type==H5D_COMPACT);
|
||
n = H5S_select_fgath(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, &store, src_type_size, fchunk_info->space,
|
||
&file_iter, smine_nelmts, dxpl_id, tconv_buf/*out*/);
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].gath_timer), &timer);
|
||
sconv->stats[1].gath_nbytes += n * src_type_size;
|
||
sconv->stats[1].gath_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed");
|
||
|
||
if (need_bkg) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
n = H5S_select_mgath(buf, dst_type_size, mchunk_info->space, &bkg_iter,
|
||
smine_nelmts, dxpl_id, bkg_buf/*out*/);
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].bkg_timer), &timer);
|
||
sconv->stats[1].bkg_nbytes += n * dst_type_size;
|
||
sconv->stats[1].bkg_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR (H5E_IO, H5E_READERROR, FAIL, "mem gather failed");
|
||
} /* end if */
|
||
|
||
/*
|
||
* Perform data type conversion.
|
||
*/
|
||
if (H5T_convert(tpath, src_id, dst_id, smine_nelmts, 0, 0,
|
||
tconv_buf, bkg_buf, dxpl_id)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "data type conversion failed");
|
||
|
||
/*
|
||
* Scatter the data into memory.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
status = H5S_select_mscat(tconv_buf, dst_type_size, mchunk_info->space,
|
||
&mem_iter, smine_nelmts, dxpl_id, buf/*out*/);
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].scat_timer), &timer);
|
||
sconv->stats[1].scat_nbytes += smine_nelmts * dst_type_size;
|
||
sconv->stats[1].scat_ncalls++;
|
||
#endif
|
||
if (status<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_READERROR, FAIL, "scatter failed");
|
||
} /* end for */
|
||
|
||
/* Release selection iterators */
|
||
if(file_iter_init) {
|
||
H5S_select_iter_release(&file_iter);
|
||
file_iter_init=0;
|
||
} /* end if */
|
||
if(mem_iter_init) {
|
||
H5S_select_iter_release(&mem_iter);
|
||
mem_iter_init=0;
|
||
} /* end if */
|
||
if(bkg_iter_init) {
|
||
H5S_select_iter_release(&bkg_iter);
|
||
bkg_iter_init=0;
|
||
} /* end if */
|
||
|
||
/* Get the next chunk nodes in the trees */
|
||
fchunk_node=H5TB_next(fchunk_node);
|
||
mchunk_node=H5TB_next(mchunk_node);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
} /* end while */
|
||
|
||
done:
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/* restore xfer_mode due to the kludge */
|
||
if (doing_mpio && xfer_mode_changed) {
|
||
#ifdef H5D_DEBUG
|
||
if (H5DEBUG(D))
|
||
fprintf (H5DEBUG(D), "H5D: dx->xfer_mode was COLLECTIVE, restored to INDEPENDENT\n");
|
||
#endif
|
||
xfer_mode = H5FD_MPIO_COLLECTIVE;
|
||
if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
|
||
HDONE_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode");
|
||
} /* end if */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
assert(dx_plist);
|
||
if (tconv_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,tconv_buf);
|
||
if (bkg_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,bkg_buf);
|
||
|
||
/* Release selection iterators, if necessary */
|
||
if(file_iter_init)
|
||
H5S_select_iter_release(&file_iter);
|
||
if(mem_iter_init)
|
||
H5S_select_iter_release(&mem_iter);
|
||
if(bkg_iter_init)
|
||
H5S_select_iter_release(&bkg_iter);
|
||
|
||
/* Release chunk mapping information */
|
||
if(H5D_destroy_chunk_map(&fm) < 0)
|
||
HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't release chunk mapping");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* H5D_chunk_read() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_chunk_write
|
||
*
|
||
* Purpose: Writes to a chunked dataset.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
* QAK - 2003/04/17
|
||
* Hacked on it a lot. :-)
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_chunk_write(hsize_t
|
||
#ifdef NDEBUG
|
||
UNUSED
|
||
#endif /* NDEBUG */
|
||
nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
|
||
const H5S_t *file_space, H5T_path_t *tpath, H5S_conv_t *sconv, H5P_genplist_t *dc_plist,
|
||
H5P_genplist_t *dx_plist, hid_t dxpl_id, hbool_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
doing_mpio, H5FD_mpio_xfer_t
|
||
#ifndef H5_HAVE_PARALLEL
|
||
UNUSED
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
xfer_mode, hid_t src_id, hid_t dst_id, const void *buf)
|
||
{
|
||
fm_map fm; /* File<->memory mapping */
|
||
H5TB_NODE *fchunk_node; /* Current node in file chunk TBBT */
|
||
H5TB_NODE *mchunk_node; /* Current node in memory chunk TBBT */
|
||
herr_t status; /*function return status*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_t timer;
|
||
#endif
|
||
size_t src_type_size; /*size of source type */
|
||
size_t dst_type_size; /*size of destination type*/
|
||
size_t target_size; /*desired buffer size */
|
||
hsize_t request_nelmts; /*requested strip mine */
|
||
hsize_t chunk_nelmts; /* Number of elements selected in current chunk */
|
||
hsize_t smine_start; /*strip mine start loc */
|
||
hsize_t n, smine_nelmts; /*elements per strip */
|
||
H5S_sel_iter_t mem_iter; /*memory selection iteration info*/
|
||
hbool_t mem_iter_init=0; /*memory selection iteration info has been initialized */
|
||
H5S_sel_iter_t bkg_iter; /*background iteration info*/
|
||
hbool_t bkg_iter_init=0; /*background iteration info has been initialized */
|
||
H5S_sel_iter_t file_iter; /*file selection iteration info*/
|
||
hbool_t file_iter_init=0; /*file selection iteration info has been initialized */
|
||
H5T_bkg_t need_bkg; /*type of background buf*/
|
||
uint8_t *tconv_buf = NULL; /*data type conv buffer */
|
||
uint8_t *bkg_buf = NULL; /*background buffer */
|
||
H5D_storage_t store; /*union of EFL and chunk pointer in file space */
|
||
#ifdef H5_HAVE_PARALLEL
|
||
hbool_t xfer_mode_changed; /* Whether the transfer mode was changed */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
herr_t ret_value = SUCCEED; /*return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_chunk_write);
|
||
|
||
/* Map elements between file and memory for each chunk*/
|
||
if(H5D_create_chunk_map(dataset, mem_type, file_space, mem_space, &fm)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't build chunk mapping");
|
||
|
||
/*
|
||
* If there is no type conversion then write directly from the
|
||
* application's buffer. This saves at least one mem-to-mem copy.
|
||
*/
|
||
if (H5T_path_noop(tpath)) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
/* Get first node in chunk trees */
|
||
fchunk_node=H5TB_first(fm.fsel->root);
|
||
mchunk_node=H5TB_first(fm.msel->root);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
|
||
/* Iterate through chunks to be operated on */
|
||
while(fchunk_node) {
|
||
H5D_fchunk_info_t *fchunk_info; /* File chunk information */
|
||
H5D_mchunk_info_t *mchunk_info; /* Memory chunk information */
|
||
|
||
/* Get the actual chunk information from the tree nodes */
|
||
fchunk_info=fchunk_node->data;
|
||
mchunk_info=mchunk_node->data;
|
||
|
||
#ifdef H5S_DEBUG
|
||
/* Get the number of elements selected in this chunk */
|
||
chunk_nelmts=H5S_get_select_npoints(fchunk_info->space);
|
||
assert(chunk_nelmts<=nelmts);
|
||
#endif /* H5S_DEBUG */
|
||
|
||
/* Pass in chunk's coordinates in a union. */
|
||
store.chunk_coords = fchunk_info->coords;
|
||
|
||
/* Perform the actual write operation */
|
||
status = (sconv->write)(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, &store, H5T_get_size(dataset->type),
|
||
fchunk_info->space, mchunk_info->space, dxpl_id, buf);
|
||
|
||
/* Check return value from optimized write */
|
||
if (status<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed");
|
||
|
||
/* Get the next chunk nodes in the trees */
|
||
fchunk_node=H5TB_next(fchunk_node);
|
||
mchunk_node=H5TB_next(mchunk_node);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
} /* end while */
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[0].write_timer), &timer);
|
||
sconv->stats[0].write_nbytes += nelmts * H5T_get_size(mem_type);
|
||
sconv->stats[0].write_ncalls++;
|
||
#endif
|
||
|
||
/* direct xfer accomplished successfully */
|
||
HGOTO_DONE(SUCCEED);
|
||
} /* end if */
|
||
|
||
/*
|
||
* This is the general case(type conversion).
|
||
*/
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
H5D_io_assist_mpio(dx_plist, doing_mpio, xfer_mode, &xfer_mode_changed);
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
/* Compute element sizes and other parameters */
|
||
src_type_size = H5T_get_size(mem_type);
|
||
dst_type_size = H5T_get_size(dataset->type);
|
||
target_size = H5P_peek_size_t(dx_plist,H5D_XFER_MAX_TEMP_BUF_NAME);
|
||
/* XXX: This could cause a problem if the user sets their buffer size
|
||
* to the same size as the default, and then the dataset elements are
|
||
* too large for the buffer... - QAK
|
||
*/
|
||
if(target_size==H5D_XFER_MAX_TEMP_BUF_DEF &&
|
||
target_size<MAX(src_type_size, dst_type_size))
|
||
target_size = MAX(src_type_size, dst_type_size);
|
||
request_nelmts = target_size / MAX (src_type_size, dst_type_size);
|
||
|
||
/* Sanity check elements in temporary buffer */
|
||
if (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. The
|
||
* malloc() is usually less resource-intensive if we allocate/free the
|
||
* same size over and over.
|
||
*/
|
||
if (H5T_path_bkg(tpath)) {
|
||
/* Retrieve the bkgr buffer property */
|
||
if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &need_bkg)<0)
|
||
HGOTO_ERROR (H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer type");
|
||
need_bkg = MAX (H5T_path_bkg(tpath), need_bkg);
|
||
} else if(H5T_detect_class(dataset->type, H5T_VLEN)) {
|
||
/* Old data is retrieved into background buffer for VL datatype. The
|
||
* data is used later for freeing heap objects. */
|
||
need_bkg = H5T_BKG_YES;
|
||
} else {
|
||
need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
|
||
} /* end else */
|
||
if (NULL==(tconv_buf=H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))) {
|
||
/* Allocate temporary buffer */
|
||
if((tconv_buf=H5FL_BLK_MALLOC(type_conv,target_size))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion");
|
||
} /* end if */
|
||
if (need_bkg && NULL==(bkg_buf=H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))) {
|
||
/* Allocate background buffer */
|
||
H5_CHECK_OVERFLOW((request_nelmts*dst_type_size),hsize_t,size_t);
|
||
if((bkg_buf=H5FL_BLK_CALLOC(type_conv,(size_t)(request_nelmts*dst_type_size)))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion");
|
||
} /* end if */
|
||
|
||
/* Loop over all the chunks, performing I/O on each */
|
||
|
||
/* Get first node in chunk trees */
|
||
fchunk_node=H5TB_first(fm.fsel->root);
|
||
mchunk_node=H5TB_first(fm.msel->root);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
|
||
/* Iterate through chunks to be operated on */
|
||
while(fchunk_node) {
|
||
H5D_fchunk_info_t *fchunk_info; /* File chunk information */
|
||
H5D_mchunk_info_t *mchunk_info; /* Memory chunk information */
|
||
|
||
/* Get the actual chunk information from the tree nodes */
|
||
fchunk_info=fchunk_node->data;
|
||
mchunk_info=mchunk_node->data;
|
||
|
||
/* Get the number of elements selected in this chunk */
|
||
chunk_nelmts=H5S_get_select_npoints(fchunk_info->space);
|
||
assert(chunk_nelmts<=nelmts);
|
||
|
||
/* initialize selection iterator */
|
||
if (H5S_select_iter_init(&file_iter, fchunk_info->space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information");
|
||
file_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&mem_iter, mchunk_info->space, src_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information");
|
||
mem_iter_init=1; /*file selection iteration info has been initialized */
|
||
if (H5S_select_iter_init(&bkg_iter, fchunk_info->space, dst_type_size)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information");
|
||
bkg_iter_init=1; /*file selection iteration info has been initialized */
|
||
|
||
/*pass in chunk's coordinates in a union*/
|
||
store.chunk_coords = fchunk_info->coords;
|
||
|
||
for (smine_start=0; smine_start<chunk_nelmts; smine_start+=smine_nelmts) {
|
||
/* Go figure out how many elements to read from the file */
|
||
assert(H5S_select_iter_nelmts(&file_iter)==(chunk_nelmts-smine_start));
|
||
smine_nelmts = MIN(request_nelmts, (chunk_nelmts-smine_start));
|
||
|
||
/*
|
||
* Gather the data from disk into the data type conversion
|
||
* buffer. Also gather data from application to background buffer
|
||
* if necessary.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
n = H5S_select_mgath(buf, src_type_size, mchunk_info->space, &mem_iter,
|
||
smine_nelmts, dxpl_id, tconv_buf/*out*/);
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[1].gath_timer), &timer);
|
||
sconv->stats[1].gath_nbytes += n * src_type_size;
|
||
sconv->stats[1].gath_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed");
|
||
|
||
if (need_bkg) {
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
n = H5S_select_fgath(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, &store, dst_type_size, fchunk_info->space,
|
||
&bkg_iter, smine_nelmts, dxpl_id, bkg_buf/*out*/);
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[0].bkg_timer), &timer);
|
||
sconv->stats[0].bkg_nbytes += n * dst_type_size;
|
||
sconv->stats[0].bkg_ncalls++;
|
||
#endif
|
||
if (n!=smine_nelmts)
|
||
HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed");
|
||
} /* end if */
|
||
|
||
/*
|
||
* Perform data type conversion.
|
||
*/
|
||
if (H5T_convert(tpath, src_id, dst_id, smine_nelmts, 0, 0,
|
||
tconv_buf, bkg_buf, dxpl_id)<0)
|
||
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "data type conversion failed");
|
||
|
||
/*
|
||
* Scatter the data out to the file.
|
||
*/
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_begin(&timer);
|
||
#endif
|
||
status = H5S_select_fscat(dataset->ent.file, &(dataset->layout),
|
||
dc_plist, &store, dst_type_size, fchunk_info->space,
|
||
&file_iter, smine_nelmts, dxpl_id, tconv_buf);
|
||
|
||
#ifdef H5S_DEBUG
|
||
H5_timer_end(&(sconv->stats[0].scat_timer), &timer);
|
||
sconv->stats[0].scat_nbytes += n * dst_type_size;
|
||
sconv->stats[0].scat_ncalls++;
|
||
#endif
|
||
if (status<0)
|
||
HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "scatter failed");
|
||
} /* end for */
|
||
|
||
/* Release selection iterators */
|
||
if(file_iter_init) {
|
||
H5S_select_iter_release(&file_iter);
|
||
file_iter_init=0;
|
||
} /* end if */
|
||
if(mem_iter_init) {
|
||
H5S_select_iter_release(&mem_iter);
|
||
mem_iter_init=0;
|
||
} /* end if */
|
||
if(bkg_iter_init) {
|
||
H5S_select_iter_release(&bkg_iter);
|
||
bkg_iter_init=0;
|
||
} /* end if */
|
||
|
||
/* Get the next chunk nodes in the trees */
|
||
fchunk_node=H5TB_next(fchunk_node);
|
||
mchunk_node=H5TB_next(mchunk_node);
|
||
|
||
/* Sanity check that we either have both file & memory chunk information
|
||
* or _don't_ have both file & memory chunk information
|
||
* (i.e. don't run out of one kind of chunk before the other)
|
||
*/
|
||
assert((fchunk_node && mchunk_node) || (!fchunk_node && !mchunk_node));
|
||
} /* end while */
|
||
|
||
done:
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/* restore xfer_mode due to the kludge */
|
||
if (doing_mpio && xfer_mode_changed) {
|
||
#ifdef H5D_DEBUG
|
||
if (H5DEBUG(D))
|
||
fprintf (H5DEBUG(D), "H5D: dx->xfer_mode was COLLECTIVE, restored to INDEPENDENT\n");
|
||
#endif
|
||
xfer_mode = H5FD_MPIO_COLLECTIVE;
|
||
if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
|
||
HDONE_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode");
|
||
} /* end if */
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
assert(dx_plist);
|
||
if (tconv_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_TCONV_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,tconv_buf);
|
||
if (bkg_buf && NULL==H5P_peek_voidp(dx_plist,H5D_XFER_BKGR_BUF_NAME))
|
||
H5FL_BLK_FREE(type_conv,bkg_buf);
|
||
|
||
/* Release selection iterators, if necessary */
|
||
if(file_iter_init)
|
||
H5S_select_iter_release(&file_iter);
|
||
if(mem_iter_init)
|
||
H5S_select_iter_release(&mem_iter);
|
||
if(bkg_iter_init)
|
||
H5S_select_iter_release(&bkg_iter);
|
||
|
||
/* Release chunk mapping information */
|
||
if(H5D_destroy_chunk_map(&fm) < 0)
|
||
HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't release chunk mapping");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* H5D_chunk_write() */
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_io_assist_mpio
|
||
*
|
||
* Purpose: Common logic for determining if the MPI transfer mode should
|
||
* be changed.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
* QAK - 2003/04/17
|
||
* Hacked on it a lot. :-)
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_io_assist_mpio(H5P_genplist_t *dx_plist, hbool_t doing_mpio, H5FD_mpio_xfer_t xfer_mode,
|
||
hbool_t *xfer_mode_changed)
|
||
{
|
||
herr_t ret_value = SUCCEED; /*return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_io_assist_mpio);
|
||
|
||
/* The following may not handle a collective call correctly
|
||
* since it does not ensure all processes can handle the write
|
||
* request according to the MPI collective specification.
|
||
* Do the collective request via independent mode.
|
||
*/
|
||
if (doing_mpio && xfer_mode==H5FD_MPIO_COLLECTIVE) {
|
||
/* Kludge: change the xfer_mode to independent, handle the request,
|
||
* then xfer_mode before return.
|
||
* Better way is to get a temporary data_xfer property with
|
||
* INDEPENDENT xfer_mode and pass it downwards.
|
||
*/
|
||
xfer_mode = H5FD_MPIO_INDEPENDENT;
|
||
if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
|
||
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode");
|
||
*xfer_mode_changed=TRUE; /* restore it before return */
|
||
#ifdef H5D_DEBUG
|
||
if (H5DEBUG(D))
|
||
fprintf(H5DEBUG(D), "H5D: Cannot handle this COLLECTIVE write request. Do it via INDEPENDENT calls\n");
|
||
#endif
|
||
} /* end if */
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
#endif /*H5_HAVE_PARALLEL*/
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_chunk_coords_assist
|
||
*
|
||
* Purpose: Compute the coords for a particular chunk (in CHUNK_IDX),
|
||
* based on the size of the dataset's dataspace (given in
|
||
* NDIMS and CHUNKS), putting the resulting chunk's coordinate
|
||
* offsets in the COORDS array.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_chunk_coords_assist(hssize_t *coords, size_t ndims, hsize_t chunks[], hsize_t chunk_idx)
|
||
{
|
||
hsize_t tmp; /* Size of "down elements" in each dimension */
|
||
size_t i, j; /* Local index variables */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_chunk_coords_assist);
|
||
|
||
for(i=0; i<ndims; i++) {
|
||
tmp=1;
|
||
for(j=i+1; j<ndims; j++)
|
||
tmp *= chunks[j];
|
||
coords[i] = (hssize_t)(chunk_idx / tmp);
|
||
chunk_idx = chunk_idx % tmp;
|
||
}
|
||
coords[ndims] = 0;
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_create_chunk_map
|
||
*
|
||
* Purpose: Creates the mapping between elements selected in each chunk
|
||
* and the elements in the memory selection.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
* QAK - 2003/04/17
|
||
* Hacked on it a lot. :-)
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_create_chunk_map(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *file_space,
|
||
const H5S_t *mem_space, fm_map *fm)
|
||
{
|
||
H5S_t *tmp_fspace=NULL, /* Temporary file dataspace */
|
||
*tmp_mspace=NULL; /* Temporary memory dataspace */
|
||
hid_t f_tid=(-1); /* Temporary copy of file datatype for iteration */
|
||
size_t elmt_size; /* Memory datatype size */
|
||
hbool_t iter_init=0; /* Selection iteration info has been initialized */
|
||
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) */
|
||
hsize_t f_dims[H5O_LAYOUT_NDIMS]; /* Dimensionality of file dataspace */
|
||
hsize_t nchunks, last_nchunks; /* Number of chunks in dataset */
|
||
H5TB_NODE *curr_node; /* Current node in TBBT */
|
||
char bogus; /* "bogus" buffer to pass to selection iterator */
|
||
unsigned u; /* Local index variable */
|
||
herr_t ret_value = SUCCEED; /*return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_create_chunk_map);
|
||
|
||
/* Initialize fm_map structure */
|
||
HDmemset(fm, 0, sizeof(fm_map));
|
||
|
||
/* Get layout for dataset */
|
||
fm->layout = &(dataset->layout);
|
||
|
||
/* Create a file space of a chunk's size, instead of whole file space*/
|
||
if(NULL==(tmp_fspace=H5S_create_simple((dataset->layout.ndims-1),dataset->layout.dim,NULL)))
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace");
|
||
|
||
/*make a copy of mem_space*/
|
||
if((tmp_mspace = H5S_copy(mem_space))==NULL)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space");
|
||
|
||
/*de-select the file space and mem space copies*/
|
||
if(H5S_select_none(tmp_fspace)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select file space");
|
||
if(H5S_select_none(tmp_mspace)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select memory space");
|
||
|
||
/* Get dim number and dimensionality for each dataspace */
|
||
fm->f_ndims=f_ndims=dataset->layout.ndims-1;
|
||
if((sm_ndims = H5S_get_simple_extent_ndims(tmp_mspace))<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number");
|
||
fm->m_ndims=sm_ndims;
|
||
|
||
if(H5S_get_simple_extent_dims(file_space, f_dims, NULL)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality");
|
||
|
||
/* Decide the number of chunks in each dimension*/
|
||
last_nchunks=0;
|
||
nchunks=1;
|
||
for(u=0; u<f_ndims; u++) {
|
||
fm->chunks[u] = ((f_dims[u]+dataset->layout.dim[u])-1) / dataset->layout.dim[u];
|
||
|
||
/* Track total number of chunks in dataset */
|
||
nchunks *= fm->chunks[u];
|
||
|
||
/* Check if the chunk indices will overflow */
|
||
if(nchunks<last_nchunks)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_OVERFLOW, FAIL, "too many chunks");
|
||
last_nchunks=nchunks;
|
||
} /* end for */
|
||
|
||
/* Compute the "down" size of 'chunks' information */
|
||
if(H5V_array_down(f_ndims,fm->chunks,fm->down_chunks)<0)
|
||
HGOTO_ERROR (H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute 'down' sizes");
|
||
|
||
/* Initialize TBBT's for file & memory chunk selections */
|
||
if((fm->fsel=H5TB_fast_dmake(H5TB_FAST_HSIZE_COMPARE))==NULL)
|
||
HGOTO_ERROR(H5E_DATASET,H5E_CANTMAKETREE,FAIL,"can't create TBBT for file chunk selections");
|
||
if((fm->msel=H5TB_fast_dmake(H5TB_FAST_HSIZE_COMPARE))==NULL)
|
||
HGOTO_ERROR(H5E_DATASET,H5E_CANTMAKETREE,FAIL,"can't create TBBT for memory chunk selections");
|
||
|
||
/* Save chunk template information */
|
||
fm->fchunk_tmpl=tmp_fspace;
|
||
fm->mchunk_tmpl=tmp_mspace;
|
||
|
||
/* Initialize "last chunk" information */
|
||
fm->last_index=(hsize_t)-1;
|
||
fm->last_fchunk=fm->last_mchunk=NULL;
|
||
|
||
/* Create temporary datatypes for selection iteration */
|
||
if((f_tid = H5I_register(H5I_DATATYPE, H5T_copy(dataset->type, H5T_COPY_ALL)))<0)
|
||
HGOTO_ERROR (H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register file datatype");
|
||
|
||
/* Create selection iterator for memory selection */
|
||
if((elmt_size=H5T_get_size(mem_type))==0)
|
||
HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "datatype size invalid");
|
||
if (H5S_select_iter_init(&(fm->mem_iter), mem_space, elmt_size)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator");
|
||
iter_init=1; /* Selection iteration info has been initialized */
|
||
|
||
/* Build the file & memory selection for each chunk */
|
||
if(H5S_select_iterate(&bogus, f_tid, file_space, H5D_chunk_cb, fm)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to iterate file space");
|
||
|
||
/* Clean file chunks' hyperslab span "scratch" information */
|
||
curr_node=H5TB_first(fm->fsel->root);
|
||
while(curr_node) {
|
||
H5D_fchunk_info_t *chunk_info; /* Pointer chunk information */
|
||
|
||
/* Get pointer to chunk's information */
|
||
chunk_info=curr_node->data;
|
||
assert(chunk_info);
|
||
|
||
/* Clean hyperslab span's "scratch" information */
|
||
if(H5S_hyper_reset_scratch(chunk_info->space)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info");
|
||
|
||
/* Get the next chunk node in the TBBT */
|
||
curr_node=H5TB_next(curr_node);
|
||
} /* end while */
|
||
|
||
/* Clean memory chunks' hyperslab span "scratch" information */
|
||
curr_node=H5TB_first(fm->msel->root);
|
||
while(curr_node) {
|
||
H5D_mchunk_info_t *chunk_info; /* Pointer chunk information */
|
||
|
||
/* Get pointer to chunk's information */
|
||
chunk_info=curr_node->data;
|
||
assert(chunk_info);
|
||
|
||
/* Clean hyperslab span's "scratch" information */
|
||
if(H5S_hyper_reset_scratch(chunk_info->space)<0)
|
||
HGOTO_ERROR (H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info");
|
||
|
||
/* Get the next chunk node in the TBBT */
|
||
curr_node=H5TB_next(curr_node);
|
||
} /* end while */
|
||
|
||
done:
|
||
/* Release the [potentially partially built] chunk mapping information if an error occurs */
|
||
if(ret_value<0) {
|
||
if(tmp_fspace && !fm->fchunk_tmpl) {
|
||
if(H5S_close(tmp_fspace)<0)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release file chunk dataspace template");
|
||
} /* end if */
|
||
|
||
if(tmp_mspace && !fm->mchunk_tmpl) {
|
||
if(H5S_close(tmp_mspace)<0)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template");
|
||
} /* end if */
|
||
|
||
if (H5D_destroy_chunk_map(fm)<0)
|
||
HDONE_ERROR (H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping");
|
||
} /* end if */
|
||
|
||
if(iter_init) {
|
||
if (H5S_select_iter_release(&(fm->mem_iter))<0)
|
||
HDONE_ERROR (H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator");
|
||
}
|
||
if(f_tid!=(-1))
|
||
H5Tclose(f_tid);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5D_create_chunk_map() */
|
||
|
||
|
||
/*--------------------------------------------------------------------------
|
||
NAME
|
||
H5D_free_fchunk_info
|
||
PURPOSE
|
||
Internal routine to destroy a file chunk info node (Wrapper for compatibility
|
||
with H5TB_dfree)
|
||
USAGE
|
||
void H5D_free_fchunk_info(fchunk_info)
|
||
void *fchunk_info; IN: Pointer to file chunk info to destroy
|
||
RETURNS
|
||
No return value
|
||
DESCRIPTION
|
||
Releases all the memory for a file chunk info node.
|
||
GLOBAL VARIABLES
|
||
COMMENTS, BUGS, ASSUMPTIONS
|
||
EXAMPLES
|
||
REVISION LOG
|
||
--------------------------------------------------------------------------*/
|
||
static void
|
||
H5D_free_fchunk_info(void *_fchunk_info)
|
||
{
|
||
H5D_fchunk_info_t *fchunk_info=(H5D_fchunk_info_t *)_fchunk_info;
|
||
|
||
FUNC_ENTER_NOINIT(H5D_free_fchunk_info);
|
||
|
||
assert(fchunk_info);
|
||
|
||
/* Close the chunk's dataspace */
|
||
H5S_close(fchunk_info->space);
|
||
|
||
/* Free the actual chunk info */
|
||
H5FL_FREE(H5D_fchunk_info_t,fchunk_info);
|
||
|
||
FUNC_LEAVE_NOAPI_VOID;
|
||
} /* H5D_free_fchunk_info() */
|
||
|
||
|
||
/*--------------------------------------------------------------------------
|
||
NAME
|
||
H5D_free_mchunk_info
|
||
PURPOSE
|
||
Internal routine to destroy a file chunk info node (Wrapper for compatibility
|
||
with H5TB_dfree)
|
||
USAGE
|
||
void H5D_free_mchunk_info(mchunk_info)
|
||
void *mchunk_info; IN: Pointer to memory chunk info to destroy
|
||
RETURNS
|
||
No return value
|
||
DESCRIPTION
|
||
Releases all the memory for a memory chunk info node.
|
||
GLOBAL VARIABLES
|
||
COMMENTS, BUGS, ASSUMPTIONS
|
||
EXAMPLES
|
||
REVISION LOG
|
||
--------------------------------------------------------------------------*/
|
||
static void
|
||
H5D_free_mchunk_info(void *_mchunk_info)
|
||
{
|
||
H5D_mchunk_info_t *mchunk_info=(H5D_mchunk_info_t *)_mchunk_info;
|
||
|
||
FUNC_ENTER_NOINIT(H5D_free_mchunk_info);
|
||
|
||
assert(mchunk_info);
|
||
|
||
/* Close the chunk's dataspace */
|
||
H5S_close(mchunk_info->space);
|
||
|
||
/* Free the actual chunk info */
|
||
H5FL_FREE(H5D_mchunk_info_t,mchunk_info);
|
||
|
||
FUNC_LEAVE_NOAPI_VOID;
|
||
} /* H5D_free_mchunk_info() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_destroy_chunk_map
|
||
*
|
||
* Purpose: Destroy chunk mapping information.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Saturday, May 17, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_destroy_chunk_map(fm_map *fm)
|
||
{
|
||
herr_t ret_value = SUCCEED; /*return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_destroy_chunk_map);
|
||
|
||
/* Free the file chunk info tree */
|
||
if(fm->fsel)
|
||
H5TB_dfree(fm->fsel,H5D_free_fchunk_info,NULL);
|
||
|
||
/* Free the memory chunk info tree */
|
||
if(fm->msel)
|
||
H5TB_dfree(fm->msel,H5D_free_mchunk_info,NULL);
|
||
|
||
/* Free the file chunk dataspace template */
|
||
if(fm->fchunk_tmpl)
|
||
if(H5S_close(fm->fchunk_tmpl)<0)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release file chunk dataspace template");
|
||
|
||
/* Free the memory chunk dataspace template */
|
||
if(fm->mchunk_tmpl)
|
||
if(H5S_close(fm->mchunk_tmpl)<0)
|
||
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5D_destroy_chunk_map() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5D_chunk_cb
|
||
*
|
||
* Purpose: Callback routine for file selection iterator. Used when
|
||
* creating selections in memory and each chunk for each chunk.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, April 10, 2003
|
||
*
|
||
* Modifications:
|
||
* QAK - 2003/04/17
|
||
* Hacked on it a lot. :-)
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5D_chunk_cb(void UNUSED *elem, hid_t UNUSED type_id, hsize_t ndims, hssize_t *coords, void *_fm)
|
||
{
|
||
fm_map *fm = (fm_map*)_fm; /* File<->memory chunk mapping info */
|
||
H5S_t *fspace; /* File chunk's dataspace */
|
||
H5S_t *mspace; /* Memory chunk's dataspace */
|
||
hssize_t coords_in_chunk[H5O_LAYOUT_NDIMS]; /* Coordinates of element in chunk */
|
||
hssize_t coords_in_mem[H5O_LAYOUT_NDIMS]; /* Coordinates of element in memory */
|
||
hsize_t chunk_index; /* Chunk index */
|
||
hsize_t u; /* Local index variables */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOINIT(H5D_chunk_cb);
|
||
#ifdef QAK
|
||
{
|
||
unsigned u;
|
||
HDfprintf(stderr,"%s: coords={",FUNC);
|
||
for(u=0; u<ndims; u++)
|
||
HDfprintf(stderr,"%Hd%s",coords[u],(u<(ndims-1)?", ":"}\n"));
|
||
}
|
||
#endif /* QAK */
|
||
|
||
/* Calculate the index of this chunk */
|
||
if(H5V_chunk_index((unsigned)ndims,coords,fm->layout->dim,fm->chunks,fm->down_chunks,&chunk_index)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index");
|
||
#ifdef QAK
|
||
HDfprintf(stderr,"%s: chunk_index=%Hu\n",FUNC,chunk_index);
|
||
#endif /* QAK */
|
||
|
||
/*convert coords from relative to whole file space to relative to its chunk space,
|
||
*pass into H5S_select_hyperslab.*/
|
||
for(u=0; u<ndims; u++)
|
||
coords_in_chunk[u] = coords[u] % fm->layout->dim[u];
|
||
|
||
#ifdef QAK
|
||
{
|
||
unsigned u;
|
||
HDfprintf(stderr,"%s: coords_in_chunk={",FUNC);
|
||
for(u=0; u<ndims; u++)
|
||
HDfprintf(stderr,"%Hd%s",coords_in_chunk[u],(u<(ndims-1)?", ":"}\n"));
|
||
}
|
||
#endif /* QAK */
|
||
|
||
/* Find correct chunk in file & memory TBBTs */
|
||
if(chunk_index==fm->last_index) {
|
||
/* If the chunk index is the same as the last chunk index we used,
|
||
* get the cached spaces to operate on.
|
||
*/
|
||
fspace=fm->last_fchunk;
|
||
mspace=fm->last_mchunk;
|
||
} /* end if */
|
||
else {
|
||
H5TB_NODE *chunk_node; /* TBBT node holding chunk information */
|
||
/* If the chunk index is not the same as the last chunk index we used,
|
||
* find the chunk in the tree.
|
||
*/
|
||
/* Get the chunk node from the TBBT */
|
||
if((chunk_node=H5TB_dfind(fm->fsel,&chunk_index,NULL))!=NULL) {
|
||
/* We found the correct chunk already in the tree */
|
||
|
||
/* Get the file space information from the node */
|
||
fspace=((H5D_fchunk_info_t *)(chunk_node->data))->space;
|
||
|
||
/* Look up the memory space information for the chunk */
|
||
if((chunk_node=H5TB_dfind(fm->msel,&chunk_index,NULL))==NULL)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_NOTFOUND, FAIL, "can't find memory chunk info");
|
||
|
||
/* Get the file space information from the node */
|
||
mspace=((H5D_mchunk_info_t *)(chunk_node->data))->space;
|
||
} /* end if */
|
||
else {
|
||
H5D_fchunk_info_t *new_fchunk_info; /* File chunk information to insert into tree */
|
||
H5D_mchunk_info_t *new_mchunk_info; /* Memory chunk information to insert into tree */
|
||
|
||
/* The correct chunk is not already in the tree, create a new node */
|
||
/* in both the file and memory chunk trees */
|
||
|
||
/* Allocate the file & memory chunk information */
|
||
if (NULL==(new_fchunk_info = H5FL_MALLOC (H5D_fchunk_info_t)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate file chunk info");
|
||
if (NULL==(new_mchunk_info = H5FL_MALLOC (H5D_mchunk_info_t)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate memory chunk info");
|
||
|
||
/* Initialize the file chunk information */
|
||
|
||
/* Set the chunk index */
|
||
new_fchunk_info->index=chunk_index;
|
||
|
||
/* Copy the template file chunk dataspace */
|
||
if((new_fchunk_info->space = H5S_copy(fm->fchunk_tmpl))==NULL)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space");
|
||
|
||
/* Compute the chunk's coordinates */
|
||
H5D_chunk_coords_assist(new_fchunk_info->coords, fm->f_ndims, fm->chunks, chunk_index);
|
||
|
||
/* Insert the new file chunk into the TBBT tree */
|
||
if(H5TB_dins(fm->fsel,new_fchunk_info,new_fchunk_info)==NULL)
|
||
HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert file chunk into TBBT");
|
||
|
||
/* Initialize the memory chunk information */
|
||
|
||
/* Set the chunk index */
|
||
new_mchunk_info->index=chunk_index;
|
||
|
||
/* Copy the template memory chunk dataspace */
|
||
if((new_mchunk_info->space = H5S_copy(fm->mchunk_tmpl))==NULL)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space");
|
||
|
||
/* Insert the new memory chunk into the TBBT tree */
|
||
if(H5TB_dins(fm->msel,new_mchunk_info,new_mchunk_info)==NULL)
|
||
HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert memory chunk into TBBT");
|
||
|
||
/* Get the dataspaces for use in this routine */
|
||
fspace=new_fchunk_info->space;
|
||
mspace=new_mchunk_info->space;
|
||
} /* end else */
|
||
|
||
/* Update the "last chunk seen" information */
|
||
fm->last_index=chunk_index;
|
||
fm->last_fchunk=fspace;
|
||
fm->last_mchunk=mspace;
|
||
} /* end else */
|
||
|
||
/* Add point to file selection for chunk */
|
||
if(H5S_hyper_add_span_element(fspace, fm->f_ndims, coords_in_chunk)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element");
|
||
|
||
/* Get coordinates of selection iterator for memory */
|
||
if(H5S_select_iter_coords(&fm->mem_iter,coords_in_mem)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get iterator coordinates");
|
||
|
||
#ifdef QAK
|
||
{
|
||
unsigned u;
|
||
HDfprintf(stderr,"%s: coords_in_mem={",FUNC);
|
||
for(u=0; u<fm->m_ndims; u++)
|
||
HDfprintf(stderr,"%Hd%s",coords_in_mem[u],(u<(fm->m_ndims-1)?", ":"}\n"));
|
||
}
|
||
#endif /* QAK */
|
||
/* Add point to memory selection for chunk */
|
||
if(H5S_hyper_add_span_element(mspace, fm->m_ndims, coords_in_mem)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element");
|
||
|
||
/* Move memory selection iterator to next element in selection */
|
||
if(H5S_select_iter_next(&fm->mem_iter,1)<0)
|
||
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTNEXT, FAIL, "unable to move to next iterator location");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5D_chunk_cb() */
|