From 495ca9c7bb19553d2c87ce68013f1de2dff3d54b Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Thu, 24 Apr 2008 10:03:41 -0500 Subject: [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 --- MANIFEST | 2 + src/H5D.c | 4 +- src/H5Dchunk.c | 1515 +++++++++++++++++++++++++ src/H5Dcompact.c | 91 +- src/H5Dcontig.c | 434 ++++--- src/H5Ddeprec.c | 2 +- src/H5Defl.c | 196 ++-- src/H5Dfill.c | 12 +- src/H5Dint.c | 269 ++++- src/H5Dio.c | 3273 +++++++---------------------------------------------- src/H5Distore.c | 409 +------ src/H5Dmpio.c | 2658 +++++++++++++++++++++---------------------- src/H5Doh.c | 2 +- src/H5Dpkg.h | 338 +++--- src/H5Dprivate.h | 22 +- src/H5Dscatgath.c | 899 +++++++++++++++ src/H5Dselect.c | 466 +------- src/H5FDmpi.h | 4 +- src/H5FDmpio.c | 188 +-- src/H5Pdxpl.c | 6 - src/H5S.c | 273 +---- src/H5Smpio.c | 14 +- src/H5Sprivate.h | 28 - src/H5T.c | 2 +- src/H5Tconv.c | 6 +- src/H5Tprivate.h | 2 +- src/Makefile.am | 4 +- src/Makefile.in | 10 +- test/cmpd_dset.c | 46 +- test/tcoords.c | 28 +- test/th5s.c | 6 +- 31 files changed, 5270 insertions(+), 5939 deletions(-) create mode 100644 src/H5Dchunk.c create mode 100644 src/H5Dscatgath.c diff --git a/MANIFEST b/MANIFEST index 46f4e75..ad3c0eb 100644 --- a/MANIFEST +++ b/MANIFEST @@ -456,6 +456,7 @@ ./src/H5CS.c ./src/H5CSprivate.h ./src/H5D.c +./src/H5Dchunk.c ./src/H5Dcompact.c ./src/H5Dcontig.c ./src/H5Ddbg.c @@ -470,6 +471,7 @@ ./src/H5Dpkg.h ./src/H5Dprivate.h ./src/H5Dpublic.h +./src/H5Dscatgath.c ./src/H5Dselect.c ./src/H5Dtest.c ./src/H5E.c diff --git a/src/H5D.c b/src/H5D.c index 7153ea5..7fd03b3 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -625,7 +625,7 @@ H5Dget_create_plist(hid_t dset_id) H5I_dec_ref(src_id); H5I_dec_ref(dst_id); if(bkg_buf) - H5FL_BLK_FREE(type_conv, bkg_buf); + (void)H5FL_BLK_FREE(type_conv, bkg_buf); HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed") } /* end if */ @@ -633,7 +633,7 @@ H5Dget_create_plist(hid_t dset_id) H5I_dec_ref(src_id); H5I_dec_ref(dst_id); if(bkg_buf) - H5FL_BLK_FREE(type_conv, bkg_buf); + (void)H5FL_BLK_FREE(type_conv, bkg_buf); } /* end if */ } /* end if */ diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c new file mode 100644 index 0000000..baaa5f1 --- /dev/null +++ b/src/H5Dchunk.c @@ -0,0 +1,1515 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 */ +#include "H5Iprivate.h" /* IDs */ +#ifdef H5_HAVE_PARALLEL +#include "H5MMprivate.h" /* Memory management */ +#endif /* H5_HAVE_PARALLEL */ +#include "H5Vprivate.h" /* Vector and array functions */ + + +/****************/ +/* Local Macros */ +/****************/ + +/* Default skip list height for storing list of chunks */ +#define H5D_DEFAULT_SKIPLIST_HEIGHT 8 + +/* Macros for iterating over chunks to operate on */ +#define H5D_CHUNK_GET_FIRST_NODE(map) (map->use_single ? (H5SL_node_t *)(1) : H5SL_first(map->sel_chunks)) +#define H5D_CHUNK_GET_NODE_INFO(map, node) (map->use_single ? map->single_chunk_info : (H5D_chunk_info_t *)H5SL_item(node)) +#define H5D_CHUNK_GET_NEXT_NODE(map, node) (map->use_single ? (H5SL_node_t *)NULL : H5SL_next(node)) + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + +/* Chunked layout operation callbacks */ +static herr_t H5D_chunk_io_init(const H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, H5D_chunk_map_t *fm); +static herr_t H5D_chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *fm); +static herr_t H5D_chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *fm); +static herr_t H5D_chunk_io_term(const H5D_chunk_map_t *fm); + +/* "Null" layout operation callbacks */ +static ssize_t H5D_null_readvv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); + +/* Helper routines */ +static herr_t H5D_free_chunk_info(void *item, void *key, void *opdata); +static herr_t H5D_create_chunk_map_single(H5D_chunk_map_t *fm, + const H5D_io_info_t *io_info); +static herr_t H5D_create_chunk_file_map_hyper(H5D_chunk_map_t *fm, + const H5D_io_info_t *io_info); +static herr_t H5D_create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm); +static herr_t H5D_chunk_file_cb(void *elem, hid_t type_id, unsigned ndims, + const hsize_t *coords, void *fm); +static herr_t H5D_chunk_mem_cb(void *elem, hid_t type_id, unsigned ndims, + const hsize_t *coords, void *fm); + + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Compact storage layout I/O ops */ +const H5D_layout_ops_t H5D_LOPS_CHUNK[1] = {{ + H5D_chunk_io_init, + H5D_chunk_read, + H5D_chunk_write, +#ifdef H5_HAVE_PARALLEL + H5D_chunk_collective_read, + H5D_chunk_collective_write, +#endif /* H5_HAVE_PARALLEL */ + NULL, + NULL, + H5D_chunk_io_term +}}; + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* "null" storage layout I/O ops */ +const H5D_layout_ops_t H5D_LOPS_NULL[1] = {{ + NULL, + NULL, + NULL, +#ifdef H5_HAVE_PARALLEL + NULL, + NULL, +#endif /* H5_HAVE_PARALLEL */ + H5D_null_readvv, + NULL, + NULL +}}; + +/* Declare a free list to manage the H5D_chunk_info_t struct */ +H5FL_DEFINE(H5D_chunk_info_t); + + + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_io_init + * + * Purpose: Performs initialization before any sort of I/O on the raw data + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 20, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *fm) +{ + H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */ + const H5T_t *mem_type = type_info->mem_type; /* Local pointer to memory datatype */ + H5S_t *tmp_mspace = NULL; /* Temporary memory dataspace */ + hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ + htri_t file_space_normalized = FALSE; /* File dataspace was normalized */ + hid_t f_tid = (-1); /* Temporary copy of file datatype for iteration */ + hbool_t iter_init = FALSE; /* 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) */ + H5SL_node_t *curr_node; /* Current node in skip list */ + H5S_sel_type fsel_type; /* Selection type on disk */ + char bogus; /* "bogus" buffer to pass to selection iterator */ + unsigned u; /* Local index variable */ + hbool_t sel_hyper_flag; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_io_init) + + /* Get layout for dataset */ + fm->layout = &(dataset->shared->layout); + fm->nelmts = nelmts; + + /* Check if the memory space is scalar & make equivalent memory space */ + if((sm_ndims = H5S_GET_EXTENT_NDIMS(mem_space)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number") + /* Set the number of dimensions for the memory dataspace */ + H5_ASSIGN_OVERFLOW(fm->m_ndims, sm_ndims, int, unsigned); + + /* Get dim number and dimensionality for each dataspace */ + fm->f_ndims = f_ndims = dataset->shared->layout.u.chunk.ndims - 1; + if(H5S_get_simple_extent_dims(file_space, fm->f_dims, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality") + + /* Normalize hyperslab selections by adjusting them by the offset */ + /* (It might be worthwhile to normalize both the file and memory dataspaces + * before any (contiguous, chunked, etc) file I/O operation, in order to + * speed up hyperslab calculations by removing the extra checks and/or + * additions involving the offset and the hyperslab selection -QAK) + */ + if((file_space_normalized = H5S_hyper_normalize_offset((H5S_t *)file_space, old_offset)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + + /* Decide the number of chunks in each dimension*/ + for(u=0; uchunk_dim[u]=fm->layout->u.chunk.dim[u]; + + /* Round up to the next integer # of chunks, to accomodate partial chunks */ + fm->chunks[u] = ((fm->f_dims[u]+dataset->shared->layout.u.chunk.dim[u])-1) / dataset->shared->layout.u.chunk.dim[u]; + } /* 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") + +#ifdef H5_HAVE_PARALLEL + /* Calculate total chunk in file map*/ + fm->select_chunk = NULL; + fm->total_chunks = 1; + for(u = 0; u < fm->f_ndims; u++) + fm->total_chunks = fm->total_chunks * fm->chunks[u]; + if(io_info->using_mpi_vfd) { + H5_CHECK_OVERFLOW(fm->total_chunks, hsize_t, size_t); + if(NULL == (fm->select_chunk = (H5D_chunk_info_t **)H5MM_calloc((size_t)fm->total_chunks * sizeof(H5D_chunk_info_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") + } /* end if */ +#endif /* H5_HAVE_PARALLEL */ + + + /* Initialize "last chunk" information */ + fm->last_index = (hsize_t)-1; + fm->last_chunk_info = NULL; + + /* Point at the dataspaces */ + fm->file_space = file_space; + fm->mem_space = mem_space; + + /* Special case for only one element in selection */ + /* (usually appending a record) */ + if(nelmts == 1 +#ifdef H5_HAVE_PARALLEL + && !(io_info->using_mpi_vfd) +#endif /* H5_HAVE_PARALLEL */ + ) { + /* Initialize skip list for chunk selections */ + fm->sel_chunks = NULL; + fm->use_single = TRUE; + + /* Initialize single chunk dataspace */ + if(NULL == dataset->shared->cache.chunk.single_space) { + /* Make a copy of the dataspace for the dataset */ + if((dataset->shared->cache.chunk.single_space = H5S_copy(file_space, TRUE, FALSE)) == NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space") + + /* Resize chunk's dataspace dimensions to size of chunk */ + if(H5S_set_extent_real(dataset->shared->cache.chunk.single_space, fm->chunk_dim) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust chunk dimensions") + + /* Set the single chunk dataspace to 'all' selection */ + if(H5S_select_all(dataset->shared->cache.chunk.single_space, TRUE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to set all selection") + } /* end if */ + fm->single_space = dataset->shared->cache.chunk.single_space; + HDassert(fm->single_space); + + /* Allocate the single chunk information */ + if(NULL == dataset->shared->cache.chunk.single_chunk_info) { + if(NULL == (dataset->shared->cache.chunk.single_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") + } /* end if */ + fm->single_chunk_info = dataset->shared->cache.chunk.single_chunk_info; + HDassert(fm->single_chunk_info); + + /* Reset chunk template information */ + fm->mchunk_tmpl = NULL; + + /* Set up chunk mapping for single element */ + if(H5D_create_chunk_map_single(fm, io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create chunk selections for single element") + } /* end if */ + else { + /* Initialize skip list for chunk selections */ + if(NULL == dataset->shared->cache.chunk.sel_chunks) { + if(NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE, 0.5, (size_t)H5D_DEFAULT_SKIPLIST_HEIGHT))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for chunk selections") + } /* end if */ + fm->sel_chunks = dataset->shared->cache.chunk.sel_chunks; + HDassert(fm->sel_chunks); + + /* We are not using single element mode */ + fm->use_single = FALSE; + + /* Get type of selection on disk & in memory */ + if((fsel_type = H5S_GET_SELECT_TYPE(file_space)) < H5S_SEL_NONE) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") + if((fm->msel_type = H5S_GET_SELECT_TYPE(mem_space)) < H5S_SEL_NONE) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") + + /* If the selection is NONE or POINTS, set the flag to FALSE */ + if(fsel_type == H5S_SEL_POINTS || fsel_type == H5S_SEL_NONE) + sel_hyper_flag = FALSE; + else + sel_hyper_flag = TRUE; + + /* Check if file selection is a not a hyperslab selection */ + if(sel_hyper_flag) { + /* Build the file selection for each chunk */ + if(H5D_create_chunk_file_map_hyper(fm, io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") + + /* Clean file chunks' hyperslab span "scratch" information */ + curr_node = H5SL_first(fm->sel_chunks); + while(curr_node) { + H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ + + /* Get pointer to chunk's information */ + chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(chunk_info); + + /* Clean hyperslab span's "scratch" information */ + if(H5S_hyper_reset_scratch(chunk_info->fspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") + + /* Get the next chunk node in the skip list */ + curr_node = H5SL_next(curr_node); + } /* end while */ + } /* end if */ + else { + /* Create temporary datatypes for selection iteration */ + if((f_tid = H5I_register(H5I_DATATYPE, H5T_copy(dataset->shared->type, H5T_COPY_ALL))) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register file datatype") + + /* Spaces might not be the same shape, iterate over the file selection directly */ + if(H5S_select_iterate(&bogus, f_tid, file_space, H5D_chunk_file_cb, fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") + + /* Reset "last chunk" info */ + fm->last_index = (hsize_t)-1; + fm->last_chunk_info = NULL; + } /* end else */ + + /* Build the memory selection for each chunk */ + if(sel_hyper_flag && H5S_select_shape_same(file_space, mem_space) == TRUE) { + /* Reset chunk template information */ + fm->mchunk_tmpl = NULL; + + /* If the selections are the same shape, use the file chunk information + * to generate the memory chunk information quickly. + */ + if(H5D_create_chunk_mem_map_hyper(fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") + } /* end if */ + else { + size_t elmt_size; /* Memory datatype size */ + + /* Make a copy of equivalent memory space */ + if((tmp_mspace = H5S_copy(mem_space, TRUE, FALSE)) == NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") + + /* De-select the mem space copy */ + if(H5S_select_none(tmp_mspace) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select memory space") + + /* Save chunk template information */ + fm->mchunk_tmpl = tmp_mspace; + + /* Create temporary datatypes for selection iteration */ + if(f_tid < 0) { + if((f_tid = H5I_register(H5I_DATATYPE, H5T_copy(dataset->shared->type, H5T_COPY_ALL))) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register file datatype") + } /* end if */ + + /* Create selection iterator for memory selection */ + if(0 == (elmt_size = H5T_get_size(mem_type))) + 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 = TRUE; /* Selection iteration info has been initialized */ + + /* Spaces aren't the same shape, iterate over the memory selection directly */ + if(H5S_select_iterate(&bogus, f_tid, file_space, H5D_chunk_mem_cb, fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") + + /* Clean up hyperslab stuff, if necessary */ + if(fm->msel_type != H5S_SEL_POINTS) { + /* Clean memory chunks' hyperslab span "scratch" information */ + curr_node = H5SL_first(fm->sel_chunks); + while(curr_node) { + H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ + + /* Get pointer to chunk's information */ + chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(chunk_info); + + /* Clean hyperslab span's "scratch" information */ + if(H5S_hyper_reset_scratch(chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") + + /* Get the next chunk node in the skip list */ + curr_node = H5SL_next(curr_node); + } /* end while */ + } /* end if */ + } /* end else */ + } /* end else */ + +done: + /* Release the [potentially partially built] chunk mapping information if an error occurs */ + if(ret_value < 0) { + if(tmp_mspace && !fm->mchunk_tmpl) { + if(H5S_close(tmp_mspace) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template") + } /* end if */ + + if(H5D_chunk_io_term(fm) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping") + } /* end if */ + + /* Reset the global dataspace info */ + fm->file_space = NULL; + fm->mem_space = NULL; + + if(iter_init) { + if(H5S_SELECT_ITER_RELEASE(&(fm->mem_iter)) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") + } /* end if */ + if(f_tid!=(-1)) { + if(H5I_dec_ref(f_tid) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID") + } /* end if */ + if(file_space_normalized) { + if(H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_chunk_io_init() */ + + +/*-------------------------------------------------------------------------- + NAME + H5D_free_chunk_info + PURPOSE + Internal routine to destroy a chunk info node + USAGE + void H5D_free_chunk_info(chunk_info) + void *chunk_info; IN: Pointer to chunk info to destroy + RETURNS + No return value + DESCRIPTION + Releases all the memory for a chunk info node. Called by H5SL_free + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5D_free_chunk_info(void *item, void UNUSED *key, void UNUSED *opdata) +{ + H5D_chunk_info_t *chunk_info = (H5D_chunk_info_t *)item; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_free_chunk_info) + + HDassert(chunk_info); + + /* Close the chunk's file dataspace, if it's not shared */ + if(!chunk_info->fspace_shared) + (void)H5S_close(chunk_info->fspace); + else + H5S_select_all(chunk_info->fspace, TRUE); + + /* Close the chunk's memory dataspace, if it's not shared */ + if(!chunk_info->mspace_shared) + (void)H5S_close(chunk_info->mspace); + + /* Free the actual chunk info */ + H5FL_FREE(H5D_chunk_info_t, chunk_info); + + FUNC_LEAVE_NOAPI(0) +} /* H5D_free_chunk_info() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_create_chunk_map_single + * + * Purpose: Create chunk selections when appending a single record + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, November 20, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t +#ifndef H5_HAVE_PARALLEL + UNUSED +#endif /* H5_HAVE_PARALLEL */ + *io_info) +{ + H5D_chunk_info_t *chunk_info; /* Chunk information to insert into skip list */ + hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ + hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_create_chunk_map_single) + + /* Sanity check */ + HDassert(fm->f_ndims > 0); + + /* Get coordinate for selection */ + if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") + + /* Initialize the 'single chunk' file & memory chunk information */ + chunk_info = fm->single_chunk_info; + chunk_info->chunk_points = 1; + + /* Set chunk location & hyperslab size */ + for(u = 0; u < fm->f_ndims; u++) { + HDassert(sel_start[u] == sel_end[u]); + chunk_info->coords[u] = (sel_start[u] / fm->layout->u.chunk.dim[u]) * fm->layout->u.chunk.dim[u]; + } /* end for */ + chunk_info->coords[fm->f_ndims] = 0; + + /* Calculate the index of this chunk */ + if(H5V_chunk_index(fm->f_ndims, chunk_info->coords, fm->layout->u.chunk.dim, fm->down_chunks, &chunk_info->index) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") + + /* Copy selection for file's dataspace into chunk dataspace */ + if(H5S_select_copy(fm->single_space, fm->file_space, FALSE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file selection") + + /* Move selection back to have correct offset in chunk */ + if(H5S_SELECT_ADJUST_U(fm->single_space, chunk_info->coords) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") + +#ifdef H5_HAVE_PARALLEL + /* store chunk selection information */ + if(io_info->using_mpi_vfd) + fm->select_chunk[chunk_info->index] = chunk_info; +#endif /* H5_HAVE_PARALLEL */ + + /* Set the file dataspace for the chunk to the shared 'single' dataspace */ + chunk_info->fspace = fm->single_space; + + /* Indicate that the chunk's file dataspace is shared */ + chunk_info->fspace_shared = TRUE; + + /* Just point at the memory dataspace & selection */ + /* (Casting away const OK -QAK) */ + chunk_info->mspace = (H5S_t *)fm->mem_space; + + /* Indicate that the chunk's memory dataspace is shared */ + chunk_info->mspace_shared = TRUE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_create_chunk_map_single() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_create_chunk_file_map_hyper + * + * Purpose: Create all chunk selections in file. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, May 29, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t +#ifndef H5_HAVE_PARALLEL + UNUSED +#endif /* H5_HAVE_PARALLEL */ + *io_info) +{ + hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ + hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ + hsize_t sel_points; /* Number of elements in file selection */ + hsize_t start_coords[H5O_LAYOUT_NDIMS]; /* Starting coordinates of selection */ + hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */ + hsize_t end[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */ + hsize_t chunk_index; /* Index of chunk */ + int curr_dim; /* Current dimension to increment */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_create_chunk_file_map_hyper) + + /* Sanity check */ + assert(fm->f_ndims>0); + + /* Get number of elements selected in file */ + sel_points = fm->nelmts; + + /* Get bounding box for selection (to reduce the number of chunks to iterate over) */ + if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") + + /* Set initial chunk location & hyperslab size */ + + for(u=0; uf_ndims; u++) { + start_coords[u]=(sel_start[u]/fm->layout->u.chunk.dim[u])*fm->layout->u.chunk.dim[u]; + coords[u]=start_coords[u]; + end[u]=(coords[u]+fm->chunk_dim[u])-1; + } /* end for */ + + + /* Calculate the index of this chunk */ + if(H5V_chunk_index(fm->f_ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") + + /* Iterate through each chunk in the dataset */ + while(sel_points) { + /* Check for intersection of temporary chunk and file selection */ + /* (Casting away const OK - QAK) */ + if(H5S_hyper_intersect_block((H5S_t *)fm->file_space,coords,end)==TRUE) { + H5S_t *tmp_fchunk; /* Temporary file dataspace */ + H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */ + hssize_t schunk_points; /* Number of elements in chunk selection */ + + /* Create "temporary" chunk for selection operations (copy file space) */ + if((tmp_fchunk = H5S_copy(fm->file_space, TRUE, FALSE)) == NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") + + /* Make certain selections are stored in span tree form (not "optimized hyperslab" or "all") */ + if(H5S_hyper_convert(tmp_fchunk) < 0) { + (void)H5S_close(tmp_fchunk); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to convert selection to span trees") + } /* end if */ + + /* "AND" temporary chunk and current chunk */ + if(H5S_select_hyperslab(tmp_fchunk,H5S_SELECT_AND,coords,NULL,fm->chunk_dim,NULL) < 0) { + (void)H5S_close(tmp_fchunk); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create chunk selection") + } /* end if */ + + /* Resize chunk's dataspace dimensions to size of chunk */ + if(H5S_set_extent_real(tmp_fchunk,fm->chunk_dim) < 0) { + (void)H5S_close(tmp_fchunk); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk dimensions") + } /* end if */ + + /* Move selection back to have correct offset in chunk */ + if(H5S_SELECT_ADJUST_U(tmp_fchunk, coords) < 0) { + (void)H5S_close(tmp_fchunk); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") + } /* end if */ + + /* Add temporary chunk to the list of chunks */ + + /* Allocate the file & memory chunk information */ + if (NULL==(new_chunk_info = H5FL_MALLOC (H5D_chunk_info_t))) { + (void)H5S_close(tmp_fchunk); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") + } /* end if */ + + /* Initialize the chunk information */ + + /* Set the chunk index */ + new_chunk_info->index=chunk_index; + +#ifdef H5_HAVE_PARALLEL + /* store chunk selection information */ + if(io_info->using_mpi_vfd) + fm->select_chunk[chunk_index] = new_chunk_info; +#endif /* H5_HAVE_PARALLEL */ + + /* Set the file chunk dataspace */ + new_chunk_info->fspace = tmp_fchunk; + new_chunk_info->fspace_shared = FALSE; + + /* Set the memory chunk dataspace */ + new_chunk_info->mspace=NULL; + new_chunk_info->mspace_shared = FALSE; + + /* Copy the chunk's coordinates */ + for(u=0; uf_ndims; u++) + new_chunk_info->coords[u]=coords[u]; + new_chunk_info->coords[fm->f_ndims]=0; + + /* Insert the new chunk into the skip list */ + if(H5SL_insert(fm->sel_chunks,new_chunk_info,&new_chunk_info->index) < 0) { + H5D_free_chunk_info(new_chunk_info,NULL,NULL); + HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert chunk into skip list") + } /* end if */ + + /* Get number of elements selected in chunk */ + if((schunk_points=H5S_GET_SELECT_NPOINTS(tmp_fchunk)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection # of elements") + H5_ASSIGN_OVERFLOW(new_chunk_info->chunk_points,schunk_points,hssize_t,size_t); + + /* Decrement # of points left in file selection */ + sel_points-=(hsize_t)schunk_points; + + /* Leave if we are done */ + if(sel_points==0) + HGOTO_DONE(SUCCEED) + assert(sel_points>0); + } /* end if */ + + /* Increment chunk index */ + chunk_index++; + + /* Set current increment dimension */ + curr_dim=(int)fm->f_ndims-1; + + /* Increment chunk location in fastest changing dimension */ + H5_CHECK_OVERFLOW(fm->chunk_dim[curr_dim],hsize_t,hssize_t); + coords[curr_dim]+=fm->chunk_dim[curr_dim]; + end[curr_dim]+=fm->chunk_dim[curr_dim]; + + /* Bring chunk location back into bounds, if necessary */ + if(coords[curr_dim]>sel_end[curr_dim]) { + do { + /* Reset current dimension's location to 0 */ + coords[curr_dim]=start_coords[curr_dim]; /*lint !e771 The start_coords will always be initialized */ + end[curr_dim]=(coords[curr_dim]+(hssize_t)fm->chunk_dim[curr_dim])-1; + + /* Decrement current dimension */ + curr_dim--; + + /* Increment chunk location in current dimension */ + coords[curr_dim]+=fm->chunk_dim[curr_dim]; + end[curr_dim]=(coords[curr_dim]+fm->chunk_dim[curr_dim])-1; + } while(coords[curr_dim]>sel_end[curr_dim]); + + /* Re-Calculate the index of this chunk */ + if(H5V_chunk_index(fm->f_ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") + } /* end if */ + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_create_chunk_file_map_hyper() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_create_chunk_mem_map_hyper + * + * Purpose: Create all chunk selections in memory by copying the file + * chunk selections and adjusting their offsets to be correct + * for the memory. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, May 29, 2003 + * + * Assumptions: That the file and memory selections are the same shape. + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) +{ + H5SL_node_t *curr_node; /* Current node in skip list */ + hsize_t file_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ + hsize_t file_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ + hsize_t mem_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ + hsize_t mem_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ + hssize_t adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to all file chunks */ + hssize_t chunk_adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to a particular chunk */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_create_chunk_mem_map_hyper) + + /* Sanity check */ + assert(fm->f_ndims>0); + + /* Check for all I/O going to a single chunk */ + if(H5SL_count(fm->sel_chunks)==1) { + H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + + /* Get the node */ + curr_node=H5SL_first(fm->sel_chunks); + + /* Get pointer to chunk's information */ + chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + assert(chunk_info); + + /* Just point at the memory dataspace & selection */ + /* (Casting away const OK -QAK) */ + chunk_info->mspace=(H5S_t *)fm->mem_space; + + /* Indicate that the chunk's memory space is shared */ + chunk_info->mspace_shared = TRUE; + } /* end if */ + else { + /* Get bounding box for file selection */ + if(H5S_SELECT_BOUNDS(fm->file_space, file_sel_start, file_sel_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") + + /* Get bounding box for memory selection */ + if(H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") + + /* Calculate the adjustment for memory selection from file selection */ + assert(fm->m_ndims==fm->f_ndims); + for(u=0; uf_ndims; u++) { + H5_CHECK_OVERFLOW(file_sel_start[u],hsize_t,hssize_t); + H5_CHECK_OVERFLOW(mem_sel_start[u],hsize_t,hssize_t); + adjust[u]=(hssize_t)file_sel_start[u]-(hssize_t)mem_sel_start[u]; + } /* end for */ + + /* Iterate over each chunk in the chunk list */ + curr_node=H5SL_first(fm->sel_chunks); + while(curr_node) { + H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + + /* Get pointer to chunk's information */ + chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + assert(chunk_info); + + /* Copy the information */ + + /* Copy the memory dataspace */ + if((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") + + /* Release the current selection */ + if(H5S_SELECT_RELEASE(chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection") + + /* Copy the file chunk's selection */ + if(H5S_select_copy(chunk_info->mspace,chunk_info->fspace,FALSE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection") + + /* Compensate for the chunk offset */ + for(u=0; uf_ndims; u++) { + H5_CHECK_OVERFLOW(chunk_info->coords[u],hsize_t,hssize_t); + chunk_adjust[u]=adjust[u]-(hssize_t)chunk_info->coords[u]; /*lint !e771 The adjust array will always be initialized */ + } /* end for */ + + /* Adjust the selection */ + if(H5S_hyper_adjust_s(chunk_info->mspace,chunk_adjust) < 0) /*lint !e772 The chunk_adjust array will always be initialized */ + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") + + /* Get the next chunk node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_create_chunk_mem_map_hyper() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_file_cb + * + * Purpose: Callback routine for file selection iterator. Used when + * creating selections in file for each point selected. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, July 23, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_chunk_file_cb(void UNUSED *elem, hid_t UNUSED type_id, unsigned ndims, const hsize_t *coords, void *_fm) +{ + H5D_chunk_map_t *fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */ + H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */ + hsize_t coords_in_chunk[H5O_LAYOUT_NDIMS]; /* Coordinates of element in chunk */ + hsize_t chunk_index; /* Chunk index */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_file_cb) + + /* Calculate the index of this chunk */ + if(H5V_chunk_index(ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") + + /* Find correct chunk in file & memory skip list */ + if(chunk_index==fm->last_index) { + /* If the chunk index is the same as the last chunk index we used, + * get the cached info to operate on. + */ + chunk_info=fm->last_chunk_info; + } /* end if */ + else { + /* If the chunk index is not the same as the last chunk index we used, + * find the chunk in the skip list. + */ + /* Get the chunk node from the skip list */ + if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) { + H5S_t *fspace; /* Memory chunk's dataspace */ + + /* Allocate the file & memory chunk information */ + if (NULL==(chunk_info = H5FL_MALLOC (H5D_chunk_info_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") + + /* Initialize the chunk information */ + + /* Set the chunk index */ + chunk_info->index=chunk_index; + + /* Create a dataspace for the chunk */ + if((fspace = H5S_create_simple(fm->f_ndims,fm->chunk_dim,NULL))==NULL) { + H5FL_FREE(H5D_chunk_info_t,chunk_info); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create dataspace for chunk") + } /* end if */ + + /* De-select the chunk space */ + if(H5S_select_none(fspace) < 0) { + (void)H5S_close(fspace); + H5FL_FREE(H5D_chunk_info_t,chunk_info); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select dataspace") + } /* end if */ + + /* Set the file chunk dataspace */ + chunk_info->fspace = fspace; + chunk_info->fspace_shared = FALSE; + + /* Set the memory chunk dataspace */ + chunk_info->mspace=NULL; + chunk_info->mspace_shared = FALSE; + + /* Set the number of selected elements in chunk to zero */ + chunk_info->chunk_points=0; + + /* Compute the chunk's coordinates */ + for(u=0; uf_ndims; u++) { + H5_CHECK_OVERFLOW(fm->layout->u.chunk.dim[u],hsize_t,hssize_t); + chunk_info->coords[u]=(coords[u]/(hssize_t)fm->layout->u.chunk.dim[u])*(hssize_t)fm->layout->u.chunk.dim[u]; + } /* end for */ + chunk_info->coords[fm->f_ndims]=0; + + /* Insert the new chunk into the skip list */ + if(H5SL_insert(fm->sel_chunks,chunk_info,&chunk_info->index) < 0) { + H5D_free_chunk_info(chunk_info,NULL,NULL); + HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert chunk into skip list") + } /* end if */ + } /* end if */ + + /* Update the "last chunk seen" information */ + fm->last_index=chunk_index; + fm->last_chunk_info=chunk_info; + } /* end else */ + + /* Get the coordinates of the element in the chunk */ + for(u=0; uf_ndims; u++) + coords_in_chunk[u]=coords[u]%fm->layout->u.chunk.dim[u]; + + /* Add point to file selection for chunk */ + if(H5S_select_elements(chunk_info->fspace, H5S_SELECT_APPEND, (size_t)1, coords_in_chunk) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") + + /* Increment the number of elemented selected in chunk */ + chunk_info->chunk_points++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_chunk_file_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_mem_cb + * + * Purpose: Callback routine for file selection iterator. Used when + * creating selections in memory for each chunk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Raymond Lu + * Thursday, April 10, 2003 + * + *------------------------------------------------------------------------- + */ +/* ARGSUSED */ +static herr_t +H5D_chunk_mem_cb(void UNUSED *elem, hid_t UNUSED type_id, unsigned ndims, const hsize_t *coords, void *_fm) +{ + H5D_chunk_map_t *fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */ + H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */ + hsize_t coords_in_mem[H5O_LAYOUT_NDIMS]; /* Coordinates of element in memory */ + hsize_t chunk_index; /* Chunk index */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_mem_cb) + + /* Calculate the index of this chunk */ + if(H5V_chunk_index(ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") + + /* Find correct chunk in file & memory skip list */ + 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. + */ + chunk_info=fm->last_chunk_info; + } /* end if */ + else { + /* If the chunk index is not the same as the last chunk index we used, + * find the chunk in the skip list. + */ + /* Get the chunk node from the skip list */ + if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) + HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, FAIL, "can't locate chunk in skip list") + + /* Check if the chunk already has a memory space */ + if(chunk_info->mspace==NULL) { + /* Copy the template memory chunk dataspace */ + if((chunk_info->mspace = H5S_copy(fm->mchunk_tmpl, FALSE, FALSE)) == NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space") + } /* end else */ + + /* Update the "last chunk seen" information */ + fm->last_index=chunk_index; + fm->last_chunk_info=chunk_info; + } /* end else */ + + /* 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") + + /* Add point to memory selection for chunk */ + if(fm->msel_type==H5S_SEL_POINTS) { + if(H5S_select_elements(chunk_info->mspace, H5S_SELECT_APPEND, (size_t)1, coords_in_mem) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") + } /* end if */ + else { + if(H5S_hyper_add_span_element(chunk_info->mspace, fm->m_ndims, coords_in_mem) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") + } /* end else */ + + /* Move memory selection iterator to next element in selection */ + if(H5S_SELECT_ITER_NEXT(&fm->mem_iter, (size_t)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_mem_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_cacheable + * + * Purpose: A small internal function to if it's possible to load the + * chunk into cache. + * + * Return: TRUE or FALSE + * + * Programmer: Raymond Lu + * 17 July 2007 + * + *------------------------------------------------------------------------- + */ +hbool_t +H5D_chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr) +{ + const H5D_t *dataset = io_info->dset; + hbool_t ret_value; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_chunk_cacheable) + + HDassert(io_info); + HDassert(dataset); + + /* Must bring the whole chunk in if there are any filters */ + if(dataset->shared->dcpl_cache.pline.nused > 0) + ret_value = TRUE; + else +#ifdef H5_HAVE_PARALLEL + /* If MPI based VFD is used and the file is opened for write access, must + * bypass the chunk-cache scheme because other MPI processes could + * be writing to other elements in the same chunk. Do a direct + * write-through of only the elements requested. + */ + if(io_info->using_mpi_vfd && (H5F_ACC_RDWR & H5F_INTENT(dataset->oloc.file))) + ret_value = FALSE; + else +#endif /* H5_HAVE_PARALLEL */ + /* If the chunk is too large to keep in the cache and if the address + * for the chunk has been defined, then don't load the chunk into the + * cache, just write the data to it directly. + */ + if(dataset->shared->layout.u.chunk.size > dataset->shared->cache.chunk.nbytes + && H5F_addr_defined(caddr)) + ret_value = FALSE; + else + ret_value = TRUE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_chunk_cacheable() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_in_cache + * + * Purpose: Check if a chunk is in the cache. + * + * Return: TRUE or FALSE + * + * Programmer: Quincey Koziol + * 1 April 2008 + * + *------------------------------------------------------------------------- + */ +static hbool_t +H5D_chunk_in_cache(const H5D_io_info_t *io_info) +{ + H5D_rdcc_t *rdcc = &(io_info->dset->shared->cache.chunk);/*raw data chunk cache*/ + hbool_t found = FALSE; /*already in cache? */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_chunk_in_cache) + + HDassert(io_info); + + /* Check if the chunk is in the cache (but hasn't been written to disk yet) */ + if(rdcc->nslots > 0) { + unsigned idx = H5D_CHUNK_HASH(io_info->dset->shared, io_info->store->chunk.index); /* Cache entry index */ + H5D_rdcc_ent_t *ent = rdcc->slot[idx]; /* Cache entry */ + + /* Potential match... */ + if(ent) { + size_t u; /* Local index variable */ + + for(u = 0, found = TRUE; u < io_info->dset->shared->layout.u.chunk.ndims; u++) { + if(io_info->store->chunk.offset[u] != ent->offset[u]) { + found = FALSE; + break; + } /* end if */ + } /* end for */ + } /* end if */ + } /* end if */ + + FUNC_LEAVE_NOAPI(found) +} /* end H5D_chunk_in_cache() */ + + +/*------------------------------------------------------------------------- + * 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 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t UNUSED nelmts, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space, + H5D_chunk_map_t *fm) +{ + H5SL_node_t *chunk_node; /* Current node in chunk skip list */ + H5D_io_info_t nul_io_info; /* "null" I/O info object */ + H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ + H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ + H5D_io_info_t cpt_io_info; /* Compact I/O info object */ + H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */ + hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ + size_t src_accessed_bytes = 0; /* Total accessed size in a chunk */ + hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */ + unsigned idx_hint = 0; /* Cache index hint */ + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_read) + + /* Sanity check */ + HDassert(io_info); + HDassert(io_info->u.rbuf); + HDassert(type_info); + HDassert(fm); + + /* Set up "null" I/O info object */ + HDmemcpy(&nul_io_info, io_info, sizeof(nul_io_info)); + nul_io_info.layout_ops = *H5D_LOPS_NULL; + + /* Set up contiguous I/O info object */ + HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); + ctg_io_info.store = &ctg_store; + ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + + /* Initialize temporary contiguous storage info */ + ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size; + + /* Set up compact I/O info object */ + HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); + cpt_io_info.store = &cpt_store; + cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + + /* Initialize temporary compact storage info */ + cpt_store.compact.dirty = &cpt_dirty; + + { + const H5O_fill_t *fill = &(io_info->dset->shared->dcpl_cache.fill); /* Fill value info */ + H5D_fill_value_t fill_status; /* Fill value status */ + + /* Check the fill value status */ + if(H5P_is_fill_value_defined(fill, &fill_status) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined") + + /* If we are never to return fill values, or if we would return them + * but they aren't set, set the flag to skip missing chunks. + */ + if(fill->fill_time == H5D_FILL_TIME_NEVER || + (fill->fill_time == H5D_FILL_TIME_IFSET && fill_status != H5D_FILL_VALUE_USER_DEFINED)) + skip_missing_chunks = TRUE; + } + + /* Iterate through nodes in chunk skip list */ + chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); + while(chunk_node) { + H5D_chunk_info_t *chunk_info; /* Chunk information */ + H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */ + void *chunk; /* Pointer to locked chunk buffer */ + haddr_t chunk_addr; /* Chunk address on disk */ + H5D_istore_ud1_t udata; /* B-tree pass-through */ + + /* Get the actual chunk information from the skip list node */ + chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + + /* Pass in chunk's coordinates in a union. */ + io_info->store->chunk.offset = chunk_info->coords; + io_info->store->chunk.index = chunk_info->index; + + /* Get the address of the chunk in the file */ + chunk_addr = H5D_istore_get_addr(io_info, &udata); + + /* Check for non-existant chunk & skip it if appropriate */ + if(!H5F_addr_defined(chunk_addr) && !H5D_chunk_in_cache(io_info) + && skip_missing_chunks) { + /* No chunk cached */ + chunk = NULL; + + /* Point I/O info at "null" I/O info for this chunk */ + chk_io_info = &nul_io_info; + } /* end if */ + else { + /* Load the chunk into cache and lock it. */ + if(H5D_chunk_cacheable(io_info, chunk_addr)) { + /* Compute # of bytes accessed in chunk */ + src_accessed_bytes = chunk_info->chunk_points * type_info->src_type_size; + + /* Lock the chunk into the cache */ + if(NULL == (chunk = H5D_istore_lock(io_info, &udata, FALSE, &idx_hint))) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") + + /* Set up the storage buffer information for this chunk */ + cpt_store.compact.buf = chunk; + + /* Point I/O info at contiguous I/O info for this chunk */ + chk_io_info = &cpt_io_info; + } /* end if */ + else { + /* Sanity check */ + HDassert(H5F_addr_defined(chunk_addr)); + + /* Set up the storage address information for this chunk */ + ctg_store.contig.dset_addr = chunk_addr; + + /* No chunk cached */ + chunk = NULL; + + /* Point I/O info at temporary I/O info for this chunk */ + chk_io_info = &ctg_io_info; + } /* end else */ + } /* end else */ + + /* Perform the actual read operation */ + if((io_info->io_ops.single_read)(chk_io_info, type_info, + (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed") + + /* Release the cache lock on the chunk. */ + if(chunk && H5D_istore_unlock(io_info, FALSE, idx_hint, chunk, src_accessed_bytes) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") + + /* Advance to next chunk in list */ + chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + } /* end while */ + +done: + 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 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t UNUSED nelmts, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space, + H5D_chunk_map_t *fm) +{ + H5SL_node_t *chunk_node; /* Current node in chunk skip list */ + H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ + H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ + H5D_io_info_t cpt_io_info; /* Compact I/O info object */ + H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */ + hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ + size_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */ + unsigned idx_hint = 0; /* Cache index hint */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_write) + + /* Sanity check */ + HDassert(io_info); + HDassert(io_info->u.wbuf); + HDassert(type_info); + HDassert(fm); + + /* Set up contiguous I/O info object */ + HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); + ctg_io_info.store = &ctg_store; + ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + + /* Initialize temporary contiguous storage info */ + ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size; + + /* Set up compact I/O info object */ + HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); + cpt_io_info.store = &cpt_store; + cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + + /* Initialize temporary compact storage info */ + cpt_store.compact.dirty = &cpt_dirty; + + /* Iterate through nodes in chunk skip list */ + chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); + while(chunk_node) { + H5D_chunk_info_t *chunk_info; /* Chunk information */ + H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */ + void *chunk; /* Pointer to locked chunk buffer */ + haddr_t chunk_addr; /* Chunk address on disk */ + H5D_istore_ud1_t udata; /* B-tree pass-through */ + + /* Get the actual chunk information from the skip list node */ + chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + + /* Pass in chunk's coordinates in a union. */ + io_info->store->chunk.offset = chunk_info->coords; + io_info->store->chunk.index = chunk_info->index; + + /* Load the chunk into cache. But if the whole chunk is written, + * simply allocate space instead of load the chunk. */ + chunk_addr = H5D_istore_get_addr(io_info, &udata); + if(H5D_chunk_cacheable(io_info, chunk_addr)) { + hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */ + + /* Compute # of bytes accessed in chunk */ + dst_accessed_bytes = chunk_info->chunk_points * type_info->dst_type_size; + + /* Determine if we will access all the data in the chunk */ + if(dst_accessed_bytes != ctg_store.contig.dset_size || + (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size) + entire_chunk = FALSE; + + /* Lock the chunk into the cache */ + if(NULL == (chunk = H5D_istore_lock(io_info, &udata, entire_chunk, &idx_hint))) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") + + /* Set up the storage buffer information for this chunk */ + cpt_store.compact.buf = chunk; + + /* Point I/O info at main I/O info for this chunk */ + chk_io_info = &cpt_io_info; + } /* end if */ + else { + /* Sanity check */ + HDassert(H5F_addr_defined(chunk_addr)); + + /* Set up the storage address information for this chunk */ + ctg_store.contig.dset_addr = chunk_addr; + + /* No chunk cached */ + chunk = NULL; + + /* Point I/O info at temporary I/O info for this chunk */ + chk_io_info = &ctg_io_info; + } /* end else */ + + /* Perform the actual write operation */ + if((io_info->io_ops.single_write)(chk_io_info, type_info, + (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed") + + /* Release the cache lock on the chunk. */ + if(chunk && H5D_istore_unlock(io_info, TRUE, idx_hint, chunk, dst_accessed_bytes) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") + + /* Advance to next chunk in list */ + chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_chunk_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_io_term + * + * Purpose: Destroy I/O operation information. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, May 17, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_chunk_io_term(const H5D_chunk_map_t *fm) +{ + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_io_term) + + /* Single element I/O vs. multiple element I/O cleanup */ + if(fm->use_single) { + /* Sanity checks */ + HDassert(fm->sel_chunks == NULL); + HDassert(fm->single_chunk_info); + HDassert(fm->single_chunk_info->fspace_shared); + HDassert(fm->single_chunk_info->mspace_shared); + + /* Reset the selection for the single element I/O */ + H5S_select_all(fm->single_space, TRUE); + } /* end if */ + else { + /* Release the nodes on the list of selected chunks */ + if(fm->sel_chunks) + if(H5SL_free(fm->sel_chunks, H5D_free_chunk_info, NULL) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTNEXT, FAIL, "can't iterate over chunks") + } /* end else */ + + /* 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") +#ifdef H5_HAVE_PARALLEL + if(fm->select_chunk) + H5MM_xfree(fm->select_chunk); +#endif /* H5_HAVE_PARALLEL */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_chunk_io_term() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_null_readvv + * + * Purpose: Performs "no-op" I/O operation, advancing through two I/O + * vectors, until one runs out. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, April 1, 2008 + * + *------------------------------------------------------------------------- + */ +static ssize_t +H5D_null_readvv(const H5D_io_info_t UNUSED *io_info, + size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) +{ + size_t u, v; /* Local index variables */ + size_t size; /* Size of sequence in bytes */ + ssize_t bytes_processed = 0; /* Eventual return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_null_readvv) + + /* Check args */ + HDassert(chunk_len_arr); + HDassert(chunk_offset_arr); + HDassert(mem_len_arr); + HDassert(mem_offset_arr); + + /* Work through all the sequences */ + for(u = *mem_curr_seq, v = *chunk_curr_seq; u < mem_max_nseq && v < chunk_max_nseq; ) { + /* Choose smallest buffer to write */ + if(chunk_len_arr[v] < mem_len_arr[u]) + size = chunk_len_arr[v]; + else + size = mem_len_arr[u]; + + /* Update source information */ + chunk_len_arr[v] -= size; + chunk_offset_arr[v] += size; + if(chunk_len_arr[v] == 0) + v++; + + /* Update destination information */ + mem_len_arr[u] -= size; + mem_offset_arr[u] += size; + if(mem_len_arr[u] == 0) + u++; + + /* Increment number of bytes copied */ + bytes_processed += (ssize_t)size; + } /* end for */ + + /* Update current sequence vectors */ + *mem_curr_seq = u; + *chunk_curr_seq = v; + + FUNC_LEAVE_NOAPI(bytes_processed) +} /* H5D_null_readvv() */ + diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c index 2e4d3f7..c3abab6 100644 --- a/src/H5Dcompact.c +++ b/src/H5Dcompact.c @@ -41,22 +41,52 @@ #include "H5Oprivate.h" /* Object headers */ #include "H5Vprivate.h" /* Vector and array functions */ + /****************/ /* Local Macros */ /****************/ + /******************/ /* Local Typedefs */ /******************/ + /********************/ /* Local Prototypes */ /********************/ +/* Layout operation callbacks */ +static herr_t H5D_compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *cm); +static ssize_t H5D_compact_readvv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]); +static ssize_t H5D_compact_writevv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]); + + /*********************/ /* Package Variables */ /*********************/ +/* Compact storage layout I/O ops */ +const H5D_layout_ops_t H5D_LOPS_COMPACT[1] = {{ + H5D_compact_io_init, + H5D_contig_read, + H5D_contig_write, +#ifdef H5_HAVE_PARALLEL + NULL, + NULL, +#endif /* H5_HAVE_PARALLEL */ + H5D_compact_readvv, + H5D_compact_writevv, + NULL +}}; + + /*******************/ /* Local Variables */ /*******************/ @@ -64,6 +94,7 @@ /* Declare extern the free list to manage blocks of type conversion data */ H5FL_BLK_EXTERN(type_conv); + /*------------------------------------------------------------------------- * Function: H5D_compact_fill @@ -118,6 +149,32 @@ done: /*------------------------------------------------------------------------- + * Function: H5D_compact_io_init + * + * Purpose: Performs initialization before any sort of I/O on the raw data + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 20, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t UNUSED *type_info, + hsize_t UNUSED nelmts, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space, + H5D_chunk_map_t UNUSED *cm) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_compact_io_init) + + io_info->store->compact.buf = io_info->dset->shared->layout.u.compact.buf; + io_info->store->compact.dirty = &io_info->dset->shared->layout.u.compact.dirty; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D_compact_io_init() */ + + +/*------------------------------------------------------------------------- * Function: H5D_compact_readvv * * Purpose: Reads some data vectors from a dataset into a buffer. @@ -135,20 +192,19 @@ done: * *------------------------------------------------------------------------- */ -ssize_t +static ssize_t H5D_compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED addr, void UNUSED *pointer/*in*/, void *buf) + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]) { - ssize_t ret_value; /* Return value */ + ssize_t ret_value; /* Return value */ - FUNC_ENTER_NOAPI(H5D_compact_readvv, FAIL) + FUNC_ENTER_NOAPI_NOINIT(H5D_compact_readvv) - assert(io_info->dset); + HDassert(io_info); /* Use the vectorized memory copy routine to do actual work */ - if((ret_value=H5V_memcpyvv(buf,mem_max_nseq,mem_curr_seq,mem_size_arr,mem_offset_arr,io_info->dset->shared->layout.u.compact.buf,dset_max_nseq,dset_curr_seq,dset_size_arr,dset_offset_arr))<0) + if((ret_value = H5V_memcpyvv(io_info->u.rbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr, io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr)) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed") done: @@ -177,24 +233,23 @@ done: * *------------------------------------------------------------------------- */ -ssize_t +static ssize_t H5D_compact_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED addr, void UNUSED *pointer/*in*/, const void *buf) + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]) { - ssize_t ret_value; /* Return value */ + ssize_t ret_value; /* Return value */ - FUNC_ENTER_NOAPI(H5D_compact_writevv, FAIL) + FUNC_ENTER_NOAPI_NOINIT(H5D_compact_writevv) - assert(io_info->dset); + HDassert(io_info); /* Use the vectorized memory copy routine to do actual work */ - if((ret_value=H5V_memcpyvv(io_info->dset->shared->layout.u.compact.buf,dset_max_nseq,dset_curr_seq,dset_size_arr,dset_offset_arr,buf,mem_max_nseq,mem_curr_seq,mem_size_arr,mem_offset_arr))<0) + if((ret_value = H5V_memcpyvv(io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr, io_info->u.wbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr)) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed") /* Mark the compact dataset's buffer as dirty */ - io_info->dset->shared->layout.u.compact.dirty = TRUE; + *io_info->store->compact.dirty = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) @@ -371,11 +426,11 @@ done: if(H5I_dec_ref(tid_mem) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID") if(buf) - H5FL_BLK_FREE(type_conv, buf); + (void)H5FL_BLK_FREE(type_conv, buf); if(reclaim_buf) - H5FL_BLK_FREE(type_conv, reclaim_buf); + (void)H5FL_BLK_FREE(type_conv, reclaim_buf); if(bkg) - H5FL_BLK_FREE(type_conv, bkg); + (void)H5FL_BLK_FREE(type_conv, bkg); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_compact_copy() */ diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c index bdb8294..1a3fda5 100644 --- a/src/H5Dcontig.c +++ b/src/H5Dcontig.c @@ -45,24 +45,50 @@ #include "H5Pprivate.h" /* Property lists */ #include "H5Vprivate.h" /* Vector and array functions */ + /****************/ /* Local Macros */ /****************/ + /******************/ /* Local Typedefs */ /******************/ + /********************/ /* Local Prototypes */ /********************/ -static herr_t H5D_contig_write(H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, const H5D_storage_t *store, hsize_t offset, size_t size, const void *buf); + +/* Layout operation callbacks */ +static herr_t H5D_contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *cm); + +/* Helper routines */ +static herr_t H5D_contig_write_one(H5D_io_info_t *io_info, hsize_t offset, + size_t size); + /*********************/ /* Package Variables */ /*********************/ +/* Contiguous storage layout I/O ops */ +const H5D_layout_ops_t H5D_LOPS_CONTIG[1] = {{ + H5D_contig_io_init, + H5D_contig_read, + H5D_contig_write, +#ifdef H5_HAVE_PARALLEL + H5D_contig_collective_read, + H5D_contig_collective_write, +#endif /* H5_HAVE_PARALLEL */ + H5D_contig_readvv, + H5D_contig_writevv, + NULL +}}; + + /*******************/ /* Local Variables */ /*******************/ @@ -73,6 +99,7 @@ H5FL_BLK_DEFINE(sieve_buf); /* Declare extern the free list to manage blocks of type conversion data */ H5FL_BLK_EXTERN(type_conv); + /*------------------------------------------------------------------------- * Function: H5D_contig_create @@ -121,7 +148,8 @@ done: herr_t H5D_contig_fill(H5D_t *dset, hid_t dxpl_id) { - H5D_storage_t store; /* Union of storage info for dataset */ + H5D_io_info_t ioinfo; /* Dataset I/O info */ + H5D_storage_t store; /* Union of storage info for dataset */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ hssize_t snpoints; /* Number of points in space (for error checking) */ @@ -198,6 +226,9 @@ H5D_contig_fill(H5D_t *dset, hid_t dxpl_id) /* Start at the beginning of the dataset */ offset = 0; + /* Simple setup for dataset I/O info struct */ + H5D_BUILD_IO_INFO_WRT(&ioinfo, dset, dxpl_cache, my_dxpl_id, &store, fb_info.fill_buf); + /* * Fill the entire current extent with the fill value. We can do * this quite efficiently by making sure we copy the fill value @@ -225,7 +256,7 @@ H5D_contig_fill(H5D_t *dset, hid_t dxpl_id) /* Write the chunks out from only one process */ /* !! Use the internal "independent" DXPL!! -QAK */ if(H5_PAR_META_WRITE == mpi_rank) - if(H5D_contig_write(dset, dxpl_cache, my_dxpl_id, &store, offset, size, fb_info.fill_buf) < 0) + if(H5D_contig_write_one(&ioinfo, offset, size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset") /* Indicate that blocks are being written */ @@ -234,7 +265,7 @@ H5D_contig_fill(H5D_t *dset, hid_t dxpl_id) else { #endif /* H5_HAVE_PARALLEL */ H5_CHECK_OVERFLOW(size, size_t, hsize_t); - if(H5D_contig_write(dset, dxpl_cache, my_dxpl_id, &store, offset, size, fb_info.fill_buf) < 0) + if(H5D_contig_write_one(&ioinfo, offset, size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset") #ifdef H5_HAVE_PARALLEL } /* end else */ @@ -324,8 +355,108 @@ H5D_contig_get_addr(const H5D_t *dset) /*------------------------------------------------------------------------- + * Function: H5D_contig_io_init + * + * Purpose: Performs initialization before any sort of I/O on the raw data + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 20, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t UNUSED *type_info, + hsize_t UNUSED nelmts, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space, + H5D_chunk_map_t UNUSED *cm) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_contig_io_init) + + io_info->store->contig.dset_addr = io_info->dset->shared->layout.u.contig.addr; + io_info->store->contig.dset_size = io_info->dset->shared->layout.u.contig.size; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D_contig_io_init() */ + + +/*------------------------------------------------------------------------- + * 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 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D_contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t UNUSED *fm) +{ + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_read) + + /* Sanity check */ + HDassert(io_info); + HDassert(io_info->u.rbuf); + HDassert(type_info); + HDassert(mem_space); + HDassert(file_space); + + /* Read data */ + if((io_info->io_ops.single_read)(io_info, type_info, nelmts, file_space, mem_space) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous read failed") + +done: + 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 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D_contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t UNUSED *fm) +{ + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_write) + + /* Sanity check */ + HDassert(io_info); + HDassert(io_info->u.wbuf); + HDassert(type_info); + HDassert(mem_space); + HDassert(file_space); + + /* Write data */ + if((io_info->io_ops.single_write)(io_info, type_info, nelmts, file_space, mem_space) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous write failed") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_contig_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_contig_write_one + * * Purpose: Writes some data from a dataset into a buffer. * The data is contiguous. The address is relative to the base * address for the file. @@ -338,34 +469,27 @@ H5D_contig_get_addr(const H5D_t *dset) *------------------------------------------------------------------------- */ static herr_t -H5D_contig_write(H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, const H5D_storage_t *store, - hsize_t offset, size_t size, const void *buf) +H5D_contig_write_one(H5D_io_info_t *io_info, hsize_t offset, size_t size) { - H5D_io_info_t io_info; /* Dataset I/O info */ - hsize_t dset_off=offset; /* Offset in dataset */ - size_t dset_len=size; /* Length in dataset */ - size_t dset_curr_seq=0; /* "Current sequence" in dataset */ - hsize_t mem_off=0; /* Offset in memory */ - size_t mem_len=size; /* Length in memory */ - size_t mem_curr_seq=0; /* "Current sequence" in memory */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_contig_write, FAIL) - - assert (dset); - assert (dxpl_cache); - assert (store); - assert (buf); - - H5D_BUILD_IO_INFO(&io_info,dset,dxpl_cache,dxpl_id,store); - if(H5D_contig_writevv(&io_info, (size_t)1, &dset_curr_seq, &dset_len, &dset_off, - (size_t)1, &mem_curr_seq, &mem_len, &mem_off, (haddr_t)0, NULL, buf) < 0) + hsize_t dset_off = offset; /* Offset in dataset */ + size_t dset_len = size; /* Length in dataset */ + size_t dset_curr_seq = 0; /* "Current sequence" in dataset */ + hsize_t mem_off = 0; /* Offset in memory */ + size_t mem_len = size; /* Length in memory */ + size_t mem_curr_seq = 0; /* "Current sequence" in memory */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_write_one) + + HDassert(io_info); + + if(H5D_contig_writevv(io_info, (size_t)1, &dset_curr_seq, &dset_len, &dset_off, + (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vector write failed") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_contig_write() */ +} /* end H5D_contig_write_one() */ /*------------------------------------------------------------------------- @@ -389,67 +513,76 @@ done: ssize_t H5D_contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED address, void UNUSED *pointer, void *_buf) + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) { H5F_t *file = io_info->dset->oloc.file; /* File for dataset */ - H5D_rdcdc_t *dset_contig=&(io_info->dset->shared->cache.contig); /* Cached information about contiguous data */ - const H5D_contig_storage_t *store_contig=&(io_info->store->contig); /* Contiguous storage info for this I/O operation */ - unsigned char *buf=(unsigned char *)_buf; /* Pointer to buffer to fill */ + H5D_rdcdc_t *dset_contig = &(io_info->dset->shared->cache.contig); /* Cached information about contiguous data */ + const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ + unsigned char *buf = (unsigned char *)io_info->u.rbuf; /* Pointer to buffer to fill */ haddr_t addr; /* Actual address to read */ - size_t total_size=0; /* Total size of sequence in bytes */ + size_t total_size = 0; /* Total size of sequence in bytes */ size_t size; /* Size of sequence in bytes */ size_t u; /* Counting variable */ size_t v; /* Counting variable */ ssize_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5D_contig_readvv, FAIL) +#ifdef QAK +HDfprintf(stderr, "%s: dset_max_nseq = %Zu\n", FUNC, dset_max_nseq); +HDfprintf(stderr, "%s: mem_max_nseq = %Zu\n", FUNC, mem_max_nseq); +HDfprintf(stderr, "%s: *dset_curr_seq= %Zu\n", FUNC, *dset_curr_seq); +HDfprintf(stderr, "%s: *mem_curr_seq= %Zu\n", FUNC, *mem_curr_seq); +for(u = 0; u < dset_max_nseq; u++) + HDfprintf(stderr, "%s: dset_len_arr[%Zu] = %Zu, dset_offset_arr[%Zu] = %Hu\n", FUNC, u, dset_len_arr[u], u, dset_offset_arr[u]); +for(u = 0; u < mem_max_nseq; u++) + HDfprintf(stderr, "%s: mem_len_arr[%Zu] = %Zu, mem_offset_arr[%Zu] = %Hu\n", FUNC, u, mem_len_arr[u], u, mem_offset_arr[u]); +#endif /* QAK */ /* Check args */ - assert(io_info); - assert(io_info->dset); - assert(io_info->store); - assert(buf); + HDassert(io_info); + HDassert(io_info->dset); + HDassert(io_info->store); + HDassert(buf); /* Check if data sieving is enabled */ - if(H5F_HAS_FEATURE(file,H5FD_FEAT_DATA_SIEVE)) { - haddr_t sieve_start=HADDR_UNDEF, sieve_end=HADDR_UNDEF; /* Start & end locations of sieve buffer */ + if(H5F_HAS_FEATURE(file, H5FD_FEAT_DATA_SIEVE)) { + haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */ haddr_t contig_end; /* End locations of block to write */ - size_t sieve_size=(size_t)-1; /* size of sieve buffer */ + size_t sieve_size = (size_t)-1; /* size of sieve buffer */ haddr_t abs_eoa; /* Absolute end of file address */ haddr_t rel_eoa; /* Relative end of file address */ hsize_t max_data; /* Actual maximum size of data to cache */ /* Set offsets in sequence lists */ - u=*dset_curr_seq; - v=*mem_curr_seq; + u = *dset_curr_seq; + v = *mem_curr_seq; /* Stash local copies of these value */ - if(dset_contig->sieve_buf!=NULL) { - sieve_start=dset_contig->sieve_loc; - sieve_size=dset_contig->sieve_size; - sieve_end=sieve_start+sieve_size; + if(dset_contig->sieve_buf != NULL) { + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start+sieve_size; } /* end if */ /* Works through sequences as fast as possible */ - for(; udset_addr+dset_offset_arr[u]; + addr = store_contig->dset_addr + dset_offset_arr[u]; /* Compute offset in memory */ - buf = (unsigned char *)_buf + mem_offset_arr[v]; + buf = (unsigned char *)io_info->u.rbuf + mem_offset_arr[v]; /* Check if the sieve buffer is allocated yet */ - if(dset_contig->sieve_buf==NULL) { + if(dset_contig->sieve_buf == NULL) { /* Check if we can actually hold the I/O request in the sieve buffer */ if(size>dset_contig->sieve_buf_size) { - if (H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf)<0) + if(H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") } /* end if */ else { @@ -465,40 +598,40 @@ H5D_contig_readvv(const H5D_io_info_t *io_info, HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to determine file size") /* Adjust absolute EOA address to relative EOA address */ - rel_eoa=abs_eoa-H5F_get_base_addr(file); + rel_eoa = abs_eoa - H5F_get_base_addr(file); /* Set up the buffer parameters */ - max_data=store_contig->dset_size-dset_offset_arr[u]; + max_data = store_contig->dset_size-dset_offset_arr[u]; /* Compute the size of the sieve buffer */ - H5_ASSIGN_OVERFLOW(dset_contig->sieve_size,MIN3(rel_eoa-dset_contig->sieve_loc,max_data,dset_contig->sieve_buf_size),hsize_t,size_t); + H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa-dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); /* Read the new sieve buffer */ - if (H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, io_info->dxpl_id, dset_contig->sieve_buf)<0) + if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(buf,dset_contig->sieve_buf,size); + HDmemcpy(buf, dset_contig->sieve_buf, size); /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty=0; + dset_contig->sieve_dirty = 0; /* Stash local copies of these value */ - sieve_start=dset_contig->sieve_loc; - sieve_size=dset_contig->sieve_size; - sieve_end=sieve_start+sieve_size; + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start+sieve_size; } /* end else */ } /* end if */ else { /* Compute end of sequence to retrieve */ - contig_end=addr+size-1; + contig_end = addr + size - 1; /* If entire read is within the sieve buffer, read it from the buffer */ if(addr>=sieve_start && contig_endsieve_buf+(addr-sieve_start); /* Grab the data out of the buffer */ - HDmemcpy(buf,base_sieve_buf,size); + HDmemcpy(buf, base_sieve_buf, size); } /* end if */ /* Entire request is not within this data sieve buffer */ else { @@ -510,16 +643,16 @@ H5D_contig_readvv(const H5D_io_info_t *io_info, /* Flush the sieve buffer, if it's dirty */ if(dset_contig->sieve_dirty) { /* Write to file */ - if (H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, io_info->dxpl_id, dset_contig->sieve_buf)<0) + if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty=0; + dset_contig->sieve_dirty = 0; } /* end if */ } /* end if */ /* Read directly into the user's buffer */ - if (H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf)<0) + if(H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") } /* end if */ /* Element size fits within the buffer size */ @@ -561,72 +694,72 @@ H5D_contig_readvv(const H5D_io_info_t *io_info, HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(buf,dset_contig->sieve_buf,size); + HDmemcpy(buf, dset_contig->sieve_buf, size); /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty=0; + dset_contig->sieve_dirty = 0; } /* end else */ } /* end else */ } /* end else */ /* Update memory information */ - mem_len_arr[v]-=size; - mem_offset_arr[v]+=size; - if(mem_len_arr[v]==0) + mem_len_arr[v] -= size; + mem_offset_arr[v] += size; + if(mem_len_arr[v] == 0) v++; /* Update file information */ - dset_len_arr[u]-=size; - dset_offset_arr[u]+=size; - if(dset_len_arr[u]==0) + dset_len_arr[u] -= size; + dset_offset_arr[u] += size; + if(dset_len_arr[u] == 0) u++; /* Increment number of bytes copied */ - total_size+=size; + total_size += size; } /* end for */ } /* end if */ else { /* Work through all the sequences */ - for(u=*dset_curr_seq, v=*mem_curr_seq; udset_addr+dset_offset_arr[u]; + addr = store_contig->dset_addr + dset_offset_arr[u]; /* Compute offset in memory */ - buf = (unsigned char *)_buf + mem_offset_arr[v]; + buf = (unsigned char *)io_info->u.rbuf + mem_offset_arr[v]; /* Write data */ - if (H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf)<0) + if(H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") /* Update memory information */ - mem_len_arr[v]-=size; - mem_offset_arr[v]+=size; - if(mem_len_arr[v]==0) + mem_len_arr[v] -= size; + mem_offset_arr[v] += size; + if(mem_len_arr[v] == 0) v++; /* Update file information */ - dset_len_arr[u]-=size; - dset_offset_arr[u]+=size; - if(dset_len_arr[u]==0) + dset_len_arr[u] -= size; + dset_offset_arr[u] += size; + if(dset_len_arr[u] == 0) u++; /* Increment number of bytes copied */ - total_size+=size; + total_size += size; } /* end for */ } /* end else */ /* Update current sequence vectors */ - *dset_curr_seq=u; - *mem_curr_seq=v; + *dset_curr_seq = u; + *mem_curr_seq = v; /* Set return value */ - H5_ASSIGN_OVERFLOW(ret_value,total_size,size_t,ssize_t); + H5_ASSIGN_OVERFLOW(ret_value, total_size, size_t, ssize_t); done: FUNC_LEAVE_NOAPI(ret_value) @@ -654,15 +787,14 @@ done: ssize_t H5D_contig_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED address, void UNUSED *pointer, const void *_buf) + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) { H5F_t *file = io_info->dset->oloc.file; /* File for dataset */ - H5D_rdcdc_t *dset_contig=&(io_info->dset->shared->cache.contig); /* Cached information about contiguous data */ - const H5D_contig_storage_t *store_contig=&(io_info->store->contig); /* Contiguous storage info for this I/O operation */ - const unsigned char *buf=(const unsigned char *)_buf; /* Pointer to buffer to fill */ + H5D_rdcdc_t *dset_contig = &(io_info->dset->shared->cache.contig); /* Cached information about contiguous data */ + const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ + const unsigned char *buf = (const unsigned char *)io_info->u.wbuf; /* Pointer to buffer to fill */ haddr_t addr; /* Actual address to read */ - size_t total_size=0; /* Size of sequence in bytes */ + size_t total_size = 0; /* Size of sequence in bytes */ size_t size; /* Size of sequence in bytes */ size_t u; /* Counting variable */ size_t v; /* Counting variable */ @@ -671,10 +803,10 @@ H5D_contig_writevv(const H5D_io_info_t *io_info, FUNC_ENTER_NOAPI(H5D_contig_writevv, FAIL) /* Check args */ - assert(io_info); - assert(io_info->dset); - assert(io_info->store); - assert(buf); + HDassert(io_info); + HDassert(io_info->dset); + HDassert(io_info->store); + HDassert(buf); /* Check if data sieving is enabled */ if(H5F_HAS_FEATURE(file,H5FD_FEAT_DATA_SIEVE)) { @@ -708,18 +840,18 @@ H5D_contig_writevv(const H5D_io_info_t *io_info, addr=store_contig->dset_addr+dset_offset_arr[u]; /* Compute offset in memory */ - buf = (const unsigned char *)_buf + mem_offset_arr[v]; + buf = (const unsigned char *)io_info->u.wbuf + mem_offset_arr[v]; /* No data sieve buffer yet, go allocate one */ if(dset_contig->sieve_buf==NULL) { /* Check if we can actually hold the I/O request in the sieve buffer */ if(size>dset_contig->sieve_buf_size) { - if (H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf)<0) + if(H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") } /* end if */ else { /* Allocate room for the data sieve buffer */ - if (NULL==(dset_contig->sieve_buf=H5FL_BLK_MALLOC(sieve_buf,dset_contig->sieve_buf_size))) + if(NULL == (dset_contig->sieve_buf = H5FL_BLK_MALLOC(sieve_buf, dset_contig->sieve_buf_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") #ifdef H5_CLEAR_MEMORY if(dset_contig->sieve_size > size) @@ -750,15 +882,15 @@ if(dset_contig->sieve_size > size) } /* end if */ /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(dset_contig->sieve_buf,buf,size); + HDmemcpy(dset_contig->sieve_buf, buf, size); /* Set sieve buffer dirty flag */ - dset_contig->sieve_dirty=1; + dset_contig->sieve_dirty = 1; /* Stash local copies of these values */ - sieve_start=dset_contig->sieve_loc; - sieve_size=dset_contig->sieve_size; - sieve_end=sieve_start+sieve_size; + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start + sieve_size; } /* end else */ } /* end if */ else { @@ -767,13 +899,13 @@ if(dset_contig->sieve_size > size) /* If entire write is within the sieve buffer, write it to the buffer */ if(addr>=sieve_start && contig_endsieve_buf+(addr-sieve_start); + unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start); /* Put the data into the sieve buffer */ - HDmemcpy(base_sieve_buf,buf,size); + HDmemcpy(base_sieve_buf, buf, size); /* Set sieve buffer dirty flag */ - dset_contig->sieve_dirty=1; + dset_contig->sieve_dirty = 1; } /* end if */ /* Entire request is not within this data sieve buffer */ else { @@ -798,7 +930,7 @@ if(dset_contig->sieve_size > size) } /* end if */ /* Write directly from the user's buffer */ - if (H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf)<0) + if(H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") } /* end if */ /* Element size fits within the buffer size */ @@ -808,30 +940,30 @@ if(dset_contig->sieve_size > size) (size+sieve_size)<=dset_contig->sieve_buf_size && dset_contig->sieve_dirty) { /* Prepend to existing sieve buffer */ - if((addr+size)==sieve_start) { + if((addr + size) == sieve_start) { /* Move existing sieve information to correct location */ - HDmemmove(dset_contig->sieve_buf+size,dset_contig->sieve_buf,dset_contig->sieve_size); + HDmemmove(dset_contig->sieve_buf + size, dset_contig->sieve_buf, dset_contig->sieve_size); /* Copy in new information (must be first in sieve buffer) */ - HDmemcpy(dset_contig->sieve_buf,buf,size); + HDmemcpy(dset_contig->sieve_buf, buf, size); /* Adjust sieve location */ - dset_contig->sieve_loc=addr; + dset_contig->sieve_loc = addr; } /* end if */ /* Append to existing sieve buffer */ else { /* Copy in new information */ - HDmemcpy(dset_contig->sieve_buf+sieve_size,buf,size); + HDmemcpy(dset_contig->sieve_buf + sieve_size, buf, size); } /* end else */ /* Adjust sieve size */ dset_contig->sieve_size += size; /* Update local copies of sieve information */ - sieve_start=dset_contig->sieve_loc; - sieve_size=dset_contig->sieve_size; - sieve_end=sieve_start+sieve_size; + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start + sieve_size; } /* end if */ /* Can't add the new data onto the existing sieve buffer */ else { @@ -875,73 +1007,73 @@ if(dset_contig->sieve_size > size) } /* end if */ /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(dset_contig->sieve_buf,buf,size); + HDmemcpy(dset_contig->sieve_buf, buf, size); /* Set sieve buffer dirty flag */ - dset_contig->sieve_dirty=1; + dset_contig->sieve_dirty = 1; } /* end else */ } /* end else */ } /* end else */ } /* end else */ /* Update memory information */ - mem_len_arr[v]-=size; - mem_offset_arr[v]+=size; - if(mem_len_arr[v]==0) + mem_len_arr[v] -= size; + mem_offset_arr[v] += size; + if(mem_len_arr[v] == 0) v++; /* Update file information */ - dset_len_arr[u]-=size; - dset_offset_arr[u]+=size; - if(dset_len_arr[u]==0) + dset_len_arr[u] -= size; + dset_offset_arr[u] += size; + if(dset_len_arr[u] == 0) u++; /* Increment number of bytes copied */ - total_size+=size; + total_size += size; } /* end for */ } /* end if */ else { /* Work through all the sequences */ - for(u=*dset_curr_seq, v=*mem_curr_seq; udset_addr+dset_offset_arr[u]; + addr = store_contig->dset_addr + dset_offset_arr[u]; /* Compute offset in memory */ - buf = (const unsigned char *)_buf + mem_offset_arr[v]; + buf = (const unsigned char *)io_info->u.wbuf + mem_offset_arr[v]; /* Write data */ - if (H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf)<0) + if(H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") /* Update memory information */ - mem_len_arr[v]-=size; - mem_offset_arr[v]+=size; - if(mem_len_arr[v]==0) + mem_len_arr[v] -= size; + mem_offset_arr[v] += size; + if(mem_len_arr[v] == 0) v++; /* Update file information */ - dset_len_arr[u]-=size; - dset_offset_arr[u]+=size; - if(dset_len_arr[u]==0) + dset_len_arr[u] -= size; + dset_offset_arr[u] += size; + if(dset_len_arr[u] == 0) u++; /* Increment number of bytes copied */ - total_size+=size; + total_size += size; } /* end for */ } /* end else */ /* Update current sequence vectors */ - *dset_curr_seq=u; - *mem_curr_seq=v; + *dset_curr_seq = u; + *mem_curr_seq = v; /* Set return value */ - H5_ASSIGN_OVERFLOW(ret_value,total_size,size_t,ssize_t); + H5_ASSIGN_OVERFLOW(ret_value, total_size, size_t, ssize_t); done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Ddeprec.c b/src/H5Ddeprec.c index 8f8aa50..fd1d2e8 100644 --- a/src/H5Ddeprec.c +++ b/src/H5Ddeprec.c @@ -156,7 +156,7 @@ H5Dcreate1(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id, HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") if(H5I_DATATYPE != H5I_get_type(type_id)) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype ID") - if(NULL == (space = H5I_object_verify(space_id,H5I_DATASPACE))) + if(NULL == (space = (const H5S_t *)H5I_object_verify(space_id,H5I_DATASPACE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace ID") if(H5P_DEFAULT == dcpl_id) dcpl_id = H5P_DATASET_CREATE_DEFAULT; diff --git a/src/H5Defl.c b/src/H5Defl.c index c8d1098..7dac29b 100644 --- a/src/H5Defl.c +++ b/src/H5Defl.c @@ -33,30 +33,88 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* Files */ + /****************/ /* Local Macros */ /****************/ + /******************/ /* Local Typedefs */ /******************/ + /********************/ /* Local Prototypes */ /********************/ -static herr_t H5D_efl_read (const H5O_efl_t *efl, haddr_t addr, size_t size, + +/* Layout operation callbacks */ +static herr_t H5D_efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *cm); +static ssize_t H5D_efl_readvv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); +static ssize_t H5D_efl_writevv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); + +/* Helper routines */ +static herr_t H5D_efl_read(const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf); static herr_t H5D_efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size, const uint8_t *buf); + /*********************/ /* Package Variables */ /*********************/ +/* External File List (EFL) storage layout I/O ops */ +const H5D_layout_ops_t H5D_LOPS_EFL[1] = {{ + H5D_efl_io_init, + H5D_contig_read, + H5D_contig_write, +#ifdef H5_HAVE_PARALLEL + NULL, + NULL, +#endif /* H5_HAVE_PARALLEL */ + H5D_efl_readvv, + H5D_efl_writevv, + NULL +}}; + + /*******************/ /* Local Variables */ /*******************/ + + +/*------------------------------------------------------------------------- + * Function: H5D_efl_io_init + * + * Purpose: Performs initialization before any sort of I/O on the raw data + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 20, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t UNUSED *type_info, + hsize_t UNUSED nelmts, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space, + H5D_chunk_map_t UNUSED *cm) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_efl_io_init) + + HDmemcpy(&io_info->store->efl, &(io_info->dset->shared->dcpl_cache.efl), sizeof(H5O_efl_t)); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D_efl_io_init() */ + /*------------------------------------------------------------------------- * Function: H5D_efl_read @@ -77,26 +135,26 @@ static herr_t H5D_efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size, *------------------------------------------------------------------------- */ static herr_t -H5D_efl_read (const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf) +H5D_efl_read(const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf) { - int fd=-1; + int fd = -1; size_t to_read; #ifndef NDEBUG hsize_t tempto_read; #endif /* NDEBUG */ - hsize_t skip=0; + hsize_t skip = 0; haddr_t cur; ssize_t n; size_t u; /* Local index variable */ - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5D_efl_read) /* Check args */ - assert (efl && efl->nused>0); - assert (H5F_addr_defined (addr)); - assert (size < SIZET_MAX); - assert (buf || 0==size); + HDassert(efl && efl->nused>0); + HDassert(H5F_addr_defined(addr)); + HDassert(size < SIZET_MAX); + HDassert(buf || 0 == size); /* Find the first efl member from which to read */ for (u=0, cur=0; unused; u++) { @@ -109,7 +167,7 @@ H5D_efl_read (const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf) /* Read the data */ while (size) { - assert(buf); + HDassert(buf); if (u>=efl->nused) HGOTO_ERROR (H5E_EFL, H5E_OVERFLOW, FAIL, "read past logical end of file") if (H5F_OVERFLOW_HSIZET2OFFT (efl->slot[u].offset+skip)) @@ -165,25 +223,25 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D_efl_write (const H5O_efl_t *efl, haddr_t addr, size_t size, const uint8_t *buf) +H5D_efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size, const uint8_t *buf) { - int fd=-1; + int fd = -1; size_t to_write; #ifndef NDEBUG hsize_t tempto_write; #endif /* NDEBUG */ haddr_t cur; - hsize_t skip=0; + hsize_t skip = 0; size_t u; /* Local index variable */ - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5D_efl_write) /* Check args */ - assert (efl && efl->nused>0); - assert (H5F_addr_defined (addr)); - assert (size < SIZET_MAX); - assert (buf || 0==size); + HDassert(efl && efl->nused>0); + HDassert(H5F_addr_defined(addr)); + HDassert(size < SIZET_MAX); + HDassert(buf || 0 == size); /* Find the first efl member in which to write */ for (u=0, cur=0; unused; u++) { @@ -248,71 +306,68 @@ done: * Programmer: Quincey Koziol * Wednesday, May 7, 2003 * - * Modifications: - * *------------------------------------------------------------------------- */ -ssize_t +static ssize_t H5D_efl_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED address, void UNUSED *pointer/*in*/, void *_buf) + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) { - const H5O_efl_t *efl=&(io_info->store->efl); /* Pointer to efl info */ + const H5O_efl_t *efl = &(io_info->store->efl); /* Pointer to efl info */ unsigned char *buf; /* Pointer to buffer to write */ haddr_t addr; /* Actual address to read */ - size_t total_size=0; /* Total size of sequence in bytes */ + size_t total_size = 0; /* Total size of sequence in bytes */ size_t size; /* Size of sequence in bytes */ size_t u; /* Counting variable */ size_t v; /* Counting variable */ ssize_t ret_value; /* Return value */ - FUNC_ENTER_NOAPI(H5D_efl_readvv, FAIL) + FUNC_ENTER_NOAPI_NOINIT(H5D_efl_readvv) /* Check args */ - assert (efl && efl->nused>0); - assert (_buf); + HDassert(efl && efl->nused > 0); + HDassert(io_info->u.rbuf); /* Work through all the sequences */ - for(u=*dset_curr_seq, v=*mem_curr_seq; uu.rbuf + mem_offset_arr[v]; /* Read data */ - if (H5D_efl_read(efl, addr, size, buf)<0) + if(H5D_efl_read(efl, addr, size, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") /* Update memory information */ - mem_len_arr[v]-=size; - mem_offset_arr[v]+=size; - if(mem_len_arr[v]==0) + mem_len_arr[v] -= size; + mem_offset_arr[v] += size; + if(mem_len_arr[v] == 0) v++; /* Update file information */ - dset_len_arr[u]-=size; - dset_offset_arr[u]+=size; - if(dset_len_arr[u]==0) + dset_len_arr[u] -= size; + dset_offset_arr[u] += size; + if(dset_len_arr[u] == 0) u++; /* Increment number of bytes copied */ - total_size+=size; + total_size += size; } /* end for */ /* Update current sequence vectors */ - *dset_curr_seq=u; - *mem_curr_seq=v; + *dset_curr_seq = u; + *mem_curr_seq = v; /* Set return value */ - H5_ASSIGN_OVERFLOW(ret_value,total_size,size_t,ssize_t); + H5_ASSIGN_OVERFLOW(ret_value, total_size, size_t, ssize_t); done: FUNC_LEAVE_NOAPI(ret_value) @@ -332,71 +387,68 @@ done: * Programmer: Quincey Koziol * Friday, May 2, 2003 * - * Modifications: - * *------------------------------------------------------------------------- */ -ssize_t +static ssize_t H5D_efl_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED address, void UNUSED *pointer/*in*/, const void *_buf) + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) { - const H5O_efl_t *efl=&(io_info->store->efl); /* Pointer to efl info */ + const H5O_efl_t *efl = &(io_info->store->efl); /* Pointer to efl info */ const unsigned char *buf; /* Pointer to buffer to write */ haddr_t addr; /* Actual address to read */ - size_t total_size=0; /* Total size of sequence in bytes */ + size_t total_size = 0; /* Total size of sequence in bytes */ size_t size; /* Size of sequence in bytes */ size_t u; /* Counting variable */ size_t v; /* Counting variable */ ssize_t ret_value; /* Return value */ - FUNC_ENTER_NOAPI(H5D_efl_writevv, FAIL) + FUNC_ENTER_NOAPI_NOINIT(H5D_efl_writevv) /* Check args */ - assert (efl && efl->nused>0); - assert (_buf); + HDassert(efl && efl->nused > 0); + HDassert(io_info->u.wbuf); /* Work through all the sequences */ - for(u=*dset_curr_seq, v=*mem_curr_seq; uu.wbuf + mem_offset_arr[v]; /* Write data */ - if (H5D_efl_write(efl, addr, size, buf)<0) + if(H5D_efl_write(efl, addr, size, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") /* Update memory information */ - mem_len_arr[v]-=size; - mem_offset_arr[v]+=size; - if(mem_len_arr[v]==0) + mem_len_arr[v] -= size; + mem_offset_arr[v] += size; + if(mem_len_arr[v] == 0) v++; /* Update file information */ - dset_len_arr[u]-=size; - dset_offset_arr[u]+=size; - if(dset_len_arr[u]==0) + dset_len_arr[u] -= size; + dset_offset_arr[u] += size; + if(dset_len_arr[u] == 0) u++; /* Increment number of bytes copied */ - total_size+=size; + total_size += size; } /* end for */ /* Update current sequence vectors */ - *dset_curr_seq=u; - *mem_curr_seq=v; + *dset_curr_seq = u; + *mem_curr_seq = v; /* Set return value */ - H5_ASSIGN_OVERFLOW(ret_value,total_size,size_t,ssize_t); + H5_ASSIGN_OVERFLOW(ret_value, total_size, size_t, ssize_t); done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Dfill.c b/src/H5Dfill.c index bfb4354..4879f4d 100644 --- a/src/H5Dfill.c +++ b/src/H5Dfill.c @@ -275,7 +275,7 @@ H5D_fill(const void *fill, const H5T_t *fill_type, void *buf, HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") /* Scatter the data into memory */ - if(H5D_select_mscat(tmp_buf, space, &mem_iter, (size_t)nelmts, dxpl_cache, buf/*out*/) < 0) { + if(H5D_scatter_mem(tmp_buf, space, &mem_iter, (size_t)nelmts, dxpl_cache, buf/*out*/) < 0) { H5S_SELECT_ITER_RELEASE(&mem_iter); HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") } /* end if */ @@ -337,13 +337,13 @@ done: if(dst_id != (-1) && H5I_dec_ref(dst_id) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID") if(tmp_buf) - H5FL_BLK_FREE(type_conv, tmp_buf); + (void)H5FL_BLK_FREE(type_conv, tmp_buf); if(elem_wb && H5WB_unwrap(elem_wb) < 0) HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") if(bkg_elem_wb && H5WB_unwrap(bkg_elem_wb) < 0) HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") if(bkg_buf) - H5FL_BLK_FREE(type_conv, bkg_buf); + (void)H5FL_BLK_FREE(type_conv, bkg_buf); FUNC_LEAVE_NOAPI(ret_value) } /* H5D_fill() */ @@ -636,9 +636,9 @@ H5D_fill_release(H5D_fill_buf_info_t *fb_info) fb_info->fill_free_func(fb_info->fill_buf, fb_info->fill_free_info); else { if(fb_info->fill->buf) - H5FL_BLK_FREE(non_zero_fill, fb_info->fill_buf); + (void)H5FL_BLK_FREE(non_zero_fill, fb_info->fill_buf); else - H5FL_BLK_FREE(zero_fill, fb_info->fill_buf); + (void)H5FL_BLK_FREE(zero_fill, fb_info->fill_buf); } /* end else */ fb_info->fill_buf = NULL; } /* end if */ @@ -677,7 +677,7 @@ H5D_fill_term(H5D_fill_buf_info_t *fb_info) else if(fb_info->mem_type) H5T_close(fb_info->mem_type); if(fb_info->bkg_buf) - H5FL_BLK_FREE(type_conv, fb_info->bkg_buf); + (void)H5FL_BLK_FREE(type_conv, fb_info->bkg_buf); } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) diff --git a/src/H5Dint.c b/src/H5Dint.c index a5ea398..acb95d2 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -59,10 +59,12 @@ typedef struct { /* General stuff */ static herr_t H5D_init_storage(H5D_t *dataset, hbool_t full_overwrite, hid_t dxpl_id); +static herr_t H5D_get_dxpl_cache_real(hid_t dxpl_id, H5D_dxpl_cache_t *cache); static H5D_shared_t *H5D_new(hid_t dcpl_id, hbool_t creating, hbool_t vl_type); static herr_t H5D_init_type(H5F_t *file, const H5D_t *dset, hid_t type_id, const H5T_t *type); static herr_t H5D_init_space(H5F_t *file, const H5D_t *dset, const H5S_t *space); +static herr_t H5D_set_io_ops(H5D_t *dataset); static herr_t H5D_update_oh_info(H5F_t *file, hid_t dxpl_id, H5D_t *dset); static herr_t H5D_open_oid(H5D_t *dataset, hid_t dxpl_id); static herr_t H5D_flush_real(H5D_t *dataset, hid_t dxpl_id, unsigned flags); @@ -250,6 +252,133 @@ H5D_term_interface(void) } /* end H5D_term_interface() */ +/*-------------------------------------------------------------------------- + NAME + H5D_get_dxpl_cache_real + PURPOSE + Get all the values for the DXPL cache. + USAGE + herr_t H5D_get_dxpl_cache_real(dxpl_id, cache) + hid_t dxpl_id; IN: DXPL to query + H5D_dxpl_cache_t *cache;IN/OUT: DXPL cache to fill with values + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Query all the values from a DXPL that are needed by internal routines + within the library. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5D_get_dxpl_cache_real(hid_t dxpl_id, H5D_dxpl_cache_t *cache) +{ + H5P_genplist_t *dx_plist; /* Data transfer property list */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_get_dxpl_cache_real) + + /* Check args */ + HDassert(cache); + + /* Get the dataset transfer property list */ + if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") + + /* Get maximum temporary buffer size */ + if(H5P_get(dx_plist, H5D_XFER_MAX_TEMP_BUF_NAME, &cache->max_temp_buf) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve maximum temporary buffer size") + + /* Get temporary buffer pointer */ + if(H5P_get(dx_plist, H5D_XFER_TCONV_BUF_NAME, &cache->tconv_buf) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve temporary buffer pointer") + + /* Get background buffer pointer */ + if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_NAME, &cache->bkgr_buf) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer pointer") + + /* Get background buffer type */ + if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &cache->bkgr_buf_type) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer type") + + /* Get B-tree split ratios */ + if(H5P_get(dx_plist, H5D_XFER_BTREE_SPLIT_RATIO_NAME, &cache->btree_split_ratio) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve B-tree split ratios") + + /* Get I/O vector size */ + if(H5P_get(dx_plist, H5D_XFER_HYPER_VECTOR_SIZE_NAME, &cache->vec_size) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve I/O vector size") + +#ifdef H5_HAVE_PARALLEL + /* Collect Parallel I/O information for possible later use */ + if(H5P_get(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &cache->xfer_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve parallel transfer method") + if(H5P_get(dx_plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &cache->coll_opt_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve collective transfer option") +#endif /* H5_HAVE_PARALLEL */ + + /* Get error detection properties */ + if(H5P_get(dx_plist, H5D_XFER_EDC_NAME, &cache->err_detect) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve error detection info") + + /* Get filter callback function */ + if(H5P_get(dx_plist, H5D_XFER_FILTER_CB_NAME, &cache->filter_cb) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve filter callback function") + + /* Get the data transform property */ + if(H5P_get(dx_plist, H5D_XFER_XFORM_NAME, &cache->data_xform_prop) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve data transform info") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_get_dxpl_cache_real() */ + + +/*-------------------------------------------------------------------------- + NAME + H5D_get_dxpl_cache + PURPOSE + Get all the values for the DXPL cache. + USAGE + herr_t H5D_get_dxpl_cache(dxpl_id, cache) + hid_t dxpl_id; IN: DXPL to query + H5D_dxpl_cache_t *cache;IN/OUT: DXPL cache to fill with values + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Query all the values from a DXPL that are needed by internal routines + within the library. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + The CACHE pointer should point at already allocated memory to place + non-default property list info. If a default property list is used, the + CACHE pointer will be changed to point at the default information. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5D_get_dxpl_cache(hid_t dxpl_id, H5D_dxpl_cache_t **cache) +{ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5D_get_dxpl_cache,FAIL) + + /* Check args */ + assert(cache); + + /* Check for the default DXPL */ + if(dxpl_id==H5P_DATASET_XFER_DEFAULT) + *cache=&H5D_def_dxpl_cache; + else + if(H5D_get_dxpl_cache_real(dxpl_id,*cache) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "Can't retrieve DXPL values") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_get_dxpl_cache() */ + + /*------------------------------------------------------------------------- * Function: H5D_create_named * @@ -556,6 +685,54 @@ done: /*------------------------------------------------------------------------- + * Function: H5D_set_io_ops + * + * Purpose: Set the I/O operation function pointers for a dataset + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 20, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_set_io_ops(H5D_t *dataset) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_set_io_ops) + + /* check args */ + HDassert(dataset); + + /* Set the I/O functions for each layout type */ + switch(dataset->shared->layout.type) { + case H5D_CONTIGUOUS: + if(dataset->shared->dcpl_cache.efl.nused > 0) + dataset->shared->layout_ops = H5D_LOPS_EFL; + else + dataset->shared->layout_ops = H5D_LOPS_CONTIG; + break; + + case H5D_CHUNKED: + dataset->shared->layout_ops = H5D_LOPS_CHUNK; + break; + + case H5D_COMPACT: + dataset->shared->layout_ops = H5D_LOPS_COMPACT; + break; + + default: + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown storage method") + } /* end switch */ /*lint !e788 All appropriate cases are covered */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_set_io_ops() */ + + +/*------------------------------------------------------------------------- * Function: H5D_update_oh_info * * Purpose: Create and fill object header for dataset @@ -979,18 +1156,10 @@ H5D_create(H5F_t *file, hid_t type_id, const H5S_t *space, hid_t dcpl_id, } else if(max_points * H5T_get_size(type) > max_storage) { HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "data space size exceeds external storage size") } - - /* Set the I/O functions for this layout type */ - new_dset->shared->io_ops.readvv = H5D_efl_readvv; - new_dset->shared->io_ops.writevv = H5D_efl_writevv; } /* end if */ else { if(ndims > 0 && max_dim[0] > dim[0]) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, "extendible contiguous non-external dataset") - - /* Set the I/O functions for this layout type */ - new_dset->shared->io_ops.readvv = H5D_contig_readvv; - new_dset->shared->io_ops.writevv = H5D_contig_writevv; } /* end else */ /* Compute the total size of a chunk */ @@ -1042,10 +1211,6 @@ H5D_create(H5F_t *file, hid_t type_id, const H5S_t *space, hid_t dcpl_id, for(u = 1, new_dset->shared->layout.u.chunk.size = new_dset->shared->layout.u.chunk.dim[0]; u < new_dset->shared->layout.u.chunk.ndims; u++) new_dset->shared->layout.u.chunk.size *= new_dset->shared->layout.u.chunk.dim[u]; - /* Set the I/O functions for this layout type */ - new_dset->shared->io_ops.readvv = H5D_istore_readvv; - new_dset->shared->io_ops.writevv = H5D_istore_writevv; - /* Initialize the chunk cache for the dataset */ if(H5D_istore_init(file, new_dset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't initialize chunk cache") @@ -1073,10 +1238,6 @@ H5D_create(H5F_t *file, hid_t type_id, const H5S_t *space, hid_t dcpl_id, comp_data_size = H5O_MESG_MAX_SIZE - H5O_layout_meta_size(file, &(new_dset->shared->layout)); if(new_dset->shared->layout.u.compact.size > comp_data_size) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "compact dataset size is bigger than header message maximum size") - - /* Set the I/O functions for this layout type */ - new_dset->shared->io_ops.readvv = H5D_compact_readvv; - new_dset->shared->io_ops.writevv = H5D_compact_writevv; } /* end case */ break; @@ -1084,6 +1245,10 @@ H5D_create(H5F_t *file, hid_t type_id, const H5S_t *space, hid_t dcpl_id, HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, "not implemented yet") } /* end switch */ /*lint !e788 All appropriate cases are covered */ + /* Set the dataset's I/O operations */ + if(H5D_set_io_ops(new_dset) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to initialize I/O operations") + /* Update the dataset's object header info. */ if(H5D_update_oh_info(file, dxpl_id, new_dset) != SUCCEED) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't update the metadata cache") @@ -1252,9 +1417,9 @@ static herr_t H5D_open_oid(H5D_t *dataset, hid_t dxpl_id) { H5P_genplist_t *plist; /* Property list */ - H5O_pline_t *pline; /* I/O pipeline information */ H5O_fill_t *fill_prop; /* Pointer to dataset's fill value info */ unsigned alloc_time_state; /* Allocation time state */ + htri_t msg_exists; /* Whether a particular type of message exists */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5D_open_oid) @@ -1285,13 +1450,17 @@ H5D_open_oid(H5D_t *dataset, hid_t dxpl_id) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list") /* Get the optional filters message */ - pline = &dataset->shared->dcpl_cache.pline; - if(NULL != H5O_msg_read(&(dataset->oloc), H5O_PLINE_ID, pline, dxpl_id)) { - if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, pline) < 0) + if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_PLINE_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists") + if(msg_exists) { + /* Retrieve the I/O pipeline message */ + if(NULL == H5O_msg_read(&(dataset->oloc), H5O_PLINE_ID, &dataset->shared->dcpl_cache.pline, dxpl_id)) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message") + + /* Set the I/O pipeline info in the property list */ + if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &dataset->shared->dcpl_cache.pline) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set pipeline") } /* end if */ - else - H5E_clear_stack(NULL); /* * Get the raw data layout info. It's actually stored in two locations: @@ -1316,10 +1485,6 @@ H5D_open_oid(H5D_t *dataset, hid_t dxpl_id) H5_ASSIGN_OVERFLOW(dataset->shared->layout.u.contig.size, tmp_size, hssize_t, hsize_t); } /* end if */ - /* Set the I/O functions for this layout type */ - dataset->shared->io_ops.readvv = H5D_contig_readvv; - dataset->shared->io_ops.writevv = H5D_contig_writevv; - /* Get the sieve buffer size for this dataset */ dataset->shared->cache.contig.sieve_buf_size = H5F_SIEVE_BUF_SIZE(dataset->oloc.file); break; @@ -1344,33 +1509,34 @@ H5D_open_oid(H5D_t *dataset, hid_t dxpl_id) if(H5D_istore_init(dataset->oloc.file, dataset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize chunk cache") } - - /* Set the I/O functions for this layout type */ - dataset->shared->io_ops.readvv = H5D_istore_readvv; - dataset->shared->io_ops.writevv = H5D_istore_writevv; break; case H5D_COMPACT: - /* Set the I/O functions for this layout type */ - dataset->shared->io_ops.readvv = H5D_compact_readvv; - dataset->shared->io_ops.writevv = H5D_compact_writevv; break; default: - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "not implemented yet") + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown storage method") } /* end switch */ /*lint !e788 All appropriate cases are covered */ /* Point at dataset's copy, to cache it for later */ fill_prop = &dataset->shared->dcpl_cache.fill; /* Try to get the new fill value message from the object header */ - if(NULL == H5O_msg_read(&(dataset->oloc), H5O_FILL_NEW_ID, fill_prop, dxpl_id)) { - H5E_clear_stack(NULL); - + if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_FILL_NEW_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists") + if(msg_exists) { + if(NULL == H5O_msg_read(&(dataset->oloc), H5O_FILL_NEW_ID, fill_prop, dxpl_id)) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message") + } /* end if */ + else { /* For backward compatibility, try to retrieve the old fill value message */ - if(NULL == H5O_msg_read(&(dataset->oloc), H5O_FILL_ID, fill_prop, dxpl_id)) { - H5E_clear_stack(NULL); - + if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_FILL_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists") + if(msg_exists) { + if(NULL == H5O_msg_read(&(dataset->oloc), H5O_FILL_ID, fill_prop, dxpl_id)) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message") + } /* end if */ + else { /* Set the space allocation time appropriately, based on the type of dataset storage */ switch(dataset->shared->layout.type) { case H5D_COMPACT: @@ -1388,7 +1554,7 @@ H5D_open_oid(H5D_t *dataset, hid_t dxpl_id) default: HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "not implemented yet") } /* end switch */ /*lint !e788 All appropriate cases are covered */ - } /* end if */ + } /* end else */ /* If "old" fill value size is 0 (undefined), map it to -1 */ if(fill_prop->size == 0) @@ -1412,18 +1578,23 @@ H5D_open_oid(H5D_t *dataset, hid_t dxpl_id) * also undefined when space allocate time is H5D_ALLOC_TIME_LATE. */ if((dataset->shared->layout.type == H5D_CONTIGUOUS && !H5F_addr_defined(dataset->shared->layout.u.contig.addr)) || (dataset->shared->layout.type == H5D_CHUNKED && !H5F_addr_defined(dataset->shared->layout.u.chunk.addr))) { - if(NULL != H5O_msg_read(&(dataset->oloc), H5O_EFL_ID, &dataset->shared->dcpl_cache.efl, dxpl_id)) { + if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_EFL_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists") + if(msg_exists) { + /* Retrieve the EFL message */ + if(NULL == H5O_msg_read(&(dataset->oloc), H5O_EFL_ID, &dataset->shared->dcpl_cache.efl, dxpl_id)) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message") + + /* Set the EFL info in the property list */ if(H5P_set(plist, H5D_CRT_EXT_FILE_LIST_NAME, &dataset->shared->dcpl_cache.efl) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set external file list") - - /* Override the I/O functions for this layout type */ - dataset->shared->io_ops.readvv = H5D_efl_readvv; - dataset->shared->io_ops.writevv = H5D_efl_writevv; } /* end if */ - else - H5E_clear_stack(NULL); } /* end if */ + /* Set the dataset's I/O operations */ + if(H5D_set_io_ops(dataset) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize I/O operations") + /* * Make sure all storage is properly initialized. * This is important only for parallel I/O where the space must @@ -2334,7 +2505,7 @@ H5D_set_extent(H5D_t *dset, const hsize_t *size, hid_t dxpl_id) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") /* Construct dataset I/O info */ - H5D_BUILD_IO_INFO(&io_info, dset, dxpl_cache, dxpl_id, NULL); + H5D_BUILD_IO_INFO_RD(&io_info, dset, dxpl_cache, dxpl_id, NULL, NULL); /* Remove excess chunks */ if(H5D_istore_prune_by_extent(&io_info, curr_dims) < 0) diff --git a/src/H5Dio.c b/src/H5Dio.c index 8576464..17bab19 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -28,27 +28,17 @@ #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 "H5SLprivate.h" /* Skip lists */ -#include "H5Vprivate.h" /* Vector and array functions */ #ifdef H5_HAVE_PARALLEL /* Remove this if H5R_DATASET_REGION is no longer used in this file */ -# include "H5Rpublic.h" +#include "H5Rpublic.h" #endif /*H5_HAVE_PARALLEL*/ + /****************/ /* Local Macros */ /****************/ -#define H5D_DEFAULT_SKIPLIST_HEIGHT 8 - -/* Macros for iterating over chunks to operate on */ -#define H5D_CHUNK_GET_FIRST_NODE(map) (map.use_single ? (H5SL_node_t *)(1) : H5SL_first(map.sel_chunks)) -#define H5D_CHUNK_GET_NODE_INFO(map, node) (map.use_single ? map.single_chunk_info : (H5D_chunk_info_t *)H5SL_item(node)) -#define H5D_CHUNK_GET_NEXT_NODE(map, node) (map.use_single ? (H5SL_node_t *)NULL : H5SL_next(node)) - /******************/ /* Local Typedefs */ @@ -59,64 +49,36 @@ /* Local Prototypes */ /********************/ +/* Internal I/O routines */ static herr_t H5D_read(H5D_t *dataset, hid_t mem_type_id, - const H5S_t *mem_space, const H5S_t *file_space, - hid_t dset_xfer_plist, void *buf/*out*/); + 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, hid_t mem_type_id, - const H5S_t *mem_space, const H5S_t *file_space, - hid_t dset_xfer_plist, const void *buf); -static herr_t H5D_contig_read(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, void *buf/*out*/); -static herr_t H5D_contig_write(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, const void *buf); -static herr_t H5D_chunk_read(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, void *buf/*out*/); -static herr_t H5D_chunk_write(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, const void *buf); -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, - hid_t src_id, hid_t dst_id, H5T_subset_t subset, void *data_buf, - void *user_buf/*out*/); -static herr_t H5D_compound_opt_write(size_t nelmts, hid_t src_id, hid_t dst_id, - void *data_buf); + const H5S_t *mem_space, const H5S_t *file_space, hid_t dset_xfer_plist, + const void *buf); +/* Setup/teardown routines */ +static herr_t H5D_ioinfo_init(H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, + hid_t dxpl_id, const H5D_type_info_t *type_info, H5D_storage_t *store, + H5D_io_info_t *io_info); +static herr_t H5D_typeinfo_init(const H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, + hid_t dxpl_id, hid_t mem_type_id, hbool_t do_write, + H5D_type_info_t *type_info); #ifdef H5_HAVE_PARALLEL +static herr_t H5D_ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, + const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, + const H5S_t *file_space, const H5S_t *mem_space, + const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm); static herr_t H5D_ioinfo_term(H5D_io_info_t *io_info); #endif /* H5_HAVE_PARALLEL */ +static herr_t H5D_typeinfo_term(const H5D_type_info_t *type_info); -/* I/O info operations */ -static herr_t H5D_ioinfo_init(H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, const H5S_t *mem_space, const H5S_t *file_space, - H5T_path_t *tpath, H5D_io_info_t *io_info); - -/* Chunk operations */ -static herr_t H5D_create_chunk_map(H5D_chunk_map_t *fm, const H5D_io_info_t *io_info, - hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - const H5T_t *mem_type); -static herr_t H5D_destroy_chunk_map(const H5D_chunk_map_t *fm); -static herr_t H5D_free_chunk_info(void *item, void *key, void *opdata); -static herr_t H5D_create_chunk_map_single(H5D_chunk_map_t *fm, - const H5D_io_info_t *io_info); -static herr_t H5D_create_chunk_file_map_hyper(H5D_chunk_map_t *fm, - const H5D_io_info_t *io_info); -static herr_t H5D_create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm); -static herr_t H5D_chunk_file_cb(void *elem, hid_t type_id, unsigned ndims, - const hsize_t *coords, void *fm); -static herr_t H5D_chunk_mem_cb(void *elem, hid_t type_id, unsigned ndims, - const hsize_t *coords, void *fm); /*********************/ /* Package Variables */ /*********************/ + /*******************/ /* Local Variables */ /*******************/ @@ -124,142 +86,6 @@ static herr_t H5D_chunk_mem_cb(void *elem, hid_t type_id, unsigned ndims, /* Declare a free list to manage blocks of type conversion data */ H5FL_BLK_DEFINE(type_conv); -/* Declare a free list to manage the H5D_chunk_info_t struct */ -H5FL_DEFINE(H5D_chunk_info_t); - -/* Declare a free list to manage sequences of size_t */ -H5FL_SEQ_DEFINE_STATIC(size_t); - -/* Declare a free list to manage sequences of hsize_t */ -H5FL_SEQ_DEFINE_STATIC(hsize_t); - - - -/*-------------------------------------------------------------------------- - NAME - H5D_get_dxpl_cache_real - PURPOSE - Get all the values for the DXPL cache. - USAGE - herr_t H5D_get_dxpl_cache_real(dxpl_id, cache) - hid_t dxpl_id; IN: DXPL to query - H5D_dxpl_cache_t *cache;IN/OUT: DXPL cache to fill with values - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Query all the values from a DXPL that are needed by internal routines - within the library. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -herr_t -H5D_get_dxpl_cache_real(hid_t dxpl_id, H5D_dxpl_cache_t *cache) -{ - H5P_genplist_t *dx_plist; /* Data transfer property list */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_get_dxpl_cache_real,FAIL) - - /* Check args */ - assert(cache); - - /* Get the dataset transfer property list */ - if (NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") - - /* Get maximum temporary buffer size */ - if(H5P_get(dx_plist, H5D_XFER_MAX_TEMP_BUF_NAME, &cache->max_temp_buf) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve maximum temporary buffer size") - - /* Get temporary buffer pointer */ - if(H5P_get(dx_plist, H5D_XFER_TCONV_BUF_NAME, &cache->tconv_buf) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve temporary buffer pointer") - - /* Get background buffer pointer */ - if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_NAME, &cache->bkgr_buf) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer pointer") - - /* Get background buffer type */ - if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &cache->bkgr_buf_type) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer type") - - /* Get B-tree split ratios */ - if(H5P_get(dx_plist, H5D_XFER_BTREE_SPLIT_RATIO_NAME, &cache->btree_split_ratio) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve B-tree split ratios") - - /* Get I/O vector size */ - if(H5P_get(dx_plist, H5D_XFER_HYPER_VECTOR_SIZE_NAME, &cache->vec_size) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve I/O vector size") - -#ifdef H5_HAVE_PARALLEL - /* Collect Parallel I/O information for possible later use */ - if(H5P_get(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &cache->xfer_mode) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve parallel transfer method") - if(H5P_get(dx_plist, H5D_XFER_IO_XFER_OPT_MODE_NAME, &cache->xfer_opt_mode) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve parallel transfer method") -#endif /*H5_HAVE_PARALLEL*/ - - /* Get error detection properties */ - if(H5P_get(dx_plist, H5D_XFER_EDC_NAME, &cache->err_detect) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve error detection info") - - /* Get filter callback function */ - if(H5P_get(dx_plist, H5D_XFER_FILTER_CB_NAME, &cache->filter_cb) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve filter callback function") - - /* Get the data transform property */ - if(H5P_get(dx_plist, H5D_XFER_XFORM_NAME, &cache->data_xform_prop) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve data transform info") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5D_get_dxpl_cache_real() */ - - -/*-------------------------------------------------------------------------- - NAME - H5D_get_dxpl_cache - PURPOSE - Get all the values for the DXPL cache. - USAGE - herr_t H5D_get_dxpl_cache(dxpl_id, cache) - hid_t dxpl_id; IN: DXPL to query - H5D_dxpl_cache_t *cache;IN/OUT: DXPL cache to fill with values - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Query all the values from a DXPL that are needed by internal routines - within the library. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - The CACHE pointer should point at already allocated memory to place - non-default property list info. If a default property list is used, the - CACHE pointer will be changed to point at the default information. - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -herr_t -H5D_get_dxpl_cache(hid_t dxpl_id, H5D_dxpl_cache_t **cache) -{ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_get_dxpl_cache,FAIL) - - /* Check args */ - assert(cache); - - /* Check for the default DXPL */ - if(dxpl_id==H5P_DATASET_XFER_DEFAULT) - *cache=&H5D_def_dxpl_cache; - else - if(H5D_get_dxpl_cache_real(dxpl_id,*cache) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "Can't retrieve DXPL values") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5D_get_dxpl_cache() */ /*------------------------------------------------------------------------- @@ -300,7 +126,7 @@ H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, const H5S_t *mem_space = NULL; const H5S_t *file_space = NULL; char fake_char; - herr_t ret_value=SUCCEED; /* Return value */ + 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, @@ -316,7 +142,7 @@ H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") /* Check for valid selection */ - if(H5S_SELECT_VALID(mem_space)!=TRUE) + if(H5S_SELECT_VALID(mem_space) != TRUE) HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent") } /* end if */ if(H5S_ALL != file_space_id) { @@ -324,33 +150,33 @@ H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") /* Check for valid selection */ - if(H5S_SELECT_VALID(file_space)!=TRUE) + if(H5S_SELECT_VALID(file_space) != TRUE) HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent") - } + } /* end if */ /* 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)) + if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_XFER)) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") - if (!buf && H5S_GET_SELECT_NPOINTS(file_space)!=0) + if(!buf && H5S_GET_SELECT_NPOINTS(file_space) != 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") /* If the buffer is nil, and 0 element is selected, make a fake buffer. * This is for some MPI package like ChaMPIon on NCSA's tungsten which * doesn't support this feature. */ - if (!buf) + if(!buf) buf = &fake_char; /* read raw data */ - if (H5D_read(dset, mem_type_id, mem_space, file_space, plist_id, buf/*out*/) < 0) + if(H5D_read(dset, mem_type_id, 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) -} +} /* end H5Dread() */ /*------------------------------------------------------------------------- @@ -392,7 +218,7 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, const H5S_t *mem_space = NULL; const H5S_t *file_space = NULL; char fake_char; - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(H5Dwrite, FAIL) H5TRACE6("e", "iiiii*x", dset_id, mem_type_id, mem_space_id, file_space_id, @@ -408,7 +234,7 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") /* Check for valid selection */ - if (H5S_SELECT_VALID(mem_space)!=TRUE) + if(H5S_SELECT_VALID(mem_space) != TRUE) HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "memory selection+offset not within extent") } /* end if */ if(H5S_ALL != file_space_id) { @@ -416,7 +242,7 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") /* Check for valid selection */ - if(H5S_SELECT_VALID(file_space)!=TRUE) + if(H5S_SELECT_VALID(file_space) != TRUE) HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "file selection+offset not within extent") } /* end if */ @@ -424,16 +250,16 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, if(H5P_DEFAULT == plist_id) plist_id= H5P_DATASET_XFER_DEFAULT; else - if(TRUE!=H5P_isa_class(plist_id,H5P_DATASET_XFER)) + if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_XFER)) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") - if(!buf && H5S_GET_SELECT_NPOINTS(file_space)!=0) + if(!buf && H5S_GET_SELECT_NPOINTS(file_space) != 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") /* If the buffer is nil, and 0 element is selected, make a fake buffer. * This is for some MPI package like ChaMPIon on NCSA's tungsten which * doesn't support this feature. */ - if (!buf) + if(!buf) buf = &fake_char; /* write raw data */ @@ -442,7 +268,7 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, done: FUNC_LEAVE_API(ret_value) -} +} /* end H5Dwrite() */ /*------------------------------------------------------------------------- @@ -462,16 +288,18 @@ static herr_t H5D_read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, const H5S_t *file_space, hid_t dxpl_id, void *buf/*out*/) { + H5D_chunk_map_t fm; /* Chunk file<->memory mapping */ + H5D_io_info_t io_info; /* Dataset I/O info */ + H5D_type_info_t type_info; /* Datatype info for operation */ + H5D_storage_t store; /*union of EFL and chunk pointer in file space */ hssize_t snelmts; /*total number of elmts (signed) */ hsize_t nelmts; /*total number of elmts */ - H5T_path_t *tpath = NULL; /*type conversion info */ - const H5T_t *mem_type = NULL; /* Memory datatype */ - H5D_io_info_t io_info; /* Dataset I/O info */ #ifdef H5_HAVE_PARALLEL hbool_t io_info_init = FALSE; /* Whether the I/O info has been initialized */ #endif /*H5_HAVE_PARALLEL*/ + hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ - H5D_dxpl_cache_t *dxpl_cache=&_dxpl_cache; /* Data transfer property cache */ + H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5D_read) @@ -479,10 +307,6 @@ H5D_read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, /* check args */ HDassert(dataset && dataset->oloc.file); - /* Get memory datatype */ - if(NULL == (mem_type = (const H5T_t *)H5I_object_verify(mem_type_id, H5I_DATATYPE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") - if(!file_space) file_space = dataset->shared->space; if(!mem_space) @@ -492,23 +316,27 @@ H5D_read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, H5_ASSIGN_OVERFLOW(nelmts,snelmts,hssize_t,hsize_t); /* Fill the DXPL cache values for later use */ - if(H5D_get_dxpl_cache(dxpl_id,&dxpl_cache) < 0) + if(H5D_get_dxpl_cache(dxpl_id, &dxpl_cache) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") + /* Set up datatype info for operation */ + if(H5D_typeinfo_init(dataset, dxpl_cache, dxpl_id, mem_type_id, FALSE, &type_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") + #ifdef H5_HAVE_PARALLEL /* Collective access is not permissible without a MPI based VFD */ - if (dxpl_cache->xfer_mode==H5FD_MPIO_COLLECTIVE && !IS_H5FD_MPI(dataset->oloc.file)) + if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE && !IS_H5FD_MPI(dataset->oloc.file)) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based drivers only") #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)) + 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") /* Make sure that both selections have their extents set */ - if( !(H5S_has_extent(file_space)) ) + if(!(H5S_has_extent(file_space))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") - if( !(H5S_has_extent(mem_space)) ) + if(!(H5S_has_extent(mem_space))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") /* Retrieve dataset properties */ @@ -539,49 +367,56 @@ H5D_read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, HGOTO_DONE(SUCCEED) /* Go fill the user's selection with the dataset's fill value */ - if(H5D_fill(dataset->shared->dcpl_cache.fill.buf, dataset->shared->type, buf, mem_type, mem_space, dxpl_id) < 0) + if(H5D_fill(dataset->shared->dcpl_cache.fill.buf, dataset->shared->type, buf, type_info.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 datatype 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 datatype conversion also - * turns off background preservation. - */ - if (NULL==(tpath=H5T_path_find(dataset->shared->type, mem_type, NULL, NULL, dxpl_id, FALSE))) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype") - /* Set up I/O operation */ - if(H5D_ioinfo_init(dataset,dxpl_cache,dxpl_id,mem_space,file_space,tpath,&io_info) < 0) + io_info.op_type = H5D_IO_OP_READ; + io_info.u.rbuf = buf; + if(H5D_ioinfo_init(dataset, dxpl_cache, dxpl_id, &type_info, &store, &io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation") #ifdef H5_HAVE_PARALLEL io_info_init = TRUE; #endif /*H5_HAVE_PARALLEL*/ - /* Determine correct I/O routine to invoke */ - if(dataset->shared->layout.type!=H5D_CHUNKED) { - if(H5D_contig_read(&io_info, nelmts, mem_type, mem_space, file_space, tpath, - dataset->shared->type_id, mem_type_id, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") - } /* end if */ - else { - if(H5D_chunk_read(&io_info, nelmts, mem_type, mem_space, file_space, tpath, - dataset->shared->type_id, mem_type_id, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") - } /* end else */ + /* Sanity check that space is allocated, if there are elements */ + if(nelmts > 0) + HDassert(((dataset->shared->layout.type == H5D_CONTIGUOUS && H5F_addr_defined(dataset->shared->layout.u.contig.addr)) + || (dataset->shared->layout.type == H5D_CHUNKED && H5F_addr_defined(dataset->shared->layout.u.chunk.addr))) + || dataset->shared->dcpl_cache.efl.nused > 0 + || dataset->shared->layout.type == H5D_COMPACT); + + /* Call storage method's I/O initialization routine */ + if(io_info.layout_ops.init && (*io_info.layout_ops.init)(&io_info, &type_info, nelmts, file_space, mem_space, &fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + io_op_init = TRUE; + +#ifdef H5_HAVE_PARALLEL + /* Adjust I/O info for any parallel I/O */ + if(H5D_ioinfo_adjust(&io_info, dataset, dxpl_cache, dxpl_id, file_space, mem_space, &type_info, &fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O") +#endif /*H5_HAVE_PARALLEL*/ + + /* Invoke correct "high level" I/O routine */ + if((*io_info.io_ops.multi_read)(&io_info, &type_info, nelmts, file_space, mem_space, &fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") done: + /* Shut down the I/O op information */ + if(io_op_init && io_info.layout_ops.term && (*io_info.layout_ops.term)(&fm) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") #ifdef H5_HAVE_PARALLEL /* Shut down io_info struct */ - if (io_info_init) + if(io_info_init) if(H5D_ioinfo_term(&io_info) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't shut down io_info") #endif /*H5_HAVE_PARALLEL*/ + /* Shut down datatype info for operation */ + if(H5D_typeinfo_term(&type_info) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_read() */ @@ -604,16 +439,18 @@ static herr_t H5D_write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, const H5S_t *file_space, hid_t dxpl_id, const void *buf) { + H5D_chunk_map_t fm; /* Chunk file<->memory mapping */ + H5D_io_info_t io_info; /* Dataset I/O info */ + H5D_type_info_t type_info; /* Datatype info for operation */ + H5D_storage_t store; /*union of EFL and chunk pointer in file space */ hssize_t snelmts; /*total number of elmts (signed) */ hsize_t nelmts; /*total number of elmts */ - H5T_path_t *tpath = NULL; /*type conversion info */ - const H5T_t *mem_type = NULL; /* Memory datatype */ - H5D_io_info_t io_info; /* Dataset I/O info */ #ifdef H5_HAVE_PARALLEL hbool_t io_info_init = FALSE; /* Whether the I/O info has been initialized */ #endif /*H5_HAVE_PARALLEL*/ + hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ - H5D_dxpl_cache_t *dxpl_cache=&_dxpl_cache; /* Data transfer property cache */ + H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5D_write) @@ -621,33 +458,33 @@ H5D_write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, /* check args */ HDassert(dataset && dataset->oloc.file); - /* Get the memory datatype */ - if(NULL == (mem_type = (const H5T_t *)H5I_object_verify(mem_type_id, H5I_DATATYPE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") - /* All filters in the DCPL must have encoding enabled. */ if(!dataset->shared->checked_filters) { - if(H5Z_can_apply(dataset->shared->dcpl_id, dataset->shared->type_id) <0) + if(H5Z_can_apply(dataset->shared->dcpl_id, dataset->shared->type_id) < 0) HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters") dataset->shared->checked_filters = TRUE; } /* end if */ /* Check if we are allowed to write to this file */ - if(0==(H5F_get_intent(dataset->oloc.file) & H5F_ACC_RDWR)) + if(0 == (H5F_INTENT(dataset->oloc.file) & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file") /* Fill the DXPL cache values for later use */ - if(H5D_get_dxpl_cache(dxpl_id,&dxpl_cache) < 0) + if(H5D_get_dxpl_cache(dxpl_id, &dxpl_cache) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") + /* Set up datatype info for operation */ + if(H5D_typeinfo_init(dataset, dxpl_cache, dxpl_id, mem_type_id, TRUE, &type_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") + /* Various MPI based checks */ #ifdef H5_HAVE_PARALLEL if(IS_H5FD_MPI(dataset->oloc.file)) { /* If MPI based VFD 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(H5T_detect_class(mem_type, H5T_VLEN)>0) + if(H5T_detect_class(type_info.mem_type, H5T_VLEN) > 0) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing VL datatypes yet") /* If MPI based VFD is used, no VL datatype support yet. */ @@ -656,42 +493,48 @@ H5D_write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, /* We should really use H5T_detect_class() here, but it will be difficult * to detect the type of the reference if it is nested... -QAK */ - if (H5T_get_class(mem_type, TRUE)==H5T_REFERENCE && - H5T_get_ref_type(mem_type)==H5R_DATASET_REGION) + if(H5T_get_class(type_info.mem_type, TRUE) == H5T_REFERENCE && + H5T_get_ref_type(type_info.mem_type) == H5R_DATASET_REGION) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing region reference datatypes yet") + + /* Can't write to chunked datasets with filters, in parallel */ + if(dataset->shared->layout.type == H5D_CHUNKED && + dataset->shared->dcpl_cache.pline.nused > 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot write to chunked storage with filters in parallel") } /* end if */ else { /* Collective access is not permissible without a MPI based VFD */ - if (dxpl_cache->xfer_mode==H5FD_MPIO_COLLECTIVE) + if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only") } /* end else */ #endif /*H5_HAVE_PARALLEL*/ - if (!file_space) + /* Initialize dataspace information */ + if(!file_space) file_space = dataset->shared->space; - if (!mem_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") - H5_ASSIGN_OVERFLOW(nelmts,snelmts,hssize_t,hsize_t); + H5_ASSIGN_OVERFLOW(nelmts, snelmts, hssize_t, hsize_t); /* Make certain that the number of elements in each selection is the same */ - if (nelmts!=(hsize_t)H5S_GET_SELECT_NPOINTS(file_space)) + 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") /* Make sure that both selections have their extents set */ - if( !(H5S_has_extent(file_space)) ) + if(!(H5S_has_extent(file_space))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") - if( !(H5S_has_extent(mem_space)) ) + if(!(H5S_has_extent(mem_space))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") /* Retrieve dataset properties */ /* */ /* Allocate data space and initialize it if it hasn't been. */ - if(nelmts > 0 && dataset->shared->dcpl_cache.efl.nused==0 && - ((dataset->shared->layout.type==H5D_CONTIGUOUS && !H5F_addr_defined(dataset->shared->layout.u.contig.addr)) - || (dataset->shared->layout.type==H5D_CHUNKED && !H5F_addr_defined(dataset->shared->layout.u.chunk.addr)))) { + if(nelmts > 0 && dataset->shared->dcpl_cache.efl.nused == 0 && + ((dataset->shared->layout.type == H5D_CONTIGUOUS && !H5F_addr_defined(dataset->shared->layout.u.contig.addr)) + || (dataset->shared->layout.type == H5D_CHUNKED && !H5F_addr_defined(dataset->shared->layout.u.chunk.addr)))) { hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */ hbool_t full_overwrite; /* Whether we are over-writing all the elements */ @@ -703,42 +546,36 @@ H5D_write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, if(H5T_detect_class(dataset->shared->type, H5T_VLEN)) full_overwrite = FALSE; else - full_overwrite = (hsize_t)file_nelmts==nelmts ? TRUE : FALSE; + full_overwrite = (hsize_t)file_nelmts == nelmts ? TRUE : FALSE; /* Allocate storage */ if(H5D_alloc_storage(dataset->oloc.file, dxpl_id, dataset, H5D_ALLOC_WRITE, full_overwrite) < 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 datatype 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 datatype conversion also - * turns off background preservation. - */ - if (NULL==(tpath=H5T_path_find(mem_type, dataset->shared->type, NULL, NULL, dxpl_id, FALSE))) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype") - /* Set up I/O operation */ - if(H5D_ioinfo_init(dataset,dxpl_cache,dxpl_id,mem_space,file_space,tpath,&io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation") + io_info.op_type = H5D_IO_OP_WRITE; + io_info.u.wbuf = buf; + if(H5D_ioinfo_init(dataset, dxpl_cache, dxpl_id, &type_info, &store, &io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation") #ifdef H5_HAVE_PARALLEL io_info_init = TRUE; #endif /*H5_HAVE_PARALLEL*/ - /* Determine correct I/O routine to invoke */ - if(dataset->shared->layout.type!=H5D_CHUNKED) { - if(H5D_contig_write(&io_info, nelmts, mem_type, mem_space, file_space, tpath, - mem_type_id, dataset->shared->type_id, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") - } /* end if */ - else { - if(H5D_chunk_write(&io_info, nelmts, mem_type, mem_space, file_space, tpath, - mem_type_id, dataset->shared->type_id, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") - } /* end else */ + /* Call storage method's I/O initialization routine */ + if(io_info.layout_ops.init && (*io_info.layout_ops.init)(&io_info, &type_info, nelmts, file_space, mem_space, &fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + io_op_init = TRUE; + +#ifdef H5_HAVE_PARALLEL + /* Adjust I/O info for any parallel I/O */ + if(H5D_ioinfo_adjust(&io_info, dataset, dxpl_cache, dxpl_id, file_space, mem_space, &type_info, &fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O") +#endif /*H5_HAVE_PARALLEL*/ + + /* Invoke correct "high level" I/O routine */ + if((*io_info.io_ops.multi_write)(&io_info, &type_info, nelmts, file_space, mem_space, &fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") #ifdef OLD_WAY /* @@ -756,2705 +593,409 @@ H5D_write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, #endif /* OLD_WAY */ done: + /* Shut down the I/O op information */ + if(io_op_init && io_info.layout_ops.term && (*io_info.layout_ops.term)(&fm) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") #ifdef H5_HAVE_PARALLEL /* Shut down io_info struct */ - if (io_info_init) - if(H5D_ioinfo_term(&io_info) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't shut down io_info") + if(io_info_init && H5D_ioinfo_term(&io_info) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't shut down io_info") #endif /*H5_HAVE_PARALLEL*/ + /* Shut down datatype info for operation */ + if(H5D_typeinfo_term(&type_info) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_write() */ /*------------------------------------------------------------------------- - * Function: H5D_contig_read + * Function: H5D_ioinfo_init * - * Purpose: Read from a contiguous dataset. + * Purpose: Routine for determining correct I/O operations for + * each I/O action. * * Return: Non-negative on success/Negative on failure * - * Programmer: Raymond Lu - * Thursday, April 10, 2003 + * Programmer: Quincey Koziol + * Thursday, September 30, 2004 * *------------------------------------------------------------------------- */ static herr_t -H5D_contig_read(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, void *buf/*out*/) +H5D_ioinfo_init(H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, + const H5D_type_info_t *type_info, H5D_storage_t *store, H5D_io_info_t *io_info) { - H5D_t *dataset=io_info->dset; /* Local pointer to dataset info */ - const H5D_dxpl_cache_t *dxpl_cache=io_info->dxpl_cache; /* Local pointer to dataset transfer info */ - 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 max_type_size; /* Size of largest source/destination type */ - size_t target_size; /*desired buffer size */ - size_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; /*datatype conv buffer */ - uint8_t *bkg_buf = NULL; /*background buffer */ - hsize_t smine_start; /*strip mine start loc */ - size_t n, smine_nelmts; /*elements per strip */ - H5D_storage_t store; /*union of storage info for dataset */ - - - herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_contig_read) - - assert (buf); - - /* Initialize storage info for this dataset */ - if (dataset->shared->dcpl_cache.efl.nused > 0) - HDmemcpy(&store.efl, &(dataset->shared->dcpl_cache.efl), sizeof(H5O_efl_t)); - else { - store.contig.dset_addr = dataset->shared->layout.u.contig.addr; - store.contig.dset_size = dataset->shared->layout.u.contig.size; - } /* end if */ - - /* Set dataset storage for I/O info */ - io_info->store=&store; - - /* - * If there is no type conversion then read directly into the - * application's buffer. This saves at least one mem-to-mem copy. - */ - if ( H5Z_xform_noop(dxpl_cache->data_xform_prop) && H5T_path_noop(tpath)) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - /* Sanity check dataset, then read it */ - assert(((dataset->shared->layout.type == H5D_CONTIGUOUS && H5F_addr_defined(dataset->shared->layout.u.contig.addr)) - || (dataset->shared->layout.type == H5D_CHUNKED && H5F_addr_defined(dataset->shared->layout.u.chunk.addr))) - || dataset->shared->dcpl_cache.efl.nused > 0 || 0 == nelmts - || dataset->shared->layout.type==H5D_COMPACT); - H5_CHECK_OVERFLOW(nelmts,hsize_t,size_t); + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_ioinfo_init) -#ifdef H5_HAVE_PARALLEL - if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) { - if(H5D_contig_collective_io(io_info,file_space,mem_space,buf,FALSE) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "contiguous read failed in collective mode"); - } - else -#endif - { - if((io_info->ops.read)(io_info, (size_t)nelmts, - H5T_get_size(dataset->shared->type), file_space, mem_space, - (haddr_t)0, NULL, buf/*out*/) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "contiguous read failed "); - } - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].read_timer), &timer); - io_info->stats->stats[1].read_nbytes += nelmts * H5T_get_size(dataset->shared->type); - io_info->stats->stats[1].read_ncalls++; -#endif - - /* direct xfer accomplished successfully */ - HGOTO_DONE(SUCCEED) - } /* end if */ + /* check args */ + HDassert(dset); + HDassert(dset->oloc.file); + HDassert(type_info); + HDassert(type_info->tpath); + HDassert(io_info); - /* - * This is the general case (type conversion, usually). - */ - if(nelmts==0) - HGOTO_DONE(SUCCEED) - - /* Compute element sizes and other parameters */ - src_type_size = H5T_get_size(dataset->shared->type); - dst_type_size = H5T_get_size(mem_type); - max_type_size = MAX(src_type_size, dst_type_size); - target_size = dxpl_cache->max_temp_buf; - /* 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_TEMP_BUF_SIZE) { - /* If the buffer is too small to hold even one element, make it bigger */ - if(target_size(nelmts*max_type_size)) - target_size=(size_t)(nelmts*max_type_size); - } /* end if */ - request_nelmts = target_size / max_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 */ + /* Set up "normal" I/O fields */ + io_info->dset = dset; + io_info->dxpl_cache = dxpl_cache; + io_info->dxpl_id = dxpl_id; + io_info->store = store; - /* - * 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)) { - H5T_bkg_t path_bkg; /* Type conversion's background info */ - - /* Retrieve the bkgr buffer property */ - need_bkg=dxpl_cache->bkgr_buf_type; - path_bkg = H5T_path_bkg(tpath); - need_bkg = MAX(path_bkg, need_bkg); - } else { - need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/ - } /* end else */ - if(NULL == (tconv_buf = (uint8_t *)dxpl_cache->tconv_buf)) { - /* Allocate temporary buffer */ - if(NULL == (tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion") - } /* end if */ - if(need_bkg && NULL == (bkg_buf = (uint8_t *)dxpl_cache->bkgr_buf)) { - /* Allocate background buffer */ - /* (Need calloc()-like call since memory needs to be initialized) */ - if(NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, (request_nelmts * dst_type_size)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion") - } /* end if */ + /* Set I/O operations to initial values */ + io_info->layout_ops = *dset->shared->layout_ops; - /* Start strip mining... */ - for (smine_start=0; smine_startio_ops.multi_read = dset->shared->layout_ops->ser_read; + io_info->io_ops.multi_write = dset->shared->layout_ops->ser_write; + /* Set the I/O operations for reading/writing single blocks on disk */ + if(type_info->is_xform_noop && type_info->is_conv_noop) { /* - * Gather the data from disk into the datatype 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 */ - HDassert(((dataset->shared->layout.type == H5D_CONTIGUOUS && H5F_addr_defined(dataset->shared->layout.u.contig.addr)) - || (dataset->shared->layout.type == H5D_CHUNKED && H5F_addr_defined(dataset->shared->layout.u.chunk.addr))) - || dataset->shared->dcpl_cache.efl.nused > 0 || - dataset->shared->layout.type == H5D_COMPACT); - n = H5D_select_fgath(io_info, file_space, &file_iter, smine_nelmts, (haddr_t)0, NULL, tconv_buf/*out*/); - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].gath_timer), &timer); - io_info->stats->stats[1].gath_nbytes += n * src_type_size; - io_info->stats->stats[1].gath_ncalls++; -#endif - 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. This optimization is for Chicago company */ - if(H5T_SUBSET_SRC==H5T_path_compound_subset(tpath)) { - if(H5D_compound_opt_read(smine_nelmts, mem_space, &mem_iter, dxpl_cache, - src_id, dst_id, H5T_SUBSET_SRC, tconv_buf, buf /*out*/)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - - continue; - } else if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) { - if(H5D_compound_opt_read(smine_nelmts, mem_space, &mem_iter, dxpl_cache, - src_id, dst_id, H5T_SUBSET_DST, tconv_buf, buf /*out*/)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - - continue; - } - - if (H5T_BKG_YES==need_bkg) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - n = H5D_select_mgath(buf, mem_space, &bkg_iter, - smine_nelmts, dxpl_cache, bkg_buf/*out*/); -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].bkg_timer), &timer); - io_info->stats->stats[1].bkg_nbytes += n * dst_type_size; - io_info->stats->stats[1].bkg_ncalls++; -#endif - if (n!=smine_nelmts) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed") - } /* end if */ - - /* - * Perform datatype conversion. + * If there is no data transform or type conversion then read directly into + * the application's buffer. This saves at least one mem-to-mem copy. */ - if (H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - - /* Do the data transform after the conversion (since we're using type mem_type) */ - if(!H5Z_xform_noop(dxpl_cache->data_xform_prop)) - if( H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, mem_type) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") - + io_info->io_ops.single_read = H5D_select_read; + io_info->io_ops.single_write = H5D_select_write; + } /* end if */ + else { /* - * Scatter the data into memory. + * This is the general case (type conversion, usually). */ -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - status = H5D_select_mscat(tconv_buf, mem_space, - &mem_iter, smine_nelmts, dxpl_cache, buf/*out*/); -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].scat_timer), &timer); - io_info->stats->stats[1].scat_nbytes += smine_nelmts * dst_type_size; - io_info->stats->stats[1].scat_ncalls++; -#endif - if (status<0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, 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 */ + io_info->io_ops.single_read = H5D_scatgath_read; + io_info->io_ops.single_write = H5D_scatgath_write; + } /* end else */ - if (tconv_buf && NULL==dxpl_cache->tconv_buf) - (void)H5FL_BLK_FREE(type_conv,tconv_buf); - if (bkg_buf && NULL==dxpl_cache->bkgr_buf) - (void)H5FL_BLK_FREE(type_conv,bkg_buf); +#ifdef H5_HAVE_PARALLEL + /* Determine if the file was opened with an MPI VFD */ + io_info->using_mpi_vfd = IS_H5FD_MPI(dset->oloc.file); +#endif /* H5_HAVE_PARALLEL */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_contig_read() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D_ioinfo_init() */ /*------------------------------------------------------------------------- - * Function: H5D_contig_write + * Function: H5D_typeinfo_init * - * Purpose: Write to a contiguous dataset. + * Purpose: Routine for determining correct datatype information for + * each I/O action. * * Return: Non-negative on success/Negative on failure * - * Programmer: Raymond Lu - * Thursday, April 10, 2003 + * Programmer: Quincey Koziol + * Tuesday, March 4, 2008 * *------------------------------------------------------------------------- */ static herr_t -H5D_contig_write(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, const void *buf) +H5D_typeinfo_init(const H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, + hid_t dxpl_id, hid_t mem_type_id, hbool_t do_write, + H5D_type_info_t *type_info) { - H5D_t *dataset=io_info->dset; /* Local pointer to dataset info */ - const H5D_dxpl_cache_t *dxpl_cache=io_info->dxpl_cache; /* Local pointer to dataset transfer info */ - 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 max_type_size; /* Size of largest source/destination type */ - size_t target_size; /*desired buffer size */ - size_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; /*datatype conv buffer */ - uint8_t *bkg_buf = NULL; /*background buffer */ - hsize_t smine_start; /*strip mine start loc */ - size_t n, smine_nelmts; /*elements per strip */ - H5D_storage_t store; /*union of storage info for dataset */ - - herr_t ret_value = SUCCEED; /*return value */ + const H5T_t *src_type; /* Source datatype */ + const H5T_t *dst_type; /* Destination datatype */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5D_contig_write) + FUNC_ENTER_NOAPI_NOINIT(H5D_typeinfo_init) - assert (buf); + /* check args */ + HDassert(type_info); + HDassert(dset); - /* Initialize storage info for this dataset */ - if(dataset->shared->dcpl_cache.efl.nused > 0) - HDmemcpy(&store.efl, &(dataset->shared->dcpl_cache.efl), sizeof(H5O_efl_t)); - else { - store.contig.dset_addr = dataset->shared->layout.u.contig.addr; - store.contig.dset_size = dataset->shared->layout.u.contig.size; - } /* end if */ + /* Initialize type info safely */ + HDmemset(type_info, 0, sizeof(H5D_type_info_t)); - /* Set dataset storage for I/O info */ - io_info->store = &store; + /* Get the memory & dataset datatypes */ + if(NULL == (type_info->mem_type = (const H5T_t *)H5I_object_verify(mem_type_id, H5I_DATATYPE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") + type_info->dset_type = dset->shared->type; - /* - * If there is no type conversion then write directly from the - * application's buffer. This saves at least one mem-to-mem copy. - */ - if(H5Z_xform_noop(dxpl_cache->data_xform_prop) && H5T_path_noop(tpath)) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - H5_CHECK_OVERFLOW(nelmts,hsize_t,size_t); -#ifdef H5_HAVE_PARALLEL - if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) { - if(H5D_contig_collective_io(io_info, file_space, mem_space, buf, TRUE) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "contiguous write failed in collective mode") - } - else -#endif - { - if((io_info->ops.write)(io_info, (size_t)nelmts, - H5T_get_size(dataset->shared->type), file_space, mem_space, - (haddr_t)0, NULL, buf/*out*/) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "contiguous write failed ") - } - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[0].write_timer), &timer); - io_info->stats->stats[0].write_nbytes += nelmts * H5T_get_size(mem_type); - io_info->stats->stats[0].write_ncalls++; -#endif - - /* direct xfer accomplished successfully */ - HGOTO_DONE(SUCCEED) + if(do_write) { + src_type = type_info->mem_type; + dst_type = dset->shared->type; + type_info->src_type_id = mem_type_id; + type_info->dst_type_id = dset->shared->type_id; } /* end if */ + else { + src_type = dset->shared->type; + dst_type = type_info->mem_type; + type_info->src_type_id = dset->shared->type_id; + type_info->dst_type_id = mem_type_id; + } /* end else */ /* - * This is the general case. - */ - if(nelmts==0) - HGOTO_DONE(SUCCEED) - - /* Compute element sizes and other parameters */ - src_type_size = H5T_get_size(mem_type); - dst_type_size = H5T_get_size(dataset->shared->type); - max_type_size = MAX(src_type_size, dst_type_size); - target_size = dxpl_cache->max_temp_buf; - /* 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 + * 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 datatype 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 datatype conversion also + * turns off background preservation. */ - if(target_size == H5D_TEMP_BUF_SIZE) { - /* If the buffer is too small to hold even one element, make it bigger */ - if(target_size(nelmts*max_type_size)) - target_size=(size_t)(nelmts*max_type_size); - } /* end if */ - request_nelmts = target_size / max_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 */ + if(NULL == (type_info->tpath = H5T_path_find(src_type, dst_type, NULL, NULL, dxpl_id, FALSE))) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype") - /* - * 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_detect_class(dataset->shared->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 if (H5T_path_bkg(tpath)) { - H5T_bkg_t path_bkg; /* Type conversion's background info */ - - /* Retrieve the bkgr buffer property */ - need_bkg=dxpl_cache->bkgr_buf_type; - path_bkg = H5T_path_bkg(tpath); - need_bkg = MAX (path_bkg, need_bkg); - } else { - need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/ - } /* end else */ - if(NULL == (tconv_buf = (uint8_t *)dxpl_cache->tconv_buf)) { - /* Allocate temporary buffer */ - if(NULL == (tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion") - } /* end if */ - if(need_bkg && NULL == (bkg_buf = (uint8_t *)dxpl_cache->bkgr_buf)) { - /* Allocate background buffer */ - /* (Don't need calloc()-like call since file data is already initialized) */ - if(NULL == (bkg_buf = H5FL_BLK_MALLOC(type_conv, (request_nelmts * dst_type_size)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion") + /* Precompute some useful information */ + type_info->src_type_size = H5T_get_size(src_type); + type_info->dst_type_size = H5T_get_size(dst_type); + type_info->max_type_size = MAX(type_info->src_type_size, type_info->dst_type_size); + type_info->is_conv_noop = H5T_path_noop(type_info->tpath); + type_info->is_xform_noop = H5Z_xform_noop(dxpl_cache->data_xform_prop); + if(type_info->is_xform_noop && type_info->is_conv_noop) { + type_info->cmpd_subset = H5T_SUBSET_FALSE; + type_info->need_bkg = H5T_BKG_NO; } /* end if */ + else { + size_t target_size; /* Desired buffer size */ - /* Start strip mining... */ - for (smine_start=0; smine_startcmpd_subset = H5T_path_compound_subset(type_info->tpath); - /* - * Gather data from application buffer into the datatype conversion - * buffer. Also gather data from the file into the background buffer - * if necessary. - */ -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - n = H5D_select_mgath(buf, mem_space, &mem_iter, - smine_nelmts, dxpl_cache, tconv_buf/*out*/); -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[0].gath_timer), &timer); - io_info->stats->stats[0].gath_nbytes += n * src_type_size; - io_info->stats->stats[0].gath_ncalls++; -#endif - 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. This - * optimization is for Chicago company */ - if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) { - if(H5D_compound_opt_write(smine_nelmts, src_id, dst_id, tconv_buf)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - } else { - if (H5T_BKG_YES==need_bkg) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - n = H5D_select_fgath(io_info, file_space, &bkg_iter, smine_nelmts, - (haddr_t)0, NULL, bkg_buf/*out*/); - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[0].bkg_timer), &timer); - io_info->stats->stats[0].bkg_nbytes += n * dst_type_size; - io_info->stats->stats[0].bkg_ncalls++; -#endif - if (n!=smine_nelmts) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed") + /* Check if we need a background buffer */ + if(do_write && H5T_detect_class(dset->shared->type, H5T_VLEN)) + type_info->need_bkg = H5T_BKG_YES; + else { + H5T_bkg_t path_bkg; /* Type conversion's background info */ + + if((path_bkg = H5T_path_bkg(type_info->tpath))) { + /* Retrieve the bkgr buffer property */ + type_info->need_bkg = dxpl_cache->bkgr_buf_type; + type_info->need_bkg = MAX(path_bkg, type_info->need_bkg); } /* end if */ + else + type_info->need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/ + } /* end else */ - /* - * Perform datatype conversion. - */ - if(H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - /* Do the data transform after the type conversion (since we're using dataset->shared->type). */ - if(!H5Z_xform_noop(dxpl_cache->data_xform_prop)) - if( H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, dataset->shared->type) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") - } + /* Set up datatype conversion/background buffers */ + + /* Get buffer size from DXPL */ + target_size = dxpl_cache->max_temp_buf; + + /* If the buffer is too small to hold even one element, try to make it bigger */ + if(target_size < type_info->max_type_size) { + hbool_t default_buffer_info; /* Whether the buffer information are the defaults */ + + /* Detect if we have all default settings for buffers */ + default_buffer_info = (H5D_TEMP_BUF_SIZE == dxpl_cache->max_temp_buf) + && (NULL == dxpl_cache->tconv_buf) && (NULL == dxpl_cache->bkgr_buf); + + /* Check if we are using the default buffer info */ + if(default_buffer_info) + /* OK to get bigger for library default settings */ + target_size = type_info->max_type_size; + else + /* Don't get bigger than the application has requested */ + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small") + } /* end if */ + + /* Compute the number of elements that will fit into buffer */ + type_info->request_nelmts = target_size / type_info->max_type_size; + + /* Sanity check elements in temporary buffer */ + if(type_info->request_nelmts == 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small") /* - * Scatter the data out to the file. + * 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. */ -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - status = H5D_select_fscat(io_info, file_space, &file_iter, smine_nelmts, - (haddr_t)0, NULL, tconv_buf); -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[0].scat_timer), &timer); - io_info->stats->stats[0].scat_nbytes += smine_nelmts * dst_type_size; - io_info->stats->stats[0].scat_ncalls++; -#endif - if (status<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "scatter failed") - } /* end for */ + if(NULL == (type_info->tconv_buf = (uint8_t *)dxpl_cache->tconv_buf)) { + /* Allocate temporary buffer */ + if(NULL == (type_info->tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion") + type_info->tconv_buf_allocated = TRUE; + } /* end if */ + if(type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)dxpl_cache->bkgr_buf)) { + size_t bkg_size; /* Desired background buffer size */ + + /* Compute the background buffer size */ + /* (don't try to use buffers smaller than the default size) */ + bkg_size = type_info->request_nelmts * type_info->dst_type_size; + if(bkg_size < dxpl_cache->max_temp_buf) + bkg_size = dxpl_cache->max_temp_buf; + + /* Allocate background buffer */ + /* (Need calloc()-like call since memory needs to be initialized) */ + if(NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion") + type_info->bkg_buf_allocated = TRUE; + } /* end if */ + } /* end else */ 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 */ - - if (tconv_buf && NULL==dxpl_cache->tconv_buf) - (void)H5FL_BLK_FREE(type_conv,tconv_buf); - if (bkg_buf && NULL==dxpl_cache->bkgr_buf) - (void)H5FL_BLK_FREE(type_conv,bkg_buf); - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_contig_write() */ +} /* end H5D_typeinfo_init() */ +#ifdef H5_HAVE_PARALLEL /*------------------------------------------------------------------------- - * Function: H5D_chunk_read + * Function: H5D_ioinfo_adjust * - * Purpose: Read from a chunked dataset. + * Purpose: Adjust operation's I/O info for any parallel I/O * * Return: Non-negative on success/Negative on failure * - * Programmer: Raymond Lu - * Thursday, April 10, 2003 + * Programmer: Quincey Koziol + * Thursday, March 27, 2008 * - * Modification: - * Raymond Lu - * 20 July 2007 - * Moved H5D_istore_lock and H5D_istore_unlock to this level - * from H5D_istore_readvv to avoid frequent lock and unlock - * and to improve performance. *------------------------------------------------------------------------- */ static herr_t -H5D_chunk_read(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, void *buf/*out*/) +H5D_ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, + const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, + const H5S_t *file_space, const H5S_t *mem_space, + const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm) { - H5D_t *dataset=io_info->dset; /* Local pointer to dataset info */ - const H5D_dxpl_cache_t *dxpl_cache=io_info->dxpl_cache; /* Local pointer to dataset transfer info */ - H5D_chunk_map_t fm; /* File<->memory mapping */ - H5SL_node_t *chunk_node; /* Current node in chunk skip list */ - 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 max_type_size; /* Size of largest source/destination type */ - size_t target_size; /*desired buffer size */ - size_t request_nelmts; /*requested strip mine */ - hsize_t smine_start; /*strip mine start loc */ - size_t n, smine_nelmts; /*elements per strip */ - size_t accessed_bytes = 0; /*total accessed size in a chunk */ - 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 */ - H5T_bkg_t need_bkg; /*type of background buf*/ - uint8_t *tconv_buf = NULL; /*datatype conv buffer */ - uint8_t *bkg_buf = NULL; /*background buffer */ - H5D_storage_t store; /*union of EFL and chunk pointer in file space */ - void *chunk = NULL; - haddr_t chunk_addr; /* Chunk address on disk */ - H5D_istore_ud1_t udata; /*B-tree pass-through */ - unsigned idx_hint=0; /* Cache index hint */ - herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_read) - - assert (buf); + herr_t ret_value = SUCCEED; /* Return value */ - /* Map elements between file and memory for each chunk*/ - if(H5D_create_chunk_map(&fm, io_info, nelmts, file_space, mem_space, mem_type) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't build chunk mapping") + FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_adjust) - /* Set dataset storage for I/O info */ - io_info->store=&store; + /* check args */ + HDassert(dset); + HDassert(dset->oloc.file); + HDassert(mem_space); + HDassert(file_space); + HDassert(type_info); + HDassert(type_info->tpath); + HDassert(io_info); - /* Compute element sizes */ - src_type_size = H5T_get_size(dataset->shared->type); - dst_type_size = H5T_get_size(mem_type); - max_type_size = MAX(src_type_size, dst_type_size); + /* Make any parallel I/O adjustments */ + if(io_info->using_mpi_vfd) { + htri_t opt; /* Flag whether a selection is optimizable */ - /* - * If there is no type conversion then read directly into the - * application's buffer. This saves at least one mem-to-mem copy. - */ - if ( H5Z_xform_noop(dxpl_cache->data_xform_prop) && H5T_path_noop(tpath)) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - /* Sanity check dataset, then read it */ - HDassert(((dataset->shared->layout.type == H5D_CONTIGUOUS && H5F_addr_defined(dataset->shared->layout.u.contig.addr)) - || (dataset->shared->layout.type == H5D_CHUNKED && H5F_addr_defined(dataset->shared->layout.u.chunk.addr))) - || dataset->shared->dcpl_cache.efl.nused > 0 || 0 == nelmts - || dataset->shared->layout.type == H5D_COMPACT); + /* Record the original state of parallel I/O transfer options */ + io_info->orig.xfer_mode = io_info->dxpl_cache->xfer_mode; + io_info->orig.coll_opt_mode = io_info->dxpl_cache->coll_opt_mode; + io_info->orig.io_ops.single_read = io_info->io_ops.single_read; + io_info->orig.io_ops.single_write = io_info->io_ops.single_write; -#ifdef H5_HAVE_PARALLEL - /* Check whether the collective mode can be turned off globally*/ -#ifndef H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS - if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) { - if(H5D_mpio_chunk_adjust_iomode(io_info ,&fm)) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't adjust collective I/O") - } -#endif /* H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS */ - /* Temporarily shut down collective IO for chunking */ - if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) { - if(H5D_chunk_collective_io(io_info, &fm, buf, FALSE) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunked read failed in collective mode") - } - else {/* sequential or independent read */ -#endif - /* Get first node in chunk skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); - - while(chunk_node) { - H5D_chunk_info_t *chunk_info; /* chunk information */ - - /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); - - /* Pass in chunk's coordinates in a union. */ - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; - - /* Load the chunk into cache and lock it. */ - chunk_addr = H5D_istore_get_addr(io_info, &udata); - if(H5D_istore_if_load(io_info, chunk_addr)) { - if(NULL == (chunk = H5D_istore_lock(io_info, &udata, FALSE, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") - } else - chunk = NULL; - - /* Perform the actual read operation */ - if((io_info->ops.read)(io_info, chunk_info->chunk_points, - src_type_size, chunk_info->fspace, - chunk_info->mspace, chunk_addr, chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, " chunked read failed") - - /* Release the cache lock on the chunk. */ - if(chunk) { - accessed_bytes = chunk_info->chunk_points * src_type_size; - if(H5D_istore_unlock(io_info, FALSE, idx_hint, chunk, accessed_bytes) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") - } /* end if */ - - /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); - } /* end while */ -#ifdef H5_HAVE_PARALLEL - } -#endif + /* Get MPI communicator */ + if(MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset->oloc.file))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator") + /* Check if we can set direct MPI-IO read/write functions */ + if((opt = H5D_mpio_opt_possible(io_info, file_space, mem_space, type_info, fm)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace ") -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].read_timer), &timer); - io_info->stats->stats[1].read_nbytes += nelmts * src_type_size; - io_info->stats->stats[1].read_ncalls++; -#endif + /* Check if we can use the optimized parallel I/O routines */ + if(opt == TRUE) { + /* Override the I/O op pointers to the MPI-specific routines */ + io_info->io_ops.multi_read = dset->shared->layout_ops->par_read; + io_info->io_ops.multi_write = dset->shared->layout_ops->par_write; + io_info->io_ops.single_read = H5D_mpio_select_read; + io_info->io_ops.single_write = H5D_mpio_select_write; + } /* end if */ + else { + /* If we won't be doing collective I/O, but the user asked for + * collective I/O, change the request to use independent I/O, but + * mark it so that we remember to revert the change. + */ + if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) { + H5P_genplist_t *dx_plist; /* Data transer property list */ - /* direct xfer accomplished successfully */ - HGOTO_DONE(SUCCEED) - } /* end if */ + /* Get the dataset transfer property list */ + if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list") - /* - * This is the general case (type conversion, usually). - */ - if(nelmts==0) - HGOTO_DONE(SUCCEED) - - /* Compute buffer sizes and other parameters */ - target_size = dxpl_cache->max_temp_buf; - /* 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_TEMP_BUF_SIZE) { - /* If the buffer is too small to hold even one element, make it bigger */ - if(target_size(nelmts*max_type_size)) - target_size=(size_t)(nelmts*max_type_size); + /* Change the xfer_mode to independent for handling the I/O */ + io_info->dxpl_cache->xfer_mode = H5FD_MPIO_INDEPENDENT; + if(H5P_set(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") + } /* end if */ + } /* end else */ } /* end if */ - request_nelmts = target_size / max_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)) { - H5T_bkg_t path_bkg; /* Type conversion's background info */ - - /* Retrieve the bkgr buffer property */ - need_bkg=dxpl_cache->bkgr_buf_type; - path_bkg = H5T_path_bkg(tpath); - need_bkg = MAX(path_bkg, need_bkg); - } else { - need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/ - } /* end else */ - if(NULL == (tconv_buf = (uint8_t *)dxpl_cache->tconv_buf)) { - /* Allocate temporary buffer */ - if(NULL == (tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion") - } /* end if */ - if(need_bkg && NULL == (bkg_buf = (uint8_t *)dxpl_cache->bkgr_buf)) { - /* Allocate background buffer */ - /* (Need calloc()-like call since memory needs to be initialized) */ - if(NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, (request_nelmts * dst_type_size)))) - 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 skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); - - /* Iterate through chunks to be operated on */ - while(chunk_node) { - H5D_chunk_info_t *chunk_info; /* chunk information */ - - /* Get the actual chunk information from the skip list nodes */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); - - /* initialize selection iterator */ - if (H5S_select_iter_init(&file_iter, chunk_info->fspace, 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, chunk_info->mspace, 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, chunk_info->mspace, 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 */ - - /* Pass in chunk's coordinates in a union*/ - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; - - /* Load the chunk into cache and lock it. */ - chunk_addr = H5D_istore_get_addr(io_info, &udata); - - if(H5D_istore_if_load(io_info, chunk_addr)) { - if(NULL == (chunk = H5D_istore_lock(io_info, &udata, FALSE, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") - } else - chunk = NULL; - - for(smine_start=0; smine_startchunk_points; smine_start+=smine_nelmts) { - /* Go figure out how many elements to read from the file */ - assert(H5S_SELECT_ITER_NELMTS(&file_iter)==(chunk_info->chunk_points-smine_start)); - smine_nelmts = (size_t)MIN(request_nelmts, (chunk_info->chunk_points-smine_start)); - - /* - * Gather the data from disk into the datatype 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 */ - HDassert(((dataset->shared->layout.type == H5D_CONTIGUOUS && H5F_addr_defined(dataset->shared->layout.u.contig.addr)) - || (dataset->shared->layout.type == H5D_CHUNKED && H5F_addr_defined(dataset->shared->layout.u.chunk.addr))) - || dataset->shared->dcpl_cache.efl.nused > 0 || dataset->shared->layout.type == H5D_COMPACT); - - if(chunk) { - n = H5D_select_mgath(chunk, chunk_info->fspace, &file_iter, - smine_nelmts, dxpl_cache, tconv_buf/*out*/); - } else { - n = H5D_select_fgath(io_info, chunk_info->fspace, &file_iter, smine_nelmts, - chunk_addr, NULL, tconv_buf/*out*/); - } - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].gath_timer), &timer); - io_info->stats->stats[1].gath_nbytes += n * src_type_size; - io_info->stats->stats[1].gath_ncalls++; -#endif - 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. This optimization is for Chicago company */ - if(H5T_SUBSET_SRC==H5T_path_compound_subset(tpath)) { - if(H5D_compound_opt_read(smine_nelmts, chunk_info->mspace, &mem_iter, dxpl_cache, - src_id, dst_id, H5T_SUBSET_SRC, tconv_buf, buf /*out*/)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - - continue; - } else if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) { - if(H5D_compound_opt_read(smine_nelmts, chunk_info->mspace, &mem_iter, dxpl_cache, - src_id, dst_id, H5T_SUBSET_DST, tconv_buf, buf /*out*/)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - - continue; - } - - if(H5T_BKG_YES == need_bkg) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - n = H5D_select_mgath(buf, chunk_info->mspace, &bkg_iter, smine_nelmts, dxpl_cache, bkg_buf/*out*/); -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].bkg_timer), &timer); - io_info->stats->stats[1].bkg_nbytes += n * dst_type_size; - io_info->stats->stats[1].bkg_ncalls++; -#endif - if(n != smine_nelmts) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed") - } /* end if */ - - /* - * Perform datatype conversion. - */ - if(H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - - /* Do the data transform after the conversion (since we're using type mem_type) */ - if(!H5Z_xform_noop(dxpl_cache->data_xform_prop)) - if(H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, mem_type) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") - - /* - * Scatter the data into memory. - */ -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - status = H5D_select_mscat(tconv_buf, chunk_info->mspace, &mem_iter, smine_nelmts, dxpl_cache, buf/*out*/); -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].scat_timer), &timer); - io_info->stats->stats[1].scat_nbytes += smine_nelmts * dst_type_size; - io_info->stats->stats[1].scat_ncalls++; -#endif - if(status < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") - } /* end for */ - - /* Release the cache lock on the chunk. */ - if(chunk) { - accessed_bytes = chunk_info->chunk_points * src_type_size; - if(H5D_istore_unlock(io_info, FALSE, idx_hint, chunk, accessed_bytes) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") - } /* end if */ - - /* Release selection iterators */ - if(file_iter_init) { - if(H5S_SELECT_ITER_RELEASE(&file_iter) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") - file_iter_init = FALSE; - } /* end if */ - if(mem_iter_init) { - if(H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") - mem_iter_init = FALSE; - } /* end if */ - if(bkg_iter_init) { - if(H5S_SELECT_ITER_RELEASE(&bkg_iter) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") - bkg_iter_init = FALSE; - } /* end if */ - - /* Get the next chunk node in the skip list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); - } /* end while */ - -done: - /* Release selection iterators, if necessary */ - 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 */ - - if(tconv_buf && NULL == dxpl_cache->tconv_buf) - (void)H5FL_BLK_FREE(type_conv, tconv_buf); - if(bkg_buf && NULL == dxpl_cache->bkgr_buf) - (void)H5FL_BLK_FREE(type_conv, bkg_buf); - - /* 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() */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_ioinfo_adjust() */ /*------------------------------------------------------------------------- - * Function: H5D_chunk_write + * Function: H5D_ioinfo_term * - * Purpose: Writes to a chunked dataset. + * Purpose: Common logic for terminating an I/O info object + * (Only used for restoring MPI transfer mode currently) * * Return: Non-negative on success/Negative on failure * - * Programmer: Raymond Lu - * Thursday, April 10, 2003 + * Programmer: Quincey Koziol + * Friday, February 6, 2004 * - * Modification: - * Raymond Lu - * 20 July 2007 - * Moved H5D_istore_lock and H5D_istore_unlock to this level - * from H5D_istore_writevv to avoid frequent lock and unlock - * and to improve performance. *------------------------------------------------------------------------- */ static herr_t -H5D_chunk_write(H5D_io_info_t *io_info, hsize_t nelmts, - const H5T_t *mem_type, const H5S_t *mem_space, - const H5S_t *file_space, H5T_path_t *tpath, - hid_t src_id, hid_t dst_id, const void *buf) +H5D_ioinfo_term(H5D_io_info_t *io_info) { - H5D_t *dataset=io_info->dset; /* Local pointer to dataset info */ - const H5D_dxpl_cache_t *dxpl_cache=io_info->dxpl_cache; /* Local pointer to dataset transfer info */ - H5D_chunk_map_t fm; /* File<->memory mapping */ - H5SL_node_t *chunk_node; /* Current node in chunk skip list */ - 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 max_type_size; /* Size of largest source/destination type */ - size_t target_size; /*desired buffer size */ - size_t request_nelmts; /*requested strip mine */ - size_t accessed_bytes; /*total accessed size in a chunk */ - hsize_t smine_start; /*strip mine start loc */ - size_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; /*datatype conv buffer */ - uint8_t *bkg_buf = NULL; /*background buffer */ - H5D_storage_t store; /*union of EFL and chunk pointer in file space */ - void *chunk = NULL; - haddr_t chunk_addr; /* Chunk address on disk */ - H5D_istore_ud1_t udata; /*B-tree pass-through */ - unsigned idx_hint=0; /* Cache index hint */ - hbool_t relax=TRUE; /* Whether whole chunk is selected */ herr_t ret_value = SUCCEED; /*return value */ - FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_write) - - assert (buf); - - /* Map elements between file and memory for each chunk*/ - if(H5D_create_chunk_map(&fm, io_info, nelmts, file_space, mem_space, mem_type) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't build chunk mapping") - - /* Set dataset storage for I/O info */ - io_info->store=&store; - -#ifdef H5_HAVE_PARALLEL - /* Additional sanity checks when operating in parallel */ - if(io_info->using_mpi_vfd) { - if (chunk_addr==HADDR_UNDEF) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to locate raw data chunk") - if (dataset->shared->dcpl_cache.pline.nused>0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot write to chunked storage with filters in parallel") - } /* end if */ -#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->shared->type); - max_type_size = MAX(src_type_size, dst_type_size); - - /* - * If there is no type conversion then write directly from the - * application's buffer. This saves at least one mem-to-mem copy. - */ - if ( H5Z_xform_noop(dxpl_cache->data_xform_prop) && H5T_path_noop(tpath)) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - -#ifdef H5_HAVE_PARALLEL - /* Check whether the collective mode can be turned off globally*/ -#ifndef H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS - if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) { - if(H5D_mpio_chunk_adjust_iomode(io_info,&fm)) - HGOTO_ERROR(H5E_DATASET,H5E_CANTGET,FAIL,"can't adjust collective I/O") - } -#endif /* H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS */ - /* Temporarily shut down collective IO for chunking */ - if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) { - if(H5D_chunk_collective_io(io_info,&fm,buf,TRUE) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunked write failed in collective mode"); - } - else {/* sequential or independent write */ -#endif /* H5_HAVE_PARALLEL */ - /* Get first node in chunk skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); - - while(chunk_node) { - H5D_chunk_info_t *chunk_info; /* Chunk information */ - - /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); - - /* Pass in chunk's coordinates in a union. */ - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; - - /* Load the chunk into cache. But if the whole chunk is written, - * simply allocate space instead of load the chunk. */ - chunk_addr = H5D_istore_get_addr(io_info, &udata); - - if(H5D_istore_if_load(io_info, chunk_addr)) { - accessed_bytes = chunk_info->chunk_points * dst_type_size; - if(accessed_bytes != dataset->shared->layout.u.chunk.size) - relax = FALSE; - - if(NULL == (chunk = H5D_istore_lock(io_info, &udata, relax, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") - } else - chunk = NULL; - - /* Perform the actual read operation */ - if((io_info->ops.write)(io_info, chunk_info->chunk_points, - dst_type_size, chunk_info->fspace, - chunk_info->mspace, chunk_addr, chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, " chunked write failed") - - /* Release the cache lock on the chunk. */ - if(chunk) { - if(H5D_istore_unlock(io_info, TRUE, idx_hint, chunk, accessed_bytes) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") - } /* end if */ - relax = TRUE; - - /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); - } /* end while */ -#ifdef H5_HAVE_PARALLEL - } -#endif - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[0].write_timer), &timer); - io_info->stats->stats[0].write_nbytes += nelmts * src_type_size; - io_info->stats->stats[0].write_ncalls++; -#endif - - /* direct xfer accomplished successfully */ - HGOTO_DONE(SUCCEED) - } /* end if */ - - /* - * This is the general case (type conversion, usually). - */ - if(nelmts==0) - HGOTO_DONE(SUCCEED) - - /* Compute buffer sizes and other parameters */ - target_size = dxpl_cache->max_temp_buf; - /* 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_TEMP_BUF_SIZE) { - /* If the buffer is too small to hold even one element, make it bigger */ - if(target_size(nelmts*max_type_size)) - target_size=(size_t)(nelmts*max_type_size); - } /* end if */ - request_nelmts = target_size / max_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_detect_class(dataset->shared->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 if (H5T_path_bkg(tpath)) { - H5T_bkg_t path_bkg; /* Type conversion's background info */ - - /* Retrieve the bkgr buffer property */ - need_bkg=dxpl_cache->bkgr_buf_type; - path_bkg = H5T_path_bkg(tpath); - need_bkg = MAX (path_bkg, need_bkg); - } else { - need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/ - } /* end else */ - if(NULL == (tconv_buf = (uint8_t *)dxpl_cache->tconv_buf)) { - /* Allocate temporary buffer */ - if(NULL == (tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion") - } /* end if */ - if(need_bkg && NULL == (bkg_buf = (uint8_t *)dxpl_cache->bkgr_buf)) { - /* Allocate background buffer */ - /* (Don't need calloc()-like call since file data is already initialized) */ - if(NULL == (bkg_buf = H5FL_BLK_MALLOC(type_conv, (request_nelmts * dst_type_size)))) - 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 skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); - - /* Iterate through chunks to be operated on */ - while(chunk_node) { - H5D_chunk_info_t *chunk_info; /* chunk information */ - - /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); - - /* initialize selection iterator */ - if (H5S_select_iter_init(&file_iter, chunk_info->fspace, 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, chunk_info->mspace, 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, chunk_info->fspace, 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.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; - - /* Load the chunk into cache. But if the whole chunk is written, - * simply allocate space instead of load the chunk. */ - chunk_addr = H5D_istore_get_addr(io_info, &udata); - - if(H5D_istore_if_load(io_info, chunk_addr)) { - accessed_bytes = chunk_info->chunk_points * dst_type_size; - if(accessed_bytes != dataset->shared->layout.u.chunk.size) - relax=FALSE; - if(relax) { - accessed_bytes = H5S_GET_SELECT_NPOINTS(chunk_info->mspace) * src_type_size; - if(accessed_bytes != dataset->shared->layout.u.chunk.size) - relax = FALSE; - } - - if(NULL == (chunk = H5D_istore_lock(io_info, &udata, relax, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") - } else - chunk = NULL; - - for(smine_start=0; smine_startchunk_points; smine_start+=smine_nelmts) { - /* Go figure out how many elements to read from the file */ - assert(H5S_SELECT_ITER_NELMTS(&file_iter)==(chunk_info->chunk_points-smine_start)); - smine_nelmts = (size_t)MIN(request_nelmts, (chunk_info->chunk_points-smine_start)); - - /* - * Gather the data from disk into the datatype conversion - * buffer. Also gather data from application to background buffer - * if necessary. - */ -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - n = H5D_select_mgath(buf, chunk_info->mspace, &mem_iter, - smine_nelmts, dxpl_cache, tconv_buf/*out*/); - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[1].gath_timer), &timer); - io_info->stats->stats[1].gath_nbytes += n * src_type_size; - io_info->stats->stats[1].gath_ncalls++; -#endif - if (n!=smine_nelmts) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file 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. This - * optimization is for Chicago company */ - if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) { - if(H5D_compound_opt_write(smine_nelmts, src_id, dst_id, tconv_buf)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - } else { - if (H5T_BKG_YES==need_bkg) { -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - if(chunk) { - n = H5D_select_mgath(chunk, chunk_info->fspace, &bkg_iter, - smine_nelmts, dxpl_cache, bkg_buf/*out*/); - } else { - n = H5D_select_fgath(io_info, chunk_info->fspace, &bkg_iter, smine_nelmts, - chunk_addr, NULL, bkg_buf/*out*/); - } - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[0].bkg_timer), &timer); - io_info->stats->stats[0].bkg_nbytes += n * dst_type_size; - io_info->stats->stats[0].bkg_ncalls++; -#endif - if (n!=smine_nelmts) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed") - } /* end if */ - - /* - * Perform datatype conversion. - */ - if(H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") - - /* Do the data transform after the type conversion (since we're using dataset->shared->type) */ - if(!H5Z_xform_noop(dxpl_cache->data_xform_prop)) - if( H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, dataset->shared->type) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") - } - - /* - * Scatter the data out to the file. - */ -#ifdef H5S_DEBUG - H5_timer_begin(&timer); -#endif - status = H5D_select_fscat(io_info, - chunk_info->fspace, &file_iter, smine_nelmts, - chunk_addr, chunk, tconv_buf); - -#ifdef H5S_DEBUG - H5_timer_end(&(io_info->stats->stats[0].scat_timer), &timer); - io_info->stats->stats[0].scat_nbytes += n * dst_type_size; - io_info->stats->stats[0].scat_ncalls++; -#endif - if (status<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "scatter failed") - } /* end for */ - - /* Release the cache lock on the chunk. */ - if(chunk) { - accessed_bytes = chunk_info->chunk_points * dst_type_size; - if(H5D_istore_unlock(io_info, TRUE, idx_hint, chunk, accessed_bytes) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") - } /* end if */ - relax = TRUE; - - /* Release selection iterators */ - if(file_iter_init) { - if(H5S_SELECT_ITER_RELEASE(&file_iter) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") - file_iter_init=0; - } /* end if */ - if(mem_iter_init) { - if(H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") - mem_iter_init=0; - } /* end if */ - if(bkg_iter_init) { - if(H5S_SELECT_ITER_RELEASE(&bkg_iter) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") - bkg_iter_init=0; - } /* end if */ - - /* Get the next chunk node in the skip list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); - } /* end while */ - -done: - /* Release selection iterators, if necessary */ - 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 */ - - if (tconv_buf && NULL==dxpl_cache->tconv_buf) - (void)H5FL_BLK_FREE(type_conv,tconv_buf); - if (bkg_buf && NULL==dxpl_cache->bkgr_buf) - (void)H5FL_BLK_FREE(type_conv,bkg_buf); - - /* 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() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_compound_opt_read - * - * Purpose: A shortcut optimization for the Chicago company for - * 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, - hid_t src_id, hid_t dst_id, H5T_subset_t subset, - void *data_buf, void *user_buf/*out*/) -{ - uint8_t *dbuf = (uint8_t *)data_buf; /*cast for pointer arithmetic */ - uint8_t *ubuf = (uint8_t *)user_buf; /*cast for pointer arithmetic */ - uint8_t *xdbuf; - uint8_t *xubuf; - - 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 nseq; /* Number of sequences generated */ - size_t curr_off; /* offset of bytes left to process in sequence */ - size_t curr_seq; /* Current sequence being processed */ - size_t curr_len; /* Length of bytes left to process in sequence */ - size_t curr_nelmts; /* number of elements to process in sequence */ - size_t i; - - H5T_t *src, *dst; - size_t src_stride, dst_stride, type_size = 0; - size_t elmtno; /*element counter */ - - herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_compound_opt_read) - - /* Check args */ - assert (data_buf); - assert (user_buf); - assert (space); - assert (iter); - assert (nelmts>0); - - /* Allocate the vector I/O arrays */ - if(dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if((len = H5FL_SEQ_MALLOC(size_t,dxpl_cache->vec_size))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array"); - if((off = H5FL_SEQ_MALLOC(hsize_t,dxpl_cache->vec_size))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array"); - } /* end if */ - else { - len=_len; - off=_off; - } /* end else */ - - if (NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type"); - - src_stride = H5T_get_size(src); - dst_stride = H5T_get_size(dst); - - if(H5T_SUBSET_SRC == subset) - type_size = src_stride; - else if(H5T_SUBSET_DST == subset) - type_size = dst_stride; - - xdbuf = dbuf; - - /* 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,&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_seqvec_size != H5D_IO_VECTOR_SIZE) { - if(len!=NULL) - H5FL_SEQ_FREE(size_t,len); - if(off!=NULL) - H5FL_SEQ_FREE(hsize_t,off); - } /* end if */ - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_compound_opt_read() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_compound_opt_write - * - * Purpose: A shortcut optimization for the Chicago company for - * 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, hid_t src_id, hid_t dst_id, void *data_buf) -{ - uint8_t *dbuf = (uint8_t *)data_buf; /*cast for pointer arithmetic */ - uint8_t *xsbuf, *xdbuf; - size_t i; - H5T_t *src, *dst; - size_t src_stride, dst_stride; - herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_compound_opt_write) - - /* Check args */ - assert (data_buf); - assert (nelmts>0); - - if (NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type"); - - src_stride = H5T_get_size(src); - dst_stride = H5T_get_size(dst); - - xsbuf = dbuf; - xdbuf = dbuf; - - /* Loop until all elements are written */ - for(i=0; idset; /* Local pointer to dataset info */ - H5S_t *tmp_mspace = NULL; /* Temporary memory dataspace */ - hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ - htri_t file_space_normalized = FALSE; /* File dataspace was normalized */ - hid_t f_tid = (-1); /* Temporary copy of file datatype for iteration */ - hbool_t iter_init = FALSE; /* 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) */ - H5SL_node_t *curr_node; /* Current node in skip list */ - H5S_sel_type fsel_type; /* Selection type on disk */ - char bogus; /* "bogus" buffer to pass to selection iterator */ - unsigned u; /* Local index variable */ - hbool_t sel_hyper_flag; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_create_chunk_map) - - /* Get layout for dataset */ - fm->layout = &(dataset->shared->layout); - fm->nelmts = nelmts; - - /* Check if the memory space is scalar & make equivalent memory space */ - if((sm_ndims = H5S_GET_EXTENT_NDIMS(mem_space)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number") - /* Set the number of dimensions for the memory dataspace */ - H5_ASSIGN_OVERFLOW(fm->m_ndims, sm_ndims, int, unsigned); - - /* Get dim number and dimensionality for each dataspace */ - fm->f_ndims = f_ndims = dataset->shared->layout.u.chunk.ndims - 1; - if(H5S_get_simple_extent_dims(file_space, fm->f_dims, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality") - - /* Normalize hyperslab selections by adjusting them by the offset */ - /* (It might be worthwhile to normalize both the file and memory dataspaces - * before any (contiguous, chunked, etc) file I/O operation, in order to - * speed up hyperslab calculations by removing the extra checks and/or - * additions involving the offset and the hyperslab selection -QAK) - */ - if((file_space_normalized = H5S_hyper_normalize_offset((H5S_t *)file_space, old_offset)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") - - /* Decide the number of chunks in each dimension*/ - for(u=0; uchunk_dim[u]=fm->layout->u.chunk.dim[u]; - - /* Round up to the next integer # of chunks, to accomodate partial chunks */ - fm->chunks[u] = ((fm->f_dims[u]+dataset->shared->layout.u.chunk.dim[u])-1) / dataset->shared->layout.u.chunk.dim[u]; - } /* 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") + FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_term) -#ifdef H5_HAVE_PARALLEL - /* Calculate total chunk in file map*/ - fm->select_chunk = NULL; - fm->total_chunks = 1; - for(u = 0; u < fm->f_ndims; u++) - fm->total_chunks = fm->total_chunks * fm->chunks[u]; + /* Check if we used the MPI VFD for the I/O */ if(io_info->using_mpi_vfd) { - H5_CHECK_OVERFLOW(fm->total_chunks, hsize_t, size_t); - if(NULL == (fm->select_chunk = (hbool_t *)H5MM_calloc((size_t)fm->total_chunks * sizeof(hbool_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") - } /* end if */ -#endif /* H5_HAVE_PARALLEL */ - + /* Check if we need to revert the change to the xfer mode */ + if(io_info->orig.xfer_mode != io_info->dxpl_cache->xfer_mode) { + H5P_genplist_t *dx_plist; /* Data transer property list */ - /* Initialize "last chunk" information */ - fm->last_index = (hsize_t)-1; - fm->last_chunk_info = NULL; + /* Get the dataset transfer property list */ + if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(io_info->dxpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") - /* Point at the dataspaces */ - fm->file_space = file_space; - fm->mem_space = mem_space; - - /* Special case for only one element in selection */ - /* (usually appending a record) */ - if(nelmts == 1 -#ifdef H5_HAVE_PARALLEL - && !(io_info->using_mpi_vfd) -#endif /* H5_HAVE_PARALLEL */ - ) { - /* Initialize skip list for chunk selections */ - fm->sel_chunks = NULL; - fm->use_single = TRUE; - - /* Initialize single chunk dataspace */ - if(NULL == dataset->shared->cache.chunk.single_space) { - /* Make a copy of the dataspace for the dataset */ - if((dataset->shared->cache.chunk.single_space = H5S_copy(file_space, TRUE, FALSE)) == NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space") - - /* Resize chunk's dataspace dimensions to size of chunk */ - if(H5S_set_extent_real(dataset->shared->cache.chunk.single_space, fm->chunk_dim) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust chunk dimensions") - - /* Set the single chunk dataspace to 'all' selection */ - if(H5S_select_all(dataset->shared->cache.chunk.single_space, TRUE) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to set all selection") + /* Restore the original parallel I/O mode */ + if(H5P_set(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->orig.xfer_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") } /* end if */ - fm->single_space = dataset->shared->cache.chunk.single_space; - HDassert(fm->single_space); - /* Allocate the single chunk information */ - if(NULL == dataset->shared->cache.chunk.single_chunk_info) { - if(NULL == (dataset->shared->cache.chunk.single_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") - } /* end if */ - fm->single_chunk_info = dataset->shared->cache.chunk.single_chunk_info; - HDassert(fm->single_chunk_info); + /* Check if we need to revert the change to the collective opt mode */ + if(io_info->orig.coll_opt_mode != io_info->dxpl_cache->coll_opt_mode) { + H5P_genplist_t *dx_plist; /* Data transer property list */ - /* Reset chunk template information */ - fm->mchunk_tmpl = NULL; + /* Get the dataset transfer property list */ + if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(io_info->dxpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") - /* Set up chunk mapping for single element */ - if(H5D_create_chunk_map_single(fm, io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create chunk selections for single element") - } /* end if */ - else { - /* Initialize skip list for chunk selections */ - if(NULL == dataset->shared->cache.chunk.sel_chunks) { - if(NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE, 0.5, (size_t)H5D_DEFAULT_SKIPLIST_HEIGHT))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for chunk selections") + /* Restore the original parallel I/O mode */ + if(H5P_set(dx_plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &io_info->orig.coll_opt_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set collective option mode") } /* end if */ - fm->sel_chunks = dataset->shared->cache.chunk.sel_chunks; - HDassert(fm->sel_chunks); - - /* We are not using single element mode */ - fm->use_single = FALSE; - - /* Get type of selection on disk & in memory */ - if((fsel_type = H5S_GET_SELECT_TYPE(file_space)) < H5S_SEL_NONE) - HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") - if((fm->msel_type = H5S_GET_SELECT_TYPE(mem_space)) < H5S_SEL_NONE) - HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") - - /* If the selection is NONE or POINTS, set the flag to FALSE */ - if(fsel_type == H5S_SEL_POINTS || fsel_type == H5S_SEL_NONE) - sel_hyper_flag = FALSE; - else - sel_hyper_flag = TRUE; - - /* Check if file selection is a not a hyperslab selection */ - if(sel_hyper_flag) { - /* Build the file selection for each chunk */ - if(H5D_create_chunk_file_map_hyper(fm, io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") - - /* Clean file chunks' hyperslab span "scratch" information */ - curr_node=H5SL_first(fm->sel_chunks); - while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ - - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - assert(chunk_info); - - /* Clean hyperslab span's "scratch" information */ - if(H5S_hyper_reset_scratch(chunk_info->fspace) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") - - /* Get the next chunk node in the skip list */ - curr_node=H5SL_next(curr_node); - } /* end while */ - } /* end if */ - else { - /* Create temporary datatypes for selection iteration */ - if((f_tid = H5I_register(H5I_DATATYPE, H5T_copy(dataset->shared->type, H5T_COPY_ALL))) < 0) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register file datatype") - - /* Spaces might not be the same shape, iterate over the file selection directly */ - if(H5S_select_iterate(&bogus, f_tid, file_space, H5D_chunk_file_cb, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") - - /* Reset "last chunk" info */ - fm->last_index=(hsize_t)-1; - fm->last_chunk_info=NULL; - } /* end else */ - - /* Build the memory selection for each chunk */ - if(sel_hyper_flag && H5S_select_shape_same(file_space, mem_space) == TRUE) { - /* Reset chunk template information */ - fm->mchunk_tmpl = NULL; - - /* If the selections are the same shape, use the file chunk information - * to generate the memory chunk information quickly. - */ - if(H5D_create_chunk_mem_map_hyper(fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") - } /* end if */ - else { - size_t elmt_size; /* Memory datatype size */ - - /* Make a copy of equivalent memory space */ - if((tmp_mspace = H5S_copy(mem_space, TRUE, FALSE)) == NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") - - /* De-select the mem space copy */ - if(H5S_select_none(tmp_mspace) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select memory space") - - /* Save chunk template information */ - fm->mchunk_tmpl=tmp_mspace; - - /* Create temporary datatypes for selection iteration */ - if(f_tid<0) { - if((f_tid = H5I_register(H5I_DATATYPE, H5T_copy(dataset->shared->type, H5T_COPY_ALL))) < 0) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register file datatype") - } /* end if */ - - /* 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 = TRUE; /* Selection iteration info has been initialized */ - - /* Spaces aren't the same shape, iterate over the memory selection directly */ - if(H5S_select_iterate(&bogus, f_tid, file_space, H5D_chunk_mem_cb, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") - - /* Clean up hyperslab stuff, if necessary */ - if(fm->msel_type != H5S_SEL_POINTS) { - /* Clean memory chunks' hyperslab span "scratch" information */ - curr_node=H5SL_first(fm->sel_chunks); - while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ - - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - assert(chunk_info); - - /* Clean hyperslab span's "scratch" information */ - if(H5S_hyper_reset_scratch(chunk_info->mspace) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") - - /* Get the next chunk node in the skip list */ - curr_node=H5SL_next(curr_node); - } /* end while */ - } /* end if */ - } /* end else */ - } /* end else */ - -done: - /* Release the [potentially partially built] chunk mapping information if an error occurs */ - if(ret_value<0) { - if(tmp_mspace && !fm->mchunk_tmpl) { - if(H5S_close(tmp_mspace) < 0) - HDONE_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 */ - /* Reset the global dataspace info */ - fm->file_space = NULL; - fm->mem_space = NULL; - - if(iter_init) { - if(H5S_SELECT_ITER_RELEASE(&(fm->mem_iter)) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") - } /* end if */ - if(f_tid!=(-1)) { - if(H5I_dec_ref(f_tid) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID") - } /* end if */ - if(file_space_normalized) { - if(H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") - } /* end if */ - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_create_chunk_map() */ - - -/*-------------------------------------------------------------------------- - NAME - H5D_free_chunk_info - PURPOSE - Internal routine to destroy a chunk info node - USAGE - void H5D_free_chunk_info(chunk_info) - void *chunk_info; IN: Pointer to chunk info to destroy - RETURNS - No return value - DESCRIPTION - Releases all the memory for a chunk info node. Called by H5SL_free - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5D_free_chunk_info(void *item, void UNUSED *key, void UNUSED *opdata) -{ - H5D_chunk_info_t *chunk_info = (H5D_chunk_info_t *)item; - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_free_chunk_info) - - HDassert(chunk_info); - - /* Close the chunk's file dataspace, if it's not shared */ - if(!chunk_info->fspace_shared) - (void)H5S_close(chunk_info->fspace); - else - H5S_select_all(chunk_info->fspace, TRUE); - - /* Close the chunk's memory dataspace, if it's not shared */ - if(!chunk_info->mspace_shared) - (void)H5S_close(chunk_info->mspace); - - /* Free the actual chunk info */ - H5FL_FREE(H5D_chunk_info_t, chunk_info); - - FUNC_LEAVE_NOAPI(0); -} /* H5D_free_chunk_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 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_destroy_chunk_map(const H5D_chunk_map_t *fm) -{ - herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_destroy_chunk_map) - - /* Single element I/O vs. multiple element I/O cleanup */ - if(fm->use_single) { - /* Sanity checks */ - HDassert(fm->sel_chunks == NULL); - HDassert(fm->single_chunk_info); - HDassert(fm->single_chunk_info->fspace_shared); - HDassert(fm->single_chunk_info->mspace_shared); - - /* Reset the selection for the single element I/O */ - H5S_select_all(fm->single_space, TRUE); - } /* end if */ - else { - /* Release the nodes on the list of selected chunks */ - if(fm->sel_chunks) - if(H5SL_free(fm->sel_chunks, H5D_free_chunk_info, NULL) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTNEXT, FAIL, "can't iterate over chunks") - } /* end else */ - - /* 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") -#ifdef H5_HAVE_PARALLEL - if(fm->select_chunk) - H5MM_xfree(fm->select_chunk); -#endif /* H5_HAVE_PARALLEL */ - done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_destroy_chunk_map() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_create_chunk_map_single - * - * Purpose: Create chunk selections when appending a single record - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Tuesday, November 20, 2007 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t -#ifndef H5_HAVE_PARALLEL - UNUSED -#endif /* H5_HAVE_PARALLEL */ - *io_info) -{ - H5D_chunk_info_t *chunk_info; /* Chunk information to insert into skip list */ - hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ - hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_create_chunk_map_single) - - /* Sanity check */ - HDassert(fm->f_ndims > 0); - - /* Get coordinate for selection */ - if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") - - /* Initialize the 'single chunk' file & memory chunk information */ - chunk_info = fm->single_chunk_info; - chunk_info->chunk_points = 1; - - /* Set chunk location & hyperslab size */ - for(u = 0; u < fm->f_ndims; u++) { - HDassert(sel_start[u] == sel_end[u]); - chunk_info->coords[u] = (sel_start[u] / fm->layout->u.chunk.dim[u]) * fm->layout->u.chunk.dim[u]; - } /* end for */ - chunk_info->coords[fm->f_ndims] = 0; - - /* Calculate the index of this chunk */ - if(H5V_chunk_index(fm->f_ndims, chunk_info->coords, fm->layout->u.chunk.dim, fm->down_chunks, &chunk_info->index) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") - - /* Copy selection for file's dataspace into chunk dataspace */ - if(H5S_select_copy(fm->single_space, fm->file_space, FALSE) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file selection") - - /* Move selection back to have correct offset in chunk */ - if(H5S_SELECT_ADJUST_U(fm->single_space, chunk_info->coords) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") +} /* end H5D_ioinfo_term() */ -#ifdef H5_HAVE_PARALLEL - /* store chunk selection information */ - if(io_info->using_mpi_vfd) - fm->select_chunk[chunk_info->index] = TRUE; #endif /* H5_HAVE_PARALLEL */ - /* Set the file dataspace for the chunk to the shared 'single' dataspace */ - chunk_info->fspace = fm->single_space; - - /* Indicate that the chunk's file dataspace is shared */ - chunk_info->fspace_shared = TRUE; - - /* Just point at the memory dataspace & selection */ - /* (Casting away const OK -QAK) */ - chunk_info->mspace = (H5S_t *)fm->mem_space; - - /* Indicate that the chunk's memory dataspace is shared */ - chunk_info->mspace_shared = TRUE; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_create_chunk_map_single() */ - /*------------------------------------------------------------------------- - * Function: H5D_create_chunk_file_map_hyper + * Function: H5D_typeinfo_term * - * Purpose: Create all chunk selections in file. + * Purpose: Common logic for terminating a type info object * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * Thursday, May 29, 2003 + * Thursday, March 6, 2008 * *------------------------------------------------------------------------- */ static herr_t -H5D_create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t -#ifndef H5_HAVE_PARALLEL - UNUSED -#endif /* H5_HAVE_PARALLEL */ - *io_info) +H5D_typeinfo_term(const H5D_type_info_t *type_info) { - hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ - hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ - hsize_t sel_points; /* Number of elements in file selection */ - hsize_t start_coords[H5O_LAYOUT_NDIMS]; /* Starting coordinates of selection */ - hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */ - hsize_t end[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */ - hsize_t chunk_index; /* Index of chunk */ - int curr_dim; /* Current dimension to increment */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_create_chunk_file_map_hyper) - - /* Sanity check */ - assert(fm->f_ndims>0); - - /* Get number of elements selected in file */ - sel_points = fm->nelmts; - - /* Get bounding box for selection (to reduce the number of chunks to iterate over) */ - if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") - - /* Set initial chunk location & hyperslab size */ - - for(u=0; uf_ndims; u++) { - start_coords[u]=(sel_start[u]/fm->layout->u.chunk.dim[u])*fm->layout->u.chunk.dim[u]; - coords[u]=start_coords[u]; - end[u]=(coords[u]+fm->chunk_dim[u])-1; - } /* end for */ - - - /* Calculate the index of this chunk */ - if(H5V_chunk_index(fm->f_ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") - - /* Iterate through each chunk in the dataset */ - while(sel_points) { - /* Check for intersection of temporary chunk and file selection */ - /* (Casting away const OK - QAK) */ - if(H5S_hyper_intersect_block((H5S_t *)fm->file_space,coords,end)==TRUE) { - H5S_t *tmp_fchunk; /* Temporary file dataspace */ - H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */ - hssize_t schunk_points; /* Number of elements in chunk selection */ - - /* Create "temporary" chunk for selection operations (copy file space) */ - if((tmp_fchunk = H5S_copy(fm->file_space, TRUE, FALSE)) == NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") - - /* Make certain selections are stored in span tree form (not "optimized hyperslab" or "all") */ - if(H5S_hyper_convert(tmp_fchunk) < 0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to convert selection to span trees") - } /* end if */ - - /* "AND" temporary chunk and current chunk */ - if(H5S_select_hyperslab(tmp_fchunk,H5S_SELECT_AND,coords,NULL,fm->chunk_dim,NULL) < 0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create chunk selection") - } /* end if */ - - /* Resize chunk's dataspace dimensions to size of chunk */ - if(H5S_set_extent_real(tmp_fchunk,fm->chunk_dim) < 0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk dimensions") - } /* end if */ - - /* Move selection back to have correct offset in chunk */ - if(H5S_SELECT_ADJUST_U(tmp_fchunk, coords) < 0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") - } /* end if */ - - /* Add temporary chunk to the list of chunks */ - - /* Allocate the file & memory chunk information */ - if (NULL==(new_chunk_info = H5FL_MALLOC (H5D_chunk_info_t))) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") - } /* end if */ - - /* Initialize the chunk information */ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_typeinfo_term) - /* Set the chunk index */ - new_chunk_info->index=chunk_index; - -#ifdef H5_HAVE_PARALLEL - /* store chunk selection information */ - if(io_info->using_mpi_vfd) - fm->select_chunk[chunk_index] = TRUE; -#endif /* H5_HAVE_PARALLEL */ - - /* Set the file chunk dataspace */ - new_chunk_info->fspace = tmp_fchunk; - new_chunk_info->fspace_shared = FALSE; - - /* Set the memory chunk dataspace */ - new_chunk_info->mspace=NULL; - new_chunk_info->mspace_shared = FALSE; - - /* Copy the chunk's coordinates */ - for(u=0; uf_ndims; u++) - new_chunk_info->coords[u]=coords[u]; - new_chunk_info->coords[fm->f_ndims]=0; - - /* Insert the new chunk into the skip list */ - if(H5SL_insert(fm->sel_chunks,new_chunk_info,&new_chunk_info->index) < 0) { - H5D_free_chunk_info(new_chunk_info,NULL,NULL); - HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert chunk into skip list") - } /* end if */ - - /* Get number of elements selected in chunk */ - if((schunk_points=H5S_GET_SELECT_NPOINTS(tmp_fchunk)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection # of elements") - H5_ASSIGN_OVERFLOW(new_chunk_info->chunk_points,schunk_points,hssize_t,size_t); - - /* Decrement # of points left in file selection */ - sel_points-=(hsize_t)schunk_points; - - /* Leave if we are done */ - if(sel_points==0) - HGOTO_DONE(SUCCEED) - assert(sel_points>0); - } /* end if */ - - /* Increment chunk index */ - chunk_index++; - - /* Set current increment dimension */ - curr_dim=(int)fm->f_ndims-1; - - /* Increment chunk location in fastest changing dimension */ - H5_CHECK_OVERFLOW(fm->chunk_dim[curr_dim],hsize_t,hssize_t); - coords[curr_dim]+=fm->chunk_dim[curr_dim]; - end[curr_dim]+=fm->chunk_dim[curr_dim]; - - /* Bring chunk location back into bounds, if necessary */ - if(coords[curr_dim]>sel_end[curr_dim]) { - do { - /* Reset current dimension's location to 0 */ - coords[curr_dim]=start_coords[curr_dim]; /*lint !e771 The start_coords will always be initialized */ - end[curr_dim]=(coords[curr_dim]+(hssize_t)fm->chunk_dim[curr_dim])-1; - - /* Decrement current dimension */ - curr_dim--; - - /* Increment chunk location in current dimension */ - coords[curr_dim]+=fm->chunk_dim[curr_dim]; - end[curr_dim]=(coords[curr_dim]+fm->chunk_dim[curr_dim])-1; - } while(coords[curr_dim]>sel_end[curr_dim]); - - /* Re-Calculate the index of this chunk */ - if(H5V_chunk_index(fm->f_ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") - } /* end if */ - } /* end while */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_create_chunk_file_map_hyper() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_create_chunk_mem_map_hyper - * - * Purpose: Create all chunk selections in memory by copying the file - * chunk selections and adjusting their offsets to be correct - * for the memory. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Thursday, May 29, 2003 - * - * Assumptions: That the file and memory selections are the same shape. - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) -{ - H5SL_node_t *curr_node; /* Current node in skip list */ - hsize_t file_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ - hsize_t file_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ - hsize_t mem_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ - hsize_t mem_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ - hssize_t adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to all file chunks */ - hssize_t chunk_adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to a particular chunk */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_create_chunk_mem_map_hyper) - - /* Sanity check */ - assert(fm->f_ndims>0); - - /* Check for all I/O going to a single chunk */ - if(H5SL_count(fm->sel_chunks)==1) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ - - /* Get the node */ - curr_node=H5SL_first(fm->sel_chunks); - - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - assert(chunk_info); - - /* Just point at the memory dataspace & selection */ - /* (Casting away const OK -QAK) */ - chunk_info->mspace=(H5S_t *)fm->mem_space; - - /* Indicate that the chunk's memory space is shared */ - chunk_info->mspace_shared = TRUE; + /* Check for releasing datatype conversion & background buffers */ + if(type_info->tconv_buf_allocated) { + HDassert(type_info->tconv_buf); + (void)H5FL_BLK_FREE(type_conv, type_info->tconv_buf); } /* end if */ - else { - /* Get bounding box for file selection */ - if(H5S_SELECT_BOUNDS(fm->file_space, file_sel_start, file_sel_end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") - - /* Get bounding box for memory selection */ - if(H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") - - /* Calculate the adjustment for memory selection from file selection */ - assert(fm->m_ndims==fm->f_ndims); - for(u=0; uf_ndims; u++) { - H5_CHECK_OVERFLOW(file_sel_start[u],hsize_t,hssize_t); - H5_CHECK_OVERFLOW(mem_sel_start[u],hsize_t,hssize_t); - adjust[u]=(hssize_t)file_sel_start[u]-(hssize_t)mem_sel_start[u]; - } /* end for */ - - /* Iterate over each chunk in the chunk list */ - curr_node=H5SL_first(fm->sel_chunks); - while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ - - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - assert(chunk_info); - - /* Copy the information */ - - /* Copy the memory dataspace */ - if((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") - - /* Release the current selection */ - if(H5S_SELECT_RELEASE(chunk_info->mspace) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection") - - /* Copy the file chunk's selection */ - if(H5S_select_copy(chunk_info->mspace,chunk_info->fspace,FALSE) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection") - - /* Compensate for the chunk offset */ - for(u=0; uf_ndims; u++) { - H5_CHECK_OVERFLOW(chunk_info->coords[u],hsize_t,hssize_t); - chunk_adjust[u]=adjust[u]-(hssize_t)chunk_info->coords[u]; /*lint !e771 The adjust array will always be initialized */ - } /* end for */ - - /* Adjust the selection */ - if(H5S_hyper_adjust_s(chunk_info->mspace,chunk_adjust) < 0) /*lint !e772 The chunk_adjust array will always be initialized */ - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") - - /* Get the next chunk node in the skip list */ - curr_node=H5SL_next(curr_node); - } /* end while */ - } /* end else */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_create_chunk_mem_map_hyper() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_chunk_file_cb - * - * Purpose: Callback routine for file selection iterator. Used when - * creating selections in file for each point selected. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Wednesday, July 23, 2003 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_chunk_file_cb(void UNUSED *elem, hid_t UNUSED type_id, unsigned ndims, const hsize_t *coords, void *_fm) -{ - H5D_chunk_map_t *fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */ - H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */ - hsize_t coords_in_chunk[H5O_LAYOUT_NDIMS]; /* Coordinates of element in chunk */ - hsize_t chunk_index; /* Chunk index */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_file_cb) - - /* Calculate the index of this chunk */ - if(H5V_chunk_index(ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") - - /* Find correct chunk in file & memory skip list */ - if(chunk_index==fm->last_index) { - /* If the chunk index is the same as the last chunk index we used, - * get the cached info to operate on. - */ - chunk_info=fm->last_chunk_info; + if(type_info->bkg_buf_allocated) { + HDassert(type_info->bkg_buf); + (void)H5FL_BLK_FREE(type_conv, type_info->bkg_buf); } /* end if */ - else { - /* If the chunk index is not the same as the last chunk index we used, - * find the chunk in the skip list. - */ - /* Get the chunk node from the skip list */ - if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) { - H5S_t *fspace; /* Memory chunk's dataspace */ - - /* Allocate the file & memory chunk information */ - if (NULL==(chunk_info = H5FL_MALLOC (H5D_chunk_info_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") - - /* Initialize the chunk information */ - - /* Set the chunk index */ - chunk_info->index=chunk_index; - - /* Create a dataspace for the chunk */ - if((fspace = H5S_create_simple(fm->f_ndims,fm->chunk_dim,NULL))==NULL) { - H5FL_FREE(H5D_chunk_info_t,chunk_info); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create dataspace for chunk") - } /* end if */ - - /* De-select the chunk space */ - if(H5S_select_none(fspace) < 0) { - (void)H5S_close(fspace); - H5FL_FREE(H5D_chunk_info_t,chunk_info); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select dataspace") - } /* end if */ - - /* Set the file chunk dataspace */ - chunk_info->fspace = fspace; - chunk_info->fspace_shared = FALSE; - - /* Set the memory chunk dataspace */ - chunk_info->mspace=NULL; - chunk_info->mspace_shared = FALSE; - - /* Set the number of selected elements in chunk to zero */ - chunk_info->chunk_points=0; - - /* Compute the chunk's coordinates */ - for(u=0; uf_ndims; u++) { - H5_CHECK_OVERFLOW(fm->layout->u.chunk.dim[u],hsize_t,hssize_t); - chunk_info->coords[u]=(coords[u]/(hssize_t)fm->layout->u.chunk.dim[u])*(hssize_t)fm->layout->u.chunk.dim[u]; - } /* end for */ - chunk_info->coords[fm->f_ndims]=0; - - /* Insert the new chunk into the skip list */ - if(H5SL_insert(fm->sel_chunks,chunk_info,&chunk_info->index) < 0) { - H5D_free_chunk_info(chunk_info,NULL,NULL); - HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert chunk into skip list") - } /* end if */ - } /* end if */ - - /* Update the "last chunk seen" information */ - fm->last_index=chunk_index; - fm->last_chunk_info=chunk_info; - } /* end else */ - - /* Get the coordinates of the element in the chunk */ - for(u=0; uf_ndims; u++) - coords_in_chunk[u]=coords[u]%fm->layout->u.chunk.dim[u]; - - /* Add point to file selection for chunk */ - if(H5S_select_elements(chunk_info->fspace, H5S_SELECT_APPEND, (size_t)1, coords_in_chunk) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") - - /* Increment the number of elemented selected in chunk */ - chunk_info->chunk_points++; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_chunk_file_cb() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_chunk_mem_cb - * - * Purpose: Callback routine for file selection iterator. Used when - * creating selections in memory for each chunk. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Raymond Lu - * Thursday, April 10, 2003 - * - *------------------------------------------------------------------------- - */ -/* ARGSUSED */ -static herr_t -H5D_chunk_mem_cb(void UNUSED *elem, hid_t UNUSED type_id, unsigned ndims, const hsize_t *coords, void *_fm) -{ - H5D_chunk_map_t *fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */ - H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */ - hsize_t coords_in_mem[H5O_LAYOUT_NDIMS]; /* Coordinates of element in memory */ - hsize_t chunk_index; /* Chunk index */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_mem_cb) - - /* Calculate the index of this chunk */ - if(H5V_chunk_index(ndims,coords,fm->layout->u.chunk.dim,fm->down_chunks,&chunk_index) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") - - /* Find correct chunk in file & memory skip list */ - 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. - */ - chunk_info=fm->last_chunk_info; - } /* end if */ - else { - /* If the chunk index is not the same as the last chunk index we used, - * find the chunk in the skip list. - */ - /* Get the chunk node from the skip list */ - if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) - HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, FAIL, "can't locate chunk in skip list") - - /* Check if the chunk already has a memory space */ - if(chunk_info->mspace==NULL) { - /* Copy the template memory chunk dataspace */ - if((chunk_info->mspace = H5S_copy(fm->mchunk_tmpl, FALSE, FALSE)) == NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space") - } /* end else */ - - /* Update the "last chunk seen" information */ - fm->last_index=chunk_index; - fm->last_chunk_info=chunk_info; - } /* end else */ - - /* 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") - - /* Add point to memory selection for chunk */ - if(fm->msel_type==H5S_SEL_POINTS) { - if(H5S_select_elements(chunk_info->mspace, H5S_SELECT_APPEND, (size_t)1, coords_in_mem) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") - } /* end if */ - else { - if(H5S_hyper_add_span_element(chunk_info->mspace, fm->m_ndims, coords_in_mem) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") - } /* end else */ - - /* Move memory selection iterator to next element in selection */ - if(H5S_SELECT_ITER_NEXT(&fm->mem_iter, (size_t)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_mem_cb() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_ioinfo_init - * - * Purpose: Routine for determining correct I/O operations for - * each I/O action. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Thursday, September 30, 2004 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_ioinfo_init(H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, - const H5S_t -#if !(defined H5_HAVE_PARALLEL || defined H5S_DEBUG) - UNUSED -#endif /* H5_HAVE_PARALLEL */ - *mem_space, const H5S_t -#if !(defined H5_HAVE_PARALLEL || defined H5S_DEBUG) - UNUSED -#endif /* H5_HAVE_PARALLEL */ - *file_space, H5T_path_t -#ifndef H5_HAVE_PARALLEL - UNUSED -#endif /* H5_HAVE_PARALLEL */ - *tpath, - H5D_io_info_t *io_info) -{ - herr_t ret_value = SUCCEED; /* Return value */ - -#if defined H5_HAVE_PARALLEL || defined H5S_DEBUG - FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_init) -#else /* defined H5_HAVE_PARALLEL || defined H5S_DEBUG */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_ioinfo_init) -#endif /* defined H5_HAVE_PARALLEL || defined H5S_DEBUG */ - - /* check args */ - HDassert(dset); - HDassert(dset->oloc.file); - HDassert(mem_space); - HDassert(file_space); - HDassert(tpath); - HDassert(io_info); - - /* Set up "normal" I/O fields */ - io_info->dset=dset; - io_info->dxpl_cache=dxpl_cache; - io_info->dxpl_id=dxpl_id; - io_info->store=NULL; /* Set later in I/O routine? */ - - /* Set I/O operations to initial values */ - io_info->ops=dset->shared->io_ops; - -#ifdef H5_HAVE_PARALLEL - /* Start in the "not modified" xfer_mode state */ - io_info->xfer_mode_changed = FALSE; - io_info->using_mpi_vfd = IS_H5FD_MPI(dset->oloc.file); - - if(io_info->using_mpi_vfd) { - htri_t opt; /* Flag whether a selection is optimizable */ - - /* Get MPI communicator */ - if((io_info->comm = H5F_mpi_get_comm(dset->oloc.file)) == MPI_COMM_NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator") - - /* - * Check if we can set direct MPI-IO read/write functions - */ - opt=H5D_mpio_opt_possible(io_info, mem_space, file_space, tpath); - if(opt==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace "); - - /* Check if we can use the optimized parallel I/O routines */ - if(opt==TRUE) { - /* Set the pointers to the MPI-specific routines */ - io_info->ops.read = H5D_mpio_select_read; - io_info->ops.write = H5D_mpio_select_write; - } /* end if */ - else { - /* Set the pointers to the non-MPI-specific routines */ - io_info->ops.read = H5D_select_read; - io_info->ops.write = H5D_select_write; - - /* If we won't be doing collective I/O, but the user asked for - * collective I/O, change the request to use independent I/O, but - * mark it so that we remember to revert the change. - */ - if(io_info->dxpl_cache->xfer_mode==H5FD_MPIO_COLLECTIVE) { - H5P_genplist_t *dx_plist; /* Data transer property list */ - - /* Get the dataset transfer property list */ - if (NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list") - - /* Change the xfer_mode to independent for handling the I/O */ - io_info->dxpl_cache->xfer_mode = H5FD_MPIO_INDEPENDENT; - if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") - - /* Indicate that the transfer mode should be restored before returning - * to user. - */ - io_info->xfer_mode_changed = TRUE; - } /* end if */ - } /* end else */ - } /* end if */ - else { - /* Set the pointers to the non-MPI-specific routines */ - io_info->ops.read = H5D_select_read; - io_info->ops.write = H5D_select_write; - } /* end else */ -#else /* H5_HAVE_PARALLEL */ - io_info->ops.read = H5D_select_read; - io_info->ops.write = H5D_select_write; -#endif /* H5_HAVE_PARALLEL */ - -#ifdef H5S_DEBUG - /* Get the information for the I/O statistics */ - if((io_info->stats=H5S_find(mem_space,file_space))==NULL) - HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "can't set up selection statistics"); -#endif /* H5S_DEBUG */ - -#if defined H5_HAVE_PARALLEL || defined H5S_DEBUG -done: -#endif /* H5_HAVE_PARALLEL || H5S_DEBUG */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_ioinfo_init() */ - -#ifdef H5_HAVE_PARALLEL - -/*------------------------------------------------------------------------- - * Function: H5D_ioinfo_term - * - * Purpose: Common logic for terminating an I/O info object - * (Only used for restoring MPI transfer mode currently) - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Friday, February 6, 2004 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_ioinfo_term(H5D_io_info_t *io_info) -{ - herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_term) - - /* Check if we need to revert the change to the xfer mode */ - if (io_info->xfer_mode_changed) { - H5P_genplist_t *dx_plist; /* Data transer property list */ - - /* Get the dataset transfer property list */ - if (NULL == (dx_plist = (H5P_genplist_t *)H5I_object(io_info->dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") - - /* Restore the original parallel I/O mode */ - io_info->dxpl_cache->xfer_mode = H5FD_MPIO_COLLECTIVE; - if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") - } /* end if */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_ioinfo_term() */ -#endif + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D_typeinfo_term() */ diff --git a/src/H5Distore.c b/src/H5Distore.c index 47e4cab..efab271 100644 --- a/src/H5Distore.c +++ b/src/H5Distore.c @@ -104,30 +104,12 @@ */ #define H5D_ISTORE_NDIMS(X) (((X)->sizeof_rkey-8)/8) -#define H5D_HASH(D,ADDR) H5F_addr_hash(ADDR,(D)->cache.chunk.nslots) - #define H5D_ISTORE_DEFAULT_SKIPLIST_HEIGHT 8 /******************/ /* Local Typedefs */ /******************/ -/* Raw data chunks are cached. Each entry in the cache is: */ -typedef struct H5D_rdcc_ent_t { - hbool_t locked; /*entry is locked in cache */ - hbool_t dirty; /*needs to be written to disk? */ - hsize_t offset[H5O_LAYOUT_NDIMS]; /*chunk name */ - size_t rd_count; /*bytes remaining to be read */ - size_t wr_count; /*bytes remaining to be written */ - size_t chunk_size; /*size of a chunk */ - size_t alloc_size; /*amount allocated for the chunk */ - uint8_t *chunk; /*the unfiltered chunk data */ - unsigned idx; /*index in hash table */ - struct H5D_rdcc_ent_t *next;/*next item in doubly-linked list */ - struct H5D_rdcc_ent_t *prev;/*previous item in doubly-linked list */ -} H5D_rdcc_ent_t; -typedef H5D_rdcc_ent_t *H5D_rdcc_ent_ptr_t; /* For free lists */ - /* * Data exchange structure for indexed storage nodes. This structure is * passed through the B-link tree layer to the methods for the objects @@ -192,7 +174,7 @@ typedef struct H5D_istore_it_ud4_t { /* B-tree callback info for iteration to obtain chunk address and the index of the chunk for all chunks in the B-tree. */ typedef struct H5D_istore_it_ud5_t { H5D_istore_bt_ud_common_t common; /* Common info for B-tree user data (must be first) */ - hsize_t *down_chunks; + const hsize_t *down_chunks; haddr_t *chunk_addr; } H5D_istore_it_ud5_t; @@ -1490,7 +1472,7 @@ H5D_istore_flush(H5D_t *dset, hid_t dxpl_id, unsigned flags) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") /* Construct dataset I/O info */ - H5D_BUILD_IO_INFO(&io_info, dset, dxpl_cache, dxpl_id, NULL); + H5D_BUILD_IO_INFO_WRT(&io_info, dset, dxpl_cache, dxpl_id, NULL, NULL); /* Loop over all entries in the chunk cache */ for(ent = rdcc->head; ent; ent = next) { @@ -1525,48 +1507,48 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D_istore_dest (H5D_t *dset, hid_t dxpl_id) +H5D_istore_dest(H5D_t *dset, hid_t dxpl_id) { H5D_io_info_t io_info; /* Temporary I/O info object */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ - H5D_dxpl_cache_t *dxpl_cache=&_dxpl_cache; /* Data transfer property cache */ - H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); - int nerrors=0; - H5D_rdcc_ent_t *ent=NULL, *next=NULL; - herr_t ret_value=SUCCEED; /* Return value */ + H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ + H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); + int nerrors = 0; + H5D_rdcc_ent_t *ent = NULL, *next = NULL; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5D_istore_dest, FAIL) - assert(dset); + HDassert(dset); /* Fill the DXPL cache values for later use */ - if (H5D_get_dxpl_cache(dxpl_id,&dxpl_cache)<0) + if(H5D_get_dxpl_cache(dxpl_id, &dxpl_cache) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") /* Construct dataset I/O info */ - H5D_BUILD_IO_INFO(&io_info,dset,dxpl_cache,dxpl_id,NULL); + H5D_BUILD_IO_INFO_WRT(&io_info, dset, dxpl_cache, dxpl_id, NULL, NULL); /* Flush all the cached chunks */ - for (ent=rdcc->head; ent; ent=next) { + for(ent = rdcc->head; ent; ent = next) { #ifdef H5D_ISTORE_DEBUG HDfputc('c', stderr); HDfflush(stderr); #endif next = ent->next; - if (H5D_istore_preempt(&io_info, ent, TRUE )<0) + if(H5D_istore_preempt(&io_info, ent, TRUE) < 0) nerrors++; - } - if (nerrors) + } /* end for */ + if(nerrors) HGOTO_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks") if(rdcc->slot) - H5FL_SEQ_FREE (H5D_rdcc_ent_ptr_t,rdcc->slot); - HDmemset (rdcc, 0, sizeof(H5D_rdcc_t)); + H5FL_SEQ_FREE(H5D_rdcc_ent_ptr_t, rdcc->slot); + HDmemset(rdcc, 0, sizeof(H5D_rdcc_t)); /* Free the raw B-tree node buffer */ - if(dset->shared->layout.u.chunk.btree_shared==NULL) + if(dset->shared->layout.u.chunk.btree_shared == NULL) HGOTO_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "ref-counted page nil") - if(H5RC_DEC(dset->shared->layout.u.chunk.btree_shared)<0) + if(H5RC_DEC(dset->shared->layout.u.chunk.btree_shared) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "unable to decrement ref-counted page") done: @@ -1835,7 +1817,7 @@ H5D_istore_lock(const H5D_io_info_t *io_info, H5D_istore_ud1_t *udata, /* Search for the chunk in the cache */ if(rdcc->nslots > 0) { - idx = H5D_HASH(dset->shared,io_info->store->chunk.index); + idx = H5D_CHUNK_HASH(dset->shared, io_info->store->chunk.index); ent = rdcc->slot[idx]; if(ent) @@ -1950,10 +1932,8 @@ H5D_istore_lock(const H5D_io_info_t *io_info, H5D_istore_ud1_t *udata, if(H5D_fill_refill_vl(&fb_info, fb_info.elmts_per_buf, io_info->dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, NULL, "can't refill fill value buffer") } /* end if */ -#ifdef H5_CLEAR_MEMORY else HDmemset(chunk, 0, chunk_size); -#endif /* H5_CLEAR_MEMORY */ #ifdef H5D_ISTORE_DEBUG rdcc->ninits++; #endif /* H5D_ISTORE_DEBUG */ @@ -2154,339 +2134,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5D_istore_if_load - * - * Purpose: A small internal function to if it's necessary to load the - * chunk into cache. - * - * Return: TRUE or FALSE - * - * Programmer: Raymond Lu - * 17 July 2007 - * - *------------------------------------------------------------------------- - */ -hbool_t -H5D_istore_if_load(const H5D_io_info_t *io_info, haddr_t caddr) -{ - const H5D_t *dataset = io_info->dset; - hbool_t ret_value; - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_istore_if_load) - - HDassert(io_info); - HDassert(dataset); - - /* - * If the chunk is too large to load into the cache and it has no - * filters in the pipeline (i.e. not compressed) and if the address - * for the chunk has been defined, then don't load the chunk into the - * cache, just write the data to it directly. - * - * If MPI based VFD is used, must bypass the - * chunk-cache scheme because other MPI processes could be - * writing to other elements in the same chunk. Do a direct - * write-through of only the elements requested. - */ - if(dataset->shared->dcpl_cache.pline.nused==0 && - ((dataset->shared->layout.u.chunk.size > dataset->shared->cache.chunk.nbytes && caddr != HADDR_UNDEF) -#ifdef H5_HAVE_PARALLEL - || (io_info->using_mpi_vfd && (H5F_ACC_RDWR & H5F_get_intent(dataset->oloc.file))) -#endif /* H5_HAVE_PARALLEL */ - )) { - ret_value = FALSE; - } else - ret_value = TRUE; - - FUNC_LEAVE_NOAPI(ret_value) -} - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_readvv - * - * Purpose: Reads a multi-dimensional buffer from (part of) an indexed raw - * storage array. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Wednesday, May 7, 2003 - * - * Modification: - * Raymond Lu - * 20 July 2007 - * Moved H5D_istore_lock and H5D_istore_unlock to H5D_chunk_read - * from this function to avoid frequent lock and unlock. - * - *------------------------------------------------------------------------- - */ -ssize_t -H5D_istore_readvv(const H5D_io_info_t *io_info, - size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t chunk_addr, void *chunk, void *buf) -{ - H5D_t *dset=io_info->dset; /* Local pointer to the dataset info */ - size_t u; /* Local index variables */ - ssize_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_readvv, FAIL) - - /* Check args */ - HDassert(io_info); - HDassert(dset && H5D_CHUNKED==dset->shared->layout.type); - HDassert(dset->shared->layout.u.chunk.ndims>0 && dset->shared->layout.u.chunk.ndims<=H5O_LAYOUT_NDIMS); - HDassert(io_info->dxpl_cache); - HDassert(io_info->store); - HDassert(chunk_len_arr); - HDassert(chunk_offset_arr); - HDassert(mem_len_arr); - HDassert(mem_offset_arr); - HDassert(buf); - - /* Get the address of this chunk on disk */ -#ifdef QAK -HDfprintf(stderr,"%s: io_info->store->chunk.offset={",FUNC); -for(u=0; ushared->layout.u.chunk.ndims; u++) - HDfprintf(stderr,"%Hd%s",io_info->store->chunk.offset[u],(u<(dset->shared->layout.u.chunk.ndims-1) ? ", " : "}\n")); - -HDfprintf(stderr,"%s: chunk_addr=%a, chunk_size=%Zu\n",FUNC,chunk_addr,dset->shared->layout.u.chunk.size); -HDfprintf(stderr,"%s: chunk_len_arr[%Zu]=%Zu\n",FUNC,*chunk_curr_seq,chunk_len_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: chunk_offset_arr[%Zu]=%Hu\n",FUNC,*chunk_curr_seq,chunk_offset_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: mem_len_arr[%Zu]=%Zu\n",FUNC,*mem_curr_seq,mem_len_arr[*mem_curr_seq]); -HDfprintf(stderr,"%s: mem_offset_arr[%Zu]=%Hu\n",FUNC,*mem_curr_seq,mem_offset_arr[*mem_curr_seq]); -HDfprintf(stderr,"%s: buf=%p\n",FUNC,buf); -#endif /* QAK */ - - /* - * If the chunk is too large to load into the cache and it has no - * filters in the pipeline (i.e. not compressed) and if the address - * for the chunk has been defined, then don't load the chunk into the - * cache, just read the data from it directly. - * - * If MPI based VFD is used, must bypass the - * chunk-cache scheme because other MPI processes could be - * writing to other elements in the same chunk. Do a direct - * read-through of only the elements requested. - */ - if(!H5D_istore_if_load(io_info, chunk_addr)) { - H5D_io_info_t chk_io_info; /* Temporary I/O info object */ - H5D_storage_t chk_store; /* Chunk storage information */ - - /* Set up the storage information for the chunk */ - chk_store.contig.dset_addr=chunk_addr; - chk_store.contig.dset_size=(hsize_t)dset->shared->layout.u.chunk.size; - - /* Set up new dataset I/O info */ - H5D_BUILD_IO_INFO(&chk_io_info,dset,io_info->dxpl_cache,io_info->dxpl_id,&chk_store); - - /* Do I/O directly on chunk without reading it into the cache */ - if ((ret_value=H5D_contig_readvv(&chk_io_info, chunk_max_nseq, chunk_curr_seq, chunk_len_arr, - chunk_offset_arr, mem_max_nseq, mem_curr_seq, mem_len_arr, mem_offset_arr, (haddr_t)0, NULL, buf))<0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data to file") - } /* end if */ - else { - ssize_t naccessed; /* Number of bytes accessed in chunk */ - - /* If the chunk address is not defined, check if the fill value is - * undefined also. If both situations hold, don't bother copying - * values to the destination buffer, since they will just be - * garbage. - * - * Ideally, this will eventually be checked at a higher level and - * the entire I/O operation on the chunk will be skipped. -QAK - */ - if(!H5F_addr_defined(chunk_addr)) { - H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);/*raw data chunk cache*/ - hbool_t found = FALSE; /*already in cache? */ - - /* Check if the chunk is in the cache (but hasn't been written to disk yet) */ - if(rdcc->nslots>0) { - unsigned idx = H5D_HASH(dset->shared, io_info->store->chunk.index); /* Cache entry index */ - H5D_rdcc_ent_t *ent = rdcc->slot[idx]; /* Cache entry */ - - /* Potential match... */ - if(ent) { - for(u = 0, found = TRUE; u < dset->shared->layout.u.chunk.ndims; u++) { - if(io_info->store->chunk.offset[u] != ent->offset[u]) { - found = FALSE; - break; - } /* end if */ - } /* end for */ - } /* end if */ - } /* end if */ - - /* If the chunk is in the cache, then it must have valid data */ - if(!found) { - const H5O_fill_t *fill = &(dset->shared->dcpl_cache.fill); /* Fill value info */ - H5D_fill_value_t fill_status; - - /* Check if the fill value is defined */ - if(H5P_is_fill_value_defined(fill, &fill_status) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined") - - /* If we are never to return fill values, or if we would return them - * but they aren't set, process the entire set of I/O vectors and - * get out now. - */ - if(fill->fill_time == H5D_FILL_TIME_NEVER || - (fill->fill_time == H5D_FILL_TIME_IFSET && fill_status!=H5D_FILL_VALUE_USER_DEFINED)) { - size_t size; /* Size of sequence in bytes */ - size_t v; /* Local index variable */ - ssize_t bytes_processed = 0; /* Eventual return value */ - - /* Work through all the sequences */ - for(u = *mem_curr_seq, v = *chunk_curr_seq; u < mem_max_nseq && v < chunk_max_nseq; ) { - /* Choose smallest buffer to write */ - if(chunk_len_arr[v] < mem_len_arr[u]) - size = chunk_len_arr[v]; - else - size = mem_len_arr[u]; - - /* Update source information */ - chunk_len_arr[v] -= size; - chunk_offset_arr[v] += size; - if(chunk_len_arr[v] == 0) - v++; - - /* Update destination information */ - mem_len_arr[u] -= size; - mem_offset_arr[u] += size; - if(mem_len_arr[u] == 0) - u++; - - /* Increment number of bytes copied */ - bytes_processed += (ssize_t)size; - } /* end for */ - - /* Update current sequence vectors */ - *mem_curr_seq = u; - *chunk_curr_seq = v; - - HGOTO_DONE(bytes_processed) - } /* end if */ - } /* end if */ - } /* end if */ - - /* Use the vectorized memory copy routine to do actual work */ - if((naccessed = H5V_memcpyvv(buf, mem_max_nseq, mem_curr_seq, mem_len_arr, mem_offset_arr, chunk, chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_offset_arr)) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "vectorized memcpy failed") - - H5_CHECK_OVERFLOW(naccessed, ssize_t, size_t); - - /* Set return value */ - ret_value = naccessed; - } /* end else */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5D_istore_readvv() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_writevv - * - * Purpose: Writes a multi-dimensional buffer to (part of) an indexed raw - * storage array. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Friday, May 2, 2003 - * - * Modification: - * Raymond Lu - * 20 July 2007 - * Moved H5D_istore_lock and H5D_istore_unlock to H5D_chunk_write - * from this function to avoid frequent lock and unlock. - * - *------------------------------------------------------------------------- - */ -ssize_t -H5D_istore_writevv(const H5D_io_info_t *io_info, - size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t chunk_addr, void *chunk, const void *buf) -{ - H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */ - ssize_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_writevv, FAIL) - - /* Check args */ - HDassert(io_info); - HDassert(dset && H5D_CHUNKED==dset->shared->layout.type); - HDassert(dset->shared->layout.u.chunk.ndims>0 && dset->shared->layout.u.chunk.ndims<=H5O_LAYOUT_NDIMS); - HDassert(io_info->dxpl_cache); - HDassert(io_info->store); - HDassert(chunk_len_arr); - HDassert(chunk_offset_arr); - HDassert(mem_len_arr); - HDassert(mem_offset_arr); - HDassert(buf); - -#ifdef QAK -{ -size_t u; /* Local index variables */ - -HDfprintf(stderr,"%s: io_info->store->chunk.offset={",FUNC); -for(u=0; ushared->layout.u.chunk.ndims; u++) - HDfprintf(stderr,"%Hd%s",io_info->store->chunk.offset[u],(u<(dset->shared->layout.u.chunk.ndims-1) ? ", " : "}\n")); - -HDfprintf(stderr,"%s: chunk_addr=%a, chunk_size=%Zu\n",FUNC,chunk_addr,dset->shared->layout.u.chunk.size); -HDfprintf(stderr,"%s: chunk_len_arr[%Zu]=%Zu\n",FUNC,*chunk_curr_seq,chunk_len_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: chunk_offset_arr[%Zu]=%Hu\n",FUNC,*chunk_curr_seq,chunk_offset_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: mem_len_arr[%Zu]=%Zu\n",FUNC,*mem_curr_seq,mem_len_arr[*mem_curr_seq]); -HDfprintf(stderr,"%s: mem_offset_arr[%Zu]=%Hu\n",FUNC,*mem_curr_seq,mem_offset_arr[*mem_curr_seq]); -} -#endif /* QAK */ - - /* - * If the chunk is too large to load into the cache and it has no - * filters in the pipeline (i.e. not compressed) and if the address - * for the chunk has been defined, then don't load the chunk into the - * cache, just write the data to it directly. - * - * If MPI based VFD is used, must bypass the - * chunk-cache scheme because other MPI processes could be - * writing to other elements in the same chunk. Do a direct - * write-through of only the elements requested. - */ - if(!H5D_istore_if_load(io_info, chunk_addr)) { - H5D_io_info_t chk_io_info; /* Temporary I/O info object */ - H5D_storage_t chk_store; /* Chunk storage information */ - - /* Set up the storage information for the chunk */ - chk_store.contig.dset_addr=chunk_addr; - chk_store.contig.dset_size=(hsize_t)dset->shared->layout.u.chunk.size; - - /* Set up new dataset I/O info */ - H5D_BUILD_IO_INFO(&chk_io_info,dset,io_info->dxpl_cache,io_info->dxpl_id,&chk_store); - - /* Do I/O directly on chunk without reading it into the cache */ - if((ret_value = H5D_contig_writevv(&chk_io_info, chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_offset_arr, mem_max_nseq, mem_curr_seq, mem_len_arr, mem_offset_arr, (haddr_t)0, NULL, buf)) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file") - } /* end if */ - else { - ssize_t naccessed; /* Number of bytes accessed in chunk */ - - /* Use the vectorized memory copy routine to do actual work */ - if((naccessed=H5V_memcpyvv(chunk,chunk_max_nseq,chunk_curr_seq,chunk_len_arr,chunk_offset_arr,buf,mem_max_nseq,mem_curr_seq,mem_len_arr,mem_offset_arr))<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed") - - H5_CHECK_OVERFLOW(naccessed,ssize_t,size_t); - - /* Set return value */ - ret_value=naccessed; - } /* end else */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5D_istore_writevv() */ - - -/*------------------------------------------------------------------------- * Function: H5D_istore_create * * Purpose: Creates a new indexed-storage B-tree and initializes the @@ -2567,16 +2214,16 @@ H5D_istore_allocated(H5D_t *dset, hid_t dxpl_id) HDassert(dset); /* Fill the DXPL cache values for later use */ - if (H5D_get_dxpl_cache(dxpl_id,&dxpl_cache)<0) + if(H5D_get_dxpl_cache(dxpl_id,&dxpl_cache) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, 0, "can't fill dxpl cache") /* Construct dataset I/O info */ - H5D_BUILD_IO_INFO(&io_info,dset,dxpl_cache,dxpl_id,NULL); + H5D_BUILD_IO_INFO_WRT(&io_info, dset, dxpl_cache, dxpl_id, NULL, NULL); /* Search for cached chunks that haven't been written out */ for(ent = rdcc->head; ent; ent = ent->next) { /* Flush the chunk out to disk, to make certain the size is correct later */ - if (H5D_istore_flush_entry(&io_info, ent, FALSE)<0) + if (H5D_istore_flush_entry(&io_info, ent, FALSE) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, 0, "cannot flush indexed storage buffer") } /* end for */ @@ -2609,7 +2256,7 @@ done: */ herr_t H5D_istore_chunkmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[], - hsize_t down_chunks[]) + const hsize_t down_chunks[]) { H5D_t *dset = io_info->dset; /* Local pointer to dataset info */ H5D_istore_it_ud5_t udata; @@ -2908,7 +2555,7 @@ H5D_istore_allocate(H5D_t *dset, hid_t dxpl_id, hbool_t full_overwrite) /* Set up dataset I/O info */ store.chunk.offset = chunk_offset; - H5D_BUILD_IO_INFO(&io_info, dset, dxpl_cache, data_dxpl_id, &store); + H5D_BUILD_IO_INFO_WRT(&io_info, dset, dxpl_cache, data_dxpl_id, &store, NULL); /* Reset the chunk offset indices */ HDmemset(chunk_offset, 0, (layout->u.chunk.ndims * sizeof(chunk_offset[0]))); @@ -3574,7 +3221,7 @@ H5D_istore_initialize_by_extent(H5D_io_info_t *io_info) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunk selection information") /* Scatter the data into memory */ - if(H5D_select_mscat(fb_info.fill_buf, space_chunk, &chunk_iter, (size_t)nelmts, io_info->dxpl_cache, chunk/*out*/) < 0) { + if(H5D_scatter_mem(fb_info.fill_buf, space_chunk, &chunk_iter, (size_t)nelmts, io_info->dxpl_cache, chunk/*out*/) < 0) { H5S_SELECT_ITER_RELEASE(&chunk_iter); HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") } /* end if */ @@ -3728,7 +3375,7 @@ H5D_istore_update_cache(H5D_t *dset, hid_t dxpl_id) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") /* Construct dataset I/O info */ - H5D_BUILD_IO_INFO(&io_info, dset, dxpl_cache, dxpl_id, NULL); + H5D_BUILD_IO_INFO_WRT(&io_info, dset, dxpl_cache, dxpl_id, NULL, NULL); /* Recompute the index for each cached chunk that is in a dataset */ for(ent = rdcc->head; ent; ent = next) { @@ -3744,7 +3391,7 @@ H5D_istore_update_cache(H5D_t *dset, hid_t dxpl_id) /* Compute the index for the chunk entry */ old_idx=ent->idx; /* Save for later */ - ent->idx=H5D_HASH(dset->shared,idx); + ent->idx=H5D_CHUNK_HASH(dset->shared, idx); if(old_idx != ent->idx) { /* Check if there is already a chunk at this chunk's new location */ diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index 22f32ab..889fbce 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -34,12 +34,12 @@ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ -#include "H5Iprivate.h" #include "H5Dpkg.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* File access */ #include "H5FDprivate.h" /* File drivers */ -#include "H5MMprivate.h" +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ #include "H5Oprivate.h" /* Object headers */ #include "H5Pprivate.h" /* Property lists */ #include "H5Sprivate.h" /* Dataspaces */ @@ -86,6 +86,7 @@ #define H5D_CHUNK_SELECT_IRREG 2 #define H5D_CHUNK_SELECT_NONE 0 + /******************/ /* Local Typedefs */ /******************/ @@ -95,66 +96,47 @@ typedef struct H5D_chunk_addr_info_t { H5D_chunk_info_t chunk_info; } H5D_chunk_addr_info_t; -/* Combine all information that needs to know for collective MPI-IO of this selection. */ -typedef struct H5D_common_coll_info_t { - hbool_t mbt_is_derived; - hbool_t mft_is_derived; - size_t mpi_buf_count; - haddr_t chunk_addr; -} H5D_common_coll_info_t; - /********************/ /* Local Prototypes */ /********************/ - -static herr_t -H5D_multi_chunk_collective_io(H5D_io_info_t *io_info,H5D_chunk_map_t *fm,const void *buf, - hbool_t do_write); -static herr_t -H5D_multi_chunk_collective_io_no_opt(H5D_io_info_t *io_info,H5D_chunk_map_t *fm,const void *buf, - hbool_t do_write); - -static herr_t -H5D_link_chunk_collective_io(H5D_io_info_t *io_info,H5D_chunk_map_t *fm,const void *buf, - hbool_t do_write,int sum_chunk); - -static herr_t -H5D_inter_collective_io(H5D_io_info_t *io_info,const H5S_t *file_space, - const H5S_t *mem_space,haddr_t addr, - const void *buf, hbool_t do_write ); - -static herr_t -H5D_final_collective_io(H5D_io_info_t *io_info,MPI_Datatype*mpi_file_type, - MPI_Datatype *mpi_buf_type, - H5D_common_coll_info_t* coll_info, - const void *buf, hbool_t do_write); -static herr_t -H5D_sort_chunk(H5D_io_info_t * io_info, - H5D_chunk_map_t *fm, - H5D_chunk_addr_info_t chunk_addr_info_array[], - int many_chunk_opt); - -static herr_t -H5D_obtain_mpio_mode(H5D_io_info_t* io_info, - H5D_chunk_map_t *fm, - uint8_t assign_io_mode[], - haddr_t chunk_addr[]); - -static herr_t H5D_ioinfo_make_ind(H5D_io_info_t *io_info); -static herr_t H5D_ioinfo_make_coll_opt(H5D_io_info_t *io_info); -static herr_t H5D_ioinfo_make_coll(H5D_io_info_t *io_info); +static herr_t H5D_chunk_collective_io(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, H5D_chunk_map_t *fm); +static herr_t H5D_multi_chunk_collective_io(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, H5D_chunk_map_t *fm, + H5P_genplist_t *dx_plist); +static herr_t H5D_multi_chunk_collective_io_no_opt(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, H5D_chunk_map_t *fm, H5P_genplist_t *dx_plist); +#ifdef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS +static herr_t H5D_link_chunk_collective_io(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, H5D_chunk_map_t *fm, int sum_chunk); +#endif /* H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS */ +static herr_t H5D_inter_collective_io(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, const H5S_t *file_space, + const H5S_t *mem_space); +static herr_t H5D_final_collective_io(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, size_t nelmts, MPI_Datatype *mpi_file_type, + MPI_Datatype *mpi_buf_type); +static herr_t H5D_sort_chunk(H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, + H5D_chunk_addr_info_t chunk_addr_info_array[], int many_chunk_opt); +static herr_t H5D_obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, + H5P_genplist_t *dx_plist, uint8_t assign_io_mode[], haddr_t chunk_addr[]); +static herr_t H5D_ioinfo_xfer_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist, + H5FD_mpio_xfer_t xfer_mode); +static herr_t H5D_ioinfo_coll_opt_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist, + H5FD_mpio_collective_opt_t coll_opt_mode); static herr_t H5D_mpio_get_min_chunk(const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, int *min_chunkf); static int H5D_cmp_chunk_addr(const void *addr1, const void *addr2); static herr_t H5D_mpio_get_sum_chunk(const H5D_io_info_t *io_info, - const H5D_chunk_map_t *fm, int *sum_chunkf); + const H5D_chunk_map_t *fm, int *sum_chunkf); /*********************/ /* Package Variables */ /*********************/ + /*******************/ /* Local Variables */ /*******************/ @@ -175,64 +157,77 @@ static herr_t H5D_mpio_get_sum_chunk(const H5D_io_info_t *io_info, *------------------------------------------------------------------------- */ htri_t -H5D_mpio_opt_possible( const H5D_io_info_t *io_info, - const H5S_t *mem_space, const H5S_t *file_space, const H5T_path_t *tpath) +H5D_mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, + const H5S_t *mem_space, const H5D_type_info_t *type_info, + const H5D_chunk_map_t *fm) { - int local_opinion = TRUE; /* This process's idea of whether to perform collective I/O or not */ - int consensus; /* Consensus opinion of all processes */ - int mpi_code; /* MPI error code */ - htri_t ret_value=TRUE; + int local_opinion = TRUE; /* This process's idea of whether to perform collective I/O or not */ + int consensus; /* Consensus opinion of all processes */ + int mpi_code; /* MPI error code */ + htri_t ret_value = TRUE; - FUNC_ENTER_NOAPI(H5D_mpio_opt_possible, FAIL); + FUNC_ENTER_NOAPI(H5D_mpio_opt_possible, FAIL) /* Check args */ - assert(io_info); - assert(mem_space); - assert(file_space); + HDassert(io_info); + HDassert(mem_space); + HDassert(file_space); + HDassert(type_info); /* For independent I/O, get out quickly and don't try to form consensus */ - if (io_info->dxpl_cache->xfer_mode==H5FD_MPIO_INDEPENDENT) + if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_INDEPENDENT) HGOTO_DONE(FALSE); + /* Don't allow collective operations if datatype conversions need to happen */ + if(!type_info->is_conv_noop) { + local_opinion = FALSE; + goto broadcast; + } /* end if */ + + /* Don't allow collective operations if data transform operations should occur */ + if(!type_info->is_xform_noop) { + local_opinion = FALSE; + goto broadcast; + } /* end if */ + /* Optimized MPI types flag must be set and it must be collective IO */ /* (Don't allow parallel I/O for the MPI-posix driver, since it doesn't do real collective I/O) */ - if (!(H5S_mpi_opt_types_g && io_info->dxpl_cache->xfer_mode==H5FD_MPIO_COLLECTIVE && !IS_H5FD_MPIPOSIX(io_info->dset->oloc.file))) { + if(!(H5S_mpi_opt_types_g && io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE + && !IS_H5FD_MPIPOSIX(io_info->dset->oloc.file))) { local_opinion = FALSE; goto broadcast; } /* end if */ /* Check whether these are both simple or scalar dataspaces */ - if (!((H5S_SIMPLE==H5S_GET_EXTENT_TYPE(mem_space) || H5S_SCALAR==H5S_GET_EXTENT_TYPE(mem_space)) - && (H5S_SIMPLE==H5S_GET_EXTENT_TYPE(file_space) || H5S_SCALAR==H5S_GET_EXTENT_TYPE(file_space)))) { + if(!((H5S_SIMPLE == H5S_GET_EXTENT_TYPE(mem_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(mem_space)) + && (H5S_SIMPLE == H5S_GET_EXTENT_TYPE(file_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(file_space)))) { local_opinion = FALSE; goto broadcast; } /* end if */ /* Can't currently handle point selections */ - if (H5S_SEL_POINTS==H5S_GET_SELECT_TYPE(mem_space) || H5S_SEL_POINTS==H5S_GET_SELECT_TYPE(file_space)) { + if(H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(mem_space) + || H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(file_space)) { local_opinion = FALSE; goto broadcast; } /* end if */ /* Dataset storage must be contiguous or chunked */ - if (!(io_info->dset->shared->layout.type == H5D_CONTIGUOUS || + if(!(io_info->dset->shared->layout.type == H5D_CONTIGUOUS || io_info->dset->shared->layout.type == H5D_CHUNKED)) { local_opinion = FALSE; goto broadcast; } /* end if */ - /* The handling of memory space is different for chunking - and contiguous storage, - For contigous storage, mem_space and file_space won't - change when it it is doing disk IO. - For chunking storage, mem_space will change for different - chunks. So for chunking storage, whether we can use - collective IO will defer until each chunk IO is reached. - For contiguous storage, if we find MPI-IO cannot - support complicated MPI derived data type and the shape - of data space is not regular, we will - set use_par_opt_io = FALSE. - */ + /* The handling of memory space is different for chunking and contiguous + * storage. For contiguous storage, mem_space and file_space won't change + * when it it is doing disk IO. For chunking storage, mem_space will + * change for different chunks. So for chunking storage, whether we can + * use collective IO will defer until each chunk IO is reached. For + * contiguous storage, if we find MPI-IO cannot support complicated MPI + * derived data type and the shape of data space is not regular, we will + * set use_par_opt_io = FALSE. + */ #ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS if(io_info->dset->shared->layout.type == H5D_CONTIGUOUS) if((H5S_SELECT_IS_REGULAR(file_space) != TRUE) || @@ -243,81 +238,43 @@ H5D_mpio_opt_possible( const H5D_io_info_t *io_info, #endif /* Don't allow collective operations if filters need to be applied */ - if(io_info->dset->shared->layout.type == H5D_CHUNKED) - if(io_info->dset->shared->dcpl_cache.pline.nused>0) { + if(io_info->dset->shared->layout.type == H5D_CHUNKED) { + if(io_info->dset->shared->dcpl_cache.pline.nused > 0) { local_opinion = FALSE; goto broadcast; } /* end if */ - /* Don't allow collective operations if datatype conversions need to happen */ - if(!H5T_path_noop(tpath)) { - local_opinion = FALSE; - goto broadcast; - } /* end if */ - - /* Don't allow collective operations if data transform operations should occur */ - if(!H5Z_xform_noop(io_info->dxpl_cache->data_xform_prop)) { - local_opinion = FALSE; - goto broadcast; +/* If H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS and H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS + * are defined, the HDF5 library will do collective IO if the application + * asks for it. + * + * If H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS is not defined and one or more + * processes are not participating in the IO, then collective IO is not + * assured. The library will check each process for the number of chunks + * it involves. If any process involves zero chunks, the library will use + * independent IO mode instead. + */ +#ifndef H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS + /* Check the number of chunks to perform I/O on */ + if(0 == H5SL_count(fm->sel_chunks)) { + local_opinion = FALSE; + goto broadcast; + } /* end if */ +#endif /* H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS */ } /* end if */ broadcast: /* Form consensus opinion among all processes about whether to perform - * collective I/O */ - if (MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_opinion, &consensus, 1, MPI_INT, MPI_LAND, io_info->comm))) + * collective I/O + */ + if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_opinion, &consensus, 1, MPI_INT, MPI_LAND, io_info->comm))) HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code) ret_value = consensus > 0 ? TRUE : FALSE; done: - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_mpio_opt_possible() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_mpio_chunk_adjust_iomode - * - * Decription: If H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS and - H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS are defined, - the HDF5 library will do collective IO if the application asks for it. - - If H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS is not defined - and one or more processes are not participating in the IO, - then collective IO is not assured. The library will check - each process for the - number of chunks it involves. If any process involves zero chunks, - the library will use independent IO mode instead. - This function is only used for linked chunk IO. - * Purpose: Checks if it is possible to do collective IO - * - * Return: Success: Non-negative: TRUE or FALSE - * Failure: Negative - * - * Programmer: Muqun Yang - * Monday, Feb. 13th, 2006 - * - *------------------------------------------------------------------------- - */ -#ifndef H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS -herr_t -H5D_mpio_chunk_adjust_iomode(H5D_io_info_t *io_info, const H5D_chunk_map_t *fm) -{ - int min_chunk; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NOINIT(H5D_mpio_chunk_adjust_iomode) - - if(H5D_mpio_get_min_chunk(io_info,fm,&min_chunk) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to obtain the min chunk number of all processes"); - if(min_chunk == 0) { - /* Switch to independent I/O */ - if(H5D_ioinfo_make_ind(io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to independent I/O") - } /* end if */ -done: FUNC_LEAVE_NOAPI(ret_value) -} -#endif +} /* H5D_mpio_opt_possible() */ /*------------------------------------------------------------------------- @@ -332,23 +289,20 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D_mpio_select_read(H5D_io_info_t *io_info, - size_t mpi_buf_count, - const size_t UNUSED elmt_size, - const H5S_t UNUSED *file_space, - const H5S_t UNUSED *mem_space, - haddr_t addr, - void UNUSED *pointer, - void *buf/*out*/) +H5D_mpio_select_read(const H5D_io_info_t *io_info, const H5D_type_info_t UNUSED *type_info, + hsize_t mpi_buf_count, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space) { + const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI(H5D_mpio_select_read,FAIL); + FUNC_ENTER_NOAPI(H5D_mpio_select_read, FAIL) + + H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t); + if(H5F_block_read(io_info->dset->oloc.file, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, io_info->dxpl_id, io_info->u.rbuf) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "can't finish collective parallel read") - if(H5F_block_read (io_info->dset->oloc.file, H5FD_MEM_DRAW, addr, mpi_buf_count, io_info->dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_IO,H5E_READERROR,FAIL,"can't finish collective parallel read"); done: - FUNC_LEAVE_NOAPI(ret_value); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_mpio_select_read() */ @@ -364,32 +318,28 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D_mpio_select_write(H5D_io_info_t *io_info, - size_t mpi_buf_count, - const size_t UNUSED elmt_size, - const H5S_t UNUSED *file_space, - const H5S_t UNUSED *mem_space, - haddr_t addr, - void UNUSED *pointer, - const void *buf) +H5D_mpio_select_write(const H5D_io_info_t *io_info, const H5D_type_info_t UNUSED *type_info, + hsize_t mpi_buf_count, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space) { + const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI(H5D_mpio_select_write,FAIL); + FUNC_ENTER_NOAPI(H5D_mpio_select_write, FAIL) /*OKAY: CAST DISCARDS CONST QUALIFIER*/ - if(H5F_block_write (io_info->dset->oloc.file, H5FD_MEM_DRAW, addr, mpi_buf_count, io_info->dxpl_id, buf)<0) - HGOTO_ERROR(H5E_IO,H5E_WRITEERROR,FAIL,"can't finish collective parallel write"); + H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t); + if(H5F_block_write(io_info->dset->oloc.file, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, io_info->dxpl_id, io_info->u.wbuf) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "can't finish collective parallel write") done: - FUNC_LEAVE_NOAPI(ret_value); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_mpio_select_write() */ /*------------------------------------------------------------------------- - * Function: H5D_ioinfo_make_ind + * Function: H5D_ioinfo_xfer_mode * - * Purpose: Switch to MPI independent I/O + * Purpose: Switch to between collective & independent MPI I/O * * Return: Non-negative on success/Negative on failure * @@ -399,42 +349,42 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D_ioinfo_make_ind(H5D_io_info_t *io_info) +H5D_ioinfo_xfer_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist, + H5FD_mpio_xfer_t xfer_mode) { - H5P_genplist_t *dx_plist; /* Data transer property list */ herr_t ret_value = SUCCEED; /*return value */ - FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_make_ind) - - /* Get the dataset transfer property list */ - if (NULL == (dx_plist = H5I_object(io_info->dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") + FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_xfer_mode) - /* Change the xfer_mode to independent, handle the request, - * then set xfer_mode before return. - */ - io_info->dxpl_cache->xfer_mode = H5FD_MPIO_INDEPENDENT; - if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0) + /* Change the xfer_mode */ + io_info->dxpl_cache->xfer_mode = xfer_mode; + if(H5P_set(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") - /* Set the pointers to the non-MPI-specific routines */ - io_info->ops.read = H5D_select_read; - io_info->ops.write = H5D_select_write; + /* Change the "single I/O" function pointers */ + if(xfer_mode == H5FD_MPIO_INDEPENDENT) { + /* Set the pointers to the original, non-MPI-specific routines */ + io_info->io_ops.single_read = io_info->orig.io_ops.single_read; + io_info->io_ops.single_write = io_info->orig.io_ops.single_write; + } /* end if */ + else { + HDassert(xfer_mode == H5FD_MPIO_COLLECTIVE); - /* Indicate that the transfer mode should be restored before returning - * to user. - */ - io_info->xfer_mode_changed=TRUE; + /* Set the pointers to the MPI-specific routines */ + io_info->io_ops.single_read = H5D_mpio_select_read; + io_info->io_ops.single_write = H5D_mpio_select_write; + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_ioinfo_make_ind() */ +} /* end H5D_ioinfo_xfer_mode() */ /*------------------------------------------------------------------------- - * Function: H5D_ioinfo_make_coll_opt + * Function: H5D_ioinfo_coll_opt_mode * - * Purpose: Switch to MPI independent I/O with file set view + * Purpose: Switch between using collective & independent MPI I/O w/file + * set view * * Return: Non-negative on success/Negative on failure * @@ -444,87 +394,21 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D_ioinfo_make_coll_opt(H5D_io_info_t *io_info) +H5D_ioinfo_coll_opt_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist, + H5FD_mpio_collective_opt_t coll_opt_mode) { - H5P_genplist_t *dx_plist; /* Data transer property list */ herr_t ret_value = SUCCEED; /*return value */ - FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_make_coll_opt) + FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_coll_opt_mode) - /* Get the dataset transfer property list */ - if (NULL == (dx_plist = H5I_object(io_info->dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") - - /* Change the optimial xfer_mode to independent, handle the request, - * then set xfer_mode before return. - */ - io_info->dxpl_cache->xfer_opt_mode = H5FD_MPIO_INDIVIDUAL_IO; - if(H5P_set (dx_plist, H5D_XFER_IO_XFER_OPT_MODE_NAME, &io_info->dxpl_cache->xfer_opt_mode) < 0) + /* Change the optimal xfer_mode */ + io_info->dxpl_cache->coll_opt_mode = coll_opt_mode; + if(H5P_set(dx_plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &io_info->dxpl_cache->coll_opt_mode) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") - /* Set the pointers to the non-MPI-specific routines */ - io_info->ops.read = H5D_mpio_select_read; - io_info->ops.write = H5D_mpio_select_write; - - /* Indicate that the transfer mode should be restored before returning - * to user. - */ - io_info->xfer_opt_mode_changed = TRUE; - done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_ioinfo_make_coll_opt() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_ioinfo_make_coll - * - * Purpose: Switch to MPI collective I/O - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Friday, August 12, 2005 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_ioinfo_make_coll(H5D_io_info_t *io_info) -{ - H5P_genplist_t *dx_plist; /* Data transer property list */ - herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_ioinfo_make_coll) - - /* Get the dataset transfer property list */ - if (NULL == (dx_plist = H5I_object(io_info->dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") - - /* Change the xfer_mode to independent, handle the request, - * then set xfer_mode before return. - */ - io_info->dxpl_cache->xfer_mode = H5FD_MPIO_COLLECTIVE; - if(H5P_set (dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") - - io_info->dxpl_cache->xfer_opt_mode = H5FD_MPIO_COLLECTIVE_IO; - if(H5P_set (dx_plist, H5D_XFER_IO_XFER_OPT_MODE_NAME, &io_info->dxpl_cache->xfer_opt_mode) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") - - - /* Set the pointers to the MPI-specific routines */ - io_info->ops.read = H5D_mpio_select_read; - io_info->ops.write = H5D_mpio_select_write; - - /* Indicate that the transfer mode should _NOT_ be restored before returning - * to user. - */ - io_info->xfer_mode_changed=FALSE; - io_info->xfer_opt_mode_changed=FALSE; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_ioinfo_make_coll() */ +} /* end H5D_ioinfo_coll_opt_mode() */ /*------------------------------------------------------------------------- @@ -535,29 +419,30 @@ done: * * Return: Non-negative on success/Negative on failure * - * Programmer: + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5D_mpio_get_min_chunk(const H5D_io_info_t *io_info, - const H5D_chunk_map_t *fm, int *min_chunkf) +H5D_mpio_get_min_chunk(const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, + int *min_chunkf) { int num_chunkf; /* Number of chunks to iterate over */ int mpi_code; /* MPI return code */ herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI_NOINIT(H5D_mpio_get_min_chunk); + FUNC_ENTER_NOAPI_NOINIT(H5D_mpio_get_min_chunk) /* Get the number of chunks to perform I/O on */ num_chunkf = H5SL_count(fm->sel_chunks); /* Determine the minimum # of chunks for all processes */ - if (MPI_SUCCESS != (mpi_code = MPI_Allreduce(&num_chunkf, min_chunkf, 1, MPI_INT, MPI_MIN, io_info->comm))) + if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&num_chunkf, min_chunkf, 1, MPI_INT, MPI_MIN, io_info->comm))) HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code) done: - FUNC_LEAVE_NOAPI(ret_value); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_mpio_get_min_chunk() */ @@ -569,221 +454,252 @@ done: * * Return: Non-negative on success/Negative on failure * - * Programmer: + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5D_mpio_get_sum_chunk(const H5D_io_info_t *io_info, - const H5D_chunk_map_t *fm, int *sum_chunkf) +H5D_mpio_get_sum_chunk(const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, + int *sum_chunkf) { int num_chunkf; /* Number of chunks to iterate over */ size_t ori_num_chunkf; int mpi_code; /* MPI return code */ herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI_NOINIT(H5D_mpio_get_sum_chunk); + FUNC_ENTER_NOAPI_NOINIT(H5D_mpio_get_sum_chunk) /* Get the number of chunks to perform I/O on */ num_chunkf = 0; ori_num_chunkf = H5SL_count(fm->sel_chunks); - H5_ASSIGN_OVERFLOW(num_chunkf,ori_num_chunkf,size_t,int); + H5_ASSIGN_OVERFLOW(num_chunkf, ori_num_chunkf, size_t, int); /* Determine the summation of number of chunks for all processes */ - if (MPI_SUCCESS != (mpi_code = MPI_Allreduce(&num_chunkf, sum_chunkf, 1, MPI_INT, MPI_SUM, io_info->comm))) + if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&num_chunkf, sum_chunkf, 1, MPI_INT, MPI_SUM, io_info->comm))) HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code) done: - FUNC_LEAVE_NOAPI(ret_value); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_mpio_get_sum_chunk() */ /*------------------------------------------------------------------------- - * Function: H5D_contig_collective_io + * Function: H5D_contig_collective_read * - * Purpose: Wrapper Routine for H5D_inter_collective_io - The starting file address of contiguous layout - will be calculated and passed to H5D_inter_collective_io routine. - * + * Purpose: Reads directly from contiguous data in file into application + * memory using collective I/O. * * Return: Non-negative on success/Negative on failure * - * Programmer: - * - * Modifications: + * Programmer: Quincey Koziol + * Tuesday, March 4, 2008 * *------------------------------------------------------------------------- */ herr_t -H5D_contig_collective_io(H5D_io_info_t *io_info, - const H5S_t *file_space, - const H5S_t *mem_space, - const void *buf, - hbool_t do_write) +H5D_contig_collective_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t UNUSED nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t UNUSED *fm) { + herr_t ret_value = SUCCEED; /* Return value */ + FUNC_ENTER_NOAPI(H5D_contig_collective_read, FAIL) - haddr_t addr = HADDR_UNDEF; /* Address of dataset (or selection) within file */ - herr_t ret_value = SUCCEED; /* return value */ + /* Sanity check */ + HDassert(IS_H5FD_MPIO(io_info->dset->oloc.file)); + HDassert(TRUE == H5P_isa_class(io_info->dxpl_id, H5P_DATASET_XFER)); + + /* Call generic internal collective I/O routine */ + if(H5D_inter_collective_io(io_info, type_info, file_space, mem_space) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't finish shared collective MPI-IO") - FUNC_ENTER_NOAPI_NOINIT(H5D_contig_collective_io) - assert (IS_H5FD_MPIO(io_info->dset->oloc.file)); +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_contig_collective_read() */ - /* Make certain we have the correct type of property list */ - assert(TRUE==H5P_isa_class(io_info->dxpl_id,H5P_DATASET_XFER)); + +/*------------------------------------------------------------------------- + * Function: H5D_contig_collective_write + * + * Purpose: Write directly to contiguous data in file from application + * memory using collective I/O. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, March 4, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D_contig_collective_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t UNUSED nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t UNUSED *fm) +{ + herr_t ret_value = SUCCEED; /* Return value */ - /* Get the base address of the contiguous dataset */ - if(io_info->dset->shared->layout.type == H5D_CONTIGUOUS) - addr = H5D_contig_get_addr(io_info->dset); + FUNC_ENTER_NOAPI(H5D_contig_collective_write, FAIL) - if(H5D_inter_collective_io(io_info,file_space,mem_space,addr,buf,do_write)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - - done: + /* Sanity check */ + HDassert(IS_H5FD_MPIO(io_info->dset->oloc.file)); + HDassert(TRUE == H5P_isa_class(io_info->dxpl_id, H5P_DATASET_XFER)); + /* Call generic internal collective I/O routine */ + if(H5D_inter_collective_io(io_info, type_info, file_space, mem_space) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "couldn't finish shared collective MPI-IO") + +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_contig_collective_io */ +} /* end H5D_contig_collective_write() */ /*------------------------------------------------------------------------- * Function: H5D_chunk_collective_io * * Purpose: Routine for - 1) choose an IO option: - a) One collective IO defined by one MPI derived datatype to link through all chunks - or b) multiple chunk IOs,to do MPI-IO for each chunk, the IO mode may be adjusted - due to the selection pattern for each chunk. + * 1) choose an IO option: + * a) One collective IO defined by one MPI derived datatype to link through all chunks + * or b) multiple chunk IOs,to do MPI-IO for each chunk, the IO mode may be adjusted + * due to the selection pattern for each chunk. * For option a) - 1. Sort the chunk address, obtain chunk info according to the sorted chunk address - 2. Build up MPI derived datatype for each chunk - 3. Build up the final MPI derived datatype - 4. Set up collective IO property list - 5. Do IO + * 1. Sort the chunk address, obtain chunk info according to the sorted chunk address + * 2. Build up MPI derived datatype for each chunk + * 3. Build up the final MPI derived datatype + * 4. Set up collective IO property list + * 5. Do IO * For option b) - 1. Use MPI_gather and MPI_Bcast to obtain information of *collective/independent/none* - IO mode for each chunk of the selection - 2. Depending on whether the IO mode is collective or independent or none, - Create either MPI derived datatype for each chunk to do collective IO or - just do independent IO or independent IO with file set view - 3. Set up collective IO property list for collective mode - 4. DO IO + * 1. Use MPI_gather and MPI_Bcast to obtain information of *collective/independent/none* + * IO mode for each chunk of the selection + * 2. Depending on whether the IO mode is collective or independent or none, + * Create either MPI derived datatype for each chunk to do collective IO or + * just do independent IO or independent IO with file set view + * 3. Set up collective IO property list for collective mode + * 4. DO IO * * Return: Non-negative on success/Negative on failure * - * Programmer: - * - * Modifications: + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ -herr_t -H5D_chunk_collective_io(H5D_io_info_t *io_info,H5D_chunk_map_t *fm,const void *buf, hbool_t do_write) +static herr_t +H5D_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + H5D_chunk_map_t *fm) { - - int io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; - int sum_chunk = 0,mpi_size; - unsigned one_link_chunk_io_threshold; - H5P_genplist_t *plist; + H5P_genplist_t *dx_plist; /* Pointer to DXPL */ H5FD_mpio_chunk_opt_t chunk_opt_mode; - + int io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; + int sum_chunk = -1; #ifdef H5_HAVE_INSTRUMENTED_LIBRARY - htri_t check_prop,temp_not_link_io = FALSE; - int new_value; + htri_t temp_not_link_io = FALSE; #endif - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_collective_io) - assert (IS_H5FD_MPIO(io_info->dset->oloc.file)); + /* Sanity checks */ + HDassert(io_info); + HDassert(io_info->using_mpi_vfd); + HDassert(type_info); + HDassert(fm); /* Obtain the data transfer properties */ - if(NULL == (plist = H5I_object(io_info->dxpl_id))) + if(NULL == (dx_plist = H5I_object(io_info->dxpl_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") - + /* Check the optional property list on what to do with collective chunk IO. */ - chunk_opt_mode=(H5FD_mpio_chunk_opt_t)H5P_peek_unsigned(plist,H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME); - + chunk_opt_mode = (H5FD_mpio_chunk_opt_t)H5P_peek_unsigned(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME); if(chunk_opt_mode == H5FD_MPIO_CHUNK_ONE_IO) - io_option = H5D_ONE_LINK_CHUNK_IO;/*no opt*/ + io_option = H5D_ONE_LINK_CHUNK_IO; /*no opt*/ else if(chunk_opt_mode == H5FD_MPIO_CHUNK_MULTI_IO) - io_option = H5D_MULTI_CHUNK_IO;/*no opt */ + io_option = H5D_MULTI_CHUNK_IO; /*no opt */ else { - if(H5D_mpio_get_sum_chunk(io_info,fm,&sum_chunk)<0) + unsigned one_link_chunk_io_threshold; /* Threshhold to use single collective I/O for all chunks */ + int mpi_size; /* Number of processes in MPI job */ + + if(H5D_mpio_get_sum_chunk(io_info, fm, &sum_chunk) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to obtain the total chunk number of all processes"); - if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file))<0) - HGOTO_ERROR (H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size"); + if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file)) < 0) + HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size") - if(NULL == (plist = H5I_object(io_info->dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") - - one_link_chunk_io_threshold =H5P_peek_unsigned(plist,H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME); + one_link_chunk_io_threshold = H5P_peek_unsigned(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME); - /* step 1: choose an IO option */ - /* If the average number of chunk per process is greater than a threshold, we will do one link chunked IO. */ - if((unsigned)sum_chunk/mpi_size >= one_link_chunk_io_threshold) + /* step 1: choose an IO option */ + /* If the average number of chunk per process is greater than a threshold, we will do one link chunked IO. */ + if((unsigned)sum_chunk / mpi_size >= one_link_chunk_io_threshold) io_option = H5D_ONE_LINK_CHUNK_IO_MORE_OPT; #ifdef H5_HAVE_INSTRUMENTED_LIBRARY - else - temp_not_link_io = TRUE; + else + temp_not_link_io = TRUE; +#endif + } /* end else */ + +#ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS + if(io_option == H5D_ONE_LINK_CHUNK_IO) + io_option = H5D_MULTI_CHUNK_IO; /* We can not do this with one chunk IO. */ + if(io_option == H5D_ONE_LINK_CHUNK_IO_MORE_OPT) + io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; #endif - } #ifdef H5_HAVE_INSTRUMENTED_LIBRARY +{ + htri_t check_prop; + int new_value; + /*** Test collective chunk user-input optimization APIs. ***/ - check_prop = H5Pexist(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_LINK_HARD_NAME); + check_prop = H5Pexist(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME); if(check_prop > 0) { if(io_option == H5D_ONE_LINK_CHUNK_IO) { - new_value = 0; - if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_LINK_HARD_NAME,&new_value)<0) - HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to get property value"); - } - } - check_prop = H5Pexist(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME); + new_value = 0; + if(H5Pset(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME, &new_value) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + } /* end if */ + check_prop = H5Pexist(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME); if(check_prop > 0) { - if(io_option == H5D_MULTI_CHUNK_IO) { - new_value = 0; - if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME,&new_value)<0) - HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to get property value"); - } - } - check_prop = H5Pexist(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME); + if(io_option == H5D_MULTI_CHUNK_IO) { + new_value = 0; + if(H5Pset(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME, &new_value) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + } /* end if */ + check_prop = H5Pexist(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME); if(check_prop > 0) { - if(io_option == H5D_ONE_LINK_CHUNK_IO_MORE_OPT) { - new_value = 0; - if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME,&new_value)<0) - HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to get property value"); - } - } - check_prop = H5Pexist(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME); + if(io_option == H5D_ONE_LINK_CHUNK_IO_MORE_OPT) { + new_value = 0; + if(H5Pset(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME, &new_value) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + } /* end if */ + check_prop = H5Pexist(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME); if(check_prop > 0) { - if(temp_not_link_io){ - new_value = 0; - if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME,&new_value)<0) - HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to get property value"); - } - } -#endif - -#ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS - if(io_option == H5D_ONE_LINK_CHUNK_IO ) - io_option = H5D_MULTI_CHUNK_IO ;/* We can not do this with one chunk IO. */ - if(io_option == H5D_ONE_LINK_CHUNK_IO_MORE_OPT) - io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; + if(temp_not_link_io) { + new_value = 0; + if(H5Pset(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME, &new_value) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + } /* end if */ +} #endif /* step 2: Go ahead to do IO.*/ +#ifdef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS if(io_option == H5D_ONE_LINK_CHUNK_IO || io_option == H5D_ONE_LINK_CHUNK_IO_MORE_OPT) { - if(H5D_link_chunk_collective_io(io_info,fm,buf,do_write,sum_chunk)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish linked chunk MPI-IO"); - } - else if(io_option == H5D_MULTI_CHUNK_IO) { - if(H5D_multi_chunk_collective_io_no_opt(io_info,fm,buf,do_write)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish multiple chunk MPI-IO"); - } + if(H5D_link_chunk_collective_io(io_info, type_info, fm, sum_chunk) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish linked chunk MPI-IO") + } /* end if */ + else +#endif /* H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS */ + if(io_option == H5D_MULTI_CHUNK_IO) { + if(H5D_multi_chunk_collective_io_no_opt(io_info, type_info, fm, dx_plist) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish multiple chunk MPI-IO") + } /* end if */ else { /*multiple chunk IOs with opt */ - if(H5D_multi_chunk_collective_io(io_info,fm,buf,do_write)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish multiple chunk MPI-IO"); - } + if(H5D_multi_chunk_collective_io(io_info, type_info, fm, dx_plist) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish optimized multiple chunk MPI-IO") + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -791,459 +707,583 @@ done: /*------------------------------------------------------------------------- - * Function: H5D_link_chunk_collective_io + * Function: H5D_chunk_collective_read * - * Purpose: Routine for one collective IO with one MPI derived datatype to link with all chunks + * Purpose: Reads directly from chunks in file into application memory + * using collective I/O. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, March 4, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D_chunk_collective_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t UNUSED nelmts, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space, + H5D_chunk_map_t *fm) +{ + herr_t ret_value = SUCCEED; /* Return value */ - 1. Sort the chunk address and chunk info - 2. Build up MPI derived datatype for each chunk - 3. Build up the final MPI derived datatype - 4. Use common collective IO routine to do MPI-IO + FUNC_ENTER_NOAPI(H5D_chunk_collective_read, FAIL) + /* Call generic selection operation */ + if(H5D_chunk_collective_io(io_info, type_info, fm) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_chunk_collective_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_collective_write * - * Return: Non-negative on success/Negative on failure + * Purpose: Write directly to chunks in file from application memory + * using collective I/O. * - * Programmer: + * Return: Non-negative on success/Negative on failure * - * Modifications: + * Programmer: Quincey Koziol + * Tuesday, March 4, 2008 * *------------------------------------------------------------------------- */ +herr_t +H5D_chunk_collective_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t UNUSED nelmts, const H5S_t UNUSED *file_space, const H5S_t UNUSED *mem_space, + H5D_chunk_map_t *fm) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5D_chunk_collective_write, FAIL) + + /* Call generic selection operation */ + if(H5D_chunk_collective_io(io_info, type_info, fm) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_chunk_collective_write() */ +#ifdef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS + +/*------------------------------------------------------------------------- + * Function: H5D_link_chunk_collective_io + * + * Purpose: Routine for one collective IO with one MPI derived datatype to link with all chunks + * + * 1. Sort the chunk address and chunk info + * 2. Build up MPI derived datatype for each chunk + * 3. Build up the final MPI derived datatype + * 4. Use common collective IO routine to do MPI-IO + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 + * + *------------------------------------------------------------------------- + */ static herr_t -H5D_link_chunk_collective_io(H5D_io_info_t *io_info,H5D_chunk_map_t *fm,const void *buf, hbool_t do_write,int sum_chunk) +H5D_link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + H5D_chunk_map_t *fm, int sum_chunk) { - size_t src_type_size; /*size of source type */ - size_t dst_type_size; /*size of destination type*/ - hsize_t mpi_buf_extra_offset; - hsize_t mpi_file_extra_offset; - size_t mpi_buf_count; - size_t mpi_file_count; - hbool_t mbt_is_derived=0, /* Whether the buffer (memory) type is derived and needs to be free'd */ - mft_is_derived=0; /* Whether the file type is derived and needs to be free'd */ - - int mpi_size,mpi_code; /* MPI return code */ - - int i,num_chunk=0,total_chunks; - size_t ori_num_chunk; - hsize_t ori_total_chunks; - haddr_t chunk_base_addr; - haddr_t* total_chunk_addr_array=NULL; - MPI_Datatype *chunk_mtype=NULL; - MPI_Datatype *chunk_ftype=NULL; - MPI_Datatype chunk_final_mtype; - MPI_Datatype chunk_final_ftype; - MPI_Aint *chunk_disp_array=NULL; - MPI_Aint *chunk_mem_disp_array=NULL; - int *blocklen=NULL; - int blocklen_value; - int actual_bsearch_coll_chunk_threshold; - int bsearch_coll_chunk_threshold; - int many_chunk_opt = 0; - - H5D_common_coll_info_t coll_info; - H5D_chunk_addr_info_t* chunk_addr_info_array=NULL; - - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NOINIT(H5D_link_chunk_collective_io) - ori_total_chunks = fm->total_chunks; - H5_ASSIGN_OVERFLOW(total_chunks,ori_total_chunks,hsize_t,int); - - /* Handle with a special case when only one chunk is covered by all processes */ - if(total_chunks == 1){ - H5SL_node_t *chunk_node; - H5D_chunk_info_t *chunk_info; - H5D_storage_t store; + H5D_chunk_addr_info_t *chunk_addr_info_array = NULL; + hbool_t mbt_is_derived = FALSE; + hbool_t mft_is_derived = FALSE; + MPI_Datatype chunk_final_mtype; /* Final memory MPI datatype for all chunks with seletion */ + MPI_Datatype chunk_final_ftype; /* Final file MPI datatype for all chunks with seletion */ + H5D_storage_t ctg_store; /* Storage info for "fake" contiguous dataset */ + size_t total_chunks; + haddr_t *total_chunk_addr_array = NULL; + MPI_Datatype *chunk_mtype = NULL; + MPI_Datatype *chunk_ftype = NULL; + MPI_Aint *chunk_disp_array = NULL; + MPI_Aint *chunk_mem_disp_array = NULL; + int *blocklen = NULL; + int mpi_code; /* MPI return code */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT(H5D_link_chunk_collective_io) + + /* Get the sum # of chunks, if not already available */ + if(sum_chunk < 0) { + if(H5D_mpio_get_sum_chunk(io_info, fm, &sum_chunk) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to obtain the total chunk number of all processes"); + } /* end if */ + + /* Retrieve total # of chunks in dataset */ + H5_ASSIGN_OVERFLOW(total_chunks, fm->total_chunks, hsize_t, size_t); + + /* Handle special case when dataspace dimensions only allow one chunk in + * the dataset. [This sometimes is used by developers who want the + * equivalent of compressed contiguous datasets - QAK] + */ + if(total_chunks == 1) { + H5D_storage_t chk_store; /* Temporary storage info for chunk address lookup */ + hsize_t coords[H5O_LAYOUT_NDIMS]; /* Coordinates of chunk in file dataset's dataspace */ + H5SL_node_t *chunk_node; /* Pointer to chunk node for selection */ + H5S_t *fspace; /* Dataspace describing chunk & selection in it */ + H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */ + + /* Initialize the chunk coordinates */ + /* (must be all zero, since there's only one chunk) */ + HDmemset(coords, 0, sizeof(coords)); + + /* Look up address of chunk */ + io_info->store = &chk_store; + chk_store.chunk.offset = coords; + chk_store.chunk.index = 0; + if(HADDR_UNDEF == (ctg_store.contig.dset_addr = H5D_istore_get_addr(io_info, NULL))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skipped list") + /* Check for this process having selection in this chunk */ chunk_node = H5SL_first(fm->sel_chunks); if(chunk_node == NULL) { - if(H5D_istore_chunkmap(io_info, &chunk_base_addr, fm->down_chunks) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address"); - if(H5D_inter_collective_io(io_info,NULL,NULL,chunk_base_addr,buf,do_write)<0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - } + /* Set the dataspace info for I/O to NULL, this process doesn't have any I/O to perform */ + fspace = mspace = NULL; + } /* end if */ else { - if(NULL ==(chunk_info = H5SL_item(chunk_node))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); - io_info->store = &store; - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; + H5D_chunk_info_t *chunk_info; + + /* Get the chunk info, for the selection in the chunk */ + if(NULL == (chunk_info = H5SL_item(chunk_node))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skipped list") + + /* Set the dataspace info for I/O */ + fspace = chunk_info->fspace; + mspace = chunk_info->mspace; + } /* end else */ + + /* Set up the base storage address for this chunk */ + io_info->store = &ctg_store; - if(HADDR_UNDEF==(chunk_base_addr = H5D_istore_get_addr(io_info,NULL))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); - #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"before inter_collective_io for total chunk = 1 \n"); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"before inter_collective_io for total chunk = 1 \n"); #endif - if(H5D_inter_collective_io(io_info,chunk_info->fspace,chunk_info->mspace,chunk_base_addr,buf,do_write)<0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - } - goto done; - } - /* Allocate chunking information */ - ori_num_chunk = H5SL_count(fm->sel_chunks); - H5_ASSIGN_OVERFLOW(num_chunk,ori_num_chunk,size_t,int); + /* Perform I/O */ + if(H5D_inter_collective_io(io_info, type_info, fspace, mspace) < 0) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO") + } /* end if */ + else { + size_t mpi_buf_count; /* Number of MPI types */ + size_t num_chunk; /* Number of chunks for this process */ + size_t u; /* Local index variable */ + + /* Get the number of chunks with a selection */ + num_chunk = H5SL_count(fm->sel_chunks); + H5_CHECK_OVERFLOW(num_chunk, size_t, int); #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"total_chunks = %d\n",(int)total_chunks); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"total_chunks = %Zu, num_chunk = %Zu\n", total_chunks, num_chunk); #endif - - if(num_chunk == 0) - total_chunk_addr_array = H5MM_malloc(sizeof(haddr_t)*total_chunks); - else - { - chunk_addr_info_array= H5MM_malloc(num_chunk*sizeof(H5D_chunk_addr_info_t)); - chunk_mtype = H5MM_malloc(num_chunk*sizeof(MPI_Datatype)); - chunk_ftype = H5MM_malloc(num_chunk*sizeof(MPI_Datatype)); - chunk_disp_array = H5MM_malloc(num_chunk*sizeof(MPI_Aint)); - chunk_mem_disp_array = H5MM_calloc(num_chunk*sizeof(MPI_Aint)); - blocklen = H5MM_malloc(num_chunk*sizeof(int)); - } - - /* Obtain information to do collective IO, - in order to do collective IO, no datatype conversion should happen. */ - if((src_type_size = H5T_get_size(io_info->dset->shared->type))==0) - HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "datatype size invalid"); - dst_type_size = src_type_size; - - bsearch_coll_chunk_threshold = H5D_ALL_CHUNK_ADDR_THRES_COL; - - if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file))<0) - HGOTO_ERROR (H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size"); - - /* Calculate the actual threshold to obtain all chunk addresses collectively - The bigger this number is, the more possible the use of obtaining chunk address collectively. */ - /* For non-optimization one-link IO, - actual bsearch threshold is always 0, - we would always want to obtain the chunk addresses individually - for each process. */ - actual_bsearch_coll_chunk_threshold = sum_chunk*100/(total_chunks*mpi_size); - - if((actual_bsearch_coll_chunk_threshold > bsearch_coll_chunk_threshold) - &&(sum_chunk/mpi_size >= H5D_ALL_CHUNK_ADDR_THRES_COL_NUM)) - many_chunk_opt = H5D_OBTAIN_ALL_CHUNK_ADDR_COL; + + /* Set up MPI datatype for chunks selected */ + if(num_chunk) { + hsize_t mpi_mem_extra_offset; /* Extra offset for memory MPI datatype */ + hsize_t mpi_file_extra_offset; /* Extra offset for file MPI datatype */ + size_t mpi_mem_count; /* Memory MPI datatype count */ + size_t mpi_file_count; /* File MPI datatype count */ + hbool_t locl_mbt_is_derived = FALSE, /* Whether the buffer (memory) type is derived and needs to be free'd */ + local_mft_is_derived = FALSE; /* Whether the file type is derived and needs to be free'd */ + int blocklen_value; /* Placeholder for array fill */ + + /* Allocate chunking information */ + chunk_addr_info_array= H5MM_malloc(num_chunk * sizeof(H5D_chunk_addr_info_t)); + chunk_mtype = H5MM_malloc(num_chunk * sizeof(MPI_Datatype)); + chunk_ftype = H5MM_malloc(num_chunk * sizeof(MPI_Datatype)); + chunk_disp_array = H5MM_malloc(num_chunk * sizeof(MPI_Aint)); + chunk_mem_disp_array = H5MM_calloc(num_chunk * sizeof(MPI_Aint)); + blocklen = H5MM_malloc(num_chunk * sizeof(int)); #ifdef H5D_DEBUG - if(H5DEBUG(D)) +if(H5DEBUG(D)) HDfprintf(H5DEBUG(D),"before sorting the chunk address \n"); #endif - - /* Sort the chunk address - when chunk optimization selection is either H5D_OBTAIN_*/ - - if(num_chunk == 0){ /* special case: this process doesn't select anything */ - if(H5D_istore_chunkmap(io_info, total_chunk_addr_array, fm->down_chunks)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address"); - chunk_base_addr = total_chunk_addr_array[0]; - } - - else { - if(H5D_sort_chunk(io_info,fm,chunk_addr_info_array,many_chunk_opt)<0) - HGOTO_ERROR (H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to sort chunk address"); - chunk_base_addr = chunk_addr_info_array[0].chunk_addr; - } + /* Sort the chunk address */ + if(H5D_sort_chunk(io_info, fm, chunk_addr_info_array, sum_chunk) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to sort chunk address") + ctg_store.contig.dset_addr = chunk_addr_info_array[0].chunk_addr; #ifdef H5D_DEBUG - if(H5DEBUG(D)) +if(H5DEBUG(D)) HDfprintf(H5DEBUG(D),"after sorting the chunk address \n"); #endif - - /* Obtain MPI derived datatype from all individual chunks */ - for ( i = 0; i < num_chunk; i++) { - /* Disk MPI derived datatype */ - if(H5S_mpio_space_type(chunk_addr_info_array[i].chunk_info.fspace,src_type_size,&chunk_ftype[i], - &mpi_file_count,&mpi_file_extra_offset,&mft_is_derived)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't create MPI file type"); - - /* Buffer MPI derived datatype */ - if(H5S_mpio_space_type(chunk_addr_info_array[i].chunk_info.mspace,dst_type_size,&chunk_mtype[i], - &mpi_buf_count,&mpi_buf_extra_offset,&mbt_is_derived)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't create MPI buf type"); - - /* Chunk address relative to the first chunk */ - chunk_addr_info_array[i].chunk_addr -= chunk_base_addr; - H5_ASSIGN_OVERFLOW(chunk_disp_array[i],chunk_addr_info_array[i].chunk_addr,haddr_t,MPI_Aint); - } - - blocklen_value = 1; - if(num_chunk){ - - /* initialize the buffer with the constant value 1; this algo. is very fast. */ - H5V_array_fill(blocklen,&blocklen_value,sizeof(int),(size_t)num_chunk); - - /* Create final MPI derived datatype */ - if(MPI_SUCCESS != (mpi_code = MPI_Type_struct(num_chunk,blocklen,chunk_disp_array,chunk_ftype,&chunk_final_ftype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_struct failed", mpi_code); - if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_ftype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code); - - if(MPI_SUCCESS != (mpi_code = MPI_Type_struct(num_chunk,blocklen,chunk_mem_disp_array,chunk_mtype,&chunk_final_mtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_struct failed", mpi_code); - if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_mtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code); - - for ( i = 0; i< num_chunk;i++){ - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( chunk_mtype+i ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( chunk_ftype+i ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - } - - /* buffer, file derived datatypes should be true */ - coll_info.mbt_is_derived = 1; - coll_info.mft_is_derived = 1; - coll_info.mpi_buf_count = 1; - coll_info.chunk_addr = chunk_base_addr; - - } - - else {/* no selection at all for this process */ - chunk_final_ftype = MPI_BYTE; - chunk_final_mtype = MPI_BYTE; - - /* buffer, file derived datatypes should be true */ - coll_info.mbt_is_derived = 0; - coll_info.mft_is_derived = 0; - coll_info.mpi_buf_count = 0; - coll_info.chunk_addr = chunk_base_addr; - } + + /* Obtain MPI derived datatype from all individual chunks */ + for(u = 0; u < num_chunk; u++) { + /* Disk MPI derived datatype */ + if(H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.fspace, + type_info->src_type_size, &chunk_ftype[u], &mpi_file_count, + &mpi_file_extra_offset, &local_mft_is_derived) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI file type") + + /* Buffer MPI derived datatype */ + if(H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.mspace, + type_info->dst_type_size, &chunk_mtype[u], &mpi_mem_count, + &mpi_mem_extra_offset, &locl_mbt_is_derived) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI buf type") + + /* Chunk address relative to the first chunk */ + chunk_addr_info_array[u].chunk_addr -= ctg_store.contig.dset_addr; + H5_ASSIGN_OVERFLOW(chunk_disp_array[u], chunk_addr_info_array[u].chunk_addr, haddr_t, MPI_Aint); + } /* end for */ + + /* Initialize the buffer with the constant value 1 */ + blocklen_value = 1; + H5V_array_fill(blocklen, &blocklen_value, sizeof(int), num_chunk); + + /* Create final MPI derived datatype for the file */ + if(MPI_SUCCESS != (mpi_code = MPI_Type_struct((int)num_chunk, blocklen, chunk_disp_array, chunk_ftype, &chunk_final_ftype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_struct failed", mpi_code) + if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_ftype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code) + + /* Create final MPI derived datatype for memory */ + if(MPI_SUCCESS != (mpi_code = MPI_Type_struct(num_chunk, blocklen, chunk_mem_disp_array, chunk_mtype, &chunk_final_mtype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_struct failed", mpi_code) + if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_mtype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code) + + /* Free the file & memory MPI datatypes for each chunk */ + for(u = 0; u < num_chunk; u++) { + if(MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_mtype + u))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + + if(MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_ftype + u))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + } /* end for */ + + /* buffer, file derived datatypes should be true */ + mbt_is_derived = TRUE; + mft_is_derived = TRUE; + mpi_buf_count = (size_t)1; + } /* end if */ + else { /* no selection at all for this process */ + /* Allocate chunking information */ + total_chunk_addr_array = H5MM_malloc(sizeof(haddr_t) * total_chunks); + + /* Retrieve chunk address map */ + if(H5D_istore_chunkmap(io_info, total_chunk_addr_array, fm->down_chunks) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address") + + /* Get chunk with lowest address */ + ctg_store.contig.dset_addr = HADDR_MAX; + for(u = 0; u < total_chunks; u++) + if(total_chunk_addr_array[u] < ctg_store.contig.dset_addr) + ctg_store.contig.dset_addr = total_chunk_addr_array[u]; + HDassert(ctg_store.contig.dset_addr != HADDR_MAX); + + /* Set the MPI datatype */ + chunk_final_ftype = MPI_BYTE; + chunk_final_mtype = MPI_BYTE; + + /* buffer, file derived datatypes should be true */ + mpi_buf_count = (size_t)0; + } /* end else */ #ifdef H5D_DEBUG - if(H5DEBUG(D)) +if(H5DEBUG(D)) HDfprintf(H5DEBUG(D),"before coming to final collective IO\n"); #endif - if(H5D_final_collective_io(io_info,&chunk_final_ftype,&chunk_final_mtype,&coll_info,buf,do_write)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish MPI-IO"); + /* Set up the base storage address for this chunk */ + io_info->store = &ctg_store; + + /* Perform final collective I/O operation */ + if(H5D_final_collective_io(io_info, type_info, mpi_buf_count, &chunk_final_ftype, &chunk_final_mtype) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish MPI-IO") + } /* end else */ done: #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"before freeing memory inside H5D_link_collective_io ret_value = %d\n",ret_value); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"before freeing memory inside H5D_link_collective_io ret_value = %d\n", ret_value); #endif - if (fm->total_chunks != 1) { - if(num_chunk == 0) HDfree(total_chunk_addr_array); - else { - HDfree(chunk_addr_info_array); - HDfree(chunk_mtype); - HDfree(chunk_ftype); - HDfree(chunk_disp_array); - HDfree(chunk_mem_disp_array); - HDfree(blocklen); - } - } - FUNC_LEAVE_NOAPI(ret_value) + if(total_chunk_addr_array) + H5MM_xfree(total_chunk_addr_array); + if(chunk_addr_info_array) + H5MM_xfree(chunk_addr_info_array); + if(chunk_mtype) + H5MM_xfree(chunk_mtype); + if(chunk_ftype) + H5MM_xfree(chunk_ftype); + if(chunk_disp_array) + H5MM_xfree(chunk_disp_array); + if(chunk_mem_disp_array) + H5MM_xfree(chunk_mem_disp_array); + if(blocklen) + H5MM_xfree(blocklen); + + /* Free the MPI buf and file types, if they were derived */ + if(mbt_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&chunk_final_mtype))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + if(mft_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&chunk_final_ftype))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_link_chunk_collective_io */ +#endif /* H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS */ /*------------------------------------------------------------------------- * Function: H5D_multi_chunk_collective_io * * Purpose: To do IO per chunk according to IO mode(collective/independent/none) - - 1. Use MPI_gather and MPI_Bcast to obtain IO mode in each chunk(collective/independent/none) - 2. Depending on whether the IO mode is collective or independent or none, - Create either MPI derived datatype for each chunk or just do independent IO - 3. Use common collective IO routine to do MPI-IO * - * Return: Non-negative on success/Negative on failure + * 1. Use MPI_gather and MPI_Bcast to obtain IO mode in each chunk(collective/independent/none) + * 2. Depending on whether the IO mode is collective or independent or none, + * Create either MPI derived datatype for each chunk or just do independent IO + * 3. Use common collective IO routine to do MPI-IO * - * Programmer: + * Return: Non-negative on success/Negative on failure * - * Modifications: + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5D_multi_chunk_collective_io(H5D_io_info_t *io_info,H5D_chunk_map_t *fm,const void *buf, hbool_t do_write) +H5D_multi_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + H5D_chunk_map_t *fm, H5P_genplist_t *dx_plist) { - unsigned i, total_chunk; - hsize_t ori_total_chunk; - uint8_t *chunk_io_option; - - H5SL_node_t *chunk_node; /* Current node in chunk skip list */ - H5D_chunk_info_t *chunk_info=NULL; - haddr_t *chunk_addr; - H5D_storage_t store; /* union of EFL and chunk pointer in file space */ - hbool_t select_chunk; - hbool_t last_io_mode_coll = TRUE; - - void *chunk = NULL; /* Pointer to the data chunk in cache */ - H5D_t *dataset=io_info->dset;/* Local pointer to dataset info */ - H5D_istore_ud1_t udata; /*B-tree pass-through */ - haddr_t caddr; /* Address of the cached chunk */ - size_t accessed_bytes; /*total accessed size in a chunk */ - unsigned idx_hint=0; /* Cache index hint */ - hbool_t dirty = TRUE; /* Flag for cache flushing */ - hbool_t relax=TRUE; /* Whether whole chunk is selected */ - - herr_t ret_value = SUCCEED; + H5D_t *dataset = io_info->dset;/* Local pointer to dataset info */ + H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ + H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ + H5D_io_info_t cpt_io_info; /* Compact I/O info object */ + H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */ + hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ + uint8_t *chunk_io_option = NULL; + haddr_t *chunk_addr = NULL; + H5D_storage_t store; /* union of EFL and chunk pointer in file space */ + H5FD_mpio_xfer_t last_xfer_mode = H5FD_MPIO_COLLECTIVE; /* Last parallel transfer for this request (H5D_XFER_IO_XFER_MODE_NAME) */ + H5FD_mpio_collective_opt_t last_coll_opt_mode = H5FD_MPIO_COLLECTIVE_IO; /* Last parallel transfer with independent IO or collective IO with this mode */ + size_t total_chunk; /* Total # of chunks in dataset */ #ifdef H5Dmpio_DEBUG - int mpi_rank; + int mpi_rank; #endif + size_t u; /* Local index variable */ + herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NOINIT(H5D_multi_chunk_collective_io) + FUNC_ENTER_NOAPI_NOINIT(H5D_multi_chunk_collective_io) #ifdef H5Dmpio_DEBUG - mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file); + mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file); #endif - /* Allocate memories */ - ori_total_chunk = fm->total_chunks; - H5_ASSIGN_OVERFLOW(total_chunk,ori_total_chunk,hsize_t,unsigned); - HDassert(total_chunk!=0); - chunk_io_option = (uint8_t *)H5MM_calloc(total_chunk*sizeof(MPI_BYTE)); - chunk_addr = (haddr_t *)H5MM_calloc(total_chunk*sizeof(haddr_t)); + /* Retrieve total # of chunks in dataset */ + H5_ASSIGN_OVERFLOW(total_chunk, fm->total_chunks, hsize_t, size_t); + HDassert(total_chunk != 0); + + /* Allocate memories */ + chunk_io_option = (uint8_t *)H5MM_calloc(total_chunk); + chunk_addr = (haddr_t *)H5MM_calloc(total_chunk * sizeof(haddr_t)); #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"total_chunk %u\n",total_chunk); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D), "total_chunk %Zu\n", total_chunk); #endif - /* obtain IO option for each chunk */ - if(H5D_obtain_mpio_mode(io_info,fm,chunk_io_option,chunk_addr)<0) - HGOTO_ERROR (H5E_DATASET, H5E_CANTRECV, FAIL, "unable to obtain MPIO mode"); + /* Obtain IO option for each chunk */ + if(H5D_obtain_mpio_mode(io_info, fm, dx_plist, chunk_io_option, chunk_addr) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTRECV, FAIL, "unable to obtain MPIO mode") + + /* Set up contiguous I/O info object */ + HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); + ctg_io_info.store = &ctg_store; + ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + + /* Initialize temporary contiguous storage info */ + ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size; + + /* Set up compact I/O info object */ + HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); + cpt_io_info.store = &cpt_store; + cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + + /* Initialize temporary compact storage info */ + cpt_store.compact.dirty = &cpt_dirty; + + /* Set dataset storage for I/O info */ + io_info->store = &store; + + /* Loop over _all_ the chunks */ + for(u = 0; u < total_chunk; u++) { + H5D_chunk_info_t *chunk_info; /* Chunk info for current chunk */ + H5S_t *fspace; /* Dataspace describing chunk & selection in it */ + H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */ - for(i = 0; i < total_chunk; i++) { #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"mpi_rank = %d, chunk index = %u\n",mpi_rank,i); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"mpi_rank = %d, chunk index = %Zu\n", mpi_rank, u); #endif - select_chunk = fm->select_chunk[i]; - if(select_chunk == 1){/* Have selection elements in this chunk. Find the chunk info. */ - if(NULL ==(chunk_node = H5SL_first(fm->sel_chunks))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk node from skipped list"); - - while(chunk_node){ - if(NULL ==(chunk_info = H5SL_item(chunk_node))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); - if(chunk_info->index == i) { - /* Set dataset storage for I/O info */ - io_info->store=&store; - /* Pass in chunk's coordinates in a union. */ - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; - break; - } - - chunk_node = H5SL_next(chunk_node); - } - } - - if(chunk_io_option[i] == 1){ /*collective IO for this chunk, - note: even there is no selection for this process, - the process still needs to contribute MPI NONE TYPE.*/ + /* Get the chunk info for this chunk, if there are elements selected */ + chunk_info = fm->select_chunk[u]; + + /* Set the storage information for chunks with selections */ + if(chunk_info) { + HDassert(chunk_info->index == u); + + /* Pass in chunk's coordinates in a union. */ + store.chunk.offset = chunk_info->coords; + store.chunk.index = chunk_info->index; + } /* end if */ + + /* Collective IO for this chunk, + * Note: even there is no selection for this process, the process still + * needs to contribute MPI NONE TYPE. + */ + if(chunk_io_option[u] == 1) { #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"inside collective chunk IO mpi_rank = %d, chunk index = %u\n",mpi_rank,i); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"inside collective chunk IO mpi_rank = %d, chunk index = %Zu\n", mpi_rank, u); #endif - if(!last_io_mode_coll) - /* Switch back to collective I/O */ - if(H5D_ioinfo_make_coll(io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to collective I/O") + /* Set the file & memory dataspaces */ + if(chunk_info) { + fspace = chunk_info->fspace; + mspace = chunk_info->mspace; + } /* end if */ + else { + fspace = mspace = NULL; + } /* end else */ + + /* Switch back to collective I/O */ + if(last_xfer_mode != H5FD_MPIO_COLLECTIVE) { + if(H5D_ioinfo_xfer_mode(io_info, dx_plist, H5FD_MPIO_COLLECTIVE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to collective I/O") + last_xfer_mode = H5FD_MPIO_COLLECTIVE; + } /* end if */ + if(last_coll_opt_mode != H5FD_MPIO_COLLECTIVE_IO) { + if(H5D_ioinfo_coll_opt_mode(io_info, dx_plist, H5FD_MPIO_COLLECTIVE_IO) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to collective I/O") + last_coll_opt_mode = H5FD_MPIO_COLLECTIVE_IO; + } /* end if */ - if(select_chunk){ - if(H5D_inter_collective_io(io_info,chunk_info->fspace,chunk_info->mspace, - chunk_addr[i],buf,do_write )<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - - } - else{ - if(H5D_inter_collective_io(io_info,NULL,NULL, - chunk_addr[i],buf,do_write )<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - - } - last_io_mode_coll = TRUE; - - } - else {/*possible independent IO for this chunk*/ + /* Initialize temporary contiguous storage address */ + ctg_store.contig.dset_addr = chunk_addr[u]; + + /* Perform the I/O */ + if(H5D_inter_collective_io(&ctg_io_info, type_info, fspace, mspace) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO") + } /* end if */ + else { /* possible independent IO for this chunk */ #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"inside independent IO mpi_rank = %d, chunk index = %u\n",mpi_rank,i); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"inside independent IO mpi_rank = %d, chunk index = %Zu\n", mpi_rank, u); #endif - HDassert(chunk_io_option[i] == 0); + HDassert(chunk_io_option[u] == 0); #if !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - if(!select_chunk) - continue; /* this process has nothing to do with this chunk, continue! */ - if(last_io_mode_coll) + /* Check if this process has somethign to do with this chunk */ + if(chunk_info) { + H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */ + H5D_istore_ud1_t udata; /* B-tree pass-through */ + void *chunk; /* Pointer to the data chunk in cache */ + size_t accessed_bytes; /* Total accessed size in a chunk */ + unsigned idx_hint = 0; /* Cache index hint */ + haddr_t caddr; /* Address of the cached chunk */ + /* Switch to independent I/O */ - if(H5D_ioinfo_make_ind(io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to independent I/O") - - /* Load the chunk into cache. But if the whole chunk is written, - * simply allocate space instead of load the chunk. */ - if(HADDR_UNDEF==(caddr = H5D_istore_get_addr(io_info, &udata))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); - - if(H5D_istore_if_load(io_info, caddr)) { - accessed_bytes = chunk_info->chunk_points * H5T_get_size(dataset->shared->type); - if((do_write && (accessed_bytes != dataset->shared->layout.u.chunk.size)) || !do_write) - relax=FALSE; - - if(NULL == (chunk = H5D_istore_lock(io_info, &udata, relax, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") - } else - chunk = NULL; - - if(do_write) { - if((io_info->ops.write)(io_info, - chunk_info->chunk_points,H5T_get_size(io_info->dset->shared->type), - chunk_info->fspace,chunk_info->mspace,caddr,chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed") - } - else { - if((io_info->ops.read)(io_info, - chunk_info->chunk_points,H5T_get_size(io_info->dset->shared->type), - chunk_info->fspace,chunk_info->mspace,caddr,chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") - } + if(last_xfer_mode != H5FD_MPIO_INDEPENDENT) { + if(H5D_ioinfo_xfer_mode(io_info, dx_plist, H5FD_MPIO_INDEPENDENT) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to independent I/O") + last_xfer_mode = H5FD_MPIO_INDEPENDENT; + } /* end if */ - /* Release the cache lock on the chunk. */ - if(chunk) { - if(!do_write) - dirty = FALSE; + /* Load the chunk into cache. But if the whole chunk is written, + * simply allocate space instead of load the chunk. + */ + if(HADDR_UNDEF == (caddr = H5D_istore_get_addr(io_info, &udata))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skipped list") - if(H5D_istore_unlock(io_info, dirty, idx_hint, chunk, accessed_bytes) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") - } /* end if */ -#else - if(!last_io_mode_coll) - /* using independent I/O with file setview.*/ - if(H5D_ioinfo_make_coll_opt(io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to collective I/O") - if(select_chunk){ - if(H5D_inter_collective_io(io_info,chunk_info->fspace,chunk_info->mspace, - chunk_addr[i],buf,do_write )<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - } + /* Load the chunk into cache and lock it. */ + if(H5D_chunk_cacheable(io_info, caddr)) { + hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */ + + /* Compute # of bytes accessed in chunk */ + accessed_bytes = chunk_info->chunk_points * type_info->src_type_size; + + /* Determine if we will access all the data in the chunk */ + if(((io_info->op_type == H5D_IO_OP_WRITE) && (accessed_bytes != ctg_store.contig.dset_size)) + || (io_info->op_type != H5D_IO_OP_WRITE)) + entire_chunk = FALSE; + + /* Lock the chunk into the cache */ + if(NULL == (chunk = H5D_istore_lock(io_info, &udata, entire_chunk, &idx_hint))) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") + + /* Set up the storage buffer information for this chunk */ + cpt_store.compact.buf = chunk; + + /* Point I/O info at contiguous I/O info for this chunk */ + chk_io_info = &cpt_io_info; + } /* end if */ + else { + /* Set up the storage address information for this chunk */ + ctg_store.contig.dset_addr = caddr; + + /* No chunk cached */ + chunk = NULL; + + /* Point I/O info at temporary I/O info for this chunk */ + chk_io_info = &ctg_io_info; + } /* end else */ + + if(io_info->op_type == H5D_IO_OP_WRITE) { + if((io_info->io_ops.single_write)(chk_io_info, type_info, + (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed") + } /* end if */ + else { + if((io_info->io_ops.single_read)(chk_io_info, type_info, + (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") + } /* end else */ + + /* Release the cache lock on the chunk. */ + if(chunk && H5D_istore_unlock(io_info, (io_info->op_type == H5D_IO_OP_WRITE), idx_hint, chunk, accessed_bytes) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") + } /* end if */ +#else /* !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) */ + /* Set the file & memory dataspaces */ + if(chunk_info) { + fspace = chunk_info->fspace; + mspace = chunk_info->mspace; + } /* end if */ else { - if(H5D_inter_collective_io(io_info,NULL,NULL, - chunk_addr[i],buf,do_write )<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - } + fspace = mspace = NULL; + } /* end else */ + + /* Using independent I/O with file setview.*/ + if(last_coll_opt_mode != H5FD_MPIO_INDIVIDUAL_IO) { + if(H5D_ioinfo_coll_opt_mode(io_info, dx_plist, H5FD_MPIO_INDIVIDUAL_IO) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to individual I/O") + last_coll_opt_mode = H5FD_MPIO_INDIVIDUAL_IO; + } /* end if */ + /* Initialize temporary contiguous storage address */ + ctg_store.contig.dset_addr = chunk_addr[u]; + + /* Perform the I/O */ + if(H5D_inter_collective_io(&ctg_io_info, type_info, fspace, mspace) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO") #ifdef H5D_DEBUG if(H5DEBUG(D)) HDfprintf(H5DEBUG(D),"after inter collective IO\n"); #endif -#endif - last_io_mode_coll = FALSE; - } - } - if(!last_io_mode_coll) - /* Switch back to collective I/O */ - if(H5D_ioinfo_make_coll(io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to collective I/O") +#endif /* !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) */ + } /* end else */ + } /* end for */ + done: - HDfree(chunk_io_option); - HDfree(chunk_addr); + if(chunk_io_option) + H5MM_xfree(chunk_io_option); + if(chunk_addr) + H5MM_xfree(chunk_addr); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_multi_chunk_collective_io */ @@ -1257,90 +1297,105 @@ done: * non-contiguous(or with holes) storage efficiently. * Under this case, the one independent IO call may consist of * many small disk IOs. So we may use independent IO with derived datatype - to replace the independent IO when we find this chunk is not good to - do collective IO. However, according to our performance study, - this approach may not overcome the overhead caused by MPI gather/scatter. - So we decide to leave the original collective IO per chunk approach as - an option for users. NO MPI gather/scatter calls are used. - HDF5 will try to collective IO if possible. - If users choose to use - H5Pset_dxpl_mpio_chunk_opt(dxpl_id,H5FD_MPIO_OPT_MULTI_IO), - this function will be called. - The HDF5 library won't do any IO management but leave it to MPI-IO to figure - out. + * to replace the independent IO when we find this chunk is not good to + * do collective IO. However, according to our performance study, + * this approach may not overcome the overhead caused by MPI gather/scatter. + * So we decide to leave the original collective IO per chunk approach as + * an option for users. NO MPI gather/scatter calls are used. + * HDF5 will try to collective IO if possible. + * If users choose to use + * H5Pset_dxpl_mpio_chunk_opt(dxpl_id,H5FD_MPIO_OPT_MULTI_IO), + * this function will be called. + * The HDF5 library won't do any IO management but leave it to MPI-IO to figure + * out. * * Return: Non-negative on success/Negative on failure * - * Programmer: - * - * Modifications: + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5D_multi_chunk_collective_io_no_opt(H5D_io_info_t *io_info,H5D_chunk_map_t *fm,const void *buf, hbool_t do_write) +H5D_multi_chunk_collective_io_no_opt(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, H5D_chunk_map_t *fm, H5P_genplist_t *dx_plist) { - int count_chunk,min_num_chunk; - haddr_t chunk_addr; - H5SL_node_t *chunk_node; /* Current node in chunk skip list */ - H5D_storage_t store; /* union of EFL and chunk pointer in file space */ - H5D_chunk_info_t *chunk_info; /* chunk information */ - hbool_t make_ind, make_coll; /* Flags to indicate that the MPI mode should change */ - - void *chunk = NULL; /* Pointer to the data chunk in cache */ - H5D_t *dataset=io_info->dset;/* Local pointer to dataset info */ - H5D_istore_ud1_t udata; /*B-tree pass-through */ - size_t accessed_bytes; /*total accessed size in a chunk */ - unsigned idx_hint=0; /* Cache index hint */ - hbool_t dirty = TRUE; /* Flag for cache flushing */ - hbool_t relax=TRUE; /* Whether whole chunk is selected */ - herr_t ret_value = SUCCEED; - -#ifdef H5Dmpio_DEBUG - int mpi_rank; -#endif + H5D_t *dataset = io_info->dset;/* Local pointer to dataset info */ + H5SL_node_t *chunk_node; /* Current node in chunk skip list */ + H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ + H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ + H5D_io_info_t cpt_io_info; /* Compact I/O info object */ + H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */ + hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ + int min_chunk = -1; /* Minimum # of chunks all processes will operate on */ + int count_chunk; /* How many chunks have we operated on? */ + H5D_storage_t store; /* union of EFL and chunk pointer in file space */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT(H5D_multi_chunk_collective_io_no_opt) - FUNC_ENTER_NOAPI_NOINIT(H5D_multi_chunk_collective_io_no_opt) #ifdef H5D_DEBUG - if(H5DEBUG(D)){ +if(H5DEBUG(D)) { + int mpi_rank; + mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file); - HDfprintf(H5DEBUG(D),"coming to multi_chunk_collective_io_no_opt\n"); - } + HDfprintf(H5DEBUG(D), "coming to multi_chunk_collective_io_no_opt\n"); +} #endif - if(H5D_mpio_get_min_chunk(io_info,fm,&min_num_chunk)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get minimum number of chunk"); - count_chunk = 0; - - /* Get first node in chunk skip list */ - chunk_node=H5SL_first(fm->sel_chunks); - - /* Iterate through chunks to be operated on */ - while(chunk_node) { - H5D_chunk_info_t *chunk_info; /* chunk information */ - hbool_t make_ind, make_coll; /* Flags to indicate that the MPI mode should change */ - - /* Get the actual chunk information from the skip list node */ - chunk_info=H5SL_item(chunk_node); - - /* Set dataset storage for I/O info */ - io_info->store=&store; - - /* Pass in chunk's coordinates in a union. */ - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; - - /* Reset flags for changing parallel I/O mode */ - make_ind = make_coll = FALSE; - - count_chunk++; - /* If the number of chunk is greater than minimum number of chunk, - Do independent read */ - if(count_chunk > min_num_chunk) { - /* Switch to independent I/O (permanently) */ - make_ind = TRUE; - } + /* Set up contiguous I/O info object */ + HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); + ctg_io_info.store = &ctg_store; + ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + + /* Initialize temporary contiguous storage info */ + ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size; + + /* Set up compact I/O info object */ + HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); + cpt_io_info.store = &cpt_store; + cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + + /* Initialize temporary compact storage info */ + cpt_store.compact.dirty = &cpt_dirty; + + /* Set dataset storage for I/O info */ + io_info->store = &store; + + /* Get the min. # of chunks */ + if(H5D_mpio_get_min_chunk(io_info, fm, &min_chunk) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get minimum number of chunk") + HDassert(min_chunk >= 0); + + /* Get first node in chunk skip list */ + chunk_node = H5SL_first(fm->sel_chunks); + count_chunk = 0; + + /* Iterate through chunks to be operated on */ + while(chunk_node) { + H5D_chunk_info_t *chunk_info; /* chunk information */ + haddr_t chunk_addr; /* Address of chunk in file */ + H5D_istore_ud1_t udata; /* B-tree pass-through */ + hbool_t make_ind, make_coll; /* Flags to indicate that the MPI mode should change */ + /* Get the actual chunk information from the skip list node */ + chunk_info = H5SL_item(chunk_node); + + /* Pass in chunk's coordinates in a union. */ + store.chunk.offset = chunk_info->coords; + store.chunk.index = chunk_info->index; + + /* Reset flags for changing parallel I/O mode */ + make_ind = make_coll = FALSE; + + count_chunk++; + + /* If the number of chunk is greater than minimum number of chunk, + * Do independent read. + */ + if(count_chunk > min_chunk) + /* Switch to independent I/O (permanently) */ + make_ind = TRUE; #ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS /* This case needs to be improved to check if the selected space is regular. If all selections are regular, collective IO can still be done. @@ -1349,67 +1404,92 @@ H5D_multi_chunk_collective_io_no_opt(H5D_io_info_t *io_info,H5D_chunk_map_t *fm, we turn off this optimization but leave the following code for future optimization. Otherwise, the following else {} doesn't make sense. KY 2006/8/4/ */ - else { - /* Switch to independent I/O (temporarily) */ - make_ind = TRUE; - make_coll = TRUE; - } /* end else */ + else { + /* Switch to independent I/O (temporarily) */ + make_ind = TRUE; + make_coll = TRUE; + } /* end else */ #endif /* H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS */ + /* Retrieve the chunk's address */ + if(HADDR_UNDEF == (chunk_addr = H5D_istore_get_addr(io_info, &udata))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list") + + /* Independent I/O */ + if(make_ind) { + void *chunk; /* Pointer to the data chunk in cache */ + H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */ + size_t accessed_bytes = 0; /* Total accessed size in a chunk */ + unsigned idx_hint = 0; /* Cache index hint */ + /* Switch to independent I/O */ - if(make_ind) - if(H5D_ioinfo_make_ind(io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to independent I/O") + if(H5D_ioinfo_xfer_mode(io_info, dx_plist, H5FD_MPIO_INDEPENDENT) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to independent I/O") - if(HADDR_UNDEF==(chunk_addr = H5D_istore_get_addr(io_info, &udata))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); + /* Load the chunk into cache and lock it. */ + if(H5D_chunk_cacheable(io_info, chunk_addr)) { + hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */ - if(make_ind) {/*independent I/O */ - /* Load the chunk into cache. But if the whole chunk is written, - * simply allocate space instead of load the chunk. */ - if(H5D_istore_if_load(io_info, chunk_addr)) { - accessed_bytes = chunk_info->chunk_points * H5T_get_size(dataset->shared->type); - if((do_write && (accessed_bytes != dataset->shared->layout.u.chunk.size)) || !do_write) - relax=FALSE; - - if(NULL == (chunk = H5D_istore_lock(io_info, &udata, relax, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") - } else - chunk = NULL; - - if(do_write) { - if((io_info->ops.write)(io_info, - chunk_info->chunk_points,H5T_get_size(io_info->dset->shared->type), - chunk_info->fspace,chunk_info->mspace, chunk_addr, chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed") - } else { - if((io_info->ops.read)(io_info, - chunk_info->chunk_points,H5T_get_size(io_info->dset->shared->type), - chunk_info->fspace,chunk_info->mspace, chunk_addr, chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") - } + /* Compute # of bytes accessed in chunk */ + accessed_bytes = chunk_info->chunk_points * type_info->src_type_size; - /* Release the cache lock on the chunk. */ - if(chunk) { - if(!do_write) - dirty = FALSE; + /* Determine if we will access all the data in the chunk */ + if(((io_info->op_type == H5D_IO_OP_WRITE) && (accessed_bytes != ctg_store.contig.dset_size)) + || (io_info->op_type != H5D_IO_OP_WRITE)) + entire_chunk = FALSE; + + /* Lock the chunk into the cache */ + if(NULL == (chunk = H5D_istore_lock(io_info, &udata, entire_chunk, &idx_hint))) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") - if(H5D_istore_unlock(io_info, dirty, idx_hint, chunk, accessed_bytes) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") - } /* end if */ + /* Set up the storage buffer information for this chunk */ + cpt_store.compact.buf = chunk; + + /* Point I/O info at contiguous I/O info for this chunk */ + chk_io_info = &cpt_io_info; } /* end if */ - else { /*collective I/O */ - if(H5D_inter_collective_io(io_info,chunk_info->fspace,chunk_info->mspace, - chunk_addr,buf,do_write ) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO"); - } - - if(make_coll) - if(H5D_ioinfo_make_coll(io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to independent I/O") - /* Get the next chunk node in the skip list */ - chunk_node=H5SL_next(chunk_node); - } /* end while */ + else { + /* Set up the storage address information for this chunk */ + ctg_store.contig.dset_addr = chunk_addr; + + /* No chunk cached */ + chunk = NULL; + + /* Point I/O info at temporary I/O info for this chunk */ + chk_io_info = &ctg_io_info; + } /* end else */ + + if(io_info->op_type == H5D_IO_OP_WRITE) { + if((io_info->io_ops.single_write)(chk_io_info, type_info, + (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed") + } /* end if */ + else { + if((io_info->io_ops.single_read)(chk_io_info, type_info, + (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") + } /* end ese */ + + /* Release the cache lock on the chunk. */ + if(chunk) + if(H5D_istore_unlock(io_info, (io_info->op_type == H5D_IO_OP_WRITE), idx_hint, chunk, accessed_bytes) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") + } /* end if */ + else { /*collective I/O */ + /* Set up the storage address information for this chunk */ + ctg_store.contig.dset_addr = chunk_addr; + + if(H5D_inter_collective_io(&ctg_io_info, type_info, chunk_info->fspace, chunk_info->mspace) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish shared collective MPI-IO") + } /* end else */ + + if(make_coll) + if(H5D_ioinfo_xfer_mode(io_info, dx_plist, H5FD_MPIO_COLLECTIVE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to independent I/O") + + /* Get the next chunk node in the skip list */ + chunk_node = H5SL_next(chunk_node); + } /* end while */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -1420,303 +1500,266 @@ done: * Function: H5D_inter_collective_io * * Purpose: Routine for the shared part of collective IO between multiple chunk - collective IO and contiguous collective IO - + * collective IO and contiguous collective IO * * Return: Non-negative on success/Negative on failure * - * Programmer: - * - * Modifications: + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5D_inter_collective_io(H5D_io_info_t *io_info,const H5S_t *file_space,const H5S_t *mem_space, - haddr_t addr, const void *buf, hbool_t do_write ) +H5D_inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + const H5S_t *file_space, const H5S_t *mem_space) { + size_t mpi_buf_count; /* # of MPI types */ + hbool_t mbt_is_derived = FALSE; + hbool_t mft_is_derived = FALSE; + MPI_Datatype mpi_file_type, mpi_buf_type; + int mpi_code; /* MPI return code */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_inter_collective_io) + + if((file_space != NULL) && (mem_space != NULL)) { + hsize_t mpi_buf_offset, mpi_file_offset; /* Offset within dataset where selection (ie. MPI type) begins */ + size_t mpi_file_count; /* Number of file "objects" to transfer */ - size_t mpi_buf_count, mpi_file_count; /* Number of "objects" to transfer */ - MPI_Datatype mpi_file_type,mpi_buf_type; - hsize_t mpi_buf_offset, mpi_file_offset; /* Offset within dataset where selection (ie. MPI type) begins */ - hbool_t mbt_is_derived=0, /* Whether the buffer (memory) type is derived and needs to be free'd */ - mft_is_derived=0; /* Whether the file type is derived and needs to be free'd */ - H5D_common_coll_info_t coll_info; - herr_t ret_value = SUCCEED; /* return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_inter_collective_io) - if((file_space!=NULL) && (mem_space != NULL)) { - /*Obtain disk and memory MPI derived datatype */ - if(H5S_mpio_space_type(file_space,H5T_get_size(io_info->dset->shared->type), - &mpi_file_type,&mpi_file_count,&mpi_file_offset,&mft_is_derived)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't create MPI file type"); - - if(H5S_mpio_space_type(mem_space,H5T_get_size(io_info->dset->shared->type), - &mpi_buf_type,&mpi_buf_count,&mpi_buf_offset,&mbt_is_derived)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't create MPI buffer type"); - - } - else { - /* For non-selection, participate with a none MPI derived datatype, the count is 0. */ - mpi_buf_type = MPI_BYTE; - mpi_file_type = MPI_BYTE; - mpi_file_count = 0; - mpi_buf_count = 0; - } - - coll_info.mbt_is_derived = mbt_is_derived; - coll_info.mft_is_derived = mft_is_derived; - coll_info.mpi_buf_count = mpi_buf_count; - coll_info.chunk_addr = addr; + /* Obtain disk and memory MPI derived datatype */ + if(H5S_mpio_space_type(file_space, type_info->src_type_size, + &mpi_file_type, &mpi_file_count, &mpi_file_offset, &mft_is_derived) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI file type") + if(H5S_mpio_space_type(mem_space, type_info->src_type_size, + &mpi_buf_type, &mpi_buf_count, &mpi_buf_offset, &mbt_is_derived) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI buffer type") + } /* end if */ + else { + /* For non-selection, participate with a none MPI derived datatype, the count is 0. */ + mpi_buf_type = MPI_BYTE; + mpi_file_type = MPI_BYTE; + mpi_buf_count = (size_t)0; + mbt_is_derived = FALSE; + mft_is_derived = FALSE; + } /* end else */ #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"before final collective IO \n"); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"before final collective IO \n"); #endif - if(H5D_final_collective_io(io_info,&mpi_file_type,&mpi_buf_type,&coll_info,buf,do_write)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish collective MPI-IO"); - done: + /* Perform final collective I/O operation */ + if(H5D_final_collective_io(io_info, type_info, mpi_buf_count, &mpi_file_type, &mpi_buf_type) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish collective MPI-IO") + +done: + /* Free the MPI buf and file types, if they were derived */ + if(mbt_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&mpi_buf_type))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + if(mft_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&mpi_file_type))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + #ifdef H5D_DEBUG - if(H5DEBUG(D)) +if(H5DEBUG(D)) HDfprintf(H5DEBUG(D),"before leaving inter_collective_io ret_value = %d\n",ret_value); #endif - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_inter_collective_io */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_inter_collective_io() */ /*------------------------------------------------------------------------- * Function: H5D_final_collective_io * * Purpose: Routine for the common part of collective IO with different storages. - * * Return: Non-negative on success/Negative on failure * - * Programmer: - * - * Modifications: + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5D_final_collective_io(H5D_io_info_t *io_info,MPI_Datatype*mpi_file_type,MPI_Datatype *mpi_buf_type, - H5D_common_coll_info_t* coll_info, const void *buf, hbool_t do_write) +H5D_final_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + size_t mpi_buf_count, MPI_Datatype *mpi_file_type, MPI_Datatype *mpi_buf_type) { - - - int mpi_code; /* MPI return code */ - hbool_t plist_is_setup=0; /* Whether the dxpl has been customized */ - herr_t ret_value = SUCCEED; - + int mpi_code; /* MPI return code */ + hbool_t plist_is_setup = FALSE; /* Whether the dxpl has been customized */ + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT(H5D_final_collective_io) - /* - * Pass buf type, file type to the file driver. - */ - - if(H5FD_mpi_setup_collective(io_info->dxpl_id, *mpi_buf_type, *mpi_file_type)<0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O properties"); + /* Pass buf type, file type to the file driver. */ + if(H5FD_mpi_setup_collective(io_info->dxpl_id, *mpi_buf_type, *mpi_file_type) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O properties") + plist_is_setup = TRUE; - plist_is_setup=1; -#ifdef H5D_DEBUG - if(H5DEBUG(D)){ - HDfprintf(H5DEBUG(D),"chunk addr %Hu\n",coll_info->chunk_addr); - HDfprintf(H5DEBUG(D),"mpi_buf_count %d\n",coll_info->mpi_buf_count); - } - -#endif - - if(do_write) { - if((io_info->ops.write)(io_info, - coll_info->mpi_buf_count,0,NULL,NULL,coll_info->chunk_addr, - NULL, buf) < 0) + if(io_info->op_type == H5D_IO_OP_WRITE) { + if((io_info->io_ops.single_write)(io_info, type_info, + (hsize_t)mpi_buf_count, NULL, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed") - } + } /* end if */ else { - if((io_info->ops.read)(io_info, - coll_info->mpi_buf_count,0,NULL,NULL,coll_info->chunk_addr, - NULL, buf) < 0) + if((io_info->io_ops.single_read)(io_info, type_info, + (hsize_t)mpi_buf_count, NULL, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") - } + } /* end else */ done: - /* Reset the dxpl settings */ - if(plist_is_setup) { - if(H5FD_mpi_teardown_collective(io_info->dxpl_id)<0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to reset dxpl values"); - } /* end if */ - - /* free the MPI buf and file types */ - if (coll_info->mbt_is_derived) { - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( mpi_buf_type ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - } - if (coll_info->mft_is_derived) { - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( mpi_file_type ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - } + /* Reset the dxpl settings */ + if(plist_is_setup) + if(H5FD_mpi_teardown_collective(io_info->dxpl_id) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to reset dxpl values") + #ifdef H5D_DEBUG - if(H5DEBUG(D)) +if(H5DEBUG(D)) HDfprintf(H5DEBUG(D),"ret_value before leaving final_collective_io=%d\n",ret_value); #endif - FUNC_LEAVE_NOAPI(ret_value) -}/* end H5D_final_collective_io */ +} /* end H5D_final_collective_io */ /*------------------------------------------------------------------------- * Function: H5D_sort_chunk * * Purpose: Routine to sort chunks in increasing order of chunk address - Each chunk address is also obtained. - - Description: - For most cases, the chunk address has already been sorted in increasing order. - The special sorting flag is used to optimize this common case. - quick sort is used for necessary sorting. - - Parameters: - Input: H5D_io_info_t* io_info, - H5D_chunk_map_t *fm(global chunk map struct) - Input/Output: H5D_chunk_addr_info_t chunk_addr_info_array[] : array to store chunk address and information - many_chunk_opt : flag to optimize the way to obtain chunk addresses - for many chunks + * Each chunk address is also obtained. * - * Return: Non-negative on success/Negative on failure + * Description: + * For most cases, the chunk address has already been sorted in increasing order. + * The special sorting flag is used to optimize this common case. + * quick sort is used for necessary sorting. * - * Programmer: + * Parameters: + * Input: H5D_io_info_t* io_info, + * H5D_chunk_map_t *fm(global chunk map struct) + * Input/Output: H5D_chunk_addr_info_t chunk_addr_info_array[] : array to store chunk address and information + * many_chunk_opt : flag to optimize the way to obtain chunk addresses + * for many chunks * - * Modifications: + * Return: Non-negative on success/Negative on failure + * + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ - static herr_t -H5D_sort_chunk(H5D_io_info_t * io_info, - H5D_chunk_map_t *fm, - H5D_chunk_addr_info_t chunk_addr_info_array[], - int many_chunk_opt) +H5D_sort_chunk(H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, + H5D_chunk_addr_info_t chunk_addr_info_array[], int sum_chunk) { - - - H5SL_node_t *chunk_node; /* Current node in chunk skip list */ + H5SL_node_t *chunk_node; /* Current node in chunk skip list */ H5D_chunk_info_t *chunk_info; /* Current chunking info. of this node. */ - haddr_t chunk_addr; /* Current chunking address of this node */ - haddr_t *total_chunk_addr_array=NULL; /* The array of chunk address for the total number of chunk */ - int i,mpi_code; - int total_chunks; - size_t num_chunks; - int mpi_type_cleanup = 0; - int tchunk_addr_cleanup = 0; - MPI_Datatype chunk_addrtype; - H5D_storage_t store; /*union of EFL and chunk pointer in file space */ - hbool_t do_sort = FALSE; - herr_t ret_value = SUCCEED; /*return value */ + haddr_t chunk_addr; /* Current chunking address of this node */ + haddr_t *total_chunk_addr_array = NULL; /* The array of chunk address for the total number of chunk */ + H5D_storage_t store; /*union of EFL and chunk pointer in file space */ + hbool_t do_sort = FALSE; /* Whether the addresses need to be sorted */ + int bsearch_coll_chunk_threshold; + int many_chunk_opt = H5D_OBTAIN_ONE_CHUNK_ADDR_IND; + int mpi_size; /* Number of MPI processes */ + int mpi_code; /* MPI return code */ + int i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5D_sort_chunk) - num_chunks = H5SL_count(fm->sel_chunks); + /* Retrieve # of MPI processes */ + if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file)) < 0) + HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size") + + /* Calculate the actual threshold to obtain all chunk addresses collectively + * The bigger this number is, the more possible the use of obtaining chunk + * address collectively. + */ + /* For non-optimization one-link IO, actual bsearch threshold is always + * 0, we would always want to obtain the chunk addresses individually + * for each process. + */ + bsearch_coll_chunk_threshold = (sum_chunk * 100) / ((int)fm->total_chunks * mpi_size); + if((bsearch_coll_chunk_threshold > H5D_ALL_CHUNK_ADDR_THRES_COL) + && ((sum_chunk / mpi_size) >= H5D_ALL_CHUNK_ADDR_THRES_COL_NUM)) + many_chunk_opt = H5D_OBTAIN_ALL_CHUNK_ADDR_COL; + #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"many_chunk_opt= %d\n",many_chunk_opt); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D), "many_chunk_opt= %d\n", many_chunk_opt); #endif /* If we need to optimize the way to obtain the chunk address */ - if(many_chunk_opt != H5D_OBTAIN_ONE_CHUNK_ADDR_IND){ + if(many_chunk_opt != H5D_OBTAIN_ONE_CHUNK_ADDR_IND) { + int mpi_rank; - int mpi_rank, root; - total_chunks = (int)fm->total_chunks; - total_chunk_addr_array = H5MM_malloc(sizeof(haddr_t)*total_chunks); - tchunk_addr_cleanup = 1; #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"Coming inside H5D_OBTAIN_ALL_CHUNK_ADDR_COL\n"); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D), "Coming inside H5D_OBTAIN_ALL_CHUNK_ADDR_COL\n"); #endif - root = 0; - if((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file))<0) - HGOTO_ERROR (H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi rank"); - - /*Create received MPI derived datatype */ - if(MPI_SUCCESS !=(mpi_code = MPI_Type_contiguous((int)(sizeof(haddr_t)*total_chunks), MPI_BYTE, &chunk_addrtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_contiguous failed", mpi_code); - if(MPI_SUCCESS !=(mpi_code = MPI_Type_commit(&chunk_addrtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code); - - mpi_type_cleanup = 1; - - if(mpi_rank == root) { - if(H5D_istore_chunkmap(io_info, total_chunk_addr_array, fm->down_chunks)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address"); - } + /* Allocate array for chunk addresses */ + if(NULL == (total_chunk_addr_array = H5MM_malloc(sizeof(haddr_t) * (size_t)fm->total_chunks))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory chunk address array") + + /* Retrieve all the chunk addresses with process 0 */ + if((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file)) < 0) + HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi rank") + if(mpi_rank == 0) { + if(H5D_istore_chunkmap(io_info, total_chunk_addr_array, fm->down_chunks) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address") + } /* end if */ + /* Broadcasting the MPI_IO option info. and chunk address info. */ - if(MPI_SUCCESS !=(mpi_code = MPI_Bcast(total_chunk_addr_array,1,chunk_addrtype,root,io_info->comm))) - HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code); + if(MPI_SUCCESS != (mpi_code = MPI_Bcast(total_chunk_addr_array, (int)(sizeof(haddr_t) * fm->total_chunks), MPI_BYTE, (int)0, io_info->comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code) } /* end if */ - /* Get first node in chunk skip list */ - if(NULL ==(chunk_node = H5SL_first(fm->sel_chunks))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk node from skipped list"); /* Set dataset storage for I/O info */ io_info->store = &store; - if(NULL ==(chunk_info = H5SL_item(chunk_node))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; + + /* Start at first node in chunk skip list */ i = 0; - if(many_chunk_opt == H5D_OBTAIN_ONE_CHUNK_ADDR_IND){ - if(HADDR_UNDEF==(chunk_addr = H5D_istore_get_addr(io_info,NULL))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); + if(NULL == (chunk_node = H5SL_first(fm->sel_chunks))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk node from skipped list") -#ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"coming to obtain each chunk address individually \n"); -#endif - } - else - chunk_addr = total_chunk_addr_array[chunk_info->index]; + /* Iterate over all chunks for this process */ + while(chunk_node) { + if(NULL == (chunk_info = H5SL_item(chunk_node))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list") + + if(many_chunk_opt == H5D_OBTAIN_ONE_CHUNK_ADDR_IND) { + store.chunk.offset = chunk_info->coords; + store.chunk.index = chunk_info->index; + if(HADDR_UNDEF == (chunk_addr = H5D_istore_get_addr(io_info, NULL))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skipped list") + } /* end if */ + else + chunk_addr = total_chunk_addr_array[chunk_info->index]; - chunk_addr_info_array[i].chunk_addr = chunk_addr; - chunk_addr_info_array[i].chunk_info = *chunk_info; + /* Check if chunk addresses are not in increasing order in the file */ + if(i > 0 && chunk_addr < chunk_addr_info_array[i - 1].chunk_addr) + do_sort = TRUE; - chunk_node = H5SL_next(chunk_node); + /* Set the address & info for this chunk */ + chunk_addr_info_array[i].chunk_addr = chunk_addr; + chunk_addr_info_array[i].chunk_info = *chunk_info; - while(chunk_node) { + /* Advance to next chunk in list */ + i++; + chunk_node = H5SL_next(chunk_node); + } /* end while */ - chunk_info = H5SL_item(chunk_node); - store.chunk.offset = chunk_info->coords; - store.chunk.index = chunk_info->index; - - if(many_chunk_opt == H5D_OBTAIN_ONE_CHUNK_ADDR_IND){ - if(HADDR_UNDEF==(chunk_addr = H5D_istore_get_addr(io_info,NULL))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list"); - } - else - chunk_addr = total_chunk_addr_array[chunk_info->index]; - - if(chunk_addr < chunk_addr_info_array[i].chunk_addr) do_sort = TRUE; - chunk_addr_info_array[i+1].chunk_addr = chunk_addr; - chunk_addr_info_array[i+1].chunk_info =*chunk_info; - i++; - chunk_node = H5SL_next(chunk_node); - } #ifdef H5D_DEBUG - if(H5DEBUG(D)) - HDfprintf(H5DEBUG(D),"before Qsort\n"); +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D), "before Qsort\n"); #endif - if(do_sort) - HDqsort(chunk_addr_info_array,num_chunks,sizeof(chunk_addr_info_array),H5D_cmp_chunk_addr); + if(do_sort) { + size_t num_chunks = H5SL_count(fm->sel_chunks); + + HDqsort(chunk_addr_info_array, num_chunks, sizeof(chunk_addr_info_array[0]), H5D_cmp_chunk_addr); + } /* end if */ done: + if(total_chunk_addr_array) + H5MM_xfree(total_chunk_addr_array); - if(tchunk_addr_cleanup) - HDfree(total_chunk_addr_array); - if(mpi_type_cleanup) { - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( &chunk_addrtype ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - } FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_sort_chunk() */ @@ -1725,310 +1768,244 @@ done: * Function: H5D_obtain_mpio_mode * * Purpose: Routine to obtain each io mode(collective,independent or none) for each chunk; - Each chunk address is also obtained. - - Description: - - 1) Each process provides two piece of information for all chunks having selection - a) chunk index - b) wheather this chunk is regular(for MPI derived datatype not working case) - - 2) Gather all the information to the root process - - 3) Root process will do the following: - a) Obtain chunk addresses for all chunks in this data space - b) With the consideration of the user option, calculate IO mode for each chunk - c) Build MPI derived datatype to combine "chunk address" and "assign_io" information - in order to do MPI Bcast only once - d) MPI Bcast the IO mode and chunk address information for each chunk. - 4) Each process then retrieves IO mode and chunk address information to assign_io_mode and chunk_addr. - - Parameters: - - Input: H5D_io_info_t* io_info, - H5D_chunk_map_t *fm,(global chunk map struct) - Output: uint8_t assign_io_mode[], : IO mode, collective, independent or none - haddr_t chunk_addr[], : chunk address array for each chunk + * Each chunk address is also obtained. * - * Return: Non-negative on success/Negative on failure + * Description: * - * Programmer: + * 1) Each process provides two piece of information for all chunks having selection + * a) chunk index + * b) wheather this chunk is regular(for MPI derived datatype not working case) + * + * 2) Gather all the information to the root process * - * Modifications: + * 3) Root process will do the following: + * a) Obtain chunk addresses for all chunks in this data space + * b) With the consideration of the user option, calculate IO mode for each chunk + * c) Build MPI derived datatype to combine "chunk address" and "assign_io" information + * in order to do MPI Bcast only once + * d) MPI Bcast the IO mode and chunk address information for each chunk. + * 4) Each process then retrieves IO mode and chunk address information to assign_io_mode and chunk_addr. + * + * Parameters: + * + * Input: H5D_io_info_t* io_info, + * H5D_chunk_map_t *fm,(global chunk map struct) + * Output: uint8_t assign_io_mode[], : IO mode, collective, independent or none + * haddr_t chunk_addr[], : chunk address array for each chunk + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 * *------------------------------------------------------------------------- */ - static herr_t -H5D_obtain_mpio_mode(H5D_io_info_t* io_info, - H5D_chunk_map_t *fm, - uint8_t assign_io_mode[], - haddr_t chunk_addr[]) +H5D_obtain_mpio_mode(H5D_io_info_t* io_info, H5D_chunk_map_t *fm, + H5P_genplist_t *dx_plist, uint8_t assign_io_mode[], haddr_t chunk_addr[]) { - - int total_chunks; - hsize_t ori_total_chunks; - unsigned percent_nproc_per_chunk,threshold_nproc_per_chunk; - H5FD_mpio_chunk_opt_t chunk_opt_mode; - uint8_t* io_mode_info=NULL; - uint8_t* recv_io_mode_info=NULL; - uint8_t* mergebuf=NULL; - uint8_t* tempbuf; - - H5SL_node_t* chunk_node; - H5D_chunk_info_t* chunk_info; - - MPI_Datatype bastype[2]; - MPI_Datatype chunk_addrtype; - int bascount; - int basblock[2]; - MPI_Aint basdisp[2]; - MPI_Datatype rtype; - MPI_Datatype stype; - int mpi_size,mpi_rank; - MPI_Comm comm; - int ic,root; - int mpi_code; - H5P_genplist_t *plist; - int mem_cleanup = 0, - mpi_type_cleanup = 0; - + int total_chunks; + unsigned percent_nproc_per_chunk,threshold_nproc_per_chunk; + H5FD_mpio_chunk_opt_t chunk_opt_mode; + uint8_t* io_mode_info=NULL; + uint8_t* recv_io_mode_info=NULL; + uint8_t* mergebuf=NULL; + uint8_t* tempbuf; + H5SL_node_t* chunk_node; + H5D_chunk_info_t* chunk_info; + int mpi_size,mpi_rank; + MPI_Comm comm; + int ic,root; + int mpi_code; + int mem_cleanup = 0; #ifdef H5_HAVE_INSTRUMENTED_LIBRARY - int new_value; - htri_t check_prop; + int new_value; + htri_t check_prop; #endif + herr_t ret_value = SUCCEED; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NOINIT(H5D_obtain_mpio_mode) + FUNC_ENTER_NOAPI_NOINIT(H5D_obtain_mpio_mode) - /* Assign the rank 0 to the root */ - root = 0; - comm = io_info->comm; + /* Assign the rank 0 to the root */ + root = 0; + comm = io_info->comm; - /* Obtain the number of process and the current rank of the process */ - if((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file))<0) - HGOTO_ERROR (H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi rank"); - if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file))<0) - HGOTO_ERROR (H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size"); + /* Obtain the number of process and the current rank of the process */ + if((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file)) < 0) + HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi rank") + if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file)) < 0) + HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size") - /* Allocate memory */ - ori_total_chunks = fm->total_chunks; - H5_ASSIGN_OVERFLOW(total_chunks,ori_total_chunks,hsize_t,int); - - /* Obtain the data transfer properties */ - if(NULL == (plist = H5I_object(io_info->dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") - - percent_nproc_per_chunk=H5P_peek_unsigned(plist,H5D_XFER_MPIO_CHUNK_OPT_RATIO_NAME); + /* Setup parameters */ + H5_ASSIGN_OVERFLOW(total_chunks, fm->total_chunks, hsize_t, int); + percent_nproc_per_chunk = H5P_peek_unsigned(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_RATIO_NAME); #if defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) && defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - - chunk_opt_mode=(H5FD_mpio_chunk_opt_t)H5P_peek_unsigned(plist,H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME); - - if((chunk_opt_mode == H5FD_MPIO_CHUNK_MULTI_IO) || (percent_nproc_per_chunk == 0)){ - if(H5D_istore_chunkmap(io_info, chunk_addr, fm->down_chunks) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address"); - for(ic = 0; icdown_chunks) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address"); + for(ic = 0; ic < total_chunks; ic++) + assign_io_mode[ic] = H5D_CHUNK_IO_MODE_COL; + + HGOTO_DONE(SUCCEED) + } /* end if */ #endif - threshold_nproc_per_chunk = mpi_size * percent_nproc_per_chunk/100; - - io_mode_info = (uint8_t *)H5MM_calloc(total_chunks*sizeof(MPI_BYTE)); - mergebuf = H5MM_malloc((sizeof(haddr_t)+sizeof(MPI_BYTE))*total_chunks); - tempbuf = mergebuf + sizeof(MPI_BYTE)*total_chunks; - if(mpi_rank == root) - recv_io_mode_info = (uint8_t *)H5MM_malloc(total_chunks*sizeof(MPI_BYTE)*mpi_size); + threshold_nproc_per_chunk = mpi_size * percent_nproc_per_chunk/100; + + /* Allocate memory */ + io_mode_info = (uint8_t *)H5MM_calloc(total_chunks); + mergebuf = H5MM_malloc((sizeof(haddr_t) + 1) * total_chunks); + tempbuf = mergebuf + total_chunks; + if(mpi_rank == root) + recv_io_mode_info = (uint8_t *)H5MM_malloc(total_chunks * mpi_size); - mem_cleanup = 1; + mem_cleanup = 1; - chunk_node = H5SL_first(fm->sel_chunks); - - /*Obtain the regularity and selection information for all chunks in this process. */ - while(chunk_node){ - - chunk_info = H5SL_item(chunk_node); + /* Obtain the regularity and selection information for all chunks in this process. */ + chunk_node = H5SL_first(fm->sel_chunks); + while(chunk_node) { + chunk_info = H5SL_item(chunk_node); #ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS - /* regularity information: 1, selection information: 2 */ - if(H5S_SELECT_IS_REGULAR(chunk_info->fspace) == TRUE && - H5S_SELECT_IS_REGULAR(chunk_info->mspace) == TRUE) + /* regularity information: 1, selection information: 2 */ + if(H5S_SELECT_IS_REGULAR(chunk_info->fspace) == TRUE && + H5S_SELECT_IS_REGULAR(chunk_info->mspace) == TRUE) #endif - io_mode_info[chunk_info->index] = H5D_CHUNK_SELECT_REG; /* this chunk is selected and is "regular" without defining H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS. */ + io_mode_info[chunk_info->index] = H5D_CHUNK_SELECT_REG; /* this chunk is selected and is "regular" without defining H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS. */ #ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS - else - io_mode_info[chunk_info->index] = H5D_CHUNK_SELECT_IRREG; /* this chunk is selected and is irregular*/ + else + io_mode_info[chunk_info->index] = H5D_CHUNK_SELECT_IRREG; /* this chunk is selected and is irregular*/ #endif - - chunk_node = H5SL_next(chunk_node); - } + chunk_node = H5SL_next(chunk_node); + } /* end while */ - /*Create sent MPI derived datatype */ - if(MPI_SUCCESS !=(mpi_code = MPI_Type_contiguous(total_chunks,MPI_BYTE,&stype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Comm_rank failed", mpi_code); - if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&stype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code); - - /*Create received basic MPI derived datatype */ - bascount = 2; - basblock[0] = total_chunks; - basblock[1] = total_chunks; - basdisp[0] = 0; - basdisp[1] = (MPI_Aint)(sizeof(MPI_BYTE)*total_chunks);/* may need to check overflow */ - bastype[0] = MPI_BYTE; - - if(MPI_SUCCESS !=(mpi_code = MPI_Type_contiguous(sizeof(haddr_t),MPI_BYTE,&chunk_addrtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_contiguous failed", mpi_code); - if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_addrtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code); - bastype[1] = chunk_addrtype; - - if(MPI_SUCCESS !=(mpi_code = MPI_Type_struct(bascount,basblock,basdisp,bastype,&rtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_struct failed", mpi_code); - if(MPI_SUCCESS !=(mpi_code = MPI_Type_commit(&rtype))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code); - - /* Set up a flag to clean up the MPI derived datatype later */ - mpi_type_cleanup = 1; - - /*Gather all the information */ - if(MPI_SUCCESS !=(mpi_code = MPI_Gather(io_mode_info,1,stype,recv_io_mode_info,1,stype,root,comm))) - HMPI_GOTO_ERROR(FAIL, "MPI_Gather failed", mpi_code); - - /* Calculate the mode for IO(collective, independent or none) at root process */ - if(mpi_rank == root) { - - int nproc; - int* nproc_per_chunk; + /*Gather all the information */ + if(MPI_SUCCESS != (mpi_code = MPI_Gather(io_mode_info, total_chunks, MPI_BYTE, recv_io_mode_info, total_chunks, MPI_BYTE, root, comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_Gather failed", mpi_code) + + /* Calculate the mode for IO(collective, independent or none) at root process */ + if(mpi_rank == root) { + int nproc; + int* nproc_per_chunk; #if !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - int* ind_this_chunk; + int* ind_this_chunk; #endif - /* pre-computing: calculate number of processes and - regularity of the selection occupied in each chunk */ - nproc_per_chunk = (int*)H5MM_calloc(total_chunks*sizeof(int)); + /* pre-computing: calculate number of processes and + regularity of the selection occupied in each chunk */ + nproc_per_chunk = (int*)H5MM_calloc(total_chunks * sizeof(int)); #if !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - ind_this_chunk = (int*)H5MM_calloc(total_chunks*sizeof(int)); + ind_this_chunk = (int*)H5MM_calloc(total_chunks * sizeof(int)); #endif - /* calculating the chunk address */ - if(H5D_istore_chunkmap(io_info, chunk_addr, fm->down_chunks)<0){ - HDfree(nproc_per_chunk); + /* calculating the chunk address */ + if(H5D_istore_chunkmap(io_info, chunk_addr, fm->down_chunks) < 0) { + HDfree(nproc_per_chunk); #if !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - HDfree(ind_this_chunk); + HDfree(ind_this_chunk); #endif - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address"); - } - - /* checking for number of process per chunk and regularity of the selection*/ - for (nproc = 0;nproc MAX(1,threshold_nproc_per_chunk)){ + /* Calculating MPIO mode for each chunk (collective, independent, none) */ + for(ic = 0; ic < total_chunks; ic++) { + if(nproc_per_chunk[ic] > MAX(1, threshold_nproc_per_chunk)) { #if !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - if(!ind_this_chunk[ic]) assign_io_mode[ic] = H5D_CHUNK_IO_MODE_COL; + if(!ind_this_chunk[ic]) + assign_io_mode[ic] = H5D_CHUNK_IO_MODE_COL; #else - assign_io_mode[ic] = H5D_CHUNK_IO_MODE_COL; + assign_io_mode[ic] = H5D_CHUNK_IO_MODE_COL; #endif - } - } + } /* end if */ + } /* end for */ - /* merge buffer io_mode info and chunk addr into one */ - HDmemcpy(mergebuf,assign_io_mode,sizeof(MPI_BYTE)*total_chunks); - HDmemcpy(tempbuf,chunk_addr,sizeof(haddr_t)*total_chunks); + /* merge buffer io_mode info and chunk addr into one */ + HDmemcpy(mergebuf, assign_io_mode, total_chunks); + HDmemcpy(tempbuf, chunk_addr, sizeof(haddr_t) * total_chunks); - HDfree(nproc_per_chunk); + HDfree(nproc_per_chunk); #if !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - HDfree(ind_this_chunk); + HDfree(ind_this_chunk); #endif - } + } /* end if */ - /* Broadcasting the MPI_IO option info. and chunk address info. */ - if(MPI_SUCCESS !=(mpi_code = MPI_Bcast(mergebuf,1,rtype,root,comm))) - HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code); + /* Broadcasting the MPI_IO option info. and chunk address info. */ + if(MPI_SUCCESS != (mpi_code = MPI_Bcast(mergebuf, ((sizeof(haddr_t) + 1) * total_chunks), MPI_BYTE, root, comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code) - HDmemcpy(assign_io_mode,mergebuf,sizeof(MPI_BYTE)*total_chunks); - HDmemcpy(chunk_addr,tempbuf,sizeof(haddr_t)*total_chunks); + HDmemcpy(assign_io_mode, mergebuf, total_chunks); + HDmemcpy(chunk_addr, tempbuf, sizeof(haddr_t) * total_chunks); #ifdef H5_HAVE_INSTRUMENTED_LIBRARY - check_prop = H5Pexist(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME); + check_prop = H5Pexist(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME); if(check_prop > 0) { #if !defined(H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS) || !defined(H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS) - new_value = 0; - if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME,&new_value)<0) - HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value"); + new_value = 0; + if(H5Pset(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME, &new_value) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value") #else - for(ic = 0; ic < total_chunks; ic++){ - if(assign_io_mode[ic] == H5D_CHUNK_IO_MODE_COL) { - new_value = 0; - if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME,&new_value)<0) - HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value"); - break; - } - } + for(ic = 0; ic < total_chunks; ic++) { + if(assign_io_mode[ic] == H5D_CHUNK_IO_MODE_COL) { + new_value = 0; + if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME,&new_value) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value") + break; + } /* end if */ + } /* end for */ #endif - } - check_prop = H5Pexist(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME); - if(check_prop > 0) { - int temp_count = 0; - for(ic = 0; ic < total_chunks; ic++){ - if(assign_io_mode[ic] == H5D_CHUNK_IO_MODE_COL) { - temp_count++; - break; - } - } - if(temp_count==0){ - new_value = 0; - if(H5Pset(io_info->dxpl_id,H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME,&new_value)<0) - HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value"); - } - } + } /* end if */ + + check_prop = H5Pexist(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME); + if(check_prop > 0) { + int temp_count = 0; + + for(ic = 0; ic < total_chunks; ic++) { + if(assign_io_mode[ic] == H5D_CHUNK_IO_MODE_COL) { + temp_count++; + break; + } /* end if */ + } /* end for */ + if(temp_count == 0) { + new_value = 0; + if(H5Pset(io_info->dxpl_id, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME, &new_value) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value") + } /* end if */ + } /* end if */ #endif done: - - if(mpi_type_cleanup) { - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( &chunk_addrtype ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( &stype ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - - if (MPI_SUCCESS != (mpi_code= MPI_Type_free( &rtype ))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code); - } - - if(mem_cleanup){ - HDfree(io_mode_info); - HDfree(mergebuf); - if(mpi_rank == root) - HDfree(recv_io_mode_info); - } + if(mem_cleanup) { + HDfree(io_mode_info); + HDfree(mergebuf); + if(mpi_rank == root) + HDfree(recv_io_mode_info); + } /* end if */ FUNC_LEAVE_NOAPI(ret_value) -}/* end H5D_obtain_mpio_mode*/ +} /* end H5D_obtain_mpio_mode() */ static int H5D_cmp_chunk_addr(const void *chunk_addr_info1, const void *chunk_addr_info2) @@ -2041,7 +2018,6 @@ H5D_cmp_chunk_addr(const void *chunk_addr_info1, const void *chunk_addr_info2) addr2 = ((const H5D_chunk_addr_info_t *)chunk_addr_info2)->chunk_addr; FUNC_LEAVE_NOAPI(H5F_addr_cmp(addr1, addr2)) - } #endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5Doh.c b/src/H5Doh.c index 01447a3..37f011b 100644 --- a/src/H5Doh.c +++ b/src/H5Doh.c @@ -316,7 +316,7 @@ H5O_dset_get_oloc(hid_t obj_id) FUNC_ENTER_NOAPI_NOINIT(H5O_dset_get_oloc) /* Get the dataset */ - if(NULL == (dset = H5I_object(obj_id))) + if(NULL == (dset = (H5D_t *)H5I_object(obj_id))) HGOTO_ERROR(H5E_OHDR, H5E_BADATOM, NULL, "couldn't get object from ID") /* Get the dataset's object header location */ diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index aec5e19..97dcacf 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -49,74 +49,156 @@ #define H5D_MINHDR_SIZE 256 /* [Simple] Macro to construct a H5D_io_info_t from it's components */ -#define H5D_BUILD_IO_INFO(io_info,ds,dxpl_c,dxpl_i,str) \ - (io_info)->dset=ds; \ - (io_info)->dxpl_cache=dxpl_c; \ - (io_info)->dxpl_id=dxpl_i; \ - (io_info)->store=str +#define H5D_BUILD_IO_INFO_WRT(io_info, ds, dxpl_c, dxpl_i, str, buf) \ + (io_info)->dset = ds; \ + (io_info)->dxpl_cache = dxpl_c; \ + (io_info)->dxpl_id = dxpl_i; \ + (io_info)->store = str; \ + (io_info)->op_type = H5D_IO_OP_WRITE; \ + (io_info)->u.wbuf = buf +#define H5D_BUILD_IO_INFO_RD(io_info, ds, dxpl_c, dxpl_i, str, buf) \ + (io_info)->dset = ds; \ + (io_info)->dxpl_cache = dxpl_c; \ + (io_info)->dxpl_id = dxpl_i; \ + (io_info)->store = str; \ + (io_info)->op_type = H5D_IO_OP_READ; \ + (io_info)->u.rbuf = buf + +#define H5D_CHUNK_HASH(D, ADDR) H5F_addr_hash(ADDR, (D)->cache.chunk.nslots) /****************************/ /* Package Private Typedefs */ /****************************/ -/* - * If there is no data type conversion then it might be possible to - * transfer data points between application memory and the file in one - * step without going through the data type conversion buffer. - */ - -/* Read from file to application w/o intermediate scratch buffer */ +/* Typedef for datatype information for raw data I/O operation */ +typedef struct H5D_type_info_t { + /* Initial values */ + const H5T_t *mem_type; /* Pointer to memory datatype */ + const H5T_t *dset_type; /* Pointer to dataset datatype */ + H5T_path_t *tpath; /* Datatype conversion path */ + hid_t src_type_id; /* Source datatype ID */ + hid_t dst_type_id; /* Destination datatype ID */ + + /* Computed/derived values */ + size_t src_type_size; /* Size of source type */ + size_t dst_type_size; /* Size of destination type*/ + size_t max_type_size; /* Size of largest source/destination type */ + hbool_t is_conv_noop; /* Whether the type conversion is a NOOP */ + hbool_t is_xform_noop; /* Whether the data transform is a NOOP */ + H5T_subset_t cmpd_subset; /* Whether (and which) the source/destination datatypes are compound subsets of one another */ + H5T_bkg_t need_bkg; /* Type of background buf needed */ + size_t request_nelmts; /* Requested strip mine */ + uint8_t *tconv_buf; /* Datatype conv buffer */ + hbool_t tconv_buf_allocated; /* Whether the type conversion buffer was allocated */ + uint8_t *bkg_buf; /* Background buffer */ + hbool_t bkg_buf_allocated; /* Whether the background buffer was allocated */ +} H5D_type_info_t; + +/* Forward declaration of structs used below */ struct H5D_io_info_t; -typedef herr_t (*H5D_io_read_func_t)(struct H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const H5S_t *file_space, const H5S_t *mem_space, haddr_t addr, - void *chunk, void *buf/*out*/); - - -/* Write directly from app buffer to file */ -typedef herr_t (*H5D_io_write_func_t)(struct H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const H5S_t *file_space, const H5S_t *mem_space, haddr_t addr, - void *chunk, const void *buf); +struct H5D_chunk_map_t; /* Function pointers for I/O on particular types of dataset layouts */ -typedef ssize_t (*H5D_io_readvv_func_t)(const struct H5D_io_info_t *io_info, +typedef herr_t (*H5D_layout_init_func_t)(const struct 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, + struct H5D_chunk_map_t *cm); +typedef herr_t (*H5D_layout_read_func_t)(struct H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, struct H5D_chunk_map_t *fm); +typedef herr_t (*H5D_layout_write_func_t)(struct 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, struct H5D_chunk_map_t *fm); +typedef ssize_t (*H5D_layout_readvv_func_t)(const struct H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t chunk_addr, void *chunk, void *buf); -typedef ssize_t (*H5D_io_writevv_func_t)(const struct H5D_io_info_t *io_info, + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); +typedef ssize_t (*H5D_layout_writevv_func_t)(const struct H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t chunk_addr, void *chunk, const void *buf); + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); +typedef herr_t (*H5D_layout_term_func_t)(const struct H5D_chunk_map_t *cm); + +/* Typedef for grouping layout I/O routines */ +typedef struct H5D_layout_ops_t { + H5D_layout_init_func_t init; /* I/O initialization routine */ + H5D_layout_read_func_t ser_read; /* High-level I/O routine for reading data in serial */ + H5D_layout_write_func_t ser_write; /* High-level I/O routine for writing data in serial */ +#ifdef H5_HAVE_PARALLEL + H5D_layout_read_func_t par_read; /* High-level I/O routine for reading data in parallel */ + H5D_layout_write_func_t par_write; /* High-level I/O routine for writing data in parallel */ +#endif /* H5_HAVE_PARALLEL */ + H5D_layout_readvv_func_t readvv; /* Low-level I/O routine for reading data */ + H5D_layout_writevv_func_t writevv; /* Low-level I/O routine for writing data */ + H5D_layout_term_func_t term; /* I/O shutdown routine */ +} H5D_layout_ops_t; + +/* Function pointers for either multiple or single block I/O access */ +typedef herr_t (*H5D_io_single_read_func_t)(const struct 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); +typedef herr_t (*H5D_io_single_write_func_t)(const struct 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); /* Typedef for raw data I/O framework info */ typedef struct H5D_io_ops_t { - H5D_io_read_func_t read; /* Direct I/O routine for reading */ - H5D_io_write_func_t write; /* Direct I/O routine for writing */ - H5D_io_readvv_func_t readvv; /* I/O routine for reading data */ - H5D_io_writevv_func_t writevv; /* I/O routine for writing data */ + H5D_layout_read_func_t multi_read; /* High-level I/O routine for reading data */ + H5D_layout_write_func_t multi_write; /* High-level I/O routine for writing data */ + H5D_io_single_read_func_t single_read; /* I/O routine for reading single block */ + H5D_io_single_write_func_t single_write; /* I/O routine for writing single block */ } H5D_io_ops_t; +/* Typedefs for dataset storage information */ +typedef struct { + haddr_t dset_addr; /* Address of dataset in file */ + hsize_t dset_size; /* Total size of dataset in file */ +} H5D_contig_storage_t; + +typedef struct { + hsize_t index; /* "Index" of chunk in dataset (must be first for TBBT routines) */ + hsize_t *offset; /* Chunk's coordinates in elements */ +} H5D_chunk_storage_t; + +typedef struct { + void *buf; /* Buffer for compact dataset */ + hbool_t *dirty; /* Pointer to dirty flag to mark */ +} H5D_compact_storage_t; + +typedef union H5D_storage_t { + H5D_contig_storage_t contig; /* Contiguous information for dataset */ + H5D_chunk_storage_t chunk; /* Chunk information for dataset */ + H5D_compact_storage_t compact; /* Compact information for dataset */ + H5O_efl_t efl; /* External file list information for dataset */ +} H5D_storage_t; + /* Typedef for raw data I/O operation info */ typedef struct H5D_io_info_t { H5D_t *dset; /* Pointer to dataset being operated on */ #ifndef H5_HAVE_PARALLEL const #endif /* H5_HAVE_PARALLEL */ - H5D_dxpl_cache_t *dxpl_cache; /* Pointer to cache DXPL info */ + H5D_dxpl_cache_t *dxpl_cache; /* Pointer to cached DXPL info */ hid_t dxpl_id; /* Original DXPL ID */ #ifdef H5_HAVE_PARALLEL MPI_Comm comm; /* MPI communicator for file */ - hbool_t xfer_mode_changed; /* Whether the transfer mode was changed */ - hbool_t xfer_opt_mode_changed; hbool_t using_mpi_vfd; /* Whether the file is using an MPI-based VFD */ + struct { + H5FD_mpio_xfer_t xfer_mode; /* Parallel transfer for this request (H5D_XFER_IO_XFER_MODE_NAME) */ + H5FD_mpio_collective_opt_t coll_opt_mode; /* Parallel transfer with independent IO or collective IO with this mode */ + H5D_io_ops_t io_ops; /* I/O operation function pointers */ + } orig; #endif /* H5_HAVE_PARALLEL */ - const H5D_storage_t *store; /* Dataset storage info */ - H5D_io_ops_t ops; /* I/O operation function pointers */ -#ifdef H5S_DEBUG - H5S_iostats_t *stats; /* I/O statistics */ -#endif /* H5S_DEBUG */ + H5D_storage_t *store; /* Dataset storage info */ + H5D_layout_ops_t layout_ops; /* Dataset layout I/O operation function pointers */ + H5D_io_ops_t io_ops; /* I/O operation function pointers */ + enum { + H5D_IO_OP_READ, /* Read operation */ + H5D_IO_OP_WRITE /* Write operation */ + } op_type; + union { + void *rbuf; /* Pointer to buffer for read */ + const void *wbuf; /* Pointer to buffer to write */ + } u; } H5D_io_info_t; /* Structure holding information about a chunk's selection for mapping */ @@ -183,8 +265,8 @@ typedef struct H5D_shared_t { hbool_t layout_dirty; /* Whether the layout info needs to be flushed to the file */ hid_t dcpl_id; /* dataset creation property id */ H5D_dcpl_cache_t dcpl_cache; /* Cached DCPL values */ - H5D_io_ops_t io_ops; /* I/O operations */ H5O_layout_t layout; /* data layout */ + const H5D_layout_ops_t *layout_ops; /* Pointer to data layout I/O operations */ hbool_t checked_filters;/* TRUE if dataset passes can_apply check */ /* Buffered/cached information for types of raw data storage*/ @@ -229,18 +311,21 @@ typedef struct H5D_chunk_map_t { H5S_sel_type msel_type; /* Selection type in memory */ H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */ + H5S_t *single_space; /* Dataspace for single chunk */ H5D_chunk_info_t *single_chunk_info; /* Pointer to single chunk's info */ hbool_t use_single; /* Whether I/O is on a single element */ + hsize_t last_index; /* Index of last chunk operated on */ H5D_chunk_info_t *last_chunk_info; /* Pointer to last chunk's info */ + hsize_t chunks[H5O_LAYOUT_NDIMS]; /* Number of chunks in each dimension */ hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Size of chunk in each dimension */ hsize_t down_chunks[H5O_LAYOUT_NDIMS]; /* "down" size of number of chunks in each dimension */ #ifdef H5_HAVE_PARALLEL - hsize_t total_chunks; /* Number of total chunks */ - hbool_t *select_chunk; /* store the information about whether this chunk is selected or not */ + hsize_t total_chunks; /* Number of chunks covered by dataspace */ + H5D_chunk_info_t **select_chunk; /* Store the information about whether this chunk is selected or not */ #endif /* H5_HAVE_PARALLEL */ } H5D_chunk_map_t; @@ -332,12 +417,34 @@ typedef struct { hsize_t size; /* Accumulated number of bytes for the selection */ } H5D_vlen_bufsize_t; +/* Raw data chunks are cached. Each entry in the cache is: */ +typedef struct H5D_rdcc_ent_t { + hbool_t locked; /*entry is locked in cache */ + hbool_t dirty; /*needs to be written to disk? */ + hsize_t offset[H5O_LAYOUT_NDIMS]; /*chunk name */ + size_t rd_count; /*bytes remaining to be read */ + size_t wr_count; /*bytes remaining to be written */ + size_t chunk_size; /*size of a chunk */ + size_t alloc_size; /*amount allocated for the chunk */ + uint8_t *chunk; /*the unfiltered chunk data */ + unsigned idx; /*index in hash table */ + struct H5D_rdcc_ent_t *next;/*next item in doubly-linked list */ + struct H5D_rdcc_ent_t *prev;/*previous item in doubly-linked list */ +} H5D_rdcc_ent_t; +typedef H5D_rdcc_ent_t *H5D_rdcc_ent_ptr_t; /* For free lists */ + /*****************************/ /* Package Private Variables */ /*****************************/ extern H5D_dxpl_cache_t H5D_def_dxpl_cache; +/* Storage layout classes */ +H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_CONTIG[1]; +H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_EFL[1]; +H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_COMPACT[1]; +H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_CHUNK[1]; + /******************************/ /* Package Private Prototypes */ @@ -361,54 +468,51 @@ H5_DLL herr_t H5D_vlen_get_buf_size(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, void *op_data); H5_DLL herr_t H5D_check_filters(H5D_t *dataset); H5_DLL herr_t H5D_set_extent(H5D_t *dataset, const hsize_t *size, hid_t dxpl_id); - -/* Functions that perform serial I/O operations */ -H5_DLL herr_t H5D_select_fscat(H5D_io_info_t *io_info, - const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, - haddr_t chunk_addr, void *chunk, const void *_buf); -H5_DLL size_t H5D_select_fgath(H5D_io_info_t *io_info, - const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, - haddr_t chunk_addr, void *chunk, void *buf); -H5_DLL herr_t H5D_select_mscat(const void *_tscat_buf, +H5_DLL herr_t H5D_get_dxpl_cache(hid_t dxpl_id, H5D_dxpl_cache_t **cache); + +/* Functions that perform direct serial I/O operations */ +H5_DLL herr_t H5D_select_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); +H5_DLL herr_t H5D_select_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); + +/* Functions that perform scatter-gather serial I/O operations */ +H5_DLL 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*/); -H5_DLL size_t H5D_select_mgath(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*/); -H5_DLL herr_t H5D_select_read(H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const H5S_t *file_space, const H5S_t *mem_space, - haddr_t addr, void *chunk/*in*/, void *buf/*out*/); -H5_DLL herr_t H5D_select_write(H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const H5S_t *file_space, const H5S_t *mem_space, - haddr_t addr, void *chunk/*in*/, const void *buf/*out*/); + const H5D_dxpl_cache_t *dxpl_cache, void *_buf); +H5_DLL 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); +H5_DLL 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); /* Functions that operate on contiguous storage */ H5_DLL herr_t H5D_contig_create(H5F_t *f, hid_t dxpl_id, H5O_layout_t *layout); H5_DLL herr_t H5D_contig_fill(H5D_t *dset, hid_t dxpl_id); H5_DLL haddr_t H5D_contig_get_addr(const H5D_t *dset); +H5_DLL herr_t H5D_contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *fm); +H5_DLL herr_t H5D_contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_chunk_map_t *fm); H5_DLL ssize_t H5D_contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED address, void UNUSED *pointer, void *buf); + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); H5_DLL ssize_t H5D_contig_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED address, void UNUSED *pointer, const void *buf); + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); H5_DLL herr_t H5D_contig_copy(H5F_t *f_src, const H5O_layout_t *layout_src, H5F_t *f_dst, H5O_layout_t *layout_dst, H5T_t *src_dtype, H5O_copy_t *cpy_info, hid_t dxpl_id); +/* Functions that operate on chunked dataset storage */ +H5_DLL hbool_t H5D_chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr); + /* Functions that operate on compact dataset storage */ H5_DLL herr_t H5D_compact_fill(H5D_t *dset, hid_t dxpl_id); -H5_DLL ssize_t H5D_compact_readvv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED addr, void UNUSED *pointer/*in*/, void *buf); -H5_DLL ssize_t H5D_compact_writevv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED addr, void UNUSED *pointer/*in*/, const void *buf); H5_DLL herr_t H5D_compact_copy(H5F_t *f_src, H5O_layout_t *layout_src, H5F_t *f_dst, H5O_layout_t *layout_dst, H5T_t *src_dtype, H5O_copy_t *cpy_info, hid_t dxpl_id); @@ -430,19 +534,11 @@ H5_DLL herr_t H5D_istore_initialize_by_extent(H5D_io_info_t *io_info); H5_DLL herr_t H5D_istore_update_cache(H5D_t *dset, hid_t dxpl_id); H5_DLL herr_t H5D_istore_dump_btree(H5F_t *f, hid_t dxpl_id, FILE *stream, unsigned ndims, haddr_t addr); -H5_DLL herr_t H5D_istore_chunkmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[],hsize_t down_chunks[] ); +H5_DLL herr_t H5D_istore_chunkmap(const H5D_io_info_t *io_info, + haddr_t chunk_addr[], const hsize_t down_chunks[]); #ifdef H5D_ISTORE_DEBUG H5_DLL herr_t H5D_istore_stats (H5D_t *dset, hbool_t headers); #endif /* H5D_ISTORE_DEBUG */ -H5_DLL ssize_t H5D_istore_readvv(const H5D_io_info_t *io_info, - size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], - hsize_t chunk_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, - size_t mem_len_arr[], hsize_t mem_offset_arr[], haddr_t chunk_addr, void *chunk, void *buf); -H5_DLL ssize_t H5D_istore_writevv(const H5D_io_info_t *io_info, - size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], - hsize_t chunk_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, - size_t mem_len_arr[], hsize_t mem_offset_arr[], haddr_t chunk_addr, void *chunk, - const void *buf); H5_DLL haddr_t H5D_istore_get_addr(const H5D_io_info_t *io_info, struct H5D_istore_ud1_t *_udata); H5_DLL herr_t H5D_istore_copy(H5F_t *f_src, H5O_layout_t *layout_src, @@ -452,17 +548,6 @@ H5_DLL void * H5D_istore_lock(const H5D_io_info_t *io_info, H5D_istore_ud1_t *ud hbool_t relax, unsigned *idx_hint/*in,out*/); H5_DLL herr_t H5D_istore_unlock(const H5D_io_info_t *io_info, hbool_t dirty, unsigned idx_hint, void *chunk, size_t naccessed); -H5_DLL hbool_t H5D_istore_if_load(const H5D_io_info_t *io_info, haddr_t caddr); - -/* Functions that operate on external file list (efl) storage */ -H5_DLL ssize_t H5D_efl_readvv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED addr, void UNUSED *pointer/*in*/, void *buf); -H5_DLL ssize_t H5D_efl_writevv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - haddr_t UNUSED addr, void UNUSED *pointer/*in*/, const void *buf); /* Functions that perform fill value operations on datasets */ H5_DLL herr_t H5D_fill(const void *fill, const H5T_t *fill_type, void *buf, @@ -485,36 +570,37 @@ H5_DLL herr_t H5D_fill_term(H5D_fill_buf_info_t *fb_info); #define H5Dmpio_DEBUG #endif /*H5Dmpio_DEBUG*/ #endif/*H5S_DEBUG*/ -/* MPI-IO function to read , it will select either regular or irregular read */ -H5_DLL herr_t H5D_mpio_select_read(H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const struct H5S_t *file_space, const struct H5S_t *mem_space, - haddr_t addr, void UNUSED *pointer/*in*/, void *buf/*out*/); - -/* MPI-IO function to read , it will select either regular or irregular read */ -H5_DLL herr_t H5D_mpio_select_write(H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const struct H5S_t *file_space, const struct H5S_t *mem_space, - haddr_t addr, void UNUSED *pointer/*in*/, const void *buf); - -/* MPI-IO function to handle contiguous collective IO */ -H5_DLL herr_t -H5D_contig_collective_io(H5D_io_info_t *io_info, - const H5S_t *file_space,const H5S_t *mem_space, - const void *_buf,hbool_t do_write); - -/* MPI-IO function to handle chunked collective IO */ -H5_DLL herr_t -H5D_chunk_collective_io(H5D_io_info_t * io_info, H5D_chunk_map_t *fm, const void*buf, - hbool_t do_write); +/* MPI-IO function to read, it will select either regular or irregular read */ +H5_DLL herr_t H5D_mpio_select_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); + +/* MPI-IO function to write, it will select either regular or irregular read */ +H5_DLL herr_t H5D_mpio_select_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); + +/* MPI-IO functions to handle contiguous collective IO */ +H5_DLL herr_t H5D_contig_collective_read(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, H5D_chunk_map_t *fm); +H5_DLL herr_t H5D_contig_collective_write(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, H5D_chunk_map_t *fm); + +/* MPI-IO functions to handle chunked collective IO */ +H5_DLL herr_t H5D_chunk_collective_read(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, H5D_chunk_map_t *fm); +H5_DLL herr_t H5D_chunk_collective_write(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, H5D_chunk_map_t *fm); + /* MPI-IO function to check if a direct I/O transfer is possible between * memory and the file */ -H5_DLL htri_t H5D_mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *mem_space, - const H5S_t *file_space, const H5T_path_t *tpath); - -#ifndef H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS -H5_DLL herr_t H5D_mpio_chunk_adjust_iomode(H5D_io_info_t *io_info, const H5D_chunk_map_t *fm); -#endif /* H5_MPI_SPECIAL_COLLECTIVE_IO_WORKS */ +H5_DLL htri_t H5D_mpio_opt_possible(const H5D_io_info_t *io_info, + const H5S_t *file_space, const H5S_t *mem_space, + const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm); #endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h index 410dc43..8cf134f 100644 --- a/src/H5Dprivate.h +++ b/src/H5Dprivate.h @@ -65,7 +65,6 @@ #define H5D_XFER_HYPER_VECTOR_SIZE_NAME "vec_size" /* Hyperslab vector size */ #ifdef H5_HAVE_PARALLEL #define H5D_XFER_IO_XFER_MODE_NAME "io_xfer_mode" /* I/O transfer mode */ -#define H5D_XFER_IO_XFER_OPT_MODE_NAME "io_xfer_opt_mode" /* I/O optimization transfer mode (using MPI-IO independent IO with file set view) */ #define H5D_XFER_MPIO_COLLECTIVE_OPT_NAME "mpio_collective_opt" /* Optimization of MPI-IO transfer mode */ #define H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME "mpio_chunk_opt_hard" #define H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME "mpio_chunk_opt_num" @@ -107,23 +106,6 @@ /* Typedef for dataset in memory (defined in H5Dpkg.h) */ typedef struct H5D_t H5D_t; -/* Typedef for dataset storage information */ -typedef struct { - hsize_t index; /* "Index" of chunk in dataset (must be first for TBBT routines) */ - hsize_t *offset; /* Chunk's coordinates in elements */ -} H5D_chunk_storage_t; - -typedef struct { - haddr_t dset_addr; /* Address of dataset in file */ - hsize_t dset_size; /* Total size of dataset in file */ -} H5D_contig_storage_t; - -typedef union H5D_storage_t { - H5O_efl_t efl; /* External file list information for dataset */ - H5D_chunk_storage_t chunk; /* Chunk information for dataset */ - H5D_contig_storage_t contig; /* Contiguous information for dataset */ -} H5D_storage_t; - /* Typedef for cached dataset transfer property list information */ typedef struct H5D_dxpl_cache_t { size_t max_temp_buf; /* Maximum temporary buffer size (H5D_XFER_MAX_TEMP_BUF_NAME) */ @@ -135,7 +117,7 @@ typedef struct H5D_dxpl_cache_t { size_t vec_size; /* Size of hyperslab vector (H5D_XFER_HYPER_VECTOR_SIZE_NAME) */ #ifdef H5_HAVE_PARALLEL H5FD_mpio_xfer_t xfer_mode; /* Parallel transfer for this request (H5D_XFER_IO_XFER_MODE_NAME) */ - H5FD_mpio_collective_opt_t xfer_opt_mode; /* Parallel transfer with independent IO or collective IO with this mode */ + H5FD_mpio_collective_opt_t coll_opt_mode; /* Parallel transfer with independent IO or collective IO with this mode */ #endif /*H5_HAVE_PARALLEL*/ H5Z_cb_t filter_cb; /* Filter callback function (H5D_XFER_FILTER_CB_NAME) */ H5Z_data_xform_t *data_xform_prop; /* Data transform prop (H5D_XFER_XFORM_NAME) */ @@ -163,8 +145,6 @@ H5_DLL H5O_loc_t *H5D_oloc(H5D_t *dataset); H5_DLL H5G_name_t *H5D_nameof(H5D_t *dataset); H5_DLL H5T_t *H5D_typeof(const H5D_t *dset); H5_DLL herr_t H5D_flush(const H5F_t *f, hid_t dxpl_id, unsigned flags); -H5_DLL herr_t H5D_get_dxpl_cache(hid_t dxpl_id, H5D_dxpl_cache_t **cache); -H5_DLL herr_t H5D_get_dxpl_cache_real(hid_t dxpl_id, H5D_dxpl_cache_t *cache); /* Functions that operate on vlen data */ H5_DLL herr_t H5D_vlen_reclaim(hid_t type_id, H5S_t *space, hid_t plist_id, 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() */ + diff --git a/src/H5Dselect.c b/src/H5Dselect.c index f08672f..947c81e 100644 --- a/src/H5Dselect.c +++ b/src/H5Dselect.c @@ -34,400 +34,37 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free Lists */ + /****************/ /* Local Macros */ /****************/ + /******************/ /* Local Typedefs */ /******************/ + /********************/ /* Local Prototypes */ /********************/ -/* Struct for holding the vectorized I/O operation buffers "loosely" */ -typedef struct { - enum { - H5S_SELECT_READ, /* Read selection */ - H5S_SELECT_WRITE /* Write selection */ - } op_type; - union { - void *rbuf; /* Buffer for read */ - const void *wbuf; /* Buffer to write */ - } u; -} H5D_select_buf_t; /*********************/ /* Package Variables */ /*********************/ + /*******************/ /* Local Variables */ /*******************/ /* Declare a free list to manage sequences of size_t */ -H5FL_SEQ_DEFINE_STATIC(size_t); +H5FL_SEQ_DEFINE(size_t); /* Declare a free list to manage sequences of hsize_t */ -H5FL_SEQ_DEFINE_STATIC(hsize_t); - - -/*------------------------------------------------------------------------- - * Function: H5D_select_fscat - * - * 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 - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_select_fscat (H5D_io_info_t *io_info, - const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, - haddr_t chunk_addr, void *chunk/*in*/, const void *_buf) -{ - const uint8_t *buf=_buf; /* Alias for pointer arithmetic */ - 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(H5D_select_fscat, FAIL); - - /* Check args */ - assert (io_info); - assert (space); - assert (iter); - assert (nelmts>0); - assert (_buf); - assert(TRUE==H5P_isa_class(io_info->dxpl_id,H5P_DATASET_XFER)); - - /* Allocate the vector I/O arrays */ - if(io_info->dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if((len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array"); - if((off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL) - 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,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((*io_info->ops.writevv)(io_info, nseq, &dset_curr_seq, len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off, chunk_addr, chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error"); - - /* Update buffer */ - buf += orig_mem_len; - - /* Decrement number of elements left to process */ - nelmts -= nelem; - } /* end while */ - -done: - if(io_info->dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if(len!=NULL) - H5FL_SEQ_FREE(size_t,len); - if(off!=NULL) - H5FL_SEQ_FREE(hsize_t,off); - } /* end if */ - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_select_fscat() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_select_fgath - * - * 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 - * - *------------------------------------------------------------------------- - */ -size_t -H5D_select_fgath (H5D_io_info_t *io_info, - const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, - haddr_t chunk_addr, void *chunk/*in*/, void *_buf/*out*/) -{ - uint8_t *buf=(uint8_t*)_buf; /* Alias for pointer arithmetic */ - 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(H5D_select_fgath, 0); - - /* Check args */ - assert (io_info); - assert (io_info->dset); - assert (io_info->store); - assert (space); - assert (iter); - assert (nelmts>0); - assert (_buf); - - /* Allocate the vector I/O arrays */ - if(io_info->dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if((len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array"); - if((off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL) - 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,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((*io_info->ops.readvv)(io_info, nseq, &dset_curr_seq, len, off, (size_t)1, - &mem_curr_seq, &mem_len, &mem_off, chunk_addr, chunk, buf) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error"); - - /* Update buffer */ - buf += orig_mem_len; - - /* Decrement number of elements left to process */ - nelmts -= nelem; - } /* end while */ - -done: - if(io_info->dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if(len!=NULL) - H5FL_SEQ_FREE(size_t,len); - if(off!=NULL) - H5FL_SEQ_FREE(hsize_t,off); - } /* end if */ - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_select_fgath() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_select_mscat - * - * 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_select_mscat (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_select_mscat, FAIL); - - /* Check args */ - assert (tscat_buf); - assert (space); - assert (iter); - assert (nelmts>0); - assert (buf); - - /* Allocate the vector I/O arrays */ - if(dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if((len = H5FL_SEQ_MALLOC(size_t,dxpl_cache->vec_size))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array"); - if((off = H5FL_SEQ_MALLOC(hsize_t,dxpl_cache->vec_size))==NULL) - 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_seqvec_size != H5D_IO_VECTOR_SIZE) { - if(len!=NULL) - H5FL_SEQ_FREE(size_t,len); - if(off!=NULL) - H5FL_SEQ_FREE(hsize_t,off); - } /* end if */ - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_select_mscat() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_select_mgath - * - * 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 - * - *------------------------------------------------------------------------- - */ -size_t -H5D_select_mgath (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(H5D_select_mgath, 0); - - /* Check args */ - assert (buf); - assert (space); - assert (iter); - assert (nelmts>0); - assert (tgath_buf); - - /* Allocate the vector I/O arrays */ - if(dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if((len = H5FL_SEQ_MALLOC(size_t,dxpl_cache->vec_size))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array"); - if((off = H5FL_SEQ_MALLOC(hsize_t,dxpl_cache->vec_size))==NULL) - 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_seqvec_size != H5D_IO_VECTOR_SIZE) { - if(len!=NULL) - H5FL_SEQ_FREE(size_t,len); - if(off!=NULL) - H5FL_SEQ_FREE(hsize_t,off); - } /* end if */ - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_select_mgath() */ /*------------------------------------------------------------------------- @@ -443,11 +80,8 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D_select_io(H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const H5S_t *file_space, const H5S_t *mem_space, - haddr_t addr, void *chunk/*in*/, - const H5D_select_buf_t *io_buf) +H5D_select_io(const H5D_io_info_t *io_info, size_t elmt_size, + size_t nelmts, const H5S_t *file_space, const H5S_t *mem_space) { H5S_sel_iter_t mem_iter; /* Memory selection iteration info */ hbool_t mem_iter_init = 0; /* Memory selection iteration info has been initialized */ @@ -475,10 +109,10 @@ H5D_select_io(H5D_io_info_t *io_info, HDassert(io_info->dset); HDassert(io_info->store); HDassert(TRUE == H5P_isa_class(io_info->dxpl_id, H5P_DATASET_XFER)); - HDassert(io_buf->u.rbuf); + HDassert(io_info->u.rbuf); /* Allocate the vector I/O arrays */ - if(io_info->dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { + if(io_info->dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { if(NULL == (mem_len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array") if(NULL == (mem_off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))) @@ -511,19 +145,17 @@ H5D_select_io(H5D_io_info_t *io_info, *file_len = *mem_len = elmt_size; /* Perform I/O on memory and file sequences */ - if(io_buf->op_type == H5S_SELECT_READ) { - if((tmp_file_len = (*io_info->ops.readvv)(io_info, + if(io_info->op_type == H5D_IO_OP_READ) { + if((tmp_file_len = (*io_info->layout_ops.readvv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, - mem_nseq, &curr_mem_seq, mem_len, mem_off, - addr, chunk, io_buf->u.rbuf)) < 0) + mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") } /* end if */ else { - HDassert(io_buf->op_type == H5S_SELECT_WRITE); - if((tmp_file_len = (*io_info->ops.writevv)(io_info, + HDassert(io_info->op_type == H5D_IO_OP_WRITE); + if((tmp_file_len = (*io_info->layout_ops.writevv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, - mem_nseq, &curr_mem_seq, mem_len, mem_off, - addr, chunk, io_buf->u.wbuf)) < 0) + mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") } /* end else */ @@ -571,19 +203,17 @@ H5D_select_io(H5D_io_info_t *io_info, } /* end if */ /* Perform I/O on memory and file sequences */ - if(io_buf->op_type == H5S_SELECT_READ) { - if((tmp_file_len = (*io_info->ops.readvv)(io_info, + if(io_info->op_type == H5D_IO_OP_READ) { + if((tmp_file_len = (*io_info->layout_ops.readvv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, - mem_nseq, &curr_mem_seq, mem_len, mem_off, - addr, chunk, io_buf->u.rbuf)) < 0) + mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") } /* end if */ else { - HDassert(io_buf->op_type == H5S_SELECT_WRITE); - if((tmp_file_len = (*io_info->ops.writevv)(io_info, + HDassert(io_info->op_type == H5D_IO_OP_WRITE); + if((tmp_file_len = (*io_info->layout_ops.writevv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, - mem_nseq, &curr_mem_seq, mem_len, mem_off, - addr, chunk, io_buf->u.wbuf)) < 0) + mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") } /* end else */ @@ -604,17 +234,15 @@ done: if(H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") - /* Free vector arrays */ - if(io_info->dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) { - if(file_len != NULL) - H5FL_SEQ_FREE(size_t, file_len); - if(file_off != NULL) - H5FL_SEQ_FREE(hsize_t, file_off); - if(mem_len != NULL) - H5FL_SEQ_FREE(size_t, mem_len); - if(mem_off != NULL) - H5FL_SEQ_FREE(hsize_t, mem_off); - } /* end if */ + /* Release vector arrays, if allocated */ + if(file_len && file_len != _file_len) + H5FL_SEQ_FREE(size_t, file_len); + if(file_off && file_off != _file_off) + H5FL_SEQ_FREE(hsize_t, file_off); + if(mem_len && mem_len != _mem_len) + H5FL_SEQ_FREE(size_t, mem_len); + if(mem_off && mem_off != _mem_off) + H5FL_SEQ_FREE(hsize_t, mem_off); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_select_io() */ @@ -633,23 +261,17 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D_select_read(H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const H5S_t *file_space, const H5S_t *mem_space, - haddr_t addr, void *chunk/*in*/, - void *buf/*out*/) +H5D_select_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) { - H5D_select_buf_t io_buf; /* Selection I/O operation to perform */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5D_select_read, FAIL) - /* Construct proper I/O operation */ - io_buf.op_type = H5S_SELECT_READ; - io_buf.u.rbuf = buf; - /* Call generic selection operation */ - if(H5D_select_io(io_info, nelmts, elmt_size, file_space, mem_space, addr, chunk, &io_buf) < 0) + H5_CHECK_OVERFLOW(nelmts, hsize_t, size_t); + if(H5D_select_io(io_info, type_info->src_type_size, (size_t)nelmts, + file_space, mem_space) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") done: @@ -670,23 +292,17 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D_select_write(H5D_io_info_t *io_info, - size_t nelmts, size_t elmt_size, - const H5S_t *file_space, const H5S_t *mem_space, - haddr_t addr, void *chunk/*in*/, - const void *buf/*out*/) +H5D_select_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) { - H5D_select_buf_t io_buf; /* Selection I/O operation to perform */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5D_select_write, FAIL) - /* Construct proper I/O operation */ - io_buf.op_type = H5S_SELECT_WRITE; - io_buf.u.wbuf = buf; - /* Call generic selection operation */ - if(H5D_select_io(io_info, nelmts, elmt_size, file_space, mem_space, addr, chunk, &io_buf) < 0) + H5_CHECK_OVERFLOW(nelmts, hsize_t, size_t); + if(H5D_select_io(io_info, type_info->dst_type_size, (size_t)nelmts, + file_space, mem_space) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") done: diff --git a/src/H5FDmpi.h b/src/H5FDmpi.h index 90aa0e2..0384018 100644 --- a/src/H5FDmpi.h +++ b/src/H5FDmpi.h @@ -42,14 +42,14 @@ typedef enum H5FD_mpio_xfer_t { H5FD_MPIO_COLLECTIVE } H5FD_mpio_xfer_t; -/* Type of I/O for data transfer properties */ +/* Type of chunked dataset I/O */ typedef enum H5FD_mpio_chunk_opt_t { H5FD_MPIO_CHUNK_DEFAULT = 0, H5FD_MPIO_CHUNK_ONE_IO, /*zero is the default*/ H5FD_MPIO_CHUNK_MULTI_IO } H5FD_mpio_chunk_opt_t; -/* Type of I/O for data transfer properties */ +/* Type of collective I/O */ typedef enum H5FD_mpio_collective_opt_t { H5FD_MPIO_COLLECTIVE_IO = 0, H5FD_MPIO_INDIVIDUAL_IO /*zero is the default*/ diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c index c8087bb..89a8637 100644 --- a/src/H5FDmpio.c +++ b/src/H5FDmpio.c @@ -572,15 +572,15 @@ H5Pset_dxpl_mpio_collective_opt(hid_t dxpl_id, H5FD_mpio_collective_opt_t opt_mo HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl") /* Set the transfer mode */ - if (H5P_set(plist,H5D_XFER_MPIO_COLLECTIVE_OPT_NAME,&opt_mode)<0) + if(H5P_set(plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &opt_mode) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value") /* Initialize driver-specific properties */ - ret_value= H5P_set_driver(plist, H5FD_MPIO, NULL); + ret_value = H5P_set_driver(plist, H5FD_MPIO, NULL); done: FUNC_LEAVE_API(ret_value) -} +} /* end H5Pset_dxpl_mpio_collective_opt() */ /*------------------------------------------------------------------------- @@ -1413,8 +1413,8 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t dxpl_id, haddr_t add int type_size; /* MPI datatype used for I/O's size */ int io_size; /* Actual number of bytes requested */ H5P_genplist_t *plist; /* Property list pointer */ - unsigned use_view_this_time=0; - herr_t ret_value=SUCCEED; + hbool_t use_view_this_time = FALSE; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5FD_mpio_read, FAIL) @@ -1464,7 +1464,7 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t dxpl_id, haddr_t add MPI_Datatype file_type; /* Remember that views are used */ - use_view_this_time=TRUE; + use_view_this_time = TRUE; /* prepare for a full-blown xfer using btype, ftype, and disp */ if(H5P_get(plist,H5FD_MPI_XFER_MEM_MPI_TYPE_NAME,&buf_type)<0) @@ -1487,9 +1487,9 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t dxpl_id, haddr_t add } /* end if */ /* Read the data. */ - if (use_view_this_time) { + if(use_view_this_time) { H5FD_mpio_collective_opt_t coll_opt_mode; - H5FD_mpio_collective_opt_t xfer_opt_mode; + #ifdef H5FDmpio_DEBUG if (H5FD_mpio_Debug[(int)'t']) fprintf(stdout, "H5FD_mpio_read: using MPIO collective mode\n"); @@ -1497,28 +1497,23 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t dxpl_id, haddr_t add /* Peek the collective_opt property to check whether the application wants to do IO individually. */ coll_opt_mode = (H5FD_mpio_collective_opt_t)H5P_peek_unsigned(plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME); - /* Peek the xfer_opt_mode property to check whether the application wants to do IO individually. */ - xfer_opt_mode = (H5FD_mpio_collective_opt_t)H5P_peek_unsigned(plist, H5D_XFER_IO_XFER_OPT_MODE_NAME); - - if(coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO && xfer_opt_mode == H5FD_MPIO_COLLECTIVE_IO) { + if(coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO) { #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "H5FD_mpio_read: doing MPI collective IO\n"); + if(H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_read: doing MPI collective IO\n"); #endif -/* Temporarily change to read_at_all - if (MPI_SUCCESS!= (mpi_code=MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat )))*/ - if (MPI_SUCCESS!= (mpi_code=MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat ))) - HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code) - } + if(MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code) + } /* end if */ else { #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "H5FD_mpio_read: doing MPI independent IO\n"); + if(H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_read: doing MPI independent IO\n"); #endif - if (MPI_SUCCESS!= (mpi_code=MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat ))) - HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) - } + if(MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) + } /* end else */ /* * Reset the file view when we used MPI derived types @@ -1700,7 +1695,7 @@ H5FD_mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, int size_i, bytes_written; int type_size; /* MPI datatype used for I/O's size */ int io_size; /* Actual number of bytes requested */ - unsigned use_view_this_time=0; + hbool_t use_view_this_time = FALSE; H5P_genplist_t *plist; /* Property list pointer */ herr_t ret_value=SUCCEED; @@ -1718,26 +1713,25 @@ H5FD_mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, assert(buf); /* Portably initialize MPI status variable */ - HDmemset(&mpi_stat,0,sizeof(MPI_Status)); + HDmemset(&mpi_stat, 0, sizeof(MPI_Status)); /* some numeric conversions */ - if (H5FD_mpi_haddr_to_MPIOff(addr, &mpi_off)<0) + if(H5FD_mpi_haddr_to_MPIOff(addr, &mpi_off) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from haddr to MPI off") size_i = (int)size; - if ((hsize_t)size_i != size) + if((hsize_t)size_i != size) HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from size to size_i") #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'w']) - fprintf(stdout, "in H5FD_mpio_write mpi_off=%ld size_i=%d\n", - (long)mpi_off, size_i); + if(H5FD_mpio_Debug[(int)'w']) + fprintf(stdout, "in H5FD_mpio_write mpi_off=%ld size_i=%d\n", (long)mpi_off, size_i); #endif /* Obtain the data transfer properties */ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") - if(type==H5FD_MEM_DRAW) { + if(type == H5FD_MEM_DRAW) { H5FD_mpio_xfer_t xfer_mode; /* I/O tranfer mode */ /* Obtain the data transfer properties */ @@ -1749,114 +1743,71 @@ H5FD_mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, * us to test that btype=ftype=MPI_BYTE (or even MPI_TYPE_NULL, which * could mean "use MPI_BYTE" by convention). */ - if(xfer_mode==H5FD_MPIO_COLLECTIVE) { + if(xfer_mode == H5FD_MPIO_COLLECTIVE) { MPI_Datatype file_type; /* Remember that views are used */ - use_view_this_time=TRUE; + use_view_this_time = TRUE; /* prepare for a full-blown xfer using btype, ftype, and disp */ - if(H5P_get(plist,H5FD_MPI_XFER_MEM_MPI_TYPE_NAME,&buf_type)<0) + if(H5P_get(plist, H5FD_MPI_XFER_MEM_MPI_TYPE_NAME, &buf_type) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O type property") - if(H5P_get(plist,H5FD_MPI_XFER_FILE_MPI_TYPE_NAME,&file_type)<0) + if(H5P_get(plist, H5FD_MPI_XFER_FILE_MPI_TYPE_NAME, &file_type) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O type property") /* * Set the file view when we are using MPI derived types */ /*OKAY: CAST DISCARDS CONST QUALIFIER*/ - if (MPI_SUCCESS != (mpi_code=MPI_File_set_view(file->f, mpi_off, MPI_BYTE, file_type, H5FD_mpi_native_g, file->info))) + if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, mpi_off, MPI_BYTE, file_type, H5FD_mpi_native_g, file->info))) HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code) /* When using types, use the address as the displacement for * MPI_File_set_view and reset the address for the read to zero */ - mpi_off=0; + mpi_off = 0; } /* end if */ } /* end if */ else { - unsigned block_before_meta_write=0; /* Whether to block before a metadata write */ - - /* Check if we need to syncronize all processes before attempting metadata write - * (Prevents race condition where the process writing the metadata goes ahead - * and writes the metadata to the file before all the processes have - * read the data, "transmitting" data from the "future" to the reading - * process. -QAK ) - * - * The only time we don't want to block before a metadata write is when - * we are flushing out a bunch of metadata. Then, we block before the - * first write and don't block for further writes in the sequence. - */ - if(H5P_exist_plist(plist,H5AC_BLOCK_BEFORE_META_WRITE_NAME)>0) - if(H5P_get(plist,H5AC_BLOCK_BEFORE_META_WRITE_NAME,&block_before_meta_write)<0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get H5AC property") - -#if 0 /* JRM */ - /* The metadata cache now only writes from process 0, which makes - * this synchronization incorrect. I'm leaving this code commented - * out instead of deleting it to remind us that we should re-write - * this function so that a metadata write from any other process - * should flag an error. - * -- JRM 9/1/05 - */ - if(block_before_meta_write) - if (MPI_SUCCESS!= (mpi_code=MPI_Barrier(file->comm))) - HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code) -#endif /* JRM */ - - /* Only one process will do the actual write if all procs in comm write same metadata */ - if (file->mpi_rank != H5_PAR_META_WRITE) { -#ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'w']) { - fprintf(stdout, - " proc %d: in H5FD_mpio_write (write omitted)\n", - file->mpi_rank ); - } -#endif + /* Only one process can do the actual metadata write */ + if(file->mpi_rank != H5_PAR_META_WRITE) +#ifdef LATER + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "can't write metadata from non-zero rank") +#else /* LATER */ HGOTO_DONE(SUCCEED) /* skip the actual write */ - } /* end if */ +#endif /* LATER */ } /* end if */ /* Write the data. */ - if (use_view_this_time) { - H5FD_mpio_collective_opt_t coll_opt_mode; - H5FD_mpio_collective_opt_t xfer_opt_mode; + if(use_view_this_time) { + H5FD_mpio_collective_opt_t coll_opt_mode; + #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) + if(H5FD_mpio_Debug[(int)'t']) fprintf(stdout, "H5FD_mpio_write: using MPIO collective mode\n"); #endif /* Peek the collective_opt property to check whether the application wants to do IO individually. */ - coll_opt_mode = (H5FD_mpio_collective_opt_t)H5P_peek_unsigned(plist,H5D_XFER_MPIO_COLLECTIVE_OPT_NAME); - - /* Peek the xfer_opt_mode property to check whether the application wants to do IO individually. */ - xfer_opt_mode = (H5FD_mpio_collective_opt_t)H5P_peek_unsigned(plist,H5D_XFER_IO_XFER_OPT_MODE_NAME); + coll_opt_mode = (H5FD_mpio_collective_opt_t)H5P_peek_unsigned(plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME); /*OKAY: CAST DISCARDS CONST QUALIFIER*/ - if(coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO && xfer_opt_mode == H5FD_MPIO_COLLECTIVE_IO ) { + if(coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO) { #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "H5FD_mpio_write: doing MPI collective IO\n"); + if(H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_write: doing MPI collective IO\n"); #endif - /* Temporarily change to _at -if (MPI_SUCCESS != (mpi_code=MPI_File_write_at_all(file->f, mpi_off, (void*)buf, size_i, buf_type, &mpi_stat))) -*/ - if (MPI_SUCCESS != (mpi_code=MPI_File_write_at_all(file->f, mpi_off, (void*)buf, size_i, buf_type, &mpi_stat))) - HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at_all failed", mpi_code) - } + if(MPI_SUCCESS != (mpi_code = MPI_File_write_at_all(file->f, mpi_off, (void*)buf, size_i, buf_type, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at_all failed", mpi_code) + } /* end if */ else { #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "H5FD_mpio_write: doing MPI independent IO\n"); + if(H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_write: doing MPI independent IO\n"); #endif - - if (MPI_SUCCESS != (mpi_code=MPI_File_write_at(file->f, mpi_off, (void*)buf, size_i, buf_type, &mpi_stat))) - HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at failed", mpi_code) - } - + if(MPI_SUCCESS != (mpi_code = MPI_File_write_at(file->f, mpi_off, (void*)buf, size_i, buf_type, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at failed", mpi_code) + } /* end else */ - /* - * Reset the file view when we used MPI derived types - */ + /* Reset the file view when we used MPI derived types */ /*OKAY: CAST DISCARDS CONST QUALIFIER*/ if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, (MPI_Offset)0, MPI_BYTE, MPI_BYTE, H5FD_mpi_native_g, file->info))) HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code) @@ -1872,48 +1823,31 @@ if (MPI_SUCCESS != (mpi_code=MPI_File_write_at_all(file->f, mpi_off, (void*)buf, * datatype in this call though... (We aren't because using it causes * the LANL "qsc" machine to dump core - 12/19/03) - QAK] */ - if (MPI_SUCCESS != (mpi_code=MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_written))) + if(MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_written))) HMPI_GOTO_ERROR(FAIL, "MPI_Get_elements failed", mpi_code) /* Get the type's size */ - if (MPI_SUCCESS != (mpi_code=MPI_Type_size(buf_type,&type_size))) + if(MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size))) HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code) /* Compute the actual number of bytes requested */ - io_size=type_size*size_i; + io_size = type_size * size_i; /* Check for write failure */ - if (bytes_written != io_size) + if(bytes_written != io_size) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") /* Forget the EOF value (see H5FD_mpio_get_eof()) --rpm 1999-08-06 */ file->eof = HADDR_UNDEF; done: - -#if 0 /* JRM */ - /* Since metadata writes are now done by process 0 only, this broadcast - * is no longer needed. I leave it in and commented out to remind us - * that we need to re-work this function to reflect this reallity. - * - * -- JRM 9/1/05 - */ - /* if only one process writes, need to broadcast the ret_value to - * other processes - */ - if(type != H5FD_MEM_DRAW) { - if(MPI_SUCCESS != (mpi_code = MPI_Bcast(&ret_value, (int)sizeof(ret_value), MPI_BYTE, H5_PAR_META_WRITE, file->comm))) - HMPI_DONE_ERROR(FAIL, "MPI_Bcast failed", mpi_code) - } /* end if */ -#endif /* JRM */ - #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) + if(H5FD_mpio_Debug[(int)'t']) fprintf(stdout, "proc %d: Leaving H5FD_mpio_write with ret_value=%d\n", file->mpi_rank, ret_value ); #endif FUNC_LEAVE_NOAPI(ret_value) -} +} /* end H5FD_mpio_write() */ /*------------------------------------------------------------------------- diff --git a/src/H5Pdxpl.c b/src/H5Pdxpl.c index 6affcad..8bc263a 100644 --- a/src/H5Pdxpl.c +++ b/src/H5Pdxpl.c @@ -90,9 +90,6 @@ /* Definitions for I/O transfer mode property */ #define H5D_XFER_IO_XFER_MODE_SIZE sizeof(H5FD_mpio_xfer_t) #define H5D_XFER_IO_XFER_MODE_DEF H5FD_MPIO_INDEPENDENT -/* Definitions for I/O optimization transfer mode property(using MPI-IO independent IO with file set view) */ -#define H5D_XFER_IO_XFER_OPT_MODE_SIZE sizeof(H5FD_mpio_collective_opt_t) -#define H5D_XFER_IO_XFER_OPT_MODE_DEF H5FD_MPIO_COLLECTIVE_IO /* Definitions for optimization of MPI-IO transfer mode property */ #define H5D_XFER_MPIO_COLLECTIVE_OPT_SIZE sizeof(H5FD_mpio_collective_opt_t) #define H5D_XFER_MPIO_COLLECTIVE_OPT_DEF H5FD_MPIO_COLLECTIVE_IO @@ -199,7 +196,6 @@ H5P_dxfr_reg_prop(H5P_genclass_t *pclass) size_t def_hyp_vec_size = H5D_XFER_HYPER_VECTOR_SIZE_DEF; /* Default value for vector size */ #ifdef H5_HAVE_PARALLEL H5FD_mpio_xfer_t def_io_xfer_mode = H5D_XFER_IO_XFER_MODE_DEF; /* Default value for I/O transfer mode */ - H5FD_mpio_collective_opt_t def_io_xfer_opt_mode = H5D_XFER_IO_XFER_OPT_MODE_DEF; H5FD_mpio_chunk_opt_t def_mpio_chunk_opt_mode = H5D_XFER_MPIO_CHUNK_OPT_HARD_DEF; H5FD_mpio_collective_opt_t def_mpio_collective_opt_mode = H5D_XFER_MPIO_COLLECTIVE_OPT_DEF; unsigned def_mpio_chunk_opt_num = H5D_XFER_MPIO_CHUNK_OPT_NUM_DEF; @@ -265,8 +261,6 @@ H5P_dxfr_reg_prop(H5P_genclass_t *pclass) /* Register the I/O transfer mode property */ if(H5P_register(pclass, H5D_XFER_IO_XFER_MODE_NAME, H5D_XFER_IO_XFER_MODE_SIZE, &def_io_xfer_mode, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") - if(H5P_register(pclass, H5D_XFER_IO_XFER_OPT_MODE_NAME, H5D_XFER_IO_XFER_OPT_MODE_SIZE, &def_io_xfer_opt_mode, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") if(H5P_register(pclass, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, H5D_XFER_MPIO_COLLECTIVE_OPT_SIZE, &def_mpio_collective_opt_mode, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") if(H5P_register(pclass, H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME, H5D_XFER_MPIO_CHUNK_OPT_HARD_SIZE, &def_mpio_chunk_opt_mode, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) diff --git a/src/H5S.c b/src/H5S.c index 8a58cba..4996f1f 100644 --- a/src/H5S.c +++ b/src/H5S.c @@ -45,18 +45,6 @@ static herr_t H5S_encode(H5S_t *obj, unsigned char *buf, size_t *nalloc); static H5S_t *H5S_decode(const unsigned char *buf); static htri_t H5S_extent_equal(const H5S_t *ds1, const H5S_t *ds2); -#ifdef H5S_DEBUG -/* Names of the selection names, for debugging */ -static const char *H5S_sel_names[]={ - "none", "point", "hyperslab", "all" -}; - -/* The path table, variable length */ -static H5S_iostats_t **H5S_iostats_g = NULL; -static size_t H5S_aiostats_g = 0; /*entries allocated*/ -static size_t H5S_niostats_g = 0; /*entries used*/ -#endif /* H5S_DEBUG */ - #ifdef H5_HAVE_PARALLEL /* Global vars whose value can be set from environment variable also */ hbool_t H5S_mpi_opt_types_g = TRUE; @@ -87,9 +75,9 @@ DESCRIPTION static herr_t H5S_init_interface(void) { - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5S_init_interface); + FUNC_ENTER_NOAPI_NOINIT(H5S_init_interface) /* Initialize the atom group for the file IDs */ if(H5I_register_type(H5I_DATASPACE, (size_t)H5I_DATASPACEID_HASHSIZE, H5S_RESERVED_ATOMS, (H5I_free_t)H5S_close) < 0) @@ -105,8 +93,8 @@ H5S_init_interface(void) #endif /* H5_HAVE_PARALLEL */ done: - FUNC_LEAVE_NOAPI(ret_value); -} + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_init_interface() */ /*-------------------------------------------------------------------------- @@ -129,156 +117,26 @@ done: int H5S_term_interface(void) { - int n=0; -#ifdef H5S_DEBUG - size_t i; - int j, nprints=0; - H5S_iostats_t *path=NULL; - char buf[256]; -#endif /* H5S_DEBUG */ - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5S_term_interface); - - if (H5_interface_initialize_g) { - if ((n=H5I_nmembers(H5I_DATASPACE))) { - H5I_clear_type(H5I_DATASPACE, FALSE); - } else { -#ifdef H5S_DEBUG - /* - * Print statistics about each conversion path. - */ - if (H5DEBUG(S)) { - for (i=0; istats[j].gath_ncalls && - 0==path->stats[j].scat_ncalls && - 0==path->stats[j].bkg_ncalls && - 0==path->stats[j].read_ncalls && - 0==path->stats[j].write_ncalls) { - continue; - } - if (0==nprints++) { - fprintf(H5DEBUG(S), "H5S: data space conversion " - "statistics:\n"); - fprintf(H5DEBUG(S), - " %-16s %10s %10s %8s %8s %8s %10s\n", - "Memory <> File", "Bytes", "Calls", - "User", "System", "Elapsed", "Bandwidth"); - fprintf(H5DEBUG(S), - " %-16s %10s %10s %8s %8s %8s %10s\n", - "--------------", "-----", "-----", - "----", "------", "-------", "---------"); - } - - /* Summary */ - sprintf(buf, "%s %c %s", - H5S_sel_names[path->mtype], 0==j?'>':'<', H5S_sel_names[path->ftype]); - fprintf(H5DEBUG(S), " %-16s\n", buf); - - /* Gather */ - if (path->stats[j].gath_ncalls) { - H5_bandwidth(buf, - (double)(path->stats[j].gath_nbytes), - path->stats[j].gath_timer.etime); - HDfprintf(H5DEBUG(S), - " %16s %10Hu %10Hu %8.2f %8.2f %8.2f " - "%10s\n", "gather", - path->stats[j].gath_nbytes, - path->stats[j].gath_ncalls, - path->stats[j].gath_timer.utime, - path->stats[j].gath_timer.stime, - path->stats[j].gath_timer.etime, - buf); - } - - /* Scatter */ - if (path->stats[j].scat_ncalls) { - H5_bandwidth(buf, - (double)(path->stats[j].scat_nbytes), - path->stats[j].scat_timer.etime); - HDfprintf(H5DEBUG(S), - " %16s %10Hu %10Hu %8.2f %8.2f %8.2f " - "%10s\n", "scatter", - path->stats[j].scat_nbytes, - path->stats[j].scat_ncalls, - path->stats[j].scat_timer.utime, - path->stats[j].scat_timer.stime, - path->stats[j].scat_timer.etime, - buf); - } - - /* Background */ - if (path->stats[j].bkg_ncalls) { - H5_bandwidth(buf, - (double)(path->stats[j].bkg_nbytes), - path->stats[j].bkg_timer.etime); - HDfprintf(H5DEBUG(S), - " %16s %10Hu %10Hu %8.2f %8.2f %8.2f " - "%10s\n", "background", - path->stats[j].bkg_nbytes, - path->stats[j].bkg_ncalls, - path->stats[j].bkg_timer.utime, - path->stats[j].bkg_timer.stime, - path->stats[j].bkg_timer.etime, - buf); - } - - /* Read */ - if (path->stats[j].read_ncalls) { - H5_bandwidth(buf, - (double)(path->stats[j].read_nbytes), - path->stats[j].read_timer.etime); - HDfprintf(H5DEBUG(S), - " %16s %10Hu %10Hu %8.2f %8.2f %8.2f " - "%10s\n", "read", - path->stats[j].read_nbytes, - path->stats[j].read_ncalls, - path->stats[j].read_timer.utime, - path->stats[j].read_timer.stime, - path->stats[j].read_timer.etime, - buf); - } - - /* Write */ - if (path->stats[j].write_ncalls) { - H5_bandwidth(buf, - (double)(path->stats[j].write_nbytes), - path->stats[j].write_timer.etime); - HDfprintf(H5DEBUG(S), - " %16s %10Hu %10Hu %8.2f %8.2f %8.2f " - "%10s\n", "write", - path->stats[j].write_nbytes, - path->stats[j].write_ncalls, - path->stats[j].write_timer.utime, - path->stats[j].write_timer.stime, - path->stats[j].write_timer.etime, - buf); - } - } - } - } -#endif /* H5S_DEBUG */ + int n = 0; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5S_term_interface) + if(H5_interface_initialize_g) { + if((n = H5I_nmembers(H5I_DATASPACE))) { + H5I_clear_type(H5I_DATASPACE, FALSE); + } /* end if */ + else { /* Free data types */ H5I_dec_type_ref(H5I_DATASPACE); -#ifdef H5S_DEBUG - /* Clear/free conversion table */ - for (i=0; iftype==H5S_GET_SELECT_TYPE(file_space) && - H5S_iostats_g[u]->mtype==H5S_GET_SELECT_TYPE(mem_space)) - HGOTO_DONE(H5S_iostats_g[u]); - - /* - * The path wasn't found. Create a new path. - */ - if (NULL==(path = H5MM_calloc(sizeof(*path)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for data space conversion path") - - /* Initialize file & memory conversion functions */ - path->ftype = H5S_GET_SELECT_TYPE(file_space); - path->mtype = H5S_GET_SELECT_TYPE(mem_space); - - /* - * Add the new path to the table. - */ - if (H5S_niostats_g>=H5S_aiostats_g) { - size_t n = MAX(10, 2*H5S_aiostats_g); - H5S_iostats_t **p = H5MM_realloc(H5S_iostats_g, n*sizeof(H5S_iostats_g[0])); - - if (NULL==p) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for data space conversion path table") - H5S_aiostats_g = n; - H5S_iostats_g = p; - } /* end if */ - H5S_iostats_g[H5S_niostats_g++] = path; - - /* Set the return value */ - ret_value=path; - -done: - if(ret_value==NULL) { - if(path!=NULL) - H5MM_xfree(path); - } /* end if */ - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5S_find() */ -#endif /* H5S_DEBUG */ - /*------------------------------------------------------------------------- * Function: H5Screate_simple diff --git a/src/H5Smpio.c b/src/H5Smpio.c index cc89b49..725b8fc 100644 --- a/src/H5Smpio.c +++ b/src/H5Smpio.c @@ -123,7 +123,7 @@ H5S_mpio_all_type( const H5S_t *space, size_t elmt_size, *new_type = MPI_BYTE; H5_ASSIGN_OVERFLOW(*count, total_bytes, hsize_t, size_t); *extra_offset = 0; - *is_derived_type = 0; + *is_derived_type = FALSE; done: FUNC_LEAVE_NOAPI(ret_value); @@ -163,7 +163,7 @@ H5S_mpio_none_type( const H5S_t UNUSED *space, size_t UNUSED elmt_size, *new_type = MPI_BYTE; *count = 0; *extra_offset = 0; - *is_derived_type = 0; + *is_derived_type = FALSE; FUNC_LEAVE_NOAPI(SUCCEED); } /* H5S_mpio_none_type() */ @@ -456,7 +456,7 @@ H5S_mpio_hyper_type( const H5S_t *space, size_t elmt_size, /* fill in the remaining return values */ *count = 1; /* only have to move one of these suckers! */ *extra_offset = 0; - *is_derived_type = 1; + *is_derived_type = TRUE; HGOTO_DONE(SUCCEED); empty: @@ -464,7 +464,7 @@ empty: *new_type = MPI_BYTE; *count = 0; *extra_offset = 0; - *is_derived_type = 0; + *is_derived_type = FALSE; done: /* Release selection iterator */ @@ -475,7 +475,7 @@ done: #ifdef H5S_DEBUG if(H5DEBUG(S)){ - HDfprintf(H5DEBUG(S), "Leave %s, count=%ld is_derived_type=%d\n", + HDfprintf(H5DEBUG(S), "Leave %s, count=%ld is_derived_type=%t\n", FUNC, *count, *is_derived_type ); } #endif @@ -556,7 +556,7 @@ H5S_mpio_span_hyper_type( const H5S_t *space, /* fill in the remaining return values */ *count = 1; *extra_offset = 0; - *is_derived_type = 1; + *is_derived_type = TRUE; HGOTO_DONE(SUCCEED); @@ -565,7 +565,7 @@ empty: *new_type = MPI_BYTE; *count = 0; *extra_offset = 0; - *is_derived_type = 0; + *is_derived_type = FALSE; done: FUNC_LEAVE_NOAPI(ret_value); diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index bd27f09..8744872 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -115,31 +115,6 @@ typedef struct H5S_sel_iter_t { } u; } H5S_sel_iter_t; -#ifdef H5S_DEBUG -typedef struct H5S_iostats_t { - H5S_sel_type ftype; - H5S_sel_type mtype; - - struct { - H5_timer_t scat_timer; /*time spent scattering */ - hsize_t scat_nbytes; /*scatter throughput */ - hsize_t scat_ncalls; /*number of calls */ - H5_timer_t gath_timer; /*time spent gathering */ - hsize_t gath_nbytes; /*gather throughput */ - hsize_t gath_ncalls; /*number of calls */ - H5_timer_t bkg_timer; /*time for background */ - hsize_t bkg_nbytes; /*background throughput */ - hsize_t bkg_ncalls; /*number of calls */ - H5_timer_t read_timer; /*time for read calls */ - hsize_t read_nbytes; /*total bytes read */ - hsize_t read_ncalls; /*number of calls */ - H5_timer_t write_timer; /*time for write calls */ - hsize_t write_nbytes; /*total bytes written */ - hsize_t write_ncalls; /*number of calls */ - } stats[2]; /* 0=output, 1=input */ -} H5S_iostats_t; -#endif - /* If the module using this macro is allowed access to the private variables, access them directly */ #ifdef H5S_PACKAGE #define H5S_GET_EXTENT_TYPE(S) ((S)->extent.type) @@ -198,9 +173,6 @@ typedef struct H5S_iostats_t { /* Operations on dataspaces */ H5_DLL H5S_t *H5S_copy(const H5S_t *src, hbool_t share_selection, hbool_t copy_max); H5_DLL herr_t H5S_close(H5S_t *ds); -#ifdef H5S_DEBUG -H5_DLL H5S_iostats_t *H5S_find(const H5S_t *mem_space, const H5S_t *file_space); -#endif /* H5S_DEBUG */ H5_DLL H5S_class_t H5S_get_simple_extent_type(const H5S_t *ds); H5_DLL hssize_t H5S_get_simple_extent_npoints(const H5S_t *ds); H5_DLL hsize_t H5S_get_npoints_max(const H5S_t *ds); diff --git a/src/H5T.c b/src/H5T.c index 04d6c0b..c726e5c 100644 --- a/src/H5T.c +++ b/src/H5T.c @@ -4552,7 +4552,7 @@ H5T_path_compound_subset(const H5T_path_t *p) FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5T_path_compound_subset); - assert(p); + HDassert(p); if(p->are_compounds) ret_value = H5T_conv_struct_subset(&(p->cdata)); diff --git a/src/H5Tconv.c b/src/H5Tconv.c index 0da4d53..7803d07 100644 --- a/src/H5Tconv.c +++ b/src/H5Tconv.c @@ -1890,17 +1890,15 @@ H5T_subset_t H5T_conv_struct_subset(const H5T_cdata_t *cdata) { H5T_conv_struct_t *priv; - H5T_subset_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5T_conv_struct_subset) HDassert(cdata); HDassert(cdata->priv); - priv = (H5T_conv_struct_t*)(cdata->priv); - ret_value = priv->smembs_subset; + priv = (H5T_conv_struct_t *)(cdata->priv); - FUNC_LEAVE_NOAPI(ret_value) + FUNC_LEAVE_NOAPI(priv->smembs_subset) } /* end H5T_conv_struct_subset() */ diff --git a/src/H5Tprivate.h b/src/H5Tprivate.h index dfe2367..2fe4c3a 100644 --- a/src/H5Tprivate.h +++ b/src/H5Tprivate.h @@ -69,7 +69,7 @@ typedef struct H5T_conv_cb_t { /* Values for the optimization of compound data reading and writing. They indicate * whether the fields of the source and destination are subset of each other and - * there is no conversion needed. It's for the Chicago company. + * there is no conversion needed. */ typedef enum { H5T_SUBSET_BADVALUE = -1, /* Invalid value */ diff --git a/src/Makefile.am b/src/Makefile.am index 0e5030b..fcb47e2 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,10 +46,10 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5AC.c H5B.c H5Bcache.c \ H5B2.c H5B2cache.c H5B2dbg.c H5B2int.c H5B2stat.c H5B2test.c \ H5C.c H5CS.c \ - H5D.c H5Dcompact.c H5Dcontig.c H5Ddbg.c \ + H5D.c H5Dchunk.c H5Dcompact.c H5Dcontig.c H5Ddbg.c \ H5Ddeprec.c H5Defl.c H5Dfill.c H5Dint.c \ H5Dio.c \ - H5Distore.c H5Dmpio.c H5Doh.c H5Dselect.c H5Dtest.c \ + H5Distore.c H5Dmpio.c H5Doh.c H5Dscatgath.c H5Dselect.c H5Dtest.c \ H5E.c H5Edeprec.c H5Eint.c \ H5F.c H5Fdbg.c H5Ffake.c H5Fmount.c H5Fsfile.c H5Fsuper.c H5Ftest.c \ H5FD.c H5FDcore.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 30b452c..1926017 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -82,9 +82,9 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5timer.lo H5trace.lo H5A.lo H5Abtree2.lo H5Adense.lo \ H5Adeprec.lo H5Aint.lo H5Atest.lo H5AC.lo H5B.lo H5Bcache.lo \ H5B2.lo H5B2cache.lo H5B2dbg.lo H5B2int.lo H5B2stat.lo \ - H5B2test.lo H5C.lo H5CS.lo H5D.lo H5Dcompact.lo H5Dcontig.lo \ + H5B2test.lo H5C.lo H5CS.lo H5D.lo H5Dchunk.lo H5Dcompact.lo H5Dcontig.lo \ H5Ddbg.lo H5Ddeprec.lo H5Defl.lo H5Dfill.lo H5Dint.lo H5Dio.lo \ - H5Distore.lo H5Dmpio.lo H5Doh.lo H5Dselect.lo H5Dtest.lo \ + H5Distore.lo H5Dmpio.lo H5Doh.lo H5Dscatgath.lo H5Dselect.lo H5Dtest.lo \ H5E.lo H5Edeprec.lo H5Eint.lo H5F.lo H5Fdbg.lo H5Ffake.lo \ H5Fmount.lo H5Fsfile.lo H5Fsuper.lo H5Ftest.lo H5FD.lo \ H5FDcore.lo H5FDdirect.lo H5FDfamily.lo H5FDlog.lo H5FDmpi.lo \ @@ -404,10 +404,10 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5AC.c H5B.c H5Bcache.c \ H5B2.c H5B2cache.c H5B2dbg.c H5B2int.c H5B2stat.c H5B2test.c \ H5C.c H5CS.c \ - H5D.c H5Dcompact.c H5Dcontig.c H5Ddbg.c \ + H5D.c H5Dchunk.c H5Dcompact.c H5Dcontig.c H5Ddbg.c \ H5Ddeprec.c H5Defl.c H5Dfill.c H5Dint.c \ H5Dio.c \ - H5Distore.c H5Dmpio.c H5Doh.c H5Dselect.c H5Dtest.c \ + H5Distore.c H5Dmpio.c H5Doh.c H5Dscatgath.c H5Dselect.c H5Dtest.c \ H5E.c H5Edeprec.c H5Eint.c \ H5F.c H5Fdbg.c H5Ffake.c H5Fmount.c H5Fsfile.c H5Fsuper.c H5Ftest.c \ H5FD.c H5FDcore.c \ @@ -602,6 +602,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5C.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5CS.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5D.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dchunk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dcompact.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dcontig.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ddbg.Plo@am__quote@ @@ -613,6 +614,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Distore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dmpio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Doh.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dscatgath.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dselect.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dtest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5E.Plo@am__quote@ diff --git a/test/cmpd_dset.c b/test/cmpd_dset.c index 66993e0..a03d37e 100644 --- a/test/cmpd_dset.c +++ b/test/cmpd_dset.c @@ -1421,32 +1421,32 @@ test_hdf5_src_subset(char *filename, hid_t fapl) /* Create xfer properties to preserve initialized data */ if((dxpl = H5Pcreate(H5P_DATASET_XFER)) < 0) - goto error; + FAIL_STACK_ERROR if(H5Pset_preserve(dxpl, TRUE) < 0) - goto error; + FAIL_STACK_ERROR /* Rewrite contiguous data set */ if((dataset = H5Dopen2(file, DSET_NAME[0], H5P_DEFAULT)) < 0) - goto error; + FAIL_STACK_ERROR /* Write the data to the dataset */ if(H5Dwrite(dataset, rew_tid, H5S_ALL, H5S_ALL, dxpl, rew_buf) < 0) - goto error; + FAIL_STACK_ERROR if(H5Dclose(dataset) < 0) - goto error; + FAIL_STACK_ERROR /* Rewrite chunked data set */ if((dataset = H5Dopen2(file, DSET_NAME[1], H5P_DEFAULT)) < 0) - goto error; + FAIL_STACK_ERROR /* Write the data to the dataset */ if(H5Dwrite(dataset, rew_tid, H5S_ALL, H5S_ALL, dxpl, rew_buf) < 0) - goto error; + FAIL_STACK_ERROR if(H5Dclose(dataset) < 0) - goto error; + FAIL_STACK_ERROR PASSED(); @@ -1458,48 +1458,48 @@ test_hdf5_src_subset(char *filename, hid_t fapl) /* Check contiguous data set */ if((dataset = H5Dopen2(file, DSET_NAME[0], H5P_DEFAULT)) < 0) - goto error; + FAIL_STACK_ERROR if(H5Dread(dataset, dst_tid, H5S_ALL, H5S_ALL, dxpl, rbuf) < 0) - goto error; + FAIL_STACK_ERROR if(compare_data(orig, rbuf, TRUE) < 0) - goto error; + TEST_ERROR if(H5Dclose(dataset) < 0) - goto error; + FAIL_STACK_ERROR /* Check chunked data set */ if((dataset = H5Dopen2(file, DSET_NAME[1], H5P_DEFAULT)) < 0) - goto error; + FAIL_STACK_ERROR if(H5Dread(dataset, dst_tid, H5S_ALL, H5S_ALL, dxpl, rbuf) < 0) - goto error; + FAIL_STACK_ERROR if(compare_data(orig, rbuf, TRUE) < 0) - goto error; + TEST_ERROR if(H5Dclose(dataset) < 0) - goto error; + FAIL_STACK_ERROR /* Finishing test and release resources */ if(H5Sclose(space) < 0) - goto error; + FAIL_STACK_ERROR if(H5Pclose(dcpl) < 0) - goto error; + FAIL_STACK_ERROR if(H5Pclose(dxpl) < 0) - goto error; + FAIL_STACK_ERROR if(H5Tclose(src_tid) < 0) - goto error; + FAIL_STACK_ERROR if(H5Tclose(dst_tid) < 0) - goto error; + FAIL_STACK_ERROR if(H5Tclose(rew_tid) < 0) - goto error; + FAIL_STACK_ERROR if(H5Fclose(file) < 0) - goto error; + FAIL_STACK_ERROR free(orig); free(rbuf); diff --git a/test/tcoords.c b/test/tcoords.c index c9d4316..998a598 100644 --- a/test/tcoords.c +++ b/test/tcoords.c @@ -148,7 +148,7 @@ static void test_singleEnd_selElements(hid_t file, hbool_t is_chunked) /* Select the elements in the dataset */ elmts_numb = 12; - ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, da_elmts1); + ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, (const hsize_t *)da_elmts1); CHECK(ret, FAIL, "H5Sselect_elements"); /* Dataspace for memory buffer */ @@ -170,7 +170,7 @@ static void test_singleEnd_selElements(hid_t file, hbool_t is_chunked) for(i=0; i<6; i++) for(j=0; j<2; j++) if(da_buffer[0][0][i][j] != mem1_buffer[0][0][i][j]) { - TestErrPrintf("Read different values than written at index 0,0,%d,%d\n", i, j); + TestErrPrintf("%u: Read different values than written at index 0,0,%d,%d\n", __LINE__, i, j); } /* ****** Case 2: ****** @@ -181,7 +181,7 @@ static void test_singleEnd_selElements(hid_t file, hbool_t is_chunked) /* Select the elements in the dataset */ elmts_numb = 6; - ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, da_elmts2); + ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, (const hsize_t *)da_elmts2); CHECK(ret, FAIL, "H5Sselect_elements"); /* Dataspace for memory buffer */ @@ -203,7 +203,7 @@ static void test_singleEnd_selElements(hid_t file, hbool_t is_chunked) for(i=0; i<2; i++) for(j=0; j<3; j++) if(da_buffer[i][j][0][0] != mem2_buffer[i][j][0][0]) { - TestErrPrintf("Read different values than written at index %d,%d,0,0\n", i, j); + TestErrPrintf("%u: Read different values than written at index %d,%d,0,0, da_buffer = %d, mem2_buffer = %d\n", __LINE__, i, j, da_buffer[i][j][0][0], mem2_buffer[i][j][0][0]); } /* ****** Case 3: ****** @@ -214,7 +214,7 @@ static void test_singleEnd_selElements(hid_t file, hbool_t is_chunked) /* Select the elements in the dataset */ elmts_numb = 18; - ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, da_elmts3); + ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, (const hsize_t *)da_elmts3); CHECK(ret, FAIL, "H5Sselect_elements"); /* Dataspace for memory buffer */ @@ -236,7 +236,7 @@ static void test_singleEnd_selElements(hid_t file, hbool_t is_chunked) for(i=0; i<3; i++) for(j=0; j<6; j++) if(da_buffer[0][i][j][0] != mem3_buffer[0][i][j][0]) { - TestErrPrintf("Read different values than written at index 0,%d,%d,0\n", i, j); + TestErrPrintf("%u: Read different values than written at index 0,%d,%d,0\n", __LINE__, i, j); } @@ -323,7 +323,7 @@ static void test_singleEnd_selHyperslab(hid_t file, hbool_t is_chunked) for(i=0; i<6; i++) for(j=0; j<2; j++) if(da_buffer[0][0][i][j] != mem1_buffer[0][0][i][j]) { - TestErrPrintf("Read different values than written at index 0,0,%d,%d\n", i, j); + TestErrPrintf("%u: Read different values than written at index 0,0,%d,%d\n", __LINE__, i, j); } /* ****** Case 2: ****** @@ -354,7 +354,7 @@ static void test_singleEnd_selHyperslab(hid_t file, hbool_t is_chunked) for(i=0; i<2; i++) for(j=0; j<3; j++) if(da_buffer[i][j][0][0] != mem2_buffer[i][j][0][0]) { - TestErrPrintf("Read different values than written at index %d,%d,0,0\n", i, j); + TestErrPrintf("%u: Read different values than written at index %d,%d,0,0\n", __LINE__, i, j); } /* ****** Case 3: ****** @@ -385,7 +385,7 @@ static void test_singleEnd_selHyperslab(hid_t file, hbool_t is_chunked) for(i=0; i<3; i++) for(j=0; j<6; j++) if(da_buffer[0][i][j][0] != mem3_buffer[0][i][j][0]) { - TestErrPrintf("Read different values than written at index 0,%d,%d,0\n", i, j); + TestErrPrintf("%u: Read different values than written at index 0,%d,%d,0\n", __LINE__, i, j); } @@ -519,7 +519,7 @@ static void test_multiple_ends(hid_t file, hbool_t is_chunked) for(k=0; k<6; k++) for(l=0; l<2; l++) if(data_buf[0][0][0][i][j][0][k][l] != mem1_buffer[0][0][0][i][j][0][k][l]) { - TestErrPrintf("Read different values than written at index 0,0,0,%d,%d,0,%d,%d\n", i, j, k, l); + TestErrPrintf("%u: Read different values than written at index 0,0,0,%d,%d,0,%d,%d\n", __LINE__, i, j, k, l); } /* ****** Case 2: ****** @@ -551,7 +551,7 @@ static void test_multiple_ends(hid_t file, hbool_t is_chunked) for(k=0; k<4; k++) for(l=0; l<2; l++) if(data_buf[i][j][0][k][l][0][0][0] != mem2_buffer[i][j][0][k][l][0][0][0]) { - TestErrPrintf("Read different values than written at index %d,%d,0,%d,%d,0,0,0\n", i, j, k, l); + TestErrPrintf("%u: Read different values than written at index %d,%d,0,%d,%d,0,0,0\n", __LINE__, i, j, k, l); } /* ****** Case 3: ****** @@ -583,7 +583,7 @@ static void test_multiple_ends(hid_t file, hbool_t is_chunked) for(k=0; k<3; k++) for(l=0; l<6; l++) if(data_buf[0][i][j][0][0][k][l][0] != mem3_buffer[0][i][j][0][0][k][l][0]) { - TestErrPrintf("Read different values than written at index 0,%d,%d,0,0,%d,%d,0\n", i, j, k, l); + TestErrPrintf("%u: Read different values than written at index 0,%d,%d,0,0,%d,%d,0\n", __LINE__, i, j, k, l); } /* ****** Case 4: ****** @@ -615,7 +615,7 @@ static void test_multiple_ends(hid_t file, hbool_t is_chunked) for(k=0; k<6; k++) for(l=0; l<2; l++) if(data_buf[i][j][0][0][0][0][k][l] != mem4_buffer[i][j][0][0][0][0][k][l]) { - TestErrPrintf("Read different values than written at index %d,%d,0,0,0,0,%d,%d\n", i, j, k, l); + TestErrPrintf("%u: Read different values than written at index %d,%d,0,0,0,0,%d,%d\n", __LINE__, i, j, k, l); } @@ -651,7 +651,7 @@ static void test_multiple_ends(hid_t file, hbool_t is_chunked) for(m=0; m<6; m++) for(n=0; n<2; n++) if(data_buf[i][j][0][k][l][0][m][n] != mem5_buffer[i][j][0][k][l][0][m][n]) { - TestErrPrintf("Read different values than written at index %d,%d,0,%d,%d,0,%d,%d\n", i, j, k, l, m, n); + TestErrPrintf("%u: Read different values than written at index %d,%d,0,%d,%d,0,%d,%d\n", __LINE__, i, j, k, l, m, n); } diff --git a/test/th5s.c b/test/th5s.c index 983838e..5bf7845 100644 --- a/test/th5s.c +++ b/test/th5s.c @@ -378,7 +378,7 @@ test_h5s_null(void) hsize_t coord[1][1]; /* Coordinates for point selection */ coord[0][0]=0; - ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)1, coord); + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord); } H5E_END_TRY; VERIFY(ret, FAIL, "H5Sselect_elements"); @@ -1055,8 +1055,8 @@ test_h5s_chunk(void) for(i=0; i<50000; i++) { for(j=0; j<3; j++) { /* Check if the two values are within 0.001% range. */ - if(!DBL_REL_EQUAL(chunk_data_dbl[i][j],chunk_data_flt[i][j], 0.00001)) - TestErrPrintf("chunk_data_dbl[%d][%d]=%f, chunk_data_flt[%d][%d]=%f\n",i,j,chunk_data_dbl[i][j],i,j,chunk_data_flt[i][j]); + if(!DBL_REL_EQUAL(chunk_data_dbl[i][j], chunk_data_flt[i][j], 0.00001)) + TestErrPrintf("%u: chunk_data_dbl[%d][%d]=%e, chunk_data_flt[%d][%d]=%e\n", (unsigned)__LINE__, i, j, chunk_data_dbl[i][j], i, j, chunk_data_flt[i][j]); } /* end for */ } /* end for */ } /* test_h5s_chunk() */ -- cgit v0.12