diff options
author | Mark Kittisopikul <mkitti@users.noreply.github.com> | 2023-02-21 14:31:03 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-21 14:31:03 (GMT) |
commit | a56f29c3c6bc4708ef775784798b9674752c2260 (patch) | |
tree | 14a707cc2ba69591319c2ce8f70a71ee71bf4953 | |
parent | add3ff0fec99b7021211fdfd050db1d58b6358a3 (diff) | |
download | hdf5-a56f29c3c6bc4708ef775784798b9674752c2260.zip hdf5-a56f29c3c6bc4708ef775784798b9674752c2260.tar.gz hdf5-a56f29c3c6bc4708ef775784798b9674752c2260.tar.bz2 |
Backport H5Dchunk_iter to 1.10 branch (#1968)
* Backport H5Dchunk_iter to 1.10 branch
* Add some accessory files, test still needs work
* Apply proper formatting, and fix compile errors
* Remove const from H5D__chunk_iter as per #1700
* Align arg types of H5D_chunk_iter_op_t with H5Dget_chunk_info (#2074)
* Align arg types of H5D_chunk_iter_op_t with H5Dget_chunk_info
* Modify chunk_info test to for unsigned / hsize_t types
* Fix types in test
* Add test_basic_query, helper functions to test/chunk_info.c 1_10
* H5Dchunk_iter now passes offsets in units of dataset elements, fix #1419 (#1969)
* H5Dchunk_iter now passes chunk dimension scaled offsets, fix #1419
* Update docs for H5Dchunk_iter, H5Dget_chunk_info*
Modified description for `H5Dchunk_iter`, `H5Dget_chunk_info`, and `H5Dget_chunk_info_by_coord` to the following
* offset Logical position of the chunk’s first element in units of dataset elements
* filter_mask Bitmask indicating the filters used when the chunk was written
* size Chunk size in bytes, 0 if the chunk does not exist
* Fix regression of #1419
* Add a note about return fail in 1.12 and older for invalid chunk index
* Committing clang-format changes
* Run clang-format on test/chunk_info.c
---------
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
-rwxr-xr-x | bin/trace | 1 | ||||
-rw-r--r-- | src/H5D.c | 80 | ||||
-rw-r--r-- | src/H5Dchunk.c | 110 | ||||
-rw-r--r-- | src/H5Dpkg.h | 1 | ||||
-rw-r--r-- | src/H5Dpublic.h | 49 | ||||
-rw-r--r-- | test/chunk_info.c | 419 |
6 files changed, 659 insertions, 1 deletions
@@ -44,6 +44,7 @@ $Source = ""; "H5D_vds_view_t" => "Dv", "H5FD_mpio_xfer_t" => "Dt", "H5FD_splitter_vfd_config_t" => "Dr", + "H5D_chunk_iter_op_t" => "x", "herr_t" => "e", "H5E_direction_t" => "Ed", "H5E_error_t" => "Ee", @@ -1230,3 +1230,83 @@ H5Dget_chunk_info_by_coord(hid_t dset_id, const hsize_t *offset, unsigned *filte done: FUNC_LEAVE_API(ret_value) } /* end H5Dget_chunk_info_by_coord() */ + +/*------------------------------------------------------------------------- + * Function: H5Dchunk_iter + * + * Purpose: Iterates over all chunks in dataset with given callback and user data. + * + * Parameters: + * hid_t dset_id; IN: Chunked dataset ID + * hid_t dxpl_id; IN: Dataset transfer property list ID + * H5D_chunk_iter_op_t cb IN: User callback function, called for every chunk. + * void *op_data IN/OUT: Optional user data passed on to user callback. + * + * Callback information: + * H5D_chunk_iter_op_t is defined as: + * + * typedef int (*H5D_chunk_iter_op_t)( + * const hsize_t *offset, + * unsigned filter_mask, + * haddr_t addr, + * hsize_t size, + * void *op_data); + * + * H5D_chunk_iter_op_t parameters: + * hsize_t *offset; IN/OUT: Logical position of the chunk’s first element in units of dataset + * elements + * unsigned filter_mask; IN: Bitmask indicating the filters used when the chunk was written haddr_t + * addr; IN: Chunk address in the file + * hsize_t; IN: Chunk size in bytes, 0 if the chunk does not exist + * void *op_data; IN/OUT: Pointer to any user-defined data associated with the operation. + * + * The return values from an operator are: + * Zero (H5_ITER_CONT) causes the iterator to continue, returning zero when all + * elements have been processed. + * Positive (H5_ITER_STOP) causes the iterator to immediately return that positive + * value, indicating short-circuit success. + * Negative (H5_ITER_ERROR) causes the iterator to immediately return that value, + * indicating failure. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Gaute Hope + * August 2020 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dchunk_iter(hid_t dset_id, hid_t dxpl_id, H5D_chunk_iter_op_t op, void *op_data) +{ + H5D_t *dset = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE4("e", "iix*x", dset_id, dxpl_id, op, op_data); + + /* Check arguments */ + if (NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier") + if (NULL == op) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid callback to chunk iteration") + + /* 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, "dxpl_id is not a dataset transfer property list ID") + + /* Sanity check */ + HDassert(dset->shared); + + /* Make sure the dataset is chunked */ + if (H5D_CHUNKED != dset->shared->layout.type) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a chunked dataset") + + /* Call private function */ + if ((ret_value = H5D__chunk_iter(dset, op, op_data)) < 0) + HERROR(H5E_DATASET, H5E_BADITER, "error iterating over dataset chunks"); + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Dchunk_iter() */
\ No newline at end of file diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index e9ca0fc..93d68b6 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -248,6 +248,12 @@ typedef struct H5D_chunk_coll_fill_info_t { } H5D_chunk_coll_fill_info_t; #endif /* H5_HAVE_PARALLEL */ +typedef struct H5D_chunk_iter_ud_t { + H5D_chunk_iter_op_t op; /* User defined callback */ + void *op_data; /* User data for user defined callback */ + H5O_layout_chunk_t *chunk; /* Chunk layout */ +} H5D_chunk_iter_ud_t; + /********************/ /* Local Prototypes */ /********************/ @@ -271,6 +277,7 @@ static herr_t H5D__chunk_dest(H5D_t *dset); static int H5D__get_num_chunks_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata); static int H5D__get_chunk_info_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata); static int H5D__get_chunk_info_by_coord_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata); +static int H5D__chunk_iter_cb(const H5D_chunk_rec_t *chunk_rec, void *udata); /* "Nonexistent" layout operation callback */ static ssize_t H5D__nonexistent_readvv(const H5D_io_info_t *io_info, size_t chunk_max_nseq, @@ -7655,3 +7662,106 @@ H5D__get_chunk_info_by_coord(const H5D_t *dset, const hsize_t *offset, unsigned done: FUNC_LEAVE_NOAPI_TAG(ret_value) } /* end H5D__get_chunk_info_by_coord() */ + +/*------------------------------------------------------------------------- + * Function: H5D__chunk_iter_cb + * + * Purpose: Call the user-defined function with the chunk data. The iterator continues if + * the user-defined function returns H5_ITER_CONT, and stops if H5_ITER_STOP is + * returned. + * + * Return: Success: H5_ITER_CONT or H5_ITER_STOP + * Failure: Negative (H5_ITER_ERROR) + * + * Programmer: Gaute Hope + * August 2020 + * + *------------------------------------------------------------------------- + */ +static int +H5D__chunk_iter_cb(const H5D_chunk_rec_t *chunk_rec, void *udata) +{ + const H5D_chunk_iter_ud_t *data = (H5D_chunk_iter_ud_t *)udata; + const H5O_layout_chunk_t *chunk = data->chunk; + int ret_value = H5_ITER_CONT; + hsize_t offset[H5O_LAYOUT_NDIMS]; + unsigned ii; /* Match H5O_layout_chunk_t.ndims */ + + /* Similar to H5D__get_chunk_info */ + for (ii = 0; ii < chunk->ndims; ii++) + offset[ii] = chunk_rec->scaled[ii] * chunk->dim[ii]; + + FUNC_ENTER_PACKAGE_NOERR + + /* Check for callback failure and pass along return value */ + if ((ret_value = (data->op)(offset, (unsigned)chunk_rec->filter_mask, chunk_rec->chunk_addr, + (hsize_t)chunk_rec->nbytes, data->op_data)) < 0) + HERROR(H5E_DATASET, H5E_CANTNEXT, "iteration operator failed"); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__chunk_iter_cb */ + +/*------------------------------------------------------------------------- + * Function: H5D__chunk_iter + * + * Purpose: Iterate over all the chunks in the dataset with given callback. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Gaute Hope + * August 2020 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D__chunk_iter(H5D_t *dset, H5D_chunk_iter_op_t op, void *op_data) +{ + const H5D_rdcc_t *rdcc = NULL; /* Raw data chunk cache */ + H5O_layout_t *layout = NULL; /* Dataset layout */ + H5D_rdcc_ent_t *ent; /* Cache entry index */ + H5D_chk_idx_info_t idx_info; /* Chunked index info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr) + + /* Check args */ + HDassert(dset); + HDassert(dset->shared); + + /* Get dataset layout and raw data chunk cache */ + layout = &(dset->shared->layout); + rdcc = &(dset->shared->cache.chunk); + HDassert(layout); + HDassert(rdcc); + HDassert(H5D_CHUNKED == layout->type); + + /* Search for cached chunks that haven't been written out */ + for (ent = rdcc->head; ent; ent = ent->next) + /* Flush the chunk out to disk, to make certain the size is correct later */ + if (H5D__chunk_flush_entry(dset, ent, FALSE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "cannot flush indexed storage buffer") + + /* Compose chunked index info struct */ + idx_info.f = dset->oloc.file; + idx_info.pline = &dset->shared->dcpl_cache.pline; + idx_info.layout = &layout->u.chunk; + idx_info.storage = &layout->storage.u.chunk; + + /* If the dataset is not written, return without errors */ + if (H5F_addr_defined(idx_info.storage->idx_addr)) { + H5D_chunk_iter_ud_t ud; + + /* Set up info for iteration callback */ + ud.op = op; + ud.op_data = op_data; + ud.chunk = &dset->shared->layout.u.chunk; + + /* Iterate over the allocated chunks calling the iterator callback */ + if ((ret_value = (layout->storage.u.chunk.ops->iterate)(&idx_info, H5D__chunk_iter_cb, &ud)) < 0) + HERROR(H5E_DATASET, H5E_CANTNEXT, "chunk iteration failed"); + } /* end if H5F_addr_defined */ + +done: + FUNC_LEAVE_NOAPI_TAG(ret_value) +} /* end H5D__chunk_iter() */ diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index b56341d..31e5356 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -571,6 +571,7 @@ H5_DLL herr_t H5D__get_chunk_info(const H5D_t *dset, const H5S_t *space, hsize_ unsigned *filter_mask, haddr_t *offset, hsize_t *size); H5_DLL herr_t H5D__get_chunk_info_by_coord(const H5D_t *dset, const hsize_t *coord, unsigned *filter_mask, haddr_t *addr, hsize_t *size); +H5_DLL herr_t H5D__chunk_iter(H5D_t *dset, H5D_chunk_iter_op_t cb, void *op_data); H5_DLL haddr_t H5D__get_offset(const H5D_t *dset); H5_DLL void *H5D__vlen_get_buf_size_alloc(size_t size, void *info); H5_DLL herr_t H5D__vlen_get_buf_size(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h index 79ae4a3..cfa5e9e 100644 --- a/src/H5Dpublic.h +++ b/src/H5Dpublic.h @@ -222,6 +222,27 @@ typedef herr_t (*H5D_scatter_func_t)(const void **src_buf /*out*/, size_t *src_b typedef herr_t (*H5D_gather_func_t)(const void *dst_buf, size_t dst_buf_bytes_used, void *op_data); //! <!-- [H5D_gather_func_t_snip] --> +//! <!-- [H5D_chunk_iter_op_t_snip] --> +/** + * \brief Callback for H5Dchunk_iter() + * + * \param[in] offset Logical position of the chunk’s first element in units of dataset elements + * \param[in] filter_mask Bitmask indicating the filters used when the chunk was written + * \param[in] addr Chunk address in the file + * \param[in] size Chunk size in bytes, 0 if the chunk does not exist + * \param[in,out] op_data Pointer to any user-defined data associated with + * the operation. + * \returns \li Zero (#H5_ITER_CONT) causes the iterator to continue, returning + * zero when all elements have been processed. + * \li A positive value (#H5_ITER_STOP) causes the iterator to + * immediately return that value, indicating short-circuit success. + * \li A negative (#H5_ITER_ERROR) causes the iterator to immediately + * return that value, indicating failure. + */ +typedef int (*H5D_chunk_iter_op_t)(const hsize_t *offset, unsigned filter_mask, haddr_t addr, hsize_t size, + void *op_data); +//! <!-- [H5D_chunk_iter_op_t_snip] --> + /********************/ /* Public Variables */ /********************/ @@ -617,6 +638,34 @@ H5_DLL herr_t H5Dget_chunk_info_by_coord(hid_t dset_id, const hsize_t *offset, u * -------------------------------------------------------------------------- * \ingroup H5D * + * \brief Iterate over all chunks of a chunked dataset + * + * \dset_id + * \param[in] dxpl_id Identifier of a transfer property list + * \param[in] cb User callback function, called for every chunk. + * \param[in] op_data User-defined pointer to data required by op + * + * \return \herr_t + * + * \details H5Dchunk_iter iterates over all chunks in the dataset, calling the + * user supplied callback with the details of the chunk and the supplied + * context \p op_data. + * + * \par Example + * For each chunk, print the allocated chunk size (0 for un-allocated chunks). + * \snippet H5D_examples.c H5Dchunk_iter_cb + * Iterate over all chunked datasets and chunks in a file. + * \snippet H5D_examples.c H5Ovisit_cb + * + * \since 1.10.9, 1.13.0 + * + */ +H5_DLL herr_t H5Dchunk_iter(hid_t dset_id, hid_t dxpl_id, H5D_chunk_iter_op_t cb, void *op_data); + +/** + * -------------------------------------------------------------------------- + * \ingroup H5D + * * \brief Retrieves information about a chunk specified by its index * * \dset_id diff --git a/test/chunk_info.c b/test/chunk_info.c index 10661c6..2219706 100644 --- a/test/chunk_info.c +++ b/test/chunk_info.c @@ -19,6 +19,7 @@ * * Test structure: * main() + * test_basic_query() * test_get_chunk_info_highest18() * test_get_chunk_info_110() * test_chunk_info_single_chunk() @@ -26,6 +27,10 @@ * test_chunk_info_fixed_array() * test_chunk_info_extensible_array() * test_chunk_info_version2_btrees() + * Helper functions: + * verify_get_chunk_info() + * verify_get_chunk_info_by_coord() + * verify_empty_chunk_info() * */ #define H5D_FRIEND @@ -40,6 +45,8 @@ const char *FILENAME[] = {"tchunk_info_18", "tchunk_info_110", "chunk_info", NUL /* From original test */ #define DATASETNAME "2d" +#define BASIC_FILE "basic_query" + /* Parameters for testing chunk querying */ #define RANK 2 #define FILENAME_BUF_SIZE 1024 @@ -57,8 +64,19 @@ const char *FILENAME[] = {"tchunk_info_18", "tchunk_info_110", "chunk_info", NUL #define CHUNK_NY 4 #define SINGLE_CHUNK_SIZE (NX * NY * sizeof(int)) #define CHUNK_SIZE 96 +#define EMPTY_CHK_SIZE 0 #define NUM_CHUNKS 16 -#define NUM_CHUNKS_WRITTEN 4 + +/* Number of chunks that have been written */ +#define NUM_CHUNKS_WRITTEN 4 +#define ONE_CHUNK_WRITTEN 1 +#define TWO_CHUNKS_WRITTEN 2 +#define NO_CHUNK_WRITTEN 0 + +/* For testing invalid arguments */ +#define NONEXIST_CHK_INDEX 3 +#define OUTOFRANGE_CHK_INDEX 5 +#define INVALID_CHK_INDEX 5 /* Artifact of original file, maybe removed */ /* #define PRINT_DATA */ @@ -66,6 +84,14 @@ const char *FILENAME[] = {"tchunk_info_18", "tchunk_info_110", "chunk_info", NUL /* Utility function to initialize arguments */ void reinit_vars(unsigned *read_flt_msk, haddr_t *addr, hsize_t *size); +/* Helper function containing common code that verifies indexing type + and number of chunks */ +static int verify_get_chunk_info(hid_t dset, hid_t dspace, hsize_t chk_index, hsize_t exp_chk_size, + const hsize_t *exp_offset, unsigned exp_flt_msk); +static int verify_get_chunk_info_by_coord(hid_t dset, hsize_t *offset, hsize_t exp_chk_size, + unsigned exp_flt_msk); +static int verify_empty_chunk_info(hid_t dset, hsize_t *offset); + /*------------------------------------------------------------------------- * Function: read_each_chunk (helper function) * @@ -131,6 +157,120 @@ reinit_vars(unsigned *read_flt_msk, haddr_t *addr, hsize_t *size) } /*------------------------------------------------------------------------- + * Function: verify_get_chunk_info (helper function) + * + * Purpose: Verifies that H5Dget_chunk_info returns correct + * values for a chunk. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Date: August 2019 + * + *------------------------------------------------------------------------- + */ +static int +verify_get_chunk_info(hid_t dset, hid_t dspace, hsize_t chk_index, hsize_t exp_chk_size, + const hsize_t *exp_offset, unsigned exp_flt_msk) +{ + unsigned read_flt_msk = 0; /* Read filter mask */ + hsize_t out_offset[2] = {0, 0}; /* Buffer to get offset coordinates */ + hsize_t size = 0; /* Size of an allocated/written chunk */ + haddr_t addr = 0; /* Address of an allocated/written chunk */ + + if (H5Dget_chunk_info(dset, dspace, chk_index, out_offset, &read_flt_msk, &addr, &size) < 0) + TEST_ERROR; + + if (HADDR_UNDEF == addr) + FAIL_PUTS_ERROR("address cannot be HADDR_UNDEF"); + if (size != exp_chk_size) + FAIL_PUTS_ERROR("unexpected chunk size"); + if (read_flt_msk != exp_flt_msk) + FAIL_PUTS_ERROR("unexpected filter mask"); + if (out_offset[0] != exp_offset[0]) + FAIL_PUTS_ERROR("unexpected offset[0]"); + if (out_offset[1] != exp_offset[1]) + FAIL_PUTS_ERROR("unexpected offset[1]"); + + return SUCCEED; + +error: + return FAIL; +} + +/*------------------------------------------------------------------------- + * Function: verify_get_chunk_info_by_coord (helper function) + * + * Purpose: Verifies that H5Dget_chunk_info_by_coord returns correct + * values for a chunk. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Date: August 2019 + * + *------------------------------------------------------------------------- + */ +static int +verify_get_chunk_info_by_coord(hid_t dset, hsize_t *offset, hsize_t exp_chk_size, unsigned exp_flt_msk) +{ + unsigned read_flt_msk = 0; /* Read filter mask */ + hsize_t size = 0; /* Size of an allocated/written chunk */ + haddr_t addr = 0; /* Address of an allocated/written chunk */ + + /* Get info of the chunk at logical coordinates specified by offset */ + if (H5Dget_chunk_info_by_coord(dset, offset, &read_flt_msk, &addr, &size) < 0) + TEST_ERROR; + + if (HADDR_UNDEF == addr) + FAIL_PUTS_ERROR("address cannot be HADDR_UNDEF"); + if (size != exp_chk_size) + FAIL_PUTS_ERROR("unexpected chunk size"); + if (read_flt_msk != exp_flt_msk) + FAIL_PUTS_ERROR("unexpected filter mask"); + + return SUCCEED; + +error: + return FAIL; +} + +/*------------------------------------------------------------------------- + * Function: verify_empty_chunk_info (helper function) + * + * Purpose: Verifies that H5Dget_chunk_info_by_coord returns correct + * values for an empty chunk. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Date: August 2018 + * + *------------------------------------------------------------------------- + */ +static int +verify_empty_chunk_info(hid_t dset, hsize_t *offset) +{ + unsigned read_flt_msk = 0; /* Read filter mask */ + hsize_t size = 0; /* Size of an allocated/written chunk */ + haddr_t addr = 0; /* Address of an allocated/written chunk */ + + /* Get info of the chunk at logical coordinates specified by offset */ + if (H5Dget_chunk_info_by_coord(dset, offset, &read_flt_msk, &addr, &size) < 0) + TEST_ERROR; + + if (HADDR_UNDEF != addr) + FAIL_PUTS_ERROR("address was not HADDR_UNDEF"); + if (EMPTY_CHK_SIZE != size) + FAIL_PUTS_ERROR("size was not EMPTY_CHK_SIZE"); + + return SUCCEED; + +error: + return FAIL; +} + +/*------------------------------------------------------------------------- * Function: test_get_chunk_info_highest18 * * Purpose: Test getting various chunk information @@ -1666,6 +1806,280 @@ error: return FAIL; } /* test_chunk_info_version2_btrees() */ +typedef struct chunk_iter_info_t { + hsize_t offset[2]; + unsigned filter_mask; + haddr_t addr; + hsize_t size; +} chunk_iter_info_t; + +typedef struct chunk_iter_udata_t { + chunk_iter_info_t *chunk_info; + int last_index; +} chunk_iter_udata_t; + +static int +iter_cb(const hsize_t *offset, unsigned filter_mask, haddr_t addr, hsize_t size, void *op_data) +{ + chunk_iter_udata_t *cidata = (chunk_iter_udata_t *)op_data; + int idx = cidata->last_index + 1; + + cidata->chunk_info[idx].offset[0] = offset[0]; + cidata->chunk_info[idx].offset[1] = offset[1]; + cidata->chunk_info[idx].filter_mask = filter_mask; + cidata->chunk_info[idx].addr = addr; + cidata->chunk_info[idx].size = size; + + cidata->last_index++; + + return H5_ITER_CONT; +} + +static int +iter_cb_stop(const hsize_t H5_ATTR_UNUSED *offset, unsigned H5_ATTR_UNUSED filter_mask, + haddr_t H5_ATTR_UNUSED addr, hsize_t H5_ATTR_UNUSED size, void *op_data) +{ + chunk_iter_info_t **chunk_info = (chunk_iter_info_t **)op_data; + *chunk_info += 1; + return H5_ITER_STOP; +} + +static int +iter_cb_fail(const hsize_t H5_ATTR_UNUSED *offset, unsigned H5_ATTR_UNUSED filter_mask, + haddr_t H5_ATTR_UNUSED addr, hsize_t H5_ATTR_UNUSED size, void *op_data) +{ + chunk_iter_info_t **chunk_info = (chunk_iter_info_t **)op_data; + *chunk_info += 1; + return H5_ITER_ERROR; +} + +/*------------------------------------------------------------------------- + * Function: test_basic_query + * + * Purpose: Tests basic operations to ensure the chunk query functions + * work properly. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Note: Note that the dataspace argument in these new functions are + * currently not used. The functionality involved the dataspace + * will be implemented in the next version. + * + * Date: August 2019 + * + *------------------------------------------------------------------------- + */ +static herr_t +test_basic_query(hid_t fapl) +{ + char filename[FILENAME_BUF_SIZE]; /* File name */ + hid_t basicfile = H5I_INVALID_HID; /* File ID */ + hid_t dspace = H5I_INVALID_HID; /* Dataspace ID */ + hid_t dset = H5I_INVALID_HID; /* Dataset ID */ + hid_t cparms = H5I_INVALID_HID; /* Creation plist */ + hsize_t dims[2] = {NX, NY}; /* Dataset dimensions */ + hsize_t chunk_dims[2] = {CHUNK_NX, CHUNK_NY}; /* Chunk dimensions */ + int direct_buf[CHUNK_NX][CHUNK_NY]; /* Data in chunks */ + unsigned flt_msk = 0; /* Filter mask */ + unsigned read_flt_msk = 0; /* Filter mask after direct read */ + hsize_t offset[2]; /* Offset coordinates of a chunk */ + hsize_t out_offset[2] = {0, 0}; /* Buffer to get offset coordinates */ + hsize_t size = 0; /* Size of an allocated/written chunk */ + hsize_t nchunks = 0; /* Number of chunks */ + haddr_t addr = 0; /* Address of an allocated/written chunk */ + hsize_t chk_index = 0; /* Index of a chunk */ + hsize_t ii, jj; /* Array indices */ + chunk_iter_info_t chunk_infos[2]; /* Chunk infos filled up by iterator */ + chunk_iter_info_t *cptr; /* Pointer to array of chunks */ + chunk_iter_udata_t udata; /* udata for iteration */ + herr_t ret; /* Temporary returned value for verifying failure */ + + TESTING("basic operations"); + + /* Create the file */ + h5_fixname(BASIC_FILE, fapl, filename, sizeof filename); + + /* Create a new file. */ + if ((basicfile = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((dspace = H5Screate_simple(RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Enable chunking */ + if ((cparms = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(cparms, RANK, chunk_dims) < 0) + TEST_ERROR; + + /* Create a new dataset using cparms creation properties */ + dset = + H5Dcreate2(basicfile, DSET_SIMPLE_CHUNKED, H5T_NATIVE_INT, dspace, H5P_DEFAULT, cparms, H5P_DEFAULT); + if (dset < 0) + TEST_ERROR; + + /* Get the number of chunks and verify that no chunk has been written */ + if (H5Dget_num_chunks(dset, dspace, &nchunks) < 0) + TEST_ERROR; + if (NO_CHUNK_WRITTEN != nchunks) + FAIL_PUTS_ERROR("unexpected number of chunks"); + + /* Initialize the array of chunk data for the single chunk */ + for (ii = 0; ii < CHUNK_NX; ii++) + for (jj = 0; jj < CHUNK_NY; jj++) + direct_buf[ii][jj] = (int)(ii * jj); + + /* Write the chunk of data */ + offset[0] = CHUNK_NX; + offset[1] = CHUNK_NY; + if (H5Dwrite_chunk(dset, H5P_DEFAULT, flt_msk, offset, CHUNK_SIZE, direct_buf) < 0) + TEST_ERROR; + + /* Get and verify that one chunk had been written */ + if (H5Dget_num_chunks(dset, dspace, &nchunks) < 0) + TEST_ERROR; + if (ONE_CHUNK_WRITTEN != nchunks) + FAIL_PUTS_ERROR("unexpected number of chunks"); + + /* Get and verify info of the first and only chunk */ + if (verify_get_chunk_info(dset, dspace, 0, CHUNK_SIZE, offset, flt_msk) == FAIL) + FAIL_PUTS_ERROR("Verification H5Dget_chunk_info failed\n"); + + /* Get and verify info of the chunk at the offset (CHUNK_NX,CHUNK_NY) */ + if (verify_get_chunk_info_by_coord(dset, offset, CHUNK_SIZE, flt_msk) == FAIL) + FAIL_PUTS_ERROR("Verification of H5Dget_chunk_info_by_coord failed\n"); + + /* Attempt to get chunk info given an invalid chunk index and verify + * that failure occurs */ + chk_index = INVALID_CHK_INDEX; + reinit_vars(&read_flt_msk, &addr, &size); + H5E_BEGIN_TRY + { + ret = H5Dget_chunk_info(dset, dspace, chk_index, out_offset, &read_flt_msk, &addr, &size); + } + H5E_END_TRY; + /* In HDF5 1.10 this will not fail. It will fail in 1.12 and older. */ + /* + if (ret != FAIL) + TEST_ERROR; + */ + + /* Write the chunk of data to another location */ + offset[0] = 0; + offset[1] = 0; + if (H5Dwrite_chunk(dset, H5P_DEFAULT, flt_msk, offset, CHUNK_SIZE, direct_buf) < 0) + TEST_ERROR; + + /* Get and verify that two chunks had been written */ + if (H5Dget_num_chunks(dset, dspace, &nchunks) < 0) + TEST_ERROR; + if (TWO_CHUNKS_WRITTEN != nchunks) + FAIL_PUTS_ERROR("unexpected number of chunks"); + + /* Get and verify info of the first written chunk in the dataset, its + offset should be (0,0) */ + if (verify_get_chunk_info(dset, dspace, 0, CHUNK_SIZE, offset, flt_msk) == FAIL) + FAIL_PUTS_ERROR("Verification H5Dget_chunk_info failed\n"); + + /* Get and verify info of the chunk at the offset (0,0) */ + if (verify_get_chunk_info_by_coord(dset, offset, CHUNK_SIZE, flt_msk) == FAIL) + FAIL_PUTS_ERROR("Verification of H5Dget_chunk_info_by_coord failed\n"); + + /* Get and verify info of the second written chunk in the dataset, its + offset should be (CHUNK_NX, CHUNK_NY) */ + offset[0] = CHUNK_NX; + offset[1] = CHUNK_NY; + if (verify_get_chunk_info(dset, dspace, 1, CHUNK_SIZE, offset, flt_msk) == FAIL) + FAIL_PUTS_ERROR("Verification H5Dget_chunk_info failed\n"); + + /* Get and verify info of the chunk at the offset (CHUNK_NX, CHUNK_NY) */ + if (verify_get_chunk_info_by_coord(dset, offset, CHUNK_SIZE, flt_msk) == FAIL) + FAIL_PUTS_ERROR("Verification of H5Dget_chunk_info_by_coord failed\n"); + + /* Get and verify info of an empty chunk, at offset + (2*CHUNK_NX, 2*CHUNK_NY) */ + offset[0] = 2 * CHUNK_NX; + offset[1] = 2 * CHUNK_NY; + /* Get and verify info of the chunk at the offset (CHUNK_NX, CHUNK_NY) */ + if (verify_empty_chunk_info(dset, offset) == FAIL) + FAIL_PUTS_ERROR("Verification of H5Dget_chunk_info_by_coord on empty chunk failed\n"); + + /* Iterate over all chunks */ + udata.chunk_info = chunk_infos; + udata.last_index = -1; + if (H5Dchunk_iter(dset, H5P_DEFAULT, &iter_cb, &udata) < 0) + TEST_ERROR; + + printf("\nchunk_infos 1 offset 0: %lld\n", chunk_infos[1].offset[0]); + + if (udata.last_index != 1) + FAIL_PUTS_ERROR("Iterator did not iterate over all chunks"); + if (chunk_infos[0].offset[0] != 0) + FAIL_PUTS_ERROR("offset[0] mismatch"); + if (chunk_infos[0].offset[1] != 0) + FAIL_PUTS_ERROR("offset[1] mismatch"); + if (chunk_infos[0].filter_mask != 0) + FAIL_PUTS_ERROR("filter mask mismatch"); + if (chunk_infos[0].size != 96) + FAIL_PUTS_ERROR("size mismatch"); + + if (chunk_infos[1].offset[0] != CHUNK_NX) + FAIL_PUTS_ERROR("offset[0] mismatch"); + if (chunk_infos[1].offset[1] != CHUNK_NY) + FAIL_PUTS_ERROR("offset[1] mismatch"); + + /* Iterate and stop after one iteration */ + cptr = &(chunk_infos[0]); + if (H5Dchunk_iter(dset, H5P_DEFAULT, &iter_cb_stop, &cptr) < 0) + TEST_ERROR; + if (cptr != &(chunk_infos[1])) + FAIL_PUTS_ERROR("Verification of halted iterator failed"); + + /* Iterate and fail after one iteration */ + cptr = &(chunk_infos[0]); + H5E_BEGIN_TRY + { + ret = H5Dchunk_iter(dset, H5P_DEFAULT, &iter_cb_fail, &cptr); + } + H5E_END_TRY; + if (ret >= 0) + TEST_ERROR; + if (cptr != &(chunk_infos[1])) + FAIL_PUTS_ERROR("Verification of halted iterator failed"); + + /* Release resource */ + if (H5Dclose(dset) < 0) + TEST_ERROR; + if (H5Sclose(dspace) < 0) + TEST_ERROR; + if (H5Pclose(cparms) < 0) + TEST_ERROR; + if (H5Fclose(basicfile) < 0) + TEST_ERROR; + + /* Remove the test file */ + HDremove(filename); + + PASSED(); + return SUCCEED; + +error: + H5E_BEGIN_TRY + { + H5Dclose(dset); + H5Sclose(dspace); + H5Pclose(cparms); + H5Fclose(basicfile); + } + H5E_END_TRY; + + H5_FAILED(); + return FAIL; +} /* test_basic_query() */ + /*------------------------------------------------------------------------- * Function: test_get_chunk_info_110 * @@ -1913,6 +2327,9 @@ main(void) if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0) TEST_ERROR + /* Test basic operations on the chunk query functions */ + nerrors += test_basic_query(fapl) < 0 ? 1 : 0; + /* Tests getting chunk information of version 1.8 and prior */ nerrors += test_get_chunk_info_highest18(fapl) < 0 ? 1 : 0; |