From b9640c71f765583f341443b06598d4d2cd6d8b16 Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Thu, 1 Jul 2021 20:19:45 -0500 Subject: Add full API support for selection I/O. Add tests for this. --- src/H5Dchunk.c | 4 +- src/H5FD.c | 200 ++++++++ src/H5FDcore.c | 2 + src/H5FDdirect.c | 2 + src/H5FDfamily.c | 2 + src/H5FDhdfs.c | 2 + src/H5FDint.c | 1277 +++++++++++++++++++++++++++++++++++----------------- src/H5FDlog.c | 2 + src/H5FDmirror.c | 2 + src/H5FDmulti.c | 2 + src/H5FDprivate.h | 10 +- src/H5FDpublic.h | 12 + src/H5FDros3.c | 2 + src/H5FDsec2.c | 2 + src/H5FDsplitter.c | 2 + src/H5FDstdio.c | 2 + src/H5Fio.c | 8 +- src/H5Fprivate.h | 4 +- test/vfd.c | 986 +++++++++++++++++++++++++++++++++++++++- 19 files changed, 2107 insertions(+), 416 deletions(-) diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index f9f56f6..ec4f4be 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -2648,7 +2648,7 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ * already verified it won't be used, and the metadata accumulator * because this is raw data) */ if (num_chunks > 0 && - H5F_shared_select_read(H5F_SHARED(io_info->dset->oloc.file), (uint32_t)num_chunks, H5FD_MEM_DRAW, + 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") @@ -2987,7 +2987,7 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize * already verified it won't be used, and the metadata accumulator * because this is raw data) */ if (num_chunks > 0 && H5F_shared_select_write( - H5F_SHARED(io_info->dset->oloc.file), (uint32_t)num_chunks, H5FD_MEM_DRAW, + 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") diff --git a/src/H5FD.c b/src/H5FD.c index bae69f5..62d5c38 100644 --- a/src/H5FD.c +++ b/src/H5FD.c @@ -1597,6 +1597,206 @@ done: } /* end H5FDwrite_vector() */ /*------------------------------------------------------------------------- + * Function: H5FDread_selection + * + * Purpose: Perform count reads from the specified file at the + * locations selected in the dataspaces in the file_spaces + * array, with each of those dataspaces starting at the file + * address specified by the corresponding element of the + * offsets array, and with the size of each element in the + * dataspace specified by the corresponding element of the + * element_sizes array. The memory type provided by type is + * the same for all selections. Data read is returned in + * the locations selected in the dataspaces in the + * mem_spaces array, within the buffers provided in the + * corresponding elements of the bufs array. + * + * If i > 0 and element_sizes[i] == 0, presume + * element_sizes[n] = element_sizes[i-1] for all n >= i and + * < count. + * + * If the underlying VFD supports selection reads, pass the + * call through directly. + * + * If it doesn't, convert the vector write into a sequence + * of individual reads. + * + * All reads are done according to the data transfer property + * list dxpl_id (which may be the constant H5P_DEFAULT). + * + * Return: Success: SUCCEED + * All reads have completed successfully, and + * the results havce been into the supplied + * buffers. + * + * Failure: FAIL + * The contents of supplied buffers are undefined. + * + * Programmer: NAF -- 5/19/21 + * + * Changes: None. + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDread_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, hid_t mem_space_ids[], + hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + + /* Check arguments */ + if (!file) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL") + + if (!file->cls) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file class pointer cannot be NULL") + + if ((!mem_space_ids) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_spaces parameter can't be NULL if count is positive") + + if ((!file_space_ids) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_spaces parameter can't be NULL if count is positive") + + if ((!offsets) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offsets parameter can't be NULL if count is positive") + + if ((!element_sizes) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "element_sizes parameter can't be NULL if count is positive") + + if ((!bufs) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs parameter can't be NULL if count is positive") + + if ((count > 0) && (element_sizes[0] == 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes[0] can't be 0") + + if ((count > 0) && (bufs[0] == NULL)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs[0] can't be NULL") + + /* 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; + } + else { + if (TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list") + } + + /* Set DXPL for operation */ + H5CX_set_dxpl(dxpl_id); + + /* Call private function */ + /* (Note compensating for base address addition in internal routine) */ + if (H5FD_read_selection_id(file, type, count, mem_space_ids, file_space_ids, offsets, element_sizes, + bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file selection read request failed") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5FDread_selection() */ + +/*------------------------------------------------------------------------- + * Function: H5FDwrite_selection + * + * Purpose: Perform count writes to the specified file at the + * locations selected in the dataspaces in the file_spaces + * array, with each of those dataspaces starting at the file + * address specified by the corresponding element of the + * offsets array, and with the size of each element in the + * dataspace specified by the corresponding element of the + * element_sizes array. The memory type provided by type is + * the same for all selections. Data write is from + * the locations selected in the dataspaces in the + * mem_spaces array, within the buffers provided in the + * corresponding elements of the bufs array. + * + * If i > 0 and element_sizes[i] == 0, presume + * element_sizes[n] = element_sizes[i-1] for all n >= i and + * < count. + * + * If the underlying VFD supports selection reads, pass the + * call through directly. + * + * If it doesn't, convert the vector write into a sequence + * of individual writes. + * + * All writes are done according to the data transfer property + * list dxpl_id (which may be the constant H5P_DEFAULT). + * + * Return: Success: SUCCEED + * All writes have completed successfully + * + * Failure: FAIL + * One or more of the writes failed. + * + * Programmer: NAF -- 5/14/21 + * + * Changes: None. + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDwrite_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, hid_t mem_space_ids[], + hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], const void *bufs[]) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + + /* Check arguments */ + if (!file) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL") + + if (!file->cls) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file class pointer cannot be NULL") + + if ((!mem_space_ids) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mem_spaces parameter can't be NULL if count is positive") + + if ((!file_space_ids) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file_spaces parameter can't be NULL if count is positive") + + if ((!offsets) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offsets parameter can't be NULL if count is positive") + + if ((!element_sizes) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "element_sizes parameter can't be NULL if count is positive") + + if ((!bufs) && (count > 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs parameter can't be NULL if count is positive") + + if ((count > 0) && (element_sizes[0] == 0)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sizes[0] can't be 0") + + if ((count > 0) && (bufs[0] == NULL)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bufs[0] can't be NULL") + + /* 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; + } + else { + if (TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list") + } + + /* Set DXPL for operation */ + H5CX_set_dxpl(dxpl_id); + + /* Call private function */ + /* (Note compensating for base address addition in internal routine) */ + if (H5FD_write_selection_id(file, type, count, mem_space_ids, file_space_ids, offsets, element_sizes, + bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file selection write request failed") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5FDwrite_selection() */ + +/*------------------------------------------------------------------------- * Function: H5FDflush * * Purpose: Notify driver to flush all cached data. If the driver has no diff --git a/src/H5FDcore.c b/src/H5FDcore.c index 2692d04..4dea126 100644 --- a/src/H5FDcore.c +++ b/src/H5FDcore.c @@ -179,6 +179,8 @@ static const H5FD_class_t H5FD_core_g = { H5FD__core_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ H5FD__core_flush, /* flush */ H5FD__core_truncate, /* truncate */ H5FD__core_lock, /* lock */ diff --git a/src/H5FDdirect.c b/src/H5FDdirect.c index 08e05ae..b777496 100644 --- a/src/H5FDdirect.c +++ b/src/H5FDdirect.c @@ -168,6 +168,8 @@ static const H5FD_class_t H5FD_direct_g = { H5FD__direct_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ NULL, /* flush */ H5FD__direct_truncate, /* truncate */ H5FD__direct_lock, /* lock */ diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c index e7350a6..c7ca09c 100644 --- a/src/H5FDfamily.c +++ b/src/H5FDfamily.c @@ -133,6 +133,8 @@ static const H5FD_class_t H5FD_family_g = { H5FD__family_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ H5FD__family_flush, /* flush */ H5FD__family_truncate, /* truncate */ H5FD__family_lock, /* lock */ diff --git a/src/H5FDhdfs.c b/src/H5FDhdfs.c index 9f18a2d..63d20a7 100644 --- a/src/H5FDhdfs.c +++ b/src/H5FDhdfs.c @@ -307,6 +307,8 @@ static const H5FD_class_t H5FD_hdfs_g = { H5FD__hdfs_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ NULL, /* flush */ H5FD__hdfs_truncate, /* truncate */ NULL, /* lock */ diff --git a/src/H5FDint.c b/src/H5FDint.c index 8bab501..7af448e 100644 --- a/src/H5FDint.c +++ b/src/H5FDint.c @@ -472,7 +472,7 @@ done: */ herr_t H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[], - const void *bufs[] /* out */) + const void *bufs[]) { hbool_t addrs_cooked = FALSE; hbool_t extend_sizes = FALSE; @@ -605,6 +605,275 @@ done: } /* end H5FD_write_vector() */ /*------------------------------------------------------------------------- + * Function: H5FD__read_selection_translate + * + * Purpose: Translates a selection read call to a vector read call if + * vector reads are supported, or a series of scalar read + * calls otherwise. + * + * Return: Success: SUCCEED + * All reads have completed successfully, and + * the results havce been into the supplied + * buffers. + * + * Failure: FAIL + * The contents of supplied buffers are undefined. + * + * Programmer: NAF -- 5/13/21 + * + * Changes: None + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__read_selection_translate(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, + H5S_t *mem_spaces[], H5S_t *file_spaces[], haddr_t offsets[], + size_t element_sizes[], void *bufs[] /* out */) +{ + hbool_t extend_sizes = FALSE; + hbool_t extend_bufs = FALSE; + uint32_t i; + size_t element_size; + void * buf; + hbool_t use_vector = FALSE; + haddr_t addrs_static[8]; + haddr_t * addrs = addrs_static; + size_t sizes_static[8]; + size_t * sizes = sizes_static; + void * vec_bufs_static[8]; + void ** vec_bufs = vec_bufs_static; + hsize_t file_off[H5FD_SEQ_LIST_LEN]; + size_t file_len[H5FD_SEQ_LIST_LEN]; + hsize_t mem_off[H5FD_SEQ_LIST_LEN]; + size_t mem_len[H5FD_SEQ_LIST_LEN]; + size_t file_seq_i; + size_t mem_seq_i; + size_t file_nseq; + size_t mem_nseq; + size_t io_len; + size_t dummy_nelem; + H5S_sel_iter_t file_iter; + H5S_sel_iter_t mem_iter; + H5FD_mem_t types[2] = {type, H5FD_MEM_NOLIST}; + size_t vec_arr_nalloc = sizeof(addrs_static) / sizeof(addrs_static[0]); + size_t vec_arr_nused = 0; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ + HDassert(file); + HDassert(file->cls); + HDassert(count > 0); + HDassert(vec_arr_nalloc == sizeof(sizes_static) / sizeof(sizes_static[0])); + HDassert(vec_arr_nalloc == sizeof(vec_bufs_static) / sizeof(vec_bufs_static[0])); + HDassert(mem_spaces); + HDassert(file_spaces); + HDassert(offsets); + HDassert(element_sizes); + HDassert(bufs); + + /* Verify that the first elements of the element_sizes and bufs arrays are + * valid. */ + HDassert(element_sizes[0] != 0); + HDassert(bufs[0] != NULL); + + /* Check if we're using vector I/O */ + use_vector = file->cls->read_vector != NULL; + + /* Loop over dataspaces */ + for (i = 0; i < count; i++) { + + /* we have already verified that element_sizes[0] != 0 and bufs[0] + * != NULL */ + + if (!extend_sizes) { + + if (element_sizes[i] == 0) { + + extend_sizes = TRUE; + element_size = element_sizes[i - 1]; + } + else { + + element_size = element_sizes[i]; + } + } + + if (!extend_bufs) { + + if (bufs[i] == NULL) { + + extend_bufs = TRUE; + buf = bufs[i - 1]; + } + else { + + buf = bufs[i]; + } + } + + /* Initialize sequence lists for memory and file spaces */ + if (H5S_select_iter_init(&file_iter, file_spaces[i], element_size, 0) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for file space") + if (H5S_select_iter_init(&mem_iter, mem_spaces[i], element_size, 0) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for memory space") + + /* Fill sequence lists */ + if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, &dummy_nelem, + file_off, file_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, &dummy_nelem, + mem_off, mem_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + if (file_nseq && !mem_nseq) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, + "memory selection is empty but file selection is not") + file_seq_i = 0; + mem_seq_i = 0; + + while (file_seq_i < file_nseq) { + /* Calculate length of this IO */ + io_len = MIN(file_len[file_seq_i], mem_len[mem_seq_i]); + + /* Check if we're using vector I/O */ + if (use_vector) { + /* Check if we need to extend the arrays */ + if (vec_arr_nused == vec_arr_nalloc) { + /* Check if we're using the static arrays */ + if (addrs == addrs_static) { + HDassert(sizes == sizes_static); + HDassert(vec_bufs == vec_bufs_static); + + /* Allocate dynamic arrays */ + if (NULL == (addrs = H5MM_malloc(sizeof(addrs_static) * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for address list") + if (NULL == (sizes = H5MM_malloc(sizeof(sizes_static) * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for size list") + if (NULL == (vec_bufs = H5MM_malloc(sizeof(vec_bufs_static) * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for buffer list") + + /* Copy the existing data */ + (void)H5MM_memcpy(addrs, addrs_static, sizeof(addrs_static)); + (void)H5MM_memcpy(sizes, sizes_static, sizeof(sizes_static)); + (void)H5MM_memcpy(vec_bufs, vec_bufs_static, sizeof(vec_bufs_static)); + } + else { + void *tmp_ptr; + + /* Reallocate arrays */ + if (NULL == (tmp_ptr = H5MM_realloc(addrs, vec_arr_nalloc * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory reallocation failed for address list") + addrs = tmp_ptr; + if (NULL == (tmp_ptr = H5MM_realloc(sizes, vec_arr_nalloc * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory reallocation failed for size list") + sizes = tmp_ptr; + if (NULL == (tmp_ptr = H5MM_realloc(vec_bufs, vec_arr_nalloc * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory reallocation failed for buffer list") + vec_bufs = tmp_ptr; + } + + /* Record that we've doubled the array sizes */ + vec_arr_nalloc *= 2; + } + + /* Add this segment to vector read list */ + addrs[vec_arr_nused] = offsets[i] + file_off[file_seq_i]; + sizes[vec_arr_nused] = io_len; + vec_bufs[vec_arr_nused] = (void *)((uint8_t *)buf + mem_off[mem_seq_i]); + vec_arr_nused++; + } + else + /* Issue scalar read call */ + if ((file->cls->read)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len, + (void *)((uint8_t *)buf + mem_off[mem_seq_i])) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed") + + /* Update file sequence */ + if (io_len == file_len[file_seq_i]) + file_seq_i++; + else { + file_off[file_seq_i] += io_len; + file_len[file_seq_i] -= io_len; + } + + /* Update memory sequence */ + if (io_len == mem_len[mem_seq_i]) + mem_seq_i++; + else { + mem_off[mem_seq_i] += io_len; + mem_len[mem_seq_i] -= io_len; + } + + /* Refill file sequence list if necessary */ + if (file_seq_i == H5FD_SEQ_LIST_LEN) { + if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, + &dummy_nelem, file_off, file_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + + file_seq_i = 0; + } + HDassert(file_seq_i <= file_nseq); + + /* Refill memory sequence list if necessary */ + if (mem_seq_i == H5FD_SEQ_LIST_LEN) { + if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, + &dummy_nelem, mem_off, mem_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + + if (!mem_nseq && file_seq_i < file_nseq) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, + "memory selection terminated before file selection") + + mem_seq_i = 0; + } + HDassert(mem_seq_i <= mem_nseq); + } + + if (mem_seq_i < mem_nseq) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "file selection terminated before memory selection") + + /* Terminate iterators */ + if (H5S_SELECT_ITER_RELEASE(&file_iter) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator") + if (H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator") + } + + /* Issue vector read call if appropriate */ + if (use_vector) { + H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t) + if ((file->cls->read_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, vec_bufs) < + 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read vector request failed") + } + +done: + /* Cleanup */ + if (use_vector) { + if (addrs != addrs_static) + addrs = H5MM_xfree(addrs); + if (sizes != sizes_static) + sizes = H5MM_xfree(sizes); + if (vec_bufs != vec_bufs_static) + vec_bufs = H5MM_xfree(vec_bufs); + } + + /* Make sure we cleaned up */ + HDassert(!addrs || addrs == addrs_static); + HDassert(!sizes || sizes == sizes_static); + HDassert(!vec_bufs || vec_bufs == vec_bufs_static); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD__read_selection_translate() */ + +/*------------------------------------------------------------------------- * Function: H5FD_read_selection * * Purpose: Private version of H5FDread_selection() @@ -646,23 +915,17 @@ done: *------------------------------------------------------------------------- */ herr_t -H5FD_read_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_spaces[], H5S_t *file_spaces[], +H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t *mem_spaces[], H5S_t *file_spaces[], haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */) { hbool_t offsets_cooked = FALSE; - hbool_t extend_sizes = FALSE; - hbool_t extend_bufs = FALSE; + hid_t mem_space_ids_static[8]; + hid_t * mem_space_ids = mem_space_ids_static; + hid_t file_space_ids_static[8]; + hid_t * file_space_ids = file_space_ids_static; + uint32_t num_spaces = 0; + hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ uint32_t i; - size_t element_size; - void * buf; - hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ - hbool_t use_vector = FALSE; - haddr_t addrs_static[8]; - haddr_t *addrs = addrs_static; - size_t sizes_static[8]; - size_t * sizes = sizes_static; - void * vec_bufs_static[8]; - void ** vec_bufs = vec_bufs_static; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -681,9 +944,6 @@ H5FD_read_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_sp HDassert((count == 0) || (element_sizes[0] != 0)); HDassert((count == 0) || (bufs[0] != NULL)); - /* Check if we're using vector I/O */ - use_vector = file->cls->write_vector != NULL; - /* Get proper DXPL for I/O */ dxpl_id = H5CX_get_dxpl(); @@ -736,211 +996,201 @@ H5FD_read_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_sp } /* if the underlying VFD supports selection read, make the call */ - /*if (file->cls->read_selection) { + if (file->cls->read_selection) { + /* Allocate array of space IDs if necessary, otherwise use static + * buffers */ + if (count > sizeof(mem_space_ids_static) / sizeof(mem_space_ids_static[0])) { + if (NULL == (mem_space_ids = H5MM_malloc(count * sizeof(hid_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") + if (NULL == (file_space_ids = H5MM_malloc(count * sizeof(hid_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") + } - if ((file->cls->read_selection)(file, count, type, mem_spaces, file_spaces, offsets, element_sizes, - bufs) < 0) + /* Create IDs for all dataspaces */ + for (; num_spaces < count; num_spaces++) { + if ((mem_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, mem_spaces[num_spaces], TRUE)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID") + if ((file_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, file_spaces[num_spaces], TRUE)) < + 0) { + if (H5I_dec_app_ref(mem_space_ids[num_spaces]) < 0) + HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id") + HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID") + } + } + + if ((file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, + element_sizes, bufs) < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read selection request failed") } - else*/ - { - hsize_t file_off[H5FD_SEQ_LIST_LEN]; - size_t file_len[H5FD_SEQ_LIST_LEN]; - hsize_t mem_off[H5FD_SEQ_LIST_LEN]; - size_t mem_len[H5FD_SEQ_LIST_LEN]; - size_t file_seq_i; - size_t mem_seq_i; - size_t file_nseq; - size_t mem_nseq; - size_t io_len; - size_t dummy_nelem; - H5S_sel_iter_t file_iter; - H5S_sel_iter_t mem_iter; - H5FD_mem_t types[2] = {type, H5FD_MEM_NOLIST}; - size_t vec_arr_nalloc = sizeof(addrs_static) / sizeof(addrs_static[0]); - size_t vec_arr_nused = 0; - - HDassert(vec_arr_nalloc == sizeof(sizes_static) / sizeof(sizes_static[0])); - HDassert(vec_arr_nalloc == sizeof(vec_bufs_static) / sizeof(vec_bufs_static[0])); - - /* otherwise, implement the selection read as a sequence of regular + else + /* Otherwise, implement the selection read as a sequence of regular * or vector read calls. */ - extend_sizes = FALSE; + if (H5FD__read_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets, + element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "translation to vector or scalar read failed") + +done: + /* undo the base addr offset to the offsets array if necessary */ + if (offsets_cooked) { + + HDassert(file->base_addr > 0); for (i = 0; i < count; i++) { - /* we have already verified that element_sizes[0] != 0 and bufs[0] - * != NULL */ + offsets[i] -= file->base_addr; + } + } - if (!extend_sizes) { + /* Cleanup dataspace arrays */ + for (i = 0; i < num_spaces; i++) { + if (H5I_dec_app_ref(mem_space_ids[i]) < 0) + HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id") + if (H5I_dec_app_ref(file_space_ids[i]) < 0) + HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id") + } + if (mem_space_ids != mem_space_ids_static) + mem_space_ids = H5MM_xfree(mem_space_ids); + if (file_space_ids != file_space_ids_static) + file_space_ids = H5MM_xfree(file_space_ids); - if (element_sizes[i] == 0) { + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_read_selection() */ - extend_sizes = TRUE; - element_size = element_sizes[i - 1]; - } - else { +/*------------------------------------------------------------------------- + * Function: H5FD_read_selection_id + * + * Purpose: Like H5FD_read_selection(), but takes hid_t arrays instead + * of H5S_t * arrays for the dataspaces. + * + * Return: Success: SUCCEED + * All reads have completed successfully, and + * the results havce been into the supplied + * buffers. + * + * Failure: FAIL + * The contents of supplied buffers are undefined. + * + * Programmer: NAF -- 5/19/21 + * + * Changes: None + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_read_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[], + hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], + void *bufs[] /* out */) +{ + hbool_t offsets_cooked = FALSE; + H5S_t * mem_spaces_static[8]; + H5S_t ** mem_spaces = mem_spaces_static; + H5S_t * file_spaces_static[8]; + H5S_t ** file_spaces = file_spaces_static; + hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ + uint32_t i; + herr_t ret_value = SUCCEED; /* Return value */ - element_size = element_sizes[i]; - } - } + FUNC_ENTER_NOAPI(FAIL) - if (!extend_bufs) { + /* Sanity checks */ + HDassert(file); + HDassert(file->cls); + HDassert((mem_space_ids) || (count == 0)); + HDassert((file_space_ids) || (count == 0)); + HDassert((offsets) || (count == 0)); + HDassert((element_sizes) || (count == 0)); + HDassert((bufs) || (count == 0)); - if (bufs[i] == NULL) { + /* Verify that the first elements of the element_sizes and bufs arrays are + * valid. */ + HDassert((count == 0) || (element_sizes[0] != 0)); + HDassert((count == 0) || (bufs[0] != NULL)); - extend_bufs = TRUE; - buf = bufs[i - 1]; - } - else { + /* Get proper DXPL for I/O */ + dxpl_id = H5CX_get_dxpl(); - buf = bufs[i]; - } - } +#ifndef H5_HAVE_PARALLEL + /* The no-op case + * + * Do not return early for Parallel mode since the I/O could be a + * collective transfer. + */ + if (0 == count) { + HGOTO_DONE(SUCCEED) + } +#endif /* H5_HAVE_PARALLEL */ - /* Initialize sequence lists for memory and file spaces */ - if (H5S_select_iter_init(&file_iter, file_spaces[i], element_size, 0) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for file space") - if (H5S_select_iter_init(&mem_iter, mem_spaces[i], element_size, 0) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for memory space") - - /* Fill sequence lists */ - if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, - &dummy_nelem, file_off, file_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, &dummy_nelem, - mem_off, mem_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - if (file_nseq && !mem_nseq) - HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, - "memory selection is empty but file selection is not") - file_seq_i = 0; - mem_seq_i = 0; - - while (file_seq_i < file_nseq) { - /* Calculate length of this IO */ - io_len = MIN(file_len[file_seq_i], mem_len[mem_seq_i]); - - /* Check if we're using vector I/O */ - if (use_vector) { - /* Check if we need to extend the arrays */ - if (vec_arr_nused == vec_arr_nalloc) { - /* Check if we're using the static arrays */ - if (addrs == addrs_static) { - HDassert(sizes == sizes_static); - HDassert(vec_bufs == vec_bufs_static); - - /* Allocate dynamic arrays */ - if (NULL == (addrs = H5MM_malloc(sizeof(addrs_static) * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for address list") - if (NULL == (sizes = H5MM_malloc(sizeof(sizes_static) * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for size list") - if (NULL == (vec_bufs = H5MM_malloc(sizeof(vec_bufs_static) * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for buffer list") - - /* Copy the existing data */ - (void)H5MM_memcpy(addrs, addrs_static, sizeof(addrs_static)); - (void)H5MM_memcpy(sizes, sizes_static, sizeof(sizes_static)); - (void)H5MM_memcpy(vec_bufs, vec_bufs_static, sizeof(vec_bufs_static)); - } - else { - void *tmp_ptr; - - /* Reallocate arrays */ - if (NULL == (tmp_ptr = H5MM_realloc(addrs, vec_arr_nalloc * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory reallocation failed for address list") - addrs = tmp_ptr; - if (NULL == (tmp_ptr = H5MM_realloc(sizes, vec_arr_nalloc * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory reallocation failed for size list") - sizes = tmp_ptr; - if (NULL == (tmp_ptr = H5MM_realloc(vec_bufs, vec_arr_nalloc * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory reallocation failed for buffer list") - vec_bufs = tmp_ptr; - } - - /* Record that we've doubled the array sizes */ - vec_arr_nalloc *= 2; - } + if (file->base_addr > 0) { - /* Add this segment to vector write list */ - addrs[vec_arr_nused] = offsets[i] + file_off[file_seq_i]; - sizes[vec_arr_nused] = io_len; - vec_bufs[vec_arr_nused] = (void *)((uint8_t *)buf + mem_off[mem_seq_i]); - vec_arr_nused++; - } - else - /* Issue scalar read call */ - if ((file->cls->read)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len, - (void *)((uint8_t *)buf + mem_off[mem_seq_i])) < 0) - HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed") - - /* Update file sequence */ - if (io_len == file_len[file_seq_i]) - file_seq_i++; - else { - file_off[file_seq_i] += io_len; - file_len[file_seq_i] -= io_len; - } + /* apply the base_addr offset to the offsets array. Must undo before + * we return. + */ + for (i = 0; i < count; i++) { - /* Update memory sequence */ - if (io_len == mem_len[mem_seq_i]) - mem_seq_i++; - else { - mem_off[mem_seq_i] += io_len; - mem_len[mem_seq_i] -= io_len; - } + offsets[i] += file->base_addr; + } + offsets_cooked = TRUE; + } - /* Refill file sequence list if necessary */ - if (file_seq_i == H5FD_SEQ_LIST_LEN) { - if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, - &dummy_nelem, file_off, file_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + /* If the file is open for SWMR read access, allow access to data past + * the end of the allocated space (the 'eoa'). This is done because the + * eoa stored in the file's superblock might be out of sync with the + * objects being written within the file by the application performing + * SWMR write operations. + */ + /* For now at least, only check that the offset is not past the eoa, since + * looking into the highest offset in the selection (different from the + * bounds) is potentially expensive. + */ + if (!(file->access_flags & H5F_ACC_SWMR_READ)) { + haddr_t eoa; - file_seq_i = 0; - } - HDassert(file_seq_i <= file_nseq); + if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed") - /* Refill memory sequence list if necessary */ - if (mem_seq_i == H5FD_SEQ_LIST_LEN) { - if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, - &dummy_nelem, mem_off, mem_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + for (i = 0; i < count; i++) { - if (!mem_nseq && file_seq_i < file_nseq) - HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, - "memory selection terminated before file selection") + if ((offsets[i]) > eoa) - mem_seq_i = 0; - } - HDassert(mem_seq_i <= mem_nseq); - } + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", + (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa) + } + } - if (mem_seq_i < mem_nseq) - HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, - "file selection terminated before memory selection") + /* if the underlying VFD supports selection read, make the call */ + if (file->cls->read_selection) { + if ((file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, + element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read selection request failed") + } + else { + /* Otherwise, implement the selection read as a sequence of regular + * or vector read calls. + */ - /* Terminate iterators */ - if (H5S_SELECT_ITER_RELEASE(&file_iter) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator") - if (H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator") + /* Allocate arrays of space objects if necessary, otherwise use static + * buffers */ + if (count > sizeof(mem_spaces_static) / sizeof(mem_spaces_static[0])) { + if (NULL == (mem_spaces = H5MM_malloc(count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") + if (NULL == (file_spaces = H5MM_malloc(count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") } - /* Issue vector read call if appropriate */ - if (use_vector) { - H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t) - if ((file->cls->read_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, - vec_bufs) < 0) - HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read vector request failed") + /* Get object pointers for all dataspaces */ + for (i = 0; i < count; i++) { + if (NULL == (mem_spaces[i] = (H5S_t *)H5I_object_verify(mem_space_ids[i], H5I_DATASPACE))) + HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve memory dataspace from ID") + if (NULL == (file_spaces[i] = (H5S_t *)H5I_object_verify(file_space_ids[i], H5I_DATASPACE))) + HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve file dataspace from ID") } + + /* Translate to vector or scalar I/O */ + if (H5FD__read_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets, + element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "translation to vector or scalar read failed") } done: @@ -955,6 +1205,264 @@ done: } } + /* Cleanup dataspace arrays */ + if (mem_spaces != mem_spaces_static) + mem_spaces = H5MM_xfree(mem_spaces); + if (file_spaces != file_spaces_static) + file_spaces = H5MM_xfree(file_spaces); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_read_selection_id() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__write_selection_translate + * + * Purpose: Translates a selection write call to a vector write call + * if vector writes are supported, or a series of scalar + * write calls otherwise. + * + * Return: Success: SUCCEED + * All writes have completed successfully. + * + * Failure: FAIL + * One or more writes failed. + * + * Programmer: NAF -- 5/13/21 + * + * Changes: None + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__write_selection_translate(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, + H5S_t *mem_spaces[], H5S_t *file_spaces[], haddr_t offsets[], + size_t element_sizes[], const void *bufs[]) +{ + hbool_t extend_sizes = FALSE; + hbool_t extend_bufs = FALSE; + uint32_t i; + size_t element_size; + const void * buf; + hbool_t use_vector = FALSE; + haddr_t addrs_static[8]; + haddr_t * addrs = addrs_static; + size_t sizes_static[8]; + size_t * sizes = sizes_static; + const void * vec_bufs_static[8]; + const void ** vec_bufs = vec_bufs_static; + hsize_t file_off[H5FD_SEQ_LIST_LEN]; + size_t file_len[H5FD_SEQ_LIST_LEN]; + hsize_t mem_off[H5FD_SEQ_LIST_LEN]; + size_t mem_len[H5FD_SEQ_LIST_LEN]; + size_t file_seq_i; + size_t mem_seq_i; + size_t file_nseq; + size_t mem_nseq; + size_t io_len; + size_t dummy_nelem; + H5S_sel_iter_t file_iter; + H5S_sel_iter_t mem_iter; + H5FD_mem_t types[2] = {type, H5FD_MEM_NOLIST}; + size_t vec_arr_nalloc = sizeof(addrs_static) / sizeof(addrs_static[0]); + size_t vec_arr_nused = 0; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ + HDassert(file); + HDassert(file->cls); + HDassert(count > 0); + HDassert(vec_arr_nalloc == sizeof(sizes_static) / sizeof(sizes_static[0])); + HDassert(vec_arr_nalloc == sizeof(vec_bufs_static) / sizeof(vec_bufs_static[0])); + HDassert(mem_spaces); + HDassert(file_spaces); + HDassert(offsets); + HDassert(element_sizes); + HDassert(bufs); + + /* Verify that the first elements of the element_sizes and bufs arrays are + * valid. */ + HDassert(element_sizes[0] != 0); + HDassert(bufs[0] != NULL); + + /* Check if we're using vector I/O */ + use_vector = file->cls->write_vector != NULL; + + /* Loop over dataspaces */ + for (i = 0; i < count; i++) { + + /* we have already verified that element_sizes[0] != 0 and bufs[0] + * != NULL */ + + if (!extend_sizes) { + + if (element_sizes[i] == 0) { + + extend_sizes = TRUE; + element_size = element_sizes[i - 1]; + } + else { + + element_size = element_sizes[i]; + } + } + + if (!extend_bufs) { + + if (bufs[i] == NULL) { + + extend_bufs = TRUE; + buf = bufs[i - 1]; + } + else { + + buf = bufs[i]; + } + } + + /* Initialize sequence lists for memory and file spaces */ + if (H5S_select_iter_init(&file_iter, file_spaces[i], element_size, 0) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for file space") + if (H5S_select_iter_init(&mem_iter, mem_spaces[i], element_size, 0) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for memory space") + + /* Fill sequence lists */ + if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, &dummy_nelem, + file_off, file_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, &dummy_nelem, + mem_off, mem_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + if (file_nseq && !mem_nseq) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, + "memory selection is empty but file selection is not") + file_seq_i = 0; + mem_seq_i = 0; + + while (file_seq_i < file_nseq) { + /* Calculate length of this IO */ + io_len = MIN(file_len[file_seq_i], mem_len[mem_seq_i]); + + /* Check if we're using vector I/O */ + if (use_vector) { + /* Check if we need to extend the arrays */ + if (vec_arr_nused == vec_arr_nalloc) { + /* Check if we're using the static arrays */ + if (addrs == addrs_static) { + HDassert(sizes == sizes_static); + HDassert(vec_bufs == vec_bufs_static); + + /* Allocate dynamic arrays */ + if (NULL == (addrs = H5MM_malloc(sizeof(addrs_static) * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for address list") + if (NULL == (sizes = H5MM_malloc(sizeof(sizes_static) * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for size list") + if (NULL == (vec_bufs = H5MM_malloc(sizeof(vec_bufs_static) * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory allocation failed for buffer list") + + /* Copy the existing data */ + (void)H5MM_memcpy(addrs, addrs_static, sizeof(addrs_static)); + (void)H5MM_memcpy(sizes, sizes_static, sizeof(sizes_static)); + (void)H5MM_memcpy(vec_bufs, vec_bufs_static, sizeof(vec_bufs_static)); + } + else { + void *tmp_ptr; + + /* Reallocate arrays */ + if (NULL == (tmp_ptr = H5MM_realloc(addrs, vec_arr_nalloc * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory reallocation failed for address list") + addrs = tmp_ptr; + if (NULL == (tmp_ptr = H5MM_realloc(sizes, vec_arr_nalloc * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory reallocation failed for size list") + sizes = tmp_ptr; + if (NULL == (tmp_ptr = H5MM_realloc(vec_bufs, vec_arr_nalloc * 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "memory reallocation failed for buffer list") + vec_bufs = tmp_ptr; + } + + /* Record that we've doubled the array sizes */ + vec_arr_nalloc *= 2; + } + + /* Add this segment to vector write list */ + addrs[vec_arr_nused] = offsets[i] + file_off[file_seq_i]; + sizes[vec_arr_nused] = io_len; + vec_bufs[vec_arr_nused] = (const void *)((const uint8_t *)buf + mem_off[mem_seq_i]); + vec_arr_nused++; + } + else + /* Issue scalar write call */ + if ((file->cls->write)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len, + (const void *)((const uint8_t *)buf + mem_off[mem_seq_i])) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write request failed") + + /* Update file sequence */ + if (io_len == file_len[file_seq_i]) + file_seq_i++; + else { + file_off[file_seq_i] += io_len; + file_len[file_seq_i] -= io_len; + } + + /* Update memory sequence */ + if (io_len == mem_len[mem_seq_i]) + mem_seq_i++; + else { + mem_off[mem_seq_i] += io_len; + mem_len[mem_seq_i] -= io_len; + } + + /* Refill file sequence list if necessary */ + if (file_seq_i == H5FD_SEQ_LIST_LEN) { + if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, + &dummy_nelem, file_off, file_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + + file_seq_i = 0; + } + HDassert(file_seq_i <= file_nseq); + + /* Refill memory sequence list if necessary */ + if (mem_seq_i == H5FD_SEQ_LIST_LEN) { + if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, + &dummy_nelem, mem_off, mem_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + + if (!mem_nseq && file_seq_i < file_nseq) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, + "memory selection terminated before file selection") + + mem_seq_i = 0; + } + HDassert(mem_seq_i <= mem_nseq); + } + + if (mem_seq_i < mem_nseq) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "file selection terminated before memory selection") + + /* Terminate iterators */ + if (H5S_SELECT_ITER_RELEASE(&file_iter) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator") + if (H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator") + } + + /* Issue vector write call if appropriate */ + if (use_vector) { + H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t) + if ((file->cls->write_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, vec_bufs) < + 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write vector request failed") + } + +done: /* Cleanup */ if (use_vector) { if (addrs != addrs_static) @@ -971,7 +1479,7 @@ done: HDassert(!vec_bufs || vec_bufs == vec_bufs_static); FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FD_read_selection() */ +} /* end H5FD__write_selection_translate() */ /*------------------------------------------------------------------------- * Function: H5FD_write_selection @@ -1013,24 +1521,18 @@ done: *------------------------------------------------------------------------- */ herr_t -H5FD_write_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_spaces[], H5S_t *file_spaces[], - haddr_t offsets[], size_t element_sizes[], const void *bufs[] /* out */) +H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t *mem_spaces[], H5S_t *file_spaces[], + haddr_t offsets[], size_t element_sizes[], const void *bufs[]) { - hbool_t offsets_cooked = FALSE; - hbool_t extend_sizes = FALSE; - hbool_t extend_bufs = FALSE; - uint32_t i; - size_t element_size; - const void * buf; - hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ - hbool_t use_vector = FALSE; - haddr_t addrs_static[8]; - haddr_t * addrs = addrs_static; - size_t sizes_static[8]; - size_t * sizes = sizes_static; - const void * vec_bufs_static[8]; - const void **vec_bufs = vec_bufs_static; - herr_t ret_value = SUCCEED; /* Return value */ + hbool_t offsets_cooked = FALSE; + hid_t mem_space_ids_static[8]; + hid_t * mem_space_ids = mem_space_ids_static; + hid_t file_space_ids_static[8]; + hid_t * file_space_ids = file_space_ids_static; + uint32_t num_spaces = 0; + hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ + uint32_t i; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -1048,9 +1550,6 @@ H5FD_write_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_s HDassert((count == 0) || (element_sizes[0] != 0)); HDassert((count == 0) || (bufs[0] != NULL)); - /* Check if we're using vector I/O */ - use_vector = file->cls->write_vector != NULL; - /* Get proper DXPL for I/O */ dxpl_id = H5CX_get_dxpl(); @@ -1097,211 +1596,192 @@ H5FD_write_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_s } /* if the underlying VFD supports selection write, make the call */ - /*if (file->cls->write_selection) { + if (file->cls->write_selection) { + /* Allocate array of space IDs if necessary, otherwise use static + * buffers */ + if (count > sizeof(mem_space_ids_static) / sizeof(mem_space_ids_static[0])) { + if (NULL == (mem_space_ids = H5MM_malloc(count * sizeof(hid_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") + if (NULL == (file_space_ids = H5MM_malloc(count * sizeof(hid_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") + } - if ((file->cls->write_selection)(file, count, type, mem_spaces, file_spaces, offsets, element_sizes, - bufs) < 0) + /* Create IDs for all dataspaces */ + for (; num_spaces < count; num_spaces++) { + if ((mem_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, mem_spaces[num_spaces], TRUE)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID") + if ((file_space_ids[num_spaces] = H5I_register(H5I_DATASPACE, file_spaces[num_spaces], TRUE)) < + 0) { + if (H5I_dec_app_ref(mem_space_ids[num_spaces]) < 0) + HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id") + HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID") + } + } + + if ((file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, + element_sizes, bufs) < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write selection request failed") } - else*/ - { - hsize_t file_off[H5FD_SEQ_LIST_LEN]; - size_t file_len[H5FD_SEQ_LIST_LEN]; - hsize_t mem_off[H5FD_SEQ_LIST_LEN]; - size_t mem_len[H5FD_SEQ_LIST_LEN]; - size_t file_seq_i; - size_t mem_seq_i; - size_t file_nseq; - size_t mem_nseq; - size_t io_len; - size_t dummy_nelem; - H5S_sel_iter_t file_iter; - H5S_sel_iter_t mem_iter; - H5FD_mem_t types[2] = {type, H5FD_MEM_NOLIST}; - size_t vec_arr_nalloc = sizeof(addrs_static) / sizeof(addrs_static[0]); - size_t vec_arr_nused = 0; - - HDassert(vec_arr_nalloc == sizeof(sizes_static) / sizeof(sizes_static[0])); - HDassert(vec_arr_nalloc == sizeof(vec_bufs_static) / sizeof(vec_bufs_static[0])); - - /* otherwise, implement the selection write as a sequence of regular + else + /* Otherwise, implement the selection write as a sequence of regular * or vector write calls. */ - extend_sizes = FALSE; + if (H5FD__write_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets, + element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "translation to vector or scalar write failed") + +done: + /* undo the base addr offset to the offsets array if necessary */ + if (offsets_cooked) { + + HDassert(file->base_addr > 0); for (i = 0; i < count; i++) { - /* we have already verified that element_sizes[0] != 0 and bufs[0] - * != NULL */ + offsets[i] -= file->base_addr; + } + } - if (!extend_sizes) { + /* Cleanup dataspace arrays */ + for (i = 0; i < num_spaces; i++) { + if (H5I_dec_app_ref(mem_space_ids[i]) < 0) + HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id") + if (H5I_dec_app_ref(file_space_ids[i]) < 0) + HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "problem freeing id") + } + if (mem_space_ids != mem_space_ids_static) + mem_space_ids = H5MM_xfree(mem_space_ids); + if (file_space_ids != file_space_ids_static) + file_space_ids = H5MM_xfree(file_space_ids); - if (element_sizes[i] == 0) { + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_write_selection() */ - extend_sizes = TRUE; - element_size = element_sizes[i - 1]; - } - else { +/*------------------------------------------------------------------------- + * Function: H5FD_write_selection_id + * + * Purpose: Like H5FD_write_selection(), but takes hid_t arrays + * instead of H5S_t * arrays for the dataspaces. + * + * Return: Success: SUCCEED + * All writes have completed successfully. + * + * Failure: FAIL + * One or more writes failed. + * + * Programmer: NAF -- 5/19/21 + * + * Changes: None + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_write_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[], + hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], const void *bufs[]) +{ + hbool_t offsets_cooked = FALSE; + H5S_t * mem_spaces_static[8]; + H5S_t ** mem_spaces = mem_spaces_static; + H5S_t * file_spaces_static[8]; + H5S_t ** file_spaces = file_spaces_static; + hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ + uint32_t i; + herr_t ret_value = SUCCEED; /* Return value */ - element_size = element_sizes[i]; - } - } + FUNC_ENTER_NOAPI(FAIL) - if (!extend_bufs) { + /* Sanity checks */ + HDassert(file); + HDassert(file->cls); + HDassert((mem_space_ids) || (count == 0)); + HDassert((file_space_ids) || (count == 0)); + HDassert((offsets) || (count == 0)); + HDassert((element_sizes) || (count == 0)); + HDassert((bufs) || (count == 0)); - if (bufs[i] == NULL) { + /* Verify that the first elements of the element_sizes and bufs arrays are + * valid. */ + HDassert((count == 0) || (element_sizes[0] != 0)); + HDassert((count == 0) || (bufs[0] != NULL)); - extend_bufs = TRUE; - buf = bufs[i - 1]; - } - else { + /* Get proper DXPL for I/O */ + dxpl_id = H5CX_get_dxpl(); - buf = bufs[i]; - } - } +#ifndef H5_HAVE_PARALLEL + /* The no-op case + * + * Do not return early for Parallel mode since the I/O could be a + * collective transfer. + */ + if (0 == count) { + HGOTO_DONE(SUCCEED) + } +#endif /* H5_HAVE_PARALLEL */ - /* Initialize sequence lists for memory and file spaces */ - if (H5S_select_iter_init(&file_iter, file_spaces[i], element_size, 0) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for file space") - if (H5S_select_iter_init(&mem_iter, mem_spaces[i], element_size, 0) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize sequence list for memory space") - - /* Fill sequence lists */ - if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, - &dummy_nelem, file_off, file_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, &dummy_nelem, - mem_off, mem_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - if (file_nseq && !mem_nseq) - HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, - "memory selection is empty but file selection is not") - file_seq_i = 0; - mem_seq_i = 0; - - while (file_seq_i < file_nseq) { - /* Calculate length of this IO */ - io_len = MIN(file_len[file_seq_i], mem_len[mem_seq_i]); - - /* Check if we're using vector I/O */ - if (use_vector) { - /* Check if we need to extend the arrays */ - if (vec_arr_nused == vec_arr_nalloc) { - /* Check if we're using the static arrays */ - if (addrs == addrs_static) { - HDassert(sizes == sizes_static); - HDassert(vec_bufs == vec_bufs_static); - - /* Allocate dynamic arrays */ - if (NULL == (addrs = H5MM_malloc(sizeof(addrs_static) * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for address list") - if (NULL == (sizes = H5MM_malloc(sizeof(sizes_static) * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for size list") - if (NULL == (vec_bufs = H5MM_malloc(sizeof(vec_bufs_static) * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory allocation failed for buffer list") - - /* Copy the existing data */ - (void)H5MM_memcpy(addrs, addrs_static, sizeof(addrs_static)); - (void)H5MM_memcpy(sizes, sizes_static, sizeof(sizes_static)); - (void)H5MM_memcpy(vec_bufs, vec_bufs_static, sizeof(vec_bufs_static)); - } - else { - void *tmp_ptr; - - /* Reallocate arrays */ - if (NULL == (tmp_ptr = H5MM_realloc(addrs, vec_arr_nalloc * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory reallocation failed for address list") - addrs = tmp_ptr; - if (NULL == (tmp_ptr = H5MM_realloc(sizes, vec_arr_nalloc * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory reallocation failed for size list") - sizes = tmp_ptr; - if (NULL == (tmp_ptr = H5MM_realloc(vec_bufs, vec_arr_nalloc * 2))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "memory reallocation failed for buffer list") - vec_bufs = tmp_ptr; - } - - /* Record that we've doubled the array sizes */ - vec_arr_nalloc *= 2; - } + if (file->base_addr > 0) { - /* Add this segment to vector write list */ - addrs[vec_arr_nused] = offsets[i] + file_off[file_seq_i]; - sizes[vec_arr_nused] = io_len; - vec_bufs[vec_arr_nused] = (const void *)((const uint8_t *)buf + mem_off[mem_seq_i]); - vec_arr_nused++; - } - else - /* Issue scalar write call */ - if ((file->cls->write)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len, - (const void *)((const uint8_t *)buf + mem_off[mem_seq_i])) < 0) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver read request failed") - - /* Update file sequence */ - if (io_len == file_len[file_seq_i]) - file_seq_i++; - else { - file_off[file_seq_i] += io_len; - file_len[file_seq_i] -= io_len; - } + /* apply the base_addr offset to the offsets array. Must undo before + * we return. + */ + for (i = 0; i < count; i++) { - /* Update memory sequence */ - if (io_len == mem_len[mem_seq_i]) - mem_seq_i++; - else { - mem_off[mem_seq_i] += io_len; - mem_len[mem_seq_i] -= io_len; - } + offsets[i] += file->base_addr; + } + offsets_cooked = TRUE; + } - /* Refill file sequence list if necessary */ - if (file_seq_i == H5FD_SEQ_LIST_LEN) { - if (H5S_SELECT_ITER_GET_SEQ_LIST(&file_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &file_nseq, - &dummy_nelem, file_off, file_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + /* For now at least, only check that the offset is not past the eoa, since + * looking into the highest offset in the selection (different from the + * bounds) is potentially expensive. + */ + { + haddr_t eoa; - file_seq_i = 0; - } - HDassert(file_seq_i <= file_nseq); + if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed") - /* Refill memory sequence list if necessary */ - if (mem_seq_i == H5FD_SEQ_LIST_LEN) { - if (H5S_SELECT_ITER_GET_SEQ_LIST(&mem_iter, H5FD_SEQ_LIST_LEN, SIZE_MAX, &mem_nseq, - &dummy_nelem, mem_off, mem_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + for (i = 0; i < count; i++) { - if (!mem_nseq && file_seq_i < file_nseq) - HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, - "memory selection terminated before file selection") + if ((offsets[i]) > eoa) - mem_seq_i = 0; - } - HDassert(mem_seq_i <= mem_nseq); - } + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", + (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa) + } + } - if (mem_seq_i < mem_nseq) - HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, - "file selection terminated before memory selection") + /* if the underlying VFD supports selection write, make the call */ + if (file->cls->write_selection) { + if ((file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, + element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write selection request failed") + } + else { + /* Otherwise, implement the selection write as a sequence of regular + * or vector write calls. + */ - /* Terminate iterators */ - if (H5S_SELECT_ITER_RELEASE(&file_iter) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release file selection iterator") - if (H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't release memory selection iterator") + /* Allocate arrays of space objects if necessary, otherwise use static + * buffers */ + if (count > sizeof(mem_spaces_static) / sizeof(mem_spaces_static[0])) { + if (NULL == (mem_spaces = H5MM_malloc(count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") + if (NULL == (file_spaces = H5MM_malloc(count * sizeof(H5S_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for dataspace list") } - /* Issue vector write call if appropriate */ - if (use_vector) { - H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t) - if ((file->cls->write_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, - vec_bufs) < 0) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write vector request failed") + /* Get object pointers for all dataspaces */ + for (i = 0; i < count; i++) { + if (NULL == (mem_spaces[i] = (H5S_t *)H5I_object_verify(mem_space_ids[i], H5I_DATASPACE))) + HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve memory dataspace from ID") + if (NULL == (file_spaces[i] = (H5S_t *)H5I_object_verify(file_space_ids[i], H5I_DATASPACE))) + HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, H5I_INVALID_HID, "can't retrieve file dataspace from ID") } + + /* Translate to vector or scalar I/O */ + if (H5FD__write_selection_translate(file, type, dxpl_id, count, mem_spaces, file_spaces, offsets, + element_sizes, bufs) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "translation to vector or scalar write failed") } done: @@ -1316,23 +1796,14 @@ done: } } - /* Cleanup */ - if (use_vector) { - if (addrs != addrs_static) - addrs = H5MM_xfree(addrs); - if (sizes != sizes_static) - sizes = H5MM_xfree(sizes); - if (vec_bufs != vec_bufs_static) - vec_bufs = H5MM_xfree(vec_bufs); - } - - /* Make sure we cleaned up */ - HDassert(!addrs || addrs == addrs_static); - HDassert(!sizes || sizes == sizes_static); - HDassert(!vec_bufs || vec_bufs == vec_bufs_static); + /* Cleanup dataspace arrays */ + if (mem_spaces != mem_spaces_static) + mem_spaces = H5MM_xfree(mem_spaces); + if (file_spaces != file_spaces_static) + file_spaces = H5MM_xfree(file_spaces); FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FD_write_selection() */ +} /* end H5FD_write_selection_id() */ /*------------------------------------------------------------------------- * Function: H5FD_set_eoa diff --git a/src/H5FDlog.c b/src/H5FDlog.c index 0f42ff9..1a4f8b0 100644 --- a/src/H5FDlog.c +++ b/src/H5FDlog.c @@ -208,6 +208,8 @@ static const H5FD_class_t H5FD_log_g = { H5FD__log_write, /* write */ NULL, /* read vector */ NULL, /* write vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ NULL, /* flush */ H5FD__log_truncate, /* truncate */ H5FD__log_lock, /* lock */ diff --git a/src/H5FDmirror.c b/src/H5FDmirror.c index e59ce62..39fc7eb 100644 --- a/src/H5FDmirror.c +++ b/src/H5FDmirror.c @@ -189,6 +189,8 @@ static const H5FD_class_t H5FD_mirror_g = { H5FD__mirror_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ NULL, /* flush */ H5FD__mirror_truncate, /* truncate */ H5FD__mirror_lock, /* lock */ diff --git a/src/H5FDmulti.c b/src/H5FDmulti.c index 8888259..644e2f5 100644 --- a/src/H5FDmulti.c +++ b/src/H5FDmulti.c @@ -166,6 +166,8 @@ static const H5FD_class_t H5FD_multi_g = { H5FD_multi_write, /*write */ NULL, /*read_vector */ NULL, /*write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ H5FD_multi_flush, /*flush */ H5FD_multi_truncate, /*truncate */ H5FD_multi_lock, /*lock */ diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h index a6f5e59..9e15e5b 100644 --- a/src/H5FDprivate.h +++ b/src/H5FDprivate.h @@ -136,12 +136,18 @@ H5_DLL herr_t H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[] size_t sizes[], void *bufs[] /* out */); H5_DLL herr_t H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[], const void *bufs[] /* out */); -H5_DLL herr_t H5FD_read_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_spaces[], +H5_DLL herr_t H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t *mem_spaces[], H5S_t *file_spaces[], haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */); -H5_DLL herr_t H5FD_write_selection(H5FD_t *file, uint32_t count, H5FD_mem_t type, H5S_t *mem_spaces[], +H5_DLL herr_t H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t *mem_spaces[], H5S_t *file_spaces[], haddr_t offsets[], size_t element_sizes[], const void *bufs[]); +H5_DLL herr_t H5FD_read_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[], + hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], + void *bufs[] /* out */); +H5_DLL herr_t H5FD_write_selection_id(H5FD_t *file, H5FD_mem_t type, uint32_t count, hid_t mem_space_ids[], + hid_t file_space_ids[], haddr_t offsets[], size_t element_sizes[], + const void *bufs[]); H5_DLL herr_t H5FD_flush(H5FD_t *file, hbool_t closing); H5_DLL herr_t H5FD_truncate(H5FD_t *file, hbool_t closing); H5_DLL herr_t H5FD_lock(H5FD_t *file, hbool_t rw); diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h index 3d19974..8483667 100644 --- a/src/H5FDpublic.h +++ b/src/H5FDpublic.h @@ -299,6 +299,12 @@ typedef struct H5FD_class_t { size_t sizes[], void *bufs[]); herr_t (*write_vector)(H5FD_t *file, hid_t dxpl, uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[], const void *bufs[]); + herr_t (*read_selection)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, size_t count, hid_t mem_spaces[], + hid_t file_spaces[], haddr_t offsets[], size_t element_sizes[], + void *bufs[] /*out*/); + herr_t (*write_selection)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, size_t count, hid_t mem_spaces[], + hid_t file_spaces[], haddr_t offsets[], size_t element_sizes[], + const void *bufs[] /*in*/); herr_t (*flush)(H5FD_t *file, hid_t dxpl_id, hbool_t closing); herr_t (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing); herr_t (*lock)(H5FD_t *file, hbool_t rw); @@ -381,6 +387,12 @@ H5_DLL herr_t H5FDread_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD haddr_t addrs[], size_t sizes[], void *bufs[] /* out */); H5_DLL herr_t H5FDwrite_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[], haddr_t addrs[], size_t sizes[], const void *bufs[] /* in */); +H5_DLL herr_t H5FDread_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, + hid_t mem_spaces[], hid_t file_spaces[], haddr_t offsets[], + size_t element_sizes[], void *bufs[] /* out */); +H5_DLL herr_t H5FDwrite_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, + hid_t mem_spaces[], hid_t file_spaces[], haddr_t offsets[], + size_t element_sizes[], const void *bufs[]); H5_DLL herr_t H5FDflush(H5FD_t *file, hid_t dxpl_id, hbool_t closing); H5_DLL herr_t H5FDtruncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing); H5_DLL herr_t H5FDlock(H5FD_t *file, hbool_t rw); diff --git a/src/H5FDros3.c b/src/H5FDros3.c index b51e027..ed5fb03 100644 --- a/src/H5FDros3.c +++ b/src/H5FDros3.c @@ -264,6 +264,8 @@ static const H5FD_class_t H5FD_ros3_g = { H5FD__ros3_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ NULL, /* flush */ H5FD__ros3_truncate, /* truncate */ NULL, /* lock */ diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c index 2da9a14..03f8c2d 100644 --- a/src/H5FDsec2.c +++ b/src/H5FDsec2.c @@ -169,6 +169,8 @@ static const H5FD_class_t H5FD_sec2_g = { H5FD__sec2_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ NULL, /* flush */ H5FD__sec2_truncate, /* truncate */ H5FD__sec2_lock, /* lock */ diff --git a/src/H5FDsplitter.c b/src/H5FDsplitter.c index d835bc0..9aec6ac 100644 --- a/src/H5FDsplitter.c +++ b/src/H5FDsplitter.c @@ -160,6 +160,8 @@ static const H5FD_class_t H5FD_splitter_g = { H5FD__splitter_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ H5FD__splitter_flush, /* flush */ H5FD__splitter_truncate, /* truncate */ H5FD__splitter_lock, /* lock */ diff --git a/src/H5FDstdio.c b/src/H5FDstdio.c index 9b9faf4..a2be248 100644 --- a/src/H5FDstdio.c +++ b/src/H5FDstdio.c @@ -211,6 +211,8 @@ static const H5FD_class_t H5FD_stdio_g = { H5FD_stdio_write, /* write */ NULL, /* read_vector */ NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ H5FD_stdio_flush, /* flush */ H5FD_stdio_truncate, /* truncate */ H5FD_stdio_lock, /* lock */ diff --git a/src/H5Fio.c b/src/H5Fio.c index 454b878..89d3d68 100644 --- a/src/H5Fio.c +++ b/src/H5Fio.c @@ -254,7 +254,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5F_shared_select_read(H5F_shared_t *f_sh, uint32_t count, H5FD_mem_t type, H5S_t *mem_spaces[], +H5F_shared_select_read(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count, H5S_t *mem_spaces[], H5S_t *file_spaces[], haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */) { @@ -275,7 +275,7 @@ H5F_shared_select_read(H5F_shared_t *f_sh, uint32_t count, H5FD_mem_t type, H5S_ map_type = (type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type; /* Pass down to file driver layer (bypass page buffer for now) */ - if (H5FD_read_selection(f_sh->lf, count, map_type, mem_spaces, file_spaces, offsets, element_sizes, + if (H5FD_read_selection(f_sh->lf, map_type, count, mem_spaces, file_spaces, offsets, element_sizes, bufs) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "selection read through file driver failed") @@ -300,7 +300,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5F_shared_select_write(H5F_shared_t *f_sh, uint32_t count, H5FD_mem_t type, H5S_t *mem_spaces[], +H5F_shared_select_write(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count, H5S_t *mem_spaces[], H5S_t *file_spaces[], haddr_t offsets[], size_t element_sizes[], const void *bufs[]) { H5FD_mem_t map_type; /* Mapped memory type */ @@ -320,7 +320,7 @@ H5F_shared_select_write(H5F_shared_t *f_sh, uint32_t count, H5FD_mem_t type, H5S map_type = (type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type; /* Pass down to file driver layer (bypass page buffer for now) */ - if (H5FD_write_selection(f_sh->lf, count, map_type, mem_spaces, file_spaces, offsets, element_sizes, + if (H5FD_write_selection(f_sh->lf, map_type, count, mem_spaces, file_spaces, offsets, element_sizes, bufs) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "selection write through file driver failed") diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 261ebfe..fe1b72c 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -923,10 +923,10 @@ H5_DLL herr_t H5F_shared_block_write(H5F_shared_t *f_sh, H5FD_mem_t type, haddr_ H5_DLL herr_t H5F_block_write(H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size, const void *buf); /* Functions that operate on selections of elements in the file */ -H5_DLL herr_t H5F_shared_select_read(H5F_shared_t *f_sh, uint32_t count, H5FD_mem_t type, +H5_DLL herr_t H5F_shared_select_read(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count, struct H5S_t *mem_spaces[], struct H5S_t *file_spaces[], haddr_t offsets[], size_t element_sizes[], void *bufs[] /* out */); -H5_DLL herr_t H5F_shared_select_write(H5F_shared_t *f_sh, uint32_t count, H5FD_mem_t type, +H5_DLL herr_t H5F_shared_select_write(H5F_shared_t *f_sh, H5FD_mem_t type, uint32_t count, struct H5S_t *mem_spaces[], struct H5S_t *file_spaces[], haddr_t offsets[], size_t element_sizes[], const void *bufs[]); diff --git a/test/vfd.c b/test/vfd.c index 1703858..217f967 100644 --- a/test/vfd.c +++ b/test/vfd.c @@ -3985,7 +3985,7 @@ test_vector_io(const char *vfd_name) void * f_read_bufs_1[VECTOR_LEN]; /* fixed read bufs vector */ void * f_read_bufs_2[VECTOR_LEN]; /* fixed read bufs vector */ - sprintf(test_title, "vector I/O with %s VFD", vfd_name); + HDsnprintf(test_title, sizeof(test_title), "vector I/O with %s VFD", vfd_name); TESTING(test_title); @@ -3994,14 +3994,14 @@ test_vector_io(const char *vfd_name) if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) TEST_ERROR; - if (strcmp(vfd_name, "sec2") == 0) { + if (HDstrcmp(vfd_name, "sec2") == 0) { if (H5Pset_fapl_sec2(fapl_id) < 0) TEST_ERROR; h5_fixname(FILENAME[0], fapl_id, filename, sizeof(filename)); } - else if (strcmp(vfd_name, "stdio") == 0) { + else if (HDstrcmp(vfd_name, "stdio") == 0) { if (H5Pset_fapl_stdio(fapl_id) < 0) TEST_ERROR; @@ -4353,6 +4353,984 @@ error: } /* end test_vector_io() */ /*------------------------------------------------------------------------- + * Function: test_selection_io_write + * + * Purpose: Updates write buffers to ensure a unique value is written + * to each element and issues a selection write call. + * + * Return: Success: TRUE + * Failure: FALSE + * + * Programmer: Neil Fortner + * 7/1/21 + * + * Changes: None. + * + *------------------------------------------------------------------------- + */ +/* Array dimensions, used for all selection I/O tests. Currently both must be + * even. 1-Dimensional arrays have a size of SEL_IO_DIM0 * SEL_IO_DIM1. */ +#define SEL_IO_DIM0 8 +#define SEL_IO_DIM1 10 + +static hbool_t +test_selection_io_write(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t mem_spaces[], hid_t file_spaces[], + haddr_t offsets[], size_t element_sizes[], int *wbufs[]) +{ + int i; + int j; + hbool_t result = TRUE; + + /* Update write buffer */ + for (i = 0; i < (int)count; i++) + if (wbufs[i] && (i == 0 || wbufs[i] != wbufs[i - 1])) + for (j = 0; j < SEL_IO_DIM0 * SEL_IO_DIM1; j++) + wbufs[i][j] += 2 * SEL_IO_DIM0 * SEL_IO_DIM1; + + /* Issue write call */ + if (H5FDwrite_selection(lf, type, H5P_DEFAULT, count, mem_spaces, file_spaces, offsets, element_sizes, + (const void **)wbufs) < 0) + TEST_ERROR + + return result; + +error: + return FALSE; +} /* end test_selection_io_write() */ + +/*------------------------------------------------------------------------- + * Function: test_selection_io_read_verify + * + * Purpose: Issues a selection read call and compares the result to + * the arrays provided in erbufs. If rbufcount is less than + * count the last element in erbufs will be repeated to make + * up the difference. + * + * Return: Success: TRUE + * Failure: FALSE + * + * Programmer: Neil Fortner + * 7/1/21 + * + * Changes: None. + * + *------------------------------------------------------------------------- + */ +static hbool_t +test_selection_io_read_verify(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t mem_spaces[], + hid_t file_spaces[], haddr_t offsets[], size_t element_sizes[], + uint32_t rbufcount, int *erbufs[], hbool_t shorten_rbufs) +{ + int rbuf1[SEL_IO_DIM0 * SEL_IO_DIM1]; + int rbuf2[SEL_IO_DIM0 * SEL_IO_DIM1]; + int * rbufs[2] = {rbuf1, rbuf2}; + int i; + int j; + hbool_t result = TRUE; + + /* Initialize read buffer */ + for (i = 0; i < (int)rbufcount; i++) + for (j = 0; j < SEL_IO_DIM0 * SEL_IO_DIM1; j++) + rbufs[i][j] = -1; + + /* Handle elements in count that are not part of rbufcount */ + for (i = (int)rbufcount; i < (int)count; i++) + if (shorten_rbufs) + rbufs[i] = NULL; + else + rbufs[i] = rbufs[rbufcount - 1]; + + /* Issue read call */ + if (H5FDread_selection(lf, type, H5P_DEFAULT, count, mem_spaces, file_spaces, offsets, element_sizes, + (void **)rbufs) < 0) + TEST_ERROR + + /* Verify result */ + for (i = 0; i < (int)rbufcount; i++) + for (j = 0; j < SEL_IO_DIM0 * SEL_IO_DIM1; j++) + if (rbufs[i][j] != erbufs[i][j]) { + H5_FAILED() + AT() + printf("data read from file does not match expected values at mapping array location %d\n", + i); + printf("expected data: \n"); + for (j = 0; j < SEL_IO_DIM0 * SEL_IO_DIM1; j++) { + printf("%6d", erbufs[i][j]); + if (!((j + 1) % SEL_IO_DIM1)) + printf("\n"); + } + printf("read data: \n"); + for (j = 0; j < SEL_IO_DIM0 * SEL_IO_DIM1; j++) { + printf("%6d", rbufs[i][j]); + if (!((j + 1) % SEL_IO_DIM1)) + printf("\n"); + } + goto error; + } + + return result; + +error: + return FALSE; +} /* end test_selection_io_read_verify() */ + +/*------------------------------------------------------------------------- + * Function: test_selection_io + * + * Purpose: Test I/O using the selection I/O VFD public VFD calls. + * + * Tests various combinations of 1D, 2D, contiguous, and + * strided selections with different file data types and + * with and without shortened arrays. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Neil Fortner + * 7/1/21 + * + * Changes: None. + * + *------------------------------------------------------------------------- + */ +static herr_t +test_selection_io(const char *vfd_name) +{ + char test_title[80]; + hid_t fapl_id = -1; /* file access property list ID */ + char filename[1024]; /* filename */ + unsigned flags = 0; /* file open flags */ + H5FD_t * lf; /* VFD struct ptr */ + int i; /* index */ + int j; /* index */ + int i2; /* index */ + int j2; /* index */ + hid_t mem_spaces[2] = {H5I_INVALID_HID, H5I_INVALID_HID}; /* memory dataspaces vector */ + hid_t file_spaces[2] = {H5I_INVALID_HID, H5I_INVALID_HID}; /* file dataspaces vecotr */ + hsize_t dims1[1] = {SEL_IO_DIM0 * SEL_IO_DIM1}; /* 1D dataspace dimensions */ + hsize_t dims2[2] = {SEL_IO_DIM0, SEL_IO_DIM1}; /* 1D dataspace dimensions */ + hsize_t start[2]; /* start for hyperslab */ + hsize_t stride[2]; /* stride for hyperslab */ + hsize_t count[2]; /* count for hyperslab */ + hsize_t block[2]; /* block for hyperslab */ + H5FD_mem_t type; /* file data type */ + haddr_t addrs[2]; /* addresses vector */ + size_t element_sizes[2] = {sizeof(int), sizeof(int)}; /* element sizes vector */ + int wbuf1[SEL_IO_DIM0 * SEL_IO_DIM1]; /* 1D write buffer */ + int wbuf2[SEL_IO_DIM0][SEL_IO_DIM1]; /* 2D write buffer */ + int * wbufs[2] = {wbuf1, wbuf2[0]}; /* Array of write buffers */ + int fbuf1[SEL_IO_DIM0 * SEL_IO_DIM1]; /* 1D file buffer */ + int fbuf2[SEL_IO_DIM0][SEL_IO_DIM1]; /* 2D file buffer */ + int * fbufs[2] = {fbuf1, fbuf2[0]}; /* Array of file buffers */ + int erbuf1[SEL_IO_DIM0 * SEL_IO_DIM1]; /* 1D expected read buffer */ + int erbuf2[SEL_IO_DIM0][SEL_IO_DIM1]; /* 2D expected read buffer */ + int * erbufs[2] = {erbuf1, erbuf2[0]}; /* Array of expected read buffers */ + int shorten_element_sizes; /* Whether to shorten the element sizes array */ + + HDsnprintf(test_title, sizeof(test_title), "selection I/O with %s VFD", vfd_name); + + TESTING(test_title); + + /* Set property list and file name for target driver */ + + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR + + if (HDstrcmp(vfd_name, "sec2") == 0) { + + if (H5Pset_fapl_sec2(fapl_id) < 0) + TEST_ERROR + + h5_fixname(FILENAME[0], fapl_id, filename, sizeof(filename)); + } + else if (HDstrcmp(vfd_name, "stdio") == 0) { + + if (H5Pset_fapl_stdio(fapl_id) < 0) + TEST_ERROR + + h5_fixname(FILENAME[7], fapl_id, filename, sizeof filename); + } + else { + + HDfprintf(stdout, "un-supported VFD\n"); + TEST_ERROR + } + + /* Initialize write buffers */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) { + wbuf1[(i * SEL_IO_DIM1) + j] = (i * SEL_IO_DIM1) + j; + wbuf2[i][j] = (i * SEL_IO_DIM1) + j + (SEL_IO_DIM0 * SEL_IO_DIM1); + } + + /* Create dataspaces - location 0 will be 1D and location 1 will be 2D */ + if ((mem_spaces[0] = H5Screate_simple(1, dims1, NULL)) < 0) + TEST_ERROR + if ((mem_spaces[1] = H5Screate_simple(2, dims2, NULL)) < 0) + TEST_ERROR + if ((file_spaces[0] = H5Screate_simple(1, dims1, NULL)) < 0) + TEST_ERROR + if ((file_spaces[1] = H5Screate_simple(2, dims2, NULL)) < 0) + TEST_ERROR + + /* Create file */ + flags = H5F_ACC_RDWR | H5F_ACC_CREAT | H5F_ACC_TRUNC; + + if (NULL == (lf = H5FDopen(filename, flags, fapl_id, HADDR_UNDEF))) + TEST_ERROR; + + /* Loop over memory types */ + for (type = 1; type < H5FD_MEM_NTYPES; type++) { + /* Allocate space for I/O */ + addrs[0] = H5FDalloc(lf, type, H5P_DEFAULT, (hsize_t)(sizeof(int) * SEL_IO_DIM0 * SEL_IO_DIM1)); + addrs[1] = H5FDalloc(lf, type, H5P_DEFAULT, (hsize_t)(sizeof(int) * SEL_IO_DIM0 * SEL_IO_DIM1)); + + /* + * Test 1: Simple 1D contiguous I/O + */ + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], element_sizes, + (int **)&wbufs[0])) + TEST_ERROR + + /* Update file buf */ + for (i = 0; i < SEL_IO_DIM0 * SEL_IO_DIM1; i++) + fbuf1[i] = wbuf1[i]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&fbufs[0], FALSE)) + TEST_ERROR + + /* + * Test 2: Simple 2D contiguous I/O + */ + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], element_sizes, + (int **)&wbufs[1])) + TEST_ERROR + + /* Update file buf */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + fbuf2[i][j] = wbuf2[i][j]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&fbufs[1], FALSE)) + TEST_ERROR + + /* + * Test 3: Strided <> Contiguous 1D I/O + */ + /* SEL_IO_DIM1 must be even */ + HDassert(SEL_IO_DIM1 / 2 == (SEL_IO_DIM1 + 1) / 2); + + /* Strided selection in memory */ + start[0] = 1; + stride[0] = 2; + count[0] = (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; + block[0] = 1; + if (H5Sselect_hyperslab(mem_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Contiguous selection in file */ + if (H5Sselect_hyperslab(file_spaces[0], H5S_SELECT_SET, start, NULL, count, NULL) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], element_sizes, + (int **)&wbufs[0])) + TEST_ERROR + + /* Update file buf */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + fbuf1[i + 1] = wbuf1[(2 * i) + 1]; + + /* Update expected read buf */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1); i++) + erbuf1[i] = -1; + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + erbuf1[(2 * i) + 1] = wbuf1[(2 * i) + 1]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&erbufs[0], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[0]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&fbufs[0], FALSE)) + TEST_ERROR + + /* + * Test 4: Contiguous <> Strided 1D I/O + */ + /* SEL_IO_DIM1 must be even */ + HDassert(SEL_IO_DIM1 / 2 == (SEL_IO_DIM1 + 1) / 2); + + /* Contiguous selection in memory */ + start[0] = 1; + stride[0] = 2; + if (H5Sselect_hyperslab(mem_spaces[0], H5S_SELECT_SET, start, NULL, count, NULL) < 0) + TEST_ERROR + + /* Strided selection in file */ + count[0] = (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; + block[0] = 1; + if (H5Sselect_hyperslab(file_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], element_sizes, + (int **)&wbufs[0])) + TEST_ERROR + + /* Update file buf */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + fbuf1[(2 * i) + 1] = wbuf1[i + 1]; + + /* Update expected read buf */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1); i++) + erbuf1[i] = -1; + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + erbuf1[i + 1] = wbuf1[i + 1]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&erbufs[0], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[0]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&fbufs[0], FALSE)) + TEST_ERROR + + /* + * Test 5: Strided <> Strided 1D I/O + */ + /* SEL_IO_DIM1 must be even */ + HDassert(SEL_IO_DIM1 / 2 == (SEL_IO_DIM1 + 1) / 2); + + /* Strided selection in memory */ + start[0] = 1; + stride[0] = 2; + count[0] = (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; + block[0] = 1; + if (H5Sselect_hyperslab(mem_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection in file */ + start[0] = 0; + if (H5Sselect_hyperslab(file_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], element_sizes, + (int **)&wbufs[0])) + TEST_ERROR + + /* Update file buf */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + fbuf1[2 * i] = wbuf1[(2 * i) + 1]; + + /* Update expected read buf */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1); i++) + erbuf1[i] = -1; + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + erbuf1[(2 * i) + 1] = wbuf1[(2 * i) + 1]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&erbufs[0], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[0]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&fbufs[0], FALSE)) + TEST_ERROR + + /* + * Test 6: Strided <> Contiguous 2D I/O + */ + /* Strided selection in memory */ + start[0] = 1; + start[1] = 0; + stride[0] = 2; + stride[1] = 1; + count[0] = SEL_IO_DIM0 / 2; + count[1] = SEL_IO_DIM1; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(mem_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Contiguous selection in file */ + if (H5Sselect_hyperslab(file_spaces[1], H5S_SELECT_SET, start, NULL, count, NULL) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], element_sizes, + (int **)&wbufs[1])) + TEST_ERROR + + /* Update file buf */ + for (i = 0; i < SEL_IO_DIM0 / 2; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + fbuf2[i + 1][j] = wbuf2[(2 * i) + 1][j]; + + /* Update expected read buf */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = -1; + for (i = 0; i < SEL_IO_DIM0 / 2; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[(2 * i) + 1][j] = wbuf2[(2 * i) + 1][j]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&erbufs[1], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[1]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[1]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&fbufs[1], FALSE)) + TEST_ERROR + + /* + * Test 7: Contiguous <> Strided 2D I/O + */ + /* Contiguous selection in memory */ + start[0] = 0; + start[1] = 1; + count[0] = SEL_IO_DIM0; + count[1] = SEL_IO_DIM1 / 2; + if (H5Sselect_hyperslab(mem_spaces[1], H5S_SELECT_SET, start, NULL, count, NULL) < 0) + TEST_ERROR + + /* Strided selection in file */ + stride[0] = 1; + stride[1] = 2; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(file_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], element_sizes, + (int **)&wbufs[1])) + TEST_ERROR + + /* Update file buf */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1 / 2; j++) + fbuf2[i][(2 * j) + 1] = wbuf2[i][j + 1]; + + /* Update expected read buf */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = -1; + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1 / 2; j++) + erbuf2[i][j + 1] = wbuf2[i][j + 1]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&erbufs[1], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[1]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[1]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&fbufs[1], FALSE)) + TEST_ERROR + + /* + * Test 8: Strided <> Strided 2D I/O + */ + /* SEL_IO_DIM0 and SEL_IO_DIM1 must be even */ + HDassert(SEL_IO_DIM0 / 2 == (SEL_IO_DIM0 + 1) / 2); + HDassert(SEL_IO_DIM1 / 2 == (SEL_IO_DIM1 + 1) / 2); + + /* Strided selection (across dim 1) in memory */ + start[0] = 0; + start[1] = 1; + stride[0] = 1; + stride[1] = 2; + count[0] = SEL_IO_DIM0; + count[1] = SEL_IO_DIM1 / 2; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(mem_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection (across dim 0) in file */ + start[0] = 1; + start[1] = 0; + stride[0] = 2; + stride[1] = 1; + count[0] = SEL_IO_DIM0 / 2; + count[1] = SEL_IO_DIM1; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(file_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], element_sizes, + (int **)&wbufs[1])) + TEST_ERROR + + /* Update file buf */ + for (i = 0, i2 = 1, j2 = 0; i < SEL_IO_DIM0; i++) + for (j = 1; j < SEL_IO_DIM1; j += 2) { + fbuf2[i2][j2] = wbuf2[i][j]; + if (++j2 == SEL_IO_DIM1) { + i2 += 2; + j2 = 0; + } + } + + /* Update expected read buf */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = -1; + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 1; j < SEL_IO_DIM1; j += 2) + erbuf2[i][j] = wbuf2[i][j]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&erbufs[1], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[1]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[1]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&fbufs[1], FALSE)) + TEST_ERROR + + /* + * Test 9: Strided 1D <> Strided 2D I/O + */ + /* Strided selection in memory */ + start[0] = 1; + stride[0] = 2; + count[0] = (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; + block[0] = 1; + if (H5Sselect_hyperslab(mem_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection (across dim 1) in file */ + start[0] = 0; + start[1] = 1; + stride[0] = 1; + stride[1] = 2; + count[0] = SEL_IO_DIM0; + count[1] = SEL_IO_DIM1 / 2; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(file_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[0], &file_spaces[1], &addrs[1], element_sizes, + (int **)&wbufs[0])) + TEST_ERROR + + /* Update file buf */ + for (i = 1, i2 = 0, j2 = 1; i < (SEL_IO_DIM0 * SEL_IO_DIM1); i += 2) { + fbuf2[i2][j2] = wbuf1[i]; + j2 += 2; + if (j2 == SEL_IO_DIM1) { + i2++; + j2 = 1; + } + } + + /* Update expected read buf */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1); i++) + erbuf1[i] = -1; + for (i = 1; i < (SEL_IO_DIM0 * SEL_IO_DIM1); i += 2) + erbuf1[i] = wbuf1[i]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&erbufs[0], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[1]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[0], &file_spaces[1], &addrs[1], + element_sizes, 1, (int **)&fbufs[1], FALSE)) + TEST_ERROR + + /* + * Test 10: Strided 2D <> Strided 1D I/O + */ + /* Strided selection (across dim 0) in memory */ + start[0] = 0; + start[1] = 0; + stride[0] = 2; + stride[1] = 1; + count[0] = SEL_IO_DIM0 / 2; + count[1] = SEL_IO_DIM1; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(mem_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection in file */ + start[0] = 0; + stride[0] = 2; + count[0] = (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; + block[0] = 1; + if (H5Sselect_hyperslab(file_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 1, &mem_spaces[1], &file_spaces[0], &addrs[0], element_sizes, + (int **)&wbufs[1])) + TEST_ERROR + + /* Update file buf */ + for (i = 0, i2 = 0; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) { + fbuf1[i2] = wbuf2[i][j]; + i2 += 2; + } + + /* Update expected read buf */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = -1; + for (i = 0; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = wbuf2[i][j]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&erbufs[1], FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[1]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[0]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 1, &mem_spaces[1], &file_spaces[0], &addrs[0], + element_sizes, 1, (int **)&fbufs[0], FALSE)) + TEST_ERROR + + /* Run tests with full and partial element sizes array */ + for (shorten_element_sizes = 0; shorten_element_sizes <= 1; shorten_element_sizes++) { + /* + * Test 11: Strided <> Strided 1D and 2D I/O + */ + /* SEL_IO_DIM1 must be even */ + HDassert(SEL_IO_DIM1 / 2 == (SEL_IO_DIM1 + 1) / 2); + + /* Strided selection in memory (1D) */ + start[0] = 0; + stride[0] = 2; + count[0] = (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; + block[0] = 1; + if (H5Sselect_hyperslab(mem_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection in file (1D) */ + start[0] = 1; + if (H5Sselect_hyperslab(file_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection (across dim 0) in memory (2D) */ + start[0] = 1; + start[1] = 0; + stride[0] = 2; + stride[1] = 1; + count[0] = SEL_IO_DIM0 / 2; + count[1] = SEL_IO_DIM1; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(mem_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection (across dim 1) in file (2D) */ + start[0] = 0; + start[1] = 1; + stride[0] = 1; + stride[1] = 2; + count[0] = SEL_IO_DIM0; + count[1] = SEL_IO_DIM1 / 2; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(file_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 2, mem_spaces, file_spaces, addrs, element_sizes, + (int **)wbufs)) + TEST_ERROR + + /* Update file bufs */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + fbuf1[(2 * i) + 1] = wbuf1[2 * i]; + for (i = 1, i2 = 0, j2 = 1; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) { + fbuf2[i2][j2] = wbuf2[i][j]; + j2 += 2; + if (j2 >= SEL_IO_DIM1) { + i2++; + j2 = 1; + } + } + + /* Update expected read bufs */ + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1); i++) + erbuf1[i] = -1; + for (i = 0; i < (SEL_IO_DIM0 * SEL_IO_DIM1) / 2; i++) + erbuf1[2 * i] = wbuf1[2 * i]; + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = -1; + for (i = 1; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = wbuf2[i][j]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 2, mem_spaces, file_spaces, addrs, element_sizes, 2, + (int **)erbufs, FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(mem_spaces[1]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[1]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 2, mem_spaces, file_spaces, addrs, element_sizes, 2, + (int **)fbufs, FALSE)) + TEST_ERROR + + /* + * Test 12: Strided <> Strided 2D I/O, 2 different selections in the same memory buffer + */ + /* Switch mem and file spaces to both be 2D */ + if (H5Sset_extent_simple(mem_spaces[0], 2, dims2, NULL) < 0) + TEST_ERROR + if (H5Sset_extent_simple(file_spaces[0], 2, dims2, NULL) < 0) + TEST_ERROR + + /* Strided selection in memory (1st) */ + start[0] = 0; + start[1] = 0; + stride[0] = 2; + stride[1] = 1; + count[0] = SEL_IO_DIM0 / 2; + count[1] = SEL_IO_DIM1; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(mem_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection (across dim 0) in memory (2nd) */ + start[0] = 1; + if (H5Sselect_hyperslab(mem_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection in file (1st) */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 2; + count[0] = SEL_IO_DIM0; + count[1] = SEL_IO_DIM1 / 2; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(file_spaces[0], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Strided selection (across dim 1) in file (2nd) */ + start[0] = 0; + start[1] = 1; + stride[0] = 1; + stride[1] = 2; + count[0] = SEL_IO_DIM0; + count[1] = SEL_IO_DIM1 / 2; + block[0] = 1; + block[1] = 1; + if (H5Sselect_hyperslab(file_spaces[1], H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR + + /* Use the same memory buffer for both selections */ + wbufs[0] = wbuf2[0]; + + /* Shorten wbuf array */ + if (shorten_element_sizes) + wbufs[1] = NULL; + else + wbufs[1] = wbufs[0]; + + /* Issue write call */ + if (!test_selection_io_write(lf, type, 2, mem_spaces, file_spaces, addrs, element_sizes, + (int **)wbufs)) + TEST_ERROR + + /* Update file bufs - need to reuse 1D array so data stays consistent, so use math to + * find 1D index into 2D array */ + for (i = 0, i2 = 0, j2 = 0; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) { + fbuf1[(i2 * SEL_IO_DIM1) + j2] = wbuf2[i][j]; + j2 += 2; + if (j2 >= SEL_IO_DIM1) { + i2++; + j2 = 0; + } + } + for (i = 1, i2 = 0, j2 = 1; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) { + fbuf2[i2][j2] = wbuf2[i][j]; + j2 += 2; + if (j2 >= SEL_IO_DIM1) { + i2++; + j2 = 1; + } + } + + /* Update expected read buf */ + for (i = 0; i < SEL_IO_DIM0; i++) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = -1; + for (i = 0; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = wbuf2[i][j]; + for (i = 1; i < SEL_IO_DIM0; i += 2) + for (j = 0; j < SEL_IO_DIM1; j++) + erbuf2[i][j] = wbuf2[i][j]; + + /* Read and verify */ + if (!test_selection_io_read_verify(lf, type, 2, mem_spaces, file_spaces, addrs, element_sizes, 1, + (int **)&erbufs[1], shorten_element_sizes ? TRUE : FALSE)) + TEST_ERROR + + /* Reset selections */ + if (H5Sselect_all(mem_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[0]) < 0) + TEST_ERROR + if (H5Sselect_all(mem_spaces[1]) < 0) + TEST_ERROR + if (H5Sselect_all(file_spaces[1]) < 0) + TEST_ERROR + + /* Read entire file buffer and verify */ + if (!test_selection_io_read_verify(lf, type, 2, mem_spaces, file_spaces, addrs, element_sizes, 2, + (int **)fbufs, FALSE)) + TEST_ERROR + + /* Reset first spaces to 1D */ + if (H5Sset_extent_simple(mem_spaces[0], 1, dims1, NULL) < 0) + TEST_ERROR + if (H5Sset_extent_simple(file_spaces[0], 1, dims1, NULL) < 0) + TEST_ERROR + + /* Reset write buffer array */ + wbufs[0] = wbuf1; + wbufs[1] = wbuf2[0]; + + /* Change to shortened element sizes array */ + element_sizes[1] = 0; + } + + /* Reset element sizes array */ + element_sizes[1] = element_sizes[0]; + } + + /* + * Cleanup + */ + /* Close file */ + if (H5FDclose(lf) < 0) + TEST_ERROR; + + h5_delete_test_file(FILENAME[0], fapl_id); + + /* Close the fapl */ + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + + /* Close dataspaces */ + for (i = 0; i < 2; i++) { + if (H5Sclose(mem_spaces[i]) < 0) + TEST_ERROR + if (H5Sclose(file_spaces[i]) < 0) + TEST_ERROR + } + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(fapl_id); + H5FDclose(lf); + for (i = 0; i < 2; i++) { + H5Sclose(mem_spaces[i]); + H5Sclose(file_spaces[i]); + } + } + H5E_END_TRY; + return -1; +} /* end test_selection_io() */ + +/*------------------------------------------------------------------------- * Function: main * * Purpose: Tests the basic features of Virtual File Drivers @@ -4387,6 +5365,8 @@ main(void) nerrors += test_splitter() < 0 ? 1 : 0; nerrors += test_vector_io("sec2") < 0 ? 1 : 0; nerrors += test_vector_io("stdio") < 0 ? 1 : 0; + nerrors += test_selection_io("sec2") < 0 ? 1 : 0; + nerrors += test_selection_io("stdio") < 0 ? 1 : 0; if (nerrors) { HDprintf("***** %d Virtual File Driver TEST%s FAILED! *****\n", nerrors, nerrors > 1 ? "S" : ""); -- cgit v0.12