diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2008-04-24 15:03:41 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2008-04-24 15:03:41 (GMT) |
commit | 495ca9c7bb19553d2c87ce68013f1de2dff3d54b (patch) | |
tree | 792e1a9ecc8aa314dfa3d0538464e4f87ad55cf5 /src/H5Dscatgath.c | |
parent | 16d4cae5b16ffb91298d8d232214afeb5112da6d (diff) | |
download | hdf5-495ca9c7bb19553d2c87ce68013f1de2dff3d54b.zip hdf5-495ca9c7bb19553d2c87ce68013f1de2dff3d54b.tar.gz hdf5-495ca9c7bb19553d2c87ce68013f1de2dff3d54b.tar.bz2 |
[svn-r14860] Description:
Omnibus raw data I/O revisions, with wide-ranging changes and
refactoring, in order to prepare for implementing "fast append" feature.
These changes remove the majority of the code duplication for raw data
I/O which has crept in over the last ten years and introduces a more object-
oriented design for operating on different types of dataset storage.
Chunked storage no longer has it's own I/O routines, it is now handled
as either contiguous (if chunk is not pulled into the cache) or compact (if the
chunk is cached in memory).
No bug or feature changes, at least intentionally... :-)
Tested on:
FreeBSD/32 6.2 (duty) in debug mode
FreeBSD/64 6.2 (liberty) w/C++ & FORTRAN, in debug mode
Linux/32 2.6 (kagiso) w/PGI compilers, w/C++ & FORTRAN, w/threadsafe,
in debug mode
Linux/64-amd64 2.6 (smirom) w/default API=1.6.x, w/C++ & FORTRAN,
in production mode
Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN,
in production mode
Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN,
w/szip filter, in production mode
Mac OS X/32 10.5.2 (amazon) in debug mode
Linux/64-ia64 2.4 (tg-login3) w/parallel, w/FORTRAN, in production mode
Diffstat (limited to 'src/H5Dscatgath.c')
-rw-r--r-- | src/H5Dscatgath.c | 899 |
1 files changed, 899 insertions, 0 deletions
diff --git a/src/H5Dscatgath.c b/src/H5Dscatgath.c new file mode 100644 index 0000000..3ea4c69 --- /dev/null +++ b/src/H5Dscatgath.c @@ -0,0 +1,899 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * 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://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5D_PACKAGE /*suppress error about including H5Dpkg */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Dpkg.h" /* Dataset functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free Lists */ + + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ +static size_t H5D_gather_file(const H5D_io_info_t *io_info, + const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, + void *buf); +static herr_t H5D_scatter_file(const H5D_io_info_t *io_info, + const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, + const void *buf); +static size_t H5D_gather_mem(const void *_buf, + const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, + const H5D_dxpl_cache_t *dxpl_cache, void *_tgath_buf/*out*/); +static herr_t H5D_compound_opt_read(size_t nelmts, const H5S_t *mem_space, + H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache, + const H5D_type_info_t *type_info, void *user_buf/*out*/); +static herr_t H5D_compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info); + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Declare a free list to manage sequences of size_t */ +H5FL_SEQ_EXTERN(size_t); + +/* Declare a free list to manage sequences of hsize_t */ +H5FL_SEQ_EXTERN(hsize_t); + + + +/*------------------------------------------------------------------------- + * Function: H5D_scatter_file + * + * Purpose: Scatters dataset elements from the type conversion buffer BUF + * to the file F where the data points are arranged according to + * the file dataspace FILE_SPACE and stored according to + * LAYOUT and EFL. Each element is ELMT_SIZE bytes. + * The caller is requesting that NELMTS elements are copied. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, June 20, 2002 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_scatter_file(const H5D_io_info_t *_io_info, + const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, + const void *_buf) +{ + H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ + hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ + hsize_t *off = NULL; /* Pointer to sequence offsets */ + hsize_t mem_off; /* Offset in memory */ + size_t mem_curr_seq; /* "Current sequence" in memory */ + size_t dset_curr_seq; /* "Current sequence" in dataset */ + size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ + size_t *len = NULL; /* Array to store sequence lengths */ + size_t orig_mem_len, mem_len; /* Length of sequence in memory */ + size_t nseq; /* Number of sequences generated */ + size_t nelem; /* Number of elements used in sequences */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_scatter_file) + + /* Check args */ + HDassert(_io_info); + HDassert(space); + HDassert(iter); + HDassert(nelmts > 0); + HDassert(_buf); + + /* Set up temporary I/O info object */ + HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); + tmp_io_info.op_type = H5D_IO_OP_WRITE; + tmp_io_info.u.wbuf = _buf; + + /* Allocate the vector I/O arrays */ + if(tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { + if(NULL == (len = H5FL_SEQ_MALLOC(size_t, tmp_io_info.dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array") + if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, tmp_io_info.dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array") + } /* end if */ + else { + len = _len; + off = _off; + } /* end else */ + + /* Loop until all elements are written */ + while(nelmts > 0) { + /* Get list of sequences for selection to write */ + if(H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, tmp_io_info.dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + + /* Reset the current sequence information */ + mem_curr_seq = dset_curr_seq = 0; + orig_mem_len = mem_len = nelem * iter->elmt_size; + mem_off = 0; + + /* Write sequence list out */ + if((*tmp_io_info.layout_ops.writevv)(&tmp_io_info, nseq, &dset_curr_seq, + len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") + + /* Update buffer */ + tmp_io_info.u.wbuf = (const uint8_t *)tmp_io_info.u.wbuf + orig_mem_len; + + /* Decrement number of elements left to process */ + nelmts -= nelem; + } /* end while */ + +done: + /* Release resources, if allocated */ + if(len && len != _len) + H5FL_SEQ_FREE(size_t, len); + if(off && off != _off) + H5FL_SEQ_FREE(hsize_t, off); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_scatter_file() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_gather_file + * + * Purpose: Gathers data points from file F and accumulates them in the + * type conversion buffer BUF. The LAYOUT argument describes + * how the data is stored on disk and EFL describes how the data + * is organized in external files. ELMT_SIZE is the size in + * bytes of a datum which this function treats as opaque. + * FILE_SPACE describes the dataspace of the dataset on disk + * and the elements that have been selected for reading (via + * hyperslab, etc). This function will copy at most NELMTS + * elements. + * + * Return: Success: Number of elements copied. + * Failure: 0 + * + * Programmer: Quincey Koziol + * Monday, June 24, 2002 + * + *------------------------------------------------------------------------- + */ +static size_t +H5D_gather_file(const H5D_io_info_t *_io_info, + const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, + void *_buf/*out*/) +{ + H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ + hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ + hsize_t *off = NULL; /* Pointer to sequence offsets */ + hsize_t mem_off; /* Offset in memory */ + size_t mem_curr_seq; /* "Current sequence" in memory */ + size_t dset_curr_seq; /* "Current sequence" in dataset */ + size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ + size_t *len = NULL; /* Pointer to sequence lengths */ + size_t orig_mem_len, mem_len; /* Length of sequence in memory */ + size_t nseq; /* Number of sequences generated */ + size_t nelem; /* Number of elements used in sequences */ + size_t ret_value = nelmts; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_gather_file) + + /* Check args */ + HDassert(_io_info); + HDassert(_io_info->dset); + HDassert(_io_info->store); + HDassert(space); + HDassert(iter); + HDassert(nelmts > 0); + HDassert(_buf); + + /* Set up temporary I/O info object */ + HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); + tmp_io_info.op_type = H5D_IO_OP_READ; + tmp_io_info.u.rbuf = _buf; + + /* Allocate the vector I/O arrays */ + if(tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { + if(NULL == (len = H5FL_SEQ_MALLOC(size_t, tmp_io_info.dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array") + if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, tmp_io_info.dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O offset vector array") + } /* end if */ + else { + len = _len; + off = _off; + } /* end else */ + + /* Loop until all elements are read */ + while(nelmts > 0) { + /* Get list of sequences for selection to read */ + if(H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, tmp_io_info.dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") + + /* Reset the current sequence information */ + mem_curr_seq = dset_curr_seq = 0; + orig_mem_len = mem_len = nelem * iter->elmt_size; + mem_off = 0; + + /* Read sequence list in */ + if((*tmp_io_info.layout_ops.readvv)(&tmp_io_info, nseq, &dset_curr_seq, + len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error") + + /* Update buffer */ + tmp_io_info.u.rbuf = (uint8_t *)tmp_io_info.u.rbuf + orig_mem_len; + + /* Decrement number of elements left to process */ + nelmts -= nelem; + } /* end while */ + +done: + /* Release resources, if allocated */ + if(len && len != _len) + H5FL_SEQ_FREE(size_t, len); + if(off && off != _off) + H5FL_SEQ_FREE(hsize_t, off); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_gather_file() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_scatter_mem + * + * Purpose: Scatters NELMTS data points from the scatter buffer + * TSCAT_BUF to the application buffer BUF. Each element is + * ELMT_SIZE bytes and they are organized in application memory + * according to SPACE. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Monday, July 8, 2002 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D_scatter_mem (const void *_tscat_buf, const H5S_t *space, + H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache, + void *_buf/*out*/) +{ + uint8_t *buf = (uint8_t *)_buf; /* Get local copies for address arithmetic */ + const uint8_t *tscat_buf = (const uint8_t *)_tscat_buf; + hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ + hsize_t *off = NULL; /* Pointer to sequence offsets */ + size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ + size_t *len = NULL; /* Pointer to sequence lengths */ + size_t curr_len; /* Length of bytes left to process in sequence */ + size_t nseq; /* Number of sequences generated */ + size_t curr_seq; /* Current sequence being processed */ + size_t nelem; /* Number of elements used in sequences */ + herr_t ret_value = SUCCEED; /* Number of elements scattered */ + + FUNC_ENTER_NOAPI(H5D_scatter_mem, FAIL) + + /* Check args */ + HDassert(tscat_buf); + HDassert(space); + HDassert(iter); + HDassert(nelmts > 0); + HDassert(buf); + + /* Allocate the vector I/O arrays */ + if(dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { + if(NULL == (len = H5FL_SEQ_MALLOC(size_t, dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array") + if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array") + } /* end if */ + else { + len = _len; + off = _off; + } /* end else */ + + /* Loop until all elements are written */ + while(nelmts > 0) { + /* Get list of sequences for selection to write */ + if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) + HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") + + /* Loop, while sequences left to process */ + for(curr_seq = 0; curr_seq < nseq; curr_seq++) { + /* Get the number of bytes in sequence */ + curr_len = len[curr_seq]; + + HDmemcpy(buf + off[curr_seq], tscat_buf, curr_len); + + /* Advance offset in destination buffer */ + tscat_buf += curr_len; + } /* end for */ + + /* Decrement number of elements left to process */ + nelmts -= nelem; + } /* end while */ + +done: + /* Release resources, if allocated */ + if(len && len != _len) + H5FL_SEQ_FREE(size_t, len); + if(off && off != _off) + H5FL_SEQ_FREE(hsize_t, off); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_scatter_mem() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_gather_mem + * + * Purpose: Gathers dataset elements from application memory BUF and + * copies them into the gather buffer TGATH_BUF. + * Each element is ELMT_SIZE bytes and arranged in application + * memory according to SPACE. + * The caller is requesting that at most NELMTS be gathered. + * + * Return: Success: Number of elements copied. + * Failure: 0 + * + * Programmer: Quincey Koziol + * Monday, June 24, 2002 + * + *------------------------------------------------------------------------- + */ +static size_t +H5D_gather_mem(const void *_buf, const H5S_t *space, + H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache, + void *_tgath_buf/*out*/) +{ + const uint8_t *buf = (const uint8_t *)_buf; /* Get local copies for address arithmetic */ + uint8_t *tgath_buf = (uint8_t *)_tgath_buf; + hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ + hsize_t *off = NULL; /* Pointer to sequence offsets */ + size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ + size_t *len = NULL; /* Pointer to sequence lengths */ + size_t curr_len; /* Length of bytes left to process in sequence */ + size_t nseq; /* Number of sequences generated */ + size_t curr_seq; /* Current sequence being processed */ + size_t nelem; /* Number of elements used in sequences */ + size_t ret_value = nelmts; /* Number of elements gathered */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_gather_mem) + + /* Check args */ + HDassert(buf); + HDassert(space); + HDassert(iter); + HDassert(nelmts > 0); + HDassert(tgath_buf); + + /* Allocate the vector I/O arrays */ + if(dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { + if(NULL == (len = H5FL_SEQ_MALLOC(size_t, dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array") + if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O offset vector array") + } /* end if */ + else { + len = _len; + off = _off; + } /* end else */ + + /* Loop until all elements are written */ + while(nelmts > 0) { + /* Get list of sequences for selection to write */ + if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) + HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") + + /* Loop, while sequences left to process */ + for(curr_seq = 0; curr_seq < nseq; curr_seq++) { + /* Get the number of bytes in sequence */ + curr_len = len[curr_seq]; + + HDmemcpy(tgath_buf, buf + off[curr_seq], curr_len); + + /* Advance offset in gather buffer */ + tgath_buf += curr_len; + } /* end for */ + + /* Decrement number of elements left to process */ + nelmts -= nelem; + } /* end while */ + +done: + /* Release resources, if allocated */ + if(len && len != _len) + H5FL_SEQ_FREE(size_t, len); + if(off && off != _off) + H5FL_SEQ_FREE(hsize_t, off); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_gather_mem() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_scatgath_read + * + * Purpose: Perform scatter/gather ead from a contiguous [piece of a] dataset. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 6, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D_scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space) +{ + const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */ + void *buf = io_info->u.rbuf; /* Local pointer to application buffer */ + H5S_sel_iter_t mem_iter; /*memory selection iteration info*/ + hbool_t mem_iter_init = FALSE; /*memory selection iteration info has been initialized */ + H5S_sel_iter_t bkg_iter; /*background iteration info*/ + hbool_t bkg_iter_init = FALSE; /*background iteration info has been initialized */ + H5S_sel_iter_t file_iter; /*file selection iteration info*/ + hbool_t file_iter_init = FALSE; /*file selection iteration info has been initialized */ + hsize_t smine_start; /*strip mine start loc */ + size_t smine_nelmts; /*elements per strip */ + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_scatgath_read) + + /* Sanity check */ + HDassert(io_info); + HDassert(type_info); + HDassert(mem_space); + HDassert(file_space); + HDassert(buf); + + /* Check for NOOP read */ + if(nelmts == 0) + HGOTO_DONE(SUCCEED) + + /* Figure out the strip mine size. */ + if(H5S_select_iter_init(&file_iter, file_space, type_info->src_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information") + file_iter_init = TRUE; /*file selection iteration info has been initialized */ + if(H5S_select_iter_init(&mem_iter, mem_space, type_info->dst_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") + mem_iter_init = TRUE; /*file selection iteration info has been initialized */ + if(H5S_select_iter_init(&bkg_iter, mem_space, type_info->dst_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information") + bkg_iter_init = TRUE; /*file selection iteration info has been initialized */ + + /* Start strip mining... */ + for(smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) { + size_t n; /* Elements operated on */ + + /* Go figure out how many elements to read from the file */ + HDassert(H5S_SELECT_ITER_NELMTS(&file_iter) == (nelmts - smine_start)); + smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start)); + + /* + * Gather the data from disk into the datatype conversion + * buffer. Also gather data from application to background buffer + * if necessary. + */ + + /* + * Gather data + */ + n = H5D_gather_file(io_info, file_space, &file_iter, smine_nelmts, + type_info->tconv_buf/*out*/); + if(n != smine_nelmts) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") + + /* If the source and destination are compound types and subset of each other + * and no conversion is needed, copy the data directly into user's buffer and + * bypass the rest of steps. + */ + if(H5T_SUBSET_FALSE != type_info->cmpd_subset) { + if(H5D_compound_opt_read(smine_nelmts, mem_space, &mem_iter, dxpl_cache, + type_info, buf /*out*/) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") + } /* end if */ + else { + if(H5T_BKG_YES == type_info->need_bkg) { + n = H5D_gather_mem(buf, mem_space, &bkg_iter, smine_nelmts, + dxpl_cache, type_info->bkg_buf/*out*/); + if(n != smine_nelmts) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed") + } /* end if */ + + /* + * Perform datatype conversion. + */ + if(H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id, + smine_nelmts, (size_t)0, (size_t)0, type_info->tconv_buf, + type_info->bkg_buf, io_info->dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed") + + /* Do the data transform after the conversion (since we're using type mem_type) */ + if(!type_info->is_xform_noop) + if(H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") + + /* + * Scatter the data into memory. + */ + if(H5D_scatter_mem(type_info->tconv_buf, mem_space, &mem_iter, + smine_nelmts, dxpl_cache, buf/*out*/) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") + } /* end else */ + } /* end for */ + +done: + /* Release selection iterators */ + if(file_iter_init) { + if(H5S_SELECT_ITER_RELEASE(&file_iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + if(mem_iter_init) { + if(H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + if(bkg_iter_init) { + if(H5S_SELECT_ITER_RELEASE(&bkg_iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_scatgath_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_scatgath_write + * + * Purpose: Perform scatter/gather write to a contiguous [piece of a] dataset. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 6, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D_scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space) +{ + const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */ + const void *buf = io_info->u.wbuf; /* Local pointer to application buffer */ + H5S_sel_iter_t mem_iter; /*memory selection iteration info*/ + hbool_t mem_iter_init = FALSE; /*memory selection iteration info has been initialized */ + H5S_sel_iter_t bkg_iter; /*background iteration info*/ + hbool_t bkg_iter_init = FALSE; /*background iteration info has been initialized */ + H5S_sel_iter_t file_iter; /*file selection iteration info*/ + hbool_t file_iter_init = FALSE; /*file selection iteration info has been initialized */ + hsize_t smine_start; /*strip mine start loc */ + size_t smine_nelmts; /*elements per strip */ + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_scatgath_write) + + /* Sanity check */ + HDassert(io_info); + HDassert(type_info); + HDassert(mem_space); + HDassert(file_space); + HDassert(buf); + + /* Check for NOOP write */ + if(nelmts == 0) + HGOTO_DONE(SUCCEED) + + /* Figure out the strip mine size. */ + if(H5S_select_iter_init(&file_iter, file_space, type_info->dst_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information") + file_iter_init = TRUE; /*file selection iteration info has been initialized */ + if(H5S_select_iter_init(&mem_iter, mem_space, type_info->src_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") + mem_iter_init = TRUE; /*file selection iteration info has been initialized */ + if(H5S_select_iter_init(&bkg_iter, file_space, type_info->dst_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information") + bkg_iter_init = TRUE; /*file selection iteration info has been initialized */ + + /* Start strip mining... */ + for(smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) { + size_t n; /* Elements operated on */ + + /* Go figure out how many elements to read from the file */ + HDassert(H5S_SELECT_ITER_NELMTS(&file_iter) == (nelmts - smine_start)); + smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start)); + + /* + * Gather data from application buffer into the datatype conversion + * buffer. Also gather data from the file into the background buffer + * if necessary. + */ + n = H5D_gather_mem(buf, mem_space, &mem_iter, smine_nelmts, + dxpl_cache, type_info->tconv_buf/*out*/); + if(n != smine_nelmts) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed") + + /* If the source and destination are compound types and the destination is + * is a subset of the source and no conversion is needed, copy the data + * directly into user's buffer and bypass the rest of steps. If the source + * is a subset of the destination, the optimization is done in conversion + * function H5T_conv_struct_opt to protect the background data. + */ + if(H5T_SUBSET_DST == type_info->cmpd_subset) { + if(H5D_compound_opt_write(smine_nelmts, type_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") + } /* end if */ + else { + if(H5T_BKG_YES == type_info->need_bkg) { + n = H5D_gather_file(io_info, file_space, &bkg_iter, smine_nelmts, + type_info->bkg_buf/*out*/); + if(n != smine_nelmts) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") + } /* end if */ + + /* + * Perform datatype conversion. + */ + if(H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id, + smine_nelmts, (size_t)0, (size_t)0, type_info->tconv_buf, + type_info->bkg_buf, io_info->dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed") + + /* Do the data transform after the type conversion (since we're using dataset->shared->type). */ + if(!type_info->is_xform_noop) + if(H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->dset_type) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") + } /* end else */ + + /* + * Scatter the data out to the file. + */ + if(H5D_scatter_file(io_info, file_space, &file_iter, smine_nelmts, + type_info->tconv_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed") + } /* end for */ + +done: + /* Release selection iterators */ + if(file_iter_init) { + if(H5S_SELECT_ITER_RELEASE(&file_iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + if(mem_iter_init) { + if(H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + if(bkg_iter_init) { + if(H5S_SELECT_ITER_RELEASE(&bkg_iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_scatgath_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_compound_opt_read + * + * Purpose: A special optimization case when the source and + * destination members are a subset of each other, and + * the order is the same, and no conversion is needed. + * For example: + * struct source { struct destination { + * TYPE1 A; --> TYPE1 A; + * TYPE2 B; --> TYPE2 B; + * TYPE3 C; --> TYPE3 C; + * }; TYPE4 D; + * TYPE5 E; + * }; + * or + * struct destination { struct source { + * TYPE1 A; <-- TYPE1 A; + * TYPE2 B; <-- TYPE2 B; + * TYPE3 C; <-- TYPE3 C; + * }; TYPE4 D; + * TYPE5 E; + * }; + * The optimization is simply moving data to the appropriate + * places in the buffer. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Raymond Lu + * 11 June 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_compound_opt_read(size_t nelmts, const H5S_t *space, + H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache, + const H5D_type_info_t *type_info, void *user_buf/*out*/) +{ + uint8_t *ubuf = (uint8_t *)user_buf; /* Cast for pointer arithmetic */ + uint8_t *xdbuf; /* Pointer into dataset buffer */ + hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ + hsize_t *off = NULL; /* Pointer to sequence offsets */ + size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ + size_t *len = NULL; /* Pointer to sequence lengths */ + size_t src_stride, dst_stride, type_size; + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_compound_opt_read) + + /* Check args */ + HDassert(nelmts > 0); + HDassert(space); + HDassert(iter); + HDassert(dxpl_cache); + HDassert(type_info); + HDassert(user_buf); + + /* Allocate the vector I/O arrays */ + if(dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { + if(NULL == (len = H5FL_SEQ_MALLOC(size_t, dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array") + if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, dxpl_cache->vec_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array") + } /* end if */ + else { + len = _len; + off = _off; + } /* end else */ + + /* Get source & destination strides */ + src_stride = type_info->src_type_size; + dst_stride = type_info->dst_type_size; + + if(H5T_SUBSET_SRC == type_info->cmpd_subset) + type_size = src_stride; + else { + HDassert(H5T_SUBSET_DST == type_info->cmpd_subset); + type_size = dst_stride; + } /* end else */ + + /* Loop until all elements are written */ + xdbuf = type_info->tconv_buf; + while(nelmts > 0) { + size_t nseq; /* Number of sequences generated */ + size_t curr_seq; /* Current sequence being processed */ + size_t elmtno; /* Element counter */ + + /* Get list of sequences for selection to write */ + if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, dxpl_cache->vec_size, nelmts, &nseq, &elmtno, off, len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") + + /* Loop, while sequences left to process */ + for(curr_seq = 0; curr_seq < nseq; curr_seq++) { + size_t curr_off; /* Offset of bytes left to process in sequence */ + size_t curr_len; /* Length of bytes left to process in sequence */ + size_t curr_nelmts; /* Number of elements to process in sequence */ + uint8_t *xubuf; + size_t i; /* Local index variable */ + + /* Get the number of bytes and offset in sequence */ + curr_len = len[curr_seq]; + curr_off = off[curr_seq]; + + /* Decide the number of elements and position in the buffer. */ + curr_nelmts = curr_len / dst_stride; + xubuf = ubuf + curr_off; + + /* Copy the data into the right place. */ + for(i = 0; i < curr_nelmts; i++) { + HDmemmove(xubuf, xdbuf, type_size); + + /* Update pointers */ + xdbuf += src_stride; + xubuf += dst_stride; + } /* end for */ + } /* end for */ + + /* Decrement number of elements left to process */ + nelmts -= elmtno; + } /* end while */ + +done: + /* Release resources, if allocated */ + if(len && len != _len) + H5FL_SEQ_FREE(size_t, len); + if(off && off != _off) + H5FL_SEQ_FREE(hsize_t, off); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_compound_opt_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_compound_opt_write + * + * Purpose: A special optimization case when the source and + * destination members are a subset of each other, and + * the order is the same, and no conversion is needed. + * For example: + * struct source { struct destination { + * TYPE1 A; --> TYPE1 A; + * TYPE2 B; --> TYPE2 B; + * TYPE3 C; --> TYPE3 C; + * }; TYPE4 D; + * TYPE5 E; + * }; + * or + * struct destination { struct source { + * TYPE1 A; <-- TYPE1 A; + * TYPE2 B; <-- TYPE2 B; + * TYPE3 C; <-- TYPE3 C; + * }; TYPE4 D; + * TYPE5 E; + * }; + * The optimization is simply moving data to the appropriate + * places in the buffer. + * + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Raymond Lu + * 11 June 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info) +{ + uint8_t *xsbuf, *xdbuf; /* Source & destination pointers into dataset buffer */ + size_t src_stride, dst_stride; /* Strides through source & destination datatypes */ + size_t i; /* Local index variable */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_compound_opt_write) + + /* Check args */ + HDassert(nelmts > 0); + HDassert(type_info); + + /* Initialize values for loop */ + src_stride = type_info->src_type_size; + dst_stride = type_info->dst_type_size; + + /* Loop until all elements are written */ + xsbuf = (uint8_t *)type_info->tconv_buf; + xdbuf = (uint8_t *)type_info->tconv_buf; + for(i = 0; i < nelmts; i++) { + HDmemmove(xdbuf, xsbuf, dst_stride); + + /* Update pointers */ + xsbuf += src_stride; + xdbuf += dst_stride; + } /* end for */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D_compound_opt_write() */ + |