From 93754cae33d4ed45850745664ce5e59f270f38f8 Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Wed, 19 Oct 2022 11:13:15 -0500 Subject: Multi Dataset (#2120) * Fix bug with cross platform compatibility of references within vlens. No testing yet. * Merge from multi_rd_wd_coll_io to a more recent branch from develop. Untested, probably does not work yet. * Committing clang-format changes * Committing clang-format changes * Fix many bugs in multi dataset branch. Mostly works, some issues in SWMR tests. * Committing clang-format changes * Disable test in swmr.c that was failing due to bug in HDF5 unrelated to multi dataset. * Committing clang-format changes * Fixed fortran multi-dataset tests * Fixed xlf errors * Added benchmark code for multi-datasets * loops over datasets * added missing error arg. * Added gnuplot formatting * Jonathan Kim original MD benchmarking code * updated MD benchmarking code * code clean-up * Only make files in feature test mode * misc clean-up * removed TEST_MDSET_NO_LAST_DSET_2ND_PROC option * Committing clang-format changes * Change multi dataset API to use arrays of individual parameters instead of the parameter struct. * Committing clang-format changes * Update to new multi dataset Fortran API and tests. (#1724) * Update to new multi dataset Fortran API and tests. * Sync Fortran with develop. * skipping h5pget_mpio_actual_io_mode_f for now * Fixed issue with dxpl_id, changed to variable size dim. (#1770) * Remove "is_coll_broken" field from H5D_io_info_t struct * Committing clang-format changes * Minor cleanup in multi dataset code. * Committing clang-format changes * Clean up in multi dataset code. * Committing clang-format changes * Committing clang-format changes * Fix speeling * Fix bug in parallel compression. Switch base_maddr in io_info to be a union. * Committing clang-format changes * Implement selection I/O support with multi dataset. Will be broken in parallel until PR 1803 is merged to develop then the MDS branch. * Committing clang-format changes * Spelling * Fix bug in multi dataset that could cause errors when only some of the datasets in the multi dataset I/O used type conversion. * Committing clang-format changes * Integrate multi dataset APIs with VOL layer. Add async versions of multi dataset APIs. * Committing clang-format changes * Spelling fixes * Fix bug in non-parallel HDF5 compilation. * Committing clang-format changes * Fix potential memory/free list error. Minor performance fix. Other minor changes. * Committing clang-format changes * Fix memory leak with memory dataspace for I/O. * Committing clang-format changes * Fix stack variables too large. Rename H5D_dset_info_t to H5D_dset_io_info_t. * Committing clang-format changes * Remove mem_space_alloc field from H5D_dset_io_info_t. Each function is now responsible for freeing any spaces it adds to dset_info. * Committing clang-format changes * fixed _multi Fortran declaration * Refactor various things in (mostly) the serial I/O code path to make things more maintainable. * Committing clang-format changes * updated to array based, doxygen, and examples * Reinstate H5D_chunk_map_t, stored (via pointer) inside H5D_dset_io_info_t. * Change from calloc to malloc for H5D_dset_io_info_t and H5D_chunk_map_t. Switch temporary dset_infos to be local stack variables. * Committing clang-format changes * format cleanup * format cleanup * added coll and ind * Modify all parallel I/O paths to take dset_info instead of assuming dset_info[0]. * Committing clang-format changes * fixed output * Rework parallel I/O code to work properly with multi dataset in more cases. Fix bug in parallel compression. * Committing clang-format changes * Prevent H5D__multi_chunk_collective_io() from messing up collective opt property for other datasets in I/O. Other minor cleanup. Add new test case to t_pmulti_dset.c for H5FD_MPIO_INDIVIDUAL_IO, disabled for now due to failures apparently unrelated to multi dataset code. * Fix spelling * Committing clang-format changes * Replace N log N algorithm for finding chunk in H5D__multi_chunk_collective_io() with O(N) algorithm, and remove use of io_info->sel_pieces in that function. * Committing clang-format changes * Replace sel_pieces skiplist in io_info with flat array of pointers, use qsort in I/O routine only when necessary. * Committing clang-format changes * Add new test case to mdset.c * Committing clang-format changes * Fix spelling * Very minor fix in H5VL__native_dataset_read() * Fix bug that could affect filtered parallel multi-dataset I/O. * Add RM entries for H5Dread_multi(), H5Dread_multi_async(), H5Dwrite_multi(), and H5Dwrite_multi_async() * Unskip test in swmr.c * Committing clang-format changes * Eliminate H5D__pre_read and H5D__pre_write * Remove examples/ph5mdsettest.c. Will fix and re-add as a test. * Enable hyperslab combinations in mdset test * Committing clang-format changes * Clarify H5Dread/write_multi documentation. * Fix bugs in multi-dataset I/O. Expand serial multi dataset test. Update macro in parallel multi dataset test. * Committing clang-format changes * Spelling * Remove obsolete entry in bin/trace * Rework type conversion buffer allocation. Only one buffer is shared between datasets in mdset mode, and it is malloced instead of calloced. * Committing clang-format changes * Fix bug in error handling in H5D__read/write * added multi-dataset fortran check with optional dataset creation id (#2150) * removed dup. dll entry * Address comments from code review. * Remove spurious changes in H5Fmpi.c * Fix issue with reading unallocated datasets in multi-dataset mode. Address other comments from code review. * Committing clang-format changes * Delay chunk index lookup from io_init to mdio_init so it doesn't add overhead to single dataset I/O. * Committing clang-format changes * Fix inappropriate use of piece_count * updated copyright on new file, removed benchmark from testing dir. Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: M. Scot Breitenfeld Co-authored-by: Dana Robinson <43805+derobins@users.noreply.github.com> --- fortran/src/H5Dff.F90 | 104 ++- fortran/src/hdf5_fortrandll.def.in | 2 + fortran/test/fortranlib_test_F03.F90 | 4 + fortran/test/tH5T_F03.F90 | 254 +++++ fortran/test/tf.F90 | 2 +- fortran/testpar/CMakeLists.txt | 1 + fortran/testpar/Makefile.am | 2 +- fortran/testpar/hyper.F90 | 31 +- fortran/testpar/multidsetrw.F90 | 235 +++++ fortran/testpar/ptest.F90 | 13 +- src/H5D.c | 308 +++++- src/H5Dchunk.c | 1705 +++++++++++++++++++--------------- src/H5Dcompact.c | 77 +- src/H5Dcontig.c | 418 +++++++-- src/H5Defl.c | 83 +- src/H5Dint.c | 87 +- src/H5Dio.c | 1365 +++++++++++++++++---------- src/H5Dlayout.c | 9 +- src/H5Dmpio.c | 1697 ++++++++++++++++----------------- src/H5Dpkg.h | 323 ++++--- src/H5Dpublic.h | 111 +++ src/H5Dscatgath.c | 225 +++-- src/H5Dselect.c | 62 +- src/H5Dvirtual.c | 202 ++-- src/H5Sselect.c | 2 +- src/H5VLcallback.c | 253 ++++- src/H5VLconnector.h | 8 +- src/H5VLconnector_passthru.h | 10 +- src/H5VLnative_dataset.c | 291 +++--- src/H5VLnative_private.h | 8 +- src/H5VLpassthru.c | 81 +- src/H5VLprivate.h | 16 +- src/H5private.h | 4 +- test/CMakeLists.txt | 1 + test/Makefile.am | 4 +- test/mdset.c | 714 ++++++++++++++ test/testfiles/error_test_1 | 2 +- testpar/CMakeLists.txt | 1 + testpar/Makefile.am | 4 +- testpar/t_pmulti_dset.c | 767 +++++++++++++++ 40 files changed, 6502 insertions(+), 2984 deletions(-) create mode 100644 fortran/testpar/multidsetrw.F90 create mode 100644 test/mdset.c create mode 100644 testpar/t_pmulti_dset.c diff --git a/fortran/src/H5Dff.F90 b/fortran/src/H5Dff.F90 index d15e59e..1e88399 100644 --- a/fortran/src/H5Dff.F90 +++ b/fortran/src/H5Dff.F90 @@ -1098,7 +1098,7 @@ CONTAINS !> !! \ingroup FH5D !! -!! \brief Writes raw data from a dataset into a buffer. +!! \brief Writes raw data from a buffer to a dataset. !! !! \attention \fortran_approved !! @@ -1762,6 +1762,108 @@ CONTAINS CALL h5dfill_ptr(f_ptr_fill_value, fill_type_id, f_ptr_buf, mem_type_id, space_id, hdferr) END SUBROUTINE h5dfill_char +!> +!! \ingroup FH5D +!! +!! \brief Reads data from a file to memory buffers for multiple datasets. +!! +!! \param count Number of datasets to write to. +!! \param dset_id Identifier of the dataset to write to. +!! \param mem_type_id Identifier of the memory datatype. +!! \param mem_space_id Identifier of the memory dataspace. +!! \param file_space_id Identifier of the dataset's dataspace in the file. +!! \param buf Buffer with data to be written to the file. +!! \param hdferr \fortran_error +!! \param xfer_prp Identifier of a transfer property list for this I/O operation. +!! + SUBROUTINE H5Dread_multi_f(count, dset_id, mem_type_id, mem_space_id, file_space_id, buf, hdferr, xfer_prp) + IMPLICIT NONE + + INTEGER(SIZE_T), INTENT(IN) :: count + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: dset_id + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: mem_type_id + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: mem_space_id + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: file_space_id + TYPE(C_PTR), DIMENSION(*) :: buf + INTEGER, INTENT(OUT) :: hdferr + INTEGER(HID_T), INTENT(IN), OPTIONAL :: xfer_prp + + INTEGER(HID_T) :: xfer_prp_default + + INTERFACE + INTEGER FUNCTION H5Dread_multi(count, dset_id, mem_type_id, mem_space_id, file_space_id, xfer_prp, buf) & + BIND(C, NAME='H5Dread_multi') + IMPORT :: SIZE_T + IMPORT :: HID_T + IMPORT :: C_PTR + IMPLICIT NONE + INTEGER(SIZE_T), VALUE :: count + INTEGER(HID_T), DIMENSION(*) :: dset_id + INTEGER(HID_T), DIMENSION(*) :: mem_type_id + INTEGER(HID_T), DIMENSION(*) :: mem_space_id + INTEGER(HID_T), DIMENSION(*) :: file_space_id + INTEGER(HID_T), VALUE :: xfer_prp + TYPE(C_PTR), DIMENSION(*) :: buf + END FUNCTION H5Dread_multi + END INTERFACE + + xfer_prp_default = H5P_DEFAULT_F + IF (PRESENT(xfer_prp)) xfer_prp_default = xfer_prp + + hdferr = H5Dread_multi(count, dset_id, mem_type_id, mem_space_id, file_space_id, xfer_prp_default, buf) + + END SUBROUTINE H5Dread_multi_f +!> +!! \ingroup FH5D +!! +!! \brief Writes data in memory to a file for multiple datasets. +!! +!! \param count Number of datasets to write to. +!! \param dset_id Identifier of the dataset to write to. +!! \param mem_type_id Identifier of the memory datatype. +!! \param mem_space_id Identifier of the memory dataspace. +!! \param file_space_id Identifier of the dataset's dataspace in the file. +!! \param buf Buffer with data to be written to the file. +!! \param hdferr \fortran_error +!! \param xfer_prp Identifier of a transfer property list for this I/O operation. +!! + SUBROUTINE H5Dwrite_multi_f(count, dset_id, mem_type_id, mem_space_id, file_space_id, buf, hdferr, xfer_prp) + IMPLICIT NONE + + INTEGER(SIZE_T), INTENT(IN) :: count + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: dset_id + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: mem_type_id + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: mem_space_id + INTEGER(HID_T), INTENT(IN), DIMENSION(*) :: file_space_id + TYPE(C_PTR), DIMENSION(*) :: buf + INTEGER, INTENT(OUT) :: hdferr + INTEGER(HID_T), INTENT(IN), OPTIONAL :: xfer_prp + + INTEGER(HID_T) :: xfer_prp_default + + INTERFACE + INTEGER FUNCTION H5Dwrite_multi(count, dset_id, mem_type_id, mem_space_id, file_space_id, xfer_prp, buf) & + BIND(C, NAME='H5Dwrite_multi') + IMPORT :: SIZE_T + IMPORT :: HID_T + IMPORT :: C_PTR + IMPLICIT NONE + INTEGER(SIZE_T), VALUE :: count + INTEGER(HID_T), DIMENSION(*) :: dset_id + INTEGER(HID_T), DIMENSION(*) :: mem_type_id + INTEGER(HID_T), DIMENSION(*) :: mem_space_id + INTEGER(HID_T), DIMENSION(*) :: file_space_id + INTEGER(HID_T), VALUE :: xfer_prp + TYPE(C_PTR), DIMENSION(*) :: buf + END FUNCTION H5Dwrite_multi + END INTERFACE + + xfer_prp_default = H5P_DEFAULT_F + IF (PRESENT(xfer_prp)) xfer_prp_default = xfer_prp + + hdferr = H5Dwrite_multi(count, dset_id, mem_type_id, mem_space_id, file_space_id, xfer_prp_default, buf) + + END SUBROUTINE H5Dwrite_multi_f #endif diff --git a/fortran/src/hdf5_fortrandll.def.in b/fortran/src/hdf5_fortrandll.def.in index dee56ac..4fa6f6a 100644 --- a/fortran/src/hdf5_fortrandll.def.in +++ b/fortran/src/hdf5_fortrandll.def.in @@ -80,6 +80,8 @@ H5D_mp_H5DGET_ACCESS_PLIST_F H5D_mp_H5DWRITE_PTR H5D_mp_H5DREAD_PTR H5D_mp_H5DVLEN_RECLAIM_F +H5D_mp_H5DREAD_MULTI_F +H5D_mp_H5DWRITE_MULTI_F ; H5E H5E_mp_H5ECLEAR_F H5E_mp_H5EPRINT_F diff --git a/fortran/test/fortranlib_test_F03.F90 b/fortran/test/fortranlib_test_F03.F90 index b310bfe..42abae1 100644 --- a/fortran/test/fortranlib_test_F03.F90 +++ b/fortran/test/fortranlib_test_F03.F90 @@ -151,6 +151,10 @@ PROGRAM fortranlibtest_F03 CALL test_h5p_file_image(ret_total_error) CALL write_test_status(ret_total_error, ' Testing h5pset/get file image', total_error) + ret_total_error = 0 + CALL multiple_dset_rw(ret_total_error) + CALL write_test_status(ret_total_error, ' Testing multi-dataset reads and writes', total_error) + ! write(*,*) ! write(*,*) '=========================================' ! write(*,*) 'Testing OBJECT interface ' diff --git a/fortran/test/tH5T_F03.F90 b/fortran/test/tH5T_F03.F90 index 200c674..02e848e 100644 --- a/fortran/test/tH5T_F03.F90 +++ b/fortran/test/tH5T_F03.F90 @@ -3407,4 +3407,258 @@ SUBROUTINE t_enum_conv(total_error) END SUBROUTINE t_enum_conv +! Tests the reading and writing of multiple datasets using H5Dread_multi and +! H5Dwrite_multi + +SUBROUTINE multiple_dset_rw(total_error) + +!------------------------------------------------------------------------- +! Subroutine: multiple_dset_rw +! +! Purpose: Tests the reading and writing of multiple datasets +! using H5Dread_multi and H5Dwrite_multi +! +! Return: Success: 0 +! Failure: number of errors +! +! Programmer: M. Scot Breitenfeld +! April 2, 2014 +! +!------------------------------------------------------------------------- +! + USE iso_c_binding + USE hdf5 + IMPLICIT NONE + + INTEGER, INTENT(INOUT) :: total_error ! number of errors + INTEGER :: error ! HDF hdferror flag + + INTEGER(SIZE_T), PARAMETER :: ndset = 5 ! Number of data sets + INTEGER(HID_T), DIMENSION(:), ALLOCATABLE :: dset_id + INTEGER(HID_T), DIMENSION(:), ALLOCATABLE :: mem_type_id + INTEGER(HID_T), DIMENSION(:), ALLOCATABLE :: mem_space_id + INTEGER(HID_T), DIMENSION(:), ALLOCATABLE :: file_space_id + + INTEGER, PARAMETER :: idim=10, idim2=5, idim3=3 ! size of integer array + INTEGER, PARAMETER :: rdim=5 ! size of real array + INTEGER, PARAMETER :: cdim=3 ! size of character array + INTEGER, PARAMETER :: sdim=2 ! length of character string + INTEGER, PARAMETER :: ddim=2 ! size of derived type array + INTEGER :: i,j,k + + TYPE(C_PTR), ALLOCATABLE, DIMENSION(:) :: buf_md ! array to hold the multi-datasets + + INTEGER, DIMENSION(1:idim), TARGET :: wbuf_int ! integer write buffer + INTEGER, DIMENSION(1:idim,idim2,idim3), TARGET :: wbuf_intmd + REAL, DIMENSION(1:rdim), TARGET :: wbuf_real ! real write buffer + CHARACTER(LEN=sdim), DIMENSION(1:cdim), TARGET :: wbuf_chr ! character write buffer + INTEGER, DIMENSION(1:idim), TARGET :: rbuf_int ! integer read buffer + INTEGER, DIMENSION(1:idim,idim2,idim3), TARGET :: rbuf_intmd ! integer read buffer + REAL, DIMENSION(1:rdim), TARGET :: rbuf_real ! real read buffer + CHARACTER(LEN=sdim), DIMENSION(1:cdim), TARGET :: rbuf_chr ! character read buffer + + TYPE derived + REAL :: r + INTEGER :: i + CHARACTER(LEN=sdim) :: c + END TYPE derived + + TYPE(derived), DIMENSION(1:ddim), TARGET :: wbuf_derived ! derived type write buffer + TYPE(derived), DIMENSION(1:ddim), TARGET :: rbuf_derived ! derived type read buffer + INTEGER(HSIZE_T), DIMENSION(1:1) :: dims ! dimension of the spaces + INTEGER(HSIZE_T), DIMENSION(1:3) :: dimsmd ! dimension of the spaces + INTEGER(HID_T) :: file_id, strtype ! handles + INTEGER(SIZE_T) :: obj_count + + ALLOCATE(buf_md(1:ndset),stat=error) + IF (error .NE. 0) THEN + WRITE(*,*) 'allocate error' + total_error = total_error + 1 + RETURN + ENDIF + ALLOCATE(dset_id(1:ndset),stat=error) + IF (error .NE. 0) THEN + WRITE(*,*) 'allocate error' + total_error = total_error + 1 + RETURN + ENDIF + ALLOCATE(mem_type_id(1:ndset),stat=error) + IF (error .NE. 0) THEN + WRITE(*,*) 'allocate error' + total_error = total_error + 1 + RETURN + ENDIF + ALLOCATE(mem_space_id(1:ndset),stat=error) + IF (error .NE. 0) THEN + WRITE(*,*) 'allocate error' + total_error = total_error + 1 + RETURN + ENDIF + ALLOCATE(file_space_id(1:ndset),stat=error) + IF (error .NE. 0) THEN + WRITE(*,*) 'allocate error' + total_error = total_error + 1 + RETURN + ENDIF + + CALL h5fcreate_f("multidset_rw.h5", H5F_ACC_TRUNC_F, file_id, error) + CALL check("h5fcreate_f", error, total_error) + ! + ! Create real dataset + ! + wbuf_real(1:rdim) = (/(i,i=1,rdim)/) + dims(1) = rdim + buf_md(1) = C_LOC(wbuf_real(1)) + mem_type_id(1) = H5T_NATIVE_REAL + CALL h5screate_simple_f(1, dims, file_space_id(1), error) + CALL check("h5screate_simple_f", error, total_error) + CALL h5dcreate_f(file_id, "ds real", mem_type_id(1), file_space_id(1), dset_id(1), error) + CALL check("h5dcreate_f", error, total_error) + mem_space_id(1) = file_space_id(1) + + ! Create integer dataset (1D) + wbuf_int(1:idim) = (/(i,i=1,idim)/) + dims(1) = idim + buf_md(2) = C_LOC(wbuf_int(1)) + mem_type_id(2) = H5T_NATIVE_INTEGER + CALL h5screate_simple_f(1, dims, file_space_id(2), error) + CALL check("h5screate_simple_f", error, total_error) + CALL h5dcreate_f(file_id, "ds int", mem_type_id(2), file_space_id(2), dset_id(2), error) + CALL check("h5dcreate_f", error, total_error) + mem_space_id(2) = file_space_id(2) + + ! Create character dataset + wbuf_chr(1:cdim) = (/'ab','cd','ef'/) + dims(1) = cdim + buf_md(3) = C_LOC(wbuf_chr(1)(1:1)) + CALL H5Tcopy_f(H5T_FORTRAN_S1, mem_type_id(3), error) + CALL check("H5Tcopy_f", error, total_error) + CALL H5Tset_size_f(mem_type_id(3), INT(sdim,SIZE_T), error) + CALL check("H5Tset_size_f", error, total_error) + CALL h5screate_simple_f(1, dims, file_space_id(3), error) + CALL check("h5screate_simple_f", error, total_error) + CALL h5dcreate_f(file_id, "ds chr", mem_type_id(3), file_space_id(3), dset_id(3), error) + CALL check("h5dcreate_f", error, total_error) + mem_space_id(3) = file_space_id(3) + + ! Create derived type dataset + wbuf_derived(1:ddim)%r = (/10.,20./) + wbuf_derived(1:ddim)%i = (/30,40/) + wbuf_derived(1:ddim)%c = (/'wx','yz'/) + buf_md(4) = C_LOC(wbuf_derived(1)%r) + CALL h5tcreate_f(H5T_COMPOUND_F, H5OFFSETOF(C_LOC(wbuf_derived(1)), C_LOC(wbuf_derived(2))), mem_type_id(4), error) + CALL check("h5tcreate_f", error, total_error) + CALL h5tinsert_f(mem_type_id(4), "real", & + H5OFFSETOF(C_LOC(wbuf_derived(1)),C_LOC(wbuf_derived(1)%r)), H5T_NATIVE_REAL, error) + CALL check("h5tinsert_f", error, total_error) + CALL h5tinsert_f(mem_type_id(4), "int", & + H5OFFSETOF(C_LOC(wbuf_derived(1)),C_LOC(wbuf_derived(1)%i)), H5T_NATIVE_INTEGER, error) + CALL check("h5tinsert_f", error, total_error) + CALL h5tcopy_f(H5T_NATIVE_CHARACTER, strtype, error) + CALL check("h5tcopy_f", error, total_error) + CALL h5tset_size_f(strtype, INT(sdim,size_t), error) + CALL check("h5tset_size_f", error, total_error) + CALL h5tinsert_f(mem_type_id(4), "chr", & + H5OFFSETOF(C_LOC(wbuf_derived(1)),C_LOC(wbuf_derived(1)%c(1:1))), strtype, error) + CALL check("h5tinsert_f", error, total_error) + + dims(1) = ddim + CALL h5screate_simple_f(1, dims, file_space_id(4), error) + CALL check("h5screate_simple_f", error, total_error) + CALL h5dcreate_f(file_id, "ds derived", mem_type_id(4), file_space_id(4), dset_id(4), error) + CALL check("h5dcreate_f", error, total_error) + mem_space_id(4) = file_space_id(4) + + + ! Create integer dataset (3D) + + DO i = 1, idim + DO j = 1, idim2 + DO k = 1, idim3 + wbuf_intmd(i,j,k) = i*j + ENDDO + ENDDO + ENDDO + + dimsmd(1:3) = (/idim,idim2,idim3/) + buf_md(5) = C_LOC(wbuf_intmd(1,1,1)) + mem_type_id(5) = H5T_NATIVE_INTEGER + CALL h5screate_simple_f(3, dimsmd, file_space_id(5), error) + CALL check("h5screate_simple_f", error, total_error) + CALL h5dcreate_f(file_id, "ds int 3d", mem_type_id(5), file_space_id(5), dset_id(5), error) + CALL check("h5dcreate_f", error, total_error) + mem_space_id(5) = file_space_id(5) + + ! write all the datasets + CALL h5dwrite_multi_f(ndset, dset_id, mem_type_id, mem_space_id, file_space_id, buf_md, error) + CALL check("h5dwrite_multi_f", error, total_error) + + ! point to read buffers + + buf_md(1) = C_LOC(rbuf_real(1)) + buf_md(2) = C_LOC(rbuf_int(1)) + buf_md(3) = C_LOC(rbuf_chr(1)(1:1)) + buf_md(4) = C_LOC(rbuf_derived(1)%r) + buf_md(5) = C_LOC(rbuf_intmd(1,1,1)) + + ! read all the datasets + CALL h5dread_multi_f(ndset, dset_id, mem_type_id, mem_space_id, file_space_id, buf_md, error) + CALL check("h5dread_multi_f", error, total_error) + + ! check the written and read in values + DO i = 1, rdim + IF(rbuf_real(i).NE.wbuf_real(i))THEN + total_error = total_error + 1 + END IF + END DO + DO i = 1, idim + IF(rbuf_int(i).NE.wbuf_int(i))THEN + total_error = total_error + 1 + END IF + END DO + DO i = 1, cdim + IF(rbuf_chr(i).NE.wbuf_chr(i))THEN + total_error = total_error + 1 + END IF + END DO + DO i = 1, ddim + IF(rbuf_derived(i)%r.NE.wbuf_derived(i)%r)THEN + total_error = total_error + 1 + END IF + IF(rbuf_derived(i)%i.NE.wbuf_derived(i)%i)THEN + total_error = total_error + 1 + END IF + IF(rbuf_derived(i)%c.NE.wbuf_derived(i)%c)THEN + total_error = total_error + 1 + END IF + END DO + DO i = 1, idim + DO j = 1, idim2 + DO k = 1, idim3 + IF(rbuf_intmd(i,j,k).NE.wbuf_intmd(i,j,k))THEN + total_error = total_error + 1 + END IF + END DO + ENDDO + ENDDO + + DO i = 1, ndset + CALL H5Dclose_f(dset_id(i), error) + CALL check("H5Dclose_f", error, total_error) + CALL H5Sclose_f(file_space_id(i), error) + CALL check("H5Sclose_f", error, total_error) + ENDDO + CALL H5Tclose_f(mem_type_id(4), error) + CALL check("H5Tclose_f", error, total_error) + + CALL h5fget_obj_count_f(file_id, H5F_OBJ_ALL_F, obj_count, error) + IF(obj_count.NE.1)THEN + total_error = total_error + 1 + END IF + + CALL H5Fclose_f(file_id, error) + +END SUBROUTINE multiple_dset_rw + + END MODULE TH5T_F03 diff --git a/fortran/test/tf.F90 b/fortran/test/tf.F90 index b2cb746..6b4a008 100644 --- a/fortran/test/tf.F90 +++ b/fortran/test/tf.F90 @@ -88,7 +88,7 @@ CONTAINS error_string = skip ENDIF - WRITE(*, fmt = '(A, T80, A)') test_title, error_string + WRITE(*, fmt = '(A, T88, A)') test_title, error_string IF(test_result.GT.0) total_error = total_error + test_result diff --git a/fortran/testpar/CMakeLists.txt b/fortran/testpar/CMakeLists.txt index e395937..58ef95d 100644 --- a/fortran/testpar/CMakeLists.txt +++ b/fortran/testpar/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable (parallel_test ptest.F90 hyper.F90 mdset.F90 + multidsetrw.F90 ) target_include_directories (parallel_test PRIVATE ${TESTPAR_INCLUDES} diff --git a/fortran/testpar/Makefile.am b/fortran/testpar/Makefile.am index bd5c725..c00e46b 100644 --- a/fortran/testpar/Makefile.am +++ b/fortran/testpar/Makefile.am @@ -40,7 +40,7 @@ check_PROGRAMS=$(TEST_PROG_PARA) CHECK_CLEANFILES+=parf[12].h5 subf.h5* # Test source files -parallel_test_SOURCES=ptest.F90 hyper.F90 mdset.F90 +parallel_test_SOURCES=ptest.F90 hyper.F90 mdset.F90 multidsetrw.F90 subfiling_test_SOURCES=subfiling.F90 # The tests depend on several libraries. diff --git a/fortran/testpar/hyper.F90 b/fortran/testpar/hyper.F90 index 910fe1f..1f6ac0f 100644 --- a/fortran/testpar/hyper.F90 +++ b/fortran/testpar/hyper.F90 @@ -237,19 +237,23 @@ SUBROUTINE hyper(length,do_collective,do_chunk, mpi_size, mpi_rank, nerrors) CALL h5pget_mpio_actual_io_mode_f(dxpl_id, actual_io_mode, hdferror) CALL check("h5pget_mpio_actual_io_mode_f", hdferror, nerrors) - IF(do_collective.AND.do_chunk)THEN - IF(actual_io_mode.NE.H5D_MPIO_CHUNK_COLLECTIVE_F)THEN - CALL check("h5pget_mpio_actual_io_mode_f", -1, nerrors) - ENDIF - ELSEIF(.NOT.do_collective)THEN - IF(actual_io_mode.NE.H5D_MPIO_NO_COLLECTIVE_F)THEN - CALL check("h5pget_mpio_actual_io_mode_f", -1, nerrors) - ENDIF - ELSEIF( do_collective.AND.(.NOT.do_chunk))THEN - IF(actual_io_mode.NE.H5D_MPIO_CONTIG_COLLECTIVE_F)THEN - CALL check("h5pget_mpio_actual_io_mode_f", -1, nerrors) - ENDIF - ENDIF +! MSB -- TODO FIX: skipping for now since multi-dataset +! has no specific path for contiguous collective +! +! IF(do_collective.AND.do_chunk)THEN +! IF(actual_io_mode.NE.H5D_MPIO_CHUNK_COLLECTIVE_F)THEN +! CALL check("h5pget_mpio_actual_io_mode_f", -1, nerrors) +! ENDIF +! ELSEIF(.NOT.do_collective)THEN +! IF(actual_io_mode.NE.H5D_MPIO_NO_COLLECTIVE_F)THEN +! CALL check("h5pget_mpio_actual_io_mode_f", -1, nerrors) +! ENDIF +! ELSEIF( do_collective.AND.(.NOT.do_chunk))THEN +! IF(actual_io_mode.NE.H5D_MPIO_CONTIG_COLLECTIVE_F)THEN +! CALL check("h5pget_mpio_actual_io_mode_f", -1, nerrors) +! ENDIF +! ENDIF +! MSB ! ! close HDF5 I/O @@ -318,7 +322,6 @@ SUBROUTINE hyper(length,do_collective,do_chunk, mpi_size, mpi_rank, nerrors) CALL h5pcreate_f(H5P_DATASET_XFER_F, dxpl_id, hdferror) CALL check("h5pcreate_f", hdferror, nerrors) - IF (do_collective) THEN CALL h5pset_dxpl_mpio_f(dxpl_id, H5FD_MPIO_COLLECTIVE_F, hdferror) CALL check("h5pset_dxpl_mpio_f", hdferror, nerrors) diff --git a/fortran/testpar/multidsetrw.F90 b/fortran/testpar/multidsetrw.F90 new file mode 100644 index 0000000..5d41e4c --- /dev/null +++ b/fortran/testpar/multidsetrw.F90 @@ -0,0 +1,235 @@ +! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +! Copyright by The HDF Group. * +! 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. * +! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +! +! writes/reads dataset by hyperslabs using multi-dataset routines, h5dread_multi and +! h5dwrite_multi +! + +SUBROUTINE pmultiple_dset_hyper_rw(do_collective, do_chunk, mpi_size, mpi_rank, nerrors) + + USE iso_c_binding + USE TH5_MISC + USE hdf5 + USE mpi + IMPLICIT NONE + + LOGICAL, INTENT(in) :: do_collective ! use collective IO + LOGICAL, INTENT(in) :: do_chunk ! use chunking + INTEGER, INTENT(in) :: mpi_size ! number of processes in the group of communicator + INTEGER, INTENT(in) :: mpi_rank ! rank of the calling process in the communicator + INTEGER, INTENT(inout) :: nerrors ! number of errors + CHARACTER(LEN=80):: dsetname ! Dataset name + INTEGER(hsize_t), DIMENSION(1:2) :: cdims ! chunk dimensions + + INTEGER(HID_T) :: file_id ! File identifier + INTEGER(HID_T) :: filespace ! Dataspace identifier in file + INTEGER(HID_T) :: memspace ! Dataspace identifier in memory + INTEGER(HID_T) :: plist_id ! Property list identifier + INTEGER(HID_T) :: dcpl_id ! Dataset creation property list + INTEGER(HSIZE_T), DIMENSION(1:2) :: dimsf ! Dataset dimensions. + + INTEGER(HSIZE_T), DIMENSION(1:2) :: count + INTEGER(HSSIZE_T), DIMENSION(1:2) :: offset + INTEGER, ALLOCATABLE, DIMENSION(:,:,:), TARGET :: DATA ! Data to write + INTEGER, ALLOCATABLE, DIMENSION(:,:,:), TARGET :: rDATA ! Data to write + INTEGER, PARAMETER :: rank = 2 ! Dataset rank + INTEGER :: i + INTEGER(HSIZE_T) :: ii, jj, kk, istart + INTEGER :: error ! Error flags + + INTEGER(SIZE_T), PARAMETER :: ndsets = 5 + INTEGER(HID_T), DIMENSION(1:ndsets) :: dset_id + INTEGER(HID_T), DIMENSION(1:ndsets) :: mem_type_id + INTEGER(HID_T), DIMENSION(1:ndsets) :: mem_space_id + INTEGER(HID_T), DIMENSION(1:ndsets) :: file_space_id + TYPE(C_PTR), DIMENSION(1:ndsets) :: buf_md + INTEGER(SIZE_T) :: obj_count + INTEGER :: data_xfer_mode + + dimsf(1) = 5_hsize_t + dimsf(2) = INT(mpi_size, hsize_t)*8_hsize_t + + ! + ! Setup file access property list with parallel I/O access. + ! + CALL h5pcreate_f(H5P_FILE_ACCESS_F, plist_id, error) + CALL check("h5pcreate_f", error, nerrors) + CALL h5pset_fapl_mpio_f(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL, error) + CALL check("h5pset_fapl_mpio_f", error, nerrors) + ! + ! Create the file collectively. + ! + CALL h5fcreate_f("parf2.h5", H5F_ACC_TRUNC_F, file_id, error, access_prp = plist_id) + CALL check("h5fcreate_f", error, nerrors) + CALL h5pclose_f(plist_id, error) + CALL check("h5pclose_f", error, nerrors) + ! + ! Create the data space for the dataset. + ! + CALL h5screate_simple_f(rank, dimsf, filespace, error) + CALL check("h5screate_simple_f", error, nerrors) + ! + ! Each process defines dataset in memory and writes it to the hyperslab + ! in the file. + ! + count(1) = dimsf(1) + count(2) = dimsf(2)/mpi_size + offset(1) = 0 + offset(2) = mpi_rank * count(2) + CALL h5screate_simple_f(rank, count, memspace, error) + CALL check("h5screate_simple_f", error, nerrors) + + ! + ! Modify dataset creation properties to enable chunking + ! + + CALL h5pcreate_f(H5P_DATASET_CREATE_F, dcpl_id, error) + CALL check("h5pcreate_f", error, nerrors) + + IF (do_chunk) THEN + cdims(1) = dimsf(1) + cdims(2) = dimsf(2)/mpi_size/2 + CALL h5pset_chunk_f(dcpl_id, 2, cdims, error) + CALL check("h5pset_chunk_f", error, nerrors) + ENDIF + ! + ! Select hyperslab in the file. + ! + CALL h5sselect_hyperslab_f(filespace, H5S_SELECT_SET_F, offset, count, error) + CALL check("h5sselect_hyperslab_f", error, nerrors) + ! + ! Initialize data buffer + ! + ALLOCATE ( DATA(COUNT(1),COUNT(2), ndsets)) + ALLOCATE ( rdata(COUNT(1),COUNT(2), ndsets)) + + ! Create property list for collective dataset write + ! + CALL h5pcreate_f(H5P_DATASET_XFER_F, plist_id, error) + CALL check("h5pcreate_f", error, nerrors) + IF(do_collective)THEN + CALL h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, error) + CALL check("h5pset_dxpl_mpio_f", error, nerrors) + ELSE + CALL h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_INDEPENDENT_F, error) + CALL check("h5pset_dxpl_mpio_f", error, nerrors) + ENDIF + + ! + ! Create the dataset with default properties. + ! + mem_type_id(1:ndsets) = H5T_NATIVE_INTEGER + mem_space_id(1:ndsets) = memspace + file_space_id(1:ndsets)= filespace + + DO ii = 1, ndsets + ! Create the data + DO kk = 1, COUNT(1) + DO jj = 1, COUNT(2) + istart = (kk-1)*dimsf(2) + mpi_rank*COUNT(2) + DATA(kk,jj,ii) = INT((istart + jj)*10**(ii-1)) + ENDDO + ENDDO + ! Point to te data + buf_md(ii) = C_LOC(DATA(1,1,ii)) + + ! direct the output of the write statement to unit "dsetname" + WRITE(dsetname,'("dataset ",I0)') ii + ! create the dataset + CALL h5dcreate_f(file_id, dsetname, H5T_NATIVE_INTEGER, filespace, dset_id(ii), error, dcpl_id) + CALL check("h5dcreate_f", error, nerrors) + ENDDO + + ! + ! Write the dataset collectively. + ! + CALL h5dwrite_multi_f(ndsets, dset_id, mem_type_id, mem_space_id, file_space_id, buf_md, error, plist_id) + CALL check("h5dwrite_multi_f", error, nerrors) + + CALL h5pget_dxpl_mpio_f(plist_id, data_xfer_mode, error) + CALL check("h5pget_dxpl_mpio_f", error, nerrors) + + IF(do_collective)THEN + IF(data_xfer_mode.NE.H5FD_MPIO_COLLECTIVE_F)THEN + nerrors = nerrors + 1 + ENDIF + ENDIF + + DO i = 1, ndsets + ! Point to the read buffer + buf_md(i) = C_LOC(rdata(1,1,i)) + ENDDO + + CALL H5Dread_multi_f(ndsets, dset_id, mem_type_id, mem_space_id, file_space_id, buf_md, error, plist_id) + CALL check("h5dread_multi_f", error, nerrors) + + CALL h5pget_dxpl_mpio_f(plist_id, data_xfer_mode, error) + CALL check("h5pget_dxpl_mpio_f", error, nerrors) + + IF(do_collective)THEN + IF(data_xfer_mode.NE.H5FD_MPIO_COLLECTIVE_F)THEN + nerrors = nerrors + 1 + ENDIF + ENDIF + + DO i = 1, ndsets + ! Close all the datasets + CALL h5dclose_f(dset_id(i), error) + CALL check("h5dclose_f", error, nerrors) + ENDDO + + ! check the data read and write buffers + DO ii = 1, ndsets + ! Create the data + DO kk = 1, COUNT(1) + DO jj = 1, COUNT(2) + IF(rDATA(kk,jj,ii).NE.DATA(kk,jj,ii))THEN + nerrors = nerrors + 1 + ENDIF + ENDDO + ENDDO + ENDDO + ! + ! Deallocate data buffer. + ! + DEALLOCATE(data, rdata) + + ! + ! Close dataspaces. + ! + CALL h5sclose_f(filespace, error) + CALL check("h5sclose_f", error, nerrors) + CALL h5sclose_f(memspace, error) + CALL check("h5sclose_f", error, nerrors) + ! + ! Close the dataset and property list. + ! + CALL h5pclose_f(dcpl_id, error) + CALL check("h5pclose_f", error, nerrors) + CALL h5pclose_f(plist_id, error) + CALL check("h5pclose_f", error, nerrors) + + CALL h5fget_obj_count_f(file_id, H5F_OBJ_ALL_F, obj_count, error) + IF(obj_count.NE.1)THEN + nerrors = nerrors + 1 + END IF + + ! + ! Close the file. + ! + CALL h5fclose_f(file_id, error) + CALL check("h5fclose_f", error, nerrors) + +END SUBROUTINE pmultiple_dset_hyper_rw diff --git a/fortran/testpar/ptest.F90 b/fortran/testpar/ptest.F90 index 0883ac2..9acff17 100644 --- a/fortran/testpar/ptest.F90 +++ b/fortran/testpar/ptest.F90 @@ -76,7 +76,18 @@ PROGRAM parallel_test CALL multiple_dset_write(length, do_collective(1), do_chunk(1), mpi_size, mpi_rank, ret_total_error) IF(mpi_rank==0) CALL write_test_status(ret_total_error, & 'Writing/reading several datasets (contiguous layout, independent MPI I/O)', total_error) - + ! + ! test write/read multiple hyperslab datasets + ! + DO i = 1, 2 + DO j = 1, 2 + ret_total_error = 0 + CALL pmultiple_dset_hyper_rw(do_collective(j), do_chunk(i), mpi_size, mpi_rank, ret_total_error) + IF(mpi_rank==0) CALL write_test_status(ret_total_error, & + "Writing/reading multiple datasets by hyperslab ("//TRIM(chr_chunk(i))//" layout, "& + //TRIM(chr_collective(j))//" MPI I/O)", total_error) + ENDDO + ENDDO ! ! close HDF5 interface ! diff --git a/src/H5D.c b/src/H5D.c index d9c75b2..66240da 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -50,10 +50,11 @@ static hid_t H5D__create_api_common(hid_t loc_id, const char *name, hid_t type_ static hid_t H5D__open_api_common(hid_t loc_id, const char *name, hid_t dapl_id, void **token_ptr, H5VL_object_t **_vol_obj_ptr); static hid_t H5D__get_space_api_common(hid_t dset_id, void **token_ptr, H5VL_object_t **_vol_obj_ptr); -static herr_t H5D__read_api_common(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, void *buf, void **token_ptr, H5VL_object_t **_vol_obj_ptr); -static herr_t H5D__write_api_common(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, const void *buf, void **token_ptr, +static herr_t H5D__read_api_common(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **token_ptr, + H5VL_object_t **_vol_obj_ptr); +static herr_t H5D__write_api_common(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void **token_ptr, H5VL_object_t **_vol_obj_ptr); static herr_t H5D__set_extent_api_common(hid_t dset_id, const hsize_t size[], void **token_ptr, H5VL_object_t **_vol_obj_ptr); @@ -943,26 +944,64 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__read_api_common(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, hid_t dxpl_id, - void *buf, void **token_ptr, H5VL_object_t **_vol_obj_ptr) +H5D__read_api_common(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **token_ptr, + H5VL_object_t **_vol_obj_ptr) { H5VL_object_t *tmp_vol_obj = NULL; /* Object for loc_id */ H5VL_object_t **vol_obj_ptr = (_vol_obj_ptr ? _vol_obj_ptr : &tmp_vol_obj); /* Ptr to object ptr for loc_id */ - herr_t ret_value = SUCCEED; /* Return value */ + void *obj_local; /* Local buffer for obj */ + void **obj = &obj_local; /* Array of object pointers */ + H5VL_t *connector; /* VOL connector pointer */ + size_t i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Check arguments */ - if (mem_space_id < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid memory dataspace ID") - if (file_space_id < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file dataspace ID") + if (count == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "count must be greater than 0") + if (!dset_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dset_id array not provided") + if (!mem_type_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_type_id array not provided") + if (!mem_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_space_id array not provided") + if (!file_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_space_id array not provided") + if (!buf) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf array not provided") - /* Get dataset pointer */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + /* Allocate obj array if necessary */ + if (count > 1) + if (NULL == (obj = (void **)H5MM_malloc(count * sizeof(void *)))) + HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate space for object array") + + /* Get vol_obj_ptr (return just the first dataset to caller if requested) */ + if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(dset_id[0], H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID") + /* Save the connector of the first dataset. Unpack the connector and call + * the "direct" read function here to avoid allocating an array of count + * H5VL_object_ts. */ + connector = (*vol_obj_ptr)->connector; + + /* Build obj array */ + obj[0] = (*vol_obj_ptr)->data; + for (i = 1; i < count; i++) { + /* Get the object */ + if (NULL == (tmp_vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id[i], H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID") + obj[i] = tmp_vol_obj->data; + + /* Make sure the class matches */ + if (tmp_vol_obj->connector->cls->value != connector->cls->value) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "datasets are accessed through different VOL connectors and can't be used in the " + "same I/O call") + } + /* Get the default dataset transfer property list if the user didn't provide one */ if (H5P_DEFAULT == dxpl_id) dxpl_id = H5P_DATASET_XFER_DEFAULT; @@ -970,11 +1009,15 @@ H5D__read_api_common(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") /* Read the data */ - if (H5VL_dataset_read(*vol_obj_ptr, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, token_ptr) < - 0) + if (H5VL_dataset_read_direct(count, obj, connector, mem_type_id, mem_space_id, file_space_id, dxpl_id, + buf, token_ptr) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") done: + /* Free memory */ + if (obj != &obj_local) + H5MM_free(obj); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__read_api_common() */ @@ -1022,7 +1065,8 @@ H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_i H5TRACE6("e", "iiiiix", dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf); /* Read the data */ - if (H5D__read_api_common(dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, NULL, NULL) < 0) + if (H5D__read_api_common(1, &dset_id, &mem_type_id, &mem_space_id, &file_space_id, dxpl_id, &buf, NULL, + NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't synchronously read data") done: @@ -1059,8 +1103,8 @@ H5Dread_async(const char *app_file, const char *app_func, unsigned app_line, hid token_ptr = &token; /* Point at token for VOL connector to set up */ /* Read the data */ - if (H5D__read_api_common(dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, token_ptr, - &vol_obj) < 0) + if (H5D__read_api_common(1, &dset_id, &mem_type_id, &mem_space_id, &file_space_id, dxpl_id, &buf, + token_ptr, &vol_obj) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't asynchronously read data") /* If a token was created, add the token to the event set */ @@ -1076,6 +1120,84 @@ done: } /* end H5Dread_async() */ /*------------------------------------------------------------------------- + * Function: H5Dread_multi + * + * Purpose: Multi-version of H5Dread(), which reads selections from + * multiple datasets from a file into application memory BUFS. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jonathan Kim Nov, 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dread_multi(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], hid_t file_space_id[], + hid_t dxpl_id, void *buf[] /*out*/) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE7("e", "z*i*i*i*iix", count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf); + + if (count == 0) + HGOTO_DONE(SUCCEED) + + /* Read the data */ + if (H5D__read_api_common(count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, NULL, + NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't synchronously read data") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Dread_multi() */ + +/*------------------------------------------------------------------------- + * Function: H5Dread_multi_async + * + * Purpose: Asynchronously read dataset elements from multiple + * datasets. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dread_multi_async(const char *app_file, const char *app_func, unsigned app_line, size_t count, + hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], hid_t file_space_id[], + hid_t dxpl_id, void *buf[] /*out*/, hid_t es_id) +{ + H5VL_object_t *vol_obj = NULL; /* Dataset VOL object */ + void *token = NULL; /* Request token for async operation */ + void **token_ptr = H5_REQUEST_NULL; /* Pointer to request token for async operation */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE11("e", "*s*sIuz*i*i*i*iixi", app_file, app_func, app_line, count, dset_id, mem_type_id, + mem_space_id, file_space_id, dxpl_id, buf, es_id); + + /* Set up request token pointer for asynchronous operation */ + if (H5ES_NONE != es_id) + token_ptr = &token; /* Point at token for VOL connector to set up */ + + /* Read the data */ + if (H5D__read_api_common(count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, + token_ptr, &vol_obj) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't asynchronously read data") + + /* If a token was created, add the token to the event set */ + if (NULL != token) + /* clang-format off */ + if (H5ES_insert(es_id, vol_obj->connector, token, + H5ARG_TRACE11(__func__, "*s*sIuz*i*i*i*iixi", app_file, app_func, app_line, count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, es_id)) < 0) + /* clang-format on */ + HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "can't insert token into event set") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Dread_multi_async() */ + +/*------------------------------------------------------------------------- * Function: H5Dread_chunk * * Purpose: Reads an entire chunk from the file directly. @@ -1142,26 +1264,64 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__write_api_common(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, const void *buf, void **token_ptr, H5VL_object_t **_vol_obj_ptr) +H5D__write_api_common(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void **token_ptr, + H5VL_object_t **_vol_obj_ptr) { H5VL_object_t *tmp_vol_obj = NULL; /* Object for loc_id */ H5VL_object_t **vol_obj_ptr = (_vol_obj_ptr ? _vol_obj_ptr : &tmp_vol_obj); /* Ptr to object ptr for loc_id */ - herr_t ret_value = SUCCEED; /* Return value */ + void *obj_local; /* Local buffer for obj */ + void **obj = &obj_local; /* Array of object pointers */ + H5VL_t *connector; /* VOL connector pointer */ + size_t i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Check arguments */ - if (mem_space_id < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid memory dataspace ID") - if (file_space_id < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file dataspace ID") + if (count == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "count must be greater than 0") + if (!dset_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dset_id array not provided") + if (!mem_type_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_type_id array not provided") + if (!mem_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_space_id array not provided") + if (!file_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_space_id array not provided") + if (!buf) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf array not provided") - /* Get dataset pointer */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + /* Allocate obj array if necessary */ + if (count > 1) + if (NULL == (obj = (void **)H5MM_malloc(count * sizeof(void *)))) + HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate space for object array") + + /* Get vol_obj_ptr (return just the first dataset to caller if requested) */ + if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(dset_id[0], H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID") + /* Save the connector of the first dataset. Unpack the connector and call + * the "direct" write function here to avoid allocating an array of count + * H5VL_object_ts. */ + connector = (*vol_obj_ptr)->connector; + + /* Build obj array */ + obj[0] = (*vol_obj_ptr)->data; + for (i = 1; i < count; i++) { + /* Get the object */ + if (NULL == (tmp_vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id[i], H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID") + obj[i] = tmp_vol_obj->data; + + /* Make sure the class matches */ + if (tmp_vol_obj->connector->cls->value != connector->cls->value) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "datasets are accessed through different VOL connectors and can't be used in the " + "same I/O call") + } + /* Get the default dataset transfer property list if the user didn't provide one */ if (H5P_DEFAULT == dxpl_id) dxpl_id = H5P_DATASET_XFER_DEFAULT; @@ -1169,11 +1329,15 @@ H5D__write_api_common(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") /* Write the data */ - if (H5VL_dataset_write(*vol_obj_ptr, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, token_ptr) < - 0) + if (H5VL_dataset_write_direct(count, obj, connector, mem_type_id, mem_space_id, file_space_id, dxpl_id, + buf, token_ptr) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") done: + /* Free memory */ + if (obj != &obj_local) + H5MM_free(obj); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__write_api_common() */ @@ -1222,8 +1386,8 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_ H5TRACE6("e", "iiiii*x", dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf); /* Write the data */ - if (H5D__write_api_common(dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, NULL, NULL) < - 0) + if (H5D__write_api_common(1, &dset_id, &mem_type_id, &mem_space_id, &file_space_id, dxpl_id, &buf, NULL, + NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't synchronously write data") done: @@ -1261,8 +1425,8 @@ H5Dwrite_async(const char *app_file, const char *app_func, unsigned app_line, hi token_ptr = &token; /* Point at token for VOL connector to set up */ /* Write the data */ - if (H5D__write_api_common(dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, token_ptr, - &vol_obj) < 0) + if (H5D__write_api_common(1, &dset_id, &mem_type_id, &mem_space_id, &file_space_id, dxpl_id, &buf, + token_ptr, &vol_obj) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't asynchronously write data") /* If a token was created, add the token to the event set */ @@ -1278,6 +1442,84 @@ done: } /* end H5Dwrite_async() */ /*------------------------------------------------------------------------- + * Function: H5Dwrite_multi + * + * Purpose: Multi-version of H5Dwrite(), which writes selections from + * application memory BUFs into multiple datasets in a file. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jonathan Kim Nov, 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dwrite_multi(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[]) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE7("e", "z*i*i*i*ii**x", count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf); + + if (count == 0) + HGOTO_DONE(SUCCEED) + + /* Write the data */ + if (H5D__write_api_common(count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, NULL, + NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't synchronously write data") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Dwrite_multi() */ + +/*------------------------------------------------------------------------- + * Function: H5Dwrite_multi_async + * + * Purpose: Asynchronously write dataset elements to multiple + * datasets. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dwrite_multi_async(const char *app_file, const char *app_func, unsigned app_line, size_t count, + hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], hid_t file_space_id[], + hid_t dxpl_id, const void *buf[], hid_t es_id) +{ + H5VL_object_t *vol_obj = NULL; /* Dataset VOL object */ + void *token = NULL; /* Request token for async operation */ + void **token_ptr = H5_REQUEST_NULL; /* Pointer to request token for async operation */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE11("e", "*s*sIuz*i*i*i*ii**xi", app_file, app_func, app_line, count, dset_id, mem_type_id, + mem_space_id, file_space_id, dxpl_id, buf, es_id); + + /* Set up request token pointer for asynchronous operation */ + if (H5ES_NONE != es_id) + token_ptr = &token; /* Point at token for VOL connector to set up */ + + /* Write the data */ + if (H5D__write_api_common(count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, + token_ptr, &vol_obj) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't asynchronously write data") + + /* If a token was created, add the token to the event set */ + if (NULL != token) + /* clang-format off */ + if (H5ES_insert(es_id, vol_obj->connector, token, + H5ARG_TRACE11(__func__, "*s*sIuz*i*i*i*ii**xi", app_file, app_func, app_line, count, dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, es_id)) < 0) + /* clang-format on */ + HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "can't insert token into event set") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Dwrite_multi_async() */ + +/*------------------------------------------------------------------------- * Function: H5Dwrite_chunk * * Purpose: Writes an entire chunk to the file directly. diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index 256b441..a3f20c5 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -67,11 +67,19 @@ /****************/ /* 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)) -#define H5D_CHUNK_GET_NODE_COUNT(map) (map->use_single ? (size_t)1 : H5SL_count(map->sel_chunks)) +#define H5D_CHUNK_GET_FIRST_NODE(dinfo) \ + (dinfo->layout_io_info.chunk_map->use_single \ + ? (H5SL_node_t *)(1) \ + : H5SL_first(dinfo->layout_io_info.chunk_map->dset_sel_pieces)) +#define H5D_CHUNK_GET_NODE_INFO(dinfo, node) \ + (dinfo->layout_io_info.chunk_map->use_single ? dinfo->layout_io_info.chunk_map->single_piece_info \ + : (H5D_piece_info_t *)H5SL_item(node)) +#define H5D_CHUNK_GET_NEXT_NODE(dinfo, node) \ + (dinfo->layout_io_info.chunk_map->use_single ? (H5SL_node_t *)NULL : H5SL_next(node)) +#define H5D_CHUNK_GET_NODE_COUNT(dinfo) \ + (dinfo->layout_io_info.chunk_map->use_single \ + ? (size_t)1 \ + : H5SL_count(dinfo->layout_io_info.chunk_map->dset_sel_pieces)) /* Sanity check on chunk index types: commonly used by a lot of routines in this file */ #define H5D_CHUNK_STORAGE_INDEX_CHK(storage) \ @@ -143,6 +151,7 @@ typedef struct H5D_chunk_it_ud1_t { H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */ const H5D_chk_idx_info_t *idx_info; /* Chunked index info */ const H5D_io_info_t *io_info; /* I/O info for dataset operation */ + const H5D_dset_io_info_t *dset_info; /* Dataset specific I/O info */ const hsize_t *space_dim; /* New dataset dimensions */ const hbool_t *shrunk_dim; /* Dimensions which have been shrunk */ H5S_t *chunk_space; /* Dataspace for a chunk */ @@ -231,14 +240,6 @@ typedef struct H5D_chunk_info_iter_ud_t { hbool_t found; /* Whether the chunk was found */ } H5D_chunk_info_iter_ud_t; -/* Callback info for file selection iteration */ -typedef struct H5D_chunk_file_iter_ud_t { - H5D_chunk_map_t *fm; /* File->memory chunk mapping info */ -#ifdef H5_HAVE_PARALLEL - const H5D_io_info_t *io_info; /* I/O info for operation */ -#endif /* H5_HAVE_PARALLEL */ -} H5D_chunk_file_iter_ud_t; - #ifdef H5_HAVE_PARALLEL /* information to construct a collective I/O operation for filling chunks */ typedef struct H5D_chunk_coll_fill_info_t { @@ -264,16 +265,13 @@ typedef struct H5D_chunk_iter_ud_t { /* Chunked layout operation callbacks */ static herr_t H5D__chunk_construct(H5F_t *f, H5D_t *dset); static herr_t H5D__chunk_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id); -static herr_t H5D__chunk_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm); -static herr_t H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - H5D_chunk_map_t *fm); -static herr_t H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, 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, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm); +static herr_t H5D__chunk_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static herr_t H5D__chunk_io_init_selections(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static herr_t H5D__chunk_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static herr_t H5D__chunk_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static herr_t H5D__chunk_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); static herr_t H5D__chunk_flush(H5D_t *dset); -static herr_t H5D__chunk_io_term(const H5D_chunk_map_t *fm); +static herr_t H5D__chunk_io_term(H5D_io_info_t *io_info, H5D_dset_io_info_t *di); static herr_t H5D__chunk_dest(H5D_t *dset); /* Chunk query operation callbacks */ @@ -283,8 +281,8 @@ static int H5D__get_chunk_info_by_coord_cb(const H5D_chunk_rec_t *chunk_rec, voi static int H5D__chunk_iter_cb(const H5D_chunk_rec_t *chunk_rec, void *udata); /* "Nonexistent" layout operation callback */ -static ssize_t H5D__nonexistent_readvv(const H5D_io_info_t *io_info, size_t chunk_max_nseq, - size_t *chunk_curr_seq, size_t chunk_len_arr[], +static ssize_t H5D__nonexistent_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_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[]); @@ -292,29 +290,28 @@ static ssize_t H5D__nonexistent_readvv(const H5D_io_info_t *io_info, size_t chun static int H5D__chunk_format_convert_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata); /* Helper routines */ -static herr_t H5D__chunk_set_info_real(H5O_layout_chunk_t *layout, unsigned ndims, const hsize_t *curr_dims, - const hsize_t *max_dims); -static herr_t H5D__chunk_cinfo_cache_reset(H5D_chunk_cached_t *last); -static herr_t H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t *last, const H5D_chunk_ud_t *udata); -static hbool_t H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last, H5D_chunk_ud_t *udata); -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_all(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_1d(const H5D_chunk_map_t *fm); -static herr_t H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm); -static herr_t H5D__chunk_file_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords, - void *fm); -static herr_t H5D__chunk_mem_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords, - void *fm); -static htri_t H5D__chunk_may_use_select_io(const H5D_io_info_t *io_info); +static herr_t H5D__chunk_set_info_real(H5O_layout_chunk_t *layout, unsigned ndims, const hsize_t *curr_dims, + const hsize_t *max_dims); +static herr_t H5D__chunk_cinfo_cache_reset(H5D_chunk_cached_t *last); +static herr_t H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t *last, const H5D_chunk_ud_t *udata); +static hbool_t H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last, H5D_chunk_ud_t *udata); +static herr_t H5D__create_piece_map_single(H5D_dset_io_info_t *di, H5D_io_info_t *io_info); +static herr_t H5D__create_piece_file_map_all(H5D_dset_io_info_t *di, H5D_io_info_t *io_info); +static herr_t H5D__create_piece_file_map_hyper(H5D_dset_io_info_t *di, H5D_io_info_t *io_info); +static herr_t H5D__create_piece_mem_map_1d(const H5D_dset_io_info_t *di); +static herr_t H5D__create_piece_mem_map_hyper(const H5D_dset_io_info_t *di); +static herr_t H5D__piece_file_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords, + void *_opdata); +static herr_t H5D__piece_mem_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords, + void *_opdata); +static htri_t H5D__chunk_may_use_select_io(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info); static unsigned H5D__chunk_hash_val(const H5D_shared_t *shared, const hsize_t *scaled); static herr_t H5D__chunk_flush_entry(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t reset); static herr_t H5D__chunk_cache_evict(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t flush); -static void *H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax, - hbool_t prev_unfilt_chunk); -static herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbool_t dirty, - void *chunk, uint32_t naccessed); +static void *H5D__chunk_lock(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + H5D_chunk_ud_t *udata, hbool_t relax, hbool_t prev_unfilt_chunk); +static herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, uint32_t naccessed); static herr_t H5D__chunk_cache_prune(const H5D_t *dset, size_t size); static herr_t H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk); #ifdef H5_HAVE_PARALLEL @@ -337,17 +334,14 @@ const H5D_layout_ops_t H5D_LOPS_CHUNK[1] = {{ H5D__chunk_is_space_alloc, /* is_space_alloc */ H5D__chunk_is_data_cached, /* is_data_cached */ H5D__chunk_io_init, /* io_init */ + H5D__chunk_mdio_init, /* mdio_init */ H5D__chunk_read, /* ser_read */ H5D__chunk_write, /* ser_write */ -#ifdef H5_HAVE_PARALLEL - H5D__chunk_collective_read, /* par_read */ - H5D__chunk_collective_write, /* par_write */ -#endif - NULL, /* readvv */ - NULL, /* writevv */ - H5D__chunk_flush, /* flush */ - H5D__chunk_io_term, /* io_term */ - H5D__chunk_dest /* dest */ + NULL, /* readvv */ + NULL, /* writevv */ + H5D__chunk_flush, /* flush */ + H5D__chunk_io_term, /* io_term */ + H5D__chunk_dest /* dest */ }}; /*******************/ @@ -355,11 +349,8 @@ const H5D_layout_ops_t H5D_LOPS_CHUNK[1] = {{ /*******************/ /* "nonexistent" storage layout I/O ops */ -const H5D_layout_ops_t H5D_LOPS_NONEXISTENT[1] = {{NULL, NULL, NULL, NULL, NULL, NULL, NULL, -#ifdef H5_HAVE_PARALLEL - NULL, NULL, -#endif /* H5_HAVE_PARALLEL */ - H5D__nonexistent_readvv, NULL, NULL, NULL, NULL}}; +const H5D_layout_ops_t H5D_LOPS_NONEXISTENT[1] = { + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, H5D__nonexistent_readvv, NULL, NULL, NULL, NULL}}; /* Declare a free list to manage the H5F_rdcc_ent_ptr_t sequence information */ H5FL_SEQ_DEFINE_STATIC(H5D_rdcc_ent_ptr_t); @@ -368,7 +359,10 @@ H5FL_SEQ_DEFINE_STATIC(H5D_rdcc_ent_ptr_t); H5FL_DEFINE_STATIC(H5D_rdcc_ent_t); /* Declare a free list to manage the H5D_chunk_info_t struct */ -H5FL_DEFINE(H5D_chunk_info_t); +H5FL_DEFINE(H5D_chunk_map_t); + +/* Declare a free list to manage the H5D_piece_info_t struct */ +H5FL_DEFINE(H5D_piece_info_t); /* Declare a free list to manage the chunk sequence information */ H5FL_BLK_DEFINE_STATIC(chunk); @@ -389,8 +383,7 @@ H5FL_EXTERN(H5S_sel_iter_t); *------------------------------------------------------------------------- */ herr_t -H5D__chunk_direct_write(const H5D_t *dset, uint32_t filters, hsize_t *offset, uint32_t data_size, - const void *buf) +H5D__chunk_direct_write(H5D_t *dset, uint32_t filters, hsize_t *offset, uint32_t data_size, const void *buf) { const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */ H5D_chunk_ud_t udata; /* User data for querying chunk info */ @@ -406,16 +399,9 @@ H5D__chunk_direct_write(const H5D_t *dset, uint32_t filters, hsize_t *offset, ui HDassert(layout->type == H5D_CHUNKED); /* Allocate dataspace and initialize it if it hasn't been. */ - if (!H5D__chunk_is_space_alloc(&layout->storage)) { - H5D_io_info_t io_info; /* to hold the dset info */ - - io_info.dset = dset; - io_info.f_sh = H5F_SHARED(dset->oloc.file); - - /* Allocate storage */ - if (H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, FALSE, NULL) < 0) + if (!H5D__chunk_is_space_alloc(&layout->storage)) + if (H5D__alloc_storage(dset, H5D_ALLOC_WRITE, FALSE, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage") - } /* Calculate the index of this chunk */ H5VM_chunk_scaled(dset->shared->ndims, offset, layout->u.chunk.dim, scaled); @@ -1069,26 +1055,40 @@ H5D__chunk_is_data_cached(const H5D_shared_t *shared_dset) *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm) +H5D__chunk_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) { - const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */ - hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ - htri_t file_space_normalized = FALSE; /* File dataspace was normalized */ - unsigned f_ndims; /* The number of dimensions of the file's dataspace */ - int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */ - htri_t use_selection_io = FALSE; /* Whether to use selection I/O */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5D_t *dataset = dinfo->dset; /* Local pointer to dataset info */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ + htri_t file_space_normalized = FALSE; /* File dataspace was normalized */ + unsigned f_ndims; /* The number of dimensions of the file's dataspace */ + int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */ + htri_t use_selection_io = FALSE; /* Whether to use selection I/O */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE + /* Allocate chunk map */ + if (NULL == (dinfo->layout_io_info.chunk_map = H5FL_MALLOC(H5D_chunk_map_t))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate chunk map") + fm = dinfo->layout_io_info.chunk_map; + /* Get layout for dataset */ - fm->layout = &(dataset->shared->layout); - fm->nelmts = nelmts; + dinfo->layout = &(dataset->shared->layout); + + /* Initialize "last chunk" information */ + fm->last_index = (hsize_t)-1; + fm->last_piece_info = NULL; + + /* Clear other fields */ + fm->mchunk_tmpl = NULL; + fm->dset_sel_pieces = NULL; + fm->single_space = NULL; + fm->single_piece_info = NULL; /* Check if the memory space is scalar & make equivalent memory space */ - if ((sm_ndims = H5S_GET_EXTENT_NDIMS(mem_space)) < 0) + if ((sm_ndims = H5S_GET_EXTENT_NDIMS(dinfo->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_CHECKED_ASSIGN(fm->m_ndims, unsigned, sm_ndims, int); @@ -1102,49 +1102,28 @@ H5D__chunk_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsi * 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(file_space, old_offset)) < 0) + if ((file_space_normalized = H5S_hyper_normalize_offset(dinfo->file_space, old_offset)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to normalize selection") /* Decide the number of chunks in each dimension */ for (u = 0; u < f_ndims; u++) /* Keep the size of the chunk dimensions as hsize_t for various routines */ - fm->chunk_dim[u] = fm->layout->u.chunk.dim[u]; - -#ifdef H5_HAVE_PARALLEL - /* Calculate total chunk in file map*/ - fm->select_chunk = NULL; - if (io_info->using_mpi_vfd) { - H5_CHECK_OVERFLOW(fm->layout->u.chunk.nchunks, hsize_t, size_t); - if (fm->layout->u.chunk.nchunks) - if (NULL == (fm->select_chunk = (H5D_chunk_info_t **)H5MM_calloc( - (size_t)fm->layout->u.chunk.nchunks * 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; + fm->chunk_dim[u] = dinfo->layout->u.chunk.dim[u]; - if (H5D__chunk_io_init_selections(io_info, type_info, fm) < 0) + if (H5D__chunk_io_init_selections(io_info, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file and memory chunk selections") - /* Check if we're performing selection I/O and save the result */ - if ((use_selection_io = H5D__chunk_may_use_select_io(io_info)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible") - io_info->use_select_io = (hbool_t)use_selection_io; + /* Check if we're performing selection I/O and save the result if it hasn't + * been disabled already */ + if (io_info->use_select_io) { + if ((use_selection_io = H5D__chunk_may_use_select_io(io_info, dinfo)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible") + io_info->use_select_io = (hbool_t)use_selection_io; + } done: - /* Reset the global dataspace info */ - fm->file_space = NULL; - fm->mem_space = NULL; - if (file_space_normalized == TRUE) - if (H5S_hyper_denormalize_offset(file_space, old_offset) < 0) + if (H5S_hyper_denormalize_offset(dinfo->file_space, old_offset) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't denormalize selection") FUNC_LEAVE_NOAPI(ret_value) @@ -1163,34 +1142,44 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - H5D_chunk_map_t *fm) +H5D__chunk_io_init_selections(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) { - const 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 */ - H5T_t *file_type = NULL; /* Temporary copy of file datatype for iteration */ - hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ - char bogus; /* "bogus" buffer to pass to selection iterator */ - herr_t ret_value = SUCCEED; /* Return value */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + const H5D_t *dataset; /* Local pointer to dataset info */ + const H5T_t *mem_type; /* Local pointer to memory datatype */ + H5S_t *tmp_mspace = NULL; /* Temporary memory dataspace */ + H5T_t *file_type = NULL; /* Temporary copy of file datatype for iteration */ + hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ + char bogus; /* "bogus" buffer to pass to selection iterator */ + H5D_io_info_wrap_t io_info_wrap; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE + HDassert(io_info); + HDassert(dinfo); + + /* Set convenience pointers */ + fm = dinfo->layout_io_info.chunk_map; + HDassert(fm); + dataset = dinfo->dset; + mem_type = dinfo->type_info.mem_type; + /* Special case for only one element in selection */ /* (usually appending a record) */ - if (fm->nelmts == 1 + if (dinfo->nelmts == 1 #ifdef H5_HAVE_PARALLEL && !(io_info->using_mpi_vfd) #endif /* H5_HAVE_PARALLEL */ - && H5S_SEL_ALL != H5S_GET_SELECT_TYPE(fm->file_space)) { + && H5S_SEL_ALL != H5S_GET_SELECT_TYPE(dinfo->file_space)) { /* 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(fm->file_space, TRUE, FALSE)) == NULL) + if ((dataset->shared->cache.chunk.single_space = H5S_copy(dinfo->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 */ @@ -1205,17 +1194,17 @@ H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_ 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))) + if (NULL == dataset->shared->cache.chunk.single_piece_info) + if (NULL == (dataset->shared->cache.chunk.single_piece_info = H5FL_MALLOC(H5D_piece_info_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") - fm->single_chunk_info = dataset->shared->cache.chunk.single_chunk_info; - HDassert(fm->single_chunk_info); + fm->single_piece_info = dataset->shared->cache.chunk.single_piece_info; + HDassert(fm->single_piece_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) + if (H5D__create_piece_map_single(dinfo, io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create chunk selections for single element") } /* end if */ @@ -1226,16 +1215,16 @@ H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_ if (NULL == dataset->shared->cache.chunk.sel_chunks) if (NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE, NULL))) HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for chunk selections") - fm->sel_chunks = dataset->shared->cache.chunk.sel_chunks; - HDassert(fm->sel_chunks); + fm->dset_sel_pieces = dataset->shared->cache.chunk.sel_chunks; + HDassert(fm->dset_sel_pieces); /* We are not using single element mode */ fm->use_single = FALSE; /* Get type of selection on disk & in memory */ - if ((fm->fsel_type = H5S_GET_SELECT_TYPE(fm->file_space)) < H5S_SEL_NONE) + if ((fm->fsel_type = H5S_GET_SELECT_TYPE(dinfo->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(fm->mem_space)) < H5S_SEL_NONE) + if ((fm->msel_type = H5S_GET_SELECT_TYPE(dinfo->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 */ @@ -1248,57 +1237,53 @@ H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_ if (sel_hyper_flag) { /* Build the file selection for each chunk */ if (H5S_SEL_ALL == fm->fsel_type) { - if (H5D__create_chunk_file_map_all(fm, io_info) < 0) + if (H5D__create_piece_file_map_all(dinfo, io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") } /* end if */ else { /* Sanity check */ HDassert(fm->fsel_type == H5S_SEL_HYPERSLABS); - if (H5D__create_chunk_file_map_hyper(fm, io_info) < 0) + if (H5D__create_piece_file_map_hyper(dinfo, io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") } /* end else */ } /* end if */ else { - H5S_sel_iter_op_t iter_op; /* Operator for iteration */ - H5D_chunk_file_iter_ud_t udata; /* User data for iteration */ + H5S_sel_iter_op_t iter_op; /* Operator for iteration */ /* Create temporary datatypes for selection iteration */ if (NULL == (file_type = H5T_copy(dataset->shared->type, H5T_COPY_ALL))) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "unable to copy file datatype") - /* Initialize the user data */ - udata.fm = fm; -#ifdef H5_HAVE_PARALLEL - udata.io_info = io_info; -#endif /* H5_HAVE_PARALLEL */ - - iter_op.op_type = H5S_SEL_ITER_OP_LIB; - iter_op.u.lib_op = H5D__chunk_file_cb; + /* set opdata for H5D__piece_mem_cb */ + io_info_wrap.io_info = io_info; + io_info_wrap.dinfo = dinfo; + iter_op.op_type = H5S_SEL_ITER_OP_LIB; + iter_op.u.lib_op = H5D__piece_file_cb; /* Spaces might not be the same shape, iterate over the file selection directly */ - if (H5S_select_iterate(&bogus, file_type, fm->file_space, &iter_op, &udata) < 0) + if (H5S_select_iterate(&bogus, file_type, dinfo->file_space, &iter_op, &io_info_wrap) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") - /* Reset "last chunk" info */ + /* Reset "last piece" info */ fm->last_index = (hsize_t)-1; - fm->last_chunk_info = NULL; + fm->last_piece_info = NULL; } /* end else */ /* Build the memory selection for each chunk */ - if (sel_hyper_flag && H5S_SELECT_SHAPE_SAME(fm->file_space, fm->mem_space) == TRUE) { + if (sel_hyper_flag && H5S_SELECT_SHAPE_SAME(dinfo->file_space, dinfo->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 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) + if (H5D__create_piece_mem_map_hyper(dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") } /* end if */ else if (sel_hyper_flag && fm->f_ndims == 1 && fm->m_ndims == 1 && - H5S_SELECT_IS_REGULAR(fm->mem_space) && H5S_SELECT_IS_SINGLE(fm->mem_space)) { - if (H5D__create_chunk_mem_map_1d(fm) < 0) + H5S_SELECT_IS_REGULAR(dinfo->mem_space) && H5S_SELECT_IS_SINGLE(dinfo->mem_space)) { + if (H5D__create_piece_mem_map_1d(dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") } /* end else-if */ else { @@ -1306,7 +1291,7 @@ H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_ size_t elmt_size; /* Memory datatype size */ /* Make a copy of equivalent memory space */ - if ((tmp_mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) + if ((tmp_mspace = H5S_copy(dinfo->mem_space, TRUE, FALSE)) == NULL) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") /* De-select the mem space copy */ @@ -1324,15 +1309,18 @@ H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_ /* 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), fm->mem_space, elmt_size, 0) < 0) + if (H5S_select_iter_init(&(fm->mem_iter), dinfo->mem_space, elmt_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") iter_init = TRUE; /* Selection iteration info has been initialized */ - iter_op.op_type = H5S_SEL_ITER_OP_LIB; - iter_op.u.lib_op = H5D__chunk_mem_cb; + /* set opdata for H5D__piece_mem_cb */ + io_info_wrap.io_info = io_info; + io_info_wrap.dinfo = dinfo; + iter_op.op_type = H5S_SEL_ITER_OP_LIB; + iter_op.u.lib_op = H5D__piece_mem_cb; /* Spaces aren't the same shape, iterate over the memory selection directly */ - if (H5S_select_iterate(&bogus, file_type, fm->file_space, &iter_op, fm) < 0) + if (H5S_select_iterate(&bogus, file_type, dinfo->file_space, &iter_op, &io_info_wrap) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") } /* end else */ } /* end else */ @@ -1344,7 +1332,7 @@ done: if (H5S_close(tmp_mspace) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template") - if (H5D__chunk_io_term(fm) < 0) + if (H5D__chunk_io_term(io_info, dinfo) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping") } /* end if */ @@ -1466,14 +1454,17 @@ H5D__chunk_mem_realloc(void *chk, size_t size, const H5O_pline_t *pline) /*-------------------------------------------------------------------------- NAME - H5D__free_chunk_info + H5D__free_piece_info PURPOSE - Internal routine to destroy a chunk info node + Performs initialization before any sort of I/O on the raw data + This was derived from H5D__free_chunk_info for multi-dset work. USAGE - void H5D__free_chunk_info(chunk_info) + herr_t H5D__free_piece_info(chunk_info, key, opdata) void *chunk_info; IN: Pointer to chunk info to destroy + void *key; Unused + void *opdata; Unused RETURNS - No return value + Non-negative on success, negative on failure DESCRIPTION Releases all the memory for a chunk info node. Called by H5SL_free GLOBAL VARIABLES @@ -1481,51 +1472,48 @@ H5D__chunk_mem_realloc(void *chk, size_t size, const H5O_pline_t *pline) EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5D__free_chunk_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *opdata) +herr_t +H5D__free_piece_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *opdata) { - H5D_chunk_info_t *chunk_info = (H5D_chunk_info_t *)item; + H5D_piece_info_t *piece_info = (H5D_piece_info_t *)item; FUNC_ENTER_PACKAGE_NOERR - HDassert(chunk_info); + HDassert(piece_info); - /* Close the chunk's file dataspace, if it's not shared */ - if (!chunk_info->fspace_shared) - (void)H5S_close(chunk_info->fspace); + /* Close the piece's file dataspace, if it's not shared */ + if (!piece_info->fspace_shared) + (void)H5S_close(piece_info->fspace); else - H5S_select_all(chunk_info->fspace, TRUE); + H5S_select_all(piece_info->fspace, TRUE); - /* Close the chunk's memory dataspace, if it's not shared */ - if (!chunk_info->mspace_shared && chunk_info->mspace) - (void)H5S_close(chunk_info->mspace); + /* Close the piece's memory dataspace, if it's not shared */ + if (!piece_info->mspace_shared && piece_info->mspace) + (void)H5S_close((H5S_t *)piece_info->mspace); - /* Free the actual chunk info */ - chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info); + /* Free the actual piece info */ + piece_info = H5FL_FREE(H5D_piece_info_t, piece_info); FUNC_LEAVE_NOAPI(0) -} /* H5D__free_chunk_info() */ +} /* H5D__free_piece_info() */ /*------------------------------------------------------------------------- - * Function: H5D__create_chunk_map_single + * Function: H5D__create_piece_map_single * - * Purpose: Create chunk selections when appending a single record + * Purpose: Create piece selections when appending a single record + * This was derived from H5D__create_chunk_map_single for + * multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Tuesday, November 20, 2007 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t -#ifndef H5_HAVE_PARALLEL - H5_ATTR_UNUSED -#endif /* H5_HAVE_PARALLEL */ - *io_info) +H5D__create_piece_map_single(H5D_dset_io_info_t *di, H5D_io_info_t *io_info) { - H5D_chunk_info_t *chunk_info; /* Chunk information to insert into skip list */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + H5D_piece_info_t *piece_info; /* Piece information to insert into skip list */ hsize_t coords[H5O_LAYOUT_NDIMS]; /* Coordinates of chunk */ 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 */ @@ -1534,64 +1522,68 @@ H5D__create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t FUNC_ENTER_PACKAGE - /* Sanity check */ + /* Set convenience pointer */ + fm = di->layout_io_info.chunk_map; + + /* Sanity checks */ + HDassert(fm); HDassert(fm->f_ndims > 0); /* Get coordinate for selection */ - if (H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0) + if (H5S_SELECT_BOUNDS(di->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; + /* Initialize the 'single piece' file & memory piece information */ + piece_info = fm->single_piece_info; + piece_info->piece_points = 1; /* Set chunk location & hyperslab size */ for (u = 0; u < fm->f_ndims; u++) { /* Validate this chunk dimension */ - if (fm->layout->u.chunk.dim[u] == 0) + if (di->layout->u.chunk.dim[u] == 0) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u) HDassert(sel_start[u] == sel_end[u]); - chunk_info->scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u]; - coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u]; + piece_info->scaled[u] = sel_start[u] / di->layout->u.chunk.dim[u]; + coords[u] = piece_info->scaled[u] * di->layout->u.chunk.dim[u]; } /* end for */ - chunk_info->scaled[fm->f_ndims] = 0; + piece_info->scaled[fm->f_ndims] = 0; /* Calculate the index of this chunk */ - chunk_info->index = - H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, chunk_info->scaled); + piece_info->index = + H5VM_array_offset_pre(fm->f_ndims, di->layout->u.chunk.down_chunks, piece_info->scaled); /* Copy selection for file's dataspace into chunk dataspace */ - if (H5S_select_copy(fm->single_space, fm->file_space, FALSE) < 0) + if (H5S_select_copy(fm->single_space, di->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, 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; + piece_info->fspace = fm->single_space; /* Indicate that the chunk's file dataspace is shared */ - chunk_info->fspace_shared = TRUE; + piece_info->fspace_shared = TRUE; /* Just point at the memory dataspace & selection */ - chunk_info->mspace = fm->mem_space; + piece_info->mspace = di->mem_space; /* Indicate that the chunk's memory dataspace is shared */ - chunk_info->mspace_shared = TRUE; + piece_info->mspace_shared = TRUE; + + /* make connection to related dset info from this piece_info */ + piece_info->dset_info = di; + + /* Add piece to global piece_count */ + io_info->piece_count++; done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__create_chunk_map_single() */ +} /* end H5D__create_piece_map_single() */ /*------------------------------------------------------------------------- - * Function: H5D__create_chunk_file_map_all + * Function: H5D__create_piece_file_map_all * * Purpose: Create all chunk selections in file, for an "all" selection. * @@ -1603,21 +1595,18 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, const H5D_io_info_t -#ifndef H5_HAVE_PARALLEL - H5_ATTR_UNUSED -#endif /* H5_HAVE_PARALLEL */ - *io_info) +H5D__create_piece_file_map_all(H5D_dset_io_info_t *di, H5D_io_info_t *io_info) { - H5S_t *tmp_fchunk = NULL; /* Temporary file dataspace */ - hsize_t file_dims[H5S_MAX_RANK]; /* File dataspace dims */ - hsize_t sel_points; /* Number of elements in file selection */ - hsize_t zeros[H5S_MAX_RANK]; /* All zero vector (for start parameter to setting hyperslab on partial - chunks) */ - hsize_t coords[H5S_MAX_RANK]; /* Current coordinates of chunk */ - hsize_t end[H5S_MAX_RANK]; /* Final coordinates of chunk */ - hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ - hsize_t chunk_index; /* "Index" of chunk */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + H5S_t *tmp_fchunk = NULL; /* Temporary file dataspace */ + hsize_t file_dims[H5S_MAX_RANK]; /* File dataspace dims */ + hsize_t sel_points; /* Number of elements in file selection */ + hsize_t zeros[H5S_MAX_RANK]; /* All zero vector (for start parameter to setting hyperslab on partial + chunks) */ + hsize_t coords[H5S_MAX_RANK]; /* Current coordinates of chunk */ + hsize_t end[H5S_MAX_RANK]; /* Final coordinates of chunk */ + hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ + hsize_t chunk_index; /* "Index" of chunk */ hsize_t curr_partial_clip[H5S_MAX_RANK]; /* Current partial dimension sizes to clip against */ hsize_t partial_dim_size[H5S_MAX_RANK]; /* Size of a partial dimension */ hbool_t is_partial_dim[H5S_MAX_RANK]; /* Whether a dimension is currently a partial chunk */ @@ -1627,14 +1616,18 @@ H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, const H5D_io_info_t FUNC_ENTER_PACKAGE - /* Sanity check */ + /* Set convenience pointer */ + fm = di->layout_io_info.chunk_map; + + /* Sanity checks */ + HDassert(fm); HDassert(fm->f_ndims > 0); /* Get number of elements selected in file */ - sel_points = fm->nelmts; + sel_points = di->nelmts; /* Get dataspace dimensions */ - if (H5S_get_simple_extent_dims(fm->file_space, file_dims, NULL) < 0) + if (H5S_get_simple_extent_dims(di->file_space, file_dims, NULL) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") /* Set initial chunk location, partial dimensions, etc */ @@ -1642,7 +1635,7 @@ H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, const H5D_io_info_t HDmemset(zeros, 0, sizeof(zeros)); for (u = 0; u < fm->f_ndims; u++) { /* Validate this chunk dimension */ - if (fm->layout->u.chunk.dim[u] == 0) + if (di->layout->u.chunk.dim[u] == 0) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u) /* Set up start / end coordinates for first chunk */ @@ -1672,54 +1665,54 @@ H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, const H5D_io_info_t /* Iterate through each chunk in the dataset */ while (sel_points) { - H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */ + H5D_piece_info_t *new_piece_info; /* Piece information to insert into skip list */ hsize_t chunk_points; /* Number of elements in chunk selection */ - /* Add temporary chunk to the list of chunks */ + /* Add temporary chunk to the list of pieces */ /* Allocate the file & memory chunk information */ - if (NULL == (new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk info") + if (NULL == (new_piece_info = H5FL_MALLOC(H5D_piece_info_t))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate piece info") /* Initialize the chunk information */ /* Set the chunk index */ - new_chunk_info->index = chunk_index; - -#ifdef H5_HAVE_PARALLEL - /* Store chunk selection information, for multi-chunk I/O */ - if (io_info->using_mpi_vfd) - fm->select_chunk[chunk_index] = new_chunk_info; -#endif /* H5_HAVE_PARALLEL */ + new_piece_info->index = chunk_index; /* Set the file chunk dataspace */ - if (NULL == (new_chunk_info->fspace = H5S_copy(tmp_fchunk, TRUE, FALSE))) + if (NULL == (new_piece_info->fspace = H5S_copy(tmp_fchunk, TRUE, FALSE))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy chunk dataspace") - new_chunk_info->fspace_shared = FALSE; + new_piece_info->fspace_shared = FALSE; /* If there are partial dimensions for this chunk, set the hyperslab for them */ if (num_partial_dims > 0) - if (H5S_select_hyperslab(new_chunk_info->fspace, H5S_SELECT_SET, zeros, NULL, curr_partial_clip, + if (H5S_select_hyperslab(new_piece_info->fspace, H5S_SELECT_SET, zeros, NULL, curr_partial_clip, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk selection") /* Set the memory chunk dataspace */ - new_chunk_info->mspace = NULL; - new_chunk_info->mspace_shared = FALSE; + new_piece_info->mspace = NULL; + new_piece_info->mspace_shared = FALSE; /* Copy the chunk's scaled coordinates */ - H5MM_memcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); - new_chunk_info->scaled[fm->f_ndims] = 0; + H5MM_memcpy(new_piece_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); + new_piece_info->scaled[fm->f_ndims] = 0; + + /* make connection to related dset info from this piece_info */ + new_piece_info->dset_info = di; /* 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); + if (H5SL_insert(fm->dset_sel_pieces, new_piece_info, &new_piece_info->index) < 0) { + H5D__free_piece_info(new_piece_info, NULL, NULL); HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list") } /* end if */ + /* Add piece to global piece_count*/ + io_info->piece_count++; + /* Get number of elements selected in chunk */ - chunk_points = H5S_GET_SELECT_NPOINTS(new_chunk_info->fspace); - H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, chunk_points, hsize_t); + chunk_points = H5S_GET_SELECT_NPOINTS(new_piece_info->fspace); + new_piece_info->piece_points = chunk_points; /* Decrement # of points left in file selection */ sel_points -= chunk_points; @@ -1796,74 +1789,75 @@ done: } /* end H5D__create_chunk_file_map_all() */ /*------------------------------------------------------------------------- - * Function: H5D__create_chunk_file_map_hyper + * Function: H5D__create_piece_file_map_hyper * - * Purpose: Create all chunk selections in file, for a hyperslab selection. + * Purpose: Create all chunk selections in file. + * This was derived from H5D__create_chunk_file_map_hyper for + * multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, May 29, 2003 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t -#ifndef H5_HAVE_PARALLEL - H5_ATTR_UNUSED -#endif /* H5_HAVE_PARALLEL */ - *io_info) +H5D__create_piece_file_map_hyper(H5D_dset_io_info_t *dinfo, H5D_io_info_t *io_info) { - H5S_t *tmp_fchunk = NULL; /* Temporary file dataspace */ - 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]; /* Final coordinates of chunk */ - hsize_t chunk_index; /* Index of chunk */ - hsize_t start_scaled[H5S_MAX_RANK]; /* Starting scaled coordinates of selection */ - hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ - int curr_dim; /* Current dimension to increment */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + H5S_t *tmp_fchunk = NULL; /* Temporary file dataspace */ + 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]; /* Final coordinates of chunk */ + hsize_t chunk_index; /* Index of chunk */ + hsize_t start_scaled[H5S_MAX_RANK]; /* Starting scaled coordinates of selection */ + hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ + int curr_dim; /* Current dimension to increment */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE - /* Sanity check */ + /* Set convenience pointer */ + fm = dinfo->layout_io_info.chunk_map; + + /* Sanity checks */ + HDassert(fm); HDassert(fm->f_ndims > 0); /* Get number of elements selected in file */ - sel_points = fm->nelmts; + sel_points = dinfo->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) + if (H5S_SELECT_BOUNDS(dinfo->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; u < fm->f_ndims; u++) { /* Validate this chunk dimension */ - if (fm->layout->u.chunk.dim[u] == 0) + if (dinfo->layout->u.chunk.dim[u] == 0) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u) - scaled[u] = start_scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u]; - coords[u] = start_coords[u] = scaled[u] * fm->layout->u.chunk.dim[u]; + scaled[u] = start_scaled[u] = sel_start[u] / dinfo->layout->u.chunk.dim[u]; + coords[u] = start_coords[u] = scaled[u] * dinfo->layout->u.chunk.dim[u]; end[u] = (coords[u] + fm->chunk_dim[u]) - 1; } /* end for */ /* Calculate the index of this chunk */ - chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled); + chunk_index = H5VM_array_offset_pre(fm->f_ndims, dinfo->layout->u.chunk.down_chunks, scaled); /* Iterate through each chunk in the dataset */ while (sel_points) { /* Check for intersection of current chunk and file selection */ - if (TRUE == H5S_SELECT_INTERSECT_BLOCK(fm->file_space, coords, end)) { - H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */ + if (TRUE == H5S_SELECT_INTERSECT_BLOCK(dinfo->file_space, coords, end)) { + H5D_piece_info_t *new_piece_info; /* chunk information to insert into skip list */ hsize_t chunk_points; /* Number of elements in chunk selection */ /* Create dataspace for chunk, 'AND'ing the overall selection with * the current chunk. */ - if (H5S_combine_hyperslab(fm->file_space, H5S_SELECT_AND, coords, NULL, fm->chunk_dim, NULL, + if (H5S_combine_hyperslab(dinfo->file_space, H5S_SELECT_AND, coords, NULL, fm->chunk_dim, NULL, &tmp_fchunk) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to combine file space selection with chunk block") @@ -1879,42 +1873,42 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* 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))) + if (NULL == (new_piece_info = H5FL_MALLOC(H5D_piece_info_t))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk info") /* Initialize the chunk information */ /* Set the chunk index */ - new_chunk_info->index = chunk_index; - -#ifdef H5_HAVE_PARALLEL - /* Store chunk selection information, for multi-chunk I/O */ - if (io_info->using_mpi_vfd) - fm->select_chunk[chunk_index] = new_chunk_info; -#endif /* H5_HAVE_PARALLEL */ + new_piece_info->index = chunk_index; /* Set the file chunk dataspace */ - new_chunk_info->fspace = tmp_fchunk; - new_chunk_info->fspace_shared = FALSE; + new_piece_info->fspace = tmp_fchunk; + new_piece_info->fspace_shared = FALSE; tmp_fchunk = NULL; /* Set the memory chunk dataspace */ - new_chunk_info->mspace = NULL; - new_chunk_info->mspace_shared = FALSE; + new_piece_info->mspace = NULL; + new_piece_info->mspace_shared = FALSE; /* Copy the chunk's scaled coordinates */ - H5MM_memcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); - new_chunk_info->scaled[fm->f_ndims] = 0; + H5MM_memcpy(new_piece_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); + new_piece_info->scaled[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") + /* make connection to related dset info from this piece_info */ + new_piece_info->dset_info = dinfo; + + /* Add piece to global piece_count */ + io_info->piece_count++; + + /* Insert the new piece into the skip list */ + if (H5SL_insert(fm->dset_sel_pieces, new_piece_info, &new_piece_info->index) < 0) { + H5D__free_piece_info(new_piece_info, NULL, NULL); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert piece into skip list") } /* end if */ /* Get number of elements selected in chunk */ - chunk_points = H5S_GET_SELECT_NPOINTS(new_chunk_info->fspace); - H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, chunk_points, hsize_t); + chunk_points = H5S_GET_SELECT_NPOINTS(new_piece_info->fspace); + new_piece_info->piece_points = chunk_points; /* Decrement # of points left in file selection */ sel_points -= chunk_points; @@ -1957,7 +1951,7 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t } while (curr_dim >= 0 && (coords[curr_dim] > sel_end[curr_dim])); /* Re-calculate the index of this chunk */ - chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled); + chunk_index = H5VM_array_offset_pre(fm->f_ndims, dinfo->layout->u.chunk.down_chunks, scaled); } /* end if */ } /* end while */ @@ -1968,28 +1962,29 @@ done: HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't release temporary dataspace") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__create_chunk_file_map_hyper() */ +} /* end H5D__create_piece_file_map_hyper() */ /*------------------------------------------------------------------------- - * Function: H5D__create_chunk_mem_map_hyper + * Function: H5D__create_piece_mem_map_hyper * - * Purpose: Create all chunk selections in memory by copying the file + * Purpose: Create all chunk selections in memory by copying the file * chunk selections and adjusting their offsets to be correct - * for the memory. + * or the memory. + * This was derived from H5D__create_chunk_mem_map_hyper for + * multi-dset work. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, May 29, 2003 + * Programmer: Jonathan Kim Nov, 2013 * * 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) +H5D__create_piece_mem_map_hyper(const H5D_dset_io_info_t *dinfo) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + H5D_piece_info_t *piece_info; /* Pointer to piece information */ H5SL_node_t *curr_node; /* Current node in skip list */ hsize_t file_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */ hsize_t file_sel_end[H5S_MAX_RANK]; /* Offset of high bound of file selection */ @@ -2002,30 +1997,33 @@ H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) FUNC_ENTER_PACKAGE /* Sanity check */ - HDassert(fm->f_ndims > 0); + HDassert(dinfo->layout_io_info.chunk_map->f_ndims > 0); + + /* Set convenience pointer */ + fm = dinfo->layout_io_info.chunk_map; /* Check for all I/O going to a single chunk */ - if (H5SL_count(fm->sel_chunks) == 1) { + if (H5SL_count(fm->dset_sel_pieces) == 1) { /* Get the node */ - curr_node = H5SL_first(fm->sel_chunks); + curr_node = H5SL_first(fm->dset_sel_pieces); - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + /* Get pointer to piece's information */ + piece_info = (H5D_piece_info_t *)H5SL_item(curr_node); + HDassert(piece_info); /* Just point at the memory dataspace & selection */ - chunk_info->mspace = fm->mem_space; + piece_info->mspace = dinfo->mem_space; - /* Indicate that the chunk's memory space is shared */ - chunk_info->mspace_shared = TRUE; + /* Indicate that the piece's memory space is shared */ + piece_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) + if (H5S_SELECT_BOUNDS(dinfo->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) + if (H5S_SELECT_BOUNDS(dinfo->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 */ @@ -2037,28 +2035,29 @@ H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) } /* end for */ /* Iterate over each chunk in the chunk list */ - curr_node = H5SL_first(fm->sel_chunks); + HDassert(fm->dset_sel_pieces); + curr_node = H5SL_first(fm->dset_sel_pieces); while (curr_node) { hsize_t coords[H5S_MAX_RANK]; /* Current coordinates of chunk */ - hssize_t chunk_adjust[H5S_MAX_RANK]; /* Adjustment to make to a particular chunk */ + hssize_t piece_adjust[H5S_MAX_RANK]; /* Adjustment to make to a particular chunk */ H5S_sel_type chunk_sel_type; /* Chunk's selection type */ - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + /* Get pointer to piece's information */ + piece_info = (H5D_piece_info_t *)H5SL_item(curr_node); + HDassert(piece_info); /* Compute the chunk coordinates from the scaled coordinates */ for (u = 0; u < fm->f_ndims; u++) - coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u]; + coords[u] = piece_info->scaled[u] * dinfo->layout->u.chunk.dim[u]; /* Copy the information */ /* Copy the memory dataspace */ - if ((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) + if ((piece_info->mspace = H5S_copy(dinfo->mem_space, TRUE, FALSE)) == NULL) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") /* Get the chunk's selection type */ - if ((chunk_sel_type = H5S_GET_SELECT_TYPE(chunk_info->fspace)) < H5S_SEL_NONE) + if ((chunk_sel_type = H5S_GET_SELECT_TYPE(piece_info->fspace)) < H5S_SEL_NONE) HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") /* Set memory selection for "all" chunk selections */ @@ -2068,7 +2067,7 @@ H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) coords[u] = (hsize_t)((hssize_t)coords[u] - adjust[u]); /* Set to same shape as chunk */ - if (H5S_select_hyperslab(chunk_info->mspace, H5S_SELECT_SET, coords, NULL, fm->chunk_dim, + if (H5S_select_hyperslab(piece_info->mspace, H5S_SELECT_SET, coords, NULL, fm->chunk_dim, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk memory selection") } /* end if */ @@ -2077,32 +2076,32 @@ H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) HDassert(H5S_SEL_HYPERSLABS == chunk_sel_type); /* Copy the file chunk's selection */ - if (H5S_SELECT_COPY(chunk_info->mspace, chunk_info->fspace, FALSE) < 0) + if (H5S_SELECT_COPY(piece_info->mspace, piece_info->fspace, FALSE) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection") /* Compute the adjustment for this chunk */ for (u = 0; u < fm->f_ndims; u++) { /* Compensate for the chunk offset */ H5_CHECK_OVERFLOW(coords[u], hsize_t, hssize_t); - chunk_adjust[u] = adjust[u] - (hssize_t)coords[u]; + piece_adjust[u] = adjust[u] - (hssize_t)coords[u]; } /* end for */ /* Adjust the selection */ - if (H5S_SELECT_ADJUST_S(chunk_info->mspace, chunk_adjust) < 0) + if (H5S_SELECT_ADJUST_S(piece_info->mspace, piece_adjust) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to adjust selection") } /* end else */ - /* Get the next chunk node in the skip list */ + /* Get the next piece 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() */ +} /* end H5D__create_piece_mem_map_hyper() */ /*------------------------------------------------------------------------- - * Function: H5D__create_mem_map_1d + * Function: H5D__create_piece_mem_map_1d * * Purpose: Create all chunk selections for 1-dimensional regular memory space * that has only one single block in the selection @@ -2115,31 +2114,36 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t *fm) +H5D__create_piece_mem_map_1d(const H5D_dset_io_info_t *dinfo) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + H5D_piece_info_t *piece_info; /* Pointer to chunk information */ H5SL_node_t *curr_node; /* Current node in skip list */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ - HDassert(fm->f_ndims > 0); + HDassert(dinfo->layout_io_info.chunk_map->f_ndims > 0); + + /* Set convenience pointer */ + fm = dinfo->layout_io_info.chunk_map; + HDassert(fm); /* Check for all I/O going to a single chunk */ - if (H5SL_count(fm->sel_chunks) == 1) { + if (H5SL_count(fm->dset_sel_pieces) == 1) { /* Get the node */ - curr_node = H5SL_first(fm->sel_chunks); + curr_node = H5SL_first(fm->dset_sel_pieces); /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + piece_info = (H5D_piece_info_t *)H5SL_item(curr_node); + HDassert(piece_info); /* Just point at the memory dataspace & selection */ - chunk_info->mspace = fm->mem_space; + piece_info->mspace = dinfo->mem_space; /* Indicate that the chunk's memory space is shared */ - chunk_info->mspace_shared = TRUE; + piece_info->mspace_shared = TRUE; } /* end if */ else { hsize_t mem_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */ @@ -2147,26 +2151,26 @@ H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t *fm) HDassert(fm->m_ndims == 1); - if (H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0) + if (H5S_SELECT_BOUNDS(dinfo->mem_space, mem_sel_start, mem_sel_end) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") /* Iterate over each chunk in the chunk list */ - curr_node = H5SL_first(fm->sel_chunks); + curr_node = H5SL_first(fm->dset_sel_pieces); while (curr_node) { hsize_t chunk_points; /* Number of elements in chunk selection */ hsize_t tmp_count = 1; /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + piece_info = (H5D_piece_info_t *)H5SL_item(curr_node); + HDassert(piece_info); /* Copy the memory dataspace */ - if ((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) + if ((piece_info->mspace = H5S_copy(dinfo->mem_space, TRUE, FALSE)) == NULL) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") - chunk_points = H5S_GET_SELECT_NPOINTS(chunk_info->fspace); + chunk_points = H5S_GET_SELECT_NPOINTS(piece_info->fspace); - if (H5S_select_hyperslab(chunk_info->mspace, H5S_SELECT_SET, mem_sel_start, NULL, &tmp_count, + if (H5S_select_hyperslab(piece_info->mspace, H5S_SELECT_SET, mem_sel_start, NULL, &tmp_count, &chunk_points) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk memory selection") @@ -2179,177 +2183,187 @@ H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t *fm) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__create_chunk_mem_map_1d() */ +} /* end H5D__create_piece_mem_map_1d() */ /*------------------------------------------------------------------------- - * Function: H5D__chunk_file_cb + * Function: H5D__piece_file_cb * - * Purpose: Callback routine for file selection iterator. Used when + * 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 + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Wednesday, July 23, 2003 + * Programmer: Jonathan Kim Nov, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, - const hsize_t *coords, void *_udata) +H5D__piece_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, + const hsize_t *coords, void *_opdata) { - H5D_chunk_file_iter_ud_t *udata = (H5D_chunk_file_iter_ud_t *)_udata; /* User data for operation */ - H5D_chunk_map_t *fm = udata->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 */ - hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + H5D_io_info_wrap_t *opdata = (H5D_io_info_wrap_t *)_opdata; + H5D_io_info_t *io_info = (H5D_io_info_t *)opdata->io_info; /* io info for multi dset */ + H5D_dset_io_info_t *dinfo = (H5D_dset_io_info_t *)opdata->dinfo; /* File<->memory piece mapping info */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + H5D_piece_info_t *piece_info; /* Chunk information for current piece */ + hsize_t coords_in_chunk[H5O_LAYOUT_NDIMS]; /* Coordinates of element in chunk */ + hsize_t chunk_index; /* Chunk index */ + hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE + /* Set convenience pointer */ + fm = dinfo->layout_io_info.chunk_map; + /* Calculate the index of this chunk */ - chunk_index = H5VM_chunk_index_scaled(ndims, coords, fm->layout->u.chunk.dim, - fm->layout->u.chunk.down_chunks, scaled); + chunk_index = H5VM_chunk_index_scaled(ndims, coords, dinfo->layout->u.chunk.dim, + dinfo->layout->u.chunk.down_chunks, scaled); /* 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; + piece_info = fm->last_piece_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))) { + * find the chunk in the skip list. If we do not find it, create + * a new node. */ + if (NULL == (piece_info = (H5D_piece_info_t *)H5SL_search(fm->dset_sel_pieces, &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))) + if (NULL == (piece_info = H5FL_MALLOC(H5D_piece_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; + piece_info->index = chunk_index; /* Create a dataspace for the chunk */ if ((fspace = H5S_create_simple(fm->f_ndims, fm->chunk_dim, NULL)) == NULL) { - chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info); + piece_info = H5FL_FREE(H5D_piece_info_t, piece_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); - chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info); + piece_info = H5FL_FREE(H5D_piece_info_t, piece_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; + piece_info->fspace = fspace; + piece_info->fspace_shared = FALSE; /* Set the memory chunk dataspace */ - chunk_info->mspace = NULL; - chunk_info->mspace_shared = FALSE; + piece_info->mspace = NULL; + piece_info->mspace_shared = FALSE; /* Set the number of selected elements in chunk to zero */ - chunk_info->chunk_points = 0; + piece_info->piece_points = 0; /* Set the chunk's scaled coordinates */ - H5MM_memcpy(chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); - chunk_info->scaled[fm->f_ndims] = 0; + H5MM_memcpy(piece_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); + piece_info->scaled[fm->f_ndims] = 0; + + /* Make connection to related dset info from this piece_info */ + piece_info->dset_info = dinfo; /* 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") + if (H5SL_insert(fm->dset_sel_pieces, piece_info, &piece_info->index) < 0) { + H5D__free_piece_info(piece_info, NULL, NULL); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into dataset skip list") } /* end if */ - } /* end if */ -#ifdef H5_HAVE_PARALLEL - /* Store chunk selection information, for collective multi-chunk I/O */ - if (udata->io_info->using_mpi_vfd) - fm->select_chunk[chunk_index] = chunk_info; -#endif /* H5_HAVE_PARALLEL */ + /* Add piece to global piece_count */ + io_info->piece_count++; + } /* end if */ /* Update the "last chunk seen" information */ fm->last_index = chunk_index; - fm->last_chunk_info = chunk_info; + fm->last_piece_info = piece_info; } /* end else */ /* Get the offset of the element within the chunk */ for (u = 0; u < fm->f_ndims; u++) - coords_in_chunk[u] = coords[u] - (scaled[u] * fm->layout->u.chunk.dim[u]); + coords_in_chunk[u] = coords[u] - (scaled[u] * dinfo->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) + if (H5S_select_elements(piece_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++; + piece_info->piece_points++; done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_file_cb() */ +} /* end H5D__piece_file_cb */ /*------------------------------------------------------------------------- - * Function: H5D__chunk_mem_cb + * Function: H5D__piece_mem_cb * - * Purpose: Callback routine for file selection iterator. Used when - * creating selections in memory for each chunk. + * Purpose: Callback routine for file selection iterator. Used when + * creating selections in memory for each piece. + * This was derived from H5D__chunk_mem_cb for multi-dset + * work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Raymond Lu - * Thursday, April 10, 2003 + * Programmer: Jonathan Kim Nov, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, - const hsize_t *coords, void *_fm) +H5D__piece_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, + const hsize_t *coords, void *_opdata) { - 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[H5S_MAX_RANK]; /* Coordinates of element in memory */ - hsize_t chunk_index; /* Chunk index */ - herr_t ret_value = SUCCEED; /* Return value */ + H5D_io_info_wrap_t *opdata = (H5D_io_info_wrap_t *)_opdata; + H5D_dset_io_info_t *dinfo = (H5D_dset_io_info_t *)opdata->dinfo; /* File<->memory chunk mapping info */ + H5D_piece_info_t *piece_info; /* Chunk information for current chunk */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + hsize_t coords_in_mem[H5S_MAX_RANK]; /* Coordinates of element in memory */ + hsize_t chunk_index; /* Chunk index */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE + /* Set convenience pointer */ + fm = dinfo->layout_io_info.chunk_map; + /* Calculate the index of this chunk */ - chunk_index = H5VM_chunk_index(ndims, coords, fm->layout->u.chunk.dim, fm->layout->u.chunk.down_chunks); + chunk_index = + H5VM_chunk_index(ndims, coords, dinfo->layout->u.chunk.dim, dinfo->layout->u.chunk.down_chunks); /* 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; + piece_info = fm->last_piece_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. + * find the chunk in the dataset 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, H5_ITER_ERROR, "can't locate chunk in skip list") + if (NULL == (piece_info = (H5D_piece_info_t *)H5SL_search(fm->dset_sel_pieces, &chunk_index))) + HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, H5_ITER_ERROR, "can't locate piece in dataset skip list") /* Check if the chunk already has a memory space */ - if (NULL == chunk_info->mspace) + if (NULL == piece_info->mspace) /* Copy the template memory chunk dataspace */ - if (NULL == (chunk_info->mspace = H5S_copy(fm->mchunk_tmpl, FALSE, FALSE))) + if (NULL == (piece_info->mspace = H5S_copy(fm->mchunk_tmpl, FALSE, FALSE))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy file space") /* Update the "last chunk seen" information */ fm->last_index = chunk_index; - fm->last_chunk_info = chunk_info; + fm->last_piece_info = piece_info; } /* end else */ /* Get coordinates of selection iterator for memory */ @@ -2358,11 +2372,11 @@ H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, u /* 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) + if (H5S_select_elements(piece_info->mspace, H5S_SELECT_APPEND, (size_t)1, coords_in_mem) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, H5_ITER_ERROR, "unable to select element") } /* end if */ else { - if (H5S_hyper_add_span_element(chunk_info->mspace, fm->m_ndims, coords_in_mem) < 0) + if (H5S_hyper_add_span_element(piece_info->mspace, fm->m_ndims, coords_in_mem) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, H5_ITER_ERROR, "unable to select element") } /* end else */ @@ -2372,7 +2386,62 @@ H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, u done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_mem_cb() */ +} /* end H5D__piece_mem_cb() */ + +/*------------------------------------------------------------------------- + * Function: H5D__chunk_mdio_init + * + * Purpose: Performs second phase of initialization for multi-dataset + * I/O. Currently looks up chunk addresses and adds chunks to + * sel_pieces. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__chunk_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) +{ + H5SL_node_t *piece_node; /* Current node in chunk skip list */ + H5D_piece_info_t *piece_info; /* Piece information for current piece */ + H5D_chunk_ud_t udata; /* Chunk data from index */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Get first node in skip list. Note we don't check for failure since NULL + * simply indicates an empty skip list. */ + piece_node = H5D_CHUNK_GET_FIRST_NODE(dinfo); + + /* Iterate over skip list */ + while (piece_node) { + /* Get piece info */ + if (NULL == (piece_info = (H5D_piece_info_t *)H5D_CHUNK_GET_NODE_INFO(dinfo, piece_node))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't get piece info from list") + + /* Get the info for the chunk in the file */ + if (H5D__chunk_lookup(dinfo->dset, piece_info->scaled, &udata) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") + + /* Save chunk file address */ + piece_info->faddr = udata.chunk_block.offset; + + /* Add piece to MDIO operation if it has a file address */ + if (H5F_addr_defined(piece_info->faddr)) { + HDassert(io_info->sel_pieces); + HDassert(io_info->pieces_added < io_info->piece_count); + + /* Add to sel_pieces and update pieces_added */ + io_info->sel_pieces[io_info->pieces_added++] = piece_info; + } + + /* Advance to next skip list node */ + piece_node = H5D_CHUNK_GET_NEXT_NODE(dinfo, piece_node); + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__chunk_mdio_init() */ /*------------------------------------------------------------------------- * Function: H5D__chunk_cacheable @@ -2388,16 +2457,19 @@ done: *------------------------------------------------------------------------- */ htri_t -H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_op) +H5D__chunk_cacheable(const H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, haddr_t caddr, + hbool_t write_op) { - const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */ - hbool_t has_filters = FALSE; /* Whether there are filters on the chunk or not */ - htri_t ret_value = FAIL; /* Return value */ + const H5D_t *dataset = NULL; /* Local pointer to dataset info */ + hbool_t has_filters = FALSE; /* Whether there are filters on the chunk or not */ + htri_t ret_value = FAIL; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(io_info); + HDassert(dset_info); + dataset = dset_info->dset; HDassert(dataset); /* Must bring the whole chunk in if there are any filters on the chunk. @@ -2405,9 +2477,9 @@ H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_ * chunk because it is a partial edge chunk. */ if (dataset->shared->dcpl_cache.pline.nused > 0) { if (dataset->shared->layout.u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) { - has_filters = !H5D__chunk_is_partial_edge_chunk( - io_info->dset->shared->ndims, io_info->dset->shared->layout.u.chunk.dim, - io_info->store->chunk.scaled, io_info->dset->shared->curr_dims); + has_filters = + !H5D__chunk_is_partial_edge_chunk(dataset->shared->ndims, dataset->shared->layout.u.chunk.dim, + dset_info->store->chunk.scaled, dataset->shared->curr_dims); } /* end if */ else has_filters = TRUE; @@ -2478,7 +2550,7 @@ done: *------------------------------------------------------------------------- */ static htri_t -H5D__chunk_may_use_select_io(const H5D_io_info_t *io_info) +H5D__chunk_may_use_select_io(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info) { const H5D_t *dataset = NULL; /* Local pointer to dataset info */ htri_t ret_value = FAIL; /* Return value */ @@ -2487,19 +2559,19 @@ H5D__chunk_may_use_select_io(const H5D_io_info_t *io_info) /* Sanity check */ HDassert(io_info); + HDassert(dset_info); - dataset = io_info->dset; + dataset = dset_info->dset; HDassert(dataset); /* Don't use selection I/O if it's globally disabled, there is a type * conversion, or if there are filters on the dataset (for now) */ - if (!H5_use_selection_io_g || io_info->io_ops.single_read != H5D__select_read || - dataset->shared->dcpl_cache.pline.nused > 0) + if (dset_info->io_ops.single_read != H5D__select_read || dataset->shared->dcpl_cache.pline.nused > 0) ret_value = FALSE; else { hbool_t page_buf_enabled; - HDassert(io_info->io_ops.single_write == H5D__select_write); + HDassert(dset_info->io_ops.single_write == H5D__select_write); /* Check if the page buffer is enabled */ if (H5PB_enabled(io_info->f_sh, H5FD_MEM_DRAW, &page_buf_enabled) < 0) @@ -2549,36 +2621,40 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t H5_ATTR_UNUSED nelmts, - H5S_t H5_ATTR_UNUSED *file_space, H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t *fm) +H5D__chunk_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info) { - H5SL_node_t *chunk_node; /* Current node in chunk skip list */ - H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */ - uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */ - hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */ - H5S_t **chunk_mem_spaces = NULL; /* Array of chunk memory spaces */ - H5S_t *chunk_mem_spaces_static[8]; /* Static buffer for chunk_mem_spaces */ - H5S_t **chunk_file_spaces = NULL; /* Array of chunk file spaces */ - H5S_t *chunk_file_spaces_static[8]; /* Static buffer for chunk_file_spaces */ - haddr_t *chunk_addrs = NULL; /* Array of chunk addresses */ - haddr_t chunk_addrs_static[8]; /* Static buffer for chunk_addrs */ - herr_t ret_value = SUCCEED; /*return value */ + H5SL_node_t *chunk_node; /* Current node in chunk skip list */ + H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */ + H5D_dset_io_info_t nonexistent_dset_info; /* "nonexistent" I/O dset info object */ + H5D_dset_io_info_t ctg_dset_info; /* Contiguous I/O dset info object */ + H5D_dset_io_info_t cpt_dset_info; /* Compact I/O dset info object */ + uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */ + hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */ + H5S_t **chunk_mem_spaces = NULL; /* Array of chunk memory spaces */ + H5S_t *chunk_mem_spaces_local[8]; /* Local buffer for chunk_mem_spaces */ + H5S_t **chunk_file_spaces = NULL; /* Array of chunk file spaces */ + H5S_t *chunk_file_spaces_local[8]; /* Local buffer for chunk_file_spaces */ + haddr_t *chunk_addrs = NULL; /* Array of chunk addresses */ + haddr_t chunk_addrs_local[8]; /* Local buffer for chunk_addrs */ + herr_t ret_value = SUCCEED; /*return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.rbuf); - HDassert(type_info); - HDassert(fm); + HDassert(dset_info); + HDassert(dset_info->buf.vp); /* Set up "nonexistent" I/O info object */ H5MM_memcpy(&nonexistent_io_info, io_info, sizeof(nonexistent_io_info)); - nonexistent_io_info.layout_ops = *H5D_LOPS_NONEXISTENT; + H5MM_memcpy(&nonexistent_dset_info, dset_info, sizeof(nonexistent_dset_info)); + nonexistent_dset_info.layout_ops = *H5D_LOPS_NONEXISTENT; + nonexistent_io_info.dsets_info = &nonexistent_dset_info; + nonexistent_io_info.count = 1; { - const H5O_fill_t *fill = &(io_info->dset->shared->dcpl_cache.fill); /* Fill value info */ - H5D_fill_value_t fill_status; /* Fill value status */ + const H5O_fill_t *fill = &(dset_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) @@ -2596,48 +2672,53 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ /* Different blocks depending on whether we're using selection I/O */ if (io_info->use_select_io) { size_t num_chunks; - size_t element_sizes[2] = {type_info->dst_type_size, 0}; - void *bufs[2] = {io_info->u.rbuf, NULL}; - - /* Cache number of chunks */ - num_chunks = H5D_CHUNK_GET_NODE_COUNT(fm); - - /* Allocate arrays of dataspaces and offsets for use with selection I/O, - * or point to static buffers */ - HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) == - sizeof(chunk_file_spaces_static) / sizeof(chunk_file_spaces_static[0])); - HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) == - sizeof(chunk_addrs_static) / sizeof(chunk_addrs_static[0])); - if (num_chunks > (sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]))) { - if (NULL == (chunk_mem_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for memory space list") - if (NULL == (chunk_file_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list") - if (NULL == (chunk_addrs = H5MM_malloc(num_chunks * sizeof(haddr_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for chunk address list") - } /* end if */ - else { - chunk_mem_spaces = chunk_mem_spaces_static; - chunk_file_spaces = chunk_file_spaces_static; - chunk_addrs = chunk_addrs_static; - } /* end else */ + size_t element_sizes[2] = {dset_info->type_info.src_type_size, 0}; + void *bufs[2] = {dset_info->buf.vp, NULL}; + + /* Only create selection I/O arrays if not performing multi dataset I/O, + * otherwise the higher level will handle it */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + /* Cache number of chunks */ + num_chunks = H5D_CHUNK_GET_NODE_COUNT(dset_info); + + /* Allocate arrays of dataspaces and offsets for use with selection I/O, + * or point to local buffers */ + HDassert(sizeof(chunk_mem_spaces_local) / sizeof(chunk_mem_spaces_local[0]) == + sizeof(chunk_file_spaces_local) / sizeof(chunk_file_spaces_local[0])); + HDassert(sizeof(chunk_mem_spaces_local) / sizeof(chunk_mem_spaces_local[0]) == + sizeof(chunk_addrs_local) / sizeof(chunk_addrs_local[0])); + if (num_chunks > (sizeof(chunk_mem_spaces_local) / sizeof(chunk_mem_spaces_local[0]))) { + if (NULL == (chunk_mem_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for memory space list") + if (NULL == (chunk_file_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for file space list") + if (NULL == (chunk_addrs = H5MM_malloc(num_chunks * sizeof(haddr_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for chunk address list") + } /* end if */ + else { + chunk_mem_spaces = chunk_mem_spaces_local; + chunk_file_spaces = chunk_file_spaces_local; + chunk_addrs = chunk_addrs_local; + } /* end else */ - /* Reset num_chunks */ - num_chunks = 0; + /* Reset num_chunks */ + num_chunks = 0; + } /* end if */ /* Iterate through nodes in chunk skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); + chunk_node = H5D_CHUNK_GET_FIRST_NODE(dset_info); while (chunk_node) { - H5D_chunk_info_t *chunk_info; /* Chunk information */ + H5D_piece_info_t *chunk_info; /* Chunk information */ H5D_chunk_ud_t udata; /* Chunk index pass-through */ /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + chunk_info = H5D_CHUNK_GET_NODE_INFO(dset_info, chunk_node); /* Get the info for the chunk in the file */ - if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0) + if (H5D__chunk_lookup(dset_info->dset, chunk_info->scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") /* There should be no chunks cached */ @@ -2649,45 +2730,66 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ /* Check for non-existent chunk & skip it if appropriate */ if (H5F_addr_defined(udata.chunk_block.offset)) { - /* Add chunk to list for selection I/O */ - chunk_mem_spaces[num_chunks] = chunk_info->mspace; - chunk_file_spaces[num_chunks] = chunk_info->fspace; - chunk_addrs[num_chunks] = udata.chunk_block.offset; - num_chunks++; + /* Add chunk to list for selection I/O, if not performing multi dataset I/O */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + chunk_mem_spaces[num_chunks] = chunk_info->mspace; + chunk_file_spaces[num_chunks] = chunk_info->fspace; + chunk_addrs[num_chunks] = udata.chunk_block.offset; + num_chunks++; + } /* end if */ + else { + /* Add to mdset selection I/O arrays */ + HDassert(io_info->mem_spaces); + HDassert(io_info->file_spaces); + HDassert(io_info->addrs); + HDassert(io_info->element_sizes); + HDassert(io_info->rbufs); + HDassert(io_info->pieces_added < io_info->piece_count); + + io_info->mem_spaces[io_info->pieces_added] = chunk_info->mspace; + io_info->file_spaces[io_info->pieces_added] = chunk_info->fspace; + io_info->addrs[io_info->pieces_added] = udata.chunk_block.offset; + io_info->element_sizes[io_info->pieces_added] = element_sizes[0]; + io_info->rbufs[io_info->pieces_added] = bufs[0]; + io_info->pieces_added++; + } } /* end if */ else if (!skip_missing_chunks) { /* Perform the actual read operation from the nonexistent chunk */ - if ((io_info->io_ops.single_read)(&nonexistent_io_info, type_info, - (hsize_t)chunk_info->chunk_points, chunk_info->fspace, - chunk_info->mspace) < 0) + nonexistent_dset_info.file_space = chunk_info->fspace; + nonexistent_dset_info.mem_space = chunk_info->mspace; + nonexistent_dset_info.nelmts = chunk_info->piece_points; + if ((dset_info->io_ops.single_read)(&nonexistent_io_info, &nonexistent_dset_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed") } /* end if */ /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + chunk_node = H5D_CHUNK_GET_NEXT_NODE(dset_info, chunk_node); } /* end while */ - /* Issue selection I/O call (we can skip the page buffer because we've - * already verified it won't be used, and the metadata accumulator - * because this is raw data) */ - if (H5F_shared_select_read(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, (uint32_t)num_chunks, - chunk_mem_spaces, chunk_file_spaces, chunk_addrs, element_sizes, bufs) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunk selection read failed") - - /* Clean up memory */ - if (chunk_mem_spaces != chunk_mem_spaces_static) { - HDassert(chunk_mem_spaces); - HDassert(chunk_file_spaces != chunk_file_spaces_static); - HDassert(chunk_addrs != chunk_addrs_static); - H5MM_free(chunk_mem_spaces); - chunk_mem_spaces = NULL; - H5MM_free(chunk_file_spaces); - chunk_file_spaces = NULL; - H5MM_free(chunk_addrs); - chunk_addrs = NULL; - } /* end if */ - } /* end if */ + /* Only perform I/O if not performing multi dataset I/O, otherwise the + * higher level will handle it after all datasets have been processed */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + /* Issue selection I/O call (we can skip the page buffer because we've + * already verified it won't be used, and the metadata accumulator + * because this is raw data) */ + H5_CHECK_OVERFLOW(num_chunks, size_t, uint32_t) + if (H5F_shared_select_read(H5F_SHARED(dset_info->dset->oloc.file), H5FD_MEM_DRAW, + (uint32_t)num_chunks, chunk_mem_spaces, chunk_file_spaces, chunk_addrs, + element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunk selection read failed") + + /* Clean up memory */ + if (chunk_mem_spaces != chunk_mem_spaces_local) { + HDassert(chunk_file_spaces != chunk_file_spaces_local); + HDassert(chunk_addrs != chunk_addrs_local); + chunk_mem_spaces = H5MM_xfree(chunk_mem_spaces); + chunk_file_spaces = H5MM_xfree(chunk_file_spaces); + chunk_addrs = H5MM_xfree(chunk_addrs); + } /* end if */ + } /* end if */ + } /* end if */ else { H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ @@ -2697,33 +2799,39 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ /* Set up contiguous I/O info object */ H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); - ctg_io_info.store = &ctg_store; - ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + HDmemcpy(&ctg_dset_info, dset_info, sizeof(ctg_dset_info)); + ctg_dset_info.store = &ctg_store; + ctg_dset_info.layout_ops = *H5D_LOPS_CONTIG; + ctg_io_info.dsets_info = &ctg_dset_info; + ctg_io_info.count = 1; /* Initialize temporary contiguous storage info */ - H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size, + H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, dset_info->dset->shared->layout.u.chunk.size, uint32_t); /* Set up compact I/O info object */ H5MM_memcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); - cpt_io_info.store = &cpt_store; - cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + HDmemcpy(&cpt_dset_info, dset_info, sizeof(cpt_dset_info)); + cpt_dset_info.store = &cpt_store; + cpt_dset_info.layout_ops = *H5D_LOPS_COMPACT; + cpt_io_info.dsets_info = &cpt_dset_info; + cpt_io_info.count = 1; /* 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); + chunk_node = H5D_CHUNK_GET_FIRST_NODE(dset_info); while (chunk_node) { - H5D_chunk_info_t *chunk_info; /* Chunk information */ + H5D_piece_info_t *chunk_info; /* Chunk information */ H5D_chunk_ud_t udata; /* Chunk index pass-through */ htri_t cacheable; /* Whether the chunk is cacheable */ /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + chunk_info = H5D_CHUNK_GET_NODE_INFO(dset_info, chunk_node); /* Get the info for the chunk in the file */ - if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0) + if (H5D__chunk_lookup(dset_info->dset, chunk_info->scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") /* Sanity check */ @@ -2737,20 +2845,23 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ void *chunk = NULL; /* Pointer to locked chunk buffer */ /* Set chunk's [scaled] coordinates */ - io_info->store->chunk.scaled = chunk_info->scaled; + dset_info->store->chunk.scaled = chunk_info->scaled; /* Determine if we should use the chunk cache */ - if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, FALSE)) < 0) + if ((cacheable = H5D__chunk_cacheable(io_info, dset_info, udata.chunk_block.offset, FALSE)) < + 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable") if (cacheable) { /* Load the chunk into cache and lock it. */ /* Compute # of bytes accessed in chunk */ - H5_CHECK_OVERFLOW(type_info->src_type_size, /*From:*/ size_t, /*To:*/ uint32_t); - src_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->src_type_size; + H5_CHECK_OVERFLOW(dset_info->type_info.src_type_size, /*From:*/ size_t, /*To:*/ uint32_t); + H5_CHECK_OVERFLOW(chunk_info->piece_points, /*From:*/ size_t, /*To:*/ uint32_t); + src_accessed_bytes = + (uint32_t)chunk_info->piece_points * (uint32_t)dset_info->type_info.src_type_size; /* Lock the chunk into the cache */ - if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE))) + if (NULL == (chunk = H5D__chunk_lock(io_info, dset_info, &udata, FALSE, FALSE))) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") /* Set up the storage buffer information for this chunk */ @@ -2772,35 +2883,39 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ } /* 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) + HDassert(chk_io_info->count == 1); + chk_io_info->dsets_info[0].file_space = chunk_info->fspace; + chk_io_info->dsets_info[0].mem_space = chunk_info->mspace; + chk_io_info->dsets_info[0].nelmts = chunk_info->piece_points; + if ((dset_info->io_ops.single_read)(chk_io_info, &chk_io_info->dsets_info[0]) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed") /* Release the cache lock on the chunk. */ - if (chunk && H5D__chunk_unlock(io_info, &udata, FALSE, chunk, src_accessed_bytes) < 0) + if (chunk && + H5D__chunk_unlock(io_info, dset_info, &udata, FALSE, chunk, src_accessed_bytes) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") } /* end if */ /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + chunk_node = H5D_CHUNK_GET_NEXT_NODE(dset_info, chunk_node); } /* end while */ } /* end else */ done: /* Cleanup on failure */ if (ret_value < 0) { - if (chunk_mem_spaces != chunk_mem_spaces_static) + if (chunk_mem_spaces != chunk_mem_spaces_local) chunk_mem_spaces = H5MM_xfree(chunk_mem_spaces); - if (chunk_file_spaces != chunk_file_spaces_static) + if (chunk_file_spaces != chunk_file_spaces_local) chunk_file_spaces = H5MM_xfree(chunk_file_spaces); - if (chunk_addrs != chunk_addrs_static) + if (chunk_addrs != chunk_addrs_local) chunk_addrs = H5MM_xfree(chunk_addrs); } /* end if */ /* Make sure we cleaned up */ - HDassert(!chunk_mem_spaces || chunk_mem_spaces == chunk_mem_spaces_static); - HDassert(!chunk_file_spaces || chunk_file_spaces == chunk_file_spaces_static); - HDassert(!chunk_addrs || chunk_addrs == chunk_addrs_static); + HDassert(!chunk_mem_spaces || chunk_mem_spaces == chunk_mem_spaces_local); + HDassert(!chunk_file_spaces || chunk_file_spaces == chunk_file_spaces_local); + HDassert(!chunk_addrs || chunk_addrs == chunk_addrs_local); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__chunk_read() */ @@ -2818,45 +2933,51 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t H5_ATTR_UNUSED nelmts, - H5S_t H5_ATTR_UNUSED *file_space, H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t *fm) +H5D__chunk_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_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 */ - uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */ - H5S_t **chunk_mem_spaces = NULL; /* Array of chunk memory spaces */ - H5S_t *chunk_mem_spaces_static[8]; /* Static buffer for chunk_mem_spaces */ - H5S_t **chunk_file_spaces = NULL; /* Array of chunk file spaces */ - H5S_t *chunk_file_spaces_static[8]; /* Static buffer for chunk_file_spaces */ - haddr_t *chunk_addrs = NULL; /* Array of chunk addresses */ - haddr_t chunk_addrs_static[8]; /* Static buffer for chunk_addrs */ - herr_t ret_value = SUCCEED; /* Return value */ + H5SL_node_t *chunk_node; /* Current node in chunk skip list */ + H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ + H5D_dset_io_info_t ctg_dset_info; /* Contiguous I/O dset 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_dset_io_info_t cpt_dset_info; /* Compact I/O dset info object */ + H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */ + hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ + uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */ + H5S_t **chunk_mem_spaces = NULL; /* Array of chunk memory spaces */ + H5S_t *chunk_mem_spaces_local[8]; /* Local buffer for chunk_mem_spaces */ + H5S_t **chunk_file_spaces = NULL; /* Array of chunk file spaces */ + H5S_t *chunk_file_spaces_local[8]; /* Local buffer for chunk_file_spaces */ + haddr_t *chunk_addrs = NULL; /* Array of chunk addresses */ + haddr_t chunk_addrs_local[8]; /* Local buffer for chunk_addrs */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.wbuf); - HDassert(type_info); - HDassert(fm); + HDassert(dset_info); + HDassert(dset_info->buf.cvp); /* Set up contiguous I/O info object */ H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); - ctg_io_info.store = &ctg_store; - ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + HDmemcpy(&ctg_dset_info, dset_info, sizeof(ctg_dset_info)); + ctg_dset_info.store = &ctg_store; + ctg_dset_info.layout_ops = *H5D_LOPS_CONTIG; + ctg_io_info.dsets_info = &ctg_dset_info; + ctg_io_info.count = 1; /* Initialize temporary contiguous storage info */ - H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size, + H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, dset_info->dset->shared->layout.u.chunk.size, uint32_t); /* Set up compact I/O info object */ H5MM_memcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); - cpt_io_info.store = &cpt_store; - cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + HDmemcpy(&cpt_dset_info, dset_info, sizeof(cpt_dset_info)); + cpt_dset_info.store = &cpt_store; + cpt_dset_info.layout_ops = *H5D_LOPS_COMPACT; + cpt_io_info.dsets_info = &cpt_dset_info; + cpt_io_info.count = 1; /* Initialize temporary compact storage info */ cpt_store.compact.dirty = &cpt_dirty; @@ -2864,51 +2985,56 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize /* Different blocks depending on whether we're using selection I/O */ if (io_info->use_select_io) { size_t num_chunks; - size_t element_sizes[2] = {type_info->dst_type_size, 0}; - const void *bufs[2] = {io_info->u.wbuf, NULL}; - - /* Cache number of chunks */ - num_chunks = H5D_CHUNK_GET_NODE_COUNT(fm); - - /* Allocate arrays of dataspaces and offsets for use with selection I/O, - * or point to static buffers */ - HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) == - sizeof(chunk_file_spaces_static) / sizeof(chunk_file_spaces_static[0])); - HDassert(sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]) == - sizeof(chunk_addrs_static) / sizeof(chunk_addrs_static[0])); - if (num_chunks > (sizeof(chunk_mem_spaces_static) / sizeof(chunk_mem_spaces_static[0]))) { - if (NULL == (chunk_mem_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for memory space list") - if (NULL == (chunk_file_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list") - if (NULL == (chunk_addrs = H5MM_malloc(num_chunks * sizeof(haddr_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for chunk address list") - } /* end if */ - else { - chunk_mem_spaces = chunk_mem_spaces_static; - chunk_file_spaces = chunk_file_spaces_static; - chunk_addrs = chunk_addrs_static; - } /* end else */ + size_t element_sizes[2] = {dset_info->type_info.dst_type_size, 0}; + const void *bufs[2] = {dset_info->buf.cvp, NULL}; + + /* Only create selection I/O arrays if not performing multi dataset I/O, + * otherwise the higher level will handle it */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + /* Cache number of chunks */ + num_chunks = H5D_CHUNK_GET_NODE_COUNT(dset_info); + + /* Allocate arrays of dataspaces and offsets for use with selection I/O, + * or point to local buffers */ + HDassert(sizeof(chunk_mem_spaces_local) / sizeof(chunk_mem_spaces_local[0]) == + sizeof(chunk_file_spaces_local) / sizeof(chunk_file_spaces_local[0])); + HDassert(sizeof(chunk_mem_spaces_local) / sizeof(chunk_mem_spaces_local[0]) == + sizeof(chunk_addrs_local) / sizeof(chunk_addrs_local[0])); + if (num_chunks > (sizeof(chunk_mem_spaces_local) / sizeof(chunk_mem_spaces_local[0]))) { + if (NULL == (chunk_mem_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for memory space list") + if (NULL == (chunk_file_spaces = H5MM_malloc(num_chunks * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for file space list") + if (NULL == (chunk_addrs = H5MM_malloc(num_chunks * sizeof(haddr_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for chunk address list") + } /* end if */ + else { + chunk_mem_spaces = chunk_mem_spaces_local; + chunk_file_spaces = chunk_file_spaces_local; + chunk_addrs = chunk_addrs_local; + } /* end else */ - /* Reset num_chunks */ - num_chunks = 0; + /* Reset num_chunks */ + num_chunks = 0; + } /* end if */ /* Iterate through nodes in chunk skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); + chunk_node = H5D_CHUNK_GET_FIRST_NODE(dset_info); while (chunk_node) { - H5D_chunk_info_t *chunk_info; /* Chunk information */ + H5D_piece_info_t *chunk_info; /* Chunk information */ H5D_chk_idx_info_t idx_info; /* Chunked index info */ H5D_chunk_ud_t udata; /* Index pass-through */ htri_t cacheable; /* Whether the chunk is cacheable */ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */ /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + chunk_info = H5D_CHUNK_GET_NODE_INFO(dset_info, chunk_node); /* Get the info for the chunk in the file */ - if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0) + if (H5D__chunk_lookup(dset_info->dset, chunk_info->scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") /* There should be no chunks cached */ @@ -2919,10 +3045,10 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0)); /* Set chunk's [scaled] coordinates */ - io_info->store->chunk.scaled = chunk_info->scaled; + dset_info->store->chunk.scaled = chunk_info->scaled; /* Determine if we should use the chunk cache */ - if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0) + if ((cacheable = H5D__chunk_cacheable(io_info, dset_info, udata.chunk_block.offset, TRUE)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable") if (cacheable) { /* Load the chunk into cache. But if the whole chunk is written, @@ -2931,42 +3057,47 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */ /* Compute # of bytes accessed in chunk */ - H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t); - dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size; + H5_CHECK_OVERFLOW(dset_info->type_info.dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t); + H5_CHECK_OVERFLOW(chunk_info->piece_points, /*From:*/ size_t, /*To:*/ uint32_t); + dst_accessed_bytes = + (uint32_t)chunk_info->piece_points * (uint32_t)dset_info->type_info.dst_type_size; /* Determine if we will access all the data in the chunk */ if (dst_accessed_bytes != ctg_store.contig.dset_size || - (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size || - fm->fsel_type == H5S_SEL_POINTS) + (chunk_info->piece_points * dset_info->type_info.src_type_size) != + ctg_store.contig.dset_size || + dset_info->layout_io_info.chunk_map->fsel_type == H5S_SEL_POINTS) entire_chunk = FALSE; /* Lock the chunk into the cache */ - if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE))) + if (NULL == (chunk = H5D__chunk_lock(io_info, dset_info, &udata, entire_chunk, FALSE))) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") /* Set up the storage buffer information for this chunk */ cpt_store.compact.buf = chunk; /* Perform the actual write operation */ - if ((io_info->io_ops.single_write)(&cpt_io_info, type_info, (hsize_t)chunk_info->chunk_points, - chunk_info->fspace, chunk_info->mspace) < 0) + cpt_dset_info.file_space = chunk_info->fspace; + cpt_dset_info.mem_space = chunk_info->mspace; + cpt_dset_info.nelmts = chunk_info->piece_points; + if ((dset_info->io_ops.single_write)(&cpt_io_info, &cpt_dset_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed") /* Release the cache lock on the chunk */ - if (H5D__chunk_unlock(io_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0) + if (H5D__chunk_unlock(io_info, dset_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") } /* end if */ else { /* If the chunk hasn't been allocated on disk, do so now. */ if (!H5F_addr_defined(udata.chunk_block.offset)) { /* Compose chunked index info struct */ - idx_info.f = io_info->dset->oloc.file; - idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline); - idx_info.layout = &(io_info->dset->shared->layout.u.chunk); - idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk); + idx_info.f = dset_info->dset->oloc.file; + idx_info.pline = &(dset_info->dset->shared->dcpl_cache.pline); + idx_info.layout = &(dset_info->dset->shared->layout.u.chunk); + idx_info.storage = &(dset_info->dset->shared->layout.storage.u.chunk); /* Set up the size of chunk for user data */ - udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size; + udata.chunk_block.length = dset_info->dset->shared->layout.u.chunk.size; /* Allocate the chunk */ if (H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert, @@ -2979,53 +3110,72 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined") /* Cache the new chunk information */ - H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata); + H5D__chunk_cinfo_cache_update(&dset_info->dset->shared->cache.chunk.last, &udata); /* Insert chunk into index */ - if (need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert) - if ((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, - NULL) < 0) + if (need_insert && dset_info->dset->shared->layout.storage.u.chunk.ops->insert) + if ((dset_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, + NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index") } /* end if */ - /* Add chunk to list for selection I/O */ - chunk_mem_spaces[num_chunks] = chunk_info->mspace; - chunk_file_spaces[num_chunks] = chunk_info->fspace; - chunk_addrs[num_chunks] = udata.chunk_block.offset; - num_chunks++; + /* Add chunk to list for selection I/O, if not performing multi dataset I/O */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + chunk_mem_spaces[num_chunks] = chunk_info->mspace; + chunk_file_spaces[num_chunks] = chunk_info->fspace; + chunk_addrs[num_chunks] = udata.chunk_block.offset; + num_chunks++; + } /* end if */ + else { + /* Add to mdset selection I/O arrays */ + HDassert(io_info->mem_spaces); + HDassert(io_info->file_spaces); + HDassert(io_info->addrs); + HDassert(io_info->element_sizes); + HDassert(io_info->wbufs); + HDassert(io_info->pieces_added < io_info->piece_count); + + io_info->mem_spaces[io_info->pieces_added] = chunk_info->mspace; + io_info->file_spaces[io_info->pieces_added] = chunk_info->fspace; + io_info->addrs[io_info->pieces_added] = udata.chunk_block.offset; + io_info->element_sizes[io_info->pieces_added] = element_sizes[0]; + io_info->wbufs[io_info->pieces_added] = bufs[0]; + io_info->pieces_added++; + } } /* end else */ /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + chunk_node = H5D_CHUNK_GET_NEXT_NODE(dset_info, chunk_node); } /* end while */ - /* Issue selection I/O call (we can skip the page buffer because we've - * already verified it won't be used, and the metadata accumulator - * because this is raw data) */ - if (H5F_shared_select_write(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, (uint32_t)num_chunks, - chunk_mem_spaces, chunk_file_spaces, chunk_addrs, element_sizes, - bufs) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunk selection read failed") - - /* Clean up memory */ - if (chunk_mem_spaces != chunk_mem_spaces_static) { - HDassert(chunk_mem_spaces); - HDassert(chunk_file_spaces != chunk_file_spaces_static); - HDassert(chunk_addrs != chunk_addrs_static); - H5MM_free(chunk_mem_spaces); - chunk_mem_spaces = NULL; - H5MM_free(chunk_file_spaces); - chunk_file_spaces = NULL; - H5MM_free(chunk_addrs); - chunk_addrs = NULL; - } /* end if */ - } /* end if */ + /* Only perform I/O if not performing multi dataset I/O, otherwise the + * higher level will handle it after all datasets have been processed */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + /* Issue selection I/O call (we can skip the page buffer because we've + * already verified it won't be used, and the metadata accumulator + * because this is raw data) */ + H5_CHECK_OVERFLOW(num_chunks, size_t, uint32_t) + if (H5F_shared_select_write(H5F_SHARED(dset_info->dset->oloc.file), H5FD_MEM_DRAW, + (uint32_t)num_chunks, chunk_mem_spaces, chunk_file_spaces, + chunk_addrs, element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "chunk selection write failed") + + /* Clean up memory */ + if (chunk_mem_spaces != chunk_mem_spaces_local) { + HDassert(chunk_file_spaces != chunk_file_spaces_local); + HDassert(chunk_addrs != chunk_addrs_local); + chunk_mem_spaces = H5MM_xfree(chunk_mem_spaces); + chunk_file_spaces = H5MM_xfree(chunk_file_spaces); + chunk_addrs = H5MM_xfree(chunk_addrs); + } /* end if */ + } /* end if */ + } /* end if */ else { /* Iterate through nodes in chunk skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); + chunk_node = H5D_CHUNK_GET_FIRST_NODE(dset_info); while (chunk_node) { - H5D_chunk_info_t *chunk_info; /* Chunk information */ + H5D_piece_info_t *chunk_info; /* Chunk information */ H5D_chk_idx_info_t idx_info; /* Chunked index info */ H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */ void *chunk; /* Pointer to locked chunk buffer */ @@ -3034,10 +3184,10 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */ /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + chunk_info = H5D_CHUNK_GET_NODE_INFO(dset_info, chunk_node); /* Look up the chunk */ - if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0) + if (H5D__chunk_lookup(dset_info->dset, chunk_info->scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") /* Sanity check */ @@ -3045,10 +3195,10 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0)); /* Set chunk's [scaled] coordinates */ - io_info->store->chunk.scaled = chunk_info->scaled; + dset_info->store->chunk.scaled = chunk_info->scaled; /* Determine if we should use the chunk cache */ - if ((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0) + if ((cacheable = H5D__chunk_cacheable(io_info, dset_info, udata.chunk_block.offset, TRUE)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable") if (cacheable) { /* Load the chunk into cache. But if the whole chunk is written, @@ -3056,17 +3206,20 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */ /* Compute # of bytes accessed in chunk */ - H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t); - dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size; + H5_CHECK_OVERFLOW(dset_info->type_info.dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t); + H5_CHECK_OVERFLOW(chunk_info->piece_points, /*From:*/ size_t, /*To:*/ uint32_t); + dst_accessed_bytes = + (uint32_t)chunk_info->piece_points * (uint32_t)dset_info->type_info.dst_type_size; /* Determine if we will access all the data in the chunk */ if (dst_accessed_bytes != ctg_store.contig.dset_size || - (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size || - fm->fsel_type == H5S_SEL_POINTS) + (chunk_info->piece_points * dset_info->type_info.src_type_size) != + ctg_store.contig.dset_size || + dset_info->layout_io_info.chunk_map->fsel_type == H5S_SEL_POINTS) entire_chunk = FALSE; /* Lock the chunk into the cache */ - if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE))) + if (NULL == (chunk = H5D__chunk_lock(io_info, dset_info, &udata, entire_chunk, FALSE))) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") /* Set up the storage buffer information for this chunk */ @@ -3079,13 +3232,13 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize /* If the chunk hasn't been allocated on disk, do so now. */ if (!H5F_addr_defined(udata.chunk_block.offset)) { /* Compose chunked index info struct */ - idx_info.f = io_info->dset->oloc.file; - idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline); - idx_info.layout = &(io_info->dset->shared->layout.u.chunk); - idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk); + idx_info.f = dset_info->dset->oloc.file; + idx_info.pline = &(dset_info->dset->shared->dcpl_cache.pline); + idx_info.layout = &(dset_info->dset->shared->layout.u.chunk); + idx_info.storage = &(dset_info->dset->shared->layout.storage.u.chunk); /* Set up the size of chunk for user data */ - udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size; + udata.chunk_block.length = dset_info->dset->shared->layout.u.chunk.size; /* Allocate the chunk */ if (H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert, @@ -3098,7 +3251,7 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined") /* Cache the new chunk information */ - H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata); + H5D__chunk_cinfo_cache_update(&dset_info->dset->shared->cache.chunk.last, &udata); } /* end if */ /* Set up the storage address information for this chunk */ @@ -3112,43 +3265,46 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize } /* 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) + HDassert(chk_io_info->count == 1); + chk_io_info->dsets_info[0].file_space = chunk_info->fspace; + chk_io_info->dsets_info[0].mem_space = chunk_info->mspace; + chk_io_info->dsets_info[0].nelmts = chunk_info->piece_points; + if ((dset_info->io_ops.single_write)(chk_io_info, &chk_io_info->dsets_info[0]) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed") /* Release the cache lock on the chunk, or insert chunk into index. */ if (chunk) { - if (H5D__chunk_unlock(io_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0) + if (H5D__chunk_unlock(io_info, dset_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") } /* end if */ else { - if (need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert) - if ((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) < - 0) + if (need_insert && dset_info->dset->shared->layout.storage.u.chunk.ops->insert) + if ((dset_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, + NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index") } /* end else */ /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + chunk_node = H5D_CHUNK_GET_NEXT_NODE(dset_info, chunk_node); } /* end while */ } /* end else */ done: /* Cleanup on failure */ if (ret_value < 0) { - if (chunk_mem_spaces != chunk_mem_spaces_static) + if (chunk_mem_spaces != chunk_mem_spaces_local) chunk_mem_spaces = H5MM_xfree(chunk_mem_spaces); - if (chunk_file_spaces != chunk_file_spaces_static) + if (chunk_file_spaces != chunk_file_spaces_local) chunk_file_spaces = H5MM_xfree(chunk_file_spaces); - if (chunk_addrs != chunk_addrs_static) + if (chunk_addrs != chunk_addrs_local) chunk_addrs = H5MM_xfree(chunk_addrs); } /* end if */ /* Make sure we cleaned up */ - HDassert(!chunk_mem_spaces || chunk_mem_spaces == chunk_mem_spaces_static); - HDassert(!chunk_file_spaces || chunk_file_spaces == chunk_file_spaces_static); - HDassert(!chunk_addrs || chunk_addrs == chunk_addrs_static); + HDassert(!chunk_mem_spaces || chunk_mem_spaces == chunk_mem_spaces_local); + HDassert(!chunk_file_spaces || chunk_file_spaces == chunk_file_spaces_local); + HDassert(!chunk_addrs || chunk_addrs == chunk_addrs_local); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__chunk_write() */ @@ -3199,44 +3355,56 @@ done: * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Saturday, May 17, 2003 + * Programmer: Jonathan Kim Nov, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_io_term(const H5D_chunk_map_t *fm) +H5D__chunk_io_term(H5D_io_info_t H5_ATTR_UNUSED *io_info, H5D_dset_io_info_t *di) { - herr_t ret_value = SUCCEED; /*return value */ + H5D_chunk_map_t *fm; /* Convenience pointer to chunk map */ + herr_t ret_value = SUCCEED; /*return value */ FUNC_ENTER_PACKAGE + HDassert(di); + + /* Set convenience pointer */ + fm = di->layout_io_info.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); + HDassert(fm->dset_sel_pieces == NULL); + HDassert(fm->last_piece_info == NULL); + HDassert(fm->single_piece_info); + HDassert(fm->single_piece_info->fspace_shared); + HDassert(fm->single_piece_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 */ + /* Release the nodes on the list of selected pieces, or the last (only) + * piece if the skiplist is not available */ + if (fm->dset_sel_pieces) { + if (H5SL_free(fm->dset_sel_pieces, H5D__free_piece_info, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTNEXT, FAIL, "can't free dataset skip list") + } /* end if */ + else if (fm->last_piece_info) { + if (H5D__free_piece_info(fm->last_piece_info, NULL, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free piece info") + fm->last_piece_info = NULL; + } /* end if */ + } /* end else */ - /* Free the memory chunk dataspace template */ + /* Free the memory piece 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 */ + + /* Free chunk map */ + di->layout_io_info.chunk_map = H5FL_FREE(H5D_chunk_map_t, di->layout_io_info.chunk_map); done: FUNC_LEAVE_NOAPI(ret_value) @@ -4099,20 +4267,19 @@ done: *------------------------------------------------------------------------- */ static void * -H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax, hbool_t prev_unfilt_chunk) +H5D__chunk_lock(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, H5D_chunk_ud_t *udata, + hbool_t relax, hbool_t prev_unfilt_chunk) { - const H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */ - H5O_pline_t *pline = - &(dset->shared->dcpl_cache - .pline); /* I/O pipeline info - always equal to the pline passed to H5D__chunk_mem_alloc */ - H5O_pline_t *old_pline = pline; /* Old pipeline, i.e. pipeline used to read the chunk */ - const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */ - const H5O_fill_t *fill = &(dset->shared->dcpl_cache.fill); /* Fill value info */ - H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */ - hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */ - H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache*/ - H5D_rdcc_ent_t *ent; /*cache entry */ - size_t chunk_size; /*size of a chunk */ + const H5D_t *dset; /* Convenience pointer to the dataset */ + H5O_pline_t *pline; /* I/O pipeline info - always equal to the pline passed to H5D__chunk_mem_alloc */ + H5O_pline_t *old_pline; /* Old pipeline, i.e. pipeline used to read the chunk */ + const H5O_layout_t *layout; /* Dataset layout */ + const H5O_fill_t *fill; /* Fill value info */ + H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */ + hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */ + H5D_rdcc_t *rdcc; /*raw data chunk cache*/ + H5D_rdcc_ent_t *ent; /*cache entry */ + size_t chunk_size; /*size of a chunk */ hbool_t disable_filters = FALSE; /* Whether to disable filters (when adding to cache) */ void *chunk = NULL; /*the file chunk */ void *ret_value = NULL; /* Return value */ @@ -4121,10 +4288,20 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel /* Sanity checks */ HDassert(io_info); - HDassert(io_info->store); - HDassert(udata); + HDassert(dset_info); + HDassert(dset_info->store); + dset = dset_info->dset; HDassert(dset); + HDassert(udata); HDassert(!(udata->new_unfilt_chunk && prev_unfilt_chunk)); + + /* Set convenience pointers */ + pline = &(dset->shared->dcpl_cache.pline); + old_pline = pline; + layout = &(dset->shared->layout); + fill = &(dset->shared->dcpl_cache.fill); + rdcc = &(dset->shared->cache.chunk); + HDassert(!rdcc->tmp_head); /* Get the chunk's size */ @@ -4146,7 +4323,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel /* Make sure this is the right chunk */ for (u = 0; u < layout->u.chunk.ndims - 1; u++) - HDassert(io_info->store->chunk.scaled[u] == ent->scaled[u]); + HDassert(dset_info->store->chunk.scaled[u] == ent->scaled[u]); } #endif /* NDEBUG */ @@ -4261,9 +4438,9 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel } /* end if */ else if (layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) { /* Check if this is an edge chunk */ - if (H5D__chunk_is_partial_edge_chunk(io_info->dset->shared->ndims, layout->u.chunk.dim, - io_info->store->chunk.scaled, - io_info->dset->shared->curr_dims)) { + if (H5D__chunk_is_partial_edge_chunk(dset->shared->ndims, layout->u.chunk.dim, + dset_info->store->chunk.scaled, + dset->shared->curr_dims)) { /* Disable the filters for both writing and reading */ disable_filters = TRUE; old_pline = NULL; @@ -4388,17 +4565,17 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel /* See if the chunk can be cached */ if (rdcc->nslots > 0 && chunk_size <= rdcc->nbytes_max) { /* Calculate the index */ - udata->idx_hint = H5D__chunk_hash_val(io_info->dset->shared, udata->common.scaled); + udata->idx_hint = H5D__chunk_hash_val(dset->shared, udata->common.scaled); /* Add the chunk to the cache only if the slot is not already locked */ ent = rdcc->slot[udata->idx_hint]; if (!ent || !ent->locked) { /* Preempt enough things from the cache to make room */ if (ent) { - if (H5D__chunk_cache_evict(io_info->dset, ent, TRUE) < 0) + if (H5D__chunk_cache_evict(dset, ent, TRUE) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk from cache") } /* end if */ - if (H5D__chunk_cache_prune(io_info->dset, chunk_size) < 0) + if (H5D__chunk_cache_prune(dset, chunk_size) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk(s) from cache") /* Create a new entry */ @@ -4498,19 +4675,26 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, - uint32_t naccessed) +H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, uint32_t naccessed) { - const H5O_layout_t *layout = &(io_info->dset->shared->layout); /* Dataset layout */ - const H5D_rdcc_t *rdcc = &(io_info->dset->shared->cache.chunk); + const H5O_layout_t *layout; /* Dataset layout */ + const H5D_rdcc_t *rdcc; + const H5D_t *dset; /* Local pointer to the dataset info */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(io_info); + HDassert(dset_info); HDassert(udata); + /* Set convenience pointers */ + layout = &(dset_info->dset->shared->layout); + rdcc = &(dset_info->dset->shared->cache.chunk); + dset = dset_info->dset; + if (UINT_MAX == udata->idx_hint) { /* * It's not in the cache, probably because it's too big. If it's @@ -4526,9 +4710,9 @@ H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbo } /* end if */ else if (layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) { /* Check if the chunk is an edge chunk, and disable filters if so */ - is_unfiltered_edge_chunk = H5D__chunk_is_partial_edge_chunk( - io_info->dset->shared->ndims, layout->u.chunk.dim, io_info->store->chunk.scaled, - io_info->dset->shared->curr_dims); + is_unfiltered_edge_chunk = + H5D__chunk_is_partial_edge_chunk(dset->shared->ndims, layout->u.chunk.dim, + dset_info->store->chunk.scaled, dset->shared->curr_dims); } /* end if */ if (dirty) { @@ -4547,13 +4731,13 @@ H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbo fake_ent.chunk_block.length = udata->chunk_block.length; fake_ent.chunk = (uint8_t *)chunk; - if (H5D__chunk_flush_entry(io_info->dset, &fake_ent, TRUE) < 0) + if (H5D__chunk_flush_entry(dset, &fake_ent, TRUE) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer") } /* end if */ else { if (chunk) chunk = H5D__chunk_mem_xfree( - chunk, (is_unfiltered_edge_chunk ? NULL : &(io_info->dset->shared->dcpl_cache.pline))); + chunk, (is_unfiltered_edge_chunk ? NULL : &(dset->shared->dcpl_cache.pline))); } /* end else */ } /* end if */ else { @@ -4676,9 +4860,8 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__chunk_allocate(const H5D_io_info_t *io_info, hbool_t full_overwrite, const hsize_t old_dim[]) +H5D__chunk_allocate(const H5D_t *dset, hbool_t full_overwrite, const hsize_t old_dim[]) { - const H5D_t *dset = io_info->dset; /* the dataset pointer */ H5D_chk_idx_info_t idx_info; /* Chunked index info */ const H5D_chunk_ops_t *ops = dset->shared->layout.storage.u.chunk.ops; /* Chunk operations */ hsize_t min_unalloc[H5O_LAYOUT_NDIMS]; /* First chunk in each dimension that is unallocated (in scaled @@ -5170,6 +5353,7 @@ H5D__chunk_update_old_edge_chunks(H5D_t *dset, hsize_t old_dim[]) H5D_io_info_t chk_io_info; /* Chunked I/O info object */ H5D_chunk_ud_t chk_udata; /* User data for locking chunk */ H5D_storage_t chk_store; /* Chunk storage information */ + H5D_dset_io_info_t chk_dset_info; /* Chunked I/O dset info object */ void *chunk; /* The file chunk */ hbool_t carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */ herr_t ret_value = SUCCEED; /* Return value */ @@ -5203,7 +5387,13 @@ H5D__chunk_update_old_edge_chunks(H5D_t *dset, hsize_t old_dim[]) * Note that we only need to set chunk_offset once, as the array's address * will never change. */ chk_store.chunk.scaled = chunk_sc; - H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, &chk_store, NULL); + + chk_io_info.op_type = H5D_IO_OP_READ; + + chk_dset_info.dset = dset; + chk_dset_info.store = &chk_store; + chk_dset_info.buf.vp = NULL; + chk_io_info.dsets_info = &chk_dset_info; /* * Determine the edges of the dataset which need to be modified @@ -5268,11 +5458,12 @@ H5D__chunk_update_old_edge_chunks(H5D_t *dset, hsize_t old_dim[]) if (H5F_addr_defined(chk_udata.chunk_block.offset) || (UINT_MAX != chk_udata.idx_hint)) { /* Lock the chunk into cache. H5D__chunk_lock will take care of * updating the chunk to no longer be an edge chunk. */ - if (NULL == (chunk = (void *)H5D__chunk_lock(&chk_io_info, &chk_udata, FALSE, TRUE))) + if (NULL == + (chunk = (void *)H5D__chunk_lock(&chk_io_info, &chk_dset_info, &chk_udata, FALSE, TRUE))) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk") /* Unlock the chunk */ - if (H5D__chunk_unlock(&chk_io_info, &chk_udata, TRUE, chunk, (uint32_t)0) < 0) + if (H5D__chunk_unlock(&chk_io_info, &chk_dset_info, &chk_udata, TRUE, chunk, (uint32_t)0) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to unlock raw data chunk") } /* end if */ @@ -5603,7 +5794,7 @@ static herr_t H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) { const H5D_io_info_t *io_info = udata->io_info; /* Local pointer to I/O info */ - const H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */ + const H5D_t *dset = udata->dset_info->dset; /* Local pointer to the dataset info */ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset's layout */ unsigned rank = udata->common.layout->ndims - 1; /* Dataset rank */ const hsize_t *scaled = udata->common.scaled; /* Scaled chunk offset */ @@ -5658,7 +5849,7 @@ H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to select hyperslab") /* Lock the chunk into the cache, to get a pointer to the chunk buffer */ - if (NULL == (chunk = (void *)H5D__chunk_lock(io_info, &chk_udata, FALSE, FALSE))) + if (NULL == (chunk = (void *)H5D__chunk_lock(io_info, udata->dset_info, &chk_udata, FALSE, FALSE))) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk") /* Fill the selection in the memory buffer */ @@ -5695,7 +5886,7 @@ H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) bytes_accessed = (uint32_t)sel_nelmts * layout->u.chunk.dim[rank]; /* Release lock on chunk */ - if (H5D__chunk_unlock(io_info, &chk_udata, TRUE, chunk, bytes_accessed) < 0) + if (H5D__chunk_unlock(io_info, udata->dset_info, &chk_udata, TRUE, chunk, bytes_accessed) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to unlock raw data chunk") done: @@ -5822,6 +6013,7 @@ H5D__chunk_prune_by_extent(H5D_t *dset, const hsize_t *old_dim) unfiltered */ H5D_chk_idx_info_t idx_info; /* Chunked index info */ H5D_io_info_t chk_io_info; /* Chunked I/O info object */ + H5D_dset_io_info_t chk_dset_info; /* Chunked I/O dset info object */ H5D_storage_t chk_store; /* Chunk storage information */ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset's layout */ const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache */ @@ -5889,7 +6081,14 @@ H5D__chunk_prune_by_extent(H5D_t *dset, const hsize_t *old_dim) * Note that we only need to set scaled once, as the array's address * will never change. */ chk_store.chunk.scaled = scaled; - H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, &chk_store, NULL); + + chk_io_info.op_type = H5D_IO_OP_READ; + + chk_dset_info.dset = dset; + chk_dset_info.store = &chk_store; + chk_dset_info.buf.vp = NULL; + chk_io_info.dsets_info = &chk_dset_info; + chk_io_info.count = 1; /* Compose chunked index info struct */ idx_info.f = dset->oloc.file; @@ -5903,6 +6102,7 @@ H5D__chunk_prune_by_extent(H5D_t *dset, const hsize_t *old_dim) udata.common.storage = sc; udata.common.scaled = scaled; udata.io_info = &chk_io_info; + udata.dset_info = &chk_dset_info; udata.idx_info = &idx_info; udata.space_dim = space_dim; udata.shrunk_dim = shrunk_dim; @@ -6183,18 +6383,18 @@ H5D__chunk_addrmap_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata) *------------------------------------------------------------------------- */ herr_t -H5D__chunk_addrmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[]) +H5D__chunk_addrmap(const H5D_t *dset, haddr_t chunk_addr[]) { - H5D_chk_idx_info_t idx_info; /* Chunked index info */ - const H5D_t *dset = io_info->dset; /* Local pointer to dataset info */ - H5D_chunk_it_ud2_t udata; /* User data for iteration callback */ - H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk); + H5D_chk_idx_info_t idx_info; /* Chunked index info */ + H5D_chunk_it_ud2_t udata; /* User data for iteration callback */ + H5O_storage_chunk_t *sc; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE HDassert(dset); HDassert(dset->shared); + sc = &(dset->shared->layout.storage.u.chunk); H5D_CHUNK_STORAGE_INDEX_CHK(sc); HDassert(chunk_addr); @@ -7254,9 +7454,10 @@ done: *------------------------------------------------------------------------- */ static ssize_t -H5D__nonexistent_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_off_arr[], size_t mem_max_nseq, - size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) +H5D__nonexistent_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], + hsize_t chunk_off_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, + size_t mem_len_arr[], hsize_t mem_off_arr[]) { H5D_chunk_readvv_ud_t udata; /* User data for H5VM_opvv() operator */ ssize_t ret_value = -1; /* Return value */ @@ -7273,8 +7474,8 @@ H5D__nonexistent_readvv(const H5D_io_info_t *io_info, size_t chunk_max_nseq, siz HDassert(mem_off_arr); /* Set up user data for H5VM_opvv() */ - udata.rbuf = (unsigned char *)io_info->u.rbuf; - udata.dset = io_info->dset; + udata.rbuf = (unsigned char *)dset_info->buf.vp; + udata.dset = dset_info->dset; /* Call generic sequence operation routine */ if ((ret_value = H5VM_opvv(chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_off_arr, mem_max_nseq, diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c index 8ac1f0a..a9e937f 100644 --- a/src/H5Dcompact.c +++ b/src/H5Dcompact.c @@ -63,15 +63,16 @@ typedef struct H5D_compact_iovv_memmanage_ud_t { /* Layout operation callbacks */ static herr_t H5D__compact_construct(H5F_t *f, H5D_t *dset); static hbool_t H5D__compact_is_space_alloc(const H5O_storage_t *storage); -static herr_t H5D__compact_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm); +static herr_t H5D__compact_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); static herr_t H5D__compact_iovv_memmanage_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata); -static ssize_t H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, - size_t dset_size_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, - 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[]); +static ssize_t H5D__compact_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_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, const H5D_dset_io_info_t *dset_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 herr_t H5D__compact_flush(H5D_t *dset); static herr_t H5D__compact_dest(H5D_t *dset); @@ -86,17 +87,14 @@ const H5D_layout_ops_t H5D_LOPS_COMPACT[1] = {{ H5D__compact_is_space_alloc, /* is_space_alloc */ NULL, /* is_data_cached */ H5D__compact_io_init, /* io_init */ + NULL, /* mdio_init */ H5D__contig_read, /* ser_read */ H5D__contig_write, /* ser_write */ -#ifdef H5_HAVE_PARALLEL - NULL, /* par_read */ - NULL, /* par_write */ -#endif - H5D__compact_readvv, /* readvv */ - H5D__compact_writevv, /* writevv */ - H5D__compact_flush, /* flush */ - NULL, /* io_term */ - H5D__compact_dest /* dest */ + H5D__compact_readvv, /* readvv */ + H5D__compact_writevv, /* writevv */ + H5D__compact_flush, /* flush */ + NULL, /* io_term */ + H5D__compact_dest /* dest */ }}; /*******************/ @@ -247,14 +245,15 @@ H5D__compact_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage) *------------------------------------------------------------------------- */ static herr_t -H5D__compact_io_init(H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space, - H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *cm) +H5D__compact_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) { FUNC_ENTER_PACKAGE_NOERR - io_info->store->compact.buf = io_info->dset->shared->layout.storage.u.compact.buf; - io_info->store->compact.dirty = &io_info->dset->shared->layout.storage.u.compact.dirty; + dinfo->store->compact.buf = dinfo->dset->shared->layout.storage.u.compact.buf; + dinfo->store->compact.dirty = &dinfo->dset->shared->layout.storage.u.compact.dirty; + + /* Disable selection I/O */ + io_info->use_select_io = FALSE; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__compact_io_init() */ @@ -320,15 +319,17 @@ done: *------------------------------------------------------------------------- */ 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[]) +H5D__compact_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_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[]) { ssize_t ret_value = -1; /* Return value */ FUNC_ENTER_PACKAGE HDassert(io_info); + HDassert(dset_info); /* Check if file driver wishes to do its own memory management */ if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_MEMMANAGE)) { @@ -336,8 +337,8 @@ H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t * /* Set up udata for memory copy operation */ udata.f_sh = io_info->f_sh; - udata.dstbuf = io_info->u.rbuf; - udata.srcbuf = io_info->store->compact.buf; + udata.dstbuf = dset_info->buf.vp; + udata.srcbuf = dset_info->store->compact.buf; /* Request that file driver does the memory copy */ if ((ret_value = H5VM_opvv(mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr, dset_max_nseq, @@ -347,8 +348,8 @@ H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t * } else { /* Use the vectorized memory copy routine to do actual work */ - if ((ret_value = H5VM_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, + if ((ret_value = H5VM_memcpyvv(dset_info->buf.vp, mem_max_nseq, mem_curr_seq, mem_size_arr, + mem_offset_arr, dset_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") } @@ -379,15 +380,17 @@ done: *------------------------------------------------------------------------- */ 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[]) +H5D__compact_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_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[]) { ssize_t ret_value = -1; /* Return value */ FUNC_ENTER_PACKAGE HDassert(io_info); + HDassert(dset_info); /* Check if file driver wishes to do its own memory management */ if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_MEMMANAGE)) { @@ -395,8 +398,8 @@ H5D__compact_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t /* Set up udata for memory copy operation */ udata.f_sh = io_info->f_sh; - udata.dstbuf = io_info->store->compact.buf; - udata.srcbuf = io_info->u.wbuf; + udata.dstbuf = dset_info->store->compact.buf; + udata.srcbuf = dset_info->buf.cvp; /* Request that file driver does the memory copy */ if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr, mem_max_nseq, @@ -406,14 +409,14 @@ H5D__compact_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t } else { /* Use the vectorized memory copy routine to do actual work */ - if ((ret_value = H5VM_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, + if ((ret_value = H5VM_memcpyvv(dset_info->store->compact.buf, dset_max_nseq, dset_curr_seq, + dset_size_arr, dset_offset_arr, dset_info->buf.cvp, 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->store->compact.dirty = TRUE; + *dset_info->store->compact.dirty = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c index 6408aaf..ce1bef4 100644 --- a/src/H5Dcontig.c +++ b/src/H5Dcontig.c @@ -91,19 +91,24 @@ typedef struct H5D_contig_writevv_ud_t { /* Layout operation callbacks */ static herr_t H5D__contig_construct(H5F_t *f, H5D_t *dset); static herr_t H5D__contig_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id); -static herr_t H5D__contig_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm); -static ssize_t H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, - size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, - size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); -static 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[]); +static herr_t H5D__contig_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static herr_t H5D__contig_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static ssize_t H5D__contig_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dinfo, + 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__contig_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dinfo, + 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 herr_t H5D__contig_flush(H5D_t *dset); +static herr_t H5D__contig_io_term(H5D_io_info_t *io_info, H5D_dset_io_info_t *di); /* Helper routines */ -static herr_t H5D__contig_write_one(H5D_io_info_t *io_info, hsize_t offset, size_t size); -static htri_t H5D__contig_may_use_select_io(const H5D_io_info_t *io_info, H5D_io_op_type_t op_type); +static herr_t H5D__contig_write_one(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hsize_t offset, + size_t size); +static htri_t H5D__contig_may_use_select_io(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + H5D_io_op_type_t op_type); /*********************/ /* Package Variables */ @@ -116,17 +121,14 @@ const H5D_layout_ops_t H5D_LOPS_CONTIG[1] = {{ H5D__contig_is_space_alloc, /* is_space_alloc */ H5D__contig_is_data_cached, /* is_data_cached */ H5D__contig_io_init, /* io_init */ + H5D__contig_mdio_init, /* mdio_init */ H5D__contig_read, /* ser_read */ H5D__contig_write, /* ser_write */ -#ifdef H5_HAVE_PARALLEL - H5D__contig_collective_read, /* par_read */ - H5D__contig_collective_write, /* par_write */ -#endif - H5D__contig_readvv, /* readvv */ - H5D__contig_writevv, /* writevv */ - H5D__contig_flush, /* flush */ - NULL, /* io_term */ - NULL /* dest */ + H5D__contig_readvv, /* readvv */ + H5D__contig_writevv, /* writevv */ + H5D__contig_flush, /* flush */ + H5D__contig_io_term, /* io_term */ + NULL /* dest */ }}; /*******************/ @@ -139,6 +141,9 @@ H5FL_BLK_DEFINE(sieve_buf); /* Declare extern the free list to manage blocks of type conversion data */ H5FL_BLK_EXTERN(type_conv); +/* Declare extern the free list to manage the H5D_piece_info_t struct */ +H5FL_EXTERN(H5D_piece_info_t); + /*------------------------------------------------------------------------- * Function: H5D__contig_alloc * @@ -183,15 +188,15 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__contig_fill(const H5D_io_info_t *io_info) +H5D__contig_fill(H5D_t *dset) { - const H5D_t *dset = io_info->dset; /* the dataset pointer */ - H5D_io_info_t ioinfo; /* Dataset I/O info */ - H5D_storage_t store; /* Union of storage info for dataset */ - hssize_t snpoints; /* Number of points in space (for error checking) */ - size_t npoints; /* Number of points in space */ - hsize_t offset; /* Offset of dataset */ - size_t max_temp_buf; /* Maximum size of temporary buffer */ + H5D_io_info_t ioinfo; /* Dataset I/O info */ + H5D_dset_io_info_t dset_info; /* Dset info */ + H5D_storage_t store; /* Union of storage info for dataset */ + hssize_t snpoints; /* Number of points in space (for error checking) */ + size_t npoints; /* Number of points in space */ + hsize_t offset; /* Offset of dataset */ + size_t max_temp_buf; /* Maximum size of temporary buffer */ #ifdef H5_HAVE_PARALLEL MPI_Comm mpi_comm = MPI_COMM_NULL; /* MPI communicator for file */ int mpi_rank = (-1); /* This process's rank */ @@ -252,7 +257,14 @@ H5D__contig_fill(const H5D_io_info_t *io_info) offset = 0; /* Simple setup for dataset I/O info struct */ - H5D_BUILD_IO_INFO_WRT(&ioinfo, dset, &store, fb_info.fill_buf); + ioinfo.op_type = H5D_IO_OP_WRITE; + + dset_info.dset = (H5D_t *)dset; + dset_info.store = &store; + dset_info.buf.cvp = fb_info.fill_buf; + dset_info.mem_space = NULL; + ioinfo.dsets_info = &dset_info; + ioinfo.f_sh = H5F_SHARED(dset->oloc.file); /* * Fill the entire current extent with the fill value. We can do @@ -281,7 +293,7 @@ H5D__contig_fill(const H5D_io_info_t *io_info) /* 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_one(&ioinfo, offset, size) < 0) { + if (H5D__contig_write_one(&ioinfo, &dset_info, offset, size) < 0) { /* If writing fails, push an error and stop writing, but * still participate in following MPI_Barrier. */ @@ -297,7 +309,7 @@ H5D__contig_fill(const H5D_io_info_t *io_info) else { #endif /* H5_HAVE_PARALLEL */ H5_CHECK_OVERFLOW(size, size_t, hsize_t); - if (H5D__contig_write_one(&ioinfo, offset, size) < 0) + if (H5D__contig_write_one(&ioinfo, &dset_info, offset, size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset") #ifdef H5_HAVE_PARALLEL } /* end else */ @@ -562,34 +574,161 @@ H5D__contig_is_data_cached(const H5D_shared_t *shared_dset) * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, March 20, 2008 - * + * Programmer: Jonathan Kim *------------------------------------------------------------------------- */ static herr_t -H5D__contig_io_init(H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space, - H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *cm) +H5D__contig_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) { + H5D_t *dataset = dinfo->dset; /* Local pointer to dataset info */ + + hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ + htri_t file_space_normalized = FALSE; /* File dataspace was normalized */ + + int sf_ndims; /* The number of dimensions of the file dataspace (signed) */ + htri_t use_selection_io = FALSE; /* Whether to use selection I/O */ - htri_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE - io_info->store->contig.dset_addr = io_info->dset->shared->layout.storage.u.contig.addr; - io_info->store->contig.dset_size = io_info->dset->shared->layout.storage.u.contig.size; + dinfo->store->contig.dset_addr = dataset->shared->layout.storage.u.contig.addr; + dinfo->store->contig.dset_size = dataset->shared->layout.storage.u.contig.size; + + /* Initialize piece info */ + dinfo->layout_io_info.contig_piece_info = NULL; + + /* Get layout for dataset */ + dinfo->layout = &(dataset->shared->layout); + + /* Get dim number and dimensionality for each dataspace */ + if ((sf_ndims = H5S_GET_EXTENT_NDIMS(dinfo->file_space)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number") + + /* 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(dinfo->file_space, old_offset)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + + /* if selected elements exist */ + if (dinfo->nelmts) { + int u; + H5D_piece_info_t *new_piece_info; /* piece information to insert into skip list */ + + /* Get copy of dset file_space, so it can be changed temporarily + * purpose + * This tmp_fspace allows multiple write before close dset */ + H5S_t *tmp_fspace; /* Temporary file dataspace */ + + /* Create "temporary" chunk for selection operations (copy file space) */ + if (NULL == (tmp_fspace = H5S_copy(dinfo->file_space, TRUE, FALSE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") + + /* Add temporary chunk to the list of pieces */ + /* collect piece_info into Skip List */ + /* Allocate the file & memory chunk information */ + if (NULL == (new_piece_info = H5FL_MALLOC(H5D_piece_info_t))) { + (void)H5S_close(tmp_fspace); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") + } /* end if */ + + /* Set the piece index */ + new_piece_info->index = 0; + + /* Set the file chunk dataspace */ + new_piece_info->fspace = tmp_fspace; + new_piece_info->fspace_shared = FALSE; + + /* Set the memory chunk dataspace */ + /* same as one chunk, just use dset mem space */ + new_piece_info->mspace = dinfo->mem_space; + + /* set true for sharing mem space with dset, which means + * fspace gets free by application H5Sclose(), and + * doesn't require providing layout_ops.io_term() for H5D_LOPS_CONTIG. + */ + new_piece_info->mspace_shared = TRUE; + + /* Set the number of points */ + new_piece_info->piece_points = dinfo->nelmts; + + /* Copy the piece's coordinates */ + for (u = 0; u < sf_ndims; u++) + new_piece_info->scaled[u] = 0; + new_piece_info->scaled[sf_ndims] = 0; + + /* make connection to related dset info from this piece_info */ + new_piece_info->dset_info = dinfo; + + /* get dset file address for piece */ + new_piece_info->faddr = dinfo->dset->shared->layout.storage.u.contig.addr; - /* Check if we're performing selection I/O */ - if ((use_selection_io = H5D__contig_may_use_select_io(io_info, H5D_IO_OP_READ)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible") - io_info->use_select_io = (hbool_t)use_selection_io; + /* Save piece to dataset info struct so it is freed at the end of the + * operation */ + dinfo->layout_io_info.contig_piece_info = new_piece_info; + + /* Add piece to piece_count */ + io_info->piece_count++; + } /* end if */ + + /* Check if we're performing selection I/O if it hasn't been disabled + * already */ + if (io_info->use_select_io) { + if ((use_selection_io = H5D__contig_may_use_select_io(io_info, dinfo, H5D_IO_OP_READ)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible") + io_info->use_select_io = (hbool_t)use_selection_io; + } done: + if (ret_value < 0) { + if (H5D__contig_io_term(io_info, dinfo) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataset I/O info") + } /* end if */ + + if (file_space_normalized) { + /* (Casting away const OK -QAK) */ + if (H5S_hyper_denormalize_offset(dinfo->file_space, old_offset) < 0) + HDONE_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + } /* end if */ + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__contig_io_init() */ /*------------------------------------------------------------------------- + * Function: H5D__contig_mdio_init + * + * Purpose: Performs second phase of initialization for multi-dataset + * I/O. Currently just adds data block to sel_pieces. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__contig_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) +{ + FUNC_ENTER_PACKAGE_NOERR + + /* Add piece if it exists */ + if (dinfo->layout_io_info.contig_piece_info) { + HDassert(io_info->sel_pieces); + HDassert(io_info->pieces_added < io_info->piece_count); + + /* Add contiguous data block to sel_pieces */ + io_info->sel_pieces[io_info->pieces_added] = dinfo->layout_io_info.contig_piece_info; + + /* Update pieces_added */ + io_info->pieces_added++; + } + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D__contig_mdio_init() */ + +/*------------------------------------------------------------------------- * Function: H5D__contig_may_use_select_io * * Purpose: A small internal function to if it may be possible to use @@ -603,7 +742,8 @@ done: *------------------------------------------------------------------------- */ static htri_t -H5D__contig_may_use_select_io(const H5D_io_info_t *io_info, H5D_io_op_type_t op_type) +H5D__contig_may_use_select_io(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + H5D_io_op_type_t op_type) { const H5D_t *dataset = NULL; /* Local pointer to dataset info */ htri_t ret_value = FAIL; /* Return value */ @@ -612,24 +752,25 @@ H5D__contig_may_use_select_io(const H5D_io_info_t *io_info, H5D_io_op_type_t op_ /* Sanity check */ HDassert(io_info); - HDassert(io_info->dset); + HDassert(dset_info); + HDassert(dset_info->dset); HDassert(op_type == H5D_IO_OP_READ || op_type == H5D_IO_OP_WRITE); - dataset = io_info->dset; + dataset = dset_info->dset; /* Don't use selection I/O if it's globally disabled, if there is a type * conversion, or if it's not a contiguous dataset, or if the sieve buffer * exists (write) or is dirty (read) */ - if (!H5_use_selection_io_g || io_info->io_ops.single_read != H5D__select_read || - io_info->layout_ops.readvv != H5D__contig_readvv || + if (dset_info->io_ops.single_read != H5D__select_read || + dset_info->layout_ops.readvv != H5D__contig_readvv || (op_type == H5D_IO_OP_READ && dataset->shared->cache.contig.sieve_dirty) || (op_type == H5D_IO_OP_WRITE && dataset->shared->cache.contig.sieve_buf)) ret_value = FALSE; else { hbool_t page_buf_enabled; - HDassert(io_info->io_ops.single_write == H5D__select_write); - HDassert(io_info->layout_ops.writevv == H5D__contig_writevv); + HDassert(dset_info->io_ops.single_write == H5D__select_write); + HDassert(dset_info->layout_ops.writevv == H5D__contig_writevv); /* Check if the page buffer is enabled */ if (H5PB_enabled(io_info->f_sh, H5FD_MEM_DRAW, &page_buf_enabled) < 0) @@ -657,8 +798,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, H5S_t *file_space, - H5S_t *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *fm) +H5D__contig_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) { herr_t ret_value = SUCCEED; /* Return value */ @@ -666,25 +806,49 @@ H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.rbuf); - HDassert(type_info); - HDassert(mem_space); - HDassert(file_space); + HDassert(dinfo); + HDassert(dinfo->buf.vp); + HDassert(dinfo->mem_space); + HDassert(dinfo->file_space); if (io_info->use_select_io) { - size_t dst_type_size = type_info->dst_type_size; - - /* Issue selection I/O call (we can skip the page buffer because we've - * already verified it won't be used, and the metadata accumulator - * because this is raw data) */ - if (H5F_shared_select_read(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, nelmts > 0 ? 1 : 0, - &mem_space, &file_space, &(io_info->store->contig.dset_addr), - &dst_type_size, &(io_info->u.rbuf)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous selection read failed") + /* Only perform I/O if not performing multi dataset I/O with selection + * I/O, otherwise the higher level will handle it after all datasets + * have been processed */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + size_t dst_type_size = dinfo->type_info.dst_type_size; + + /* Issue selection I/O call (we can skip the page buffer because we've + * already verified it won't be used, and the metadata accumulator + * because this is raw data) */ + if (H5F_shared_select_read(H5F_SHARED(dinfo->dset->oloc.file), H5FD_MEM_DRAW, + dinfo->nelmts > 0 ? 1 : 0, &dinfo->mem_space, &dinfo->file_space, + &(dinfo->store->contig.dset_addr), &dst_type_size, + &(dinfo->buf.vp)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous selection read failed") + } + else { + if (dinfo->layout_io_info.contig_piece_info) { + /* Add to mdset selection I/O arrays */ + HDassert(io_info->mem_spaces); + HDassert(io_info->file_spaces); + HDassert(io_info->addrs); + HDassert(io_info->element_sizes); + HDassert(io_info->rbufs); + HDassert(io_info->pieces_added < io_info->piece_count); + + io_info->mem_spaces[io_info->pieces_added] = dinfo->mem_space; + io_info->file_spaces[io_info->pieces_added] = dinfo->file_space; + io_info->addrs[io_info->pieces_added] = dinfo->store->contig.dset_addr; + io_info->element_sizes[io_info->pieces_added] = dinfo->type_info.src_type_size; + io_info->rbufs[io_info->pieces_added] = dinfo->buf.vp; + io_info->pieces_added++; + } + } } /* end if */ else /* Read data through legacy (non-selection I/O) pathway */ - if ((io_info->io_ops.single_read)(io_info, type_info, nelmts, file_space, mem_space) < 0) + if ((dinfo->io_ops.single_read)(io_info, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous read failed") done: @@ -704,8 +868,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, H5S_t *file_space, - H5S_t *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *fm) +H5D__contig_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) { herr_t ret_value = SUCCEED; /* Return value */ @@ -713,25 +876,49 @@ H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsiz /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.wbuf); - HDassert(type_info); - HDassert(mem_space); - HDassert(file_space); + HDassert(dinfo); + HDassert(dinfo->buf.cvp); + HDassert(dinfo->mem_space); + HDassert(dinfo->file_space); if (io_info->use_select_io) { - size_t dst_type_size = type_info->dst_type_size; - - /* Issue selection I/O call (we can skip the page buffer because we've - * already verified it won't be used, and the metadata accumulator - * because this is raw data) */ - if (H5F_shared_select_write(H5F_SHARED(io_info->dset->oloc.file), H5FD_MEM_DRAW, nelmts > 0 ? 1 : 0, - &mem_space, &file_space, &(io_info->store->contig.dset_addr), - &dst_type_size, &(io_info->u.wbuf)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous selection write failed") + /* Only perform I/O if not performing multi dataset I/O with selection + * I/O, otherwise the higher level will handle it after all datasets + * have been processed */ + if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) { + size_t dst_type_size = dinfo->type_info.dst_type_size; + + /* Issue selection I/O call (we can skip the page buffer because we've + * already verified it won't be used, and the metadata accumulator + * because this is raw data) */ + if (H5F_shared_select_write(H5F_SHARED(dinfo->dset->oloc.file), H5FD_MEM_DRAW, + dinfo->nelmts > 0 ? 1 : 0, &dinfo->mem_space, &dinfo->file_space, + &(dinfo->store->contig.dset_addr), &dst_type_size, + &(dinfo->buf.cvp)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous selection write failed") + } + else { + if (dinfo->layout_io_info.contig_piece_info) { + /* Add to mdset selection I/O arrays */ + HDassert(io_info->mem_spaces); + HDassert(io_info->file_spaces); + HDassert(io_info->addrs); + HDassert(io_info->element_sizes); + HDassert(io_info->wbufs); + HDassert(io_info->pieces_added < io_info->piece_count); + + io_info->mem_spaces[io_info->pieces_added] = dinfo->mem_space; + io_info->file_spaces[io_info->pieces_added] = dinfo->file_space; + io_info->addrs[io_info->pieces_added] = dinfo->store->contig.dset_addr; + io_info->element_sizes[io_info->pieces_added] = dinfo->type_info.dst_type_size; + io_info->wbufs[io_info->pieces_added] = dinfo->buf.cvp; + io_info->pieces_added++; + } + } } /* end if */ else /* Write data through legacy (non-selection I/O) pathway */ - if ((io_info->io_ops.single_write)(io_info, type_info, nelmts, file_space, mem_space) < 0) + if ((dinfo->io_ops.single_write)(io_info, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous write failed") done: @@ -753,7 +940,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__contig_write_one(H5D_io_info_t *io_info, hsize_t offset, size_t size) +H5D__contig_write_one(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hsize_t offset, size_t size) { hsize_t dset_off = offset; /* Offset in dataset */ size_t dset_len = size; /* Length in dataset */ @@ -767,7 +954,7 @@ H5D__contig_write_one(H5D_io_info_t *io_info, hsize_t offset, size_t size) HDassert(io_info); - if (H5D__contig_writevv(io_info, (size_t)1, &dset_curr_seq, &dset_len, &dset_off, (size_t)1, + if (H5D__contig_writevv(io_info, dset_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") @@ -990,9 +1177,9 @@ done: *------------------------------------------------------------------------- */ static ssize_t -H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, - size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, - size_t mem_len_arr[], hsize_t mem_off_arr[]) +H5D__contig_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq, + size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, + size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { ssize_t ret_value = -1; /* Return value */ @@ -1000,6 +1187,7 @@ H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *d /* Check args */ HDassert(io_info); + HDassert(dset_info); HDassert(dset_curr_seq); HDassert(dset_len_arr); HDassert(dset_off_arr); @@ -1013,9 +1201,9 @@ H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *d /* Set up user data for H5VM_opvv() */ udata.f_sh = io_info->f_sh; - udata.dset_contig = &(io_info->dset->shared->cache.contig); - udata.store_contig = &(io_info->store->contig); - udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.dset_contig = &(dset_info->dset->shared->cache.contig); + udata.store_contig = &(dset_info->store->contig); + udata.rbuf = (unsigned char *)dset_info->buf.vp; /* Call generic sequence operation routine */ if ((ret_value = @@ -1028,8 +1216,8 @@ H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *d /* Set up user data for H5VM_opvv() */ udata.f_sh = io_info->f_sh; - udata.dset_addr = io_info->store->contig.dset_addr; - udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.dset_addr = dset_info->store->contig.dset_addr; + udata.rbuf = (unsigned char *)dset_info->buf.vp; /* Call generic sequence operation routine */ if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, @@ -1308,9 +1496,9 @@ done: *------------------------------------------------------------------------- */ static 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_off_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, - size_t mem_len_arr[], hsize_t mem_off_arr[]) +H5D__contig_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq, + size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, + size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { ssize_t ret_value = -1; /* Return value (Size of sequence in bytes) */ @@ -1318,6 +1506,7 @@ H5D__contig_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t * /* Check args */ HDassert(io_info); + HDassert(dset_info); HDassert(dset_curr_seq); HDassert(dset_len_arr); HDassert(dset_off_arr); @@ -1331,9 +1520,9 @@ H5D__contig_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t * /* Set up user data for H5VM_opvv() */ udata.f_sh = io_info->f_sh; - udata.dset_contig = &(io_info->dset->shared->cache.contig); - udata.store_contig = &(io_info->store->contig); - udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.dset_contig = &(dset_info->dset->shared->cache.contig); + udata.store_contig = &(dset_info->store->contig); + udata.wbuf = (const unsigned char *)dset_info->buf.cvp; /* Call generic sequence operation routine */ if ((ret_value = @@ -1346,8 +1535,8 @@ H5D__contig_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t * /* Set up user data for H5VM_opvv() */ udata.f_sh = io_info->f_sh; - udata.dset_addr = io_info->store->contig.dset_addr; - udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.dset_addr = dset_info->store->contig.dset_addr; + udata.wbuf = (const unsigned char *)dset_info->buf.cvp; /* Call generic sequence operation routine */ if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, @@ -1391,6 +1580,35 @@ done: } /* end H5D__contig_flush() */ /*------------------------------------------------------------------------- + * Function: H5D__contig_io_term + * + * Purpose: Destroy I/O operation information. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__contig_io_term(H5D_io_info_t H5_ATTR_UNUSED *io_info, H5D_dset_io_info_t *di) +{ + herr_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_PACKAGE + + HDassert(di); + + /* Free piece info */ + if (di->layout_io_info.contig_piece_info) { + if (H5D__free_piece_info(di->layout_io_info.contig_piece_info, NULL, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free piece info") + di->layout_io_info.contig_piece_info = NULL; + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__contig_io_term() */ + +/*------------------------------------------------------------------------- * Function: H5D__contig_copy * * Purpose: Copy contiguous storage raw data from SRC file to DST file. diff --git a/src/H5Defl.c b/src/H5Defl.c index d81ed13..c6a1961 100644 --- a/src/H5Defl.c +++ b/src/H5Defl.c @@ -61,14 +61,15 @@ typedef struct H5D_efl_writevv_ud_t { /* Layout operation callbacks */ static herr_t H5D__efl_construct(H5F_t *f, H5D_t *dset); -static herr_t H5D__efl_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *cm); -static ssize_t H5D__efl_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, - size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, - size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); -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[]); +static herr_t H5D__efl_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static ssize_t H5D__efl_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_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, const H5D_dset_io_info_t *dset_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, const H5D_t *dset, haddr_t addr, size_t size, uint8_t *buf); @@ -86,17 +87,14 @@ const H5D_layout_ops_t H5D_LOPS_EFL[1] = {{ H5D__efl_is_space_alloc, /* is_space_alloc */ NULL, /* is_data_cached */ H5D__efl_io_init, /* io_init */ + NULL, /* mdio_init */ H5D__contig_read, /* ser_read */ H5D__contig_write, /* ser_write */ -#ifdef H5_HAVE_PARALLEL - NULL, /* par_read */ - NULL, /* par_write */ -#endif - H5D__efl_readvv, /* readvv */ - H5D__efl_writevv, /* writevv */ - NULL, /* flush */ - NULL, /* io_term */ - NULL /* dest */ + H5D__efl_readvv, /* readvv */ + H5D__efl_writevv, /* writevv */ + NULL, /* flush */ + NULL, /* io_term */ + NULL /* dest */ }}; /*******************/ @@ -209,13 +207,14 @@ H5D__efl_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage) *------------------------------------------------------------------------- */ static herr_t -H5D__efl_io_init(H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space, - H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *cm) +H5D__efl_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo) { FUNC_ENTER_PACKAGE_NOERR - H5MM_memcpy(&io_info->store->efl, &(io_info->dset->shared->dcpl_cache.efl), sizeof(H5O_efl_t)); + H5MM_memcpy(&dinfo->store->efl, &(dinfo->dset->shared->dcpl_cache.efl), sizeof(H5O_efl_t)); + + /* Disable selection I/O */ + io_info->use_select_io = FALSE; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__efl_io_init() */ @@ -443,9 +442,9 @@ done: *------------------------------------------------------------------------- */ 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_off_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, - size_t mem_len_arr[], hsize_t mem_off_arr[]) +H5D__efl_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq, + size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, + size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { H5D_efl_readvv_ud_t udata; /* User data for H5VM_opvv() operator */ ssize_t ret_value = -1; /* Return value (Total size of sequence in bytes) */ @@ -454,10 +453,11 @@ H5D__efl_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset /* Check args */ HDassert(io_info); - HDassert(io_info->store->efl.nused > 0); - HDassert(io_info->u.rbuf); - HDassert(io_info->dset); - HDassert(io_info->dset->shared); + HDassert(dset_info); + HDassert(dset_info->store->efl.nused > 0); + HDassert(dset_info->buf.vp); + HDassert(dset_info->dset); + HDassert(dset_info->dset->shared); HDassert(dset_curr_seq); HDassert(dset_len_arr); HDassert(dset_off_arr); @@ -466,9 +466,9 @@ H5D__efl_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset HDassert(mem_off_arr); /* Set up user data for H5VM_opvv() */ - udata.efl = &(io_info->store->efl); - udata.dset = io_info->dset; - udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.efl = &(dset_info->store->efl); + udata.dset = dset_info->dset; + udata.rbuf = (unsigned char *)dset_info->buf.vp; /* Call generic sequence operation routine */ if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, @@ -523,9 +523,9 @@ done: *------------------------------------------------------------------------- */ 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_off_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, - size_t mem_len_arr[], hsize_t mem_off_arr[]) +H5D__efl_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq, + size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, + size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { H5D_efl_writevv_ud_t udata; /* User data for H5VM_opvv() operator */ ssize_t ret_value = -1; /* Return value (Total size of sequence in bytes) */ @@ -534,10 +534,11 @@ H5D__efl_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dse /* Check args */ HDassert(io_info); - HDassert(io_info->store->efl.nused > 0); - HDassert(io_info->u.wbuf); - HDassert(io_info->dset); - HDassert(io_info->dset->shared); + HDassert(dset_info); + HDassert(dset_info->store->efl.nused > 0); + HDassert(dset_info->buf.cvp); + HDassert(dset_info->dset); + HDassert(dset_info->dset->shared); HDassert(dset_curr_seq); HDassert(dset_len_arr); HDassert(dset_off_arr); @@ -546,9 +547,9 @@ H5D__efl_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dse HDassert(mem_off_arr); /* Set up user data for H5VM_opvv() */ - udata.efl = &(io_info->store->efl); - udata.dset = io_info->dset; - udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.efl = &(dset_info->store->efl); + udata.dset = dset_info->dset; + udata.wbuf = (const unsigned char *)dset_info->buf.cvp; /* Call generic sequence operation routine */ if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq, diff --git a/src/H5Dint.c b/src/H5Dint.c index 9d80654..754ddad 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -61,7 +61,7 @@ typedef struct { /* Internal data structure for computing variable-length dataset's total size */ /* (Used for generic 'get vlen buf size' operation) */ typedef struct { - H5VL_object_t *dset_vol_obj; /* VOL object for the dataset */ + const H5VL_object_t *dset_vol_obj; /* VOL object for the dataset */ hid_t fspace_id; /* Dataset dataspace ID of the dataset we are working on */ H5S_t *fspace; /* Dataset's dataspace for operation */ hid_t mspace_id; /* Memory dataspace ID of the dataset we are working on */ @@ -81,7 +81,7 @@ static herr_t H5D__init_space(H5F_t *file, const H5D_t *dset, const H5S_t static herr_t H5D__update_oh_info(H5F_t *file, H5D_t *dset, hid_t dapl_id); static herr_t H5D__build_file_prefix(const H5D_t *dset, H5F_prefix_open_t prefix_type, char **file_prefix); static herr_t H5D__open_oid(H5D_t *dataset, hid_t dapl_id); -static herr_t H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t old_dim[]); +static herr_t H5D__init_storage(H5D_t *dset, hbool_t full_overwrite, hsize_t old_dim[]); static herr_t H5D__append_flush_setup(H5D_t *dset, hid_t dapl_id); static herr_t H5D__close_cb(H5VL_object_t *dset_vol_obj, void **request); static herr_t H5D__use_minimized_dset_headers(H5F_t *file, hbool_t *minimize); @@ -119,8 +119,8 @@ H5FL_DEFINE_STATIC(H5D_shared_t); /* Declare the external PQ free list for the sieve buffer information */ H5FL_BLK_EXTERN(sieve_buf); -/* Declare the external free list to manage the H5D_chunk_info_t struct */ -H5FL_EXTERN(H5D_chunk_info_t); +/* Declare the external free list to manage the H5D_piece_info_t struct */ +H5FL_EXTERN(H5D_piece_info_t); /* Declare extern the free list to manage blocks of type conversion data */ H5FL_BLK_EXTERN(type_conv); @@ -1793,14 +1793,9 @@ H5D__open_oid(H5D_t *dataset, hid_t dapl_id) */ if ((H5F_INTENT(dataset->oloc.file) & H5F_ACC_RDWR) && !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage) && - H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_ALLOCATE_EARLY)) { - H5D_io_info_t io_info; - - io_info.dset = dataset; - - if (H5D__alloc_storage(&io_info, H5D_ALLOC_OPEN, FALSE, NULL) < 0) + H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_ALLOCATE_EARLY)) + if (H5D__alloc_storage(dataset, H5D_ALLOC_OPEN, FALSE, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file storage") - } /* end if */ done: if (ret_value < 0) { @@ -1894,10 +1889,10 @@ H5D_close(H5D_t *dataset) } /* end if */ /* Check for cached single element chunk info */ - if (dataset->shared->cache.chunk.single_chunk_info) { - dataset->shared->cache.chunk.single_chunk_info = - H5FL_FREE(H5D_chunk_info_t, dataset->shared->cache.chunk.single_chunk_info); - dataset->shared->cache.chunk.single_chunk_info = NULL; + if (dataset->shared->cache.chunk.single_piece_info) { + dataset->shared->cache.chunk.single_piece_info = + H5FL_FREE(H5D_piece_info_t, dataset->shared->cache.chunk.single_piece_info); + dataset->shared->cache.chunk.single_piece_info = NULL; } /* end if */ break; @@ -2088,10 +2083,10 @@ H5D_mult_refresh_close(hid_t dset_id) } /* end if */ /* Check for cached single element chunk info */ - if (dataset->shared->cache.chunk.single_chunk_info) { - dataset->shared->cache.chunk.single_chunk_info = - H5FL_FREE(H5D_chunk_info_t, dataset->shared->cache.chunk.single_chunk_info); - dataset->shared->cache.chunk.single_chunk_info = NULL; + if (dataset->shared->cache.chunk.single_piece_info) { + dataset->shared->cache.chunk.single_piece_info = + H5FL_FREE(H5D_piece_info_t, dataset->shared->cache.chunk.single_piece_info); + dataset->shared->cache.chunk.single_piece_info = NULL; } /* end if */ break; @@ -2209,11 +2204,9 @@ H5D_nameof(H5D_t *dataset) *------------------------------------------------------------------------- */ herr_t -H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, hbool_t full_overwrite, - hsize_t old_dim[]) +H5D__alloc_storage(H5D_t *dset, H5D_time_alloc_t time_alloc, hbool_t full_overwrite, hsize_t old_dim[]) { - const H5D_t *dset = io_info->dset; /* The dataset object */ - H5F_t *f = dset->oloc.file; /* The dataset's file pointer */ + H5F_t *f; /* The dataset's file pointer */ H5O_layout_t *layout; /* The dataset's layout information */ hbool_t must_init_space = FALSE; /* Flag to indicate that space should be initialized */ hbool_t addr_set = FALSE; /* Flag to indicate that the dataset's storage address was set */ @@ -2223,6 +2216,7 @@ H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, hb /* check args */ HDassert(dset); + f = dset->oloc.file; HDassert(f); /* If the data is stored in external files, don't set an address for the layout @@ -2333,7 +2327,7 @@ H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, hb */ if (!(dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_INCR && time_alloc == H5D_ALLOC_WRITE)) - if (H5D__init_storage(io_info, full_overwrite, old_dim) < 0) + if (H5D__init_storage(dset, full_overwrite, old_dim) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize dataset with fill value") } /* end if */ @@ -2349,7 +2343,7 @@ H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, hb if (dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC || (dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET && fill_status == H5D_FILL_VALUE_USER_DEFINED)) - if (H5D__init_storage(io_info, full_overwrite, old_dim) < 0) + if (H5D__init_storage(dset, full_overwrite, old_dim) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize dataset with fill value") } /* end else */ @@ -2383,10 +2377,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t old_dim[]) +H5D__init_storage(H5D_t *dset, hbool_t full_overwrite, hsize_t old_dim[]) { - const H5D_t *dset = io_info->dset; /* dataset pointer */ - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE @@ -2408,7 +2401,7 @@ H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t /* If we will be immediately overwriting the values, don't bother to clear them */ if ((dset->shared->dcpl_cache.efl.nused == 0 || dset->shared->dcpl_cache.fill.buf) && !full_overwrite) - if (H5D__contig_fill(io_info) < 0) + if (H5D__contig_fill(dset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to allocate all chunks of dataset") break; @@ -2424,7 +2417,7 @@ H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t if (old_dim == NULL) old_dim = zero_dim; - if (H5D__chunk_allocate(io_info, full_overwrite, old_dim) < 0) + if (H5D__chunk_allocate(dset, full_overwrite, old_dim) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to allocate all chunks of dataset") break; } /* end block */ @@ -2599,7 +2592,8 @@ H5D__vlen_get_buf_size_cb(void H5_ATTR_UNUSED *elem, hid_t type_id, unsigned H5_ const hsize_t *point, void *op_data) { H5D_vlen_bufsize_native_t *vlen_bufsize = (H5D_vlen_bufsize_native_t *)op_data; - herr_t ret_value = H5_ITER_CONT; /* Return value */ + H5D_dset_io_info_t dset_info; /* Internal multi-dataset info placeholder */ + herr_t ret_value = H5_ITER_CONT; /* Return value */ FUNC_ENTER_PACKAGE @@ -2612,10 +2606,17 @@ H5D__vlen_get_buf_size_cb(void H5_ATTR_UNUSED *elem, hid_t type_id, unsigned H5_ if (H5S_select_elements(vlen_bufsize->fspace, H5S_SELECT_SET, (size_t)1, point) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, H5_ITER_ERROR, "can't select point") - /* Read in the point (with the custom VL memory allocator) */ - if (H5D__read(vlen_bufsize->dset, type_id, vlen_bufsize->mspace, vlen_bufsize->fspace, - vlen_bufsize->common.fl_tbuf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, H5_ITER_ERROR, "can't read point") + { + dset_info.dset = vlen_bufsize->dset; + dset_info.mem_space = vlen_bufsize->mspace; + dset_info.file_space = vlen_bufsize->fspace; + dset_info.buf.vp = vlen_bufsize->common.fl_tbuf; + dset_info.mem_type_id = type_id; + + /* Read in the point (with the custom VL memory allocator) */ + if (H5D__read(1, &dset_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -2767,8 +2768,8 @@ H5D__vlen_get_buf_size_gen_cb(void H5_ATTR_UNUSED *elem, hid_t type_id, unsigned HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't select point") /* Read in the point (with the custom VL memory allocator) */ - if (H5VL_dataset_read(vlen_bufsize->dset_vol_obj, type_id, vlen_bufsize->mspace_id, - vlen_bufsize->fspace_id, vlen_bufsize->dxpl_id, vlen_bufsize->common.fl_tbuf, + if (H5VL_dataset_read(1, &vlen_bufsize->dset_vol_obj, &type_id, &vlen_bufsize->mspace_id, + &vlen_bufsize->fspace_id, vlen_bufsize->dxpl_id, &vlen_bufsize->common.fl_tbuf, H5_REQUEST_NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read point") @@ -2814,7 +2815,7 @@ H5D__vlen_get_buf_size_gen(H5VL_object_t *vol_obj, hid_t type_id, hid_t space_id HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "dataspace does not have extent set") /* Save the dataset */ - vlen_bufsize.dset_vol_obj = vol_obj; + vlen_bufsize.dset_vol_obj = (const H5VL_object_t *)vol_obj; /* Set up VOL callback arguments */ vol_cb_args.op_type = H5VL_DATASET_GET_SPACE; @@ -3095,14 +3096,10 @@ H5D__set_extent(H5D_t *dset, const hsize_t *size) } /* end if */ /* Allocate space for the new parts of the dataset, if appropriate */ - if (expand && dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_EARLY) { - H5D_io_info_t io_info; - - io_info.dset = dset; - - if (H5D__alloc_storage(&io_info, H5D_ALLOC_EXTEND, FALSE, curr_dims) < 0) + if (expand && dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_EARLY) + if (H5D__alloc_storage(dset, H5D_ALLOC_EXTEND, FALSE, curr_dims) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to extend dataset storage") - } + /*------------------------------------------------------------------------- * Remove chunk information in the case of chunked datasets * This removal takes place only in case we are shrinking the dataset diff --git a/src/H5Dio.c b/src/H5Dio.c index c1427d1..0b52208 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -44,15 +44,14 @@ /********************/ /* Setup/teardown routines */ -static herr_t H5D__ioinfo_init(H5D_t *dset, const H5D_type_info_t *type_info, H5D_storage_t *store, - H5D_io_info_t *io_info); -static herr_t H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, - H5D_type_info_t *type_info); +static herr_t H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info); +static herr_t H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store); +static herr_t H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id); +static herr_t H5D__typeinfo_init_phase2(H5D_io_info_t *io_info); #ifdef H5_HAVE_PARALLEL -static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_space, - const H5S_t *mem_space, const H5D_type_info_t *type_info); +static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info); #endif /* H5_HAVE_PARALLEL */ -static herr_t H5D__typeinfo_term(const H5D_type_info_t *type_info); +static herr_t H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init); /*********************/ /* Package Variables */ @@ -65,66 +64,63 @@ static herr_t H5D__typeinfo_term(const H5D_type_info_t *type_info); /* Declare a free list to manage blocks of type conversion data */ H5FL_BLK_DEFINE(type_conv); -/* Declare a free list to manage the H5D_chunk_map_t struct */ -H5FL_DEFINE(H5D_chunk_map_t); - /*------------------------------------------------------------------------- * Function: H5D__read * - * Purpose: Reads (part of) a DATASET into application memory BUF. See - * H5Dread() for complete details. + * Purpose: Reads multiple (parts of) DATASETs into application memory BUFs. + * See H5Dread_multi() for complete details. * * Return: Non-negative on success/Negative on failure * - * Programmer: Robb Matzke - * Thursday, December 4, 1997 - * *------------------------------------------------------------------------- */ herr_t -H5D__read(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space, void *buf /*out*/) +H5D__read(size_t count, H5D_dset_io_info_t *dset_info) { - H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */ - H5D_io_info_t io_info; /* Dataset I/O info */ - H5D_type_info_t type_info; /* Datatype info for operation */ - H5D_layout_t layout_type; /* Dataset's layout type (contig, chunked, compact, etc.) */ - hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */ - H5S_t *projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */ - /* projection of the supplied mem_space to a new */ - /* dataspace with rank equal to that of */ - /* file_space. */ - /* */ - /* This field is only used if */ - /* H5S_select_shape_same() returns TRUE when */ - /* comparing the mem_space and the data_space, */ - /* and the mem_space have different rank. */ - /* */ - /* Note that if this variable is used, the */ - /* projected mem space must be discarded at the */ - /* end of the function to avoid a memory leak. */ - H5D_storage_t store; /* union of EFL and chunk pointer in file space */ - hsize_t nelmts; /* total number of elmts */ - hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ - char fake_char; /* Temporary variable for NULL buffer pointers */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_PACKAGE_TAG(dataset->oloc.addr) + H5D_io_info_t io_info; /* Dataset I/O info for multi dsets */ + size_t type_info_init = 0; /* Number of datatype info structs that have been initialized */ + H5S_t *orig_mem_space_local; /* Local buffer for orig_mem_space */ + H5S_t **orig_mem_space = NULL; /* If not NULL, ptr to an array of dataspaces */ + /* containing the original memory spaces contained */ + /* in dset_info. This is needed in order to */ + /* restore the original state of dset_info if we */ + /* replaced any mem spaces with equivalents */ + /* projected to a rank equal to that of file_space. */ + /* */ + /* This field is only used if */ + /* H5S_select_shape_same() returns TRUE when */ + /* comparing at least one mem_space and data_space, */ + /* and the mem_space has a different rank. */ + /* */ + /* Note that this is a temporary variable - the */ + /* projected memory space is stored in dset_info, */ + /* and will be freed when that structure is */ + /* freed. */ + H5D_storage_t store_local; /* Local buffer for store */ + H5D_storage_t *store = &store_local; /* Union of EFL and chunk pointer in file space */ + size_t io_op_init = 0; /* Number I/O ops that have been initialized */ + size_t io_skipped = + 0; /* Number I/O ops that have been skipped (due to the dataset not being allocated) */ + size_t i; /* Local index variable */ + char fake_char; /* Temporary variable for NULL buffer pointers */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check args */ - HDassert(dataset && dataset->oloc.file); - HDassert(file_space); - HDassert(mem_space); + FUNC_ENTER_NOAPI(FAIL) - layout_type = dataset->shared->layout.type; + /* Init io_info */ + if (H5D__ioinfo_init(count, dset_info, &io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + io_info.op_type = H5D_IO_OP_READ; - /* Set up datatype info for operation */ - if (H5D__typeinfo_init(dataset, mem_type_id, FALSE, &type_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") - type_info_init = TRUE; + /* Allocate store buffer if necessary */ + if (count > 1) + if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer") #ifdef H5_HAVE_PARALLEL - /* Check for non-MPI-based VFD */ - if (!(H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI))) { + /* Check for non-MPI-based VFD. Only need to check first dataset since all + * share the same file. */ + if (!(H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI))) { H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ /* Get I/O transfer mode */ @@ -137,363 +133,626 @@ H5D__read(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space } /* end if */ #endif /*H5_HAVE_PARALLEL*/ - /* Make certain that the number of elements in each selection is the same */ - nelmts = H5S_GET_SELECT_NPOINTS(mem_space); - if (nelmts != H5S_GET_SELECT_NPOINTS(file_space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "src and dest dataspaces have different number of elements selected") - - /* Check for a NULL buffer */ - if (NULL == buf) { - /* Check for any elements selected (which is invalid) */ - if (nelmts > 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") - - /* If the buffer is nil, and 0 element is selected, make a fake buffer. - * This is for some MPI package like ChaMPIon on NCSA's tungsten which - * doesn't support this feature. - */ - buf = &fake_char; - } /* end if */ - - /* Make sure that both selections have their extents set */ - if (!(H5S_has_extent(file_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") - if (!(H5S_has_extent(mem_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") + /* iterate over all dsets and construct I/O information necessary to do I/O */ + for (i = 0; i < count; i++) { + haddr_t prev_tag = HADDR_UNDEF; + + /* check args */ + if (NULL == dset_info[i].dset) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + if (NULL == dset_info[i].dset->oloc.file) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") + + /* set metadata tagging with dset oheader addr */ + H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag); + + /* Set up datatype info for operation */ + if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") + type_info_init++; + + /* Make certain that the number of elements in each selection is the same, and cache nelmts in + * dset_info */ + dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space); + if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "src and dest dataspaces have different number of elements selected") + + /* Check for a NULL buffer */ + if (NULL == dset_info[i].buf.vp) { + /* Check for any elements selected (which is invalid) */ + if (dset_info[i].nelmts > 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") + + /* If the buffer is nil, and 0 element is selected, make a fake buffer. + * This is for some MPI package like ChaMPIon on NCSA's tungsten which + * doesn't support this feature. + */ + dset_info[i].buf.vp = &fake_char; + } /* end if */ - /* H5S_select_shape_same() has been modified to accept topologically identical - * selections with different rank as having the same shape (if the most - * rapidly changing coordinates match up), but the I/O code still has - * difficulties with the notion. - * - * To solve this, we check to see if H5S_select_shape_same() returns true, - * and if the ranks of the mem and file spaces are different. If they are, - * construct a new mem space that is equivalent to the old mem space, and - * use that instead. - * - * Note that in general, this requires us to touch up the memory buffer as - * well. - */ - if (nelmts > 0 && TRUE == H5S_SELECT_SHAPE_SAME(mem_space, file_space) && - H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) { - ptrdiff_t buf_adj = 0; - - /* Attempt to construct projected dataspace for memory dataspace */ - if (H5S_select_construct_projection(mem_space, &projected_mem_space, - (unsigned)H5S_GET_EXTENT_NDIMS(file_space), - type_info.dst_type_size, &buf_adj) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") - HDassert(projected_mem_space); - - /* Adjust the buffer by the given amount */ - buf = (void *)(((uint8_t *)buf) + buf_adj); - - /* Switch to using projected memory dataspace & adjusted buffer */ - mem_space = projected_mem_space; - } /* end if */ + /* Make sure that both selections have their extents set */ + if (!(H5S_has_extent(dset_info[i].file_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") + if (!(H5S_has_extent(dset_info[i].mem_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") + + /* H5S_select_shape_same() has been modified to accept topologically identical + * selections with different rank as having the same shape (if the most + * rapidly changing coordinates match up), but the I/O code still has + * difficulties with the notion. + * + * To solve this, we check to see if H5S_select_shape_same() returns true, + * and if the ranks of the mem and file spaces are different. If they are, + * construct a new mem space that is equivalent to the old mem space, and + * use that instead. + * + * Note that in general, this requires us to touch up the memory buffer as + * well. + */ + if (dset_info[i].nelmts > 0 && + TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) && + H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) { + ptrdiff_t buf_adj = 0; + + /* Allocate original memory space buffer if necessary */ + if (!orig_mem_space) { + if (count > 1) { + /* Allocate buffer */ + if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, + "couldn't allocate original memory space array buffer") + } + else + /* Use local buffer */ + orig_mem_space = &orig_mem_space_local; + } - /* Retrieve dataset properties */ - /* */ + /* Save original memory space */ + orig_mem_space[i] = dset_info[i].mem_space; + dset_info[i].mem_space = NULL; - /* If space hasn't been allocated and not using external storage, - * return fill value to buffer if fill time is upon allocation, or - * do nothing if fill time is never. If the dataset is compact and - * fill time is NEVER, there is no way to tell whether part of data - * has been overwritten. So just proceed in reading. - */ - if (nelmts > 0 && dataset->shared->dcpl_cache.efl.nused == 0 && - !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage) && - !(dataset->shared->layout.ops->is_data_cached && - (*dataset->shared->layout.ops->is_data_cached)(dataset->shared))) { - H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */ - - /* Retrieve dataset's fill-value properties */ - if (H5P_is_fill_value_defined(&dataset->shared->dcpl_cache.fill, &fill_status) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined") - - /* Should be impossible, but check anyway... */ - if (fill_status == H5D_FILL_VALUE_UNDEFINED && - (dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC || - dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET)) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, - "read failed: dataset doesn't exist, no data can be read") - - /* If we're never going to fill this dataset, just leave the junk in the user's buffer */ - if (dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_NEVER) - HGOTO_DONE(SUCCEED) - - /* Go fill the user's selection with the dataset's fill value */ - if (H5D__fill(dataset->shared->dcpl_cache.fill.buf, dataset->shared->type, buf, type_info.mem_type, - mem_space) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed") - else - HGOTO_DONE(SUCCEED) - } /* end if */ + /* Attempt to construct projected dataspace for memory dataspace */ + if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space, + (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space), + (hsize_t)dset_info[i].type_info.dst_type_size, &buf_adj) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") + HDassert(dset_info[i].mem_space); - /* Set up I/O operation */ - io_info.op_type = H5D_IO_OP_READ; - io_info.u.rbuf = buf; - if (H5D__ioinfo_init(dataset, &type_info, &store, &io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation") - - /* Sanity check that space is allocated, if there are elements */ - if (nelmts > 0) - HDassert((*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage) || - (dataset->shared->layout.ops->is_data_cached && - (*dataset->shared->layout.ops->is_data_cached)(dataset->shared)) || - dataset->shared->dcpl_cache.efl.nused > 0 || layout_type == H5D_COMPACT); - - /* Allocate the chunk map */ - if (H5D_CONTIGUOUS != layout_type && H5D_COMPACT != layout_type) { - if (NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map") - } + /* Adjust the buffer by the given amount */ + dset_info[i].buf.vp = (void *)(((uint8_t *)dset_info[i].buf.vp) + buf_adj); + } /* end if */ - /* Call storage method's I/O initialization routine */ - if (io_info.layout_ops.io_init && - (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") - io_op_init = TRUE; + /* If space hasn't been allocated and not using external storage, + * return fill value to buffer if fill time is upon allocation, or + * do nothing if fill time is never. If the dataset is compact and + * fill time is NEVER, there is no way to tell whether part of data + * has been overwritten. So just proceed in reading. + */ + if (dset_info[i].nelmts > 0 && dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 && + !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)( + &dset_info[i].dset->shared->layout.storage) && + !(dset_info[i].dset->shared->layout.ops->is_data_cached && + (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared))) { + H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */ + + /* Retrieve dataset's fill-value properties */ + if (H5P_is_fill_value_defined(&dset_info[i].dset->shared->dcpl_cache.fill, &fill_status) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined") + + /* Should be impossible, but check anyway... */ + if (fill_status == H5D_FILL_VALUE_UNDEFINED && + (dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC || + dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET)) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, + "read failed: dataset doesn't exist, no data can be read") + + /* If we're never going to fill this dataset, just leave the junk in the user's buffer */ + if (dset_info[i].dset->shared->dcpl_cache.fill.fill_time != H5D_FILL_TIME_NEVER) + /* Go fill the user's selection with the dataset's fill value */ + if (H5D__fill(dset_info[i].dset->shared->dcpl_cache.fill.buf, dset_info[i].dset->shared->type, + dset_info[i].buf.vp, dset_info[i].type_info.mem_type, + dset_info[i].mem_space) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed") + + /* No need to perform any more I/O for this dataset */ + dset_info[i].skip_io = TRUE; + io_skipped++; + } /* end if */ + else { + /* Set up I/O operation */ + if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation") + + /* Sanity check that space is allocated, if there are elements */ + if (dset_info[i].nelmts > 0) + HDassert( + (*dset_info[i].dset->shared->layout.ops->is_space_alloc)( + &dset_info[i].dset->shared->layout.storage) || + (dset_info[i].dset->shared->layout.ops->is_data_cached && + (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared)) || + dset_info[i].dset->shared->dcpl_cache.efl.nused > 0 || + dset_info[i].dset->shared->layout.type == H5D_COMPACT); + + /* Call storage method's I/O initialization routine */ + if (dset_info[i].layout_ops.io_init && + (dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + dset_info[i].skip_io = FALSE; + io_op_init++; + + /* Reset metadata tagging */ + H5AC_tag(prev_tag, NULL); + } + } /* end of for loop */ + + HDassert(type_info_init == count); + HDassert(io_op_init + io_skipped == count); + + /* If no datasets have I/O, we're done */ + if (io_op_init == 0) + HGOTO_DONE(SUCCEED) + + /* Perform second phase of type info initialization */ + if (H5D__typeinfo_init_phase2(&io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)") #ifdef H5_HAVE_PARALLEL /* Adjust I/O info for any parallel I/O */ - if (H5D__ioinfo_adjust(&io_info, dataset, file_space, mem_space, &type_info) < 0) + if (H5D__ioinfo_adjust(&io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O") #endif /*H5_HAVE_PARALLEL*/ - /* Invoke correct "high level" I/O routine */ - if ((*io_info.io_ops.multi_read)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + /* If multi dataset I/O callback is not provided, perform read IO via + * single-dset path with looping */ + if (io_info.md_io_ops.multi_read_md) { + /* Create sel_pieces array if any pieces are selected */ + if (io_info.piece_count > 0) { + HDassert(!io_info.sel_pieces); + HDassert(io_info.pieces_added == 0); + + /* Allocate sel_pieces array */ + if (NULL == + (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0])))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces") + } + + /* MDIO-specific second phase initialization */ + for (i = 0; i < count; i++) + if (dset_info[i].layout_ops.mdio_init) { + haddr_t prev_tag = HADDR_UNDEF; + + /* set metadata tagging with dset oheader addr */ + H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag); + + /* Make second phase IO init call */ + if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces") + + /* Reset metadata tagging */ + H5AC_tag(prev_tag, NULL); + } + + /* Invoke correct "high level" I/O routine */ + if ((*io_info.md_io_ops.multi_read_md)(&io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + } /* end if */ + else { + haddr_t prev_tag = HADDR_UNDEF; + + if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) { + if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for memory space list") + if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list") + if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for piece address list") + if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for element size list") + if (NULL == (io_info.rbufs = H5MM_malloc(io_info.piece_count * sizeof(void *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for read buffer list") + } + + /* Loop with serial & single-dset read IO path */ + for (i = 0; i < count; i++) { + /* Check for skipped I/O */ + if (dset_info[i].skip_io) + continue; + + /* set metadata tagging with dset oheader addr */ + H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag); + + /* Invoke correct "high level" I/O routine */ + if ((*dset_info[i].io_ops.multi_read)(&io_info, &dset_info[i]) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + + /* Reset metadata tagging */ + H5AC_tag(prev_tag, NULL); + } + + /* Make final multi dataset selection I/O call if we are using both + * features - in this case the multi_read callbacks did not perform the + * actual I/O */ + H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t) + if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info)) + if (H5F_shared_select_read(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added, + io_info.mem_spaces, io_info.file_spaces, io_info.addrs, + io_info.element_sizes, io_info.rbufs) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "selection read failed") + } done: /* Shut down the I/O op information */ - if (io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") - if (fm) - fm = H5FL_FREE(H5D_chunk_map_t, fm); + for (i = 0; i < io_op_init; i++) + if (!dset_info[i].skip_io && dset_info[i].layout_ops.io_term && + (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") /* Shut down datatype info for operation */ - if (type_info_init && H5D__typeinfo_term(&type_info) < 0) + if (H5D__typeinfo_term(&io_info, type_info_init) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") - /* discard projected mem space if it was created */ - if (NULL != projected_mem_space) - if (H5S_close(projected_mem_space) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace") + /* Discard projected mem spaces and restore originals */ + if (orig_mem_space) { + for (i = 0; i < count; i++) + if (orig_mem_space[i]) { + if (H5S_close(dset_info[i].mem_space) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, + "unable to shut down projected memory dataspace") + dset_info[i].mem_space = orig_mem_space[i]; + } + + /* Free orig_mem_space array if it was allocated */ + if (orig_mem_space != &orig_mem_space_local) + H5MM_free(orig_mem_space); + } + + /* Free global piece array */ + H5MM_xfree(io_info.sel_pieces); + + /* Free selection I/O arrays */ + H5MM_xfree(io_info.mem_spaces); + H5MM_xfree(io_info.file_spaces); + H5MM_xfree(io_info.addrs); + H5MM_xfree(io_info.element_sizes); + H5MM_xfree(io_info.rbufs); - FUNC_LEAVE_NOAPI_TAG(ret_value) + /* Free store array if it was allocated */ + if (store != &store_local) + H5MM_free(store); + + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__read() */ /*------------------------------------------------------------------------- * Function: H5D__write * - * Purpose: Writes (part of) a DATASET to a file from application memory - * BUF. See H5Dwrite() for complete details. + * Purpose: Writes multiple (part of) DATASETs to a file from application + * memory BUFs. See H5Dwrite_multi() for complete details. * - * Return: Non-negative on success/Negative on failure + * This was referred from H5D__write for multi-dset work. * - * Programmer: Robb Matzke - * Thursday, December 4, 1997 + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t -H5D__write(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space, const void *buf) +H5D__write(size_t count, H5D_dset_io_info_t *dset_info) { - H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */ - H5D_io_info_t io_info; /* Dataset I/O info */ - H5D_type_info_t type_info; /* Datatype info for operation */ - H5D_layout_t layout_type; /* Dataset's layout type (contig, chunked, compact, etc.) */ - hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */ - hbool_t should_alloc_space = FALSE; /* Whether or not to initialize dataset's storage */ - H5S_t *projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */ - /* projection of the supplied mem_space to a new */ - /* dataspace with rank equal to that of */ - /* file_space. */ - /* */ - /* This field is only used if */ - /* H5S_select_shape_same() returns TRUE when */ - /* comparing the mem_space and the data_space, */ - /* and the mem_space have different rank. */ - /* */ - /* Note that if this variable is used, the */ - /* projected mem space must be discarded at the */ - /* end of the function to avoid a memory leak. */ - H5D_storage_t store; /* union of EFL and chunk pointer in file space */ - hsize_t nelmts; /* total number of elmts */ - hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ - char fake_char; /* Temporary variable for NULL buffer pointers */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_PACKAGE_TAG(dataset->oloc.addr) + H5D_io_info_t io_info; /* Dataset I/O info for multi dsets */ + size_t type_info_init = 0; /* Number of datatype info structs that have been initialized */ + H5S_t *orig_mem_space_local; /* Local buffer for orig_mem_space */ + H5S_t **orig_mem_space = NULL; /* If not NULL, ptr to an array of dataspaces */ + /* containing the original memory spaces contained */ + /* in dset_info. This is needed in order to */ + /* restore the original state of dset_info if we */ + /* replaced any mem spaces with equivalents */ + /* projected to a rank equal to that of file_space. */ + /* */ + /* This field is only used if */ + /* H5S_select_shape_same() returns TRUE when */ + /* comparing at least one mem_space and data_space, */ + /* and the mem_space has a different rank. */ + /* */ + /* Note that this is a temporary variable - the */ + /* projected memory space is stored in dset_info, */ + /* and will be freed when that structure is */ + /* freed. */ + H5D_storage_t store_local; /* Local buffer for store */ + H5D_storage_t *store = &store_local; /* Union of EFL and chunk pointer in file space */ + size_t io_op_init = 0; /* Number I/O ops that have been initialized */ + size_t i; /* Local index variable */ + char fake_char; /* Temporary variable for NULL buffer pointers */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Init io_info */ + if (H5D__ioinfo_init(count, dset_info, &io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + io_info.op_type = H5D_IO_OP_WRITE; - /* check args */ - HDassert(dataset && dataset->oloc.file); - HDassert(file_space); - HDassert(mem_space); + /* Allocate store buffer if necessary */ + if (count > 1) + if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer") - layout_type = dataset->shared->layout.type; + /* iterate over all dsets and construct I/O information */ + for (i = 0; i < count; i++) { + hbool_t should_alloc_space = FALSE; /* Whether or not to initialize dataset's storage */ + haddr_t prev_tag = HADDR_UNDEF; - /* All filters in the DCPL must have encoding enabled. */ - if (!dataset->shared->checked_filters) { - if (H5Z_can_apply(dataset->shared->dcpl_id, dataset->shared->type_id) < 0) - HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters") + /* check args */ + if (NULL == dset_info[i].dset) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + if (NULL == dset_info[i].dset->oloc.file) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") - dataset->shared->checked_filters = TRUE; - } /* end if */ + /* set metadata tagging with dset oheader addr */ + H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag); + + /* All filters in the DCPL must have encoding enabled. */ + if (!dset_info[i].dset->shared->checked_filters) { + if (H5Z_can_apply(dset_info[i].dset->shared->dcpl_id, dset_info[i].dset->shared->type_id) < 0) + HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters") - /* Check if we are allowed to write to this file */ - if (0 == (H5F_INTENT(dataset->oloc.file) & H5F_ACC_RDWR)) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file") + dset_info[i].dset->shared->checked_filters = TRUE; + } /* end if */ + + /* Check if we are allowed to write to this file */ + if (0 == (H5F_INTENT(dset_info[i].dset->oloc.file) & H5F_ACC_RDWR)) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file") - /* Set up datatype info for operation */ - if (H5D__typeinfo_init(dataset, mem_type_id, TRUE, &type_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") - type_info_init = TRUE; + /* Set up datatype info for operation */ + if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") + type_info_init++; - /* Various MPI based checks */ + /* Various MPI based checks */ #ifdef H5_HAVE_PARALLEL - if (H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI)) { - /* If MPI based VFD is used, no VL or region reference datatype support yet. */ - /* This is because they use the global heap in the file and we don't */ - /* support parallel access of that yet */ - if (H5T_is_vl_storage(type_info.mem_type) > 0) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, - "Parallel IO does not support writing VL or region reference datatypes yet") - } /* end if */ - else { - H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ + if (H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI)) { + /* If MPI based VFD is used, no VL or region reference datatype support yet. */ + /* This is because they use the global heap in the file and we don't */ + /* support parallel access of that yet */ + if (H5T_is_vl_storage(dset_info[i].type_info.mem_type) > 0) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, + "Parallel IO does not support writing VL or region reference datatypes yet") + } /* end if */ + else { + H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ + + /* Get I/O transfer mode */ + if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode") + + /* Collective access is not permissible without a MPI based VFD */ + if (io_xfer_mode == H5FD_MPIO_COLLECTIVE) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only") + } /* end else */ +#endif /*H5_HAVE_PARALLEL*/ + + /* Make certain that the number of elements in each selection is the same, and cache nelmts in + * dset_info */ + dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space); + if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "src and dest dataspaces have different number of elements selected") + + /* Check for a NULL buffer */ + if (NULL == dset_info[i].buf.cvp) { + /* Check for any elements selected (which is invalid) */ + if (dset_info[i].nelmts > 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") + + /* If the buffer is nil, and 0 element is selected, make a fake buffer. + * This is for some MPI package like ChaMPIon on NCSA's tungsten which + * doesn't support this feature. + */ + dset_info[i].buf.cvp = &fake_char; + } /* end if */ - /* Get I/O transfer mode */ - if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode") + /* Make sure that both selections have their extents set */ + if (!(H5S_has_extent(dset_info[i].file_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") + if (!(H5S_has_extent(dset_info[i].mem_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") + + /* H5S_select_shape_same() has been modified to accept topologically + * identical selections with different rank as having the same shape + * (if the most rapidly changing coordinates match up), but the I/O + * code still has difficulties with the notion. + * + * To solve this, we check to see if H5S_select_shape_same() returns + * true, and if the ranks of the mem and file spaces are different. + * If they are, construct a new mem space that is equivalent to the + * old mem space, and use that instead. + * + * Note that in general, this requires us to touch up the memory buffer + * as well. + */ + if (dset_info[i].nelmts > 0 && + TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) && + H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) { + ptrdiff_t buf_adj = 0; + + /* Allocate original memory space buffer if necessary */ + if (!orig_mem_space) { + if (count > 1) { + /* Allocate buffer */ + if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, + "couldn't allocate original memory space array buffer") + } + else + /* Use local buffer */ + orig_mem_space = &orig_mem_space_local; + } - /* Collective access is not permissible without a MPI based VFD */ - if (io_xfer_mode == H5FD_MPIO_COLLECTIVE) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only") - } /* end else */ -#endif /*H5_HAVE_PARALLEL*/ + /* Save original memory space */ + orig_mem_space[i] = dset_info[i].mem_space; + dset_info[i].mem_space = NULL; + + /* Attempt to construct projected dataspace for memory dataspace */ + if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space, + (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space), + dset_info[i].type_info.src_type_size, &buf_adj) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") + HDassert(dset_info[i].mem_space); + + /* Adjust the buffer by the given amount */ + dset_info[i].buf.cvp = (const void *)(((const uint8_t *)dset_info[i].buf.cvp) + buf_adj); + } /* end if */ - /* Make certain that the number of elements in each selection is the same */ - nelmts = H5S_GET_SELECT_NPOINTS(mem_space); - if (nelmts != H5S_GET_SELECT_NPOINTS(file_space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "src and dest dataspaces have different number of elements selected") - - /* Check for a NULL buffer */ - if (NULL == buf) { - /* Check for any elements selected (which is invalid) */ - if (nelmts > 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") - - /* If the buffer is nil, and 0 element is selected, make a fake buffer. - * This is for some MPI package like ChaMPIon on NCSA's tungsten which - * doesn't support this feature. + /* Retrieve dataset properties */ + /* */ + + /* Set up I/O operation */ + if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation") + + /* Allocate dataspace and initialize it if it hasn't been. */ + should_alloc_space = dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 && + !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)( + &dset_info[i].dset->shared->layout.storage); + + /* + * If not using an MPI-based VFD, we only need to allocate + * and initialize storage if there's a selection in the + * dataset's dataspace. Otherwise, we always need to participate + * in the storage allocation since this may use collective + * operations and we will hang if we don't participate. */ - buf = &fake_char; - } /* end if */ + if (!H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI)) + should_alloc_space = should_alloc_space && (dset_info[i].nelmts > 0); - /* Make sure that both selections have their extents set */ - if (!(H5S_has_extent(file_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") - if (!(H5S_has_extent(mem_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") + if (should_alloc_space) { + hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */ + hbool_t full_overwrite; /* Whether we are over-writing all the elements */ - /* H5S_select_shape_same() has been modified to accept topologically - * identical selections with different rank as having the same shape - * (if the most rapidly changing coordinates match up), but the I/O - * code still has difficulties with the notion. - * - * To solve this, we check to see if H5S_select_shape_same() returns - * true, and if the ranks of the mem and file spaces are different. - * If the are, construct a new mem space that is equivalent to the - * old mem space, and use that instead. - * - * Note that in general, this requires us to touch up the memory buffer - * as well. - */ - if (nelmts > 0 && TRUE == H5S_SELECT_SHAPE_SAME(mem_space, file_space) && - H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) { - ptrdiff_t buf_adj = 0; - - /* Attempt to construct projected dataspace for memory dataspace */ - if (H5S_select_construct_projection(mem_space, &projected_mem_space, - (unsigned)H5S_GET_EXTENT_NDIMS(file_space), - type_info.src_type_size, &buf_adj) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") - HDassert(projected_mem_space); - - /* Adjust the buffer by the given amount */ - buf = (const void *)(((const uint8_t *)buf) + buf_adj); - - /* Switch to using projected memory dataspace & adjusted buffer */ - mem_space = projected_mem_space; - } /* end if */ + /* Get the number of elements in file dataset's dataspace */ + if ((file_nelmts = H5S_GET_EXTENT_NPOINTS(dset_info[i].file_space)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, + "can't retrieve number of elements in file dataset") - /* Retrieve dataset properties */ - /* */ + /* Always allow fill values to be written if the dataset has a VL datatype */ + if (H5T_detect_class(dset_info[i].dset->shared->type, H5T_VLEN, FALSE)) + full_overwrite = FALSE; + else + full_overwrite = (hbool_t)((hsize_t)file_nelmts == dset_info[i].nelmts ? TRUE : FALSE); - /* Set up I/O operation */ - io_info.op_type = H5D_IO_OP_WRITE; - io_info.u.wbuf = buf; - if (H5D__ioinfo_init(dataset, &type_info, &store, &io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation") + /* Allocate storage */ + if (H5D__alloc_storage(dset_info[i].dset, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage") + } /* end if */ - /* Allocate dataspace and initialize it if it hasn't been. */ - should_alloc_space = dataset->shared->dcpl_cache.efl.nused == 0 && - !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage); + /* Call storage method's I/O initialization routine */ + /* Init io_info.dset_info[] and generate piece_info in skip list */ + if (dset_info[i].layout_ops.io_init && + (*dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + dset_info[i].skip_io = FALSE; + io_op_init++; - /* - * If not using an MPI-based VFD, we only need to allocate - * and initialize storage if there's a selection in the - * dataset's dataspace. Otherwise, we always need to participate - * in the storage allocation since this may use collective - * operations and we will hang if we don't participate. - */ - if (!H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI)) - should_alloc_space = should_alloc_space && (nelmts > 0); - - if (should_alloc_space) { - hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */ - hbool_t full_overwrite; /* Whether we are over-writing all the elements */ - - /* Get the number of elements in file dataset's dataspace */ - if ((file_nelmts = H5S_GET_EXTENT_NPOINTS(file_space)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "can't retrieve number of elements in file dataset") - - /* Always allow fill values to be written if the dataset has a VL datatype */ - if (H5T_detect_class(dataset->shared->type, H5T_VLEN, FALSE)) - full_overwrite = FALSE; - else - full_overwrite = (hbool_t)((hsize_t)file_nelmts == nelmts ? TRUE : FALSE); - - /* Allocate storage */ - if (H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage") - } /* end if */ + /* Reset metadata tagging */ + H5AC_tag(prev_tag, NULL); + } /* end of for loop */ - /* Allocate the chunk map */ - if (H5D_CONTIGUOUS != layout_type && H5D_COMPACT != layout_type) { - if (NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map") - } + HDassert(type_info_init == count); + HDassert(io_op_init == count); - /* Call storage method's I/O initialization routine */ - if (io_info.layout_ops.io_init && - (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") - io_op_init = TRUE; + /* Perform second phase of type info initialization */ + if (H5D__typeinfo_init_phase2(&io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)") #ifdef H5_HAVE_PARALLEL /* Adjust I/O info for any parallel I/O */ - if (H5D__ioinfo_adjust(&io_info, dataset, file_space, mem_space, &type_info) < 0) + if (H5D__ioinfo_adjust(&io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O") #endif /*H5_HAVE_PARALLEL*/ - /* Invoke correct "high level" I/O routine */ - if ((*io_info.io_ops.multi_write)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + /* If multi dataset I/O callback is not provided, perform write IO via + * single-dset path with looping */ + if (io_info.md_io_ops.multi_write_md) { + /* Create sel_pieces array if any pieces are selected */ + if (io_info.piece_count > 0) { + HDassert(!io_info.sel_pieces); + HDassert(io_info.pieces_added == 0); + + /* Allocate sel_pieces array */ + if (NULL == + (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0])))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces") + } + + /* MDIO-specific second phase initialization */ + for (i = 0; i < count; i++) + if (dset_info[i].layout_ops.mdio_init) { + haddr_t prev_tag = HADDR_UNDEF; + + /* set metadata tagging with dset oheader addr */ + H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag); + + /* Make second phase IO init call */ + if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces") + + /* Reset metadata tagging */ + H5AC_tag(prev_tag, NULL); + } + + /* Invoke correct "high level" I/O routine */ + if ((*io_info.md_io_ops.multi_write_md)(&io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + } /* end if */ + else { + haddr_t prev_tag = HADDR_UNDEF; + + if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) { + if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for memory space list") + if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list") + if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for piece address list") + if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for element size list") + if (NULL == (io_info.wbufs = H5MM_malloc(io_info.piece_count * sizeof(const void *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for read buffer list") + } + + /* loop with serial & single-dset write IO path */ + for (i = 0; i < count; i++) { + HDassert(!dset_info[i].skip_io); + + /* set metadata tagging with dset oheader addr */ + H5AC_tag(dset_info->dset->oloc.addr, &prev_tag); + + /* Invoke correct "high level" I/O routine */ + if ((*dset_info[i].io_ops.multi_write)(&io_info, &dset_info[i]) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + + /* Reset metadata tagging */ + H5AC_tag(prev_tag, NULL); + } + + /* Make final multi dataset selection I/O call if we are using both + * features - in this case the multi_write callbacks did not perform the + * actual I/O */ + H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t) + if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info)) + if (H5F_shared_select_write(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added, + io_info.mem_spaces, io_info.file_spaces, io_info.addrs, + io_info.element_sizes, io_info.wbufs) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "selection write failed") + } #ifdef OLD_WAY /* @@ -515,88 +774,138 @@ H5D__write(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_spac done: /* Shut down the I/O op information */ - if (io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") - if (fm) - fm = H5FL_FREE(H5D_chunk_map_t, fm); + for (i = 0; i < io_op_init; i++) { + HDassert(!dset_info[i].skip_io); + if (dset_info[i].layout_ops.io_term && + (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") + } /* Shut down datatype info for operation */ - if (type_info_init && H5D__typeinfo_term(&type_info) < 0) + if (H5D__typeinfo_term(&io_info, type_info_init) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") - /* discard projected mem space if it was created */ - if (NULL != projected_mem_space) - if (H5S_close(projected_mem_space) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace") + /* Discard projected mem spaces and restore originals */ + if (orig_mem_space) { + for (i = 0; i < count; i++) + if (orig_mem_space[i]) { + if (H5S_close(dset_info[i].mem_space) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, + "unable to shut down projected memory dataspace") + dset_info[i].mem_space = orig_mem_space[i]; + } + + /* Free orig_mem_space array if it was allocated */ + if (orig_mem_space != &orig_mem_space_local) + H5MM_free(orig_mem_space); + } + + /* Free global piece array */ + H5MM_xfree(io_info.sel_pieces); - FUNC_LEAVE_NOAPI_TAG(ret_value) -} /* end H5D__write() */ + /* Free store array if it was allocated */ + if (store != &store_local) + H5MM_free(store); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__write */ /*------------------------------------------------------------------------- * Function: H5D__ioinfo_init * - * Purpose: Routine for determining correct I/O operations for - * each I/O action. + * Purpose: General setup for H5D_io_info_t struct * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, September 30, 2004 + *------------------------------------------------------------------------- + */ +static herr_t +H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info) +{ + FUNC_ENTER_PACKAGE_NOERR + + /* check args */ + HDassert(count > 0); + HDassert(dset_info); + HDassert(dset_info[0].dset->oloc.file); + HDassert(io_info); + + /* Zero out struct */ + HDmemset(io_info, 0, sizeof(*io_info)); + + /* Set up simple fields */ + io_info->f_sh = count > 0 ? H5F_SHARED(dset_info[0].dset->oloc.file) : NULL; + io_info->count = count; + + /* Start without multi-dataset I/O ops. If we're not using the collective + * I/O path then we will call the single dataset callbacks in a loop. */ + + /* Use provided dset_info */ + io_info->dsets_info = dset_info; + + /* Start with selection I/O on if the global is on, layout callback will + * turn it off if appropriate */ + io_info->use_select_io = H5_use_selection_io_g; + +#ifdef H5_HAVE_PARALLEL + /* Determine if the file was opened with an MPI VFD */ + if (count > 0) + io_info->using_mpi_vfd = H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI); +#endif /* H5_HAVE_PARALLEL */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D__ioinfo_init() */ + +/*------------------------------------------------------------------------- + * Function: H5D__dset_ioinfo_init + * + * Purpose: Routine for determining correct I/O operations for each I/O action. + * + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t -H5D__ioinfo_init(H5D_t *dset, const H5D_type_info_t *type_info, H5D_storage_t *store, H5D_io_info_t *io_info) +H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store) { FUNC_ENTER_PACKAGE_NOERR /* check args */ HDassert(dset); HDassert(dset->oloc.file); - HDassert(type_info); - HDassert(type_info->tpath); - HDassert(io_info); + HDassert(dset_info->type_info.tpath); /* Set up "normal" I/O fields */ - io_info->dset = dset; - io_info->f_sh = H5F_SHARED(dset->oloc.file); - io_info->store = store; + dset_info->dset = dset; + dset_info->store = store; /* Set I/O operations to initial values */ - io_info->layout_ops = *dset->shared->layout.ops; + dset_info->layout_ops = *dset->shared->layout.ops; /* Set the "high-level" I/O operations for the dataset */ - io_info->io_ops.multi_read = dset->shared->layout.ops->ser_read; - io_info->io_ops.multi_write = dset->shared->layout.ops->ser_write; + dset_info->io_ops.multi_read = dset->shared->layout.ops->ser_read; + dset_info->io_ops.multi_write = dset->shared->layout.ops->ser_write; /* Set the I/O operations for reading/writing single blocks on disk */ - if (type_info->is_xform_noop && type_info->is_conv_noop) { + if (dset_info->type_info.is_xform_noop && dset_info->type_info.is_conv_noop) { /* - * If there is no data transform or type conversion then read directly into - * the application's buffer. This saves at least one mem-to-mem copy. + * If there is no data transform or type conversion then read directly + * into the application's buffer. + * This saves at least one mem-to-mem copy. */ - io_info->io_ops.single_read = H5D__select_read; - io_info->io_ops.single_write = H5D__select_write; + dset_info->io_ops.single_read = H5D__select_read; + dset_info->io_ops.single_write = H5D__select_write; } /* end if */ else { /* * This is the general case (type conversion, usually). */ - io_info->io_ops.single_read = H5D__scatgath_read; - io_info->io_ops.single_write = H5D__scatgath_write; + dset_info->io_ops.single_read = H5D__scatgath_read; + dset_info->io_ops.single_write = H5D__scatgath_write; } /* end else */ - /* Start with selection I/O off, layout callback will turn it on if - * appropriate */ - io_info->use_select_io = FALSE; - -#ifdef H5_HAVE_PARALLEL - /* Determine if the file was opened with an MPI VFD */ - io_info->using_mpi_vfd = H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI); -#endif /* H5_HAVE_PARALLEL */ - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5D__ioinfo_init() */ +} /* end H5D__dset_ioinfo_init() */ /*------------------------------------------------------------------------- * Function: H5D__typeinfo_init @@ -612,8 +921,10 @@ H5D__ioinfo_init(H5D_t *dset, const H5D_type_info_t *type_info, H5D_storage_t *s *------------------------------------------------------------------------- */ static herr_t -H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_type_info_t *type_info) +H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id) { + H5D_type_info_t *type_info; + const H5D_t *dset; const H5T_t *src_type; /* Source datatype */ const H5T_t *dst_type; /* Destination datatype */ H5Z_data_xform_t *data_transform; /* Data transform info */ @@ -622,7 +933,12 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t FUNC_ENTER_PACKAGE /* check args */ - HDassert(type_info); + HDassert(io_info); + HDassert(dset_info); + + /* Set convenience pointers */ + type_info = &dset_info->type_info; + dset = dset_info->dset; HDassert(dset); /* Patch the top level file pointer for dt->shared->u.vlen.f if needed */ @@ -637,7 +953,7 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") type_info->dset_type = dset->shared->type; - if (do_write) { + if (io_info->op_type == H5D_IO_OP_WRITE) { src_type = type_info->mem_type; dst_type = dset->shared->type; type_info->src_type_id = mem_type_id; @@ -667,7 +983,6 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t /* Precompute some useful information */ type_info->src_type_size = H5T_get_size(src_type); type_info->dst_type_size = H5T_get_size(dst_type); - type_info->max_type_size = MAX(type_info->src_type_size, type_info->dst_type_size); type_info->is_conv_noop = H5T_path_noop(type_info->tpath); type_info->is_xform_noop = H5Z_xform_noop(data_transform); if (type_info->is_xform_noop && type_info->is_conv_noop) { @@ -675,27 +990,21 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t type_info->need_bkg = H5T_BKG_NO; } /* end if */ else { - void *tconv_buf; /* Temporary conversion buffer pointer */ - void *bkgr_buf; /* Background conversion buffer pointer */ - size_t max_temp_buf; /* Maximum temporary buffer size */ H5T_bkg_t bkgr_buf_type; /* Background buffer type */ - size_t target_size; /* Desired buffer size */ /* Get info from API context */ - if (H5CX_get_max_temp_buf(&max_temp_buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size") - if (H5CX_get_tconv_buf(&tconv_buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve temp. conversion buffer pointer") - if (H5CX_get_bkgr_buf(&bkgr_buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background conversion buffer pointer") if (H5CX_get_bkgr_buf_type(&bkgr_buf_type) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background buffer type") /* Check if the datatypes are compound subsets of one another */ type_info->cmpd_subset = H5T_path_compound_subset(type_info->tpath); + /* Update io_info->max_type_size */ + io_info->max_type_size = + MAX3(io_info->max_type_size, type_info->src_type_size, type_info->dst_type_size); + /* Check if we need a background buffer */ - if (do_write && H5T_detect_class(dset->shared->type, H5T_VLEN, FALSE)) + if ((io_info->op_type == H5D_IO_OP_WRITE) && H5T_detect_class(dset->shared->type, H5T_VLEN, FALSE)) type_info->need_bkg = H5T_BKG_YES; else { H5T_bkg_t path_bkg; /* Type conversion's background info */ @@ -708,13 +1017,54 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t else type_info->need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/ } /* end else */ + } /* end else */ - /* Set up datatype conversion/background buffers */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__typeinfo_init() */ + +/*------------------------------------------------------------------------- + * Function: H5D__typeinfo_init_phase2 + * + * Purpose: Finish initializing type info for all datasets after + * calculating the max type size across all datasets. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__typeinfo_init_phase2(H5D_io_info_t *io_info) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* check args */ + HDassert(io_info); + + /* Check if we need to allocate a shared type conversion buffer */ + if (io_info->max_type_size) { + void *tconv_buf; /* Temporary conversion buffer pointer */ + void *bkgr_buf; /* Background conversion buffer pointer */ + size_t max_temp_buf; /* Maximum temporary buffer size */ + size_t target_size; /* Desired buffer size */ + size_t i; /* Local index variable */ + + /* Get info from API context */ + if (H5CX_get_max_temp_buf(&max_temp_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size") + if (H5CX_get_tconv_buf(&tconv_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve temp. conversion buffer pointer") + if (H5CX_get_bkgr_buf(&bkgr_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background conversion buffer pointer") + /* Set up datatype conversion/background buffers */ target_size = max_temp_buf; - /* If the buffer is too small to hold even one element, try to make it bigger */ - if (target_size < type_info->max_type_size) { + /* If the buffer is too small to hold even one element (in the dataset with the largest , try to make + * it bigger */ + if (target_size < io_info->max_type_size) { hbool_t default_buffer_info; /* Whether the buffer information are the defaults */ /* Detect if we have all default settings for buffers */ @@ -724,50 +1074,64 @@ H5D__typeinfo_init(const H5D_t *dset, hid_t mem_type_id, hbool_t do_write, H5D_t /* Check if we are using the default buffer info */ if (default_buffer_info) /* OK to get bigger for library default settings */ - target_size = type_info->max_type_size; + target_size = io_info->max_type_size; else /* Don't get bigger than the application has requested */ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small") } /* end if */ - /* Compute the number of elements that will fit into buffer */ - type_info->request_nelmts = target_size / type_info->max_type_size; - - /* Sanity check elements in temporary buffer */ - if (type_info->request_nelmts == 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small") - /* Get a temporary buffer for type conversion unless the app has already * supplied one through the xfer properties. Instead of allocating a - * buffer which is the exact size, we allocate the target size. - */ - if (NULL == (type_info->tconv_buf = (uint8_t *)tconv_buf)) { + * buffer which is the exact size, we allocate the target size. This + * buffer is shared among all datasets in the operation, unlike for the + * background buffer, where each dataset gets its own. */ + if (NULL == (io_info->tconv_buf = (uint8_t *)tconv_buf)) { /* Allocate temporary buffer */ - if (NULL == (type_info->tconv_buf = H5FL_BLK_CALLOC(type_conv, target_size))) + if (NULL == (io_info->tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion") - type_info->tconv_buf_allocated = TRUE; - } /* end if */ - if (type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)bkgr_buf)) { - size_t bkg_size; /* Desired background buffer size */ - - /* Compute the background buffer size */ - /* (don't try to use buffers smaller than the default size) */ - bkg_size = type_info->request_nelmts * type_info->dst_type_size; - if (bkg_size < max_temp_buf) - bkg_size = max_temp_buf; - - /* Allocate background buffer */ - /* (Need calloc()-like call since memory needs to be initialized) */ - if (NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "memory allocation failed for background conversion") - type_info->bkg_buf_allocated = TRUE; + io_info->tconv_buf_allocated = TRUE; } /* end if */ - } /* end else */ + + /* Don't use API provided background buffer if there's more than one dataset, since each + * dataset needs its own */ + if (io_info->count > 1) + bkgr_buf = NULL; + + /* Iterate over datasets */ + for (i = 0; i < io_info->count; i++) { + H5D_type_info_t *type_info = &io_info->dsets_info[i].type_info; + + /* Compute the number of elements that will fit into buffer */ + type_info->request_nelmts = target_size / MAX(type_info->src_type_size, type_info->dst_type_size); + ; + + /* Sanity check elements in temporary buffer */ + if (type_info->request_nelmts == 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small") + + /* Allocate background buffer if necessary */ + if (type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)bkgr_buf)) { + size_t bkg_size; /* Desired background buffer size */ + + /* Compute the background buffer size */ + /* (don't try to use buffers smaller than the default size) */ + bkg_size = type_info->request_nelmts * type_info->dst_type_size; + if (bkg_size < max_temp_buf) + bkg_size = max_temp_buf; + + /* Allocate background buffer */ + /* (Need calloc()-like call since memory needs to be initialized) */ + if (NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed for background conversion") + type_info->bkg_buf_allocated = TRUE; + } /* end if */ + } + } done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__typeinfo_init() */ +} /* end H5D__typeinfo_init_phase2() */ #ifdef H5_HAVE_PARALLEL @@ -776,30 +1140,28 @@ done: * * Purpose: Adjust operation's I/O info for any parallel I/O * - * Return: Non-negative on success/Negative on failure + * This was derived from H5D__ioinfo_adjust for multi-dset work. * - * Programmer: Quincey Koziol - * Thursday, March 27, 2008 + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t -H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_space, const H5S_t *mem_space, - const H5D_type_info_t *type_info) +H5D__ioinfo_adjust(H5D_io_info_t *io_info) { + H5D_t *dset0; /* only the first dset , also for single dsets case */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* check args */ - HDassert(dset); - HDassert(dset->oloc.file); - HDassert(mem_space); - HDassert(file_space); - HDassert(type_info); - HDassert(type_info->tpath); HDassert(io_info); + /* check the first dset, should exist either single or multi dset cases */ + HDassert(io_info->dsets_info[0].dset); + dset0 = io_info->dsets_info[0].dset; + HDassert(dset0->oloc.file); + /* Reset the actual io mode properties to the default values in case * the DXPL (if it's non-default) was previously used in a collective * I/O operation. @@ -819,11 +1181,11 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode") /* Get MPI communicator */ - if (MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset->oloc.file))) + if (MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset0->oloc.file))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator") /* Check if we can set direct MPI-IO read/write functions */ - if ((opt = H5D__mpio_opt_possible(io_info, file_space, mem_space, type_info)) < 0) + if ((opt = H5D__mpio_opt_possible(io_info)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace ") /* Check if we can use the optimized parallel I/O routines */ @@ -833,10 +1195,10 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_ * handle collective I/O */ /* Check for selection/vector support in file driver? -NAF */ if (!io_info->use_select_io) { - io_info->io_ops.multi_read = dset->shared->layout.ops->par_read; - io_info->io_ops.multi_write = dset->shared->layout.ops->par_write; - io_info->io_ops.single_read = H5D__mpio_select_read; - io_info->io_ops.single_write = H5D__mpio_select_write; + io_info->md_io_ops.multi_read_md = H5D__collective_read; + io_info->md_io_ops.multi_write_md = H5D__collective_write; + io_info->md_io_ops.single_read_md = H5D__mpio_select_read; + io_info->md_io_ops.single_write_md = H5D__mpio_select_write; } /* end if */ } /* end if */ else { @@ -857,28 +1219,38 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, const H5S_t *file_ * with multiple ranks involved; otherwise, there will be metadata * inconsistencies in the file. */ - if (io_info->op_type == H5D_IO_OP_WRITE && io_info->dset->shared->dcpl_cache.pline.nused > 0) { - int comm_size = 0; - - /* Retrieve size of MPI communicator used for file */ - if ((comm_size = H5F_shared_mpi_get_size(io_info->f_sh)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MPI communicator size") - - if (comm_size > 1) { - char local_no_coll_cause_string[512]; - char global_no_coll_cause_string[512]; - - if (H5D__mpio_get_no_coll_cause_strings(local_no_coll_cause_string, 512, - global_no_coll_cause_string, 512) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, - "can't get reasons for breaking collective I/O") - - HGOTO_ERROR(H5E_IO, H5E_NO_INDEPENDENT, FAIL, - "Can't perform independent write with filters in pipeline.\n" - " The following caused a break from collective I/O:\n" - " Local causes: %s\n" - " Global causes: %s", - local_no_coll_cause_string, global_no_coll_cause_string); + if (io_info->op_type == H5D_IO_OP_WRITE) { + size_t i; + + /* Check all datasets for filters */ + for (i = 0; i < io_info->count; i++) + if (io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused > 0) + break; + + /* If the above loop didn't complete at least one dataset has a filter */ + if (i < io_info->count) { + int comm_size = 0; + + /* Retrieve size of MPI communicator used for file */ + if ((comm_size = H5F_shared_mpi_get_size(io_info->f_sh)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MPI communicator size") + + if (comm_size > 1) { + char local_no_coll_cause_string[512]; + char global_no_coll_cause_string[512]; + + if (H5D__mpio_get_no_coll_cause_strings(local_no_coll_cause_string, 512, + global_no_coll_cause_string, 512) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, + "can't get reasons for breaking collective I/O") + + HGOTO_ERROR(H5E_IO, H5E_NO_INDEPENDENT, FAIL, + "Can't perform independent write with filters in pipeline.\n" + " The following caused a break from collective I/O:\n" + " Local causes: %s\n" + " Global causes: %s", + local_no_coll_cause_string, global_no_coll_cause_string); + } } } @@ -899,31 +1271,34 @@ done: #endif /* H5_HAVE_PARALLEL */ /*------------------------------------------------------------------------- - * Function: H5D__typeinfo_term + * Function: H5D__typeinfo_term * - * Purpose: Common logic for terminating a type info object + * Purpose: Common logic for terminating a type info object * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, March 6, 2008 + * Programmer: Quincey Koziol + * Thursday, March 6, 2008 * *------------------------------------------------------------------------- */ static herr_t -H5D__typeinfo_term(const H5D_type_info_t *type_info) +H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init) { + size_t i; + FUNC_ENTER_PACKAGE_NOERR /* Check for releasing datatype conversion & background buffers */ - if (type_info->tconv_buf_allocated) { - HDassert(type_info->tconv_buf); - (void)H5FL_BLK_FREE(type_conv, type_info->tconv_buf); - } /* end if */ - if (type_info->bkg_buf_allocated) { - HDassert(type_info->bkg_buf); - (void)H5FL_BLK_FREE(type_conv, type_info->bkg_buf); + if (io_info->tconv_buf_allocated) { + HDassert(io_info->tconv_buf); + (void)H5FL_BLK_FREE(type_conv, io_info->tconv_buf); } /* end if */ + for (i = 0; i < type_info_init; i++) + if (io_info->dsets_info[i].type_info.bkg_buf_allocated) { + HDassert(io_info->dsets_info[i].type_info.bkg_buf); + (void)H5FL_BLK_FREE(type_conv, io_info->dsets_info[i].type_info.bkg_buf); + } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__typeinfo_term() */ diff --git a/src/H5Dlayout.c b/src/H5Dlayout.c index fd7e5b9..95d29c1 100644 --- a/src/H5Dlayout.c +++ b/src/H5Dlayout.c @@ -489,14 +489,9 @@ H5D__layout_oh_create(H5F_t *file, H5O_t *oh, H5D_t *dset, hid_t dapl_id) * Allocate storage if space allocate time is early; otherwise delay * allocation until later. */ - if (fill_prop->alloc_time == H5D_ALLOC_TIME_EARLY) { - H5D_io_info_t io_info; - - io_info.dset = dset; - - if (H5D__alloc_storage(&io_info, H5D_ALLOC_CREATE, FALSE, NULL) < 0) + if (fill_prop->alloc_time == H5D_ALLOC_TIME_EARLY) + if (H5D__alloc_storage(dset, H5D_ALLOC_CREATE, FALSE, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage") - } /* Update external storage message, if it's used */ if (dset->shared->dcpl_cache.efl.nused > 0) { diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index 17ae0e5..3bddf0b 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -55,12 +55,15 @@ #define H5D_MULTI_CHUNK_IO 1 #define H5D_ONE_LINK_CHUNK_IO_MORE_OPT 2 #define H5D_MULTI_CHUNK_IO_MORE_OPT 3 +#define H5D_NO_IO 4 /***** Macros for One linked collective IO case. *****/ /* The default value to do one linked collective IO for all chunks. - If the average number of chunks per process is greater than this value, - the library will create an MPI derived datatype to link all chunks to do collective IO. - The user can set this value through an API. */ + * If the average number of chunks per process is greater than this + * value, the library will create an MPI derived datatype to link all + * chunks to do collective IO. The user can set this value through an + * API. + */ /* Macros to represent options on how to obtain chunk address for one linked-chunk IO case */ #define H5D_OBTAIN_ONE_CHUNK_ADDR_IND 0 @@ -71,10 +74,10 @@ #define H5D_ALL_CHUNK_ADDR_THRES_COL_NUM 10000 /***** Macros for multi-chunk collective IO case. *****/ -/* The default value of the threshold to do collective IO for this chunk. - If the average number of processes per chunk is greater than the default value, - collective IO is done for this chunk. -*/ +/* The default value of the threshold to do collective IO for this + * chunk. If the average number of processes per chunk is greater + * than the default value, collective IO is done for this chunk. + */ /* Macros to represent different IO modes(NONE, Independent or collective)for multiple chunk IO case */ #define H5D_CHUNK_IO_MODE_COL 1 @@ -107,12 +110,12 @@ * structure, given a pointer to a H5D_io_info_t * structure */ -#define H5D_MPIO_INIT_CHUNK_IDX_INFO(index_info, io_info_ptr) \ +#define H5D_MPIO_INIT_CHUNK_IDX_INFO(index_info, dset) \ do { \ - index_info.f = (io_info_ptr)->dset->oloc.file; \ - index_info.pline = &((io_info_ptr)->dset->shared->dcpl_cache.pline); \ - index_info.layout = &((io_info_ptr)->dset->shared->layout.u.chunk); \ - index_info.storage = &((io_info_ptr)->dset->shared->layout.storage.u.chunk); \ + index_info.f = (dset)->oloc.file; \ + index_info.pline = &((dset)->shared->dcpl_cache.pline); \ + index_info.layout = &((dset)->shared->layout.u.chunk); \ + index_info.storage = &((dset)->shared->layout.storage.u.chunk); \ } while (0) /* @@ -130,10 +133,12 @@ /* Local Typedefs */ /******************/ -/* Combine chunk address and chunk info into a struct for better performance. */ +/* Combine chunk/piece address and chunk/piece info into a struct for + * better performance. */ typedef struct H5D_chunk_addr_info_t { - haddr_t chunk_addr; - H5D_chunk_info_t chunk_info; + /* piece for multi-dset */ + haddr_t piece_addr; + H5D_piece_info_t piece_info; } H5D_chunk_addr_info_t; /* Rank 0 Bcast values */ @@ -187,7 +192,7 @@ typedef struct H5D_chunk_index_info_t { * need_insert - A flag which determines whether or not a chunk needs to be re-inserted into * the chunk index after the write operation. * - * chunk_info - A pointer to the chunk's H5D_chunk_info_t structure, which contains useful + * chunk_info - A pointer to the chunk's H5D_piece_info_t structure, which contains useful * information like the dataspaces containing the selection in the chunk. * * chunk_current - The address in the file and size of this chunk before the filtering @@ -241,7 +246,7 @@ typedef struct H5D_chunk_index_info_t { typedef struct H5D_filtered_collective_io_info_t { H5D_chunk_index_info_t index_info; - H5D_chunk_info_t *chunk_info; + H5D_piece_info_t *chunk_info; H5F_block_t chunk_current; H5F_block_t chunk_new; hbool_t need_read; @@ -281,65 +286,57 @@ typedef struct H5D_chunk_insert_info_t { /********************/ /* Local Prototypes */ /********************/ -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, int mpi_rank, int mpi_size); -static herr_t H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, H5D_chunk_map_t *fm, +static herr_t H5D__piece_io(H5D_io_info_t *io_info); +static herr_t H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, + int mpi_rank, int mpi_size); +static herr_t H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, int mpi_rank, int mpi_size); -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, int mpi_rank, int mpi_size); -static herr_t H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - H5D_chunk_map_t *fm, int mpi_rank, int mpi_size); -static herr_t H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, +static herr_t H5D__link_piece_collective_io(H5D_io_info_t *io_info, int mpi_rank); +static herr_t H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, + int mpi_rank, int mpi_size); +static herr_t H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_dset_io_info_t *di, H5S_t *file_space, H5S_t *mem_space); -static herr_t H5D__final_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_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, int mpi_rank, - int mpi_size); -static herr_t H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assign_io_mode[], +static herr_t H5D__final_collective_io(H5D_io_info_t *io_info, hsize_t mpi_buf_count, + MPI_Datatype mpi_file_type, MPI_Datatype mpi_buf_type); +static herr_t H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_dset_io_info_t *di, uint8_t assign_io_mode[], haddr_t chunk_addr[], int mpi_rank, int mpi_size); -static herr_t H5D__mpio_get_sum_chunk(const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, - int *sum_chunkf); +static herr_t H5D__mpio_get_sum_chunk(const H5D_io_info_t *io_info, int *sum_chunkf); +static herr_t H5D__mpio_get_sum_chunk_dset(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + int *sum_chunkf); static herr_t H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, - const H5D_chunk_map_t *fm, + const H5D_dset_io_info_t *di, H5D_filtered_collective_io_info_t **chunk_list, size_t *num_entries, int mpi_rank); static herr_t H5D__mpio_redistribute_shared_chunks(H5D_filtered_collective_io_info_t *chunk_list, size_t chunk_list_num_entries, - const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, - int mpi_rank, int mpi_size, + const H5D_io_info_t *io_info, int mpi_rank, int mpi_size, size_t **rank_chunks_assigned_map); static herr_t H5D__mpio_redistribute_shared_chunks_int(H5D_filtered_collective_io_info_t *chunk_list, - size_t *num_chunks_assigned_map, - hbool_t all_ranks_involved, - const H5D_io_info_t *io_info, - const H5D_chunk_map_t *fm, int mpi_rank, int mpi_size); + size_t *num_chunks_assigned_map, + hbool_t all_ranks_involved, + const H5D_io_info_t *io_info, int mpi_rank, + int mpi_size); static herr_t H5D__mpio_share_chunk_modification_data(H5D_filtered_collective_io_info_t *chunk_list, size_t *chunk_list_num_entries, H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, int mpi_rank, + H5D_dset_io_info_t *dset_info, int mpi_rank, int mpi_size, H5D_filtered_collective_io_info_t **chunk_hash_table, unsigned char ***chunk_msg_bufs, int *chunk_msg_bufs_len); static herr_t H5D__mpio_collective_filtered_chunk_common_io(H5D_filtered_collective_io_info_t *chunk_list, - size_t chunk_list_num_entries, - const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, int mpi_size); + size_t chunk_list_num_entries, + const H5D_io_info_t *io_info, int mpi_size); static herr_t H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chunk_list, - size_t chunk_list_num_entries, - const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, int mpi_rank, + size_t chunk_list_num_entries, + const H5D_io_info_t *io_info, + const H5D_dset_io_info_t *di, int mpi_rank, int mpi_size); static herr_t H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *chunk_list, size_t chunk_list_num_entries, H5D_filtered_collective_io_info_t *chunk_hash_table, unsigned char **chunk_msg_bufs, int chunk_msg_bufs_len, const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, int mpi_rank, + const H5D_dset_io_info_t *di, int mpi_rank, int mpi_size); static herr_t H5D__mpio_collective_filtered_chunk_reallocate(H5D_filtered_collective_io_info_t *chunk_list, size_t chunk_list_num_entries, @@ -348,9 +345,9 @@ static herr_t H5D__mpio_collective_filtered_chunk_reallocate(H5D_filtered_collec H5D_chk_idx_info_t *idx_info, int mpi_rank, int mpi_size); static herr_t H5D__mpio_collective_filtered_chunk_reinsert(H5D_filtered_collective_io_info_t *chunk_list, - size_t chunk_list_num_entries, - size_t *num_chunks_assigned_map, - H5D_io_info_t *io_info, + size_t chunk_list_num_entries, + size_t *num_chunks_assigned_map, + H5D_io_info_t *io_info, H5D_dset_io_info_t *di, H5D_chk_idx_info_t *idx_info, int mpi_rank, int mpi_size); static herr_t H5D__mpio_get_chunk_redistribute_info_types(MPI_Datatype *contig_type, @@ -366,7 +363,7 @@ static herr_t H5D__mpio_collective_filtered_io_type(H5D_filtered_collective_io_i size_t num_entries, H5D_io_op_type_t op_type, MPI_Datatype *new_mem_type, hbool_t *mem_type_derived, MPI_Datatype *new_file_type, hbool_t *file_type_derived); -static int H5D__cmp_chunk_addr(const void *chunk_addr_info1, const void *chunk_addr_info2); +static int H5D__cmp_piece_addr(const void *chunk_addr_info1, const void *chunk_addr_info2); static int H5D__cmp_filtered_collective_io_info_entry(const void *filtered_collective_io_info_entry1, const void *filtered_collective_io_info_entry2); static int H5D__cmp_chunk_redistribute_info(const void *entry1, const void *entry2); @@ -572,34 +569,40 @@ H5D__mpio_debug_init(void) * Function: H5D__mpio_opt_possible * * Purpose: Checks if an direct I/O transfer is possible between memory and - * the file. + * the file. + * + * This was derived from H5D__mpio_opt_possible for + * multi-dset work. * * Return: Success: Non-negative: TRUE or FALSE * Failure: Negative * - * Programmer: Quincey Koziol - * Wednesday, April 3, 2002 - * *------------------------------------------------------------------------- */ 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) +H5D__mpio_opt_possible(H5D_io_info_t *io_info) { - H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ + H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ + size_t i; + H5D_t *dset; + const H5S_t *file_space; + const H5S_t *mem_space; + H5D_type_info_t *type_info; unsigned local_cause[2] = {0, 0}; /* [0] Local reason(s) for breaking collective mode */ /* [1] Flag if dataset is both: H5S_ALL and small */ unsigned global_cause[2] = {0, 0}; /* Global reason(s) for breaking collective mode */ - htri_t is_vl_storage; /* Whether the dataset's datatype is stored in a variable-length form */ - htri_t ret_value = SUCCEED; /* Return value */ + htri_t is_vl_storage; /* Whether the dataset's datatype is stored in a variable-length form */ + htri_t ret_value = TRUE; /* Return value */ FUNC_ENTER_PACKAGE /* Check args */ HDassert(io_info); - HDassert(mem_space); - HDassert(file_space); - HDassert(type_info); + + for (i = 0; i < io_info->count; i++) { + HDassert(io_info->dsets_info[i].file_space); + HDassert(io_info->dsets_info[i].mem_space); + } /* For independent I/O, get out quickly and don't try to form consensus */ if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0) @@ -608,90 +611,103 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, co if (io_xfer_mode == H5FD_MPIO_INDEPENDENT) local_cause[0] |= H5D_MPIO_SET_INDEPENDENT; - /* Optimized MPI types flag must be set */ - /* (based on 'HDF5_MPI_OPT_TYPES' environment variable) */ - if (!H5FD_mpi_opt_types_g) - local_cause[0] |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; - - /* Don't allow collective operations if datatype conversions need to happen */ - if (!type_info->is_conv_noop) - local_cause[0] |= H5D_MPIO_DATATYPE_CONVERSION; - - /* Don't allow collective operations if data transform operations should occur */ - if (!type_info->is_xform_noop) - local_cause[0] |= H5D_MPIO_DATA_TRANSFORMS; - - /* 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)))) - local_cause[0] |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; - - /* Dataset storage must be contiguous or chunked */ - if (!(io_info->dset->shared->layout.type == H5D_CONTIGUOUS || - io_info->dset->shared->layout.type == H5D_CHUNKED)) - local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; - - /* check if external-file storage is used */ - if (io_info->dset->shared->dcpl_cache.efl.nused > 0) - local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; - - /* 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 (i = 0; i < io_info->count; i++) { + /* Check for skipped I/O */ + if (io_info->dsets_info[i].skip_io) + continue; + + /* Set convenience pointers */ + dset = io_info->dsets_info[i].dset; + file_space = io_info->dsets_info[i].file_space; + mem_space = io_info->dsets_info[i].mem_space; + type_info = &io_info->dsets_info[i].type_info; + + /* Optimized MPI types flag must be set */ + /* (based on 'HDF5_MPI_OPT_TYPES' environment variable) */ + if (!H5FD_mpi_opt_types_g) + local_cause[0] |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; + + /* Don't allow collective operations if datatype conversions need to happen */ + if (!type_info->is_conv_noop) + local_cause[0] |= H5D_MPIO_DATATYPE_CONVERSION; + + /* Don't allow collective operations if data transform operations should occur */ + if (!type_info->is_xform_noop) + local_cause[0] |= H5D_MPIO_DATA_TRANSFORMS; + + /* 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)))) + local_cause[0] |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; + + /* Dataset storage must be contiguous or chunked */ + if (!(dset->shared->layout.type == H5D_CONTIGUOUS || dset->shared->layout.type == H5D_CHUNKED)) + local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + + /* check if external-file storage is used */ + if (dset->shared->dcpl_cache.efl.nused > 0) + local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + + /* 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. + */ #ifndef H5_HAVE_PARALLEL_FILTERED_WRITES - /* Don't allow writes to filtered datasets if the functionality is disabled */ - if (io_info->op_type == H5D_IO_OP_WRITE && io_info->dset->shared->dcpl_cache.pline.nused > 0) - local_cause[0] |= H5D_MPIO_PARALLEL_FILTERED_WRITES_DISABLED; + /* Don't allow writes to filtered datasets if the functionality is disabled */ + if (io_info->op_type == H5D_IO_OP_WRITE && dset->shared->dcpl_cache.pline.nused > 0) + local_cause[0] |= H5D_MPIO_PARALLEL_FILTERED_WRITES_DISABLED; #endif - /* Check if we are able to do a MPI_Bcast of the data from one rank - * instead of having all the processes involved in the collective I/O call. - */ - - /* Check to see if the process is reading the entire dataset */ - if (H5S_GET_SELECT_TYPE(file_space) != H5S_SEL_ALL) - local_cause[1] |= H5D_MPIO_RANK0_NOT_H5S_ALL; - /* Only perform this optimization for contiguous datasets, currently */ - else if (H5D_CONTIGUOUS != io_info->dset->shared->layout.type) - /* Flag to do a MPI_Bcast of the data from one proc instead of - * having all the processes involved in the collective I/O. + /* Check if we are able to do a MPI_Bcast of the data from one rank + * instead of having all the processes involved in the collective I/O call. */ - local_cause[1] |= H5D_MPIO_RANK0_NOT_CONTIGUOUS; - else if ((is_vl_storage = H5T_is_vl_storage(type_info->dset_type)) < 0) - local_cause[0] |= H5D_MPIO_ERROR_WHILE_CHECKING_COLLECTIVE_POSSIBLE; - else if (is_vl_storage) - local_cause[1] |= H5D_MPIO_RANK0_NOT_FIXED_SIZE; - else { - size_t type_size; /* Size of dataset's datatype */ - /* Retrieve the size of the dataset's datatype */ - if (0 == (type_size = H5T_GET_SIZE(type_info->dset_type))) + /* Check to see if the process is reading the entire dataset */ + if (H5S_GET_SELECT_TYPE(file_space) != H5S_SEL_ALL) + local_cause[1] |= H5D_MPIO_RANK0_NOT_H5S_ALL; + /* Only perform this optimization for contiguous datasets, currently */ + else if (H5D_CONTIGUOUS != dset->shared->layout.type) + /* Flag to do a MPI_Bcast of the data from one proc instead of + * having all the processes involved in the collective I/O. + */ + local_cause[1] |= H5D_MPIO_RANK0_NOT_CONTIGUOUS; + else if ((is_vl_storage = H5T_is_vl_storage(type_info->dset_type)) < 0) local_cause[0] |= H5D_MPIO_ERROR_WHILE_CHECKING_COLLECTIVE_POSSIBLE; + else if (is_vl_storage) + local_cause[1] |= H5D_MPIO_RANK0_NOT_FIXED_SIZE; else { - hssize_t snelmts; /* [Signed] # of elements in dataset's dataspace */ + size_t type_size; /* Size of dataset's datatype */ /* Retrieve the size of the dataset's datatype */ - if ((snelmts = H5S_GET_EXTENT_NPOINTS(file_space)) < 0) + if (0 == (type_size = H5T_GET_SIZE(type_info->dset_type))) local_cause[0] |= H5D_MPIO_ERROR_WHILE_CHECKING_COLLECTIVE_POSSIBLE; else { - hsize_t dset_size; + hssize_t snelmts; /* [Signed] # of elements in dataset's dataspace */ - /* Determine dataset size */ - dset_size = ((hsize_t)snelmts) * type_size; + /* Retrieve the size of the dataset's datatype */ + if ((snelmts = H5S_GET_EXTENT_NPOINTS(file_space)) < 0) + local_cause[0] |= H5D_MPIO_ERROR_WHILE_CHECKING_COLLECTIVE_POSSIBLE; + else { + hsize_t dset_size; - /* If the size of the dataset is less than 2GB then do an MPI_Bcast - * of the data from one process instead of having all the processes - * involved in the collective I/O. - */ - if (dset_size > ((hsize_t)(2.0F * H5_GB) - 1)) - local_cause[1] |= H5D_MPIO_RANK0_GREATER_THAN_2GB; - } /* end else */ - } /* end else */ - } /* end else */ + /* Determine dataset size */ + dset_size = ((hsize_t)snelmts) * type_size; + + /* If the size of the dataset is less than 2GB then do an MPI_Bcast + * of the data from one process instead of having all the processes + * involved in the collective I/O. + */ + if (dset_size > ((hsize_t)(2.0F * H5_GB) - 1)) + local_cause[1] |= H5D_MPIO_RANK0_GREATER_THAN_2GB; + } /* end else */ + } /* end else */ + } /* end else */ + } /* end for loop */ /* Check for independent I/O */ if (local_cause[0] & H5D_MPIO_SET_INDEPENDENT) @@ -875,26 +891,29 @@ done: * * Purpose: MPI-IO function to read directly from app buffer to file. * - * Return: non-negative on success, negative on failure. + * This was referred from H5D__mpio_select_read for + * multi-dset work. * - * Programmer: + * Return: non-negative on success, negative on failure. * *------------------------------------------------------------------------- */ herr_t -H5D__mpio_select_read(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t mpi_buf_count, H5S_t H5_ATTR_UNUSED *file_space, +H5D__mpio_select_read(const H5D_io_info_t *io_info, hsize_t mpi_buf_count, H5S_t H5_ATTR_UNUSED *file_space, H5S_t H5_ATTR_UNUSED *mem_space) { - const H5D_contig_storage_t *store_contig = - &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ + void *rbuf = NULL; herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE + /* memory addr from a piece with lowest file addr */ + rbuf = io_info->base_maddr.vp; + + /*OKAY: CAST DISCARDS CONST QUALIFIER*/ H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t); - if (H5F_shared_block_read(io_info->f_sh, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, - io_info->u.rbuf) < 0) + if (H5F_shared_block_read(io_info->f_sh, H5FD_MEM_DRAW, io_info->store_faddr, (size_t)mpi_buf_count, + rbuf) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "can't finish collective parallel read") done: @@ -906,27 +925,29 @@ done: * * Purpose: MPI-IO function to write directly from app buffer to file. * - * Return: non-negative on success, negative on failure. + * This was referred from H5D__mpio_select_write for + * multi-dset work. * - * Programmer: + * Return: non-negative on success, negative on failure. * *------------------------------------------------------------------------- */ herr_t -H5D__mpio_select_write(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t mpi_buf_count, H5S_t H5_ATTR_UNUSED *file_space, +H5D__mpio_select_write(const H5D_io_info_t *io_info, hsize_t mpi_buf_count, H5S_t H5_ATTR_UNUSED *file_space, H5S_t H5_ATTR_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; + const void *wbuf = NULL; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE + /* memory addr from a piece with lowest file addr */ + wbuf = io_info->base_maddr.cvp; + /*OKAY: CAST DISCARDS CONST QUALIFIER*/ H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t); - if (H5F_shared_block_write(io_info->f_sh, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, - io_info->u.wbuf) < 0) + if (H5F_shared_block_write(io_info->f_sh, H5FD_MEM_DRAW, io_info->store_faddr, (size_t)mpi_buf_count, + wbuf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "can't finish collective parallel write") done: @@ -937,17 +958,15 @@ done: * Function: H5D__mpio_get_sum_chunk * * Purpose: Routine for obtaining total number of chunks to cover - * hyperslab selection selected by all processors. + * hyperslab selection selected by all processors. Operates + * on all datasets in the operation. * * Return: Non-negative on success/Negative on failure * - * 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, int *sum_chunkf) { int num_chunkf; /* Number of chunks to iterate over */ size_t ori_num_chunkf; @@ -958,7 +977,7 @@ H5D__mpio_get_sum_chunk(const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm, /* Get the number of chunks to perform I/O on */ num_chunkf = 0; - ori_num_chunkf = H5SL_count(fm->sel_chunks); + ori_num_chunkf = io_info->pieces_added; H5_CHECKED_ASSIGN(num_chunkf, int, ori_num_chunkf, size_t); /* Determine the summation of number of chunks for all processes */ @@ -971,85 +990,47 @@ done: } /* end H5D__mpio_get_sum_chunk() */ /*------------------------------------------------------------------------- - * Function: H5D__contig_collective_read - * - * Purpose: Reads directly from contiguous data 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__contig_collective_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t H5_ATTR_UNUSED nelmts, H5S_t *file_space, H5S_t *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *fm) -{ - H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_CONTIGUOUS_COLLECTIVE; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_PACKAGE - - /* Sanity check */ - HDassert(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)); - - /* 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") - - /* Set the actual I/O mode property. internal_collective_io will not break to - * independent I/O, so we set it here. - */ - H5CX_set_mpio_actual_io_mode(actual_io_mode); - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__contig_collective_read() */ - -/*------------------------------------------------------------------------- - * Function: H5D__contig_collective_write + * Function: H5D__mpio_get_sum_chunk_dset * - * Purpose: Write directly to contiguous data in file from application - * memory using collective I/O. + * Purpose: Routine for obtaining total number of chunks to cover + * hyperslab selection selected by all processors. Operates + * on a single dataset. * * 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 H5_ATTR_UNUSED nelmts, H5S_t *file_space, H5S_t *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *fm) +static herr_t +H5D__mpio_get_sum_chunk_dset(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + int *sum_chunkf) { - H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_CONTIGUOUS_COLLECTIVE; - herr_t ret_value = SUCCEED; /* Return value */ + 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_PACKAGE - /* Sanity check */ - HDassert(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)); + /* Check for non-chunked dataset, in this case we know the number of "chunks" + * is simply the mpi size */ + HDassert(dset_info->layout->type == H5D_CHUNKED); - /* 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") + /* Get the number of chunks to perform I/O on */ + num_chunkf = 0; + ori_num_chunkf = H5SL_count(dset_info->layout_io_info.chunk_map->dset_sel_pieces); + H5_CHECKED_ASSIGN(num_chunkf, int, ori_num_chunkf, size_t); - /* Set the actual I/O mode property. internal_collective_io will not break to - * independent I/O, so we set it here. - */ - H5CX_set_mpio_actual_io_mode(actual_io_mode); + /* 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))) + HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__contig_collective_write() */ +} /* end H5D__mpio_get_sum_chunk_dset() */ /*------------------------------------------------------------------------- - * Function: H5D__chunk_collective_io + * Function: H5D__piece_io * * Purpose: Routine for * 1) choose an IO option: @@ -1085,34 +1066,34 @@ done: *------------------------------------------------------------------------- */ 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) +H5D__piece_io(H5D_io_info_t *io_info) { H5FD_mpio_chunk_opt_t chunk_opt_mode; #ifdef H5Dmpio_DEBUG hbool_t log_file_flag = FALSE; FILE *debug_log_file = NULL; #endif -#ifdef H5_HAVE_INSTRUMENTED_LIBRARY - htri_t temp_not_link_io = FALSE; -#endif - int io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; - int sum_chunk = -1; - int mpi_rank; - int mpi_size; - herr_t ret_value = SUCCEED; + int io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; + hbool_t recalc_io_option = FALSE; + hbool_t use_multi_dset = FALSE; + unsigned one_link_chunk_io_threshold; /* Threshold to use single collective I/O for all chunks */ + int sum_chunk = -1; + int mpi_rank; + int mpi_size; + size_t i; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE /* Sanity checks */ HDassert(io_info); HDassert(io_info->using_mpi_vfd); - HDassert(type_info); - HDassert(fm); + HDassert(io_info->count > 0); /* Obtain the current rank of the process and the number of ranks */ - if ((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file)) < 0) + if ((mpi_rank = H5F_mpi_get_rank(io_info->dsets_info[0].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) + if ((mpi_size = H5F_mpi_get_size(io_info->dsets_info[0].dset->oloc.file)) < 0) HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain MPI size") #ifdef H5Dmpio_DEBUG @@ -1139,7 +1120,9 @@ H5D__chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf } #endif - /* Check the optional property list for the collective chunk IO optimization option */ + /* Check the optional property list for the collective chunk IO optimization option. + * Only set here if it's a static option, if it needs to be calculated using the + * number of chunks per process delay that calculation until later. */ if (H5CX_get_mpio_chunk_opt_mode(&chunk_opt_mode) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't get chunk optimization option") @@ -1148,81 +1131,190 @@ H5D__chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* direct request to multi-chunk-io */ else if (H5FD_MPIO_CHUNK_MULTI_IO == chunk_opt_mode) io_option = H5D_MULTI_CHUNK_IO; - /* via default path. branch by num threshold */ - else { - unsigned one_link_chunk_io_threshold; /* Threshold to use single collective I/O for all chunks */ + else + recalc_io_option = TRUE; - 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"); + /* Check if we can and should use multi dataset path */ + if (io_info->count > 1 && (io_option == H5D_ONE_LINK_CHUNK_IO || recalc_io_option)) { + /* Use multi dataset path for now */ + use_multi_dset = TRUE; - /* Get the chunk optimization option threshold */ - if (H5CX_get_mpio_chunk_opt_num(&one_link_chunk_io_threshold) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, - "couldn't get chunk optimization option threshold value") + /* Check for filtered datasets */ + for (i = 0; i < io_info->count; i++) + if (io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused > 0) { + use_multi_dset = FALSE; + break; + } - /* 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 / (unsigned)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; -#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ - } /* end else */ + /* Check if this I/O exceeds one linked chunk threshold */ + if (recalc_io_option && use_multi_dset) { + /* Get the chunk optimization option threshold */ + if (H5CX_get_mpio_chunk_opt_num(&one_link_chunk_io_threshold) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, + "couldn't get chunk optimization option threshold value") + + /* If the threshold is 0, no need to check number of chunks */ + if (one_link_chunk_io_threshold > 0) { + /* Get number of chunks for all processes */ + if (H5D__mpio_get_sum_chunk(io_info, &sum_chunk) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, + "unable to obtain the total chunk number of all processes"); + + /* If the average number of chunk per process is less than the threshold, we will do multi + * chunk IO. If this threshold is not exceeded for all datasets, no need to check it again + * for each individual dataset. */ + if ((unsigned)sum_chunk / (unsigned)mpi_size < one_link_chunk_io_threshold) { + recalc_io_option = FALSE; + use_multi_dset = FALSE; + } + } + } + /* Perform multi dataset I/O if appropriate */ + if (use_multi_dset) { #ifdef H5_HAVE_INSTRUMENTED_LIBRARY - { - /*** Set collective chunk user-input optimization APIs. ***/ - if (H5D_ONE_LINK_CHUNK_IO == io_option) { - if (H5CX_test_set_mpio_coll_chunk_link_hard(0) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") - } /* end if */ - else if (H5D_MULTI_CHUNK_IO == io_option) { - if (H5CX_test_set_mpio_coll_chunk_multi_hard(0) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") - } /* end else-if */ - else if (H5D_ONE_LINK_CHUNK_IO_MORE_OPT == io_option) { - if (H5CX_test_set_mpio_coll_chunk_link_num_true(0) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") - } /* end if */ - else if (temp_not_link_io) { - if (H5CX_test_set_mpio_coll_chunk_link_num_false(0) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") - } /* end if */ + /*** Set collective chunk user-input optimization API. ***/ + if (H5D_ONE_LINK_CHUNK_IO == io_option) { + if (H5CX_test_set_mpio_coll_chunk_link_hard(0) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + /* Perform unfiltered link chunk collective IO */ + if (H5D__link_piece_collective_io(io_info, mpi_rank) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish linked chunk MPI-IO") + } } -#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ - /* step 2: Go ahead to do IO.*/ - switch (io_option) { - case H5D_ONE_LINK_CHUNK_IO: - case H5D_ONE_LINK_CHUNK_IO_MORE_OPT: - /* Check if there are any filters in the pipeline */ - if (io_info->dset->shared->dcpl_cache.pline.nused > 0) { - if (H5D__link_chunk_filtered_collective_io(io_info, type_info, fm, mpi_rank, mpi_size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish filtered linked chunk MPI-IO") - } /* end if */ - else - /* Perform unfiltered link chunk collective IO */ - if (H5D__link_chunk_collective_io(io_info, type_info, fm, sum_chunk, mpi_rank, mpi_size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish linked chunk MPI-IO") - break; + if (!use_multi_dset) { + /* Loop over datasets */ + for (i = 0; i < io_info->count; i++) { + if (io_info->dsets_info[i].layout->type == H5D_CONTIGUOUS) { + /* Contiguous: call H5D__inter_collective_io() directly */ + H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_CONTIGUOUS_COLLECTIVE; - case H5D_MULTI_CHUNK_IO: /* direct request to do multi-chunk IO */ - default: /* multiple chunk IO via threshold */ - /* Check if there are any filters in the pipeline */ - if (io_info->dset->shared->dcpl_cache.pline.nused > 0) { - if (H5D__multi_chunk_filtered_collective_io(io_info, type_info, fm, mpi_rank, mpi_size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, - "couldn't finish optimized multiple filtered chunk MPI-IO") - } /* end if */ - else - /* Perform unfiltered multi chunk collective IO */ - if (H5D__multi_chunk_collective_io(io_info, type_info, fm, mpi_rank, mpi_size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish optimized multiple chunk MPI-IO") - break; - } /* end switch */ + io_info->store_faddr = io_info->dsets_info[i].store->contig.dset_addr; + io_info->base_maddr = io_info->dsets_info[i].buf; + + if (H5D__inter_collective_io(io_info, &io_info->dsets_info[i], + io_info->dsets_info[i].file_space, + io_info->dsets_info[i].mem_space) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO") + + /* Set the actual I/O mode property. internal_collective_io will not break to + * independent I/O, so we set it here. + */ + H5CX_set_mpio_actual_io_mode(actual_io_mode); + } + else { + /* Chunked I/O path */ + HDassert(io_info->dsets_info[i].layout->type == H5D_CHUNKED); + + /* Recalculate io_option if necessary */ + if (recalc_io_option) { + /* Get the chunk optimization option threshold */ + if (H5CX_get_mpio_chunk_opt_num(&one_link_chunk_io_threshold) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, + "couldn't get chunk optimization option threshold value") + + /* If the threshold is 0, no need to check number of chunks */ + if (one_link_chunk_io_threshold == 0) { + io_option = H5D_ONE_LINK_CHUNK_IO_MORE_OPT; + recalc_io_option = FALSE; + } + else { + /* Get number of chunks for all processes */ + if (H5D__mpio_get_sum_chunk_dset(io_info, &io_info->dsets_info[i], &sum_chunk) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, + "unable to obtain the total chunk number of all processes"); + + /* 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 / (unsigned)mpi_size >= one_link_chunk_io_threshold) + io_option = H5D_ONE_LINK_CHUNK_IO_MORE_OPT; + else + io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; + } + } + + /* step 2: Go ahead to do IO.*/ + switch (io_option) { + case H5D_ONE_LINK_CHUNK_IO: + case H5D_ONE_LINK_CHUNK_IO_MORE_OPT: + /* Check if there are any filters in the pipeline */ + if (io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused > 0) { + if (H5D__link_chunk_filtered_collective_io(io_info, &io_info->dsets_info[i], + mpi_rank, mpi_size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, + "couldn't finish filtered linked chunk MPI-IO") + } /* end if */ + else { + /* If there is more than one dataset we cannot make the multi dataset call here, + * fall back to multi chunk */ + if (io_info->count > 1) { + io_option = H5D_MULTI_CHUNK_IO_MORE_OPT; + recalc_io_option = TRUE; + + if (H5D__multi_chunk_collective_io(io_info, &io_info->dsets_info[i], mpi_rank, + mpi_size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, + "couldn't finish optimized multiple chunk MPI-IO") + } + else { + /* Perform unfiltered link chunk collective IO */ + if (H5D__link_piece_collective_io(io_info, mpi_rank) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, + "couldn't finish linked chunk MPI-IO") + } + } + + break; + + case H5D_MULTI_CHUNK_IO: /* direct request to do multi-chunk IO */ + default: /* multiple chunk IO via threshold */ + /* Check if there are any filters in the pipeline */ + if (io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused > 0) { + if (H5D__multi_chunk_filtered_collective_io(io_info, &io_info->dsets_info[i], + mpi_rank, mpi_size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, + "couldn't finish optimized multiple filtered chunk MPI-IO") + } /* end if */ + else { + /* Perform unfiltered multi chunk collective IO */ + if (H5D__multi_chunk_collective_io(io_info, &io_info->dsets_info[i], mpi_rank, + mpi_size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, + "couldn't finish optimized multiple chunk MPI-IO") + } + + break; + } /* end switch */ + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + { + /*** Set collective chunk user-input optimization APIs. ***/ + if (H5D_ONE_LINK_CHUNK_IO == io_option) { + if (H5CX_test_set_mpio_coll_chunk_link_hard(0) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + else if (H5D_MULTI_CHUNK_IO == io_option) { + if (H5CX_test_set_mpio_coll_chunk_multi_hard(0) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") + } /* end else-if */ + else if (H5D_ONE_LINK_CHUNK_IO_MORE_OPT == io_option) { + if (H5CX_test_set_mpio_coll_chunk_link_num_true(0) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + else if (H5D_MULTI_CHUNK_IO_MORE_OPT == io_option) { + if (H5CX_test_set_mpio_coll_chunk_link_num_false(0) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + } +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + } + } + } done: #ifdef H5Dmpio_DEBUG @@ -1236,13 +1328,13 @@ done: #endif FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_collective_io */ +} /* end H5D__piece_io */ /*------------------------------------------------------------------------- - * Function: H5D__chunk_collective_read + * Function: H5D__collective_read * - * Purpose: Reads directly from chunks in file into application memory - * using collective I/O. + * Purpose: Read directly from pieces (chunks/contig) in file into + * application memory using collective I/O. * * Return: Non-negative on success/Negative on failure * @@ -1252,27 +1344,25 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__chunk_collective_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space, - H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t *fm) +H5D__collective_read(H5D_io_info_t *io_info) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Call generic selection operation */ - if (H5D__chunk_collective_io(io_info, type_info, fm) < 0) + if (H5D__piece_io(io_info) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_collective_read() */ +} /* end H5D__collective_read() */ /*------------------------------------------------------------------------- - * Function: H5D__chunk_collective_write + * Function: H5D__collective_write * - * Purpose: Write directly to chunks in file from application memory - * using collective I/O. + * Purpose: Write directly to pieces (chunks/contig) in file into + * application memory using collective I/O. * * Return: Non-negative on success/Negative on failure * @@ -1282,31 +1372,30 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__chunk_collective_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t H5_ATTR_UNUSED nelmts, H5S_t H5_ATTR_UNUSED *file_space, - H5S_t H5_ATTR_UNUSED *mem_space, H5D_chunk_map_t *fm) +H5D__collective_write(H5D_io_info_t *io_info) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Call generic selection operation */ - if (H5D__chunk_collective_io(io_info, type_info, fm) < 0) + if (H5D__piece_io(io_info) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_collective_write() */ +} /* end H5D__collective_write() */ /*------------------------------------------------------------------------- - * Function: H5D__link_chunk_collective_io + * Function: H5D__link_piece_collective_io * - * Purpose: Routine for one collective IO with one MPI derived datatype to link with all chunks + * Purpose: Routine for single collective IO with one MPI derived datatype + * to link with all pieces (chunks + contig) * - * 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 + * 1. Use the piece addresses and piece info sorted in skiplist + * 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 * @@ -1316,121 +1405,100 @@ done: *------------------------------------------------------------------------- */ 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, int mpi_rank, int mpi_size) +H5D__link_piece_collective_io(H5D_io_info_t *io_info, int mpi_rank) { - H5D_chunk_addr_info_t *chunk_addr_info_array = NULL; - MPI_Datatype chunk_final_mtype; /* Final memory MPI datatype for all chunks with selection */ - hbool_t chunk_final_mtype_is_derived = FALSE; - MPI_Datatype chunk_final_ftype; /* Final file MPI datatype for all chunks with selection */ - hbool_t chunk_final_ftype_is_derived = FALSE; - H5D_storage_t ctg_store; /* Storage info for "fake" contiguous dataset */ - size_t total_chunks; - MPI_Datatype *chunk_mtype = NULL; - MPI_Datatype *chunk_ftype = NULL; - MPI_Aint *chunk_disp_array = NULL; - MPI_Aint *chunk_mem_disp_array = NULL; - hbool_t *chunk_mft_is_derived_array = + MPI_Datatype chunk_final_mtype; /* Final memory MPI datatype for all chunks with selection */ + hbool_t chunk_final_mtype_is_derived = FALSE; + MPI_Datatype chunk_final_ftype; /* Final file MPI datatype for all chunks with selection */ + hbool_t chunk_final_ftype_is_derived = FALSE; + H5D_storage_t ctg_store; /* Storage info for "fake" contiguous dataset */ + MPI_Datatype *chunk_mtype = NULL; + MPI_Datatype *chunk_ftype = NULL; + MPI_Aint *chunk_file_disp_array = NULL; + MPI_Aint *chunk_mem_disp_array = NULL; + hbool_t *chunk_mft_is_derived_array = NULL; /* Flags to indicate each chunk's MPI file datatype is derived */ hbool_t *chunk_mbt_is_derived_array = - NULL; /* Flags to indicate each chunk's MPI memory datatype is derived */ - int *chunk_mpi_file_counts = NULL; /* Count of MPI file datatype for each chunk */ - int *chunk_mpi_mem_counts = NULL; /* Count of MPI memory datatype for each chunk */ - int mpi_code; /* MPI return code */ - herr_t ret_value = SUCCEED; + NULL; /* Flags to indicate each chunk's MPI memory datatype is derived */ + int *chunk_mpi_file_counts = NULL; /* Count of MPI file datatype for each chunk */ + int *chunk_mpi_mem_counts = NULL; /* Count of MPI memory datatype for each chunk */ + int mpi_code; /* MPI return code */ + H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode = H5D_MPIO_LINK_CHUNK; + H5D_mpio_actual_io_mode_t actual_io_mode = 0; + size_t i; /* Local index variable */ + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE + /* set actual_io_mode */ + for (i = 0; i < io_info->count; i++) { + HDassert(io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused == 0); + if (io_info->dsets_info[i].layout->type == H5D_CHUNKED) + actual_io_mode |= H5D_MPIO_CHUNK_COLLECTIVE; + else if (io_info->dsets_info[i].layout->type == H5D_CONTIGUOUS) { + actual_io_mode |= H5D_MPIO_CONTIGUOUS_COLLECTIVE; + + /* if only single-dset */ + if (1 == io_info->count) + actual_chunk_opt_mode = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + } + else + HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "unsupported storage layout") + } + /* Set the actual-chunk-opt-mode property. */ - H5CX_set_mpio_actual_chunk_opt(H5D_MPIO_LINK_CHUNK); + H5CX_set_mpio_actual_chunk_opt(actual_chunk_opt_mode); /* Set the actual-io-mode property. * Link chunk I/O does not break to independent, so can set right away */ - H5CX_set_mpio_actual_io_mode(H5D_MPIO_CHUNK_COLLECTIVE); - - /* 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_CHECKED_ASSIGN(total_chunks, size_t, fm->layout->u.chunk.nchunks, hsize_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) { - 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 */ - - /* Check for this process having selection in this chunk */ - chunk_node = H5SL_first(fm->sel_chunks); - - if (chunk_node == NULL) { - /* Set the dataspace info for I/O to NULL, this process doesn't have any I/O to perform */ - fspace = mspace = NULL; - - /* Initialize chunk address */ - ctg_store.contig.dset_addr = 0; - } /* end if */ - else { - H5D_chunk_ud_t udata; /* User data for querying chunk info */ - H5D_chunk_info_t *chunk_info; /* Info for chunk in skiplist */ - - /* Get the chunk info, for the selection in the chunk */ - if (NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_item(chunk_node))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skip list") - - /* Set the dataspace info for I/O */ - fspace = chunk_info->fspace; - mspace = chunk_info->mspace; - - /* Look up address of chunk */ - if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk address") - ctg_store.contig.dset_addr = udata.chunk_block.offset; - } /* end else */ - - /* Set up the base storage address for this chunk */ - io_info->store = &ctg_store; - -#ifdef H5Dmpio_DEBUG - H5D_MPIO_DEBUG(mpi_rank, "before inter_collective_io for total chunk = 1"); -#endif + H5CX_set_mpio_actual_io_mode(actual_io_mode); - /* 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 { + /* Code block for actual actions (Build a MPI Type, IO) */ + { hsize_t mpi_buf_count; /* Number of MPI types */ size_t num_chunk; /* Number of chunks for this process */ - size_t u; /* Local index variable */ + + H5D_piece_info_t *piece_info; + + /* local variable for base address for buffer */ + H5_flexible_const_ptr_t base_buf_addr; + base_buf_addr.cvp = NULL; /* Get the number of chunks with a selection */ - num_chunk = H5SL_count(fm->sel_chunks); + num_chunk = io_info->pieces_added; H5_CHECK_OVERFLOW(num_chunk, size_t, int); #ifdef H5Dmpio_DEBUG - H5D_MPIO_DEBUG_VA(mpi_rank, "total_chunks = %zu, num_chunk = %zu", total_chunks, num_chunk); + H5D_MPIO_DEBUG_VA(mpi_rank, "num_chunk = %zu\n", num_chunk); #endif /* Set up MPI datatype for chunks selected */ if (num_chunk) { + hbool_t need_sort = FALSE; + + /* Check if sel_pieces array is sorted */ + HDassert(io_info->sel_pieces[0]->faddr != HADDR_UNDEF); + for (i = 1; i < num_chunk; i++) { + HDassert(io_info->sel_pieces[i]->faddr != HADDR_UNDEF); + + if (io_info->sel_pieces[i]->faddr < io_info->sel_pieces[i - 1]->faddr) { + need_sort = TRUE; + break; + } + } + + /* Sort sel_pieces if necessary */ + if (need_sort) + HDqsort(io_info->sel_pieces, io_info->pieces_added, sizeof(io_info->sel_pieces[0]), + H5D__cmp_piece_addr); + /* Allocate chunking information */ - if (NULL == (chunk_addr_info_array = - (H5D_chunk_addr_info_t *)H5MM_malloc(num_chunk * sizeof(H5D_chunk_addr_info_t)))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk array buffer") if (NULL == (chunk_mtype = (MPI_Datatype *)H5MM_malloc(num_chunk * sizeof(MPI_Datatype)))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory datatype buffer") if (NULL == (chunk_ftype = (MPI_Datatype *)H5MM_malloc(num_chunk * sizeof(MPI_Datatype)))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file datatype buffer") - if (NULL == (chunk_disp_array = (MPI_Aint *)H5MM_malloc(num_chunk * sizeof(MPI_Aint)))) + if (NULL == (chunk_file_disp_array = (MPI_Aint *)H5MM_malloc(num_chunk * sizeof(MPI_Aint)))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file displacement buffer") if (NULL == (chunk_mem_disp_array = (MPI_Aint *)H5MM_calloc(num_chunk * sizeof(MPI_Aint)))) @@ -1447,36 +1515,37 @@ H5D__link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *typ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file is derived datatype flags buffer") -#ifdef H5Dmpio_DEBUG - H5D_MPIO_DEBUG(mpi_rank, "before sorting chunk addresses"); -#endif + /* save lowest file address */ + ctg_store.contig.dset_addr = io_info->sel_pieces[0]->faddr; - /* Sort the chunk address */ - if (H5D__sort_chunk(io_info, fm, chunk_addr_info_array, sum_chunk, mpi_rank, mpi_size) < 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; + /* save base mem addr of piece for read/write */ + base_buf_addr = io_info->sel_pieces[0]->dset_info->buf; #ifdef H5Dmpio_DEBUG - H5D_MPIO_DEBUG(mpi_rank, "after sorting chunk addresses"); + H5D_MPIO_DEBUG(mpi_rank, "before iterate over selected pieces\n"); #endif - /* Obtain MPI derived datatype from all individual chunks */ - for (u = 0; u < num_chunk; u++) { + /* Obtain MPI derived datatype from all individual pieces */ + /* Iterate over selected pieces for this process */ + for (i = 0; i < num_chunk; i++) { hsize_t *permute_map = NULL; /* array that holds the mapping from the old, out-of-order displacements to the in-order displacements of the MPI datatypes of the point selection of the file space */ hbool_t is_permuted = FALSE; + /* Assign convenience pointer to piece info */ + piece_info = io_info->sel_pieces[i]; + /* Obtain disk and memory MPI derived datatype */ /* NOTE: The permute_map array can be allocated within H5S_mpio_space_type * and will be fed into the next call to H5S_mpio_space_type * where it will be freed. */ - if (H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.fspace, type_info->src_type_size, - &chunk_ftype[u], /* OUT: datatype created */ - &chunk_mpi_file_counts[u], /* OUT */ - &(chunk_mft_is_derived_array[u]), /* OUT */ + if (H5S_mpio_space_type(piece_info->fspace, piece_info->dset_info->type_info.src_type_size, + &chunk_ftype[i], /* OUT: datatype created */ + &chunk_mpi_file_counts[i], /* OUT */ + &(chunk_mft_is_derived_array[i]), /* OUT */ TRUE, /* this is a file space, so permute the datatype if the point @@ -1488,12 +1557,13 @@ H5D__link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *typ are out of order */ &is_permuted /* OUT */) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI file type") + /* Sanity check */ if (is_permuted) HDassert(permute_map); - if (H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.mspace, type_info->dst_type_size, - &chunk_mtype[u], &chunk_mpi_mem_counts[u], - &(chunk_mbt_is_derived_array[u]), FALSE, /* this is a memory + if (H5S_mpio_space_type(piece_info->mspace, piece_info->dset_info->type_info.dst_type_size, + &chunk_mtype[i], &chunk_mpi_mem_counts[i], + &(chunk_mbt_is_derived_array[i]), FALSE, /* this is a memory space, so if the file space is not permuted, there is no @@ -1512,19 +1582,27 @@ H5D__link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *typ if (is_permuted) HDassert(!permute_map); - /* Chunk address relative to the first chunk */ - chunk_addr_info_array[u].chunk_addr -= ctg_store.contig.dset_addr; + /* Piece address relative to the first piece addr + * Assign piece address to MPI displacement + * (assume MPI_Aint big enough to hold it) */ + chunk_file_disp_array[i] = (MPI_Aint)piece_info->faddr - (MPI_Aint)ctg_store.contig.dset_addr; - /* Assign chunk address to MPI displacement */ - /* (assume MPI_Aint big enough to hold it) */ - chunk_disp_array[u] = (MPI_Aint)chunk_addr_info_array[u].chunk_addr; + if (io_info->op_type == H5D_IO_OP_WRITE) { + chunk_mem_disp_array[i] = + (MPI_Aint)piece_info->dset_info->buf.cvp - (MPI_Aint)base_buf_addr.cvp; + } + else if (io_info->op_type == H5D_IO_OP_READ) { + chunk_mem_disp_array[i] = + (MPI_Aint)piece_info->dset_info->buf.vp - (MPI_Aint)base_buf_addr.vp; + } } /* end for */ /* Create final MPI derived datatype for the file */ if (MPI_SUCCESS != - (mpi_code = MPI_Type_create_struct((int)num_chunk, chunk_mpi_file_counts, chunk_disp_array, - chunk_ftype, &chunk_final_ftype))) + (mpi_code = MPI_Type_create_struct((int)num_chunk, chunk_mpi_file_counts, + chunk_file_disp_array, chunk_ftype, &chunk_final_ftype))) HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_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) chunk_final_ftype_is_derived = TRUE; @@ -1539,13 +1617,13 @@ H5D__link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *typ chunk_final_mtype_is_derived = TRUE; /* Free the file & memory MPI datatypes for each chunk */ - for (u = 0; u < num_chunk; u++) { - if (chunk_mbt_is_derived_array[u]) - if (MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_mtype + u))) + for (i = 0; i < num_chunk; i++) { + if (chunk_mbt_is_derived_array[i]) + if (MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_mtype + i))) HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) - if (chunk_mft_is_derived_array[u]) - if (MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_ftype + u))) + if (chunk_mft_is_derived_array[i]) + if (MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_ftype + i))) HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) } /* end for */ @@ -1555,6 +1633,9 @@ H5D__link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *typ else { /* no selection at all for this process */ ctg_store.contig.dset_addr = 0; + /* just provide a valid mem address. no actual IO occur */ + base_buf_addr = io_info->dsets_info[0].buf; + /* Set the MPI datatype */ chunk_final_ftype = MPI_BYTE; chunk_final_mtype = MPI_BYTE; @@ -1566,15 +1647,14 @@ H5D__link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *typ #ifdef H5Dmpio_DEBUG H5D_MPIO_DEBUG(mpi_rank, "before coming to final collective I/O"); #endif - - /* Set up the base storage address for this chunk */ - io_info->store = &ctg_store; + /* Set up the base storage address for this piece */ + io_info->store_faddr = ctg_store.contig.dset_addr; + io_info->base_maddr = base_buf_addr; /* 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) + if (H5D__final_collective_io(io_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 H5Dmpio_DEBUG @@ -1583,14 +1663,12 @@ done: #endif /* Release resources */ - 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_file_disp_array) + H5MM_xfree(chunk_file_disp_array); if (chunk_mem_disp_array) H5MM_xfree(chunk_mem_disp_array); if (chunk_mpi_mem_counts) @@ -1609,7 +1687,7 @@ done: HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__link_chunk_collective_io */ +} /* end H5D__link_piece_collective_io */ /*------------------------------------------------------------------------- * Function: H5D__link_chunk_filtered_collective_io @@ -1680,29 +1758,27 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - H5D_chunk_map_t *fm, int mpi_rank, int mpi_size) +H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, int mpi_rank, + int mpi_size) { - H5D_filtered_collective_io_info_t *chunk_list = NULL; /* The list of chunks being read/written */ - H5D_filtered_collective_io_info_t *chunk_hash_table = NULL; - unsigned char **chunk_msg_bufs = NULL; - H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ - MPI_Datatype mem_type = MPI_BYTE; - MPI_Datatype file_type = MPI_BYTE; - hbool_t mem_type_is_derived = FALSE; + H5D_filtered_collective_io_info_t *chunk_list = NULL; /* The list of chunks being read/written */ + H5D_filtered_collective_io_info_t *chunk_hash_table = NULL; + unsigned char **chunk_msg_bufs = NULL; + MPI_Datatype mem_type = MPI_BYTE; + MPI_Datatype file_type = MPI_BYTE; + hbool_t mem_type_is_derived = FALSE; hbool_t file_type_is_derived = FALSE; size_t *rank_chunks_assigned_map = NULL; size_t chunk_list_num_entries; size_t i; int chunk_msg_bufs_len = 0; - int mpi_code; - herr_t ret_value = SUCCEED; + char fake_buf; /* Used as a fake buffer for ranks with no chunks, thus a NULL buf pointer */ + int mpi_code; + herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE + FUNC_ENTER_PACKAGE_TAG(dset_info->dset->oloc.addr) HDassert(io_info); - HDassert(type_info); - HDassert(fm); #ifdef H5Dmpio_DEBUG H5D_MPIO_TRACE_ENTER(mpi_rank); @@ -1720,12 +1796,12 @@ H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_in H5CX_set_mpio_actual_io_mode(H5D_MPIO_CHUNK_COLLECTIVE); /* Build a list of selected chunks in the collective io operation */ - if (H5D__mpio_collective_filtered_chunk_io_setup(io_info, type_info, fm, &chunk_list, - &chunk_list_num_entries, mpi_rank) < 0) + if (H5D__mpio_collective_filtered_chunk_io_setup(io_info, dset_info, &chunk_list, &chunk_list_num_entries, + mpi_rank) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "couldn't construct filtered I/O info list") if (io_info->op_type == H5D_IO_OP_READ) { /* Filtered collective read */ - if (H5D__mpio_collective_filtered_chunk_read(chunk_list, chunk_list_num_entries, io_info, type_info, + if (H5D__mpio_collective_filtered_chunk_read(chunk_list, chunk_list_num_entries, io_info, dset_info, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "couldn't read filtered chunks") } @@ -1733,17 +1809,17 @@ H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_in H5D_chk_idx_info_t index_info; hsize_t mpi_buf_count; - H5D_MPIO_INIT_CHUNK_IDX_INFO(index_info, io_info); + H5D_MPIO_INIT_CHUNK_IDX_INFO(index_info, dset_info->dset); if (mpi_size > 1) { /* Redistribute shared chunks being written to */ - if (H5D__mpio_redistribute_shared_chunks(chunk_list, chunk_list_num_entries, io_info, fm, - mpi_rank, mpi_size, &rank_chunks_assigned_map) < 0) + if (H5D__mpio_redistribute_shared_chunks(chunk_list, chunk_list_num_entries, io_info, mpi_rank, + mpi_size, &rank_chunks_assigned_map) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to redistribute shared chunks") /* Send any chunk modification messages for chunks this rank no longer owns */ if (H5D__mpio_share_chunk_modification_data(chunk_list, &chunk_list_num_entries, io_info, - type_info, mpi_rank, mpi_size, &chunk_hash_table, + dset_info, mpi_rank, mpi_size, &chunk_hash_table, &chunk_msg_bufs, &chunk_msg_bufs_len) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to send chunk modification data between MPI ranks") @@ -1758,7 +1834,7 @@ H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_in * must participate. */ if (H5D__mpio_collective_filtered_chunk_update(chunk_list, chunk_list_num_entries, chunk_hash_table, - chunk_msg_bufs, chunk_msg_bufs_len, io_info, type_info, + chunk_msg_bufs, chunk_msg_bufs_len, io_info, dset_info, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "couldn't update modified chunks") @@ -1790,20 +1866,21 @@ H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_in * Override the write buffer to point to the first * chunk's data buffer */ - io_info->u.wbuf = chunk_list[0].buf; + io_info->base_maddr.cvp = chunk_list[0].buf; /* * Setup the base storage address for this operation * to be the first chunk's file address */ - ctg_store.contig.dset_addr = chunk_list[0].chunk_new.offset; + io_info->store_faddr = chunk_list[0].chunk_new.offset; + } + else { + io_info->base_maddr.cvp = &fake_buf; + io_info->store_faddr = 0; } - else - ctg_store.contig.dset_addr = 0; /* Perform I/O */ - io_info->store = &ctg_store; - if (H5D__final_collective_io(io_info, type_info, mpi_buf_count, file_type, mem_type) < 0) + if (H5D__final_collective_io(io_info, mpi_buf_count, file_type, mem_type) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish MPI-IO") /* Free up resources in anticipation of following collective operation */ @@ -1818,8 +1895,8 @@ H5D__link_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_in * into the chunk index */ if (H5D__mpio_collective_filtered_chunk_reinsert(chunk_list, chunk_list_num_entries, - rank_chunks_assigned_map, io_info, &index_info, - mpi_rank, mpi_size) < 0) + rank_chunks_assigned_map, io_info, dset_info, + &index_info, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "couldn't collectively re-insert modified chunks into chunk index") } @@ -1857,7 +1934,7 @@ done: H5D_MPIO_TRACE_EXIT(mpi_rank); #endif - FUNC_LEAVE_NOAPI(ret_value) + FUNC_LEAVE_NOAPI_TAG(ret_value) } /* end H5D__link_chunk_filtered_collective_io() */ /*------------------------------------------------------------------------- @@ -1878,33 +1955,39 @@ done: *------------------------------------------------------------------------- */ 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, - int mpi_rank, int mpi_size) +H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, int mpi_rank, + int mpi_size) { - 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_collective_opt_t last_coll_opt_mode = H5FD_MPIO_COLLECTIVE_IO; /* Last parallel transfer with independent IO or collective IO with this mode */ + H5FD_mpio_collective_opt_t orig_coll_opt_mode = + H5FD_MPIO_COLLECTIVE_IO; /* Original parallel transfer property on entering this function */ size_t total_chunk; /* Total # of chunks in dataset */ - size_t u; /* Local index variable */ + size_t num_chunk; /* Number of chunks for this process */ + H5SL_node_t *piece_node = NULL; /* Current node in chunk skip list */ + H5D_piece_info_t *next_chunk_info = NULL; /* Chunk info for next selected chunk */ + size_t u; /* Local index variable */ H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_NO_COLLECTIVE; /* Local variable for tracking the I/O mode used. */ herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE + FUNC_ENTER_PACKAGE_TAG(dset_info->dset->oloc.addr) + + HDassert(dset_info->layout->type == H5D_CHUNKED); + + /* Get the current I/O collective opt mode so we can restore it later */ + if (H5CX_get_mpio_coll_opt(&orig_coll_opt_mode) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O collective_op property") /* Set the actual chunk opt mode property */ H5CX_set_mpio_actual_chunk_opt(H5D_MPIO_MULTI_CHUNK); /* Retrieve total # of chunks in dataset */ - H5_CHECKED_ASSIGN(total_chunk, size_t, fm->layout->u.chunk.nchunks, hsize_t); + H5_CHECKED_ASSIGN(total_chunk, size_t, dset_info->layout->u.chunk.nchunks, hsize_t); HDassert(total_chunk != 0); /* Allocate memories */ @@ -1916,47 +1999,62 @@ H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *ty #endif /* Obtain IO option for each chunk */ - if (H5D__obtain_mpio_mode(io_info, fm, chunk_io_option, chunk_addr, mpi_rank, mpi_size) < 0) + if (H5D__obtain_mpio_mode(io_info, dset_info, chunk_io_option, chunk_addr, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTRECV, FAIL, "unable to obtain MPIO mode") - /* Set up contiguous I/O info object */ - H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); - ctg_io_info.store = &ctg_store; - ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; - - /* Initialize temporary contiguous storage info */ - ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size; - - /* Set up compact I/O info object */ - H5MM_memcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); - cpt_io_info.store = &cpt_store; - cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; - - /* Initialize temporary compact storage info */ - cpt_store.compact.dirty = &cpt_dirty; + /* Set memory buffers */ + io_info->base_maddr = dset_info->buf; /* Set dataset storage for I/O info */ - io_info->store = &store; + dset_info->store = &store; + + /* Get the number of chunks with a selection */ + num_chunk = H5SL_count(dset_info->layout_io_info.chunk_map->dset_sel_pieces); + + if (num_chunk) { + /* Start at the beginning of the chunk map skiplist. Since these chunks are + * stored in index order and since we're iterating in index order we can + * just check for each chunk being selected in order */ + if (NULL == (piece_node = H5SL_first(dset_info->layout_io_info.chunk_map->dset_sel_pieces))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't get piece node from skip list") + if (NULL == (next_chunk_info = (H5D_piece_info_t *)H5SL_item(piece_node))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't get piece info from skip list") + } /* Loop over _all_ the chunks */ for (u = 0; u < total_chunk; u++) { - H5D_chunk_info_t *chunk_info; /* Chunk info for current chunk */ + H5D_piece_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 */ #ifdef H5Dmpio_DEBUG H5D_MPIO_DEBUG_VA(mpi_rank, "mpi_rank = %d, chunk index = %zu", mpi_rank, u); #endif - /* 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); + /* Check if this chunk is the next chunk in the skip list, if there are + * selected chunks left to process */ + HDassert(!num_chunk || next_chunk_info); + HDassert(!num_chunk || next_chunk_info->index >= u); + if (num_chunk && next_chunk_info->index == u) { + /* Next chunk is this chunk */ + chunk_info = next_chunk_info; + + /* One less chunk to process */ + num_chunk--; + + /* Advance next chunk to next node in skip list, if there are more chunks selected */ + if (num_chunk) { + if (NULL == (piece_node = H5SL_next(piece_node))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk skip list terminated early") + if (NULL == (next_chunk_info = (H5D_piece_info_t *)H5SL_item(piece_node))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't get piece info from skip list") + } /* Pass in chunk's coordinates in a union. */ store.chunk.scaled = chunk_info->scaled; - } /* end if */ + } + else + chunk_info = NULL; /* Collective IO for this chunk, * Note: even there is no selection for this process, the process still @@ -1994,10 +2092,10 @@ H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *ty } /* end if */ /* Initialize temporary contiguous storage address */ - ctg_store.contig.dset_addr = chunk_addr[u]; + io_info->store_faddr = chunk_addr[u]; /* Perform the I/O */ - if (H5D__inter_collective_io(&ctg_io_info, type_info, fspace, mspace) < 0) + if (H5D__inter_collective_io(io_info, dset_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 */ @@ -2028,10 +2126,10 @@ H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *ty } /* end if */ /* Initialize temporary contiguous storage address */ - ctg_store.contig.dset_addr = chunk_addr[u]; + io_info->store_faddr = chunk_addr[u]; /* Perform the I/O */ - if (H5D__inter_collective_io(&ctg_io_info, type_info, fspace, mspace) < 0) + if (H5D__inter_collective_io(io_info, dset_info, fspace, mspace) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO") #ifdef H5Dmpio_DEBUG H5D_MPIO_DEBUG(mpi_rank, "after inter collective IO"); @@ -2043,12 +2141,17 @@ H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *ty H5CX_set_mpio_actual_io_mode(actual_io_mode); done: + /* Reset collective opt mode */ + if (H5CX_set_mpio_coll_opt(orig_coll_opt_mode) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't reset MPI-I/O collective_op property") + + /* Free memory */ if (chunk_io_option) H5MM_xfree(chunk_io_option); if (chunk_addr) H5MM_xfree(chunk_addr); - FUNC_LEAVE_NOAPI(ret_value) + FUNC_LEAVE_NOAPI_TAG(ret_value) } /* end H5D__multi_chunk_collective_io */ /*------------------------------------------------------------------------- @@ -2130,14 +2233,13 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - H5D_chunk_map_t *fm, int mpi_rank, int mpi_size) +H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, int mpi_rank, + int mpi_size) { H5D_filtered_collective_io_info_t *chunk_list = NULL; /* The list of chunks being read/written */ H5D_filtered_collective_io_info_t *chunk_hash_table = NULL; unsigned char **chunk_msg_bufs = NULL; H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ - H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ MPI_Datatype mem_type = MPI_BYTE; MPI_Datatype file_type = MPI_BYTE; hbool_t mem_type_is_derived = FALSE; @@ -2150,11 +2252,9 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i int mpi_code; herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE + FUNC_ENTER_PACKAGE_TAG(dset_info->dset->oloc.addr) HDassert(io_info); - HDassert(type_info); - HDassert(fm); #ifdef H5Dmpio_DEBUG H5D_MPIO_TRACE_ENTER(mpi_rank); @@ -2172,8 +2272,8 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i H5CX_set_mpio_actual_io_mode(H5D_MPIO_CHUNK_COLLECTIVE); /* Build a list of selected chunks in the collective IO operation */ - if (H5D__mpio_collective_filtered_chunk_io_setup(io_info, type_info, fm, &chunk_list, - &chunk_list_num_entries, mpi_rank) < 0) + if (H5D__mpio_collective_filtered_chunk_io_setup(io_info, dset_info, &chunk_list, &chunk_list_num_entries, + mpi_rank) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "couldn't construct filtered I/O info list") /* Retrieve the maximum number of chunks selected for any rank */ @@ -2187,11 +2287,6 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i /* Set up contiguous I/O info object */ H5MM_memcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); - ctg_io_info.store = &ctg_store; - ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; - - /* Initialize temporary contiguous storage info */ - ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size; if (io_info->op_type == H5D_IO_OP_READ) { /* Filtered collective read */ for (i = 0; i < max_num_chunks; i++) { @@ -2199,7 +2294,7 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i have_chunk_to_process = (i < chunk_list_num_entries); if (H5D__mpio_collective_filtered_chunk_read(have_chunk_to_process ? &chunk_list[i] : NULL, - have_chunk_to_process ? 1 : 0, io_info, type_info, + have_chunk_to_process ? 1 : 0, io_info, dset_info, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "couldn't read filtered chunks") @@ -2214,17 +2309,17 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i hsize_t mpi_buf_count; /* Construct chunked index info */ - H5D_MPIO_INIT_CHUNK_IDX_INFO(index_info, io_info); + H5D_MPIO_INIT_CHUNK_IDX_INFO(index_info, dset_info->dset); if (mpi_size > 1) { /* Redistribute shared chunks being written to */ - if (H5D__mpio_redistribute_shared_chunks(chunk_list, chunk_list_num_entries, io_info, fm, - mpi_rank, mpi_size, NULL) < 0) + if (H5D__mpio_redistribute_shared_chunks(chunk_list, chunk_list_num_entries, io_info, mpi_rank, + mpi_size, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to redistribute shared chunks") /* Send any chunk modification messages for chunks this rank no longer owns */ if (H5D__mpio_share_chunk_modification_data(chunk_list, &chunk_list_num_entries, io_info, - type_info, mpi_rank, mpi_size, &chunk_hash_table, + dset_info, mpi_rank, mpi_size, &chunk_hash_table, &chunk_msg_bufs, &chunk_msg_bufs_len) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to send chunk modification data between MPI ranks") @@ -2246,7 +2341,7 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i if (H5D__mpio_collective_filtered_chunk_update(have_chunk_to_process ? &chunk_list[i] : NULL, have_chunk_to_process ? 1 : 0, chunk_hash_table, chunk_msg_bufs, chunk_msg_bufs_len, io_info, - type_info, mpi_rank, mpi_size) < 0) + dset_info, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "couldn't update modified chunks") /* All ranks now collectively re-allocate file space for all chunks */ @@ -2276,19 +2371,21 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i * Override the write buffer to point to the * chunk's data buffer */ - ctg_io_info.u.wbuf = chunk_list[i].buf; + ctg_io_info.base_maddr.cvp = chunk_list[i].buf; /* * Setup the base storage address for this * operation to be the chunk's file address */ - ctg_store.contig.dset_addr = chunk_list[i].chunk_new.offset; + ctg_io_info.store_faddr = chunk_list[i].chunk_new.offset; + } + else { + ctg_io_info.store_faddr = 0; + ctg_io_info.base_maddr = dset_info->buf; } - else - ctg_store.contig.dset_addr = 0; /* Perform the I/O */ - if (H5D__final_collective_io(&ctg_io_info, type_info, mpi_buf_count, file_type, mem_type) < 0) + if (H5D__final_collective_io(&ctg_io_info, mpi_buf_count, file_type, mem_type) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish MPI-IO") /* Free up resources in anticipation of following collective operation */ @@ -2302,7 +2399,7 @@ H5D__multi_chunk_filtered_collective_io(H5D_io_info_t *io_info, const H5D_type_i */ if (H5D__mpio_collective_filtered_chunk_reinsert(have_chunk_to_process ? &chunk_list[i] : NULL, have_chunk_to_process ? 1 : 0, NULL, io_info, - &index_info, mpi_rank, mpi_size) < 0) + dset_info, &index_info, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "couldn't collectively re-insert modified chunks into chunk index") @@ -2346,7 +2443,7 @@ done: H5D_MPIO_TRACE_EXIT(mpi_rank); #endif - FUNC_LEAVE_NOAPI(ret_value) + FUNC_LEAVE_NOAPI_TAG(ret_value) } /* end H5D__multi_chunk_filtered_collective_io() */ /*------------------------------------------------------------------------- @@ -2363,7 +2460,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, H5S_t *file_space, +H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_dset_io_info_t *di, H5S_t *file_space, H5S_t *mem_space) { int mpi_buf_count; /* # of MPI types */ @@ -2379,13 +2476,15 @@ H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf FUNC_ENTER_PACKAGE #ifdef H5Dmpio_DEBUG - mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file); + mpi_rank = H5F_mpi_get_rank(di->dset->oloc.file); H5D_MPIO_TRACE_ENTER(mpi_rank); H5D_MPIO_TIME_START(mpi_rank, "Inter collective I/O"); if (mpi_rank < 0) HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain MPI rank") #endif + HDassert(io_info); + if ((file_space != NULL) && (mem_space != NULL)) { int mpi_file_count; /* Number of file "objects" to transfer */ hsize_t *permute_map = NULL; /* array that holds the mapping from the old, @@ -2394,12 +2493,14 @@ H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf point selection of the file space */ hbool_t is_permuted = FALSE; + HDassert(di); + /* Obtain disk and memory MPI derived datatype */ /* NOTE: The permute_map array can be allocated within H5S_mpio_space_type * and will be fed into the next call to H5S_mpio_space_type * where it will be freed. */ - if (H5S_mpio_space_type(file_space, type_info->src_type_size, &mpi_file_type, &mpi_file_count, + if (H5S_mpio_space_type(file_space, di->type_info.src_type_size, &mpi_file_type, &mpi_file_count, &mft_is_derived, /* OUT: datatype created */ TRUE, /* this is a file space, so permute the datatype if the @@ -2415,7 +2516,7 @@ H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* Sanity check */ if (is_permuted) HDassert(permute_map); - if (H5S_mpio_space_type(mem_space, type_info->src_type_size, &mpi_buf_type, &mpi_buf_count, + if (H5S_mpio_space_type(mem_space, di->type_info.src_type_size, &mpi_buf_type, &mpi_buf_count, &mbt_is_derived, /* OUT: datatype created */ FALSE, /* this is a memory space, so if the file space is not @@ -2449,7 +2550,7 @@ H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf #endif /* Perform final collective I/O operation */ - if (H5D__final_collective_io(io_info, type_info, (hsize_t)mpi_buf_count, mpi_file_type, mpi_buf_type) < 0) + if (H5D__final_collective_io(io_info, (hsize_t)mpi_buf_count, mpi_file_type, mpi_buf_type) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish collective MPI-IO") done: @@ -2481,8 +2582,8 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__final_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t mpi_buf_count, - MPI_Datatype mpi_file_type, MPI_Datatype mpi_buf_type) +H5D__final_collective_io(H5D_io_info_t *io_info, hsize_t mpi_buf_count, MPI_Datatype mpi_file_type, + MPI_Datatype mpi_buf_type) { #ifdef H5Dmpio_DEBUG int mpi_rank; @@ -2492,7 +2593,7 @@ H5D__final_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf FUNC_ENTER_PACKAGE #ifdef H5Dmpio_DEBUG - mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file); + mpi_rank = H5F_mpi_get_rank(io_info->dsets_info[0].dset->oloc.file); H5D_MPIO_TRACE_ENTER(mpi_rank); H5D_MPIO_TIME_START(mpi_rank, "Final collective I/O"); if (mpi_rank < 0) @@ -2504,11 +2605,11 @@ H5D__final_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_inf HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set MPI-I/O collective I/O datatypes") if (io_info->op_type == H5D_IO_OP_WRITE) { - if ((io_info->io_ops.single_write)(io_info, type_info, mpi_buf_count, NULL, NULL) < 0) + if ((io_info->md_io_ops.single_write_md)(io_info, mpi_buf_count, NULL, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed") } /* end if */ else { - if ((io_info->io_ops.single_read)(io_info, type_info, mpi_buf_count, NULL, NULL) < 0) + if ((io_info->md_io_ops.single_read_md)(io_info, mpi_buf_count, NULL, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") } /* end else */ @@ -2523,28 +2624,26 @@ done: } /* end H5D__final_collective_io */ /*------------------------------------------------------------------------- - * Function: H5D__cmp_chunk_addr + * Function: H5D__cmp_piece_addr * - * Purpose: Routine to compare chunk addresses + * Purpose: Routine to compare piece addresses * - * Description: Callback for qsort() to compare chunk addresses + * Description: Callback for qsort() to compare piece addresses * * Return: -1, 0, 1 * - * Programmer: Muqun Yang - * Monday, Feb. 13th, 2006 - * *------------------------------------------------------------------------- */ static int -H5D__cmp_chunk_addr(const void *chunk_addr_info1, const void *chunk_addr_info2) +H5D__cmp_piece_addr(const void *piece_info1, const void *piece_info2) { - haddr_t addr1 = HADDR_UNDEF, addr2 = HADDR_UNDEF; + haddr_t addr1; + haddr_t addr2; FUNC_ENTER_PACKAGE_NOERR - addr1 = ((const H5D_chunk_addr_info_t *)chunk_addr_info1)->chunk_addr; - addr2 = ((const H5D_chunk_addr_info_t *)chunk_addr_info2)->chunk_addr; + addr1 = (*((const H5D_piece_info_t *const *)piece_info1))->faddr; + addr2 = (*((const H5D_piece_info_t *const *)piece_info2))->faddr; FUNC_LEAVE_NOAPI(H5F_addr_cmp(addr1, addr2)) } /* end H5D__cmp_chunk_addr() */ @@ -2705,178 +2804,6 @@ H5D__cmp_chunk_redistribute_info_orig_owner(const void *_entry1, const void *_en } /* end H5D__cmp_chunk_redistribute_info_orig_owner() */ /*------------------------------------------------------------------------- - * 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 - * - * 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, const H5D_chunk_map_t *fm, - H5D_chunk_addr_info_t chunk_addr_info_array[], int sum_chunk, int mpi_rank, int mpi_size) -{ - 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 */ - H5P_coll_md_read_flag_t md_reads_file_flag; - hbool_t md_reads_context_flag; - hbool_t restore_md_reads_state = FALSE; - 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_code; /* MPI return code */ - int i; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_PACKAGE - - /* 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->layout->u.chunk.nchunks * 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 H5Dmpio_DEBUG - H5D_MPIO_DEBUG_VA(mpi_rank, "many_chunk_opt = %d", 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) { -#ifdef H5Dmpio_DEBUG - H5D_MPIO_DEBUG(mpi_rank, "Coming inside H5D_OBTAIN_ALL_CHUNK_ADDR_COL"); -#endif - /* Allocate array for chunk addresses */ - if (NULL == (total_chunk_addr_array = - (haddr_t *)H5MM_malloc(sizeof(haddr_t) * (size_t)fm->layout->u.chunk.nchunks))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory chunk address array") - - if (mpi_rank == 0) { - herr_t result; - - /* - * If enabled, disable collective metadata reads here. - * Since the chunk address mapping is done on rank 0 - * only here, it will cause problems if collective - * metadata reads are enabled. - */ - if (H5F_get_coll_metadata_reads(io_info->dset->oloc.file)) { - md_reads_file_flag = H5P_FORCE_FALSE; - md_reads_context_flag = FALSE; - H5F_set_coll_metadata_reads(io_info->dset->oloc.file, &md_reads_file_flag, - &md_reads_context_flag); - restore_md_reads_state = TRUE; - } - - result = H5D__chunk_addrmap(io_info, total_chunk_addr_array); - - /* Ensure that we restore the old collective metadata reads state */ - if (restore_md_reads_state) { - H5F_set_coll_metadata_reads(io_info->dset->oloc.file, &md_reads_file_flag, - &md_reads_context_flag); - restore_md_reads_state = FALSE; - } - - if (result < 0) { - size_t u; - - /* Clear total chunk address array */ - for (u = 0; u < (size_t)fm->layout->u.chunk.nchunks; u++) - total_chunk_addr_array[u] = HADDR_UNDEF; - - /* Push error, but still participate in following MPI_Bcast */ - HDONE_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, - (int)(sizeof(haddr_t) * fm->layout->u.chunk.nchunks), - MPI_BYTE, (int)0, io_info->comm))) - HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code) - } /* end if */ - - /* Start at first node in chunk skip list */ - i = 0; - if (NULL == (chunk_node = H5SL_first(fm->sel_chunks))) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk node from skipped list") - - /* Iterate over all chunks for this process */ - while (chunk_node) { - if (NULL == (chunk_info = (H5D_chunk_info_t *)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) { - H5D_chunk_ud_t udata; /* User data for querying chunk info */ - - /* Get address of chunk */ - if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skipped list") - chunk_addr = udata.chunk_block.offset; - } /* end if */ - else - chunk_addr = total_chunk_addr_array[chunk_info->index]; - - /* 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; - - /* 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; - - /* Advance to next chunk in list */ - i++; - chunk_node = H5SL_next(chunk_node); - } /* end while */ - -#ifdef H5Dmpio_DEBUG - H5D_MPIO_DEBUG(mpi_rank, "before Qsort"); -#endif - - 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: - /* Re-enable collective metadata reads if we disabled them */ - if (restore_md_reads_state) - H5F_set_coll_metadata_reads(io_info->dset->oloc.file, &md_reads_file_flag, &md_reads_context_flag); - - if (total_chunk_addr_array) - H5MM_xfree(total_chunk_addr_array); - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__sort_chunk() */ - -/*------------------------------------------------------------------------- * Function: H5D__obtain_mpio_mode * * Purpose: Routine to obtain each io mode(collective,independent or none) for each chunk; @@ -2902,7 +2829,7 @@ done: * Parameters: * * Input: H5D_io_info_t* io_info, - * H5D_chunk_map_t *fm,(global chunk map struct) + * H5D_dset_io_info_t *di,(dataset info struct) * Output: uint8_t assign_io_mode[], : IO mode, collective, independent or none * haddr_t chunk_addr[], : chunk address array for each chunk * @@ -2914,7 +2841,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assign_io_mode[], +H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_dset_io_info_t *di, uint8_t assign_io_mode[], haddr_t chunk_addr[], int mpi_rank, int mpi_size) { size_t total_chunks; @@ -2924,7 +2851,7 @@ H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assig uint8_t *mergebuf = NULL; uint8_t *tempbuf; H5SL_node_t *chunk_node; - H5D_chunk_info_t *chunk_info; + H5D_piece_info_t *chunk_info; H5P_coll_md_read_flag_t md_reads_file_flag; hbool_t md_reads_context_flag; hbool_t restore_md_reads_state = FALSE; @@ -2936,17 +2863,19 @@ H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assig FUNC_ENTER_PACKAGE + HDassert(di->layout->type == H5D_CHUNKED); + /* Assign the rank 0 to the root */ root = 0; comm = io_info->comm; /* Setup parameters */ - H5_CHECKED_ASSIGN(total_chunks, size_t, fm->layout->u.chunk.nchunks, hsize_t); + H5_CHECKED_ASSIGN(total_chunks, size_t, di->layout->u.chunk.nchunks, hsize_t); if (H5CX_get_mpio_chunk_opt_ratio(&percent_nproc_per_chunk) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't get percent nproc per chunk") /* if ratio is 0, perform collective io */ if (0 == percent_nproc_per_chunk) { - if (H5D__chunk_addrmap(io_info, chunk_addr) < 0) + if (H5D__chunk_addrmap(di->dset, chunk_addr) < 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; @@ -2967,9 +2896,9 @@ H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assig HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate recv I/O mode info buffer") /* Obtain the regularity and selection information for all chunks in this process. */ - chunk_node = H5SL_first(fm->sel_chunks); + chunk_node = H5SL_first(di->layout_io_info.chunk_map->dset_sel_pieces); while (chunk_node) { - chunk_info = (H5D_chunk_info_t *)H5SL_item(chunk_node); + chunk_info = (H5D_piece_info_t *)H5SL_item(chunk_node); io_mode_info[chunk_info->index] = H5D_CHUNK_SELECT_REG; /* this chunk is selected and is "regular" */ chunk_node = H5SL_next(chunk_node); @@ -2992,11 +2921,10 @@ H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assig * only here, it will cause problems if collective * metadata reads are enabled. */ - if (H5F_get_coll_metadata_reads(io_info->dset->oloc.file)) { + if (H5F_get_coll_metadata_reads(di->dset->oloc.file)) { md_reads_file_flag = H5P_FORCE_FALSE; md_reads_context_flag = FALSE; - H5F_set_coll_metadata_reads(io_info->dset->oloc.file, &md_reads_file_flag, - &md_reads_context_flag); + H5F_set_coll_metadata_reads(di->dset->oloc.file, &md_reads_file_flag, &md_reads_context_flag); restore_md_reads_state = TRUE; } @@ -3006,7 +2934,7 @@ H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assig HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate nproc_per_chunk buffer") /* calculating the chunk address */ - if (H5D__chunk_addrmap(io_info, chunk_addr) < 0) { + if (H5D__chunk_addrmap(di->dset, chunk_addr) < 0) { H5MM_free(nproc_per_chunk); HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address") } /* end if */ @@ -3068,7 +2996,7 @@ H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm, uint8_t assig done: /* Re-enable collective metadata reads if we disabled them */ if (restore_md_reads_state) - H5F_set_coll_metadata_reads(io_info->dset->oloc.file, &md_reads_file_flag, &md_reads_context_flag); + H5F_set_coll_metadata_reads(di->dset->oloc.file, &md_reads_file_flag, &md_reads_context_flag); if (io_mode_info) H5MM_free(io_mode_info); @@ -3098,8 +3026,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - const H5D_chunk_map_t *fm, +H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *di, H5D_filtered_collective_io_info_t **chunk_list, size_t *num_entries, int mpi_rank) { @@ -3113,36 +3040,36 @@ H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const FUNC_ENTER_PACKAGE HDassert(io_info); - HDassert(type_info); - HDassert(fm); + HDassert(di); HDassert(chunk_list); HDassert(num_entries); - #ifdef H5Dmpio_DEBUG H5D_MPIO_TRACE_ENTER(mpi_rank); H5D_MPIO_TIME_START(mpi_rank, "Filtered Collective I/O Setup"); #endif + HDassert(di->layout->type == H5D_CHUNKED); + /* Each rank builds a local list of the chunks they have selected */ - if ((num_chunks_selected = H5SL_count(fm->sel_chunks))) { - H5D_chunk_info_t *chunk_info; + if ((num_chunks_selected = H5SL_count(di->layout_io_info.chunk_map->dset_sel_pieces))) { + H5D_piece_info_t *chunk_info; H5SL_node_t *chunk_node; hsize_t select_npoints; hbool_t need_sort = FALSE; /* Determine whether partial edge chunks should be filtered */ - filter_partial_edge_chunks = !(io_info->dset->shared->layout.u.chunk.flags & - H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS); + filter_partial_edge_chunks = + !(di->dset->shared->layout.u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS); if (NULL == (local_info_array = H5MM_malloc(num_chunks_selected * sizeof(*local_info_array)))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate local io info array buffer") - chunk_node = H5SL_first(fm->sel_chunks); + chunk_node = H5SL_first(di->layout_io_info.chunk_map->dset_sel_pieces); for (i = 0; chunk_node; i++) { - chunk_info = (H5D_chunk_info_t *)H5SL_item(chunk_node); + chunk_info = (H5D_piece_info_t *)H5SL_item(chunk_node); /* Obtain this chunk's address */ - if (H5D__chunk_lookup(io_info->dset, chunk_info->scaled, &udata) < 0) + if (H5D__chunk_lookup(di->dset, chunk_info->scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") /* Initialize rank-local chunk info */ @@ -3154,7 +3081,7 @@ H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const local_info_array[i].buf = NULL; select_npoints = H5S_GET_SELECT_NPOINTS(chunk_info->fspace); - local_info_array[i].io_size = (size_t)select_npoints * type_info->dst_type_size; + local_info_array[i].io_size = (size_t)select_npoints * di->type_info.dst_type_size; /* * Determine whether this chunk will need to be read from the file. If this is @@ -3204,7 +3131,7 @@ H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const local_info_array[i].need_read = TRUE; else { local_info_array[i].need_read = - local_info_array[i].io_size < (size_t)io_info->dset->shared->layout.u.chunk.size; + local_info_array[i].io_size < (size_t)di->dset->shared->layout.u.chunk.size; } local_info_array[i].skip_filter_pline = FALSE; @@ -3213,9 +3140,9 @@ H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const * If this is a partial edge chunk and the "don't filter partial edge * chunks" flag is set, make sure not to apply filters to the chunk. */ - if (H5D__chunk_is_partial_edge_chunk(io_info->dset->shared->ndims, - io_info->dset->shared->layout.u.chunk.dim, - chunk_info->scaled, io_info->dset->shared->curr_dims)) + if (H5D__chunk_is_partial_edge_chunk(di->dset->shared->ndims, + di->dset->shared->layout.u.chunk.dim, chunk_info->scaled, + di->dset->shared->curr_dims)) local_info_array[i].skip_filter_pline = TRUE; } @@ -3244,7 +3171,7 @@ H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const * extensible array code calculated instead of what was calculated * in the chunk file mapping. */ - if (io_info->dset->shared->layout.u.chunk.idx_type == H5D_CHUNK_IDX_EARRAY) + if (di->dset->shared->layout.u.chunk.idx_type == H5D_CHUNK_IDX_EARRAY) local_info_array[i].index_info.chunk_idx = udata.chunk_idx; else local_info_array[i].index_info.chunk_idx = chunk_info->index; @@ -3264,7 +3191,7 @@ H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const H5D__mpio_dump_collective_filtered_chunk_list(local_info_array, num_chunks_selected, mpi_rank); #endif } - else if (H5F_get_coll_metadata_reads(io_info->dset->oloc.file)) { + else if (H5F_get_coll_metadata_reads(di->dset->oloc.file)) { hsize_t scaled[H5O_LAYOUT_NDIMS] = {0}; /* @@ -3281,7 +3208,7 @@ H5D__mpio_collective_filtered_chunk_io_setup(const H5D_io_info_t *io_info, const * callback that can be used to ensure collectivity between ranks * in a more natural way, but this hack should suffice for now. */ - if (H5D__chunk_lookup(io_info->dset, scaled, &udata) < 0) + if (H5D__chunk_lookup(di->dset, scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") } @@ -3320,8 +3247,7 @@ done: static herr_t H5D__mpio_redistribute_shared_chunks(H5D_filtered_collective_io_info_t *chunk_list, size_t chunk_list_num_entries, const H5D_io_info_t *io_info, - const H5D_chunk_map_t *fm, int mpi_rank, int mpi_size, - size_t **rank_chunks_assigned_map) + int mpi_rank, int mpi_size, size_t **rank_chunks_assigned_map) { hbool_t redistribute_on_all_ranks; size_t *num_chunks_map = NULL; @@ -3334,7 +3260,6 @@ H5D__mpio_redistribute_shared_chunks(H5D_filtered_collective_io_info_t *chunk_li HDassert(chunk_list || 0 == chunk_list_num_entries); HDassert(io_info); - HDassert(fm); HDassert(mpi_size > 1); /* No chunk sharing is possible for MPI Comm size of 1 */ #ifdef H5Dmpio_DEBUG @@ -3368,7 +3293,7 @@ H5D__mpio_redistribute_shared_chunks(H5D_filtered_collective_io_info_t *chunk_li redistribute_on_all_ranks = coll_chunk_list_size < H5D_CHUNK_REDISTRIBUTE_THRES; if (H5D__mpio_redistribute_shared_chunks_int(chunk_list, num_chunks_map, redistribute_on_all_ranks, - io_info, fm, mpi_rank, mpi_size) < 0) + io_info, mpi_rank, mpi_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTREDISTRIBUTE, FAIL, "can't redistribute shared chunks") /* @@ -3458,9 +3383,7 @@ done: static herr_t H5D__mpio_redistribute_shared_chunks_int(H5D_filtered_collective_io_info_t *chunk_list, size_t *num_chunks_assigned_map, hbool_t all_ranks_involved, - const H5D_io_info_t *io_info, - const H5D_chunk_map_t H5_ATTR_NDEBUG_UNUSED *fm, int mpi_rank, - int mpi_size) + const H5D_io_info_t *io_info, int mpi_rank, int mpi_size) { MPI_Datatype struct_type; MPI_Datatype packed_type; @@ -3481,7 +3404,6 @@ H5D__mpio_redistribute_shared_chunks_int(H5D_filtered_collective_io_info_t *chun HDassert(num_chunks_assigned_map); HDassert(chunk_list || 0 == num_chunks_assigned_map[mpi_rank]); HDassert(io_info); - HDassert(fm); HDassert(mpi_size > 1); #ifdef H5Dmpio_DEBUG @@ -3789,7 +3711,7 @@ done: static herr_t H5D__mpio_share_chunk_modification_data(H5D_filtered_collective_io_info_t *chunk_list, size_t *chunk_list_num_entries, H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, int mpi_rank, + H5D_dset_io_info_t *dset_info, int mpi_rank, int H5_ATTR_NDEBUG_UNUSED mpi_size, H5D_filtered_collective_io_info_t **chunk_hash_table, unsigned char ***chunk_msg_bufs, int *chunk_msg_bufs_len) @@ -3818,7 +3740,7 @@ H5D__mpio_share_chunk_modification_data(H5D_filtered_collective_io_info_t *chunk HDassert(chunk_list_num_entries); HDassert(chunk_list || 0 == *chunk_list_num_entries); HDassert(io_info); - HDassert(type_info); + HDassert(dset_info); HDassert(mpi_size > 1); HDassert(chunk_msg_bufs); HDassert(chunk_msg_bufs_len); @@ -3891,7 +3813,7 @@ H5D__mpio_share_chunk_modification_data(H5D_filtered_collective_io_info_t *chunk last_assigned_idx++; } else { - H5D_chunk_info_t *chunk_info = chunk_entry->chunk_info; + H5D_piece_info_t *chunk_info = chunk_entry->chunk_info; unsigned char *mod_data_p = NULL; hsize_t iter_nelmts; size_t mod_data_size = 0; @@ -3909,7 +3831,7 @@ H5D__mpio_share_chunk_modification_data(H5D_filtered_collective_io_info_t *chunk iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace); H5_CHECK_OVERFLOW(iter_nelmts, hsize_t, size_t); - mod_data_size += (size_t)iter_nelmts * type_info->src_type_size; + mod_data_size += (size_t)iter_nelmts * dset_info->type_info.src_type_size; if (NULL == (msg_send_bufs[num_send_requests] = H5MM_malloc(mod_data_size))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, @@ -3926,14 +3848,14 @@ H5D__mpio_share_chunk_modification_data(H5D_filtered_collective_io_info_t *chunk HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "unable to encode dataspace") /* Initialize iterator for memory selection */ - if (H5S_select_iter_init(mem_iter, chunk_info->mspace, type_info->src_type_size, + if (H5S_select_iter_init(mem_iter, chunk_info->mspace, dset_info->type_info.src_type_size, H5S_SEL_ITER_SHARE_WITH_DATASPACE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; /* Collect the modification data into the buffer */ - if (0 == H5D__gather_mem(io_info->u.wbuf, mem_iter, (size_t)iter_nelmts, mod_data_p)) + if (0 == H5D__gather_mem(dset_info->buf.cvp, mem_iter, (size_t)iter_nelmts, mod_data_p)) HGOTO_ERROR(H5E_IO, H5E_CANTGATHER, FAIL, "couldn't gather from write buffer") /* @@ -4202,10 +4124,9 @@ done: static herr_t H5D__mpio_collective_filtered_chunk_common_io(H5D_filtered_collective_io_info_t *chunk_list, size_t chunk_list_num_entries, const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, int mpi_size) + int mpi_size) { H5D_io_info_t coll_io_info; - H5D_storage_t ctg_store; MPI_Datatype file_type = MPI_DATATYPE_NULL; MPI_Datatype mem_type = MPI_DATATYPE_NULL; hbool_t mem_type_is_derived = FALSE; @@ -4222,7 +4143,6 @@ H5D__mpio_collective_filtered_chunk_common_io(H5D_filtered_collective_io_info_t HDassert(chunk_list || 0 == chunk_list_num_entries); HDassert(io_info); - HDassert(type_info); /* Initialize temporary I/O info */ coll_io_info = *io_info; @@ -4258,9 +4178,7 @@ H5D__mpio_collective_filtered_chunk_common_io(H5D_filtered_collective_io_info_t /* * If this rank doesn't have a selection, it can - * skip I/O if independent I/O was requested at - * the low level, or if the MPI communicator size - * is 1. + * skip I/O if the MPI communicator size is 1. * * Otherwise, this rank has to participate in * collective I/O, but probably has a NULL buf @@ -4268,20 +4186,13 @@ H5D__mpio_collective_filtered_chunk_common_io(H5D_filtered_collective_io_info_t * write/read function expects one. */ if (num_chunks == 0) { - H5FD_mpio_collective_opt_t coll_opt_mode; - - /* Get the collective_opt property to check whether the application wants to do IO individually. */ - if (H5CX_get_mpio_coll_opt(&coll_opt_mode) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O collective_opt property") - - if ((mpi_size == 1) || (H5FD_MPIO_INDIVIDUAL_IO == coll_opt_mode)) { + if (mpi_size == 1) HGOTO_DONE(SUCCEED) - } else { if (io_info->op_type == H5D_IO_OP_WRITE) - coll_io_info.u.wbuf = &fake_buf; + coll_io_info.base_maddr.cvp = &fake_buf; else - coll_io_info.u.rbuf = &fake_buf; + coll_io_info.base_maddr.vp = &fake_buf; } } @@ -4297,18 +4208,15 @@ H5D__mpio_collective_filtered_chunk_common_io(H5D_filtered_collective_io_info_t * to be the first chunk's file address */ if (io_info->op_type == H5D_IO_OP_WRITE) - ctg_store.contig.dset_addr = chunk_list[0].chunk_new.offset; + coll_io_info.store_faddr = chunk_list[0].chunk_new.offset; else - ctg_store.contig.dset_addr = base_read_offset; + coll_io_info.store_faddr = base_read_offset; } else - ctg_store.contig.dset_addr = 0; - - ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size; - coll_io_info.store = &ctg_store; + coll_io_info.store_faddr = 0; /* Perform I/O */ - if (H5D__final_collective_io(&coll_io_info, type_info, mpi_buf_count, file_type, mem_type) < 0) + if (H5D__final_collective_io(&coll_io_info, mpi_buf_count, file_type, mem_type) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't finish MPI I/O") done: @@ -4335,10 +4243,10 @@ done: static herr_t H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chunk_list, size_t chunk_list_num_entries, const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, int mpi_rank, int mpi_size) + const H5D_dset_io_info_t *di, int mpi_rank, int mpi_size) { H5D_fill_buf_info_t fb_info; - H5D_chunk_info_t *chunk_info = NULL; + H5D_piece_info_t *chunk_info = NULL; H5D_io_info_t coll_io_info; H5Z_EDC_t err_detect; /* Error detection info */ H5Z_cb_t filter_cb; /* I/O filter callback function */ @@ -4356,7 +4264,7 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun HDassert(chunk_list || 0 == chunk_list_num_entries); HDassert(io_info); - HDassert(type_info); + HDassert(di); #ifdef H5Dmpio_DEBUG H5D_MPIO_TRACE_ENTER(mpi_rank); @@ -4366,8 +4274,8 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun #endif /* Initialize temporary I/O info */ - coll_io_info = *io_info; - coll_io_info.u.rbuf = NULL; + coll_io_info = *io_info; + coll_io_info.base_maddr.vp = NULL; if (chunk_list_num_entries) { /* Retrieve filter settings from API context */ @@ -4377,12 +4285,12 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get I/O filter callback function") /* Set size of full chunks in dataset */ - file_chunk_size = io_info->dset->shared->layout.u.chunk.size; + file_chunk_size = di->dset->shared->layout.u.chunk.size; /* Determine if fill values should be "read" for unallocated chunks */ - should_fill = (io_info->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC) || - ((io_info->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET) && - io_info->dset->shared->dcpl_cache.fill.fill_defined); + should_fill = (di->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC) || + ((di->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET) && + di->dset->shared->dcpl_cache.fill.fill_defined); } /* @@ -4436,22 +4344,21 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun if (!fb_info_init) { hsize_t chunk_dims[H5S_MAX_RANK]; - HDassert(io_info->dset->shared->ndims == io_info->dset->shared->layout.u.chunk.ndims - 1); - for (size_t j = 0; j < io_info->dset->shared->layout.u.chunk.ndims - 1; j++) - chunk_dims[j] = (hsize_t)io_info->dset->shared->layout.u.chunk.dim[j]; + HDassert(di->dset->shared->ndims == di->dset->shared->layout.u.chunk.ndims - 1); + for (size_t j = 0; j < di->dset->shared->layout.u.chunk.ndims - 1; j++) + chunk_dims[j] = (hsize_t)di->dset->shared->layout.u.chunk.dim[j]; /* Get a dataspace for filling chunk memory buffers */ - if (NULL == (fill_space = H5S_create_simple( - io_info->dset->shared->layout.u.chunk.ndims - 1, chunk_dims, NULL))) + if (NULL == (fill_space = H5S_create_simple(di->dset->shared->layout.u.chunk.ndims - 1, + chunk_dims, NULL))) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create chunk fill dataspace") /* Initialize fill value buffer */ - if (H5D__fill_init(&fb_info, NULL, (H5MM_allocate_t)H5D__chunk_mem_alloc, - (void *)&io_info->dset->shared->dcpl_cache.pline, - (H5MM_free_t)H5D__chunk_mem_free, - (void *)&io_info->dset->shared->dcpl_cache.pline, - &io_info->dset->shared->dcpl_cache.fill, io_info->dset->shared->type, - io_info->dset->shared->type_id, 0, file_chunk_size) < 0) + if (H5D__fill_init( + &fb_info, NULL, (H5MM_allocate_t)H5D__chunk_mem_alloc, + (void *)&di->dset->shared->dcpl_cache.pline, (H5MM_free_t)H5D__chunk_mem_free, + (void *)&di->dset->shared->dcpl_cache.pline, &di->dset->shared->dcpl_cache.fill, + di->dset->shared->type, di->dset->shared->type_id, 0, file_chunk_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill value buffer") fb_info_init = TRUE; @@ -4459,8 +4366,8 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun /* Write fill value to memory buffer */ HDassert(fb_info.fill_buf); - if (H5D__fill(fb_info.fill_buf, io_info->dset->shared->type, chunk_list[i].buf, - type_info->mem_type, fill_space) < 0) + if (H5D__fill(fb_info.fill_buf, di->dset->shared->type, chunk_list[i].buf, + di->type_info.mem_type, fill_space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "couldn't fill chunk buffer with fill value") } } @@ -4472,8 +4379,8 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun * read of chunks is essentially a no-op, so avoid it here. */ index_empty = FALSE; - if (io_info->dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_INCR) - if (H5D__chunk_index_empty(io_info->dset, &index_empty) < 0) + if (di->dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_INCR) + if (H5D__chunk_index_empty(di->dset, &index_empty) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't determine if chunk index is empty") if (!index_empty) { @@ -4482,11 +4389,11 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun * the first chunk data buffer being read into */ if (base_read_buf) - coll_io_info.u.rbuf = base_read_buf; + coll_io_info.base_maddr.vp = base_read_buf; /* Perform collective chunk read */ if (H5D__mpio_collective_filtered_chunk_common_io(chunk_list, chunk_list_num_entries, &coll_io_info, - type_info, mpi_size) < 0) + mpi_size) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't finish collective filtered chunk read") } @@ -4499,7 +4406,7 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun /* Unfilter the chunk, unless we didn't read it from the file */ if (chunk_list[i].need_read && !chunk_list[i].skip_filter_pline) { - if (H5Z_pipeline(&io_info->dset->shared->dcpl_cache.pline, H5Z_FLAG_REVERSE, + if (H5Z_pipeline(&di->dset->shared->dcpl_cache.pline, H5Z_FLAG_REVERSE, &(chunk_list[i].index_info.filter_mask), err_detect, filter_cb, (size_t *)&chunk_list[i].chunk_new.length, &chunk_list[i].chunk_buf_size, &chunk_list[i].buf) < 0) @@ -4509,8 +4416,8 @@ H5D__mpio_collective_filtered_chunk_read(H5D_filtered_collective_io_info_t *chun /* Scatter the chunk data to the read buffer */ iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->fspace); - if (H5D_select_io_mem(io_info->u.rbuf, chunk_info->mspace, chunk_list[i].buf, chunk_info->fspace, - type_info->src_type_size, (size_t)iter_nelmts) < 0) + if (H5D_select_io_mem(di->buf.vp, chunk_info->mspace, chunk_list[i].buf, chunk_info->fspace, + di->type_info.src_type_size, (size_t)iter_nelmts) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "couldn't copy chunk data to read buffer") } @@ -4554,39 +4461,44 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch size_t chunk_list_num_entries, H5D_filtered_collective_io_info_t *chunk_hash_table, unsigned char **chunk_msg_bufs, int chunk_msg_bufs_len, - const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + const H5D_io_info_t *io_info, const H5D_dset_io_info_t *di, int H5_ATTR_NDEBUG_UNUSED mpi_rank, int mpi_size) { - H5D_fill_buf_info_t fb_info; - H5D_chunk_info_t *chunk_info = NULL; - H5S_sel_iter_t *sel_iter = NULL; /* Dataspace selection iterator for H5D__scatter_mem */ - H5D_io_info_t coll_io_info; - H5Z_EDC_t err_detect; /* Error detection info */ - H5Z_cb_t filter_cb; /* I/O filter callback function */ - hsize_t file_chunk_size = 0; - hsize_t iter_nelmts; /* Number of points to iterate over for the chunk IO operation */ - hbool_t should_fill = FALSE; - hbool_t fb_info_init = FALSE; - hbool_t sel_iter_init = FALSE; - hbool_t index_empty = FALSE; - size_t i; - H5S_t *dataspace = NULL; - H5S_t *fill_space = NULL; - void *base_read_buf = NULL; - herr_t ret_value = SUCCEED; + const H5D_type_info_t *type_info = NULL; + H5D_fill_buf_info_t fb_info; + H5D_piece_info_t *chunk_info = NULL; + H5S_sel_iter_t *sel_iter = NULL; /* Dataspace selection iterator for H5D__scatter_mem */ + H5D_io_info_t coll_io_info; + H5Z_EDC_t err_detect; /* Error detection info */ + H5Z_cb_t filter_cb; /* I/O filter callback function */ + hsize_t file_chunk_size = 0; + hsize_t iter_nelmts; /* Number of points to iterate over for the chunk IO operation */ + hbool_t should_fill = FALSE; + hbool_t fb_info_init = FALSE; + hbool_t sel_iter_init = FALSE; + hbool_t index_empty = FALSE; + size_t i; + H5S_t *dataspace = NULL; + H5S_t *fill_space = NULL; + void *base_read_buf = NULL; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE HDassert(chunk_list || 0 == chunk_list_num_entries); HDassert((chunk_msg_bufs && chunk_hash_table) || 0 == chunk_msg_bufs_len); HDassert(io_info); - HDassert(type_info); + HDassert(di); #ifdef H5Dmpio_DEBUG H5D_MPIO_TRACE_ENTER(mpi_rank); H5D_MPIO_TIME_START(mpi_rank, "Filtered collective chunk update"); #endif + /* Set convenience pointers */ + type_info = &(di->type_info); + HDassert(type_info); + if (chunk_list_num_entries) { /* Retrieve filter settings from API context */ if (H5CX_get_err_detect(&err_detect) < 0) @@ -4595,12 +4507,12 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get I/O filter callback function") /* Set size of full chunks in dataset */ - file_chunk_size = io_info->dset->shared->layout.u.chunk.size; + file_chunk_size = di->dset->shared->layout.u.chunk.size; /* Determine if fill values should be written to chunks */ - should_fill = (io_info->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC) || - ((io_info->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET) && - io_info->dset->shared->dcpl_cache.fill.fill_defined); + should_fill = (di->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC) || + ((di->dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET) && + di->dset->shared->dcpl_cache.fill.fill_defined); } /* @@ -4672,25 +4584,23 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch if (!fb_info_init) { hsize_t chunk_dims[H5S_MAX_RANK]; - HDassert(io_info->dset->shared->ndims == - io_info->dset->shared->layout.u.chunk.ndims - 1); - for (size_t j = 0; j < io_info->dset->shared->layout.u.chunk.ndims - 1; j++) - chunk_dims[j] = (hsize_t)io_info->dset->shared->layout.u.chunk.dim[j]; + HDassert(di->dset->shared->ndims == di->dset->shared->layout.u.chunk.ndims - 1); + for (size_t j = 0; j < di->dset->shared->layout.u.chunk.ndims - 1; j++) + chunk_dims[j] = (hsize_t)di->dset->shared->layout.u.chunk.dim[j]; /* Get a dataspace for filling chunk memory buffers */ if (NULL == (fill_space = H5S_create_simple( - io_info->dset->shared->layout.u.chunk.ndims - 1, chunk_dims, NULL))) + di->dset->shared->layout.u.chunk.ndims - 1, chunk_dims, NULL))) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create chunk fill dataspace") /* Initialize fill value buffer */ if (H5D__fill_init(&fb_info, NULL, (H5MM_allocate_t)H5D__chunk_mem_alloc, - (void *)&io_info->dset->shared->dcpl_cache.pline, + (void *)&di->dset->shared->dcpl_cache.pline, (H5MM_free_t)H5D__chunk_mem_free, - (void *)&io_info->dset->shared->dcpl_cache.pline, - &io_info->dset->shared->dcpl_cache.fill, - io_info->dset->shared->type, io_info->dset->shared->type_id, 0, - file_chunk_size) < 0) + (void *)&di->dset->shared->dcpl_cache.pline, + &di->dset->shared->dcpl_cache.fill, di->dset->shared->type, + di->dset->shared->type_id, 0, file_chunk_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill value buffer") fb_info_init = TRUE; @@ -4698,7 +4608,7 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch /* Write fill value to memory buffer */ HDassert(fb_info.fill_buf); - if (H5D__fill(fb_info.fill_buf, io_info->dset->shared->type, chunk_list[i].buf, + if (H5D__fill(fb_info.fill_buf, di->dset->shared->type, chunk_list[i].buf, type_info->mem_type, fill_space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "couldn't fill chunk buffer with fill value") @@ -4715,8 +4625,8 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch * read of chunks is essentially a no-op, so avoid it here. */ index_empty = FALSE; - if (io_info->dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_INCR) - if (H5D__chunk_index_empty(io_info->dset, &index_empty) < 0) + if (di->dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_INCR) + if (H5D__chunk_index_empty(di->dset, &index_empty) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "couldn't determine if chunk index is empty") if (!index_empty) { @@ -4731,12 +4641,13 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch /* Override the read buffer to point to the address of the first * chunk data buffer being read into */ - if (base_read_buf) - coll_io_info.u.rbuf = base_read_buf; + if (base_read_buf) { + coll_io_info.base_maddr.vp = base_read_buf; + } /* Read all chunks that need to be read from the file */ if (H5D__mpio_collective_filtered_chunk_common_io(chunk_list, chunk_list_num_entries, &coll_io_info, - type_info, mpi_size) < 0) + mpi_size) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't finish collective filtered chunk read") } @@ -4756,7 +4667,7 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch * the file, so we need to unfilter it */ if (chunk_list[i].need_read && !chunk_list[i].skip_filter_pline) { - if (H5Z_pipeline(&io_info->dset->shared->dcpl_cache.pline, H5Z_FLAG_REVERSE, + if (H5Z_pipeline(&di->dset->shared->dcpl_cache.pline, H5Z_FLAG_REVERSE, &(chunk_list[i].index_info.filter_mask), err_detect, filter_cb, (size_t *)&chunk_list[i].chunk_new.length, &chunk_list[i].chunk_buf_size, &chunk_list[i].buf) < 0) @@ -4765,7 +4676,7 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace); - if (H5D_select_io_mem(chunk_list[i].buf, chunk_info->fspace, io_info->u.wbuf, chunk_info->mspace, + if (H5D_select_io_mem(chunk_list[i].buf, chunk_info->fspace, di->buf.cvp, chunk_info->mspace, type_info->dst_type_size, (size_t)iter_nelmts) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "couldn't copy chunk data to write buffer") } @@ -4834,10 +4745,9 @@ H5D__mpio_collective_filtered_chunk_update(H5D_filtered_collective_io_info_t *ch /* Finally, filter all the chunks */ for (i = 0; i < chunk_list_num_entries; i++) { if (!chunk_list[i].skip_filter_pline) { - if (H5Z_pipeline(&io_info->dset->shared->dcpl_cache.pline, 0, - &(chunk_list[i].index_info.filter_mask), err_detect, filter_cb, - (size_t *)&chunk_list[i].chunk_new.length, &chunk_list[i].chunk_buf_size, - &chunk_list[i].buf) < 0) + if (H5Z_pipeline(&di->dset->shared->dcpl_cache.pline, 0, &(chunk_list[i].index_info.filter_mask), + err_detect, filter_cb, (size_t *)&chunk_list[i].chunk_new.length, + &chunk_list[i].chunk_buf_size, &chunk_list[i].buf) < 0) HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "output pipeline failed") } @@ -5088,8 +4998,8 @@ done: static herr_t H5D__mpio_collective_filtered_chunk_reinsert(H5D_filtered_collective_io_info_t *chunk_list, size_t chunk_list_num_entries, size_t *num_chunks_assigned_map, - H5D_io_info_t *io_info, H5D_chk_idx_info_t *idx_info, - int mpi_rank, int mpi_size) + H5D_io_info_t *io_info, H5D_dset_io_info_t *di, + H5D_chk_idx_info_t *idx_info, int mpi_rank, int mpi_size) { H5D_chunk_ud_t chunk_ud; MPI_Datatype send_type; @@ -5110,6 +5020,7 @@ H5D__mpio_collective_filtered_chunk_reinsert(H5D_filtered_collective_io_info_t * HDassert(chunk_list || 0 == chunk_list_num_entries); HDassert(io_info); + HDassert(di); HDassert(idx_info); #ifdef H5Dmpio_DEBUG @@ -5219,17 +5130,17 @@ H5D__mpio_collective_filtered_chunk_reinsert(H5D_filtered_collective_io_info_t * * callback that accepts a chunk index and provides the * caller with the scaled coordinates for that chunk. */ - H5VM_array_calc_pre(chunk_ud.chunk_idx, io_info->dset->shared->ndims, + H5VM_array_calc_pre(chunk_ud.chunk_idx, di->dset->shared->ndims, idx_info->layout->u.earray.swizzled_down_chunks, scaled_coords); H5VM_unswizzle_coords(hsize_t, scaled_coords, idx_info->layout->u.earray.unlim_dim); } else { - H5VM_array_calc_pre(chunk_ud.chunk_idx, io_info->dset->shared->ndims, - io_info->dset->shared->layout.u.chunk.down_chunks, scaled_coords); + H5VM_array_calc_pre(chunk_ud.chunk_idx, di->dset->shared->ndims, + di->dset->shared->layout.u.chunk.down_chunks, scaled_coords); } - scaled_coords[io_info->dset->shared->ndims] = 0; + scaled_coords[di->dset->shared->ndims] = 0; #ifndef NDEBUG /* @@ -5243,7 +5154,7 @@ H5D__mpio_collective_filtered_chunk_reinsert(H5D_filtered_collective_io_info_t * for (size_t dbg_idx = 0; dbg_idx < chunk_list_num_entries; dbg_idx++) { if (coll_entry->index_info.chunk_idx == chunk_list[dbg_idx].index_info.chunk_idx) { hbool_t coords_match = !HDmemcmp(scaled_coords, chunk_list[dbg_idx].chunk_info->scaled, - io_info->dset->shared->ndims * sizeof(hsize_t)); + di->dset->shared->ndims * sizeof(hsize_t)); HDassert(coords_match && "Calculated scaled coordinates for chunk didn't match " "chunk's actual scaled coordinates!"); @@ -5252,7 +5163,7 @@ H5D__mpio_collective_filtered_chunk_reinsert(H5D_filtered_collective_io_info_t * } #endif - if ((idx_info->storage->ops->insert)(idx_info, &chunk_ud, io_info->dset) < 0) + if ((idx_info->storage->ops->insert)(idx_info, &chunk_ud, di->dset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk address into index") } diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 0b98ce7..557d745 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -33,6 +33,7 @@ #include "H5ACprivate.h" /* Metadata cache */ #include "H5B2private.h" /* v2 B-trees */ #include "H5Fprivate.h" /* File access */ +#include "H5FLprivate.h" /* Free Lists */ #include "H5Gprivate.h" /* Groups */ #include "H5SLprivate.h" /* Skip lists */ #include "H5Tprivate.h" /* Datatypes */ @@ -44,20 +45,6 @@ /* Set the minimum object header size to create objects with */ #define H5D_MINHDR_SIZE 256 -/* [Simple] Macro to construct a H5D_io_info_t from it's components */ -#define H5D_BUILD_IO_INFO_WRT(io_info, ds, str, buf) \ - (io_info)->dset = ds; \ - (io_info)->f_sh = H5F_SHARED((ds)->oloc.file); \ - (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, str, buf) \ - (io_info)->dset = ds; \ - (io_info)->f_sh = H5F_SHARED((ds)->oloc.file); \ - (io_info)->store = str; \ - (io_info)->op_type = H5D_IO_OP_READ; \ - (io_info)->u.rbuf = buf - /* Flags for marking aspects of a dataset dirty */ #define H5D_MARK_SPACE 0x01 #define H5D_MARK_LAYOUT 0x02 @@ -83,6 +70,9 @@ #define H5D_BT2_SPLIT_PERC 100 #define H5D_BT2_MERGE_PERC 40 +/* Macro to determine if the layout I/O callback should perform I/O */ +#define H5D_LAYOUT_CB_PERFORM_IO(IO_INFO) (!(IO_INFO)->use_select_io || (IO_INFO)->count == 1) + /****************************/ /* Package Private Typedefs */ /****************************/ @@ -97,23 +87,20 @@ typedef struct H5D_type_info_t { 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 */ - const H5T_subset_info_t *cmpd_subset; /* Info related to the compound subset conversion functions */ - 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 */ + size_t src_type_size; /* Size of source type */ + size_t dst_type_size; /* Size of 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 */ + const H5T_subset_info_t *cmpd_subset; /* Info related to the compound subset conversion functions */ + H5T_bkg_t need_bkg; /* Type of background buf needed */ + size_t request_nelmts; /* Requested strip mine */ + 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; -struct H5D_chunk_map_t; +struct H5D_dset_io_info_t; typedef struct H5D_shared_t H5D_shared_t; /* Function pointers for I/O on particular types of dataset layouts */ @@ -121,27 +108,27 @@ typedef herr_t (*H5D_layout_construct_func_t)(H5F_t *f, H5D_t *dset); typedef herr_t (*H5D_layout_init_func_t)(H5F_t *f, const H5D_t *dset, hid_t dapl_id); typedef hbool_t (*H5D_layout_is_space_alloc_func_t)(const H5O_storage_t *storage); typedef hbool_t (*H5D_layout_is_data_cached_func_t)(const H5D_shared_t *shared_dset); -typedef herr_t (*H5D_layout_io_init_func_t)(struct H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space, - struct H5D_chunk_map_t *cm); -typedef herr_t (*H5D_layout_read_func_t)(struct H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space, - struct H5D_chunk_map_t *fm); -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, H5S_t *file_space, 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, +typedef herr_t (*H5D_layout_io_init_func_t)(struct H5D_io_info_t *io_info, struct H5D_dset_io_info_t *dinfo); +typedef herr_t (*H5D_layout_mdio_init_func_t)(struct H5D_io_info_t *io_info, + struct H5D_dset_io_info_t *dinfo); +typedef herr_t (*H5D_layout_read_func_t)(struct H5D_io_info_t *io_info, struct H5D_dset_io_info_t *dinfo); +typedef herr_t (*H5D_layout_write_func_t)(struct H5D_io_info_t *io_info, struct H5D_dset_io_info_t *dinfo); +typedef herr_t (*H5D_layout_read_md_func_t)(struct H5D_io_info_t *io_info); +typedef herr_t (*H5D_layout_write_md_func_t)(struct H5D_io_info_t *io_info); +typedef ssize_t (*H5D_layout_readvv_func_t)(const struct H5D_io_info_t *io_info, + const struct H5D_dset_io_info_t *dset_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[]); -typedef ssize_t (*H5D_layout_writevv_func_t)(const struct H5D_io_info_t *io_info, size_t dset_max_nseq, +typedef ssize_t (*H5D_layout_writevv_func_t)(const struct H5D_io_info_t *io_info, + const struct H5D_dset_io_info_t *dset_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[]); typedef herr_t (*H5D_layout_flush_func_t)(H5D_t *dataset); -typedef herr_t (*H5D_layout_io_term_func_t)(const struct H5D_chunk_map_t *cm); +typedef herr_t (*H5D_layout_io_term_func_t)(struct H5D_io_info_t *io_info, struct H5D_dset_io_info_t *di); typedef herr_t (*H5D_layout_dest_func_t)(H5D_t *dataset); /* Typedef for grouping layout I/O routines */ @@ -152,27 +139,28 @@ typedef struct H5D_layout_ops_t { H5D_layout_is_data_cached_func_t is_data_cached; /* Query routine to determine if any raw data is cached. If routine is not present then the layout type never caches raw data. */ - H5D_layout_io_init_func_t io_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_flush_func_t flush; /* Low-level I/O routine for flushing raw data */ - H5D_layout_io_term_func_t io_term; /* I/O shutdown routine */ - H5D_layout_dest_func_t dest; /* Destroy layout info */ + H5D_layout_io_init_func_t io_init; /* I/O initialization routine */ + H5D_layout_mdio_init_func_t mdio_init; /* Multi Dataset I/O initialization routine - called after all + datasets have done io_init and sel_pieces has been allocated */ + 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 */ + 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_flush_func_t flush; /* Low-level I/O routine for flushing raw data */ + H5D_layout_io_term_func_t io_term; /* I/O shutdown routine for multi-dset */ + H5D_layout_dest_func_t dest; /* Destroy layout info */ } 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, - H5S_t *file_space, 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, - H5S_t *file_space, H5S_t *mem_space); +typedef herr_t (*H5D_io_single_read_func_t)(const struct H5D_io_info_t *io_info, + const struct H5D_dset_io_info_t *dset_info); +typedef herr_t (*H5D_io_single_write_func_t)(const struct H5D_io_info_t *io_info, + const struct H5D_dset_io_info_t *dset_info); + +typedef herr_t (*H5D_io_single_read_md_func_t)(const struct H5D_io_info_t *io_info, hsize_t nelmts, + H5S_t *file_space, H5S_t *mem_space); +typedef herr_t (*H5D_io_single_write_md_func_t)(const struct H5D_io_info_t *io_info, hsize_t nelmts, + H5S_t *file_space, H5S_t *mem_space); /* Typedef for raw data I/O framework info */ typedef struct H5D_io_ops_t { @@ -182,6 +170,14 @@ typedef struct H5D_io_ops_t { H5D_io_single_write_func_t single_write; /* I/O routine for writing single block */ } H5D_io_ops_t; +/* Typedef for raw data I/O framework info (multi-dataset I/O) */ +typedef struct H5D_md_io_ops_t { + H5D_layout_read_md_func_t multi_read_md; /* High-level I/O routine for reading data for multi-dset */ + H5D_layout_write_md_func_t multi_write_md; /* High-level I/O routine for writing data for multi-dset */ + H5D_io_single_read_md_func_t single_read_md; /* I/O routine for reading single block for multi-dset */ + H5D_io_single_write_md_func_t single_write_md; /* I/O routine for writing single block for multi-dset */ +} H5D_md_io_ops_t; + /* Typedefs for dataset storage information */ typedef struct { haddr_t dset_addr; /* Address of dataset in file */ @@ -210,25 +206,79 @@ typedef enum H5D_io_op_type_t { H5D_IO_OP_WRITE /* Write operation */ } H5D_io_op_type_t; +/* Piece info for a data chunk/block during I/O */ +typedef struct H5D_piece_info_t { + haddr_t faddr; /* File address */ + hsize_t index; /* "Index" of chunk in dataset */ + hsize_t piece_points; /* Number of elements selected in piece */ + hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Scaled coordinates of chunk (in file dataset's dataspace) */ + H5S_t *fspace; /* Dataspace describing chunk & selection in it */ + unsigned fspace_shared; /* Indicate that the file space for a chunk is shared and shouldn't be freed */ + H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */ + unsigned mspace_shared; /* Indicate that the memory space for a chunk is shared and shouldn't be freed */ + struct H5D_dset_io_info_t *dset_info; /* Pointer to dset_info */ +} H5D_piece_info_t; + +/* I/O info for a single dataset */ +typedef struct H5D_dset_io_info_t { + H5D_t *dset; /* Pointer to dataset being operated on */ + H5D_storage_t *store; /* Dataset storage info */ + H5D_layout_ops_t layout_ops; /* Dataset layout I/O operation function pointers */ + H5_flexible_const_ptr_t buf; /* Buffer pointer */ + + H5D_io_ops_t io_ops; /* I/O operations for this dataset */ + + H5O_layout_t *layout; /* Dataset layout information*/ + hsize_t nelmts; /* Number of elements selected in file & memory dataspaces */ + + H5S_t *file_space; /* Pointer to the file dataspace */ + H5S_t *mem_space; /* Pointer to the memory dataspace */ + + union { + struct H5D_chunk_map_t *chunk_map; /* Chunk specific I/O info */ + H5D_piece_info_t *contig_piece_info; /* Piece info for contiguous dataset */ + } layout_io_info; + + hid_t mem_type_id; /* memory datatype ID */ + H5D_type_info_t type_info; + hbool_t skip_io; /* Whether to skip I/O for this dataset */ +} H5D_dset_io_info_t; + +/* I/O info for entire I/O operation */ typedef struct H5D_io_info_t { - const H5D_t *dset; /* Pointer to dataset being operated on */ - /* QAK: Delete the f_sh field when oloc has a shared file pointer? */ + /* QAK: Delete the f_sh field when oloc has a shared file pointer? */ H5F_shared_t *f_sh; /* Pointer to shared file struct that dataset is within */ #ifdef H5_HAVE_PARALLEL - MPI_Comm comm; /* MPI communicator for file */ - hbool_t using_mpi_vfd; /* Whether the file is using an MPI-based VFD */ -#endif /* H5_HAVE_PARALLEL */ - 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 */ - H5D_io_op_type_t op_type; - hbool_t use_select_io; /* Whether to use selection I/O */ - union { - void *rbuf; /* Pointer to buffer for read */ - const void *wbuf; /* Pointer to buffer to write */ - } u; + MPI_Comm comm; /* MPI communicator for file */ + hbool_t using_mpi_vfd; /* Whether the file is using an MPI-based VFD */ +#endif /* H5_HAVE_PARALLEL */ + H5D_md_io_ops_t md_io_ops; /* Multi dataset I/O operation function pointers */ + H5D_io_op_type_t op_type; + size_t count; /* Number of datasets in I/O request */ + H5D_dset_io_info_t *dsets_info; /* dsets info where I/O is done to/from */ + size_t piece_count; /* Number of pieces in I/O request */ + size_t pieces_added; /* Number of pieces added so far to arrays */ + H5D_piece_info_t **sel_pieces; /* Array of info struct for all pieces in I/O */ + H5S_t **mem_spaces; /* Array of chunk memory spaces */ + H5S_t **file_spaces; /* Array of chunk file spaces */ + haddr_t *addrs; /* Array of chunk addresses */ + size_t *element_sizes; /* Array of element sizes */ + void **rbufs; /* Array of read buffers */ + const void **wbufs; /* Array of write buffers */ + haddr_t store_faddr; /* lowest file addr for read/write */ + H5_flexible_const_ptr_t base_maddr; /* starting mem address */ + hbool_t use_select_io; /* Whether to use selection I/O */ + uint8_t *tconv_buf; /* Datatype conv buffer */ + hbool_t tconv_buf_allocated; /* Whether the type conversion buffer was allocated */ + size_t max_type_size; /* Largest of all source and destination type sizes */ } H5D_io_info_t; +/* Created to pass both at once for callback func */ +typedef struct H5D_io_info_wrap_t { + H5D_io_info_t *io_info; + H5D_dset_io_info_t *dinfo; +} H5D_io_info_wrap_t; + /******************/ /* Chunk typedefs */ /******************/ @@ -330,46 +380,26 @@ typedef struct H5D_chunk_ops_t { H5D_chunk_dest_func_t dest; /* Routine to destroy indexing information in memory */ } H5D_chunk_ops_t; -/* Structure holding information about a chunk's selection for mapping */ -typedef struct H5D_chunk_info_t { - hsize_t index; /* "Index" of chunk in dataset */ - uint32_t chunk_points; /* Number of elements selected in chunk */ - hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Scaled coordinates of chunk (in file dataset's dataspace) */ - H5S_t *fspace; /* Dataspace describing chunk & selection in it */ - hbool_t fspace_shared; /* Indicate that the file space for a chunk is shared and shouldn't be freed */ - H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */ - hbool_t mspace_shared; /* Indicate that the memory space for a chunk is shared and shouldn't be freed */ -} H5D_chunk_info_t; - /* Main structure holding the mapping between file chunks and memory */ typedef struct H5D_chunk_map_t { - H5O_layout_t *layout; /* Dataset layout information*/ - hsize_t nelmts; /* Number of elements selected in file & memory dataspaces */ + unsigned f_ndims; /* Number of dimensions for file dataspace */ - H5S_t *file_space; /* Pointer to the file dataspace */ - unsigned f_ndims; /* Number of dimensions for file dataspace */ - - H5S_t *mem_space; /* Pointer to the memory dataspace */ H5S_t *mchunk_tmpl; /* Dataspace template for new memory chunks */ H5S_sel_iter_t mem_iter; /* Iterator for elements in memory selection */ unsigned m_ndims; /* Number of dimensions for memory dataspace */ H5S_sel_type msel_type; /* Selection type in memory */ H5S_sel_type fsel_type; /* Selection type in file */ - H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */ + H5SL_t *dset_sel_pieces; /* 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 */ + H5D_piece_info_t *single_piece_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 */ + H5D_piece_info_t *last_piece_info; /* Pointer to last chunk's info */ hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Size of chunk in each dimension */ - -#ifdef H5_HAVE_PARALLEL - 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; /* Cached information about a particular chunk */ @@ -415,7 +445,7 @@ typedef struct H5D_rdcc_t { struct H5D_rdcc_ent_t **slot; /* Chunk slots, each points to a chunk*/ H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */ H5S_t *single_space; /* Dataspace for single element I/O on chunks */ - H5D_chunk_info_t *single_chunk_info; /* Pointer to single chunk's info */ + H5D_piece_info_t *single_piece_info; /* Pointer to single piece's info */ /* Cached information about scaled dataspace dimensions */ hsize_t scaled_dims[H5S_MAX_RANK]; /* The scaled dim sizes */ @@ -458,12 +488,13 @@ struct H5D_shared_t { /* Buffered/cached information for types of raw data storage*/ struct { - H5D_rdcdc_t contig; /* Information about contiguous data */ - /* (Note that the "contig" cache - * information can be used by a chunked - * dataset in certain circumstances) - */ - H5D_rdcc_t chunk; /* Information about chunked data */ + H5D_rdcdc_t contig; /* Information about contiguous data */ + /* (Note that the "contig" cache + * information can be used by a chunked + * dataset in certain circumstances) + */ + H5D_rdcc_t chunk; /* Information about chunked data */ + H5SL_t *sel_pieces; /* Skip list containing information for each piece selected */ } cache; H5D_append_flush_t append_flush; /* Append flush property information */ @@ -556,8 +587,8 @@ H5_DLL H5D_t *H5D__open_name(const H5G_loc_t *loc, const char *name, hid_t dapl H5_DLL hid_t H5D__get_space(const H5D_t *dset); H5_DLL hid_t H5D__get_type(const H5D_t *dset); H5_DLL herr_t H5D__get_space_status(const H5D_t *dset, H5D_space_status_t *allocation); -H5_DLL herr_t H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, - hbool_t full_overwrite, hsize_t old_dim[]); +H5_DLL herr_t H5D__alloc_storage(H5D_t *dset, H5D_time_alloc_t time_alloc, hbool_t full_overwrite, + hsize_t old_dim[]); H5_DLL herr_t H5D__get_storage_size(const H5D_t *dset, hsize_t *storage_size); H5_DLL herr_t H5D__get_chunk_storage_size(H5D_t *dset, const hsize_t *offset, hsize_t *storage_size); H5_DLL herr_t H5D__chunk_index_empty(const H5D_t *dset, hbool_t *empty); @@ -582,16 +613,12 @@ H5_DLL herr_t H5D__refresh(H5D_t *dataset, hid_t dset_id); H5_DLL herr_t H5D__format_convert(H5D_t *dataset); /* Internal I/O routines */ -H5_DLL herr_t H5D__read(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space, - void *buf /*out*/); -H5_DLL herr_t H5D__write(H5D_t *dataset, hid_t mem_type_id, H5S_t *mem_space, H5S_t *file_space, - const void *buf); +H5_DLL herr_t H5D__read(size_t count, H5D_dset_io_info_t *dset_info); +H5_DLL herr_t H5D__write(size_t count, H5D_dset_io_info_t *dset_info); /* 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, - H5S_t *file_space, 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, H5S_t *file_space, H5S_t *mem_space); +H5_DLL herr_t H5D__select_read(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info); +H5_DLL herr_t H5D__select_write(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info); /* Functions that perform direct copying between memory buffers */ H5_DLL herr_t H5D_select_io_mem(void *dst_buf, H5S_t *dst_space, const void *src_buf, H5S_t *src_space, @@ -601,10 +628,8 @@ H5_DLL herr_t H5D_select_io_mem(void *dst_buf, H5S_t *dst_space, const void *src H5_DLL herr_t H5D__scatter_mem(const void *_tscat_buf, H5S_sel_iter_t *iter, size_t nelmts, void *_buf); H5_DLL size_t H5D__gather_mem(const void *_buf, H5S_sel_iter_t *iter, size_t nelmts, void *_tgath_buf /*out*/); -H5_DLL herr_t H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space); -H5_DLL herr_t H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t nelmts, H5S_t *file_space, H5S_t *mem_space); +H5_DLL herr_t H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info); +H5_DLL herr_t H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info); /* Functions that operate on dataset's layout information */ H5_DLL herr_t H5D__layout_set_io_ops(const H5D_t *dataset); @@ -620,25 +645,23 @@ H5_DLL herr_t H5D__layout_oh_write(const H5D_t *dataset, H5O_t *oh, unsigned upd H5_DLL herr_t H5D__contig_alloc(H5F_t *f, H5O_storage_contig_t *storage); H5_DLL hbool_t H5D__contig_is_space_alloc(const H5O_storage_t *storage); H5_DLL hbool_t H5D__contig_is_data_cached(const H5D_shared_t *shared_dset); -H5_DLL herr_t H5D__contig_fill(const H5D_io_info_t *io_info); -H5_DLL herr_t H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm); -H5_DLL herr_t H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm); +H5_DLL herr_t H5D__contig_fill(H5D_t *dset); +H5_DLL herr_t H5D__contig_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +H5_DLL herr_t H5D__contig_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); H5_DLL herr_t H5D__contig_copy(H5F_t *f_src, const H5O_storage_contig_t *storage_src, H5F_t *f_dst, H5O_storage_contig_t *storage_dst, H5T_t *src_dtype, H5O_copy_t *cpy_info); H5_DLL herr_t H5D__contig_delete(H5F_t *f, const H5O_storage_t *store); /* Functions that operate on chunked dataset storage */ -H5_DLL htri_t H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_op); -H5_DLL herr_t H5D__chunk_create(const H5D_t *dset /*in,out*/); -H5_DLL herr_t H5D__chunk_set_info(const H5D_t *dset); +H5_DLL htri_t H5D__chunk_cacheable(const H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, haddr_t caddr, + hbool_t write_op); +H5_DLL herr_t H5D__chunk_create(const H5D_t *dset /*in,out*/); +H5_DLL herr_t H5D__chunk_set_info(const H5D_t *dset); H5_DLL hbool_t H5D__chunk_is_space_alloc(const H5O_storage_t *storage); H5_DLL hbool_t H5D__chunk_is_data_cached(const H5D_shared_t *shared_dset); H5_DLL herr_t H5D__chunk_lookup(const H5D_t *dset, const hsize_t *scaled, H5D_chunk_ud_t *udata); H5_DLL herr_t H5D__chunk_allocated(const H5D_t *dset, hsize_t *nbytes); -H5_DLL herr_t H5D__chunk_allocate(const H5D_io_info_t *io_info, hbool_t full_overwrite, - const hsize_t old_dim[]); +H5_DLL herr_t H5D__chunk_allocate(const H5D_t *dset, hbool_t full_overwrite, const hsize_t old_dim[]); H5_DLL herr_t H5D__chunk_file_alloc(const H5D_chk_idx_info_t *idx_info, const H5F_block_t *old_chunk, H5F_block_t *new_chunk, hbool_t *need_insert, const hsize_t *scaled); H5_DLL void *H5D__chunk_mem_alloc(size_t size, void *pline); @@ -651,7 +674,7 @@ H5_DLL hbool_t H5D__chunk_is_partial_edge_chunk(unsigned dset_ndims, const uint3 H5_DLL herr_t H5D__chunk_prune_by_extent(H5D_t *dset, const hsize_t *old_dim); H5_DLL herr_t H5D__chunk_set_sizes(H5D_t *dset); #ifdef H5_HAVE_PARALLEL -H5_DLL herr_t H5D__chunk_addrmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[]); +H5_DLL herr_t H5D__chunk_addrmap(const H5D_t *dset, haddr_t chunk_addr[]); #endif /* H5_HAVE_PARALLEL */ H5_DLL herr_t H5D__chunk_update_cache(H5D_t *dset); H5_DLL herr_t H5D__chunk_copy(H5F_t *f_src, H5O_storage_chunk_t *storage_src, H5O_layout_chunk_t *layout_src, @@ -662,8 +685,8 @@ H5_DLL herr_t H5D__chunk_bh_info(const H5O_loc_t *loc, H5O_t *oh, H5O_layout_t * H5_DLL herr_t H5D__chunk_dump_index(H5D_t *dset, FILE *stream); H5_DLL herr_t H5D__chunk_delete(H5F_t *f, H5O_t *oh, H5O_storage_t *store); H5_DLL herr_t H5D__chunk_get_offset_copy(const H5D_t *dset, const hsize_t *offset, hsize_t *offset_copy); -H5_DLL herr_t H5D__chunk_direct_write(const H5D_t *dset, uint32_t filters, hsize_t *offset, - uint32_t data_size, const void *buf); +H5_DLL herr_t H5D__chunk_direct_write(H5D_t *dset, uint32_t filters, hsize_t *offset, uint32_t data_size, + const void *buf); H5_DLL herr_t H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, void *buf); #ifdef H5D_CHUNK_DEBUG H5_DLL herr_t H5D__chunk_stats(const H5D_t *dset, hbool_t headers); @@ -711,39 +734,31 @@ H5_DLL herr_t H5D__fill_term(H5D_fill_buf_info_t *fb_info); #define H5Dmpio_DEBUG #endif /*H5Dmpio_DEBUG*/ #endif /*H5D_DEBUG*/ -/* 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, H5S_t *file_space, 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, H5S_t *file_space, 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, H5S_t *file_space, 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, H5S_t *file_space, 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, H5S_t *file_space, 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, H5S_t *file_space, H5S_t *mem_space, - H5D_chunk_map_t *fm); +/* MPI-IO function to read multi-dsets (Chunk, Contig), it will select either + * regular or irregular read */ +H5_DLL herr_t H5D__mpio_select_read(const H5D_io_info_t *io_info, hsize_t nelmts, H5S_t *file_space, + H5S_t *mem_space); + +/* MPI-IO function to write multi-dsets (Chunk, Contig), it will select either + * regular or irregular write */ +H5_DLL herr_t H5D__mpio_select_write(const H5D_io_info_t *io_info, hsize_t nelmts, H5S_t *file_space, + H5S_t *mem_space); + +/* MPI-IO functions to handle collective IO for multiple dsets (CONTIG, CHUNK) */ +H5_DLL herr_t H5D__collective_read(H5D_io_info_t *io_info); +H5_DLL herr_t H5D__collective_write(H5D_io_info_t *io_info); /* 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 *file_space, - const H5S_t *mem_space, const H5D_type_info_t *type_info); +H5_DLL htri_t H5D__mpio_opt_possible(H5D_io_info_t *io_info); H5_DLL herr_t H5D__mpio_get_no_coll_cause_strings(char *local_cause, size_t local_cause_len, char *global_cause, size_t global_cause_len); #endif /* H5_HAVE_PARALLEL */ +/* Free a piece (chunk or contiguous dataset data block) info struct */ +H5_DLL herr_t H5D__free_piece_info(void *item, void *key, void *opdata); + /* Testing functions */ #ifdef H5D_TESTING H5_DLL herr_t H5D__layout_version_test(hid_t did, unsigned *version); diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h index 6fad138..8040272 100644 --- a/src/H5Dpublic.h +++ b/src/H5Dpublic.h @@ -852,6 +852,52 @@ H5_DLL herr_t H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_ /** * -------------------------------------------------------------------------- + * \ingroup H5D + * + * \brief Reads raw data from a set of datasets into the provided buffers + * + * \param[in] count Number of datasets to read from + * \param[in] dset_id Identifiers of the datasets to read from + * \param[in] mem_type_id Identifiers of the memory datatypes + * \param[in] mem_space_id Identifiers of the memory dataspaces + * \param[in] file_space_id Identifiers of the datasets' dataspaces in the file + * \param[in] dxpl_id Identifier of a transfer property list + * \param[out] buf Buffers to receive data read from file + * + * \return \herr_t + * + * \details H5Dread_multi() reads data from \p count datasets, whose identifiers + * are listed in the \p dset_id array, from the file into multiple + * application memory buffers listed in the \p buf array. Data transfer + * properties are defined by the argument \p dxpl_id. The memory + * datatypes of each dataset are listed by identifier in the \p + * mem_type_id array. The parts of each dataset to read are listed by + * identifier in the \p file_space_id array, and the parts of each + * application memory buffer to read to are listed by identifier in the + * \p mem_space_id array. All array parameters have length \p count. + * + * This function will produce the same results as \p count calls to + * H5Dread(). Information listed in that function about the specifics + * of its behaviour also apply to H5Dread_multi(). By calling + * H5Dread_multi() instead of multiple calls to H5Dread(), however, the + * library can in some cases pass information about the entire I/O + * operation to the file driver, which can improve performance. + * + * All datasets must be in the same HDF5 file, and each unique dataset + * may only be listed once. If this function is called collectively in + * parallel, each rank must pass exactly the same list of datasets in + * \p dset_id , though the other parameters may differ. + * + * \since 1.13.3 + * + * \see H5Dread() + * + */ +H5_DLL herr_t H5Dread_multi(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[] /*out*/); + +/** + * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Dread} */ @@ -861,6 +907,15 @@ H5_DLL herr_t H5Dread_async(const char *app_file, const char *app_func, unsigned /** * -------------------------------------------------------------------------- + * \ingroup ASYNC + * \async_variant_of{H5Dread_multi} + */ +H5_DLL herr_t H5Dread_multi_async(const char *app_file, const char *app_func, unsigned app_line, size_t count, + hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[] /*out*/, hid_t es_id); + +/** + * -------------------------------------------------------------------------- * \ingroup H5D * * \brief Writes raw data from a buffer to a dataset @@ -977,6 +1032,53 @@ H5_DLL herr_t H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid /** * -------------------------------------------------------------------------- + * \ingroup H5D + * + * \brief Writes raw data from a set buffers to a set of datasets + * + * \param[in] count Number of datasets to write to + * \param[in] dset_id Identifiers of the datasets to write to + * \param[in] mem_type_id Identifiers of the memory datatypes + * \param[in] mem_space_id Identifiers of the memory dataspaces + * \param[in] file_space_id Identifiers of the datasets' dataspaces in the file + * \param[in] dxpl_id Identifier of a transfer property list + * \param[in] buf Buffers with data to be written to the file + * + * \return \herr_t + * + * \details H5Dwrite_multi() writes data to \p count datasets, whose identifiers + * are listed in the \p dset_id array, from multiple application memory + * buffers listed in the \p buf array. Data transfer properties are + * defined by the argument \p dxpl_id. The memory datatypes of each + * dataset are listed by identifier in the \p mem_type_id array. The + * parts of each dataset to write are listed by identifier in the \p + * file_space_id array, and the parts of each application memory buffer + * to write from are listed by identifier in the \p mem_space_id array. + * All array parameters have length \p count. + * + * This function will produce the same results as \p count calls to + * H5Dwrite(). Information listed in that function's documentation + * about the specifics of its behaviour also apply to H5Dwrite_multi(). + * By calling H5Dwrite_multi() instead of multiple calls to H5Dwrite(), + * however, the library can in some cases pass information about the + * entire I/O operation to the file driver, which can improve + * performance. + * + * All datasets must be in the same HDF5 file, and each unique dataset + * may only be listed once. If this function is called collectively in + * parallel, each rank must pass exactly the same list of datasets in + * \p dset_id , though the other parameters may differ. + * + * \since 1.13.3 + * + * \see H5Dwrite() + * + */ +H5_DLL herr_t H5Dwrite_multi(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[]); + +/** + * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Dwrite} */ @@ -986,6 +1088,15 @@ H5_DLL herr_t H5Dwrite_async(const char *app_file, const char *app_func, unsigne /** * -------------------------------------------------------------------------- + * \ingroup ASYNC + * \async_variant_of{H5Dwrite_multi} + */ +H5_DLL herr_t H5Dwrite_multi_async(const char *app_file, const char *app_func, unsigned app_line, + size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], hid_t es_id); + +/** + * -------------------------------------------------------------------------- * \ingroup H5D * * \brief Writes a raw data chunk from a buffer directly to a dataset in a file diff --git a/src/H5Dscatgath.c b/src/H5Dscatgath.c index 45c7bff..7cc075e 100644 --- a/src/H5Dscatgath.c +++ b/src/H5Dscatgath.c @@ -39,13 +39,13 @@ /********************/ /* Local Prototypes */ /********************/ -static herr_t H5D__scatter_file(const H5D_io_info_t *io_info, H5S_sel_iter_t *file_iter, size_t nelmts, - const void *buf); -static size_t H5D__gather_file(const H5D_io_info_t *io_info, 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 H5D_dset_io_info_t *dset_info, + H5S_sel_iter_t *file_iter, size_t nelmts, const void *buf); +static size_t H5D__gather_file(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + H5S_sel_iter_t *file_iter, size_t nelmts, void *buf); static herr_t H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, 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); + uint8_t *tconv_buf, void *user_buf /*out*/); +static herr_t H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info, uint8_t *tconv_buf); /*********************/ /* Package Variables */ @@ -81,33 +81,40 @@ H5FL_SEQ_EXTERN(hsize_t); *------------------------------------------------------------------------- */ static herr_t -H5D__scatter_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, size_t nelmts, const void *_buf) +H5D__scatter_file(const H5D_io_info_t *_io_info, const H5D_dset_io_info_t *_dset_info, 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 = 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 = 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 */ - size_t dxpl_vec_size; /* Vector length from API context's DXPL */ - size_t vec_size; /* Vector length */ - herr_t ret_value = SUCCEED; /* Return value */ + H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ + H5D_dset_io_info_t tmp_dset_info; /* Temporary I/O info object */ + 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 = 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 */ + size_t dxpl_vec_size; /* Vector length from API context's DXPL */ + size_t vec_size; /* Vector length */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Check args */ HDassert(_io_info); + HDassert(_dset_info); + HDassert(_dset_info->dset); + HDassert(_dset_info->store); HDassert(iter); HDassert(nelmts > 0); HDassert(_buf); /* Set up temporary I/O info object */ H5MM_memcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); - tmp_io_info.op_type = H5D_IO_OP_WRITE; - tmp_io_info.u.wbuf = _buf; + HDmemcpy(&tmp_dset_info, _dset_info, sizeof(*_dset_info)); + tmp_io_info.op_type = H5D_IO_OP_WRITE; + tmp_dset_info.buf.cvp = _buf; + tmp_io_info.dsets_info = &tmp_dset_info; /* Get info from API context */ if (H5CX_get_vec_size(&dxpl_vec_size) < 0) @@ -135,12 +142,12 @@ H5D__scatter_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, size_t ne 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) + if ((*tmp_dset_info.layout_ops.writevv)(&tmp_io_info, &tmp_dset_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; + tmp_dset_info.buf.cvp = (const uint8_t *)tmp_dset_info.buf.cvp + orig_mem_len; /* Decrement number of elements left to process */ nelmts -= nelem; @@ -178,35 +185,40 @@ done: *------------------------------------------------------------------------- */ static size_t -H5D__gather_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, size_t nelmts, void *_buf /*out*/) +H5D__gather_file(const H5D_io_info_t *_io_info, const H5D_dset_io_info_t *_dset_info, 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 = 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 = 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 dxpl_vec_size; /* Vector length from API context's DXPL */ - size_t vec_size; /* Vector length */ - size_t ret_value = nelmts; /* Return value */ + H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ + H5D_dset_io_info_t tmp_dset_info; /* Temporary I/O info object */ + 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 = 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 dxpl_vec_size; /* Vector length from API context's DXPL */ + size_t vec_size; /* Vector length */ + size_t ret_value = nelmts; /* Return value */ FUNC_ENTER_PACKAGE /* Check args */ HDassert(_io_info); - HDassert(_io_info->dset); - HDassert(_io_info->store); + HDassert(_dset_info); + HDassert(_dset_info->dset); + HDassert(_dset_info->store); HDassert(iter); HDassert(nelmts > 0); HDassert(_buf); /* Set up temporary I/O info object */ H5MM_memcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); - tmp_io_info.op_type = H5D_IO_OP_READ; - tmp_io_info.u.rbuf = _buf; + HDmemcpy(&tmp_dset_info, _dset_info, sizeof(*_dset_info)); + tmp_io_info.op_type = H5D_IO_OP_READ; + tmp_dset_info.buf.vp = _buf; + tmp_io_info.dsets_info = &tmp_dset_info; /* Get info from API context */ if (H5CX_get_vec_size(&dxpl_vec_size) < 0) @@ -234,12 +246,12 @@ H5D__gather_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, size_t nel 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) + if ((*tmp_dset_info.layout_ops.readvv)(&tmp_io_info, &tmp_dset_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; + tmp_dset_info.buf.vp = (uint8_t *)tmp_dset_info.buf.vp + orig_mem_len; /* Decrement number of elements left to process */ nelmts -= nelem; @@ -436,11 +448,10 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space) +H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info) { - void *buf = io_info->u.rbuf; /* Local pointer to application buffer */ - H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/ + void *buf; /* Local pointer to application buffer */ + H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */ H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/ hbool_t bkg_iter_init = FALSE; /* Background iteration info has been initialized */ @@ -454,13 +465,16 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* Sanity check */ HDassert(io_info); - HDassert(type_info); - HDassert(mem_space); - HDassert(file_space); - HDassert(buf); + HDassert(dset_info); + HDassert(dset_info->mem_space); + HDassert(dset_info->file_space); + HDassert(dset_info->buf.vp); + + /* Set buf pointer */ + buf = dset_info->buf.vp; /* Check for NOOP read */ - if (nelmts == 0) + if (dset_info->nelmts == 0) HGOTO_DONE(SUCCEED) /* Allocate the iterators */ @@ -472,24 +486,24 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator") /* Figure out the strip mine size. */ - if (H5S_select_iter_init(file_iter, file_space, type_info->src_type_size, + if (H5S_select_iter_init(file_iter, dset_info->file_space, dset_info->type_info.src_type_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 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) < 0) + if (H5S_select_iter_init(mem_iter, dset_info->mem_space, dset_info->type_info.dst_type_size, 0) < 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) < 0) + if (H5S_select_iter_init(bkg_iter, dset_info->mem_space, dset_info->type_info.dst_type_size, 0) < 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) { + for (smine_start = 0; smine_start < dset_info->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)); + HDassert(H5S_SELECT_ITER_NELMTS(file_iter) == (dset_info->nelmts - smine_start)); + smine_nelmts = (size_t)MIN(dset_info->type_info.request_nelmts, (dset_info->nelmts - smine_start)); /* * Gather the data from disk into the datatype conversion @@ -500,7 +514,7 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* * Gather data */ - n = H5D__gather_file(io_info, file_iter, smine_nelmts, type_info->tconv_buf /*out*/); + n = H5D__gather_file(io_info, dset_info, file_iter, smine_nelmts, io_info->tconv_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") @@ -508,13 +522,15 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf * and no conversion is needed, copy the data directly into user's buffer and * bypass the rest of steps. */ - if (type_info->cmpd_subset && H5T_SUBSET_FALSE != type_info->cmpd_subset->subset) { - if (H5D__compound_opt_read(smine_nelmts, mem_iter, type_info, buf /*out*/) < 0) + if (dset_info->type_info.cmpd_subset && + H5T_SUBSET_FALSE != dset_info->type_info.cmpd_subset->subset) { + if (H5D__compound_opt_read(smine_nelmts, mem_iter, &dset_info->type_info, io_info->tconv_buf, + 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, bkg_iter, smine_nelmts, type_info->bkg_buf /*out*/); + if (H5T_BKG_YES == dset_info->type_info.need_bkg) { + n = H5D__gather_mem(buf, bkg_iter, smine_nelmts, dset_info->type_info.bkg_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed") } /* end if */ @@ -522,25 +538,26 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* * 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) < 0) + if (H5T_convert(dset_info->type_info.tpath, dset_info->type_info.src_type_id, + dset_info->type_info.dst_type_id, smine_nelmts, (size_t)0, (size_t)0, + io_info->tconv_buf, dset_info->type_info.bkg_buf) < 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 (!dset_info->type_info.is_xform_noop) { H5Z_data_xform_t *data_transform; /* Data transform info */ /* Retrieve info from API context */ if (H5CX_get_data_transform(&data_transform) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info") - if (H5Z_xform_eval(data_transform, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < - 0) + if (H5Z_xform_eval(data_transform, io_info->tconv_buf, smine_nelmts, + dset_info->type_info.mem_type) < 0) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform") } /* Scatter the data into memory */ - if (H5D__scatter_mem(type_info->tconv_buf, mem_iter, smine_nelmts, buf /*out*/) < 0) + if (H5D__scatter_mem(io_info->tconv_buf, mem_iter, smine_nelmts, buf /*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") } /* end else */ } /* end for */ @@ -576,11 +593,10 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space) +H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info) { - const void *buf = io_info->u.wbuf; /* Local pointer to application buffer */ - H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/ + const void *buf; /* Local pointer to application buffer */ + H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */ H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/ hbool_t bkg_iter_init = FALSE; /* Background iteration info has been initialized */ @@ -594,13 +610,16 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in /* Sanity check */ HDassert(io_info); - HDassert(type_info); - HDassert(mem_space); - HDassert(file_space); - HDassert(buf); + HDassert(dset_info); + HDassert(dset_info->mem_space); + HDassert(dset_info->file_space); + HDassert(dset_info->buf.vp); + + /* Set buf pointer */ + buf = dset_info->buf.cvp; /* Check for NOOP write */ - if (nelmts == 0) + if (dset_info->nelmts == 0) HGOTO_DONE(SUCCEED) /* Allocate the iterators */ @@ -612,32 +631,32 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator") /* Figure out the strip mine size. */ - if (H5S_select_iter_init(file_iter, file_space, type_info->dst_type_size, + if (H5S_select_iter_init(file_iter, dset_info->file_space, dset_info->type_info.dst_type_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 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) < 0) + if (H5S_select_iter_init(mem_iter, dset_info->mem_space, dset_info->type_info.src_type_size, 0) < 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, + if (H5S_select_iter_init(bkg_iter, dset_info->file_space, dset_info->type_info.dst_type_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 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) { + for (smine_start = 0; smine_start < dset_info->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)); + HDassert(H5S_SELECT_ITER_NELMTS(file_iter) == (dset_info->nelmts - smine_start)); + smine_nelmts = (size_t)MIN(dset_info->type_info.request_nelmts, (dset_info->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_iter, smine_nelmts, type_info->tconv_buf /*out*/); + n = H5D__gather_mem(buf, mem_iter, smine_nelmts, io_info->tconv_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed") @@ -647,44 +666,46 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in * is a subset of the destination, the optimization is done in conversion * function H5T_conv_struct_opt to protect the background data. */ - if (type_info->cmpd_subset && H5T_SUBSET_DST == type_info->cmpd_subset->subset && - type_info->dst_type_size == type_info->cmpd_subset->copy_size) { - if (H5D__compound_opt_write(smine_nelmts, type_info) < 0) + if (dset_info->type_info.cmpd_subset && H5T_SUBSET_DST == dset_info->type_info.cmpd_subset->subset && + dset_info->type_info.dst_type_size == dset_info->type_info.cmpd_subset->copy_size) { + if (H5D__compound_opt_write(smine_nelmts, &dset_info->type_info, io_info->tconv_buf) < 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, bkg_iter, smine_nelmts, type_info->bkg_buf /*out*/); + if (H5T_BKG_YES == dset_info->type_info.need_bkg) { + n = H5D__gather_file(io_info, dset_info, bkg_iter, smine_nelmts, + dset_info->type_info.bkg_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") } /* end if */ /* Do the data transform before the type conversion (since * transforms must be done in the memory type). */ - if (!type_info->is_xform_noop) { + if (!dset_info->type_info.is_xform_noop) { H5Z_data_xform_t *data_transform; /* Data transform info */ /* Retrieve info from API context */ if (H5CX_get_data_transform(&data_transform) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info") - if (H5Z_xform_eval(data_transform, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < - 0) + if (H5Z_xform_eval(data_transform, io_info->tconv_buf, smine_nelmts, + dset_info->type_info.mem_type) < 0) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform") } /* * 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) < 0) + if (H5T_convert(dset_info->type_info.tpath, dset_info->type_info.src_type_id, + dset_info->type_info.dst_type_id, smine_nelmts, (size_t)0, (size_t)0, + io_info->tconv_buf, dset_info->type_info.bkg_buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed") } /* end else */ /* * Scatter the data out to the file. */ - if (H5D__scatter_file(io_info, file_iter, smine_nelmts, type_info->tconv_buf) < 0) + if (H5D__scatter_file(io_info, dset_info, file_iter, smine_nelmts, io_info->tconv_buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed") } /* end for */ @@ -740,7 +761,7 @@ done: */ static herr_t H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, const H5D_type_info_t *type_info, - void *user_buf /*out*/) + uint8_t *tconv_buf, void *user_buf /*out*/) { uint8_t *ubuf = (uint8_t *)user_buf; /* Cast for pointer arithmetic */ uint8_t *xdbuf; /* Pointer into dataset buffer */ @@ -784,7 +805,7 @@ H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, const H5D_type_info_ copy_size = type_info->cmpd_subset->copy_size; /* Loop until all elements are written */ - xdbuf = type_info->tconv_buf; + xdbuf = tconv_buf; while (nelmts > 0) { size_t nseq; /* Number of sequences generated */ size_t curr_seq; /* Current sequence being processed */ @@ -869,7 +890,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info) +H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info, uint8_t *tconv_buf) { uint8_t *xsbuf, *xdbuf; /* Source & destination pointers into dataset buffer */ size_t src_stride, dst_stride; /* Strides through source & destination datatypes */ @@ -886,8 +907,8 @@ H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info) 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; + xsbuf = tconv_buf; + xdbuf = tconv_buf; for (i = 0; i < nelmts; i++) { HDmemmove(xdbuf, xsbuf, dst_stride); diff --git a/src/H5Dselect.c b/src/H5Dselect.c index b16dd5a..1d1b5f2 100644 --- a/src/H5Dselect.c +++ b/src/H5Dselect.c @@ -44,8 +44,8 @@ /* Local Prototypes */ /********************/ -static herr_t H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t nelmts, H5S_t *file_space, - H5S_t *mem_space); +static herr_t H5D__select_io(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, + size_t elmt_size); /*********************/ /* Package Variables */ @@ -77,8 +77,7 @@ H5FL_EXTERN(H5S_sel_iter_t); *------------------------------------------------------------------------- */ static herr_t -H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t nelmts, H5S_t *file_space, - H5S_t *mem_space) +H5D__select_io(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t elmt_size) { H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info */ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */ @@ -95,19 +94,23 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t nelmts, H5 size_t dxpl_vec_size; /* Vector length from API context's DXPL */ size_t vec_size; /* Vector length */ ssize_t tmp_file_len; /* Temporary number of bytes in file sequence */ + size_t nelmts; /* Number of elements to process */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Check args */ HDassert(io_info); - HDassert(io_info->dset); - HDassert(io_info->store); - HDassert(io_info->u.rbuf); + HDassert(dset_info->dset); + HDassert(dset_info->store); + HDassert(dset_info->buf.vp); if (elmt_size == 0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "invalid elmt_size of 0") + /* Initialize nelmts */ + nelmts = dset_info->nelmts; + /* Check for only one element in selection */ if (nelmts == 1) { hsize_t single_mem_off; /* Offset in memory */ @@ -116,9 +119,9 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t nelmts, H5 size_t single_file_len; /* Length in the file */ /* Get offset of first element in selections */ - if (H5S_SELECT_OFFSET(file_space, &single_file_off) < 0) + if (H5S_SELECT_OFFSET(dset_info->file_space, &single_file_off) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "can't retrieve file selection offset") - if (H5S_SELECT_OFFSET(mem_space, &single_mem_off) < 0) + if (H5S_SELECT_OFFSET(dset_info->mem_space, &single_mem_off) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "can't retrieve memory selection offset") /* Set up necessary information for I/O operation */ @@ -130,16 +133,16 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t nelmts, H5 /* Perform I/O on memory and file sequences */ 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, &single_file_len, &single_file_off, mem_nseq, - &curr_mem_seq, &single_mem_len, &single_mem_off)) < 0) + if ((tmp_file_len = (*dset_info->layout_ops.readvv)( + io_info, dset_info, file_nseq, &curr_file_seq, &single_file_len, &single_file_off, + mem_nseq, &curr_mem_seq, &single_mem_len, &single_mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") } /* end if */ else { 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, &single_file_len, &single_file_off, mem_nseq, - &curr_mem_seq, &single_mem_len, &single_mem_off)) < 0) + if ((tmp_file_len = (*dset_info->layout_ops.writevv)( + io_info, dset_info, file_nseq, &curr_file_seq, &single_file_len, &single_file_off, + mem_nseq, &curr_mem_seq, &single_mem_len, &single_mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") } /* end else */ @@ -175,12 +178,13 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t nelmts, H5 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator") /* Initialize file iterator */ - if (H5S_select_iter_init(file_iter, file_space, elmt_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0) + if (H5S_select_iter_init(file_iter, dset_info->file_space, elmt_size, + H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") file_iter_init = 1; /* File selection iteration info has been initialized */ /* Initialize memory iterator */ - if (H5S_select_iter_init(mem_iter, mem_space, elmt_size, 0) < 0) + if (H5S_select_iter_init(mem_iter, dset_info->mem_space, elmt_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") mem_iter_init = 1; /* Memory selection iteration info has been initialized */ @@ -214,16 +218,16 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t nelmts, H5 /* Perform I/O on memory and file sequences */ 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)) < 0) + if ((tmp_file_len = (*dset_info->layout_ops.readvv)( + io_info, dset_info, file_nseq, &curr_file_seq, file_len, file_off, mem_nseq, + &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") } /* end if */ else { 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)) < 0) + if ((tmp_file_len = (*dset_info->layout_ops.writevv)( + io_info, dset_info, file_nseq, &curr_file_seq, file_len, file_off, mem_nseq, + &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") } /* end else */ @@ -452,16 +456,14 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__select_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space) +H5D__select_read(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Call generic selection operation */ - 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) + if (H5D__select_io(io_info, dset_info, dset_info->type_info.src_type_size) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") done: @@ -481,16 +483,14 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__select_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space) +H5D__select_write(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Call generic selection operation */ - 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) + if (H5D__select_io(io_info, dset_info, dset_info->type_info.dst_type_size) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") done: diff --git a/src/H5Dvirtual.c b/src/H5Dvirtual.c index 04981c2..ee16a17 100644 --- a/src/H5Dvirtual.c +++ b/src/H5Dvirtual.c @@ -83,10 +83,9 @@ /* Layout operation callbacks */ static hbool_t H5D__virtual_is_data_cached(const H5D_shared_t *shared_dset); -static herr_t H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm); -static herr_t H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t *fm); +static herr_t H5D__virtual_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static herr_t H5D__virtual_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); +static herr_t H5D__virtual_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo); static herr_t H5D__virtual_flush(H5D_t *dset); /* Other functions */ @@ -103,13 +102,13 @@ static herr_t H5D__virtual_build_source_name(char size_t static_strlen, size_t nsubs, hsize_t blockno, char **built_name); static herr_t H5D__virtual_init_all(const H5D_t *dset); -static herr_t H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_t *file_space, - H5S_t *mem_space, hsize_t *tot_nelmts); +static herr_t H5D__virtual_pre_io(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_t *storage, + H5S_t *file_space, H5S_t *mem_space, hsize_t *tot_nelmts); static herr_t H5D__virtual_post_io(H5O_storage_virtual_t *storage); -static herr_t H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset); -static herr_t H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset); +static herr_t H5D__virtual_read_one(H5D_dset_io_info_t *dset_info, + H5O_storage_virtual_srcdset_t *source_dset); +static herr_t H5D__virtual_write_one(H5D_dset_io_info_t *dset_info, + H5O_storage_virtual_srcdset_t *source_dset); /*********************/ /* Package Variables */ @@ -121,18 +120,15 @@ const H5D_layout_ops_t H5D_LOPS_VIRTUAL[1] = {{ H5D__virtual_init, /* init */ H5D__virtual_is_space_alloc, /* is_space_alloc */ H5D__virtual_is_data_cached, /* is_data_cached */ - NULL, /* io_init */ + H5D__virtual_io_init, /* io_init */ + NULL, /* mdio_init */ H5D__virtual_read, /* ser_read */ H5D__virtual_write, /* ser_write */ -#ifdef H5_HAVE_PARALLEL - NULL, /* par_read */ - NULL, /* par_write */ -#endif - NULL, /* readvv */ - NULL, /* writevv */ - H5D__virtual_flush, /* flush */ - NULL, /* io_term */ - NULL /* dest */ + NULL, /* readvv */ + NULL, /* writevv */ + H5D__virtual_flush, /* flush */ + NULL, /* io_term */ + NULL /* dest */ }}; /*******************/ @@ -2371,6 +2367,29 @@ done: } /* end H5D__virtual_is_data_cached() */ /*------------------------------------------------------------------------- + * Function: H5D__virtual_io_init + * + * Purpose: Performs initialization before any sort of I/O on the raw data + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * Sunday, May 22, 2022 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__virtual_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t H5_ATTR_UNUSED *dinfo) +{ + FUNC_ENTER_PACKAGE_NOERR + + /* Disable selection I/O */ + io_info->use_select_io = FALSE; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5D__virtual_io_init() */ + +/*------------------------------------------------------------------------- * Function: H5D__virtual_pre_io * * Purpose: Project all virtual mappings onto mem_space, with the @@ -2386,16 +2405,17 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_t *file_space, +H5D__virtual_pre_io(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_t *storage, H5S_t *file_space, H5S_t *mem_space, hsize_t *tot_nelmts) { - hssize_t select_nelmts; /* Number of elements in selection */ - hsize_t bounds_start[H5S_MAX_RANK]; /* Selection bounds start */ - hsize_t bounds_end[H5S_MAX_RANK]; /* Selection bounds end */ - int rank = 0; - hbool_t bounds_init = FALSE; /* Whether bounds_start, bounds_end, and rank are valid */ - size_t i, j, k; /* Local index variables */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5D_t *dset = dset_info->dset; /* Local pointer to dataset info */ + hssize_t select_nelmts; /* Number of elements in selection */ + hsize_t bounds_start[H5S_MAX_RANK]; /* Selection bounds start */ + hsize_t bounds_end[H5S_MAX_RANK]; /* Selection bounds end */ + int rank = 0; + hbool_t bounds_init = FALSE; /* Whether bounds_start, bounds_end, and rank are valid */ + size_t i, j, k; /* Local index variables */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE @@ -2407,7 +2427,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_ /* Initialize layout if necessary */ if (!storage->init) - if (H5D__virtual_init_all(io_info->dset) < 0) + if (H5D__virtual_init_all(dset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize virtual layout") /* Initialize tot_nelmts */ @@ -2427,7 +2447,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_ /* Get selection bounds if necessary */ if (!bounds_init) { /* Get rank of VDS */ - if ((rank = H5S_GET_EXTENT_NDIMS(io_info->dset->shared->space)) < 0) + if ((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions") /* Get selection bounds */ @@ -2469,7 +2489,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_ * open the source dataset to patch it */ if (storage->list[i].source_space_status != H5O_VIRTUAL_STATUS_CORRECT) { HDassert(!storage->list[i].sub_dset[j].dset); - if (H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], + if (H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].sub_dset[j]) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset") } /* end if */ @@ -2499,7 +2519,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace") /* Get current VDS dimensions */ - if (H5S_get_simple_extent_dims(io_info->dset->shared->space, tmp_dims, NULL) < 0) + if (H5S_get_simple_extent_dims(dset->shared->space, tmp_dims, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions") /* Copy virtual selection */ @@ -2554,7 +2574,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_ /* Open source dataset */ if (!storage->list[i].sub_dset[j].dset) /* Try to open dataset */ - if (H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], + if (H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].sub_dset[j]) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset") @@ -2599,7 +2619,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, H5O_storage_virtual_t *storage, H5S_ /* Open source dataset */ if (!storage->list[i].source_dset.dset) /* Try to open dataset */ - if (H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], + if (H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].source_dset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset") @@ -2697,11 +2717,11 @@ H5D__virtual_post_io(H5O_storage_virtual_t *storage) *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, H5S_t *file_space, - H5O_storage_virtual_srcdset_t *source_dset) +H5D__virtual_read_one(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_srcdset_t *source_dset) { - H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */ - herr_t ret_value = SUCCEED; /* Return value */ + H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */ + H5D_dset_io_info_t source_dinfo; /* Dataset info for source dataset read */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE @@ -2717,15 +2737,23 @@ H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Project intersection of file space and mapping virtual space onto * mapping source space */ if (H5S_select_project_intersection(source_dset->clipped_virtual_select, - source_dset->clipped_source_select, file_space, + source_dset->clipped_source_select, dset_info->file_space, &projected_src_space, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space") - /* Perform read on source dataset */ - if (H5D__read(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, - projected_src_space, io_info->u.rbuf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset") + { + /* Initialize source_dinfo */ + source_dinfo.dset = source_dset->dset; + source_dinfo.mem_space = source_dset->projected_mem_space; + source_dinfo.file_space = projected_src_space; + source_dinfo.buf.vp = dset_info->buf.vp; + source_dinfo.mem_type_id = dset_info->type_info.dst_type_id; + + /* Read in the point (with the custom VL memory allocator) */ + if (H5D__read(1, &source_dinfo) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset") + } /* Close projected_src_space */ if (H5S_close(projected_src_space) < 0) @@ -2734,7 +2762,7 @@ H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, } /* end if */ done: - /* Release allocated resources on failure */ + /* Release allocated resources */ if (projected_src_space) { HDassert(ret_value < 0); if (H5S_close(projected_src_space) < 0) @@ -2757,12 +2785,12 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, H5S_t *file_space, - H5S_t *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *fm) +H5D__virtual_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info) { H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */ hsize_t tot_nelmts; /* Total number of elements mapped to mem_space */ H5S_t *fill_space = NULL; /* Space to fill with fill value */ + size_t nelmts; /* Number of elements to process */ size_t i, j; /* Local index variables */ herr_t ret_value = SUCCEED; /* Return value */ @@ -2770,22 +2798,25 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsiz /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.rbuf); - HDassert(type_info); - HDassert(mem_space); - HDassert(file_space); + HDassert(dset_info); + HDassert(dset_info->buf.vp); + HDassert(dset_info->mem_space); + HDassert(dset_info->file_space); - storage = &io_info->dset->shared->layout.storage.u.virt; + storage = &(dset_info->dset->shared->layout.storage.u.virt); HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE)); + /* Initialize nelmts */ + nelmts = H5S_GET_SELECT_NPOINTS(dset_info->file_space); + #ifdef H5_HAVE_PARALLEL /* Parallel reads are not supported (yet) */ - if (H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) + if (H5F_HAS_FEATURE(dset_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel reads not supported on virtual datasets") #endif /* H5_HAVE_PARALLEL */ /* Prepare for I/O operation */ - if (H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0) + if (H5D__virtual_pre_io(dset_info, storage, dset_info->file_space, dset_info->mem_space, &tot_nelmts) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation") /* Iterate over mappings */ @@ -2797,12 +2828,12 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsiz if (storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) { /* Iterate over sub-source dsets */ for (j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++) - if (H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0) + if (H5D__virtual_read_one(dset_info, &storage->list[i].sub_dset[j]) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset") } /* end if */ else /* Read from source dataset */ - if (H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0) + if (H5D__virtual_read_one(dset_info, &storage->list[i].source_dset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset") } /* end for */ @@ -2811,13 +2842,13 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsiz H5D_fill_value_t fill_status; /* Fill value status */ /* Check the fill value status */ - if (H5P_is_fill_value_defined(&io_info->dset->shared->dcpl_cache.fill, &fill_status) < 0) + if (H5P_is_fill_value_defined(&dset_info->dset->shared->dcpl_cache.fill, &fill_status) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if fill value defined") /* Always write fill value to memory buffer unless it is undefined */ if (fill_status != H5D_FILL_VALUE_UNDEFINED) { /* Start with fill space equal to memory space */ - if (NULL == (fill_space = H5S_copy(mem_space, FALSE, TRUE))) + if (NULL == (fill_space = H5S_copy(dset_info->mem_space, FALSE, TRUE))) HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy memory selection") /* Iterate over mappings */ @@ -2837,8 +2868,8 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsiz HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection") /* Write fill values to memory buffer */ - if (H5D__fill(io_info->dset->shared->dcpl_cache.fill.buf, io_info->dset->shared->type, - io_info->u.rbuf, type_info->mem_type, fill_space) < 0) + if (H5D__fill(dset_info->dset->shared->dcpl_cache.fill.buf, dset_info->dset->shared->type, + dset_info->buf.vp, dset_info->type_info.mem_type, fill_space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "filling buf failed") #ifndef NDEBUG @@ -2887,11 +2918,11 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, H5S_t *file_space, - H5O_storage_virtual_srcdset_t *source_dset) +H5D__virtual_write_one(H5D_dset_io_info_t *dset_info, H5O_storage_virtual_srcdset_t *source_dset) { - H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */ - herr_t ret_value = SUCCEED; /* Return value */ + H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */ + H5D_dset_io_info_t source_dinfo; /* Dataset info for source dataset write */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE @@ -2909,15 +2940,23 @@ H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Project intersection of file space and mapping virtual space onto * mapping source space */ if (H5S_select_project_intersection(source_dset->clipped_virtual_select, - source_dset->clipped_source_select, file_space, + source_dset->clipped_source_select, dset_info->file_space, &projected_src_space, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space") - /* Perform write on source dataset */ - if (H5D__write(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, - projected_src_space, io_info->u.wbuf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write to source dataset") + { + /* Initialize source_dinfo */ + source_dinfo.dset = source_dset->dset; + source_dinfo.mem_space = source_dset->projected_mem_space; + source_dinfo.file_space = projected_src_space; + source_dinfo.buf.cvp = dset_info->buf.cvp; + source_dinfo.mem_type_id = dset_info->type_info.dst_type_id; + + /* Read in the point (with the custom VL memory allocator) */ + if (H5D__write(1, &source_dinfo) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset") + } /* Close projected_src_space */ if (H5S_close(projected_src_space) < 0) @@ -2926,7 +2965,7 @@ H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, } /* end if */ done: - /* Release allocated resources on failure */ + /* Release allocated resources */ if (projected_src_space) { HDassert(ret_value < 0); if (H5S_close(projected_src_space) < 0) @@ -2949,11 +2988,11 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, - H5S_t *file_space, H5S_t *mem_space, H5D_chunk_map_t H5_ATTR_UNUSED *fm) +H5D__virtual_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info) { H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */ hsize_t tot_nelmts; /* Total number of elements mapped to mem_space */ + size_t nelmts; /* Number of elements to process */ size_t i, j; /* Local index variables */ herr_t ret_value = SUCCEED; /* Return value */ @@ -2961,22 +3000,25 @@ H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsi /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.wbuf); - HDassert(type_info); - HDassert(mem_space); - HDassert(file_space); + HDassert(dset_info); + HDassert(dset_info->buf.cvp); + HDassert(dset_info->mem_space); + HDassert(dset_info->file_space); - storage = &io_info->dset->shared->layout.storage.u.virt; + storage = &(dset_info->dset->shared->layout.storage.u.virt); HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE)); + /* Initialize nelmts */ + nelmts = H5S_GET_SELECT_NPOINTS(dset_info->file_space); + #ifdef H5_HAVE_PARALLEL /* Parallel writes are not supported (yet) */ - if (H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) + if (H5F_HAS_FEATURE(dset_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel writes not supported on virtual datasets") #endif /* H5_HAVE_PARALLEL */ /* Prepare for I/O operation */ - if (H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0) + if (H5D__virtual_pre_io(dset_info, storage, dset_info->file_space, dset_info->mem_space, &tot_nelmts) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation") /* Fail if there are unmapped parts of the selection as they would not be @@ -2994,12 +3036,12 @@ H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsi if (storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) { /* Iterate over sub-source dsets */ for (j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++) - if (H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0) + if (H5D__virtual_write_one(dset_info, &storage->list[i].sub_dset[j]) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset") } /* end if */ else /* Write to source dataset */ - if (H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0) + if (H5D__virtual_write_one(dset_info, &storage->list[i].source_dset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset") } /* end for */ diff --git a/src/H5Sselect.c b/src/H5Sselect.c index f596258..4fc0f61 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -400,7 +400,7 @@ done: PURPOSE Get the number of elements in current selection USAGE - hssize_t H5Sget_select_npoints(space) + hsize_t H5Sget_select_npoints(space) H5S_t *space; IN: Dataspace of selection to query RETURNS The number of elements in selection on success, 0 on failure diff --git a/src/H5VLcallback.c b/src/H5VLcallback.c index 4fb0a63..8191d29 100644 --- a/src/H5VLcallback.c +++ b/src/H5VLcallback.c @@ -88,10 +88,12 @@ static void *H5VL__dataset_create(void *obj, const H5VL_loc_params_t *loc_param hid_t dcpl_id, hid_t dapl_id, hid_t dxpl_id, void **req); static void *H5VL__dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_class_t *cls, const char *name, hid_t dapl_id, hid_t dxpl_id, void **req); -static herr_t H5VL__dataset_read(void *dset, const H5VL_class_t *cls, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t dxpl_id, void *buf, void **req); -static herr_t H5VL__dataset_write(void *obj, const H5VL_class_t *cls, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t dxpl_id, const void *buf, void **req); +static herr_t H5VL__dataset_read(size_t count, void *obj[], const H5VL_class_t *cls, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, void *buf[], + void **req); +static herr_t H5VL__dataset_write(size_t count, void *obj[], const H5VL_class_t *cls, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, + const void *buf[], void **req); static herr_t H5VL__dataset_get(void *obj, const H5VL_class_t *cls, H5VL_dataset_get_args_t *args, hid_t dxpl_id, void **req); static herr_t H5VL__dataset_specific(void *obj, const H5VL_class_t *cls, H5VL_dataset_specific_args_t *args, @@ -2020,9 +2022,9 @@ done: } /* end H5VLdataset_open() */ /*------------------------------------------------------------------------- - * Function: H5VL__dataset_read + * Function: H5VL__dataset_read * - * Purpose: Reads data from dataset through the VOL + * Purpose: Reads data from dataset through the VOL * * Return: Success: Non-negative * Failure: Negative @@ -2030,8 +2032,8 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5VL__dataset_read(void *obj, const H5VL_class_t *cls, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t dxpl_id, void *buf, void **req) +H5VL__dataset_read(size_t count, void *obj[], const H5VL_class_t *cls, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **req) { herr_t ret_value = SUCCEED; /* Return value */ @@ -2042,7 +2044,7 @@ H5VL__dataset_read(void *obj, const H5VL_class_t *cls, hid_t mem_type_id, hid_t HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset read' method") /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.read)(obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) + if ((cls->dataset_cls.read)(count, obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) HGOTO_ERROR(H5E_VOL, H5E_READERROR, FAIL, "dataset read failed") done: @@ -2050,6 +2052,54 @@ done: } /* end H5VL__dataset_read() */ /*------------------------------------------------------------------------- + * Function: H5VL_dataset_read_direct + * + * Purpose: Reads data from dataset through the VOL. This is like + * H5VL_dataset_read, but takes an array of void * for the + * objects and a class pointer instead of an array of + * H5VL_object_t. This allows us to avoid allocating and + * copying an extra array (of H5VL_object_ts). + * + * Return: Success: Non-negative + * Failure: Negative + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_dataset_read_direct(size_t count, void *obj[], H5VL_t *connector, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **req) +{ + hbool_t vol_wrapper_set = FALSE; /* Whether the VOL object wrapping context was set up */ + H5VL_object_t tmp_vol_obj; /* Temporary VOL object for setting VOL wrapper */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(obj); + HDassert(connector); + + /* Set wrapper info in API context */ + tmp_vol_obj.data = obj[0]; + tmp_vol_obj.connector = connector; + tmp_vol_obj.rc = 1; + if (H5VL_set_vol_wrapper(&tmp_vol_obj) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL wrapper info") + vol_wrapper_set = TRUE; + + /* Call the corresponding internal VOL routine */ + if (H5VL__dataset_read(count, obj, connector->cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, + req) < 0) + HGOTO_ERROR(H5E_VOL, H5E_READERROR, FAIL, "dataset read failed") + +done: + /* Reset object wrapping info in API context */ + if (vol_wrapper_set && H5VL_reset_vol_wrapper() < 0) + HDONE_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't reset VOL wrapper info") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_dataset_read_direct() */ + +/*------------------------------------------------------------------------- * Function: H5VL_dataset_read * * Purpose: Reads data from dataset through the VOL @@ -2060,21 +2110,44 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VL_dataset_read(const H5VL_object_t *vol_obj, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, void *buf, void **req) +H5VL_dataset_read(size_t count, const H5VL_object_t *vol_obj[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **req) { - hbool_t vol_wrapper_set = FALSE; /* Whether the VOL object wrapping context was set up */ - herr_t ret_value = SUCCEED; /* Return value */ + hbool_t vol_wrapper_set = FALSE; /* Whether the VOL object wrapping context was set up */ + void *obj_local; /* Local buffer for obj */ + void **obj = &obj_local; /* Array of object pointers */ + size_t i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) + HDassert(vol_obj); + HDassert(vol_obj[0]); + /* Set wrapper info in API context */ - if (H5VL_set_vol_wrapper(vol_obj) < 0) + if (H5VL_set_vol_wrapper(vol_obj[0]) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL wrapper info") vol_wrapper_set = TRUE; + /* Allocate obj array if necessary */ + if (count > 1) + if (NULL == (obj = (void **)H5MM_malloc(count * sizeof(void *)))) + HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate space for object array") + + /* Build obj array */ + for (i = 0; i < count; i++) { + /* Get the object */ + obj[i] = vol_obj[i]->data; + + /* Make sure the class matches */ + if (vol_obj[i]->connector->cls->value != vol_obj[0]->connector->cls->value) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "datasets are accessed through different VOL connectors and can't be used in the " + "same I/O call") + } + /* Call the corresponding internal VOL routine */ - if (H5VL__dataset_read(vol_obj->data, vol_obj->connector->cls, mem_type_id, mem_space_id, file_space_id, + if (H5VL__dataset_read(count, obj, vol_obj[0]->connector->cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) HGOTO_ERROR(H5E_VOL, H5E_READERROR, FAIL, "dataset read failed") @@ -2083,6 +2156,10 @@ done: if (vol_wrapper_set && H5VL_reset_vol_wrapper() < 0) HDONE_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't reset VOL wrapper info") + /* Free memory */ + if (obj != &obj_local) + H5MM_free(obj); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL_dataset_read() */ @@ -2097,24 +2174,36 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VLdataset_read(void *obj, hid_t connector_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, void *buf, void **req /*out*/) +H5VLdataset_read(size_t count, void *obj[], hid_t connector_id, hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **req /*out*/) { H5VL_class_t *cls; /* VOL connector's class struct */ + size_t i; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API_NOINIT - H5TRACE8("e", "*xiiiii*xx", obj, connector_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, - req); + H5TRACE9("e", "z**xi*i*i*ii**xx", count, obj, connector_id, mem_type_id, mem_space_id, file_space_id, + dxpl_id, buf, req); /* Check args and get class pointer */ if (NULL == obj) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid object") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "obj array not provided") + for (i = 1; i < count; i++) + if (NULL == obj[i]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid object") + if (NULL == mem_type_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_type_id array not provided") + if (NULL == mem_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_space_id array not provided") + if (NULL == file_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_space_id array not provided") + if (NULL == buf) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf array not provided") if (NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a VOL connector ID") /* Call the corresponding internal VOL routine */ - if (H5VL__dataset_read(obj, cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) + if (H5VL__dataset_read(count, obj, cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to read dataset") done: @@ -2122,9 +2211,9 @@ done: } /* end H5VLdataset_read() */ /*------------------------------------------------------------------------- - * Function: H5VL__dataset_write + * Function: H5VL__dataset_write * - * Purpose: Writes data from dataset through the VOL + * Purpose: Writes data from dataset through the VOL * * Return: Success: Non-negative * Failure: Negative @@ -2132,8 +2221,8 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5VL__dataset_write(void *obj, const H5VL_class_t *cls, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t dxpl_id, const void *buf, void **req) +H5VL__dataset_write(size_t count, void *obj[], const H5VL_class_t *cls, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void **req) { herr_t ret_value = SUCCEED; /* Return value */ @@ -2144,7 +2233,7 @@ H5VL__dataset_write(void *obj, const H5VL_class_t *cls, hid_t mem_type_id, hid_t HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset write' method") /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.write)(obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) + if ((cls->dataset_cls.write)(count, obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) HGOTO_ERROR(H5E_VOL, H5E_WRITEERROR, FAIL, "dataset write failed") done: @@ -2152,6 +2241,55 @@ done: } /* end H5VL__dataset_write() */ /*------------------------------------------------------------------------- + * Function: H5VL_dataset_write_direct + * + * Purpose: Writes data from dataset through the VOL. This is like + * H5VL_dataset_write, but takes an array of void * for the + * objects and a class pointer instead of an array of + * H5VL_object_t. This allows us to avoid allocating and + * copying an extra array (of H5VL_object_ts). + * + * Return: Success: Non-negative + * Failure: Negative + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_dataset_write_direct(size_t count, void *obj[], H5VL_t *connector, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, const void *buf[], + void **req) +{ + hbool_t vol_wrapper_set = FALSE; /* Whether the VOL object wrapping context was set up */ + H5VL_object_t tmp_vol_obj; /* Temporary VOL object for setting VOL wrapper */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(obj); + HDassert(connector); + + /* Set wrapper info in API context */ + tmp_vol_obj.data = obj[0]; + tmp_vol_obj.connector = connector; + tmp_vol_obj.rc = 1; + if (H5VL_set_vol_wrapper(&tmp_vol_obj) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL wrapper info") + vol_wrapper_set = TRUE; + + /* Call the corresponding internal VOL routine */ + if (H5VL__dataset_write(count, obj, connector->cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, + buf, req) < 0) + HGOTO_ERROR(H5E_VOL, H5E_WRITEERROR, FAIL, "dataset write failed") + +done: + /* Reset object wrapping info in API context */ + if (vol_wrapper_set && H5VL_reset_vol_wrapper() < 0) + HDONE_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't reset VOL wrapper info") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_dataset_write_direct() */ + +/*------------------------------------------------------------------------- * Function: H5VL_dataset_write * * Purpose: Writes data from dataset through the VOL @@ -2162,21 +2300,44 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VL_dataset_write(const H5VL_object_t *vol_obj, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, const void *buf, void **req) +H5VL_dataset_write(size_t count, const H5VL_object_t *vol_obj[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void **req) { - hbool_t vol_wrapper_set = FALSE; /* Whether the VOL object wrapping context was set up */ - herr_t ret_value = SUCCEED; /* Return value */ + hbool_t vol_wrapper_set = FALSE; /* Whether the VOL object wrapping context was set up */ + void *obj_local; /* Local buffer for obj */ + void **obj = &obj_local; /* Array of object pointers */ + size_t i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) + HDassert(vol_obj); + HDassert(vol_obj[0]); + /* Set wrapper info in API context */ - if (H5VL_set_vol_wrapper(vol_obj) < 0) + if (H5VL_set_vol_wrapper(vol_obj[0]) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL wrapper info") vol_wrapper_set = TRUE; + /* Allocate obj array if necessary */ + if (count > 1) + if (NULL == (obj = (void **)H5MM_malloc(count * sizeof(void *)))) + HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate space for object array") + + /* Build obj array */ + for (i = 0; i < count; i++) { + /* Get the object */ + obj[i] = vol_obj[i]->data; + + /* Make sure the class matches */ + if (vol_obj[i]->connector->cls->value != vol_obj[0]->connector->cls->value) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "datasets are accessed through different VOL connectors and can't be used in the " + "same I/O call") + } + /* Call the corresponding internal VOL routine */ - if (H5VL__dataset_write(vol_obj->data, vol_obj->connector->cls, mem_type_id, mem_space_id, file_space_id, + if (H5VL__dataset_write(count, obj, vol_obj[0]->connector->cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) HGOTO_ERROR(H5E_VOL, H5E_WRITEERROR, FAIL, "dataset write failed") @@ -2185,6 +2346,10 @@ done: if (vol_wrapper_set && H5VL_reset_vol_wrapper() < 0) HDONE_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't reset VOL wrapper info") + /* Free memory */ + if (obj != &obj_local) + H5MM_free(obj); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL_dataset_write() */ @@ -2199,24 +2364,36 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VLdataset_write(void *obj, hid_t connector_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, const void *buf, void **req /*out*/) +H5VLdataset_write(size_t count, void *obj[], hid_t connector_id, hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void **req /*out*/) { H5VL_class_t *cls; /* VOL connector's class struct */ + size_t i; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API_NOINIT - H5TRACE8("e", "*xiiiii*xx", obj, connector_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, - req); + H5TRACE9("e", "z**xi*i*i*ii**xx", count, obj, connector_id, mem_type_id, mem_space_id, file_space_id, + dxpl_id, buf, req); /* Check args and get class pointer */ if (NULL == obj) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid object") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "obj array not provided") + for (i = 1; i < count; i++) + if (NULL == obj[i]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid object") + if (NULL == mem_type_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_type_id array not provided") + if (NULL == mem_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_space_id array not provided") + if (NULL == file_space_id) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_space_id array not provided") + if (NULL == buf) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf array not provided") if (NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a VOL connector ID") /* Call the corresponding internal VOL routine */ - if (H5VL__dataset_write(obj, cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) + if (H5VL__dataset_write(count, obj, cls, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to write dataset") done: diff --git a/src/H5VLconnector.h b/src/H5VLconnector.h index bb434be..ad28136 100644 --- a/src/H5VLconnector.h +++ b/src/H5VLconnector.h @@ -879,10 +879,10 @@ typedef struct H5VL_dataset_class_t { hid_t type_id, hid_t space_id, hid_t dcpl_id, hid_t dapl_id, hid_t dxpl_id, void **req); void *(*open)(void *obj, const H5VL_loc_params_t *loc_params, const char *name, hid_t dapl_id, hid_t dxpl_id, void **req); - herr_t (*read)(void *dset, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, hid_t dxpl_id, - void *buf, void **req); - herr_t (*write)(void *dset, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, hid_t dxpl_id, - const void *buf, void **req); + herr_t (*read)(size_t count, void *dset[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **req); + herr_t (*write)(size_t count, void *dset[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void **req); herr_t (*get)(void *obj, H5VL_dataset_get_args_t *args, hid_t dxpl_id, void **req); herr_t (*specific)(void *obj, H5VL_dataset_specific_args_t *args, hid_t dxpl_id, void **req); herr_t (*optional)(void *obj, H5VL_optional_args_t *args, hid_t dxpl_id, void **req); diff --git a/src/H5VLconnector_passthru.h b/src/H5VLconnector_passthru.h index 03264be..079a869 100644 --- a/src/H5VLconnector_passthru.h +++ b/src/H5VLconnector_passthru.h @@ -107,10 +107,12 @@ H5_DLL void *H5VLdataset_create(void *obj, const H5VL_loc_params_t *loc_params, hid_t dapl_id, hid_t dxpl_id, void **req); H5_DLL void *H5VLdataset_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_id, const char *name, hid_t dapl_id, hid_t dxpl_id, void **req); -H5_DLL herr_t H5VLdataset_read(void *dset, hid_t connector_id, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t plist_id, void *buf, void **req); -H5_DLL herr_t H5VLdataset_write(void *dset, hid_t connector_id, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t plist_id, const void *buf, void **req); +H5_DLL herr_t H5VLdataset_read(size_t count, void *dset[], hid_t connector_id, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t plist_id, void *buf[], + void **req); +H5_DLL herr_t H5VLdataset_write(size_t count, void *dset[], hid_t connector_id, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t plist_id, + const void *buf[], void **req); H5_DLL herr_t H5VLdataset_get(void *dset, hid_t connector_id, H5VL_dataset_get_args_t *args, hid_t dxpl_id, void **req); H5_DLL herr_t H5VLdataset_specific(void *obj, hid_t connector_id, H5VL_dataset_specific_args_t *args, diff --git a/src/H5VLnative_dataset.c b/src/H5VLnative_dataset.c index 26daa83..9bd711b 100644 --- a/src/H5VLnative_dataset.c +++ b/src/H5VLnative_dataset.c @@ -50,8 +50,11 @@ /********************/ /* Helper routines for read/write API calls */ -static herr_t H5VL__native_dataset_io_setup(H5D_t *dset, hid_t dxpl_id, hid_t file_space_id, - hid_t mem_space_id, H5S_t **file_space, H5S_t **mem_space); +static herr_t H5VL__native_dataset_io_setup(size_t count, void *obj[], hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, + H5_flexible_const_ptr_t buf[], H5D_dset_io_info_t *dinfo); +static herr_t H5VL__native_dataset_io_cleanup(size_t count, hid_t mem_space_id[], hid_t file_space_id[], + H5D_dset_io_info_t *dinfo); /*********************/ /* Package Variables */ @@ -75,91 +78,155 @@ static herr_t H5VL__native_dataset_io_setup(H5D_t *dset, hid_t dxpl_id, hid_t fi *------------------------------------------------------------------------- */ static herr_t -H5VL__native_dataset_io_setup(H5D_t *dset, hid_t dxpl_id, hid_t file_space_id, hid_t mem_space_id, - H5S_t **file_space, H5S_t **mem_space) +H5VL__native_dataset_io_setup(size_t count, void *obj[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, H5_flexible_const_ptr_t buf[], + H5D_dset_io_info_t *dinfo) { - herr_t ret_value = SUCCEED; /* Return value */ + H5F_shared_t *f_sh; + size_t i; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity checks */ - HDassert(dset); - HDassert(file_space && NULL == *file_space); - HDassert(mem_space && NULL == *mem_space); - - /* Set up file dataspace */ - if (H5S_ALL == file_space_id) - /* Use dataspace for dataset */ - *file_space = dset->shared->space; - else if (H5S_BLOCK == file_space_id) - HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "H5S_BLOCK is not allowed for file dataspace") - else if (H5S_PLIST == file_space_id) { - H5P_genplist_t *plist; /* Property list pointer */ - H5S_t *space; /* Dataspace to hold selection */ - - /* Get the plist structure */ - if (NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER))) - HGOTO_ERROR(H5E_DATASET, H5E_BADID, FAIL, "bad dataset transfer property list") - - /* See if a dataset I/O selection is already set, and free it if it is */ - if (H5P_peek(plist, H5D_XFER_DSET_IO_SEL_NAME, &space) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error getting dataset I/O selection") - - /* Use dataspace for dataset */ - *file_space = dset->shared->space; - - /* Copy, but share, selection from property list to dataset's dataspace */ - if (H5S_SELECT_COPY(*file_space, space, TRUE) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dataset I/O selection") - } /* end else-if */ - else { - /* Get the dataspace pointer */ - if (NULL == (*file_space = (H5S_t *)H5I_object_verify(file_space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "file_space_id is not a dataspace ID") - } /* end else */ - - /* Get dataspace for memory buffer */ - if (H5S_ALL == mem_space_id) - *mem_space = *file_space; - else if (H5S_BLOCK == mem_space_id) { - hsize_t nelmts; /* # of selected elements in file */ - - /* Get the # of elements selected */ - nelmts = H5S_GET_SELECT_NPOINTS(*file_space); + HDassert(dinfo); + + /* Get shared file */ + f_sh = H5F_SHARED(((H5D_t *)obj[0])->oloc.file); + + /* Iterate over datasets */ + for (i = 0; i < count; i++) { + /* Set up dset */ + dinfo[i].dset = (H5D_t *)obj[i]; + HDassert(dinfo[i].dset); + + /* Check dataset's file pointer is valid */ + if (NULL == dinfo[i].dset->oloc.file) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dataset is not associated with a file") + if (f_sh != H5F_SHARED(dinfo[i].dset->oloc.file)) + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, + "different files detected in multi dataset I/O request") + + /* Set up memory type */ + dinfo[i].mem_type_id = mem_type_id[i]; + + /* Set up file dataspace */ + if (H5S_ALL == file_space_id[i]) + /* Use dataspace for dataset */ + dinfo[i].file_space = dinfo[i].dset->shared->space; + else if (H5S_BLOCK == file_space_id[i]) + HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "H5S_BLOCK is not allowed for file dataspace") + else if (H5S_PLIST == file_space_id[i]) { + H5P_genplist_t *plist; /* Property list pointer */ + H5S_t *space; /* Dataspace to hold selection */ + + /* Get the plist structure */ + if (NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER))) + HGOTO_ERROR(H5E_DATASET, H5E_BADID, FAIL, "bad dataset transfer property list") + + /* Get a pointer to the file space in the property list */ + if (H5P_peek(plist, H5D_XFER_DSET_IO_SEL_NAME, &space) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error getting dataset I/O selection") + + /* Use dataspace for dataset */ + dinfo[i].file_space = dinfo[i].dset->shared->space; + + /* Copy, but share, selection from property list to dataset's dataspace */ + if (H5S_SELECT_COPY(dinfo[i].file_space, space, TRUE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dataset I/O selection") + } /* end else-if */ + else { + /* Get the dataspace pointer */ + if (NULL == (dinfo[i].file_space = (H5S_t *)H5I_object_verify(file_space_id[i], H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "file_space_id is not a dataspace ID") + } /* end else */ - /* Check for any elements */ - if (nelmts > 0) { - /* Create a 1-D dataspace of the same # of elements */ - if (NULL == (*mem_space = H5S_create_simple(1, &nelmts, NULL))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create simple memory dataspace") - } /* end if */ + /* Get dataspace for memory buffer */ + if (H5S_ALL == mem_space_id[i]) + dinfo[i].mem_space = dinfo[i].file_space; + else if (H5S_BLOCK == mem_space_id[i]) { + hsize_t nelmts; /* # of selected elements in file */ + + /* Get the # of elements selected */ + nelmts = H5S_GET_SELECT_NPOINTS(dinfo[i].file_space); + + /* Check for any elements */ + if (nelmts > 0) { + /* Create a 1-D dataspace of the same # of elements */ + if (NULL == (dinfo[i].mem_space = H5S_create_simple(1, &nelmts, NULL))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create simple memory dataspace") + } /* end if */ + else { + /* Create a NULL dataspace of the same # of elements */ + if (NULL == (dinfo[i].mem_space = H5S_create(H5S_NULL))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create NULL memory dataspace") + } /* end else */ + } /* end if */ + else if (H5S_PLIST == mem_space_id[i]) + HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "H5S_PLIST is not allowed for memory dataspace") else { - /* Create a NULL dataspace of the same # of elements */ - if (NULL == (*mem_space = H5S_create(H5S_NULL))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create NULL memory dataspace") + /* Get the dataspace pointer */ + if (NULL == (dinfo[i].mem_space = (H5S_t *)H5I_object_verify(mem_space_id[i], H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "mem_space_id is not a dataspace ID") } /* end else */ - } /* end if */ - else if (H5S_PLIST == mem_space_id) - HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "H5S_PLIST is not allowed for memory dataspace") - else { - /* Get the dataspace pointer */ - if (NULL == (*mem_space = (H5S_t *)H5I_object_verify(mem_space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "mem_space_id is not a dataspace ID") - } /* end else */ - /* Check for valid selections */ - if (H5S_SELECT_VALID(*file_space) != TRUE) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, - "selection + offset not within extent for file dataspace") - if (H5S_SELECT_VALID(*mem_space) != TRUE) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, - "selection + offset not within extent for memory dataspace") + /* Check for valid selections */ + if (H5S_SELECT_VALID(dinfo[i].file_space) != TRUE) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, + "selection + offset not within extent for file dataspace") + if (H5S_SELECT_VALID(dinfo[i].mem_space) != TRUE) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, + "selection + offset not within extent for memory dataspace") + + /* Set up buf */ + dinfo[i].buf = buf[i]; + } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL__native_dataset_io_setup() */ /*------------------------------------------------------------------------- + * Function: H5VL__native_dataset_io_cleanup + * + * Purpose: Frees memory allocated by H5VL__native_dataset_io_setup() + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5VL__native_dataset_io_cleanup(size_t count, hid_t mem_space_id[], hid_t file_space_id[], + H5D_dset_io_info_t *dinfo) +{ + size_t i; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Sanity checks */ + HDassert(dinfo); + + /* Iterate over datasets */ + for (i = 0; i < count; i++) { + /* Free memory dataspace if it was created. Use HDONE_ERROR in this function so we always + * try to free everything we can. */ + if (H5S_BLOCK == mem_space_id[i] && dinfo[i].mem_space) + if (H5S_close(dinfo[i].mem_space) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, + "unable to release temporary memory dataspace for H5S_BLOCK") + + /* Reset file dataspace selection if it was copied from the property list */ + if (H5S_PLIST == file_space_id[i] && dinfo[i].file_space) + if (H5S_select_all(dinfo[i].file_space, TRUE) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, + "unable to release file dataspace selection for H5S_PLIST") + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__native_dataset_io_cleanup() */ + +/*------------------------------------------------------------------------- * Function: H5VL__native_dataset_create * * Purpose: Handles the dataset create callback @@ -267,43 +334,39 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VL__native_dataset_read(void *obj, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, void *buf, void H5_ATTR_UNUSED **req) +H5VL__native_dataset_read(size_t count, void *obj[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[], void H5_ATTR_UNUSED **req) { - H5D_t *dset = (H5D_t *)obj; - H5S_t *mem_space = NULL; - H5S_t *file_space = NULL; - herr_t ret_value = SUCCEED; /* Return value */ + H5D_dset_io_info_t dinfo_local; + H5D_dset_io_info_t *dinfo = &dinfo_local; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE - /* Check arguments */ - if (NULL == dset->oloc.file) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dataset is not associated with a file") + /* Allocate dataset info array if necessary */ + if (count > 1) + if (NULL == (dinfo = (H5D_dset_io_info_t *)H5MM_malloc(count * sizeof(H5D_dset_io_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") /* Get file & memory dataspaces */ - if (H5VL__native_dataset_io_setup(dset, dxpl_id, file_space_id, mem_space_id, &file_space, &mem_space) < - 0) + if (H5VL__native_dataset_io_setup(count, obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, + (H5_flexible_const_ptr_t *)buf, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up file and memory dataspaces") /* Set DXPL for operation */ H5CX_set_dxpl(dxpl_id); - /* Read raw data */ - if (H5D__read(dset, mem_type_id, mem_space, file_space, buf /*out*/) < 0) + /* Read raw data. Call H5D__read directly in single dset case. */ + if (H5D__read(count, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") done: /* Clean up */ - if (H5S_BLOCK == mem_space_id && mem_space) { - if (H5S_close(mem_space) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, - "unable to release temporary memory dataspace for H5S_BLOCK") - } /* end if */ - else if (H5S_PLIST == file_space_id && file_space) - if (H5S_select_all(file_space, TRUE) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, - "unable to release file dataspace selection for H5S_PLIST") + if (H5VL__native_dataset_io_cleanup(count, mem_space_id, file_space_id, dinfo) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to release dataset info") + + if (dinfo != &dinfo_local) + H5MM_xfree(dinfo); FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL__native_dataset_read() */ @@ -318,43 +381,39 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VL__native_dataset_write(void *obj, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t dxpl_id, const void *buf, void H5_ATTR_UNUSED **req) +H5VL__native_dataset_write(size_t count, void *obj[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void H5_ATTR_UNUSED **req) { - H5D_t *dset = (H5D_t *)obj; - H5S_t *mem_space = NULL; - H5S_t *file_space = NULL; - herr_t ret_value = SUCCEED; /* Return value */ + H5D_dset_io_info_t dinfo_local; + H5D_dset_io_info_t *dinfo = &dinfo_local; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE - /* check arguments */ - if (NULL == dset->oloc.file) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dataset is not associated with a file") + /* Allocate dataset info array if necessary */ + if (count > 1) + if (NULL == (dinfo = (H5D_dset_io_info_t *)H5MM_malloc(count * sizeof(H5D_dset_io_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") /* Get file & memory dataspaces */ - if (H5VL__native_dataset_io_setup(dset, dxpl_id, file_space_id, mem_space_id, &file_space, &mem_space) < - 0) + if (H5VL__native_dataset_io_setup(count, obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, + (H5_flexible_const_ptr_t *)buf, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up file and memory dataspaces") /* Set DXPL for operation */ H5CX_set_dxpl(dxpl_id); - /* Write the data */ - if (H5D__write(dset, mem_type_id, mem_space, file_space, buf) < 0) + /* Write raw data. Call H5D__write directly in single dset case. */ + if (H5D__write(count, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") done: /* Clean up */ - if (H5S_BLOCK == mem_space_id && mem_space) { - if (H5S_close(mem_space) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, - "unable to release temporary memory dataspace for H5S_BLOCK") - } /* end if */ - else if (H5S_PLIST == file_space_id && file_space) - if (H5S_select_all(file_space, TRUE) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, - "unable to release file dataspace selection for H5S_PLIST") + if (H5VL__native_dataset_io_cleanup(count, mem_space_id, file_space_id, dinfo) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to release dataset info") + + if (dinfo != &dinfo_local) + H5MM_xfree(dinfo); FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL__native_dataset_write() */ diff --git a/src/H5VLnative_private.h b/src/H5VLnative_private.h index 82b7d33..c80c114 100644 --- a/src/H5VLnative_private.h +++ b/src/H5VLnative_private.h @@ -61,10 +61,10 @@ H5_DLL void *H5VL__native_dataset_create(void *obj, const H5VL_loc_params_t *lo hid_t dapl_id, hid_t dxpl_id, void **req); H5_DLL void *H5VL__native_dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name, hid_t dapl_id, hid_t dxpl_id, void **req); -H5_DLL herr_t H5VL__native_dataset_read(void *dset, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t plist_id, void *buf, void **req); -H5_DLL herr_t H5VL__native_dataset_write(void *dset, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t plist_id, const void *buf, void **req); +H5_DLL herr_t H5VL__native_dataset_read(size_t count, void *obj[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, void *buf[], void **req); +H5_DLL herr_t H5VL__native_dataset_write(size_t count, void *obj[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t dxpl_id, const void *buf[], void **req); H5_DLL herr_t H5VL__native_dataset_get(void *dset, H5VL_dataset_get_args_t *args, hid_t dxpl_id, void **req); H5_DLL herr_t H5VL__native_dataset_specific(void *dset, H5VL_dataset_specific_args_t *args, hid_t dxpl_id, void **req); diff --git a/src/H5VLpassthru.c b/src/H5VLpassthru.c index af79284..d7e730a 100644 --- a/src/H5VLpassthru.c +++ b/src/H5VLpassthru.c @@ -121,11 +121,12 @@ static void *H5VL_pass_through_dataset_create(void *obj, const H5VL_loc_params_ hid_t dcpl_id, hid_t dapl_id, hid_t dxpl_id, void **req); static void *H5VL_pass_through_dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name, hid_t dapl_id, hid_t dxpl_id, void **req); -static herr_t H5VL_pass_through_dataset_read(void *dset, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t plist_id, void *buf, void **req); -static herr_t H5VL_pass_through_dataset_write(void *dset, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t plist_id, const void *buf, - void **req); +static herr_t H5VL_pass_through_dataset_read(size_t count, void *dset[], hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t plist_id, + void *buf[], void **req); +static herr_t H5VL_pass_through_dataset_write(size_t count, void *dset[], hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t plist_id, + const void *buf[], void **req); static herr_t H5VL_pass_through_dataset_get(void *dset, H5VL_dataset_get_args_t *args, hid_t dxpl_id, void **req); static herr_t H5VL_pass_through_dataset_specific(void *obj, H5VL_dataset_specific_args_t *args, hid_t dxpl_id, @@ -1197,22 +1198,43 @@ H5VL_pass_through_dataset_open(void *obj, const H5VL_loc_params_t *loc_params, c *------------------------------------------------------------------------- */ static herr_t -H5VL_pass_through_dataset_read(void *dset, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t plist_id, void *buf, void **req) +H5VL_pass_through_dataset_read(size_t count, void *dset[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t plist_id, void *buf[], void **req) { - H5VL_pass_through_t *o = (H5VL_pass_through_t *)dset; - herr_t ret_value; + void *obj_local; /* Local buffer for obj */ + void **obj = &obj_local; /* Array of object pointers */ + size_t i; /* Local index variable */ + herr_t ret_value; #ifdef ENABLE_PASSTHRU_LOGGING printf("------- PASS THROUGH VOL DATASET Read\n"); #endif - ret_value = H5VLdataset_read(o->under_object, o->under_vol_id, mem_type_id, mem_space_id, file_space_id, - plist_id, buf, req); + /* Allocate obj array if necessary */ + if (count > 1) + if (NULL == (obj = (void **)malloc(count * sizeof(void *)))) + return -1; + + /* Build obj array */ + for (i = 0; i < count; i++) { + /* Get the object */ + obj[i] = ((H5VL_pass_through_t *)dset[i])->under_object; + + /* Make sure the class matches */ + if (((H5VL_pass_through_t *)dset[i])->under_vol_id != ((H5VL_pass_through_t *)dset[0])->under_vol_id) + return -1; + } + + ret_value = H5VLdataset_read(count, obj, ((H5VL_pass_through_t *)dset[0])->under_vol_id, mem_type_id, + mem_space_id, file_space_id, plist_id, buf, req); /* Check for async request */ if (req && *req) - *req = H5VL_pass_through_new_obj(*req, o->under_vol_id); + *req = H5VL_pass_through_new_obj(*req, ((H5VL_pass_through_t *)dset[0])->under_vol_id); + + /* Free memory */ + if (obj != &obj_local) + free(obj); return ret_value; } /* end H5VL_pass_through_dataset_read() */ @@ -1228,22 +1250,43 @@ H5VL_pass_through_dataset_read(void *dset, hid_t mem_type_id, hid_t mem_space_id *------------------------------------------------------------------------- */ static herr_t -H5VL_pass_through_dataset_write(void *dset, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, - hid_t plist_id, const void *buf, void **req) +H5VL_pass_through_dataset_write(size_t count, void *dset[], hid_t mem_type_id[], hid_t mem_space_id[], + hid_t file_space_id[], hid_t plist_id, const void *buf[], void **req) { - H5VL_pass_through_t *o = (H5VL_pass_through_t *)dset; - herr_t ret_value; + void *obj_local; /* Local buffer for obj */ + void **obj = &obj_local; /* Array of object pointers */ + size_t i; /* Local index variable */ + herr_t ret_value; #ifdef ENABLE_PASSTHRU_LOGGING printf("------- PASS THROUGH VOL DATASET Write\n"); #endif - ret_value = H5VLdataset_write(o->under_object, o->under_vol_id, mem_type_id, mem_space_id, file_space_id, - plist_id, buf, req); + /* Allocate obj array if necessary */ + if (count > 1) + if (NULL == (obj = (void **)malloc(count * sizeof(void *)))) + return -1; + + /* Build obj array */ + for (i = 0; i < count; i++) { + /* Get the object */ + obj[i] = ((H5VL_pass_through_t *)dset[i])->under_object; + + /* Make sure the class matches */ + if (((H5VL_pass_through_t *)dset[i])->under_vol_id != ((H5VL_pass_through_t *)dset[0])->under_vol_id) + return -1; + } + + ret_value = H5VLdataset_write(count, obj, ((H5VL_pass_through_t *)dset[0])->under_vol_id, mem_type_id, + mem_space_id, file_space_id, plist_id, buf, req); /* Check for async request */ if (req && *req) - *req = H5VL_pass_through_new_obj(*req, o->under_vol_id); + *req = H5VL_pass_through_new_obj(*req, ((H5VL_pass_through_t *)dset[0])->under_vol_id); + + /* Free memory */ + if (obj != &obj_local) + free(obj); return ret_value; } /* end H5VL_pass_through_dataset_write() */ diff --git a/src/H5VLprivate.h b/src/H5VLprivate.h index a61b03e..5f73e74 100644 --- a/src/H5VLprivate.h +++ b/src/H5VLprivate.h @@ -177,10 +177,18 @@ H5_DLL void *H5VL_dataset_create(const H5VL_object_t *vol_obj, const H5VL_loc_p hid_t dcpl_id, hid_t dapl_id, hid_t dxpl_id, void **req); H5_DLL void *H5VL_dataset_open(const H5VL_object_t *vol_obj, const H5VL_loc_params_t *loc_params, const char *name, hid_t dapl_id, hid_t dxpl_id, void **req); -H5_DLL herr_t H5VL_dataset_read(const H5VL_object_t *vol_obj, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t dxpl_id, void *buf, void **req); -H5_DLL herr_t H5VL_dataset_write(const H5VL_object_t *vol_obj, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t dxpl_id, const void *buf, void **req); +H5_DLL herr_t H5VL_dataset_read(size_t count, const H5VL_object_t *vol_obj[], hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, void *buf[], + void **req); +H5_DLL herr_t H5VL_dataset_read_direct(size_t count, void *obj[], H5VL_t *connector, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, + void *buf[], void **req); +H5_DLL herr_t H5VL_dataset_write(size_t count, const H5VL_object_t *vol_obj[], hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, + const void *buf[], void **req); +H5_DLL herr_t H5VL_dataset_write_direct(size_t count, void *obj[], H5VL_t *connector, hid_t mem_type_id[], + hid_t mem_space_id[], hid_t file_space_id[], hid_t dxpl_id, + const void *buf[], void **req); H5_DLL herr_t H5VL_dataset_get(const H5VL_object_t *vol_obj, H5VL_dataset_get_args_t *args, hid_t dxpl_id, void **req); H5_DLL herr_t H5VL_dataset_specific(const H5VL_object_t *cls, H5VL_dataset_specific_args_t *args, diff --git a/src/H5private.h b/src/H5private.h index f9ff043..5f755b2 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -2512,7 +2512,9 @@ H5_DLL herr_t H5CX_pop(hbool_t update_dxpl_props); /* Union for const/non-const pointer for use by functions that manipulate * pointers but do not write to their targets or return pointers to const - * specified locations. This helps us avoid compiler warnings. */ + * specified locations. Also used for I/O functions that work for read and + * write - these functions are expected to never write to these locations in the + * write case. This helps us avoid compiler warnings. */ typedef union { void *vp; const void *cvp; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b5af95e..a9412f0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -339,6 +339,7 @@ set (H5_TESTS dsets chunk_info # compression lib link cmpd_dset + mdset filter_fail extend direct_chunk # compression lib link diff --git a/test/Makefile.am b/test/Makefile.am index d441113..2176222 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -64,7 +64,7 @@ TEST_PROG= testhdf5 \ cache cache_api cache_image cache_tagging lheap ohdr \ stab gheap evict_on_close farray earray btree2 fheap \ accum hyperslab istore bittests dt_arith page_buffer \ - dtypes dsets chunk_info cmpd_dset cmpd_dtransform filter_fail extend direct_chunk \ + dtypes dsets chunk_info cmpd_dset mdset cmpd_dtransform filter_fail extend direct_chunk \ external efc objcopy objcopy_ref links unlink twriteorder big mtime \ fillval mount \ flush1 flush2 app_ref enum set_extent ttsafe enc_dec_plist \ @@ -184,7 +184,7 @@ flush2.chkexe_: flush1.chkexe_ # specifying a file prefix or low-level driver. Changing the file # prefix or low-level driver with environment variables will influence # the temporary file name in ways that the makefile is not aware of. -CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offset.h5 \ +CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 mdset.h5 compact_dataset.h5 dataset.h5 dset_offset.h5 \ max_compact_dataset.h5 simple.h5 set_local.h5 random_chunks.h5 \ huge_chunks.h5 chunk_cache.h5 big_chunk.h5 chunk_fast.h5 chunk_expand.h5 \ chunk_fixed.h5 copy_dcpl_newfile.h5 partial_chunks.h5 layout_extend.h5 \ diff --git a/test/mdset.c b/test/mdset.c new file mode 100644 index 0000000..f1e50e7 --- /dev/null +++ b/test/mdset.c @@ -0,0 +1,714 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Neil Fortner + * March 10, 2014 + * + * Purpose: Test H5Dwrite_multi() and H5Dread_multi using randomized + * parameters. Also tests H5Dwrite() and H5Dread() using a similar + * method. + */ + +#include "h5test.h" + +#define NAME_BUF_SIZE 1024 +#define MAX_DSETS 6 +#define MAX_DSET_X 10 +#define MAX_DSET_Y 10 +#define MAX_CHUNK_X 4 +#define MAX_CHUNK_Y 4 +#define MAX_HS_X 6 +#define MAX_HS_Y 6 +#define MAX_HS 3 +#define MAX_POINTS 6 +#define OPS_PER_FILE 50 +#define DSET_MAX_NAME_LEN 8 +#define EXT_FILENAME "mdset_ext.h5" +#define SOURCE_DS_NAME "vds_source" + +/* Option flags */ +#define MDSET_FLAG_CHUNK 0x01u +#define MDSET_FLAG_MLAYOUT 0x02u +#define MDSET_FLAG_SHAPESAME 0x04u +#define MDSET_FLAG_MDSET 0x08u +#define MDSET_FLAG_TCONV 0x10u +#define MDSET_FLAG_FILTER 0x20u +#define MDSET_ALL_FLAGS \ + (MDSET_FLAG_CHUNK | MDSET_FLAG_MLAYOUT | MDSET_FLAG_SHAPESAME | MDSET_FLAG_MDSET | MDSET_FLAG_TCONV | \ + MDSET_FLAG_FILTER) + +const char *FILENAME[] = {"mdset", "mdset1", "mdset2", NULL}; + +/* Names for datasets */ +char dset_name[MAX_DSETS][DSET_MAX_NAME_LEN]; + +/* Whether these filters are available */ +htri_t deflate_avail = FALSE; +htri_t fletcher32_avail = FALSE; + +static int +test_mdset_location(hid_t fapl_id) +{ + hid_t file_id1, file_id2; + herr_t ret; + hid_t dset_ids[2]; + hid_t mem_type_ids[2]; + hid_t mem_space_ids[2]; + hid_t file_space_ids[2]; + void *rbufs[2]; + const void *wbufs[2]; + hsize_t dset_dims[2]; + int *buf = NULL; + char filename1[NAME_BUF_SIZE]; + char filename2[NAME_BUF_SIZE]; + + TESTING("mdset location"); + + h5_fixname(FILENAME[1], fapl_id, filename1, sizeof filename1); + h5_fixname(FILENAME[2], fapl_id, filename2, sizeof filename2); + + /* Create files */ + if ((file_id1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + TEST_ERROR; + if ((file_id2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + TEST_ERROR; + + if (NULL == (buf = (int *)HDcalloc(2 * MAX_DSET_X * MAX_DSET_Y, sizeof(int)))) + TEST_ERROR; + + /* Generate memory dataspace */ + dset_dims[0] = MAX_DSET_X; + dset_dims[1] = MAX_DSET_Y; + if ((file_space_ids[0] = H5Screate_simple(2, dset_dims, NULL)) < 0) + TEST_ERROR; + if ((file_space_ids[1] = H5Screate_simple(2, dset_dims, NULL)) < 0) + TEST_ERROR; + + mem_space_ids[0] = H5S_ALL; + mem_space_ids[1] = H5S_ALL; + + mem_type_ids[0] = H5T_NATIVE_UINT; + mem_type_ids[1] = H5T_NATIVE_UINT; + + if ((dset_ids[0] = H5Dcreate2(file_id1, dset_name[0], H5T_NATIVE_UINT, file_space_ids[0], H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if ((dset_ids[1] = H5Dcreate2(file_id2, dset_name[1], H5T_NATIVE_UINT, file_space_ids[1], H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + wbufs[0] = buf; + wbufs[1] = buf + (MAX_DSET_X * MAX_DSET_Y); + + H5E_BEGIN_TRY + { + ret = H5Dwrite_multi(2, dset_ids, mem_type_ids, mem_space_ids, file_space_ids, H5P_DEFAULT, wbufs); + } + H5E_END_TRY + + if (ret >= 0) { + fprintf(stderr, "H5Dmulti_write with datasets in multiple files should fail.\n"); + TEST_ERROR; + } + + rbufs[0] = buf; + rbufs[1] = buf + (MAX_DSET_X * MAX_DSET_Y); + + H5E_BEGIN_TRY + { + ret = H5Dread_multi(2, dset_ids, mem_type_ids, mem_space_ids, file_space_ids, H5P_DEFAULT, rbufs); + } + H5E_END_TRY + + if (ret >= 0) { + fprintf(stderr, "H5Dmulti_read with datasets in multiple files should fail.\n"); + TEST_ERROR; + } + + H5Dclose(dset_ids[0]); + H5Sclose(file_space_ids[0]); + H5Dclose(dset_ids[1]); + H5Sclose(file_space_ids[1]); + H5Fclose(file_id1); + H5Fclose(file_id2); + + if (buf) + free(buf); + + PASSED(); + return 0; + +error: + if (buf) + free(buf); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: test_mdset + * + * Purpose: Test randomized I/O using one or more datasets. Creates a + * file, runs OPS_PER_FILE read or write operations verifying + * that reads return the expected data, then closes the file. + * Runs the test with a new file niter times. + * + * The operations can use either hyperslab or point + * selections. Options are available for chunked or + * contiguous layout, use of multiple datasets and H5D*_multi + * calls, and use of the "shapesame" algorithm code path. To + * avoid the shapesame path when that option is not set, this + * function simply adds a dimension to the memory buffer in a + * way that the shapesame code is not designed to handle. + * + * Return: Number of errors + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +static int +test_mdset(size_t niter, unsigned flags, hid_t fapl_id) +{ + hid_t dset_ids[MAX_DSETS]; + hid_t mem_type_ids[MAX_DSETS]; + hid_t mem_space_ids[MAX_DSETS]; + hid_t file_space_ids[MAX_DSETS]; + void *rbufs[MAX_DSETS]; + const void *wbufs[MAX_DSETS]; + size_t max_dsets; + size_t buf_size; + size_t ndsets; + hid_t file_id = -1; + hid_t dcpl_id[MAX_DSETS]; + hsize_t dset_dims[MAX_DSETS][3]; + hsize_t chunk_dims[2]; + hsize_t max_dims[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; + unsigned *rbuf = NULL; + unsigned *rbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *erbuf = NULL; + unsigned *erbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *wbuf = NULL; + unsigned *wbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *efbuf = NULL; + unsigned *efbufi[MAX_DSETS][MAX_DSET_X]; + hbool_t do_read; + hsize_t start[3]; + hsize_t count[3]; + hsize_t points[3 * MAX_POINTS]; + char filename[NAME_BUF_SIZE]; + size_t i, j, k, l, m, n; + + TESTING("random I/O"); + + h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename); + + /* Calculate maximum number of datasets */ + max_dsets = (flags & MDSET_FLAG_MDSET) ? MAX_DSETS : 1; + + /* Calculate buffer size */ + buf_size = max_dsets * MAX_DSET_X * MAX_DSET_Y * sizeof(unsigned); + + /* Initialize dcpl_id array */ + for (i = 0; i < max_dsets; i++) + dcpl_id[i] = -1; + + /* Allocate buffers */ + if (NULL == (rbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR; + if (NULL == (erbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR; + if (NULL == (wbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR; + if (NULL == (efbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR; + + /* Initialize buffer indices */ + for (i = 0; i < max_dsets; i++) + for (j = 0; j < MAX_DSET_X; j++) { + rbufi[i][j] = rbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + erbufi[i][j] = erbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + wbufi[i][j] = wbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + efbufi[i][j] = efbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + } /* end for */ + + /* Initialize 3rd dimension information (for tricking library into using + * non-"shapesame" code */ + for (i = 0; i < max_dsets; i++) + dset_dims[i][2] = 1; + start[2] = 0; + count[2] = 1; + + /* Initialize IDs */ + for (i = 0; i < max_dsets; i++) { + dset_ids[i] = -1; + file_space_ids[i] = -1; + mem_type_ids[i] = H5T_NATIVE_UINT; + mem_space_ids[i] = -1; + } /* end for */ + + /* Generate memory dataspace */ + dset_dims[0][0] = MAX_DSET_X; + dset_dims[0][1] = MAX_DSET_Y; + if ((mem_space_ids[0] = H5Screate_simple((flags & MDSET_FLAG_SHAPESAME) ? 2 : 3, dset_dims[0], NULL)) < 0) + TEST_ERROR; + for (i = 1; i < max_dsets; i++) + if ((mem_space_ids[i] = H5Scopy(mem_space_ids[0])) < 0) + TEST_ERROR; + + /* Create dcpl 0 */ + if ((dcpl_id[0] = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + /* Set fill time to alloc, and alloc time to early (so we always know + * what's in the file) */ + if (H5Pset_fill_time(dcpl_id[0], H5D_FILL_TIME_ALLOC) < 0) + TEST_ERROR; + if (H5Pset_alloc_time(dcpl_id[0], H5D_ALLOC_TIME_EARLY) < 0) + TEST_ERROR; + + /* Set filters if requested */ + if (flags & MDSET_FLAG_FILTER) { + if (fletcher32_avail) + if (H5Pset_fletcher32(dcpl_id[0]) < 0) + TEST_ERROR; + if (deflate_avail) + if (H5Pset_deflate(dcpl_id[0], 1) < 0) + TEST_ERROR; + } + + /* Copy dcpl 0 to other slots in dcpl_id array */ + for (i = 1; i < MAX_DSETS; i++) + if ((dcpl_id[i] = H5Pcopy(dcpl_id[0])) < 0) + TEST_ERROR; + + /* If this is a multi layout run, set up different filters and layouts. Chunked and virtual + * datasets will be set every iteration (with different dims), and contiguous is the default, so + * no need to set either of those. */ + if (flags & MDSET_FLAG_MLAYOUT) { + /* Set filters on dataset 2 */ + if (fletcher32_avail) + if (H5Pset_fletcher32(dcpl_id[2]) < 0) + TEST_ERROR; + if (deflate_avail) + if (H5Pset_deflate(dcpl_id[2], 1) < 0) + TEST_ERROR; + + /* Dataset 3 is compact */ + if (H5Pset_layout(dcpl_id[3], H5D_COMPACT) < 0) + TEST_ERROR; + + /* Dataset 4 is external */ + if (H5Pset_external(dcpl_id[4], EXT_FILENAME, 0, H5F_UNLIMITED) < 0) + TEST_ERROR; + } + + for (i = 0; i < niter; i++) { + /* Determine number of datasets */ + ndsets = (flags & MDSET_FLAG_MLAYOUT) ? 6 + : (flags & MDSET_FLAG_MDSET) ? (size_t)((size_t)HDrandom() % max_dsets) + 1 + : 1; + + /* Create file */ + if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + TEST_ERROR; + + /* Create datasets */ + for (j = 0; j < ndsets; j++) { + hid_t source_dset; + + hbool_t use_chunk = + (flags & MDSET_FLAG_CHUNK) || ((flags & MDSET_FLAG_MLAYOUT) && (j == 1 || j == 2)); + + /* Generate file dataspace */ + dset_dims[j][0] = (hsize_t)((HDrandom() % MAX_DSET_X) + 1); + dset_dims[j][1] = (hsize_t)((HDrandom() % MAX_DSET_Y) + 1); + if ((file_space_ids[j] = H5Screate_simple(2, dset_dims[j], use_chunk ? max_dims : NULL)) < 0) + TEST_ERROR; + + /* Generate chunk if called for by configuration (multi layout uses chunked for datasets + * 1 and 2) */ + if (use_chunk) { + chunk_dims[0] = (hsize_t)((HDrandom() % MAX_CHUNK_X) + 1); + chunk_dims[1] = (hsize_t)((HDrandom() % MAX_CHUNK_Y) + 1); + if (H5Pset_chunk(dcpl_id[j], 2, chunk_dims) < 0) + TEST_ERROR; + } /* end if */ + else if ((flags & MDSET_FLAG_CHUNK) && j == 5) { + /* Dataset 5 is virtual in multi layout case */ + /* Set to contiguous to clear previous VDS settings */ + if (H5Pset_layout(dcpl_id[j], H5D_CONTIGUOUS) < 0) + TEST_ERROR; + + /* Set virtual dataset layout, ALL<>ALL mapping */ + if (H5Pset_virtual(dcpl_id[j], file_space_ids[j], ".", SOURCE_DS_NAME, file_space_ids[j]) < 0) + TEST_ERROR; + } + + /* Create dataset */ + /* If MDSET_FLAG_TCONV is set, use a different datatype with 50% probability, so + * some datasets require type conversion and others do not */ + if ((dset_ids[j] = H5Dcreate2(file_id, dset_name[j], + (flags & MDSET_FLAG_TCONV && HDrandom() % 2) ? H5T_NATIVE_LONG + : H5T_NATIVE_UINT, + file_space_ids[j], H5P_DEFAULT, dcpl_id[j], H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Create virtual source dataset if necessary. Use dcpl_id[0] for a contiguous dataset + */ + if ((flags & MDSET_FLAG_MLAYOUT) && (j == 6)) { + if ((source_dset = H5Dcreate2(file_id, SOURCE_DS_NAME, + (flags & MDSET_FLAG_TCONV && HDrandom() % 2) ? H5T_NATIVE_LONG + : H5T_NATIVE_UINT, + file_space_ids[j], H5P_DEFAULT, dcpl_id[0], H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Dclose(source_dset) < 0) + TEST_ERROR; + } + } /* end for */ + + /* Initialize read buffer and expected read buffer */ + (void)HDmemset(rbuf, 0, buf_size); + (void)HDmemset(erbuf, 0, buf_size); + + /* Initialize write buffer */ + for (j = 0; j < max_dsets; j++) + for (k = 0; k < MAX_DSET_X; k++) + for (l = 0; l < MAX_DSET_Y; l++) + wbufi[j][k][l] = (unsigned)((j * MAX_DSET_X * MAX_DSET_Y) + (k * MAX_DSET_Y) + l); + + /* Initialize expected file buffer */ + (void)HDmemset(efbuf, 0, buf_size); + + /* Perform read/write operations */ + for (j = 0; j < OPS_PER_FILE; j++) { + /* Decide whether to read or write. Can't read on the first iteration with external + * layout because the write is needed to create the external file. */ + do_read = (j == 0 && flags & MDSET_FLAG_MLAYOUT) ? FALSE : (hbool_t)(HDrandom() % 2); + + /* Loop over datasets */ + for (k = 0; k < ndsets; k++) { + int sel_type; + + /* Reset selection */ + if (H5Sselect_none(mem_space_ids[k]) < 0) + TEST_ERROR; + if (H5Sselect_none(file_space_ids[k]) < 0) + TEST_ERROR; + + /* Decide whether to do a hyperslab, point, or all selection */ + sel_type = HDrandom() % 3; + if (sel_type == 0) { + /* Hyperslab */ + size_t nhs = (size_t)((HDrandom() % MAX_HS) + 1); /* Number of hyperslabs */ + size_t max_hs_x = (MAX_HS_X <= dset_dims[k][0]) + ? MAX_HS_X + : dset_dims[k][0]; /* Determine maximum hyperslab size in X */ + size_t max_hs_y = (MAX_HS_Y <= dset_dims[k][1]) + ? MAX_HS_Y + : dset_dims[k][1]; /* Determine maximum hyperslab size in Y */ + + for (l = 0; l < nhs; l++) { + /* Generate hyperslab */ + count[0] = (hsize_t)(((hsize_t)HDrandom() % max_hs_x) + 1); + count[1] = (hsize_t)(((hsize_t)HDrandom() % max_hs_y) + 1); + start[0] = (count[0] == dset_dims[k][0]) + ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][0] - count[0] + 1); + start[1] = (count[1] == dset_dims[k][1]) + ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][1] - count[1] + 1); + + /* Select hyperslab */ + if (H5Sselect_hyperslab(mem_space_ids[k], H5S_SELECT_OR, start, NULL, count, NULL) < + 0) + TEST_ERROR; + if (H5Sselect_hyperslab(file_space_ids[k], H5S_SELECT_OR, start, NULL, count, NULL) < + 0) + TEST_ERROR; + + /* Update expected buffers */ + if (do_read) { + for (m = start[0]; m < (start[0] + count[0]); m++) + for (n = start[1]; n < (start[1] + count[1]); n++) + erbufi[k][m][n] = efbufi[k][m][n]; + } /* end if */ + else + for (m = start[0]; m < (start[0] + count[0]); m++) + for (n = start[1]; n < (start[1] + count[1]); n++) + efbufi[k][m][n] = wbufi[k][m][n]; + } /* end for */ + } /* end if */ + else if (sel_type == 1) { + /* Point selection */ + size_t npoints = (size_t)(((size_t)HDrandom() % MAX_POINTS) + 1); /* Number of points */ + + /* Generate points */ + for (l = 0; l < npoints; l++) { + points[2 * l] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][0]); + points[(2 * l) + 1] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][1]); + } /* end for */ + + /* Select points in file */ + if (H5Sselect_elements(file_space_ids[k], H5S_SELECT_APPEND, npoints, points) < 0) + TEST_ERROR; + + /* Update expected buffers */ + if (do_read) { + for (l = 0; l < npoints; l++) + erbufi[k][points[2 * l]][points[(2 * l) + 1]] = + efbufi[k][points[2 * l]][points[(2 * l) + 1]]; + } /* end if */ + else + for (l = 0; l < npoints; l++) + efbufi[k][points[2 * l]][points[(2 * l) + 1]] = + wbufi[k][points[2 * l]][points[(2 * l) + 1]]; + + /* Convert to 3D for memory selection, if not using + * "shapesame" */ + if (!(flags & MDSET_FLAG_SHAPESAME)) { + for (l = npoints - 1; l > 0; l--) { + points[(3 * l) + 2] = 0; + points[(3 * l) + 1] = points[(2 * l) + 1]; + points[3 * l] = points[2 * l]; + } /* end for */ + points[2] = 0; + } /* end if */ + + /* Select points in memory */ + if (H5Sselect_elements(mem_space_ids[k], H5S_SELECT_APPEND, npoints, points) < 0) + TEST_ERROR; + } /* end else */ + else { + /* All selection */ + /* Select entire dataset in file */ + if (H5Sselect_all(file_space_ids[k]) < 0) + TEST_ERROR; + + /* Select entire dataset in memory using hyperslab */ + start[0] = 0; + start[1] = 0; + count[0] = dset_dims[k][0]; + count[1] = dset_dims[k][1]; + if (H5Sselect_hyperslab(mem_space_ids[k], H5S_SELECT_SET, start, NULL, count, NULL) < 0) + TEST_ERROR; + + /* Update expected buffers */ + if (do_read) { + for (m = 0; m < dset_dims[k][0]; m++) + for (n = 0; n < dset_dims[k][1]; n++) + erbufi[k][m][n] = efbufi[k][m][n]; + } /* end if */ + else + for (m = 0; m < dset_dims[k][0]; m++) + for (n = 0; n < dset_dims[k][1]; n++) + efbufi[k][m][n] = wbufi[k][m][n]; + } + } /* end for */ + + /* Perform I/O */ + if (do_read) { + if (flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for (k = 0; k < ndsets; k++) + rbufs[k] = rbufi[k][0]; + + /* Read datasets */ + if (H5Dread_multi(ndsets, dset_ids, mem_type_ids, mem_space_ids, file_space_ids, + H5P_DEFAULT, rbufs) < 0) + TEST_ERROR; + } /* end if */ + else + /* Read */ + if (H5Dread(dset_ids[0], mem_type_ids[0], mem_space_ids[0], file_space_ids[0], + H5P_DEFAULT, rbuf) < 0) + TEST_ERROR; + + /* Verify data */ + if (0 != memcmp(rbuf, erbuf, buf_size)) + TEST_ERROR; + } /* end if */ + else { + if (flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for (k = 0; k < ndsets; k++) + wbufs[k] = wbufi[k][0]; + + /* Write datasets */ + if (H5Dwrite_multi(ndsets, dset_ids, mem_type_ids, mem_space_ids, file_space_ids, + H5P_DEFAULT, wbufs) < 0) + TEST_ERROR; + } /* end if */ + else + /* Write */ + if (H5Dwrite(dset_ids[0], mem_type_ids[0], mem_space_ids[0], file_space_ids[0], + H5P_DEFAULT, wbuf) < 0) + TEST_ERROR; + + /* Update wbuf */ + for (l = 0; l < max_dsets; l++) + for (m = 0; m < MAX_DSET_X; m++) + for (n = 0; n < MAX_DSET_Y; n++) + wbufi[l][m][n] += (unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y; + } /* end else */ + } /* end for */ + + /* Close */ + for (j = 0; j < ndsets; j++) { + if (H5Dclose(dset_ids[j]) < 0) + TEST_ERROR; + dset_ids[j] = -1; + if (H5Sclose(file_space_ids[j]) < 0) + TEST_ERROR; + file_space_ids[j] = -1; + } /* end for */ + if (H5Fclose(file_id) < 0) + TEST_ERROR; + file_id = -1; + + /* Cleanup external file. Need to do this because otherwise there is garbage when the + * dataset is created, even with early allocation and fill time. */ + HDremove(EXT_FILENAME); + } /* end for */ + + /* Close */ + for (i = 0; i < max_dsets; i++) { + if (H5Sclose(mem_space_ids[i]) < 0) + TEST_ERROR; + mem_space_ids[i] = -1; + } /* end for */ + for (i = 0; i < MAX_DSETS; i++) { + if (H5Pclose(dcpl_id[i]) < 0) + TEST_ERROR; + dcpl_id[i] = -1; + } + free(rbuf); + rbuf = NULL; + free(erbuf); + erbuf = NULL; + free(wbuf); + wbuf = NULL; + free(efbuf); + efbuf = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + for (i = 0; i < max_dsets; i++) { + H5Dclose(dset_ids[i]); + H5Sclose(mem_space_ids[i]); + H5Sclose(file_space_ids[i]); + H5Pclose(dcpl_id[i]); + } /* end for */ + H5Fclose(file_id); + } + H5E_END_TRY + if (rbuf) + free(rbuf); + if (erbuf) + free(erbuf); + if (wbuf) + free(wbuf); + if (efbuf) + free(efbuf); + + return -1; +} /* end test_mdset() */ + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Runs all tests with all combinations of configuration + * flags. + * + * Return: Success: 0 + * Failure: 1 + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + hid_t fapl_id; + int nerrors = 0; + unsigned i; + int ret; + + h5_reset(); + fapl_id = h5_fileaccess(); + + /* Initialize random number seed */ + HDsrandom((unsigned)HDtime(NULL)); + + /* Fill dset_name array */ + for (i = 0; i < MAX_DSETS; i++) { + if ((ret = snprintf(dset_name[i], DSET_MAX_NAME_LEN, "dset%u", i)) < 0) + TEST_ERROR; + if (ret >= DSET_MAX_NAME_LEN) + TEST_ERROR; + } /* end for */ + + /* Check if deflate and fletcher32 filters are available */ + if ((deflate_avail = H5Zfilter_avail(H5Z_FILTER_DEFLATE)) < 0) + TEST_ERROR; + if ((fletcher32_avail = H5Zfilter_avail(H5Z_FILTER_FLETCHER32)) < 0) + TEST_ERROR; + + for (i = 0; i <= MDSET_ALL_FLAGS; i++) { + /* Skip incompatible flag combinations */ + if (((i & MDSET_FLAG_MLAYOUT) && (i & MDSET_FLAG_CHUNK)) || + ((i & MDSET_FLAG_MLAYOUT) && !(i & MDSET_FLAG_MDSET)) || + ((i & MDSET_FLAG_FILTER) && !(i & MDSET_FLAG_CHUNK))) + continue; + + /* Print flag configuration */ + puts("\nConfiguration:"); + printf(" Layout: %s\n", (i & MDSET_FLAG_MLAYOUT) ? "Multi" + : (i & MDSET_FLAG_CHUNK) ? "Chunked" + : "Contiguous"); + printf(" Shape same: %s\n", (i & MDSET_FLAG_SHAPESAME) ? "Yes" : "No"); + printf(" I/O type: %s\n", (i & MDSET_FLAG_MDSET) ? "Multi" : "Single"); + printf(" Type conversion: %s\n", (i & MDSET_FLAG_TCONV) ? "Yes" : "No"); + printf(" Data filter: %s\n", (i & MDSET_FLAG_MLAYOUT) ? "Mixed" + : (i & MDSET_FLAG_FILTER) ? "Yes" + : "No"); + + nerrors += test_mdset(50, i, fapl_id); + } + + /* test all datasets in same container */ + nerrors += test_mdset_location(fapl_id); + + h5_cleanup(FILENAME, fapl_id); + + if (nerrors) + goto error; + puts("All multi dataset tests passed."); + + return 0; + +error: + nerrors = MAX(1, nerrors); + printf("***** %d multi dataset TEST%s FAILED! *****\n", nerrors, 1 == nerrors ? "" : "S"); + return 1; +} /* end main() */ diff --git a/test/testfiles/error_test_1 b/test/testfiles/error_test_1 index 070869e..9798fac 100644 --- a/test/testfiles/error_test_1 +++ b/test/testfiles/error_test_1 @@ -50,7 +50,7 @@ HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): #001: (file name) line (number) in H5D__read_api_common(): can't read data major: Dataset minor: Read failed - #002: (file name) line (number) in H5VL_dataset_read(): dataset read failed + #002: (file name) line (number) in H5VL_dataset_read_direct(): dataset read failed major: Virtual Object Layer minor: Read failed #003: (file name) line (number) in H5VL__dataset_read(): dataset read failed diff --git a/testpar/CMakeLists.txt b/testpar/CMakeLists.txt index 5922695..c9e0cc9 100644 --- a/testpar/CMakeLists.txt +++ b/testpar/CMakeLists.txt @@ -95,6 +95,7 @@ set (H5P_TESTS t_pshutdown t_prestart t_init_term + t_pmulti_dset t_shapesame t_filters_parallel t_subfiling_vfd diff --git a/testpar/Makefile.am b/testpar/Makefile.am index b53553a..4b35099 100644 --- a/testpar/Makefile.am +++ b/testpar/Makefile.am @@ -34,7 +34,7 @@ check_SCRIPTS = $(TEST_SCRIPT_PARA) # Test programs. These are our main targets. # -TEST_PROG_PARA=t_mpi t_bigio testphdf5 t_cache t_cache_image t_pread t_pshutdown t_prestart t_init_term t_shapesame t_filters_parallel t_2Gio t_vfd +TEST_PROG_PARA=t_mpi t_bigio testphdf5 t_cache t_cache_image t_pread t_pshutdown t_prestart t_init_term t_pmulti_dset t_shapesame t_filters_parallel t_2Gio t_vfd if SUBFILING_VFD_CONDITIONAL TEST_PROG_PARA += t_subfiling_vfd @@ -59,6 +59,6 @@ LDADD = $(LIBH5TEST) $(LIBHDF5) # after_mpi_fin.h5 is from t_init_term # go is used for debugging. See testphdf5.c. CHECK_CLEANFILES+=MPItest.h5 Para*.h5 bigio_test.h5 CacheTestDummy.h5 \ - ShapeSameTest.h5 shutdown.h5 after_mpi_fin.h5 go + ShapeSameTest.h5 shutdown.h5 pmulti_dset.h5 after_mpi_fin.h5 go include $(top_srcdir)/config/conclude.am diff --git a/testpar/t_pmulti_dset.c b/testpar/t_pmulti_dset.c new file mode 100644 index 0000000..a29755a --- /dev/null +++ b/testpar/t_pmulti_dset.c @@ -0,0 +1,767 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Neil Fortner + * March 10, 2014 + * + * Purpose: Test H5Dwrite_multi() and H5Dread_multi using randomized + * parameters in parallel. Also tests H5Dwrite() and H5Dread() + * using a similar method. + * + * Note that this test currently relies on all processes generating + * the same sequence of random numbers after using a shared seed + * value, therefore it may not work across multiple machines. + */ + +#include "h5test.h" +#include "testpar.h" + +#define T_PMD_ERROR \ + do { \ + nerrors++; \ + H5_FAILED(); \ + AT(); \ + printf("seed = %u\n", seed); \ + } while (0) + +#define FILENAME "pmulti_dset.h5" +#define MAX_DSETS 5 +#define MAX_DSET_X 15 +#define MAX_DSET_Y 10 +#define MAX_CHUNK_X 8 +#define MAX_CHUNK_Y 6 +#define MAX_HS_X 4 +#define MAX_HS_Y 2 +#define MAX_HS 2 +#define MAX_POINTS 6 +#define MAX_SEL_RETRIES 10 +#define OPS_PER_FILE 25 +#define DSET_MAX_NAME_LEN 8 + +/* Option flags */ +#define MDSET_FLAG_CHUNK 0x01u +#define MDSET_FLAG_MLAYOUT 0x02u +#define MDSET_FLAG_SHAPESAME 0x04u +#define MDSET_FLAG_MDSET 0x08u +#define MDSET_FLAG_COLLECTIVE 0x10u +#define MDSET_FLAG_COLLECTIVE_OPT 0x20u +#define MDSET_FLAG_TCONV 0x40u +#define MDSET_FLAG_FILTER 0x80u +#define MDSET_ALL_FLAGS \ + (MDSET_FLAG_CHUNK | MDSET_FLAG_MLAYOUT | MDSET_FLAG_SHAPESAME | MDSET_FLAG_MDSET | \ + MDSET_FLAG_COLLECTIVE | MDSET_FLAG_COLLECTIVE_OPT | MDSET_FLAG_TCONV | MDSET_FLAG_FILTER) + +/* MPI variables */ +int mpi_size; +int mpi_rank; + +/* Names for datasets */ +char dset_name[MAX_DSETS][DSET_MAX_NAME_LEN]; + +/* Random number seed */ +unsigned seed; + +/* Number of errors */ +int nerrors = 0; + +/* Whether these filters are available */ +htri_t deflate_avail = FALSE; +htri_t fletcher32_avail = FALSE; + +/*------------------------------------------------------------------------- + * Function: test_pmdset + * + * Purpose: Test randomized I/O using one or more datasets. Creates a + * file, runs OPS_PER_FILE read or write operations verifying + * that reads return the expected data, then closes the file. + * Runs the test with a new file niter times. + * + * The operations can use either hyperslab or point + * selections. Options are available for chunked or + * contiguous layout, use of multiple datasets and H5D*_multi + * calls, and use of the "shapesame" algorithm code path. To + * avoid the shapesame path when that option is not set, this + * function simply adds a dimension to the memory buffer in a + * way that the shapesame code is not designed to handle. + * + * Return: Number of errors + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +static void +test_pmdset(size_t niter, unsigned flags) +{ + hid_t dset_ids[MAX_DSETS]; + hid_t mem_type_ids[MAX_DSETS]; + hid_t mem_space_ids[MAX_DSETS]; + hid_t file_space_ids[MAX_DSETS]; + void *rbufs[MAX_DSETS]; + const void *wbufs[MAX_DSETS]; + size_t max_dsets; + size_t buf_size; + size_t ndsets; + hid_t file_id = -1; + hid_t fapl_id = -1; + hid_t dcpl_id[MAX_DSETS]; + hid_t dxpl_id = -1; + hsize_t dset_dims[MAX_DSETS][3]; + hsize_t chunk_dims[2]; + hsize_t max_dims[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; + unsigned *rbuf = NULL; + unsigned *rbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *erbuf = NULL; + unsigned *erbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *wbuf = NULL; + unsigned *wbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *efbuf = NULL; + unsigned *efbufi[MAX_DSETS][MAX_DSET_X]; + unsigned char *dset_usage; + unsigned char *dset_usagei[MAX_DSETS][MAX_DSET_X]; + hbool_t do_read; + hbool_t last_read; + hbool_t overlap; + hsize_t start[MAX_HS][3]; + hsize_t count[MAX_HS][3]; + hsize_t points[3 * MAX_POINTS]; + int rank_data_diff; + unsigned op_data_incr; + size_t i, j, k, l, m, n, o, p; + + if (mpi_rank == 0) + TESTING("random I/O"); + + /* Skipped configurations */ + if (!(flags & MDSET_FLAG_COLLECTIVE_OPT)) { + if (mpi_rank == 0) + SKIPPED(); + return; + } + + /* Calculate maximum number of datasets */ + max_dsets = (flags & MDSET_FLAG_MDSET) ? MAX_DSETS : 1; + + /* Calculate data increment per write operation */ + op_data_incr = (unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y * (unsigned)mpi_size; + + /* Calculate buffer size */ + buf_size = max_dsets * MAX_DSET_X * MAX_DSET_Y * sizeof(unsigned); + + /* Initialize dcpl_id array */ + for (i = 0; i < max_dsets; i++) + dcpl_id[i] = -1; + + /* Allocate buffers */ + if (NULL == (rbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR; + if (NULL == (erbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR; + if (NULL == (wbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR; + if (NULL == (efbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR; + if (NULL == (dset_usage = (unsigned char *)HDmalloc(max_dsets * MAX_DSET_X * MAX_DSET_Y))) + T_PMD_ERROR; + + /* Initialize buffer indices */ + for (i = 0; i < max_dsets; i++) + for (j = 0; j < MAX_DSET_X; j++) { + rbufi[i][j] = rbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + erbufi[i][j] = erbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + wbufi[i][j] = wbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + efbufi[i][j] = efbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + dset_usagei[i][j] = dset_usage + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + } /* end for */ + + /* Initialize 3rd dimension information (for tricking library into using + * non-"shapesame" code */ + for (i = 0; i < max_dsets; i++) + dset_dims[i][2] = 1; + for (i = 0; i < MAX_HS; i++) { + start[i][2] = 0; + count[i][2] = 1; + } /* end for */ + + /* Initialize IDs */ + for (i = 0; i < max_dsets; i++) { + dset_ids[i] = -1; + file_space_ids[i] = -1; + mem_type_ids[i] = H5T_NATIVE_UINT; + mem_space_ids[i] = -1; + } /* end for */ + + /* Generate memory dataspace */ + dset_dims[0][0] = MAX_DSET_X; + dset_dims[0][1] = MAX_DSET_Y; + if ((mem_space_ids[0] = H5Screate_simple((flags & MDSET_FLAG_SHAPESAME) ? 2 : 3, dset_dims[0], NULL)) < 0) + T_PMD_ERROR; + for (i = 1; i < max_dsets; i++) + if ((mem_space_ids[i] = H5Scopy(mem_space_ids[0])) < 0) + T_PMD_ERROR; + + /* Create fapl */ + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + T_PMD_ERROR; + + /* Set MPIO file driver */ + if ((H5Pset_fapl_mpio(fapl_id, MPI_COMM_WORLD, MPI_INFO_NULL)) < 0) + T_PMD_ERROR; + + /* Create dcpl 0 */ + if ((dcpl_id[0] = H5Pcreate(H5P_DATASET_CREATE)) < 0) + T_PMD_ERROR; + + /* Set fill time to alloc, and alloc time to early (so we always know + * what's in the file) */ + if (H5Pset_fill_time(dcpl_id[0], H5D_FILL_TIME_ALLOC) < 0) + T_PMD_ERROR; + if (H5Pset_alloc_time(dcpl_id[0], H5D_ALLOC_TIME_EARLY) < 0) + T_PMD_ERROR; + + /* Set filters if requested */ + if (flags & MDSET_FLAG_FILTER) { + if (fletcher32_avail) + if (H5Pset_fletcher32(dcpl_id[0]) < 0) + T_PMD_ERROR; + if (deflate_avail) + if (H5Pset_deflate(dcpl_id[0], 1) < 0) + T_PMD_ERROR; + } + + /* Copy dcpl 0 to other slots in dcpl_id array */ + for (i = 1; i < MAX_DSETS; i++) + if ((dcpl_id[i] = H5Pcopy(dcpl_id[0])) < 0) + T_PMD_ERROR; + + /* If this is a multi layout run, dataset 2 will use filters, set them now */ + if (flags & MDSET_FLAG_MLAYOUT) { + if (fletcher32_avail) + if (H5Pset_fletcher32(dcpl_id[2]) < 0) + T_PMD_ERROR; + if (deflate_avail) + if (H5Pset_deflate(dcpl_id[2], 1) < 0) + T_PMD_ERROR; + } + + /* Create dxpl */ + if ((dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0) + T_PMD_ERROR; + + /* Set collective or independent I/O */ + if (flags & MDSET_FLAG_COLLECTIVE) { + if (H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) < 0) + T_PMD_ERROR; + + /* Set low level I/O mode */ + if (flags & MDSET_FLAG_COLLECTIVE_OPT) { + if (H5Pset_dxpl_mpio_collective_opt(dxpl_id, H5FD_MPIO_COLLECTIVE_IO) < 0) + T_PMD_ERROR; + } + else if (H5Pset_dxpl_mpio_collective_opt(dxpl_id, H5FD_MPIO_INDIVIDUAL_IO) < 0) + T_PMD_ERROR; + } /* end if */ + else if (H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_INDEPENDENT) < 0) + T_PMD_ERROR; + + for (i = 0; i < niter; i++) { + /* Determine number of datasets */ + ndsets = (flags & MDSET_FLAG_MLAYOUT) ? 3 + : (flags & MDSET_FLAG_MDSET) ? (size_t)((size_t)HDrandom() % max_dsets) + 1 + : 1; + + /* Create file */ + if ((file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + T_PMD_ERROR; + + /* Create datasets */ + for (j = 0; j < ndsets; j++) { + hbool_t use_chunk = + (flags & MDSET_FLAG_CHUNK) || ((flags & MDSET_FLAG_MLAYOUT) && (j == 1 || j == 2)); + + /* Generate file dataspace */ + dset_dims[j][0] = (hsize_t)((HDrandom() % MAX_DSET_X) + 1); + dset_dims[j][1] = (hsize_t)((HDrandom() % MAX_DSET_Y) + 1); + if ((file_space_ids[j] = H5Screate_simple(2, dset_dims[j], use_chunk ? max_dims : NULL)) < 0) + T_PMD_ERROR; + + /* Generate chunk if called for by configuration (multi layout uses chunked for datasets + * 1 and 2) */ + if (use_chunk) { + chunk_dims[0] = (hsize_t)((HDrandom() % MAX_CHUNK_X) + 1); + chunk_dims[1] = (hsize_t)((HDrandom() % MAX_CHUNK_Y) + 1); + if (H5Pset_chunk(dcpl_id[j], 2, chunk_dims) < 0) + T_PMD_ERROR; + } /* end if */ + + /* Create dataset */ + /* If MDSET_FLAG_TCONV is set, use a different datatype with 50% probability, so + * some datasets require type conversion and others do not */ + if ((dset_ids[j] = H5Dcreate2(file_id, dset_name[j], + (flags & MDSET_FLAG_TCONV && HDrandom() % 2) ? H5T_NATIVE_LONG + : H5T_NATIVE_UINT, + file_space_ids[j], H5P_DEFAULT, dcpl_id[j], H5P_DEFAULT)) < 0) + T_PMD_ERROR; + } /* end for */ + + /* Initialize read buffer and expected read buffer */ + (void)HDmemset(rbuf, 0, buf_size); + (void)HDmemset(erbuf, 0, buf_size); + + /* Initialize write buffer */ + for (j = 0; j < max_dsets; j++) + for (k = 0; k < MAX_DSET_X; k++) + for (l = 0; l < MAX_DSET_Y; l++) + wbufi[j][k][l] = (unsigned)(((unsigned)mpi_rank * max_dsets * MAX_DSET_X * MAX_DSET_Y) + + (j * MAX_DSET_X * MAX_DSET_Y) + (k * MAX_DSET_Y) + l); + + /* Initialize expected file buffer */ + (void)HDmemset(efbuf, 0, buf_size); + + /* Set last_read to TRUE so we don't reopen the file on the first + * iteration */ + last_read = TRUE; + + /* Perform read/write operations */ + for (j = 0; j < OPS_PER_FILE; j++) { + /* Decide whether to read or write */ + do_read = (hbool_t)(HDrandom() % 2); + + /* Barrier to ensure processes have finished the previous operation + */ + MPI_Barrier(MPI_COMM_WORLD); + + /* If the last operation was a write we must close and reopen the + * file to ensure consistency */ + /* Possibly change to MPI_FILE_SYNC at some point? -NAF */ + if (!last_read) { + /* Close datasets */ + for (k = 0; k < ndsets; k++) { + if (H5Dclose(dset_ids[k]) < 0) + T_PMD_ERROR; + dset_ids[k] = -1; + } /* end for */ + + /* Close file */ + if (H5Fclose(file_id) < 0) + T_PMD_ERROR; + file_id = -1; + + /* Barrier */ + MPI_Barrier(MPI_COMM_WORLD); + + /* Reopen file */ + if ((file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl_id)) < 0) + T_PMD_ERROR; + + /* Reopen datasets */ + for (k = 0; k < ndsets; k++) { + if ((dset_ids[k] = H5Dopen2(file_id, dset_name[k], H5P_DEFAULT)) < 0) + T_PMD_ERROR; + } /* end for */ + + /* Barrier */ + MPI_Barrier(MPI_COMM_WORLD); + } /* end if */ + + /* Keep track of whether the last operation was a read */ + last_read = do_read; + + /* Loop over datasets */ + for (k = 0; k < ndsets; k++) { + /* Reset selection */ + if (H5Sselect_none(mem_space_ids[k]) < 0) + T_PMD_ERROR; + if (H5Sselect_none(file_space_ids[k]) < 0) + T_PMD_ERROR; + + /* Reset dataset usage array, if writing */ + if (!do_read) + HDmemset(dset_usage, 0, max_dsets * MAX_DSET_X * MAX_DSET_Y); + + /* Iterate over processes */ + for (l = 0; l < (size_t)mpi_size; l++) { + /* Calculate difference between data in process being + * iterated over and that in this process */ + rank_data_diff = + (int)((unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y) * ((int)l - (int)mpi_rank); + + /* Decide whether to do a hyperslab or point selection */ + if (HDrandom() % 2) { + /* Hyperslab */ + size_t nhs = (size_t)((HDrandom() % MAX_HS) + 1); /* Number of hyperslabs */ + size_t max_hs_x = (MAX_HS_X <= dset_dims[k][0]) + ? MAX_HS_X + : dset_dims[k][0]; /* Determine maximum hyperslab size in X */ + size_t max_hs_y = (MAX_HS_Y <= dset_dims[k][1]) + ? MAX_HS_Y + : dset_dims[k][1]; /* Determine maximum hyperslab size in Y */ + + for (m = 0; m < nhs; m++) { + overlap = TRUE; + for (n = 0; overlap && (n < MAX_SEL_RETRIES); n++) { + /* Generate hyperslab */ + count[m][0] = (hsize_t)(((hsize_t)HDrandom() % max_hs_x) + 1); + count[m][1] = (hsize_t)(((hsize_t)HDrandom() % max_hs_y) + 1); + start[m][0] = (count[m][0] == dset_dims[k][0]) + ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][0] - count[m][0] + 1); + start[m][1] = (count[m][1] == dset_dims[k][1]) + ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][1] - count[m][1] + 1); + + /* If writing, check for overlap with other processes */ + overlap = FALSE; + if (!do_read) + for (o = start[m][0]; (o < (start[m][0] + count[m][0])) && !overlap; o++) + for (p = start[m][1]; (p < (start[m][1] + count[m][1])) && !overlap; + p++) + if (dset_usagei[k][o][p]) + overlap = TRUE; + } /* end for */ + + /* If we did not find a non-overlapping hyperslab + * quit trying to generate new ones */ + if (overlap) { + nhs = m; + break; + } /* end if */ + + /* Select hyperslab if this is the current process + */ + if (l == (size_t)mpi_rank) { + if (H5Sselect_hyperslab(mem_space_ids[k], H5S_SELECT_OR, start[m], NULL, + count[m], NULL) < 0) + T_PMD_ERROR; + if (H5Sselect_hyperslab(file_space_ids[k], H5S_SELECT_OR, start[m], NULL, + count[m], NULL) < 0) + T_PMD_ERROR; + } /* end if */ + + /* Update expected buffers */ + if (do_read) { + if (l == (size_t)mpi_rank) + for (n = start[m][0]; n < (start[m][0] + count[m][0]); n++) + for (o = start[m][1]; o < (start[m][1] + count[m][1]); o++) + erbufi[k][n][o] = efbufi[k][n][o]; + } /* end if */ + else + for (n = start[m][0]; n < (start[m][0] + count[m][0]); n++) + for (o = start[m][1]; o < (start[m][1] + count[m][1]); o++) + efbufi[k][n][o] = (unsigned)((int)wbufi[k][n][o] + rank_data_diff); + } /* end for */ + + /* Update dataset usage array if writing */ + if (!do_read) + for (m = 0; m < nhs; m++) + for (n = start[m][0]; n < (start[m][0] + count[m][0]); n++) + for (o = start[m][1]; o < (start[m][1] + count[m][1]); o++) + dset_usagei[k][n][o] = (unsigned char)1; + } /* end if */ + else { + /* Point selection */ + size_t npoints = + (size_t)(((size_t)HDrandom() % MAX_POINTS) + 1); /* Number of points */ + + /* Reset dataset usage array if reading, since in this case we don't care + * about overlapping selections between processes */ + if (do_read) + HDmemset(dset_usage, 0, max_dsets * MAX_DSET_X * MAX_DSET_Y); + + /* Generate points */ + for (m = 0; m < npoints; m++) { + overlap = TRUE; + for (n = 0; overlap && (n < MAX_SEL_RETRIES); n++) { + /* Generate point */ + points[2 * m] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][0]); + points[(2 * m) + 1] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][1]); + + /* Check for overlap with other processes (write) or this process + * (always) */ + overlap = FALSE; + if (dset_usagei[k][points[2 * m]][points[(2 * m) + 1]]) + overlap = TRUE; + } /* end for */ + + /* If we did not find a non-overlapping point quit + * trying to generate new ones */ + if (overlap) { + npoints = m; + break; + } /* end if */ + + /* Update dataset usage array after each point to prevent the same point + * being selected twice by a single process, since this is not supported + * by MPI */ + dset_usagei[k][points[2 * m]][points[(2 * m) + 1]] = (unsigned char)1; + } /* end for */ + + /* Select points in file if this is the current process + */ + if ((l == (size_t)mpi_rank) && (npoints > 0)) + if (H5Sselect_elements(file_space_ids[k], H5S_SELECT_APPEND, npoints, points) < 0) + T_PMD_ERROR; + + /* Update expected buffers */ + if (do_read) { + if (l == (size_t)mpi_rank) + for (m = 0; m < npoints; m++) + erbufi[k][points[2 * m]][points[(2 * m) + 1]] = + efbufi[k][points[2 * m]][points[(2 * m) + 1]]; + } /* end if */ + else + for (m = 0; m < npoints; m++) + efbufi[k][points[2 * m]][points[(2 * m) + 1]] = + (unsigned)((int)wbufi[k][points[2 * m]][points[(2 * m) + 1]] + + rank_data_diff); + + /* Select points in memory if this is the current + * process */ + if ((l == (size_t)mpi_rank) && (npoints > 0)) { + /* Convert to 3D for memory selection, if not using + * "shapesame" */ + if (!(flags & MDSET_FLAG_SHAPESAME)) { + for (m = npoints - 1; m > 0; m--) { + points[(3 * m) + 2] = 0; + points[(3 * m) + 1] = points[(2 * m) + 1]; + points[3 * m] = points[2 * m]; + } /* end for */ + points[2] = 0; + } /* end if */ + + /* Select elements */ + if (H5Sselect_elements(mem_space_ids[k], H5S_SELECT_APPEND, npoints, points) < 0) + T_PMD_ERROR; + } /* end if */ + } /* end else */ + } /* end for */ + } /* end for */ + + /* Perform I/O */ + if (do_read) { + if (flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for (k = 0; k < ndsets; k++) + rbufs[k] = rbufi[k][0]; + + /* Read datasets */ + if (H5Dread_multi(ndsets, dset_ids, mem_type_ids, mem_space_ids, file_space_ids, dxpl_id, + rbufs) < 0) + T_PMD_ERROR; + } /* end if */ + else + /* Read */ + if (H5Dread(dset_ids[0], mem_type_ids[0], mem_space_ids[0], file_space_ids[0], dxpl_id, + rbuf) < 0) + T_PMD_ERROR; + + /* Verify data */ + if (0 != memcmp(rbuf, erbuf, buf_size)) + T_PMD_ERROR; + } /* end if */ + else { + if (flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for (k = 0; k < ndsets; k++) + wbufs[k] = wbufi[k][0]; + + /* Write datasets */ + if (H5Dwrite_multi(ndsets, dset_ids, mem_type_ids, mem_space_ids, file_space_ids, dxpl_id, + wbufs) < 0) + T_PMD_ERROR; + } /* end if */ + else + /* Write */ + if (H5Dwrite(dset_ids[0], mem_type_ids[0], mem_space_ids[0], file_space_ids[0], dxpl_id, + wbuf) < 0) + T_PMD_ERROR; + + /* Update wbuf */ + for (l = 0; l < max_dsets; l++) + for (m = 0; m < MAX_DSET_X; m++) + for (n = 0; n < MAX_DSET_Y; n++) + wbufi[l][m][n] += op_data_incr; + } /* end else */ + } /* end for */ + + /* Close */ + for (j = 0; j < ndsets; j++) { + if (H5Dclose(dset_ids[j]) < 0) + T_PMD_ERROR; + dset_ids[j] = -1; + if (H5Sclose(file_space_ids[j]) < 0) + T_PMD_ERROR; + file_space_ids[j] = -1; + } /* end for */ + if (H5Fclose(file_id) < 0) + T_PMD_ERROR; + file_id = -1; + } /* end for */ + + /* Close */ + for (i = 0; i < max_dsets; i++) { + if (H5Sclose(mem_space_ids[i]) < 0) + T_PMD_ERROR; + mem_space_ids[i] = -1; + } /* end for */ + if (H5Pclose(dxpl_id) < 0) + T_PMD_ERROR; + dxpl_id = -1; + for (i = 0; i < MAX_DSETS; i++) { + if (H5Pclose(dcpl_id[i]) < 0) + T_PMD_ERROR; + dcpl_id[i] = -1; + } + if (H5Pclose(fapl_id) < 0) + T_PMD_ERROR; + fapl_id = -1; + free(rbuf); + rbuf = NULL; + free(erbuf); + erbuf = NULL; + free(wbuf); + wbuf = NULL; + free(efbuf); + efbuf = NULL; + free(dset_usage); + dset_usage = NULL; + + if (mpi_rank == 0) + PASSED(); + + return; +} /* end test_mdset() */ + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Runs all tests with all combinations of configuration + * flags. + * + * Return: Success: 0 + * Failure: 1 + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +int +main(int argc, char *argv[]) +{ + unsigned i; + int ret; + + h5_reset(); + + /* Initialize MPI */ + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Generate random number seed, if rank 0 */ + if (MAINPROCESS) + seed = (unsigned)HDtime(NULL); + + /* Broadcast seed from rank 0 (other ranks will receive rank 0's seed) */ + if (MPI_SUCCESS != MPI_Bcast(&seed, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD)) + T_PMD_ERROR; + + /* Seed random number generator with shared seed (so all ranks generate the + * same sequence) */ + HDsrandom(seed); + + /* Fill dset_name array */ + for (i = 0; i < MAX_DSETS; i++) { + if ((ret = snprintf(dset_name[i], DSET_MAX_NAME_LEN, "dset%u", i)) < 0) + T_PMD_ERROR; + if (ret >= DSET_MAX_NAME_LEN) + T_PMD_ERROR; + } /* end for */ + + /* Check if deflate and fletcher32 filters are available */ + if ((deflate_avail = H5Zfilter_avail(H5Z_FILTER_DEFLATE)) < 0) + T_PMD_ERROR; + if ((fletcher32_avail = H5Zfilter_avail(H5Z_FILTER_FLETCHER32)) < 0) + T_PMD_ERROR; + + for (i = 0; i <= MDSET_ALL_FLAGS; i++) { + /* Skip incompatible flag combinations */ + if (((i & MDSET_FLAG_MLAYOUT) && (i & MDSET_FLAG_CHUNK)) || + ((i & MDSET_FLAG_MLAYOUT) && !(i & MDSET_FLAG_MDSET)) || + ((i & MDSET_FLAG_MLAYOUT) && !(i & MDSET_FLAG_COLLECTIVE)) || + ((i & MDSET_FLAG_MLAYOUT) && (i & MDSET_FLAG_TCONV)) || + ((i & MDSET_FLAG_FILTER) && !(i & MDSET_FLAG_CHUNK)) || + ((i & MDSET_FLAG_FILTER) && !(i & MDSET_FLAG_COLLECTIVE)) || + ((i & MDSET_FLAG_FILTER) && (i & MDSET_FLAG_TCONV)) || + (!(i & MDSET_FLAG_COLLECTIVE_OPT) && !(i & MDSET_FLAG_COLLECTIVE))) + continue; + + /* Print flag configuration */ + if (MAINPROCESS) { + puts("\nConfiguration:"); + printf(" Layout: %s\n", (i & MDSET_FLAG_MLAYOUT) ? "Multi" + : (i & MDSET_FLAG_CHUNK) ? "Chunked" + : "Contiguous"); + printf(" Shape same: %s\n", (i & MDSET_FLAG_SHAPESAME) ? "Yes" : "No"); + printf(" I/O type: %s\n", (i & MDSET_FLAG_MDSET) ? "Multi" : "Single"); + printf(" MPI I/O type: %s\n", (i & MDSET_FLAG_COLLECTIVE) ? "Collective" : "Independent"); + if (i & MDSET_FLAG_COLLECTIVE) + printf(" Low level MPI I/O:%s\n", + (i & MDSET_FLAG_COLLECTIVE_OPT) ? "Collective" : "Independent"); + printf(" Type conversion: %s\n", (i & MDSET_FLAG_TCONV) ? "Yes" : "No"); + printf(" Data filter: %s\n", (i & MDSET_FLAG_MLAYOUT) ? "Mixed" + : (i & MDSET_FLAG_FILTER) ? "Yes" + : "No"); + } /* end if */ + + test_pmdset(10, i); + } /* end for */ + + /* Barrier to make sure all ranks are done before deleting the file, and + * also to clean up output (make sure PASSED is printed before any of the + * following messages) */ + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) + T_PMD_ERROR; + + /* Delete file */ + if (mpi_rank == 0) + if (MPI_SUCCESS != MPI_File_delete(FILENAME, MPI_INFO_NULL)) + T_PMD_ERROR; + + /* Gather errors from all processes */ + MPI_Allreduce(&nerrors, &ret, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + nerrors = ret; + + if (MAINPROCESS) { + printf("===================================\n"); + if (nerrors) + printf("***Parallel multi dataset tests detected %d errors***\n", nerrors); + else + printf("Parallel multi dataset tests finished with no errors\n"); + printf("===================================\n"); + } /* end if */ + + /* close HDF5 library */ + H5close(); + + /* MPI_Finalize must be called AFTER H5close which may use MPI calls */ + MPI_Finalize(); + + /* cannot just return (nerrors) because exit code is limited to 1 byte */ + return (nerrors != 0); +} /* end main() */ -- cgit v0.12