diff options
author | Larry Knox <lrknox@hdfgroup.org> | 2024-01-08 13:52:11 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-08 13:52:11 (GMT) |
commit | c0d6d9bb220bf995a268367cca88dc4febbacf99 (patch) | |
tree | 53847b4d8549e3233d58f6ecc6393787af15b098 /src | |
parent | 77de8fda28aab930294a081dedfdc2a0c6617d2f (diff) | |
download | hdf5-c0d6d9bb220bf995a268367cca88dc4febbacf99.zip hdf5-c0d6d9bb220bf995a268367cca88dc4febbacf99.tar.gz hdf5-c0d6d9bb220bf995a268367cca88dc4febbacf99.tar.bz2 |
Sync 1.14 branch with develop (#3923)
* Fix build error on freebsd (#3883)
Fixes:
checking for config freebsd12.1... no
checking for config freebsd... found
compiler '/home/svcpetsc/petsc-hash-pkgs/39f577/bin/mpicc' is GNU gcc-9.2.0
compiler '/home/svcpetsc/petsc-hash-pkgs/39f577/bin/mpif90' is GNU gfortran-9.2.0
stdout: .: cannot open ./config/classic-fflags: No such file or directory
* Correct CMake command and example packaging (#3888)
* Feat: Hashpin sensitive dependencies on GitHub Actions and enable Dependabot to update them monthly (#3892)
* feat: hashpin sensitive dependencies on GHAs
Signed-off-by: Diogo Teles Sant'Anna <diogoteles@google.com>
* feat: enable dependabot for monthly updates on GHA
Signed-off-by: Diogo Teles Sant'Anna <diogoteles@google.com>
---------
Signed-off-by: Diogo Teles Sant'Anna <diogoteles@google.com>
* Some changes to portal links when they could be found on docs.hdfgroup.org, and changed the helpdesk link to help.hdfgroup.org (#3893)
* Updated some portal links to go directly to docs.hdfgroup.
* Fixed some portal and help desk links
* Add variable option syncing for examples (#3885)
* Add period(.) at the end of the sentence for consistency. (#3897)
* Remove redundant backslash character from comment. (#3899)
* Disable doxygen as errors for netcdf (#3900)
* disable building doxygen for netcdf test
* Doc versions (#3903)
* Added missing \since tags to H5D.
* Committing clang-format changes
* Fixed H5T version info.
* Committing clang-format changes
* Added missing version info to H5E.
* Committing clang-format changes
* Added version info to H5F public APIs.
* Committing clang-format changes
* Added missing H5Z public API version info.
* Added missing version info to H5G public APIs
* Added missing version info to H5I public API.
* Added missing version info to H5 public APIs
* Committing clang-format changes
* Added missing version info to H5P public APIs
* Added missing version info to H5R public APIs
* Fix comment error.
* Committing clang-format changes
---------
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
* Change Trouble Shooting to Troubleshooting (#3905)
* Implement optimized support for vector I/O in Subfiling VFD (#3896)
Vector I/O requests are now processed within a single
set of I/O call batches, rather than each I/O vector
entry (tuple constructed from the types, addrs, sizes
and bufs arrays) being processed individually. This allows I/O to be
more efficiently parallelized among the I/O concentrator processes
during large I/O requests.
* Fixed some calculations and add test cases for issues spotted from review
* Removed a variable that was compensating for previous miscalculations
* Add 'warning density' computation to the warnhist script (#3910)
* Add 'warning density' computation to the warnhist script, along with several
cleanups to it. Add "--enable-show-all-warnings" configure (and CMake)
option to disable compiler diagnostic suppression (and therefore show all the
otherwise suppressed compiler diagnostics), disabled by default. Clean up
a buncn of misc. warnings.
Signed-off-by: Quincey Koziol <qkoziol@amazon.com>
* Added H5Fdelete_f with test (#3912)
* New Fortran Examples added (#3916)
* added subfiling example
* Added filtered writes with no selection example
* Version and space corrections.
* Restore H5_VERSION definition in configure.ac.
* renamed defined H5_VERS* to avoid conflicts (#3926)
Diffstat (limited to 'src')
-rw-r--r-- | src/H5Dpkg.h | 2 | ||||
-rw-r--r-- | src/H5Dpublic.h | 17 | ||||
-rw-r--r-- | src/H5EApkg.h | 2 | ||||
-rw-r--r-- | src/H5ESpkg.h | 2 | ||||
-rw-r--r-- | src/H5Epublic.h | 20 | ||||
-rw-r--r-- | src/H5F.c | 2 | ||||
-rw-r--r-- | src/H5FDsubfiling/H5FDioc.c | 50 | ||||
-rw-r--r-- | src/H5FDsubfiling/H5FDioc_int.c | 8 | ||||
-rw-r--r-- | src/H5FDsubfiling/H5FDioc_threads.c | 12 | ||||
-rw-r--r-- | src/H5FDsubfiling/H5FDsubfiling.c | 2395 | ||||
-rw-r--r-- | src/H5FDsubfiling/H5subfiling_common.c | 33 | ||||
-rw-r--r-- | src/H5FDsubfiling/H5subfiling_common.h | 3 | ||||
-rw-r--r-- | src/H5Fpublic.h | 40 | ||||
-rw-r--r-- | src/H5Gpublic.h | 39 | ||||
-rw-r--r-- | src/H5Idbg.c | 15 | ||||
-rw-r--r-- | src/H5Idevelop.h | 2 | ||||
-rw-r--r-- | src/H5Iint.c | 58 | ||||
-rw-r--r-- | src/H5Ipkg.h | 11 | ||||
-rw-r--r-- | src/H5Ipublic.h | 30 | ||||
-rw-r--r-- | src/H5Pprivate.h | 2 | ||||
-rw-r--r-- | src/H5Ppublic.h | 48 | ||||
-rw-r--r-- | src/H5Rpublic.h | 45 | ||||
-rw-r--r-- | src/H5Tpkg.h | 2 | ||||
-rw-r--r-- | src/H5Tpublic.h | 106 | ||||
-rw-r--r-- | src/H5Zdevelop.h | 5 | ||||
-rw-r--r-- | src/H5Zpublic.h | 2 | ||||
-rw-r--r-- | src/H5private.h | 8 | ||||
-rw-r--r-- | src/H5public.h | 21 |
28 files changed, 1823 insertions, 1157 deletions
diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index a3695ae..dc842e8 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -727,7 +727,7 @@ H5_DLL herr_t H5D__chunk_allocated(const H5D_t *dset, hsize_t *nbytes); H5_DLL herr_t H5D__chunk_allocate(const H5D_t *dset, bool full_overwrite, const hsize_t old_dim[]); H5_DLL herr_t H5D__chunk_file_alloc(const H5D_chk_idx_info_t *idx_info, const H5F_block_t *old_chunk, H5F_block_t *new_chunk, bool *need_insert, const hsize_t *scaled); -H5_DLL void *H5D__chunk_mem_alloc(size_t size, void *pline); +H5_DLL void *H5D__chunk_mem_alloc(size_t size, void *pline) H5_ATTR_MALLOC; H5_DLL void H5D__chunk_mem_free(void *chk, void *pline); H5_DLL void *H5D__chunk_mem_xfree(void *chk, const void *pline); H5_DLL void *H5D__chunk_mem_realloc(void *chk, size_t size, const H5O_pline_t *pline); diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h index a4c60cd..35d0edf 100644 --- a/src/H5Dpublic.h +++ b/src/H5Dpublic.h @@ -424,6 +424,8 @@ H5_DLL hid_t H5Dopen_async(hid_t loc_id, const char *name, hid_t dapl_id, hid_t * be released with H5Sclose() when the identifier is no longer * needed so that resource leaks will not occur. * + * \since 1.0.0 + * * \par Example * \snippet H5D_examples.c update * @@ -494,6 +496,8 @@ H5_DLL herr_t H5Dget_space_status(hid_t dset_id, H5D_space_status_t *allocation) * opened datatype is returned. Otherwise, the returned datatype * is read-only. * + * \since 1.0.0 + * */ H5_DLL hid_t H5Dget_type(hid_t dset_id); @@ -515,6 +519,8 @@ H5_DLL hid_t H5Dget_type(hid_t dset_id); * The creation property list identifier should be released with * H5Pclose() to prevent resource leaks. * + * \since 1.0.0 + * */ H5_DLL hid_t H5Dget_create_plist(hid_t dset_id); @@ -590,6 +596,7 @@ H5_DLL hid_t H5Dget_access_plist(hid_t dset_id); * with no stored values, and 0 (zero), the value returned to * indicate an error. * + * \since 1.2.0 * */ H5_DLL hsize_t H5Dget_storage_size(hid_t dset_id); @@ -872,6 +879,8 @@ H5_DLL haddr_t H5Dget_offset(hid_t dset_id); * \par Example * \snippet H5D_examples.c read * + * \since 1.0.0 + * */ H5_DLL herr_t H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, hid_t dxpl_id, void *buf /*out*/); @@ -1060,6 +1069,8 @@ H5_DLL herr_t H5Dread_multi_async(size_t count, hid_t dset_id[], hid_t mem_type_ * \par Example * \snippet H5D_examples.c update * + * \since 1.0.0 + * * \see H5Pset_fill_time(), H5Pset_alloc_time() * */ @@ -1355,6 +1366,7 @@ H5_DLL herr_t H5Dvlen_get_buf_size(hid_t dset_id, hid_t type_id, hid_t space_id, * * \see H5Pset_fill_value(), H5Pget_fill_value(), H5Pfill_value_defined(), * H5Pset_fill_time(), H5Pget_fill_time(), H5Pcreate(), H5Dcreate_anon() + * \since 1.6.0 * */ H5_DLL herr_t H5Dfill(const void *fill, hid_t fill_type_id, void *buf, hid_t buf_type_id, hid_t space_id); @@ -1598,7 +1610,7 @@ H5_DLL herr_t H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id, * \par Example * \snippet H5D_examples.c read * - * \since 1.8.0 + * \since 1.0.0 * * \see H5Dcreate2(), H5Dopen2() * @@ -1811,6 +1823,7 @@ H5_DLL hid_t H5Dopen1(hid_t loc_id, const char *name); * * \version 1.8.0 Function deprecated in this release. Parameter size * syntax changed to \Code{const hsize_t size[]} in this release. + * \since 1.0.0 * */ H5_DLL herr_t H5Dextend(hid_t dset_id, const hsize_t size[]); @@ -1847,6 +1860,8 @@ H5_DLL herr_t H5Dextend(hid_t dset_id, const hsize_t size[]); * * \version 1.12.0 Function was deprecated * + * \since 1.2.0 + * */ H5_DLL herr_t H5Dvlen_reclaim(hid_t type_id, hid_t space_id, hid_t dxpl_id, void *buf); diff --git a/src/H5EApkg.h b/src/H5EApkg.h index 90ba02a..e8b5a13 100644 --- a/src/H5EApkg.h +++ b/src/H5EApkg.h @@ -389,7 +389,7 @@ H5_DLL herr_t H5EA__destroy_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t H5_DLL H5EA_hdr_t *H5EA__hdr_alloc(H5F_t *f); H5_DLL herr_t H5EA__hdr_init(H5EA_hdr_t *hdr, void *ctx_udata); H5_DLL haddr_t H5EA__hdr_create(H5F_t *f, const H5EA_create_t *cparam, void *ctx_udata); -H5_DLL void *H5EA__hdr_alloc_elmts(H5EA_hdr_t *hdr, size_t nelmts); +H5_DLL void *H5EA__hdr_alloc_elmts(H5EA_hdr_t *hdr, size_t nelmts) H5_ATTR_MALLOC; H5_DLL herr_t H5EA__hdr_free_elmts(H5EA_hdr_t *hdr, size_t nelmts, void *elmts); H5_DLL herr_t H5EA__hdr_incr(H5EA_hdr_t *hdr); H5_DLL herr_t H5EA__hdr_decr(H5EA_hdr_t *hdr); diff --git a/src/H5ESpkg.h b/src/H5ESpkg.h index f7c70e8..1da58a6 100644 --- a/src/H5ESpkg.h +++ b/src/H5ESpkg.h @@ -75,7 +75,7 @@ typedef int (*H5ES_list_iter_func_t)(H5ES_event_t *ev, void *ctx); /******************************/ /* Package Private Prototypes */ /******************************/ -H5_DLL H5ES_t *H5ES__create(void); +H5_DLL H5ES_t *H5ES__create(void) H5_ATTR_MALLOC; H5_DLL herr_t H5ES__insert_request(H5ES_t *es, H5VL_t *connector, void *token); H5_DLL herr_t H5ES__wait(H5ES_t *es, uint64_t timeout, size_t *num_in_progress, bool *op_failed); H5_DLL herr_t H5ES__get_requests(H5ES_t *es, H5_iter_order_t order, hid_t *connector_ids, void **requests, diff --git a/src/H5Epublic.h b/src/H5Epublic.h index b6cc1cb..a22c9c6 100644 --- a/src/H5Epublic.h +++ b/src/H5Epublic.h @@ -697,6 +697,9 @@ typedef struct H5E_error1_t { * \param[in] client_data Pointer to client data in the format expected by the * user-defined function * \return \herr_t + * + * \since 1.0.0 + * */ typedef herr_t (*H5E_walk1_t)(int n, H5E_error1_t *err_desc, void *client_data); //! <!-- [H5E_walk1_t_snip] --> @@ -708,6 +711,9 @@ typedef herr_t (*H5E_walk1_t)(int n, H5E_error1_t *err_desc, void *client_data); * \param[in] client_data Pointer to client data in the format expected by the * user-defined function * \return \herr_t + * + * \since 1.0.0 + * */ typedef herr_t (*H5E_auto1_t)(void *client_data); //! <!-- [H5E_auto1_t_snip] --> @@ -728,6 +734,8 @@ typedef herr_t (*H5E_auto1_t)(void *client_data); * The stack is also cleared whenever an API function is called, with * certain exceptions (for instance, H5Eprint1()). * + * \since 1.0.0 + * */ H5_DLL herr_t H5Eclear1(void); /** @@ -772,6 +780,8 @@ H5_DLL herr_t H5Eclear1(void); * H5Eprint2(), mixing H5Eset_auto1() and H5Eget_auto2() or mixing * H5Eset_auto2() and H5Eget_auto1() does not fail. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Eget_auto1(H5E_auto1_t *func, void **client_data); /** @@ -826,6 +836,8 @@ H5_DLL herr_t H5Epush1(const char *file, const char *func, unsigned line, H5E_ma * that prints error messages. Users are encouraged to write their own * more specific error handlers. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Eprint1(FILE *stream); /** @@ -857,6 +869,8 @@ H5_DLL herr_t H5Eprint1(FILE *stream); * Automatic stack traversal is always in the #H5E_WALK_DOWNWARD * direction. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Eset_auto1(H5E_auto1_t func, void *client_data); /** @@ -890,6 +904,8 @@ H5_DLL herr_t H5Eset_auto1(H5E_auto1_t func, void *client_data); * is as follows: * \snippet this H5E_walk1_t_snip * + * \since 1.0.0 + * */ H5_DLL herr_t H5Ewalk1(H5E_direction_t direction, H5E_walk1_t func, void *client_data); /** @@ -911,6 +927,8 @@ H5_DLL herr_t H5Ewalk1(H5E_direction_t direction, H5E_walk1_t func, void *client * array). An application calling this function must free the memory * associated with the return value to prevent a memory leak. * + * \since 1.0.0 + * */ H5_DLL char *H5Eget_major(H5E_major_t maj); /** @@ -934,6 +952,8 @@ H5_DLL char *H5Eget_major(H5E_major_t maj); * the memory associated with the return value to prevent a memory * leak. This is a change from the 1.6.x release series. * + * \since 1.0.0 + * */ H5_DLL char *H5Eget_minor(H5E_minor_t min); #endif /* H5_NO_DEPRECATED_SYMBOLS */ @@ -2211,7 +2211,7 @@ done: * * Purpose: Releases the external file cache associated with the * provided file, potentially closing any cached files - * unless they are held open from somewhere\ else. + * unless they are held open from somewhere else. * * Return: Success: Non-negative * Failure: Negative diff --git a/src/H5FDsubfiling/H5FDioc.c b/src/H5FDsubfiling/H5FDioc.c index 80771c0..b019add 100644 --- a/src/H5FDsubfiling/H5FDioc.c +++ b/src/H5FDsubfiling/H5FDioc.c @@ -1610,12 +1610,14 @@ H5FD__ioc_write_vector_internal(H5FD_t *_file, uint32_t count, H5FD_mem_t H5_ATT H5FD_ioc_t *file_ptr = (H5FD_ioc_t *)_file; io_req_t **sf_io_reqs = NULL; int64_t sf_context_id = -1; + size_t io_size = 0; + bool extend_sizes = false; herr_t ret_value = SUCCEED; assert(_file); - assert(addrs); - assert(sizes); - assert(bufs); + assert((addrs) || (count == 0)); + assert((sizes) || (count == 0)); + assert((bufs) || (count == 0)); if (count == 0) H5_SUBFILING_GOTO_DONE(SUCCEED); @@ -1648,12 +1650,22 @@ H5FD__ioc_write_vector_internal(H5FD_t *_file, uint32_t count, H5FD_mem_t H5_ATT for (size_t i = 0; i < (size_t)count; i++) { herr_t write_status; - if (sizes[i] == 0) + if (!extend_sizes) { + if ((i > 0) && (sizes[i] == 0)) { + extend_sizes = true; + io_size = sizes[i - 1]; + } + else { + io_size = sizes[i]; + } + } + + if (io_size == 0) H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "invalid size argument of 0"); H5_CHECK_OVERFLOW(addrs[i], haddr_t, int64_t); - H5_CHECK_OVERFLOW(sizes[i], size_t, int64_t); - write_status = ioc__write_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)sizes[i], + H5_CHECK_OVERFLOW(io_size, size_t, int64_t); + write_status = ioc__write_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)io_size, bufs[i], &sf_io_reqs[i]); if (write_status < 0) @@ -1691,12 +1703,14 @@ H5FD__ioc_read_vector_internal(H5FD_t *_file, uint32_t count, haddr_t addrs[], s H5FD_ioc_t *file_ptr = (H5FD_ioc_t *)_file; io_req_t **sf_io_reqs = NULL; int64_t sf_context_id = -1; + size_t io_size = 0; + bool extend_sizes = false; herr_t ret_value = SUCCEED; assert(_file); - assert(addrs); - assert(sizes); - assert(bufs); + assert((addrs) || (count == 0)); + assert((sizes) || (count == 0)); + assert((bufs) || (count == 0)); if (count == 0) H5_SUBFILING_GOTO_DONE(SUCCEED); @@ -1720,12 +1734,22 @@ H5FD__ioc_read_vector_internal(H5FD_t *_file, uint32_t count, haddr_t addrs[], s H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate MPI request array"); for (size_t i = 0; i < (size_t)count; i++) { - int read_status; + herr_t read_status; + + if (!extend_sizes) { + if ((i > 0) && (sizes[i] == 0)) { + extend_sizes = true; + io_size = sizes[i - 1]; + } + else { + io_size = sizes[i]; + } + } H5_CHECK_OVERFLOW(addrs[i], haddr_t, int64_t); - H5_CHECK_OVERFLOW(sizes[i], size_t, int64_t); - read_status = ioc__read_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)sizes[i], - bufs[i], &sf_io_reqs[i]); + H5_CHECK_OVERFLOW(io_size, size_t, int64_t); + read_status = ioc__read_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)io_size, bufs[i], + &sf_io_reqs[i]); if (read_status < 0) H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't queue read operation"); diff --git a/src/H5FDsubfiling/H5FDioc_int.c b/src/H5FDsubfiling/H5FDioc_int.c index 5528fc8..75a36d0 100644 --- a/src/H5FDsubfiling/H5FDioc_int.c +++ b/src/H5FDsubfiling/H5FDioc_int.c @@ -297,9 +297,13 @@ ioc__read_independent_async(int64_t context_id, int64_t offset, int64_t elements * unpredictable order. However, if some IOCs own more than * 1 subfile, we need to associate each read with a unique * message tag to make sure the data is received in the - * correct order. + * correct order. We also need a unique message tag in the + * case where only 1 subfile is used in total. In this case, + * vector I/O calls are passed directly down to this VFD without + * being split up into multiple I/O requests, so we need the + * tag to distinguish each I/O request. */ - need_data_tag = num_subfiles != num_io_concentrators; + need_data_tag = (num_subfiles == 1) || (num_subfiles != num_io_concentrators); if (!need_data_tag) data_tag = READ_INDEP_DATA; diff --git a/src/H5FDsubfiling/H5FDioc_threads.c b/src/H5FDsubfiling/H5FDioc_threads.c index c86157b..85c2561 100644 --- a/src/H5FDsubfiling/H5FDioc_threads.c +++ b/src/H5FDsubfiling/H5FDioc_threads.c @@ -456,8 +456,9 @@ translate_opcode(io_op_t op) case LOGGING_OP: return "LOGGING_OP"; break; + default: + return "unknown"; } - return "unknown"; } #endif @@ -873,9 +874,14 @@ ioc_file_queue_read_indep(sf_work_request_t *msg, int ioc_idx, int source, MPI_C * unpredictable order. However, if some IOCs own more than * 1 subfile, we need to associate each read with a unique * message tag to make sure the data is received in the - * correct order. + * correct order. We also need a unique message tag in the + * case where only 1 subfile is used in total. In this case, + * vector I/O calls are passed directly down to this VFD without + * being split up into multiple I/O requests, so we need the + * tag to distinguish each I/O request. */ - need_data_tag = sf_context->sf_num_subfiles != sf_context->topology->n_io_concentrators; + need_data_tag = (sf_context->sf_num_subfiles == 1) || + (sf_context->sf_num_subfiles != sf_context->topology->n_io_concentrators); if (!need_data_tag) send_tag = READ_INDEP_DATA; diff --git a/src/H5FDsubfiling/H5FDsubfiling.c b/src/H5FDsubfiling/H5FDsubfiling.c index 461fa16..bf175e6 100644 --- a/src/H5FDsubfiling/H5FDsubfiling.c +++ b/src/H5FDsubfiling/H5FDsubfiling.c @@ -121,6 +121,11 @@ typedef struct H5FD_subfiling_t { char filename[H5FD_MAX_FILENAME_LEN]; /* Copy of file name from open operation */ } H5FD_subfiling_t; +typedef enum H5FD_subfiling_io_type_t { + IO_TYPE_WRITE, + IO_TYPE_READ, +} H5FD_subfiling_io_type_t; + /* * These macros check for overflow of various quantities. These macros * assume that HDoff_t is signed and haddr_t and size_t are unsigned. @@ -187,27 +192,52 @@ static int H5FD__copy_plist(hid_t fapl_id, hid_t *id_out_ptr); static herr_t H5FD__subfiling_close_int(H5FD_subfiling_t *file_ptr); -static herr_t init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_nelemts, - size_t dtype_extent, size_t max_iovec_len, int64_t *mem_buf_offset, - int64_t *target_file_offset, int64_t *io_block_len, int *first_subfile_index, - int *n_subfiles_used, int64_t *max_io_req_per_subfile); -static herr_t iovec_fill_first(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t target_datasize, - int64_t start_mem_offset, int64_t start_file_offset, int64_t first_io_len, - int64_t *mem_offset_out, int64_t *target_file_offset_out, - int64_t *io_block_len_out); -static herr_t iovec_fill_last(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t target_datasize, - int64_t start_mem_offset, int64_t start_file_offset, int64_t last_io_len, - int64_t *mem_offset_out, int64_t *target_file_offset_out, - int64_t *io_block_len_out); -static herr_t iovec_fill_first_last(subfiling_context_t *sf_context, int64_t iovec_depth, - int64_t target_datasize, int64_t start_mem_offset, - int64_t start_file_offset, int64_t first_io_len, int64_t last_io_len, - int64_t *mem_offset_out, int64_t *target_file_offset_out, - int64_t *io_block_len_out); -static herr_t iovec_fill_uniform(subfiling_context_t *sf_context, int64_t iovec_depth, +static herr_t H5FD__subfiling_io_helper(H5FD_subfiling_t *file_ptr, size_t io_count, H5FD_mem_t types[], + haddr_t addrs[], size_t sizes[], H5_flexible_const_ptr_t bufs[], + H5FD_subfiling_io_type_t io_type); +static herr_t H5FD__subfiling_mirror_writes_to_stub(H5FD_subfiling_t *file_ptr, uint32_t count, + H5FD_mem_t types[], haddr_t addrs[], size_t sizes[], + const void *bufs[]); +static herr_t generate_io_vectors(subfiling_context_t *sf_context, size_t in_count, H5FD_mem_t types[], + haddr_t file_offsets[], size_t nelemts[], H5_flexible_const_ptr_t bufs[], + size_t dtype_extent, H5FD_subfiling_io_type_t io_type, size_t *ioreq_count, + uint32_t *iovec_len, H5FD_mem_t **io_types, haddr_t **io_addrs, + size_t **io_sizes, H5_flexible_const_ptr_t **io_bufs); +static void get_iovec_sizes(subfiling_context_t *sf_context, size_t in_count, haddr_t file_offsets[], + size_t nelemts[], size_t dtype_extent, size_t *max_iovec_depth, + size_t *max_num_subfiles); +static herr_t translate_io_req_to_iovec(subfiling_context_t *sf_context, size_t iovec_idx, size_t iovec_len, + size_t iovec_count, H5FD_mem_t type, haddr_t addr, size_t io_size, + H5_flexible_const_ptr_t io_buf, H5FD_subfiling_io_type_t io_type, + H5FD_mem_t *io_types, haddr_t *io_addrs, size_t *io_sizes, + H5_flexible_const_ptr_t *io_bufs); +static herr_t iovec_fill_first(subfiling_context_t *sf_context, size_t iovec_len, int64_t cur_iovec_depth, + int64_t target_datasize, int64_t start_mem_offset, int64_t start_file_offset, + int64_t first_io_len, H5_flexible_const_ptr_t buf, + H5FD_subfiling_io_type_t io_type, haddr_t *io_addrs_ptr, size_t *io_sizes_ptr, + H5_flexible_const_ptr_t *io_bufs_ptr); +static herr_t iovec_fill_last(subfiling_context_t *sf_context, size_t iovec_len, int64_t cur_iovec_depth, + int64_t target_datasize, int64_t start_mem_offset, int64_t start_file_offset, + int64_t last_io_len, H5_flexible_const_ptr_t buf, + H5FD_subfiling_io_type_t io_type, haddr_t *io_addrs_ptr, size_t *io_sizes_ptr, + H5_flexible_const_ptr_t *io_bufs_ptr); +static herr_t iovec_fill_first_last(subfiling_context_t *sf_context, size_t iovec_len, + int64_t cur_iovec_depth, int64_t target_datasize, + int64_t start_mem_offset, int64_t start_file_offset, int64_t first_io_len, + int64_t last_io_len, H5_flexible_const_ptr_t buf, + H5FD_subfiling_io_type_t io_type, haddr_t *io_addrs_ptr, + size_t *io_sizes_ptr, H5_flexible_const_ptr_t *io_bufs_ptr); +static herr_t iovec_fill_uniform(subfiling_context_t *sf_context, size_t iovec_len, int64_t cur_iovec_depth, int64_t target_datasize, int64_t start_mem_offset, int64_t start_file_offset, - int64_t *mem_offset_out, int64_t *target_file_offset_out, - int64_t *io_block_len_out); + H5_flexible_const_ptr_t buf, H5FD_subfiling_io_type_t io_type, + haddr_t *io_addrs_ptr, size_t *io_sizes_ptr, + H5_flexible_const_ptr_t *io_bufs_ptr); + +#ifdef H5_SUBFILING_DEBUG +void H5_subfiling_dump_iovecs(subfiling_context_t *sf_context, size_t ioreq_count, size_t iovec_len, + H5FD_subfiling_io_type_t io_type, H5FD_mem_t *io_types, haddr_t *io_addrs, + size_t *io_sizes, H5_flexible_const_ptr_t *io_bufs); +#endif void H5FD__subfiling_mpi_finalize(void); @@ -384,7 +414,7 @@ H5FD__subfiling_term(void) if (MPI_SUCCESS != (mpi_code = MPI_Type_free(&H5_subfiling_rpc_msg_type))) H5_SUBFILING_MPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code); } -#ifdef H5FD_SUBFILING_DEBUG +#ifdef H5_SUBFILING_DEBUG else printf("** WARNING **: HDF5 is terminating the Subfiling VFD after MPI_Finalize() was " "called - an HDF5 ID was probably left unclosed\n"); @@ -1535,199 +1565,16 @@ static herr_t H5FD__subfiling_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, void *buf /*out*/) { - subfiling_context_t *sf_context = NULL; - H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file; - H5FD_mem_t *io_types = NULL; - haddr_t *io_addrs = NULL; - size_t *io_sizes = NULL; - void **io_bufs = NULL; - int64_t *source_data_offset = NULL; - int64_t *sf_data_size = NULL; - int64_t *sf_offset = NULL; - bool rank0_bcast = false; - int num_subfiles; - herr_t ret_value = SUCCEED; + H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file; + herr_t ret_value = SUCCEED; - assert(file_ptr && file_ptr->pub.cls); + assert(file_ptr); + assert(file_ptr->pub.driver_id == H5FD_SUBFILING); assert(buf); - /* Check for overflow conditions */ - if (!H5_addr_defined(addr)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %" PRIuHADDR, addr); - if (REGION_OVERFLOW(addr, size)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addr = %" PRIuHADDR ", size = %zu", addr, size); - - /* Temporarily reject collective I/O until support is implemented (unless types are simple MPI_BYTE) */ - { - H5FD_mpio_xfer_t xfer_mode; - - if (H5CX_get_io_xfer_mode(&xfer_mode) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTGET, FAIL, - "can't determine I/O collectivity setting"); - - if (xfer_mode == H5FD_MPIO_COLLECTIVE) { - MPI_Datatype btype, ftype; - - if (H5CX_get_mpi_coll_datatypes(&btype, &ftype) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI-I/O datatypes"); - if (MPI_BYTE != btype || MPI_BYTE != ftype) - H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, - "collective I/O is currently unsupported"); - } - - /* Determine whether a rank 0 bcast approach has been requested */ - rank0_bcast = H5CX_get_mpio_rank0_bcast(); - - /* - * If we reached here, we're still doing independent I/O regardless - * of collectivity setting, so set that. - */ - H5CX_set_io_xfer_mode(H5FD_MPIO_INDEPENDENT); - } - - /* - * Retrieve the subfiling context object and the number - * of subfiles. - * - * Given the current I/O and the I/O concentrator info, - * we can determine some I/O transaction parameters. - * In particular, for large I/O operations, each IOC - * may require multiple I/Os to fulfill the user I/O - * request. The block size and number of IOCs are used - * to size the vectors that will be used to invoke the - * underlying I/O operations. - */ - sf_context = (subfiling_context_t *)H5_get_subfiling_object(file_ptr->context_id); - assert(sf_context); - assert(sf_context->topology); - - num_subfiles = sf_context->sf_num_subfiles; - - if (num_subfiles <= 0) { - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid number of subfiles (%d)", - num_subfiles); - } - else if (num_subfiles == 1) { - /*************************************** - * No striping - just a single subfile * - ***************************************/ - - /* Make vector read call to subfile */ - if (H5FD_read_vector(file_ptr->sf_file, 1, &type, &addr, &size, &buf) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "read from subfile failed"); - } - else { - int64_t max_io_req_per_subfile; - int64_t file_offset; - int64_t block_size; - size_t max_depth; - herr_t status; - int num_subfiles_used = 0; - int first_subfile_idx = -1; - - /************************************* - * Striping across multiple subfiles * - *************************************/ - - block_size = sf_context->sf_blocksize_per_stripe; - max_depth = (size / (size_t)block_size) + 2; - - /* - * Given the number of subfiles, allocate vectors (one per subfile) - * to contain the translation of the I/O request into a collection of - * I/O requests. - */ - if (NULL == - (source_data_offset = calloc(1, (size_t)num_subfiles * max_depth * sizeof(*source_data_offset)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate source data offset I/O vector"); - if (NULL == (sf_data_size = calloc(1, (size_t)num_subfiles * max_depth * sizeof(*sf_data_size)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile data size I/O vector"); - if (NULL == (sf_offset = calloc(1, (size_t)num_subfiles * max_depth * sizeof(*sf_offset)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile offset I/O vector"); - - H5_CHECKED_ASSIGN(file_offset, int64_t, addr, haddr_t); - - /* - * Get the potential set of IOC transactions; e.g., data sizes, - * offsets and datatypes. - */ - status = init_indep_io(sf_context, /* IN: Context used to look up config info */ - file_offset, /* IN: Starting file offset */ - size, /* IN: I/O size */ - 1, /* IN: Data extent of the 'type' assumes byte */ - max_depth, /* IN: Maximum stripe depth */ - source_data_offset, /* OUT: Memory offset */ - sf_offset, /* OUT: File offset */ - sf_data_size, /* OUT: Length of this contiguous block */ - &first_subfile_idx, /* OUT: Subfile index corresponding to starting offset */ - &num_subfiles_used, /* OUT: Number of actual subfiles used */ - &max_io_req_per_subfile); /* OUT: Maximum number of requests to any subfile */ - - if (status < 0) - H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't initialize IOC transactions"); - - if (max_io_req_per_subfile > 0) { - uint32_t vector_len; - - H5_CHECKED_ASSIGN(vector_len, uint32_t, num_subfiles_used, int); - - /* Allocate I/O vectors */ - if (NULL == (io_types = malloc(vector_len * sizeof(*io_types)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O types vector"); - if (NULL == (io_addrs = malloc(vector_len * sizeof(*io_addrs)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O addresses vector"); - if (NULL == (io_sizes = malloc(vector_len * sizeof(*io_sizes)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O sizes vector"); - if (NULL == (io_bufs = malloc(vector_len * sizeof(*io_bufs)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O buffers vector"); - - for (int64_t i = 0; i < max_io_req_per_subfile; i++) { - uint32_t final_vec_len = vector_len; - int next_subfile_idx = first_subfile_idx; - - /* Fill in I/O types, offsets, sizes and buffers vectors */ - for (uint32_t k = 0, vec_idx = 0; k < vector_len; k++) { - size_t idx = (size_t)next_subfile_idx * max_depth + (size_t)i; - - io_types[vec_idx] = type; - H5_CHECKED_ASSIGN(io_addrs[vec_idx], haddr_t, sf_offset[idx], int64_t); - H5_CHECKED_ASSIGN(io_sizes[vec_idx], size_t, sf_data_size[idx], int64_t); - io_bufs[vec_idx] = ((char *)buf + source_data_offset[idx]); - - next_subfile_idx = (next_subfile_idx + 1) % num_subfiles; - - /* Skip 0-sized I/Os */ - if (io_sizes[vec_idx] == 0) { - final_vec_len--; - continue; - } - - vec_idx++; - } - - if (!rank0_bcast || (file_ptr->mpi_rank == 0)) { - /* Make vector read call to subfile */ - if (H5FD_read_vector(file_ptr->sf_file, final_vec_len, io_types, io_addrs, io_sizes, - io_bufs) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "read from subfile failed"); - } - } - - if (rank0_bcast && (file_ptr->mpi_size > 1)) { - H5_CHECK_OVERFLOW(size, size_t, int); - if (MPI_SUCCESS != MPI_Bcast(buf, (int)size, MPI_BYTE, 0, file_ptr->comm)) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't broadcast data from rank 0"); - } - } - } + if (H5FD__subfiling_io_helper(file_ptr, 1, &type, &addr, &size, (H5_flexible_const_ptr_t *)&buf, + IO_TYPE_READ) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "read from subfiles failed"); /* Point to the end of the current I/O */ addr += (haddr_t)size; @@ -1737,14 +1584,6 @@ H5FD__subfiling_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_i file_ptr->op = OP_READ; done: - free(io_bufs); - free(io_sizes); - free(io_addrs); - free(io_types); - free(sf_offset); - free(sf_data_size); - free(source_data_offset); - if (ret_value < 0) { /* Reset last file I/O information */ file_ptr->pos = HADDR_UNDEF; @@ -1769,214 +1608,16 @@ static herr_t H5FD__subfiling_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, const void *buf /*in*/) { - subfiling_context_t *sf_context = NULL; - H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file; - const void **io_bufs = NULL; - H5FD_mem_t *io_types = NULL; - haddr_t *io_addrs = NULL; - size_t *io_sizes = NULL; - int64_t *source_data_offset = NULL; - int64_t *sf_data_size = NULL; - int64_t *sf_offset = NULL; - int num_subfiles; - herr_t ret_value = SUCCEED; + H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file; + herr_t ret_value = SUCCEED; - assert(file_ptr && file_ptr->pub.cls); + assert(file_ptr); + assert(file_ptr->pub.driver_id == H5FD_SUBFILING); assert(buf); - /* Check for overflow conditions */ - if (!H5_addr_defined(addr)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %" PRIuHADDR, addr); - if (REGION_OVERFLOW(addr, size)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addr = %" PRIuHADDR ", size = %zu", addr, size); - - /* Temporarily reject collective I/O until support is implemented (unless types are simple MPI_BYTE) */ - { - H5FD_mpio_xfer_t xfer_mode; - - if (H5CX_get_io_xfer_mode(&xfer_mode) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTGET, FAIL, - "can't determine I/O collectivity setting"); - - if (xfer_mode == H5FD_MPIO_COLLECTIVE) { - MPI_Datatype btype, ftype; - - if (H5CX_get_mpi_coll_datatypes(&btype, &ftype) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI-I/O datatypes"); - if (MPI_BYTE != btype || MPI_BYTE != ftype) - H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, - "collective I/O is currently unsupported"); - } - - /* - * If we reached here, we're still doing independent I/O regardless - * of collectivity setting, so set that. - */ - H5CX_set_io_xfer_mode(H5FD_MPIO_INDEPENDENT); - } - - /* - * Retrieve the subfiling context object and the number - * of subfiles. - * - * Given the current I/O and the I/O concentrator info, - * we can determine some I/O transaction parameters. - * In particular, for large I/O operations, each IOC - * may require multiple I/Os to fulfill the user I/O - * request. The block size and number of IOCs are used - * to size the vectors that will be used to invoke the - * underlying I/O operations. - */ - sf_context = (subfiling_context_t *)H5_get_subfiling_object(file_ptr->context_id); - assert(sf_context); - assert(sf_context->topology); - - num_subfiles = sf_context->sf_num_subfiles; - - if (num_subfiles <= 0) { - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid number of subfiles (%d)", - num_subfiles); - } - else if (num_subfiles == 1) { - /*************************************** - * No striping - just a single subfile * - ***************************************/ - - /* Make vector write call to subfile */ - if (H5FD_write_vector(file_ptr->sf_file, 1, &type, &addr, &size, &buf) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "write to subfile failed"); - - /* - * Mirror superblock writes to the stub file so that - * legacy HDF5 applications can check what type of - * file they are reading - */ - if ((type == H5FD_MEM_SUPER) && (file_ptr->mpi_rank == 0)) { - if (H5FD_write_vector(file_ptr->stub_file, 1, &type, &addr, &size, &buf) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, - "couldn't write superblock information to stub file"); - } - } - else { - int64_t max_io_req_per_subfile; - int64_t file_offset; - int64_t block_size; - size_t max_depth; - herr_t status; - int num_subfiles_used = 0; - int first_subfile_idx = -1; - - /************************************* - * Striping across multiple subfiles * - *************************************/ - - block_size = sf_context->sf_blocksize_per_stripe; - max_depth = (size / (size_t)block_size) + 2; - - /* - * Given the number of subfiles, allocate vectors (one per subfile) - * to contain the translation of the I/O request into a collection of - * I/O requests. - */ - if (NULL == - (source_data_offset = calloc(1, (size_t)num_subfiles * max_depth * sizeof(*source_data_offset)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate source data offset I/O vector"); - if (NULL == (sf_data_size = calloc(1, (size_t)num_subfiles * max_depth * sizeof(*sf_data_size)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile data size I/O vector"); - if (NULL == (sf_offset = calloc(1, (size_t)num_subfiles * max_depth * sizeof(*sf_offset)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile offset I/O vector"); - - H5_CHECKED_ASSIGN(file_offset, int64_t, addr, haddr_t); - - /* - * Get the potential set of IOC transactions; e.g., data sizes, - * offsets and datatypes. - */ - status = init_indep_io(sf_context, /* IN: Context used to look up config info */ - file_offset, /* IN: Starting file offset */ - size, /* IN: I/O size */ - 1, /* IN: Data extent of the 'type' assumes byte */ - max_depth, /* IN: Maximum stripe depth */ - source_data_offset, /* OUT: Memory offset */ - sf_offset, /* OUT: File offset */ - sf_data_size, /* OUT: Length of this contiguous block */ - &first_subfile_idx, /* OUT: Subfile index corresponding to starting offset */ - &num_subfiles_used, /* OUT: Number of actual subfiles used */ - &max_io_req_per_subfile); /* OUT: Maximum number of requests to any subfile */ - - if (status < 0) - H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't initialize IOC transactions"); - - if (max_io_req_per_subfile > 0) { - uint32_t vector_len; - - H5_CHECKED_ASSIGN(vector_len, uint32_t, num_subfiles_used, int); - - /* Allocate I/O vectors */ - if (NULL == (io_types = malloc(vector_len * sizeof(*io_types)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O types vector"); - if (NULL == (io_addrs = malloc(vector_len * sizeof(*io_addrs)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O addresses vector"); - if (NULL == (io_sizes = malloc(vector_len * sizeof(*io_sizes)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O sizes vector"); - if (NULL == (io_bufs = malloc(vector_len * sizeof(*io_bufs)))) - H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "can't allocate subfile I/O buffers vector"); - - for (int64_t i = 0; i < max_io_req_per_subfile; i++) { - uint32_t final_vec_len = vector_len; - int next_subfile_idx = first_subfile_idx; - - /* Fill in I/O types, offsets, sizes and buffers vectors */ - for (uint32_t k = 0, vec_idx = 0; k < vector_len; k++) { - size_t idx = (size_t)next_subfile_idx * max_depth + (size_t)i; - - io_types[vec_idx] = type; - H5_CHECKED_ASSIGN(io_addrs[vec_idx], haddr_t, sf_offset[idx], int64_t); - H5_CHECKED_ASSIGN(io_sizes[vec_idx], size_t, sf_data_size[idx], int64_t); - io_bufs[vec_idx] = ((const char *)buf + source_data_offset[idx]); - - next_subfile_idx = (next_subfile_idx + 1) % num_subfiles; - - /* Skip 0-sized I/Os */ - if (io_sizes[vec_idx] == 0) { - final_vec_len--; - continue; - } - - vec_idx++; - } - - /* Make vector write call to subfile */ - if (H5FD_write_vector(file_ptr->sf_file, final_vec_len, io_types, io_addrs, io_sizes, - io_bufs) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "write to subfile failed"); - - /* - * Mirror superblock writes to the stub file so that - * legacy HDF5 applications can check what type of - * file they are reading - */ - if (file_ptr->mpi_rank == 0) { - for (size_t count_idx = 0; count_idx < (size_t)final_vec_len; count_idx++) { - if (io_types[count_idx] == H5FD_MEM_SUPER) { - if (H5FD_write(file_ptr->stub_file, H5FD_MEM_SUPER, io_addrs[count_idx], - io_sizes[count_idx], io_bufs[count_idx]) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, - "couldn't write superblock information to stub file"); - } - } - } - } - } - } + if (H5FD__subfiling_io_helper(file_ptr, 1, &type, &addr, &size, (H5_flexible_const_ptr_t *)&buf, + IO_TYPE_WRITE) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write to subfiles failed"); /* Point to the end of the current I/O */ addr += (haddr_t)size; @@ -1992,14 +1633,6 @@ H5FD__subfiling_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_ file_ptr->local_eof = file_ptr->pos; done: - free(io_bufs); - free(io_sizes); - free(io_addrs); - free(io_types); - free(sf_offset); - free(sf_data_size); - free(source_data_offset); - if (ret_value < 0) { /* Reset last file I/O information */ file_ptr->pos = HADDR_UNDEF; @@ -2048,31 +1681,21 @@ H5FD__subfiling_read_vector(H5FD_t *_file, hid_t dxpl_id, uint32_t count, H5FD_m size_t sizes[], void *bufs[] /* out */) { H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file; - H5FD_mpio_xfer_t xfer_mode = H5FD_MPIO_INDEPENDENT; - herr_t ret_value = SUCCEED; /* Return value */ - - /* Check arguments - * RAW - Do we really need to check arguments once again? - * These have already been checked in H5FD__subfiling_read_vector (see below)! - */ - if (!file_ptr) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL"); - - if ((!types) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "types parameter can't be NULL if count is positive"); - - if ((!addrs) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "addrs parameter can't be NULL if count is positive"); + herr_t ret_value = SUCCEED; - if ((!sizes) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "sizes parameter can't be NULL if count is positive"); + assert(file_ptr); + assert(file_ptr->pub.driver_id == H5FD_SUBFILING); + assert((types) || (count == 0)); + assert((addrs) || (count == 0)); + assert((sizes) || (count == 0)); + assert((bufs) || (count == 0)); - if ((!bufs) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "bufs parameter can't be NULL if count is positive"); + /* + * Verify that the first elements of the sizes and + * types arrays are valid. + */ + assert((count == 0) || (sizes[0] != 0)); + assert((count == 0) || (types[0] != H5FD_MEM_NOLIST)); /* Get the default dataset transfer property list if the user didn't provide one */ if (H5P_DEFAULT == dxpl_id) { @@ -2086,98 +1709,27 @@ H5FD__subfiling_read_vector(H5FD_t *_file, hid_t dxpl_id, uint32_t count, H5FD_m /* Set DXPL for operation */ H5CX_set_dxpl(dxpl_id); - /* TODO: setup real support for vector I/O */ if (file_ptr->fa.require_ioc) { - - bool extend_sizes = false; - bool extend_types = false; - int k; - size_t size; - H5FD_mem_t type; - haddr_t eoa; - - assert((count == 0) || (sizes[0] != 0)); - assert((count == 0) || (types[0] != H5FD_MEM_NOLIST)); - - if (H5CX_get_io_xfer_mode(&xfer_mode) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTGET, FAIL, - "can't determine I/O collectivity setting"); - - /* Currently, treat collective calls as independent */ - if (xfer_mode != H5FD_MPIO_INDEPENDENT) - if (H5CX_set_io_xfer_mode(H5FD_MPIO_INDEPENDENT) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTSET, FAIL, "can't set I/O collectivity setting"); - - /* Note that the following code does not let the sub-filing VFD participate - * in collective calls when there is no data to write. This is not an issue - * now, as we don't do anything special with collective operations. However - * this needs to be fixed. - */ - for (k = 0; k < (int)count; k++) { - - if (!extend_sizes) { - - if (sizes[k] == 0) { - - extend_sizes = true; - size = sizes[k - 1]; - } - else { - - size = sizes[k]; - } - } - - if (!extend_types) { - - if (types[k] == H5FD_MEM_NOLIST) { - - extend_types = true; - type = types[k - 1]; - } - else { - - type = types[k]; - } - } - - if (HADDR_UNDEF == (eoa = H5FD__subfiling_get_eoa(_file, type))) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); - - if ((addrs[k] + size) > eoa) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addrs[%d] = %llu, sizes[%d] = %llu, eoa = %llu", - (int)k, (unsigned long long)(addrs[k]), (int)k, - (unsigned long long)size, (unsigned long long)eoa); - - if (H5FD__subfiling_read(_file, type, dxpl_id, addrs[k], size, bufs[k]) != SUCCEED) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file vector read request failed"); - } + if (H5FD__subfiling_io_helper(file_ptr, (size_t)count, types, addrs, sizes, + (H5_flexible_const_ptr_t *)bufs, IO_TYPE_READ) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't read data"); } else { - /* sec2 driver.. - * Call the subfiling 'direct write' version - * of subfiling. - */ - if (H5FD_read_vector(_file, count, types, addrs, sizes, bufs) != SUCCEED) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file vector read request failed"); + if (H5FD_read_vector(_file, count, types, addrs, sizes, bufs) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't read data"); } done: - if (xfer_mode != H5FD_MPIO_INDEPENDENT) - if (H5CX_set_io_xfer_mode(xfer_mode) < 0) - H5_SUBFILING_DONE_ERROR(H5E_CONTEXT, H5E_CANTSET, FAIL, "can't set I/O collectivity setting"); - H5_SUBFILING_FUNC_LEAVE_API; } /* end H5FD__subfiling_read_vector() */ /*------------------------------------------------------------------------- - * Function: H5FD__subfile_write_vector (internal function) + * Function: H5FD__subfiling_write_vector * * Purpose: Perform count writes to the specified file at the offsets - * provided in the addrs array. Lengths and memory - * types provided in the sizes and types arrays. Data to be - * written is referenced by the bufs array. + * provided in the addrs array. Lengths and memory types + * types are provided in the sizes and types arrays. Data to + * be written is referenced by the bufs array. * * All writes are done according to the data transfer property * list dxpl_id (which may be the constant H5P_DEFAULT). @@ -2190,17 +1742,6 @@ done: * input arguments are not valid, or the actual * subfiling writes have failed for some reason. * - * Notes: Thus function doesn't actually implement vector write. - * Instead, it converts the vector write call into a series - * of scalar read calls. Fix this when time permits. - * - * Also, it didn't support the sizes and types optimization. - * I implemented a version of this which is more generous - * than that currently defined in the RFC. This is good - * enough for now, but the final version should follow - * the RFC. - * JRM -- 10/5/21 - * *------------------------------------------------------------------------- */ static herr_t @@ -2208,33 +1749,21 @@ H5FD__subfiling_write_vector(H5FD_t *_file, hid_t dxpl_id, uint32_t count, H5FD_ haddr_t addrs[], size_t sizes[], const void *bufs[] /* in */) { H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file; - H5FD_mpio_xfer_t xfer_mode = H5FD_MPIO_INDEPENDENT; - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; - assert(file_ptr != NULL); /* sanity check */ + assert(file_ptr); + assert(file_ptr->pub.driver_id == H5FD_SUBFILING); + assert((types) || (count == 0)); + assert((addrs) || (count == 0)); + assert((sizes) || (count == 0)); + assert((bufs) || (count == 0)); - /* Check arguments - * RAW - Do we really need to check arguments once again? - * These have already been checked in H5FD__subfiling_write_vector (see below)! + /* + * Verify that the first elements of the sizes and + * types arrays are valid. */ - if (!file_ptr) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL"); - - if ((!types) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "types parameter can't be NULL if count is positive"); - - if ((!addrs) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "addrs parameter can't be NULL if count is positive"); - - if ((!sizes) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "sizes parameter can't be NULL if count is positive"); - - if ((!bufs) && (count > 0)) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "bufs parameter can't be NULL if count is positive"); + assert((count == 0) || (sizes[0] != 0)); + assert((count == 0) || (types[0] != H5FD_MEM_NOLIST)); /* Get the default dataset transfer property list if the user didn't provide one */ if (H5P_DEFAULT == dxpl_id) { @@ -2244,88 +1773,21 @@ H5FD__subfiling_write_vector(H5FD_t *_file, hid_t dxpl_id, uint32_t count, H5FD_ if (true != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list"); } - /* Call the subfiling IOC write*/ - if (file_ptr->fa.require_ioc) { - - bool extend_sizes = false; - bool extend_types = false; - int k; - size_t size; - H5FD_mem_t type; - haddr_t eoa; - - assert((count == 0) || (sizes[0] != 0)); - assert((count == 0) || (types[0] != H5FD_MEM_NOLIST)); - - if (H5CX_get_io_xfer_mode(&xfer_mode) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTGET, FAIL, - "can't determine I/O collectivity setting"); - - /* Currently, treat collective calls as independent */ - if (xfer_mode != H5FD_MPIO_INDEPENDENT) - if (H5CX_set_io_xfer_mode(H5FD_MPIO_INDEPENDENT) < 0) - H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTSET, FAIL, "can't set I/O collectivity setting"); - - /* Note that the following code does not let the sub-filing VFD participate - * in collective calls when there is no data to write. This is not an issue - * now, as we don't do anything special with collective operations. However - * this needs to be fixed. - */ - for (k = 0; k < (int)count; k++) { - - if (!extend_sizes) { - if (sizes[k] == 0) { - - extend_sizes = true; - size = sizes[k - 1]; - } - else { - - size = sizes[k]; - } - } - - if (!extend_types) { - - if (types[k] == H5FD_MEM_NOLIST) { - - extend_types = true; - type = types[k - 1]; - } - else { - - type = types[k]; - } - } - - if (HADDR_UNDEF == (eoa = H5FD__subfiling_get_eoa(_file, type))) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); - - if ((addrs[k] + size) > eoa) - H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addrs[%d] = %llu, sizes[%d] = %llu, eoa = %llu", - (int)k, (unsigned long long)(addrs[k]), (int)k, - (unsigned long long)size, (unsigned long long)eoa); + /* Set DXPL for operation */ + H5CX_set_dxpl(dxpl_id); - if (H5FD__subfiling_write(_file, type, dxpl_id, addrs[k], size, bufs[k]) != SUCCEED) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file vector write request failed"); - } + if (file_ptr->fa.require_ioc) { + if (H5FD__subfiling_io_helper(file_ptr, (size_t)count, types, addrs, sizes, + (H5_flexible_const_ptr_t *)bufs, IO_TYPE_WRITE) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "couldn't write data"); } else { - /* sec2 driver.. - * Call the subfiling 'direct write' version - * of subfiling. - */ - if (H5FD_write_vector(_file, count, types, addrs, sizes, bufs) != SUCCEED) - H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file vector write request failed"); + if (H5FD_write_vector(_file, count, types, addrs, sizes, bufs) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "couldn't write data"); } done: - if (xfer_mode != H5FD_MPIO_INDEPENDENT) - if (H5CX_set_io_xfer_mode(xfer_mode) < 0) - H5_SUBFILING_DONE_ERROR(H5E_CONTEXT, H5E_CANTSET, FAIL, "can't set I/O collectivity setting"); - H5_SUBFILING_FUNC_LEAVE_API; } /* end H5FDsubfile__write_vector() */ @@ -2581,138 +2043,918 @@ done: } /* end H5FD__subfiling_ctl() */ /*------------------------------------------------------------------------- - * Function: init_indep_io - * - * Purpose: Utility function to initialize the set of I/O transactions - * used to communicate with I/O concentrators for read and - * write I/O operations. - * - * Fills the I/O vectors contained in the output arrays - * `mem_buf_offset`, `target_file_offset` and `io_block_len`. - * As a consequence of not allowing use of MPI derived - * datatypes in the VFD layer, we need to accommodate the - * possibility that large I/O transactions will be required to - * use multiple I/Os per subfile. - * - * Example: Using 4 subfiles, each with 1M stripe-depth; when - * presented an I/O request for 8MB then at a minimum each - * subfile will require 2 I/Os of 1MB each. Depending on the - * starting file offset, the 2 I/Os can instead be 3... - * - * To fully describe the I/O transactions for reads and writes - * the output arrays are therefore arrays of I/O vectors, - * where each vector has a length of which corresponds to the - * max number of I/O transactions per subfile. In the example - * above, these vector lengths can be 2 or 3. The actual - * length is determined by the 'container_depth' variable. - * - * For I/O operations which involve a subset of subfiles, the - * vector entries for the unused subfiles will have lengths of - * zero and be empty. The 'container_depth' in this case will - * always be 1. + * Function: H5FD__subfiling_io_helper + * + * Purpose: Helper routine to manage the common portions of I/O between + * normal and vector I/O calls. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__subfiling_io_helper(H5FD_subfiling_t *file_ptr, size_t io_count, H5FD_mem_t types[], haddr_t addrs[], + size_t sizes[], H5_flexible_const_ptr_t bufs[], H5FD_subfiling_io_type_t io_type) +{ + H5_flexible_const_ptr_t *io_bufs = NULL; + subfiling_context_t *sf_context = NULL; + H5FD_mpio_xfer_t xfer_mode = H5FD_MPIO_INDEPENDENT; + H5FD_mem_t *io_types = NULL; + haddr_t *io_addrs = NULL; + size_t *io_sizes = NULL; + haddr_t file_eoa = HADDR_UNDEF; + size_t io_size = 0; + bool rank0_bcast = false; + bool extend_sizes = false; + int num_subfiles; + herr_t ret_value = SUCCEED; + + assert(file_ptr); + + if (HADDR_UNDEF == (file_eoa = H5FD__subfiling_get_eoa((const H5FD_t *)file_ptr, H5FD_MEM_DEFAULT))) + H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get file EOA"); + + /* Perform some sanity checking on the given (address, size) pairs */ + extend_sizes = false; + for (size_t i = 0; i < io_count; i++) { + if (!extend_sizes) { + if ((i > 0) && (sizes[i] == 0)) { + extend_sizes = true; + io_size = sizes[i - 1]; + } + else { + io_size = sizes[i]; + } + } + + if (!H5_addr_defined(addrs[i])) + H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr[%zu] undefined, addr = %" PRIuHADDR, + i, addrs[i]); + if (REGION_OVERFLOW(addrs[i], io_size)) + H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, + "addr[%zu] overflow, addr = %" PRIuHADDR ", size = %zu", i, addrs[i], + io_size); + if ((addrs[i] + io_size) > file_eoa) + H5_SUBFILING_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, + "addr overflow, addrs[%zu] = %" PRIuHADDR + ", sizes[%zu] = %zu, eoa = %" PRIuHADDR, + i, addrs[i], i, io_size, file_eoa); + } + + /* + * Temporarily reject collective I/O until support is + * implemented (unless types are simple MPI_BYTE), which + * can be properly handled here. + */ + if (H5CX_get_io_xfer_mode(&xfer_mode) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTGET, FAIL, "can't determine I/O collectivity setting"); + + if (xfer_mode == H5FD_MPIO_COLLECTIVE) { + MPI_Datatype btype, ftype; + + if (H5CX_get_mpi_coll_datatypes(&btype, &ftype) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_CONTEXT, H5E_CANTGET, FAIL, "can't get MPI-I/O datatypes"); + if (MPI_BYTE != btype || MPI_BYTE != ftype) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "collective I/O is currently unsupported"); + } + + /* + * If we reached here, we're still doing independent I/O regardless + * of collectivity setting, so set that. + */ + H5CX_set_io_xfer_mode(H5FD_MPIO_INDEPENDENT); + + /* Determine whether a rank 0 bcast approach has been requested */ + if (io_type == IO_TYPE_READ) + rank0_bcast = H5CX_get_mpio_rank0_bcast(); + + /* + * Retrieve the subfiling context object and the number + * of subfiles. + * + * Given the current I/O and the I/O concentrator info, + * we can determine some I/O transaction parameters. + * In particular, for large I/O operations, each IOC + * may require multiple I/Os to fulfill the user I/O + * request. The block size and number of IOCs are used + * to size the vectors that will be used to invoke the + * underlying I/O operations. + */ + if (NULL == (sf_context = (subfiling_context_t *)H5_get_subfiling_object(file_ptr->context_id))) + H5_SUBFILING_GOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, + "invalid or missing subfiling context object"); + assert(sf_context->topology); + + if ((num_subfiles = sf_context->sf_num_subfiles) <= 0) + H5_SUBFILING_GOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "invalid number of subfiles (%d)", + num_subfiles); + + if (num_subfiles == 1) { + uint32_t u32_io_count; + + /*************************************** + * No striping - just a single subfile * + ***************************************/ + + /* + * Convert the I/O count back to a uint32_t for the vector I/O + * call until the interface can possibly be changed to use size_t + * in the future + */ + H5_CHECKED_ASSIGN(u32_io_count, uint32_t, io_count, size_t); + + if (io_type == IO_TYPE_WRITE) { + /* Make vector write call to VFD controlling subfiles */ + if (H5FD_write_vector(file_ptr->sf_file, u32_io_count, types, addrs, sizes, (const void **)bufs) < + 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write to subfile failed"); + + /* + * Mirror superblock writes to the stub file so that + * legacy HDF5 applications can check what type of + * file they are reading + */ + if (H5FD__subfiling_mirror_writes_to_stub(file_ptr, u32_io_count, types, addrs, sizes, + (const void **)bufs) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mirrored write to stub file failed"); + } + else { + /* Make vector read call to VFD controlling subfiles */ + if (H5FD_read_vector(file_ptr->sf_file, u32_io_count, types, addrs, sizes, (void **)bufs) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "read from subfile failed"); + } + } + else { + uint32_t iovec_len; + size_t ioreq_count = 0; + herr_t status; + + /************************************* + * Striping across multiple subfiles * + *************************************/ + + /* + * Generate the types, addrs, sizes and bufs I/O vectors for + * this I/O request. + */ + status = generate_io_vectors( + sf_context, /* IN: Subfiling context used to look up config info */ + io_count, /* IN: Number of entries in `types`, `addrs`, `sizes` and `bufs` */ + types, /* IN: Array of memory types */ + addrs, /* IN: Array of starting file offsets */ + sizes, /* IN: Array of I/O sizes (in terms of elements) */ + bufs, /* IN: Array of I/O buffers */ + 1, /* IN: Data extent of the 'type'; byte is assumed currently */ + io_type, /* IN: Type of I/O being performed (IO_TYPE_WRITE or IO_TYPE_READ) */ + &ioreq_count, /* OUT: Number of I/O requests to be made */ + &iovec_len, /* OUT: Number of elements in I/O vector for a single I/O request */ + &io_types, /* OUT: I/O vector of memory types for each I/O entry */ + &io_addrs, /* OUT: I/O vector of file addresses for each I/O entry */ + &io_sizes, /* OUT: I/O vector of I/O sizes for each I/O entry */ + &io_bufs); /* OUT: I/O vector of buffers for each I/O entry */ + + if (status < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't initialize I/O vectors"); + + /* Nothing to do + * + * TODO: Note that this does not let the sub-filing VFD participate in + * collective calls when there is no data to write. This is not an issue + * now, as we don't do anything special with collective operations. + * However, this needs to be fixed. + */ + if (ioreq_count == 0) + H5_SUBFILING_GOTO_DONE(SUCCEED); + +#ifdef H5_SUBFILING_DEBUG + H5_subfiling_dump_iovecs(sf_context, ioreq_count, iovec_len, io_type, io_types, io_addrs, io_sizes, + io_bufs); +#endif + + /* clang-format off */ + /* + * Having now populated the I/O vectors for this I/O request and + * having determined how many I/O calls need to be made to satisfy + * the entire I/O request, loop that many times, making an I/O call + * with each set of I/O vectors. Each I/O call uses a set of I/O + * vectors with a length of up to 'number of subfiles' elements and + * each I/O call's I/O vectors are setup to ensure that the I/O is + * spread across as many subfiles as possible for each iteration. In + * the simple case of N evenly-distributed and well-aligned I/O + * requests being performed on 4 subfiles, this can be visualized as + * the following: + * + * I/O REQ. 0 I/O REQ. 1 ... I/O REQ. N-1 + * || || || + * VV VV VV + * {IOVEC[0]} {IOVEC[4]} ... {IOVEC[(N-1 * iovec_len)]} -> SUBFILE 0 + * {IOVEC[1]} {IOVEC[5]} ... {IOVEC[(N-1 * iovec_len) + 1]} -> SUBFILE 1 + * {IOVEC[2]} {IOVEC[6]} ... {IOVEC[(N-1 * iovec_len) + 2]} -> SUBFILE 2 + * {IOVEC[3]} {IOVEC[7]} ... {IOVEC[(N-1 * iovec_len) + 3]} -> SUBFILE 3 + * + * where {IOVEC[X]} represents an I/O vector composed of the entries + * at index X of io_types, io_addrs, io_sizes and io_bufs. Note that + * the entire set of I/O vectors, e.g. [ {IOVEC[0]}, {IOVEC[1]}, {IOVEC[2]}, {IOVEC[3]} ] + * from the above visualization will be sent to the underlying I/O + * concentrator VFD in a single I/O call on each iteration. That VFD is + * ultimately responsible for mapping each I/O vector to its corresponding + * subfile (here, pointed to by '->' to the right of each I/O vector). + */ + /* clang-format on */ + for (size_t ioreq_idx = 0; ioreq_idx < ioreq_count; ioreq_idx++) { + H5_flexible_const_ptr_t *io_bufs_ptr = NULL; + H5FD_mem_t *io_types_ptr = NULL; + uint32_t final_vec_len = iovec_len; + haddr_t *io_addrs_ptr = NULL; + size_t *io_sizes_ptr = NULL; + + /* Setup index into I/O vectors for this I/O operation */ + io_types_ptr = &io_types[ioreq_idx * iovec_len]; + io_addrs_ptr = &io_addrs[ioreq_idx * iovec_len]; + io_sizes_ptr = &io_sizes[ioreq_idx * iovec_len]; + io_bufs_ptr = &io_bufs[ioreq_idx * iovec_len]; + + /* Skip 0-sized I/Os */ + for (size_t vec_idx = 0; vec_idx < iovec_len; vec_idx++) + if (io_sizes_ptr[vec_idx] == 0) + final_vec_len--; + + if (io_type == IO_TYPE_WRITE) { + /* Make vector write call to VFD controlling subfiles */ + if (H5FD_write_vector(file_ptr->sf_file, final_vec_len, io_types_ptr, io_addrs_ptr, + io_sizes_ptr, (const void **)io_bufs_ptr) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write to subfile failed"); + + /* + * Mirror superblock writes to the stub file so that + * legacy HDF5 applications can check what type of + * file they are reading + */ + if (H5FD__subfiling_mirror_writes_to_stub(file_ptr, final_vec_len, io_types_ptr, io_addrs_ptr, + io_sizes_ptr, (const void **)io_bufs_ptr) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, + "mirrored write to stub file failed"); + } + else { + if (!rank0_bcast || (file_ptr->mpi_rank == 0)) { + /* Make vector read call to VFD controlling subfiles */ + if (H5FD_read_vector(file_ptr->sf_file, final_vec_len, io_types_ptr, io_addrs_ptr, + io_sizes_ptr, (void **)io_bufs_ptr) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "read from subfile failed"); + } + } + } + + if (rank0_bcast && (file_ptr->mpi_size > 1)) { + size_t size; + + assert(io_type == IO_TYPE_READ); + + extend_sizes = false; + for (size_t i = 0; i < io_count; i++) { + if (!extend_sizes) { + if ((i > 0) && (sizes[i] == 0)) { + extend_sizes = true; + size = sizes[i - 1]; + } + else { + size = sizes[i]; + } + } + + H5_CHECK_OVERFLOW(size, size_t, int); + if (MPI_SUCCESS != MPI_Bcast(bufs[i].vp, (int)size, MPI_BYTE, 0, file_ptr->comm)) + H5_SUBFILING_GOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't broadcast data from rank 0"); + } + } + } + +done: + /* Restore original transfer mode if we changed it */ + if (xfer_mode != H5FD_MPIO_INDEPENDENT) + if (H5CX_set_io_xfer_mode(xfer_mode) < 0) + H5_SUBFILING_DONE_ERROR(H5E_CONTEXT, H5E_CANTSET, FAIL, "can't set I/O collectivity setting"); + + free(io_bufs); + free(io_sizes); + free(io_addrs); + free(io_types); + + H5_SUBFILING_FUNC_LEAVE; +} + +/*------------------------------------------------------------------------- + * Function: H5FD__subfiling_mirror_writes_to_stub + * + * Purpose: Mirrors write calls to the Subfiling stub file so that + * legacy HDF5 applications can check what type of file they + * are reading. Only superblock I/O is mirrored to the stub + * file and only if that I/O comes from MPI rank 0. This + * means that file metadata could be missed if it comes from + * other MPI ranks (such as when using a distributed metadata + * write strategy), but, at least currently, we generally only + * care about the first few bytes of the file being properly + * written to the stub file. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__subfiling_mirror_writes_to_stub(H5FD_subfiling_t *file_ptr, uint32_t count, H5FD_mem_t types[], + haddr_t addrs[], size_t sizes[], const void *bufs[]) +{ + const void **copied_bufs = NULL; + H5FD_mem_t *copied_types = NULL; + haddr_t *copied_addrs = NULL; + size_t *copied_sizes = NULL; + H5FD_mem_t type = H5FD_MEM_DEFAULT; + size_t io_size = 0; + bool all_super_writes = true; + bool some_super_writes = false; + bool extend_types = false; + bool extend_sizes = false; + herr_t ret_value = SUCCEED; + + assert(file_ptr); + + /* Only mirror I/O from MPI rank 0 */ + if (file_ptr->mpi_rank != 0) + H5_SUBFILING_GOTO_DONE(SUCCEED); + + if (count == 0) + H5_SUBFILING_GOTO_DONE(SUCCEED); + + for (size_t i = 0; i < count; i++) { + if (!extend_types) { + if ((i > 0) && (types[i] == H5FD_MEM_NOLIST)) { + extend_types = true; + type = types[i - 1]; + } + else { + type = types[i]; + } + } + + if (type == H5FD_MEM_SUPER) + some_super_writes = true; + else + all_super_writes = false; + + /* + * If we find H5FD_MEM_NOLIST, we don't need to + * keep looking through the array entries + */ + if (extend_types) + break; + } + + if (all_super_writes) { + if (H5FD_write_vector(file_ptr->stub_file, count, types, addrs, sizes, bufs) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, + "couldn't write superblock information to stub file"); + } + else if (some_super_writes) { + uint32_t vec_len = 0; + + /* Copy I/O vectors and strip out non-superblock I/O */ + + if (NULL == (copied_types = malloc(count * sizeof(*copied_types)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "can't allocate copy of I/O types array"); + if (NULL == (copied_addrs = malloc(count * sizeof(*copied_addrs)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "can't allocate copy of I/O addresses array"); + if (NULL == (copied_sizes = malloc(count * sizeof(*copied_sizes)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "can't allocate copy of I/O sizes array"); + if (NULL == (copied_bufs = malloc(count * sizeof(*copied_bufs)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "can't allocate copy of I/O buffers array"); + + extend_types = false; + extend_sizes = false; + for (size_t i = 0; i < count; i++) { + if (!extend_types) { + if ((i > 0) && (types[i] == H5FD_MEM_NOLIST)) { + extend_types = true; + type = types[i - 1]; + + /* End early if none of the remaining memory types are H5FD_MEM_SUPER */ + if (type != H5FD_MEM_SUPER) + break; + } + else { + type = types[i]; + } + } + + if (!extend_sizes) { + if ((i > 0) && (sizes[i] == 0)) { + extend_sizes = true; + io_size = sizes[i - 1]; + } + else { + io_size = sizes[i]; + } + } + + if (type != H5FD_MEM_SUPER) + continue; + + copied_types[vec_len] = type; + copied_addrs[vec_len] = addrs[i]; + copied_sizes[vec_len] = io_size; + copied_bufs[vec_len] = bufs[i]; + + vec_len++; + } + + if ((vec_len > 0) && (H5FD_write_vector(file_ptr->stub_file, vec_len, copied_types, copied_addrs, + copied_sizes, copied_bufs) < 0)) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, + "couldn't write superblock information to stub file"); + } + +done: + free(copied_bufs); + free(copied_sizes); + free(copied_addrs); + free(copied_types); + + H5_SUBFILING_FUNC_LEAVE; +} + +/*------------------------------------------------------------------------- + * Function: generate_io_vectors + * + * Purpose: Given an array of memory types, an array of file offsets, + * an array of the number of I/O elements for each file + * offset and an array of I/O buffers, translates each (type, + * offset, number of elements, I/O buffer) tuple into a set of + * I/O vectors according to the subfiling configuration + * specified in `sf_context`. These I/O vectors are generated + * such that a set of `iovec_len` elements from each of + * `io_types`, `io_addrs`, `io_sizes` and `io_bufs` can be + * passed to H5FD_write_vector/H5FD_read_vector and that I/O + * call will span as many subfiles as possible, parallelizing + * the I/O. Then, the next set of `iovec_len` elements can be + * passed and so on, until the whole I/O request has been + * parallelized across the subfiles. Once this function + * returns, `io_types`, `io_addrs`, `io_sizes` and `io_bufs` + * will each contain `ioreq_count` sets of I/O vectors, with + * each set containing `iovec_len` elements. * * sf_context (IN) * - the subfiling context for the file * - * file_offset (IN) - * - the starting file offset for I/O + * in_count (IN) + * - the number of entries in the `types`, `file_offsets`, + * `nelemts` and `bufs` arrays + * + * types (IN) + * - the memory types for each I/O entry + * + * file_offsets (IN) + * - array of starting file offsets for I/O + * + * nelemts (IN) + * - array of the number of data elements for the I/O + * operation * - * io_nelemts (IN) - * - the number of data elements for the I/O operation + * bufs (IN) + * - array of the I/O buffers to use for each I/O entry * * dtype_extent (IN) * - the extent of the datatype of each data element for - * the I/O operation - * - * max_iovec_len (IN) - * - the maximum size for a single I/O vector in each of - * the output arrays `mem_buf_offset`, `io_block_len` - * and `sf_offset`. NOTE that this routine expects each - * of these output arrays to have enough space allocated - * for one I/O vector PER subfile. Therefore, the total - * size of each output array should be at least - * `max_iovec_len * num_subfiles`. - * - * mem_buf_offset (OUT) - * - output array of vectors (one vector for each subfile) - * containing the set of offsets into the memory buffer - * for I/O - * - * target_file_offset (OUT) - * - output array of vectors (one vector for each subfile) - * containing the set of offsets into the target file - * - * io_block_len (OUT) - * - output array of vectors (one vector for each subfile) - * containing the set of block lengths for each source - * buffer/target file offset. - * - * first_subfile_index (OUT) - * - the index of the first subfile that this I/O operation - * begins at - * - * n_subfiles_used (OUT) - * - the number of subfiles actually used for this I/O - * operation, which may be different from the total - * number of subfiles for the file - * - * max_io_req_per_subfile (OUT) - * - the maximum number of I/O requests to any particular - * subfile, or the maximum "depth" of each I/O vector - * in the output arrays. + * the I/O operation (currently assumed to be 1, meaning + * entries in `nelemts` are expressed in terms of + * bytes) + * + * io_type (IN) + * - the type of I/O being performed (IO_TYPE_WRITE or + * IO_TYPE_READ) + * + * ioreq_count (OUT) + * - the number of I/O requests needed to fully satisfy the + * I/O operation + * + * iovec_len (OUT) + * - the size of each I/O vector (in terms of array elements) + * for each I/O request to be made + * + * io_types (OUT) + * - I/O vector of memory types for the I/O operation. + * Allocated by this function and must be freed by the + * caller. + * + * io_addrs (OUT) + * - I/O vector of file addresses for the I/O operation. + * Allocated by this function and must be freed by the + * caller. + * + * io_sizes (OUT) + * - I/O vector of the I/O sizes for the I/O operation. + * Allocated by this function and must be freed by the + * caller. + * + * io_bufs (OUT) + * - I/O vector of the I/O buffers for the I/O operation. + * Allocated by this function and must be freed by the + * caller. * * Return: Non-negative on success/Negative on failure * - *------------------------------------------------------------------------- */ static herr_t -init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_nelemts, size_t dtype_extent, - size_t max_iovec_len, int64_t *mem_buf_offset, int64_t *target_file_offset, - int64_t *io_block_len, int *first_subfile_index, int *n_subfiles_used, - int64_t *max_io_req_per_subfile) +generate_io_vectors(subfiling_context_t *sf_context, size_t in_count, H5FD_mem_t types[], + haddr_t file_offsets[], size_t nelemts[], H5_flexible_const_ptr_t bufs[], + size_t dtype_extent, H5FD_subfiling_io_type_t io_type, size_t *ioreq_count, + uint32_t *iovec_len, H5FD_mem_t **io_types, haddr_t **io_addrs, size_t **io_sizes, + H5_flexible_const_ptr_t **io_bufs) +{ + H5_flexible_const_ptr_t *loc_io_bufs = NULL; + H5FD_mem_t *loc_io_types = NULL; + H5FD_mem_t mem_type = H5FD_MEM_DEFAULT; + haddr_t *loc_io_addrs = NULL; + size_t *loc_io_sizes = NULL; + size_t max_iovec_depth = 0; + size_t max_num_subfiles_touched = 0; + size_t tot_iovec_len = 0; + size_t io_size = 0; + bool extend_sizes = false; + bool extend_types = false; + herr_t ret_value = SUCCEED; + + assert(sf_context); + assert(sf_context->sf_stripe_size > 0); + assert(sf_context->sf_blocksize_per_stripe > 0); + assert(sf_context->sf_num_subfiles > 0); + assert(sf_context->topology); + assert((types) || (in_count == 0)); + assert((file_offsets) || (in_count == 0)); + assert((nelemts) || (in_count == 0)); + assert((bufs) || (in_count == 0)); + assert(dtype_extent == 1); /* For now, assume 'byte'-sized elements */ + assert(ioreq_count); + assert(iovec_len); + assert(io_types); + assert(io_addrs); + assert(io_sizes); + assert(io_bufs); + + /* Set some returned values early */ + *ioreq_count = 0; + *iovec_len = 0; + + /* Nothing to do */ + if (in_count == 0) + H5_SUBFILING_GOTO_DONE(SUCCEED); + + /* + * Do some initial pre-processing to determine how large of + * I/O vectors we will need to allocate to satisfy the + * entire I/O request + */ + get_iovec_sizes(sf_context, in_count, file_offsets, nelemts, dtype_extent, &max_iovec_depth, + &max_num_subfiles_touched); + + tot_iovec_len = in_count * max_iovec_depth * max_num_subfiles_touched; + +#ifdef H5_SUBFILING_DEBUG + H5_subfiling_log( + sf_context->sf_context_id, + "%s: I/O count: %zu, max_iovec_depth = %zu, max_num_subfiles_touched = %zu, iovec_len = %zu", + __func__, in_count, max_iovec_depth, max_num_subfiles_touched, tot_iovec_len); +#endif + + /* Allocate I/O vectors that will be returned to the caller */ + if (NULL == (loc_io_types = calloc(1, tot_iovec_len * sizeof(*loc_io_types)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate subfile I/O types vector"); + if (NULL == (loc_io_addrs = calloc(1, tot_iovec_len * sizeof(*loc_io_addrs)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "can't allocate subfile I/O addresses vector"); + if (NULL == (loc_io_sizes = calloc(1, tot_iovec_len * sizeof(*loc_io_sizes)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate subfile I/O sizes vector"); + if (NULL == (loc_io_bufs = calloc(1, tot_iovec_len * sizeof(*loc_io_bufs)))) + H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + "can't allocate subfile I/O buffers vector"); + + /* + * Populate the I/O vectors by looping through each + * of the (type, addrs, I/O size, buf) tuples + */ + for (size_t io_idx = 0; io_idx < in_count; io_idx++) { + size_t iovec_idx; + + iovec_idx = (io_idx * max_iovec_depth * max_num_subfiles_touched); + assert(iovec_idx < tot_iovec_len); + + if (!extend_types) { + if ((io_idx > 0) && (types[io_idx] == H5FD_MEM_NOLIST)) { + extend_types = true; + mem_type = types[io_idx - 1]; + } + else { + mem_type = types[io_idx]; + } + } + + if (!extend_sizes) { + if ((io_idx > 0) && (nelemts[io_idx] == 0)) { + extend_sizes = true; + io_size = nelemts[io_idx - 1] * dtype_extent; + } + else { + io_size = nelemts[io_idx] * dtype_extent; + } + } + + if (translate_io_req_to_iovec(sf_context, iovec_idx, max_num_subfiles_touched, max_iovec_depth, + mem_type, file_offsets[io_idx], io_size, bufs[io_idx], io_type, + loc_io_types, loc_io_addrs, loc_io_sizes, loc_io_bufs) < 0) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't translate I/O request to I/O vectors"); + } + + *ioreq_count = in_count * max_iovec_depth; + H5_CHECK_OVERFLOW(max_num_subfiles_touched, size_t, uint32_t); + *iovec_len = (uint32_t)max_num_subfiles_touched; + *io_types = loc_io_types; + *io_addrs = loc_io_addrs; + *io_sizes = loc_io_sizes; + *io_bufs = loc_io_bufs; + +done: + if (ret_value < 0) { + free(loc_io_bufs); + free(loc_io_sizes); + free(loc_io_addrs); + free(loc_io_types); + } + + H5_SUBFILING_FUNC_LEAVE; +} + +/*------------------------------------------------------------------------- + * Function: get_iovec_sizes + * + * Purpose: Helper routine to determine the maximum I/O vector depth + * (in terms of array elements) and maximum number of subfiles + * touched for any particular piece of an I/O request. This + * info is used to calculate the total size of I/O vectors we + * need to allocate to satisfy an entire I/O request. + * + * Return: Maximum I/O vector depth and maximum number of subfiles + * touched (can't fail) + * + *------------------------------------------------------------------------- + */ +static void +get_iovec_sizes(subfiling_context_t *sf_context, size_t in_count, haddr_t file_offsets[], size_t nelemts[], + size_t dtype_extent, size_t *max_iovec_depth, size_t *max_num_subfiles) { int64_t stripe_size = 0; int64_t block_size = 0; - int64_t data_size = 0; + size_t loc_max_iovec_depth = 0; + size_t loc_max_num_subfiles = 0; + int num_subfiles = 0; + + assert(sf_context); + assert(file_offsets); + assert(nelemts); + assert(max_iovec_depth); + assert(max_num_subfiles); + + stripe_size = sf_context->sf_stripe_size; + block_size = sf_context->sf_blocksize_per_stripe; + num_subfiles = sf_context->sf_num_subfiles; + + for (size_t io_idx = 0; io_idx < in_count; io_idx++) { + int64_t stripe_idx; + int64_t final_stripe_idx; + int64_t cur_file_offset; + int64_t final_offset; + int64_t data_size; + int64_t first_subfile; + int64_t last_subfile; + int64_t row_stripe_idx_start; + int64_t row_stripe_idx_final; + int64_t cur_max_num_subfiles; + size_t cur_iovec_depth; + + H5_CHECKED_ASSIGN(cur_file_offset, int64_t, file_offsets[io_idx], haddr_t); + H5_CHECKED_ASSIGN(data_size, int64_t, (nelemts[io_idx] * dtype_extent), size_t); + + /* + * Calculate the following from the starting file offset: + * + * stripe_idx + * - a stripe "index" given by the file offset divided by the + * stripe size. Note that when the file offset equals or exceeds + * the block size, we simply wrap around. So, for example, if 4 + * subfiles are being used with a stripe size of 1KiB, the block + * size would be 4KiB and file offset 4096 would have a stripe + * index of 4 and reside in the same subfile as stripe index 0 + * (offsets 0-1023) + * final_offset + * - the last offset in the virtual file covered by this I/O + * operation. Simply the I/O size added to the starting file + * offset. + */ + stripe_idx = cur_file_offset / stripe_size; + final_offset = cur_file_offset + data_size; + + /* Determine which subfile the I/O request begins in */ + first_subfile = stripe_idx % num_subfiles; + + /* + * Determine the stripe "index" of the last offset in the + * virtual file and, from that, determine the subfile that + * the I/O request ends in. + */ + final_stripe_idx = final_offset / stripe_size; + last_subfile = final_stripe_idx % num_subfiles; + + /* + * Determine how "deep" the resulting I/O vectors are at + * most by calculating the maximum number of "rows" spanned + * for any particular subfile; e.g. the maximum number of + * I/O requests for any particular subfile + */ + row_stripe_idx_start = stripe_idx - first_subfile; + row_stripe_idx_final = final_stripe_idx - last_subfile; + cur_iovec_depth = (size_t)((row_stripe_idx_final - row_stripe_idx_start) / num_subfiles) + 1; + + /* + * If the I/O request "wrapped around" and ends in a subfile + * less than the subfile we started in, subtract one from the + * I/O vector length to account for "empty space". This can be + * visualized as follows: + * + * SUBFILE 0 SUBFILE 1 SUBFILE 2 SUBFILE 3 + * _______________________________________________ + * | | | XXXXX | XXXXX | ROW 0 + * | XXXXX | XXXXX | XXXXX | XXXXX | ROW 1 + * | XXXXX | XXXXX | | | ROW 2 + * | | | | | ROW ... + * | | | | | + * | | | | | + * | | | | | + * |___________|___________|___________|___________| + * + * Here, `stripe_idx` would be calculated as 2 (I/O begins in + * the 3rd stripe, or subfile index 2), `first_subfile` would be + * calculated as 2 and the starting "row" (row_stripe_idx_start) + * would be calculated as "row" index 0. `final_stripe_idx` would + * be calculated as 9, `last_subfile` would be calculated as + * (9 % 4) = 1 and the ending "row" (row_stripe_idx_final) would + * be calculated as (9 - 1) = 8. Thus, the calculated I/O vector + * length would be ((8 - 0) / 4) + 1 = 3. However, since there is + * no I/O to stripe indices 0 and 1 (residing in "row" 0 of subfile + * index 0 and 1, respectively), it can be seen that the real I/O + * vector length is 2. + */ + if (last_subfile < first_subfile) + cur_iovec_depth--; + + loc_max_iovec_depth = MAX(cur_iovec_depth, loc_max_iovec_depth); + + /* + * Determine the maximum number of subfiles this piece of the + * I/O request could touch + */ + if (data_size >= block_size) { + /* + * I/O of a size greater than the block size definitionally + * touches all subfiles at least once. + */ + cur_max_num_subfiles = (size_t)num_subfiles; + } + else if (data_size < stripe_size) { + /* + * I/O of a size smaller than the stripe size could + * touch one or two subfiles at most, depending on + * the file offset. + */ + cur_max_num_subfiles = 2; + } + else { + /* + * I/O of a size smaller than the block size, but larger + * than or equal to the stripe size must touch at least + * (data_size / stripe_size) subfiles, but could touch + * an additional subfile, depending on the file offset. + */ + cur_max_num_subfiles = (((cur_file_offset % stripe_size) + data_size - 1) / stripe_size) + 1; + } + + loc_max_num_subfiles = MAX((size_t)cur_max_num_subfiles, loc_max_num_subfiles); + } + + *max_iovec_depth = loc_max_iovec_depth; + *max_num_subfiles = loc_max_num_subfiles; +} + +/*------------------------------------------------------------------------- + * Function: translate_io_req_to_iovec + * + * Purpose: Helper routine to perform the translation between an I/O + * request (type, addr, size, buf tuple) and a set of I/O + * vectors that spans all the subfiles touched by that I/O + * request. Once finished, this function will have generated + * at most `iovec_count` sets of I/O vectors, each containing + * `iovec_len` elements, but a smaller number of I/O vector + * sets could be generated, depending on the I/O request. + * + * sf_context (IN) + * - the subfiling context for the file + * + * iovec_idx (IN) + * - the index into `io_types`, `io_addrs`, `io_sizes` and + * `io_bufs` where this function should begin filling in + * the I/O vectors + * + * iovec_len (IN) + * - the number of elements in each I/O vector generated + * + * iovec_count (IN) + * - the maximum number of I/O vectors to be generated, as + * calculated in generate_io_vectors() + * + * type (IN) + * - the memory type to use for each component of the I/O + * vectors generated + * + * addr (IN) + * - the starting file offset used to generate the I/O + * vectors + * + * io_size (IN) + * - the size of the I/O to the given file offset, which is + * used when generating the I/O vectors + * + * io_buf (IN) + * - the I/O buffer to be partitioned up while generating + * the I/O vectors + * + * io_type (IN) + * - the type of I/O being performed (IO_TYPE_WRITE or + * IO_TYPE_READ) + * + * io_types (OUT) + * - pointer to the memory types I/O vector to populate + * + * io_addrs (OUT) + * - pointer to the file offsets I/O vector to populate + * + * io_sizes (OUT) + * - pointer to the I/O sizes I/O vector to populate + * + * io_bufs (OUT) + * - pointer to the I/O buffers I/O vector to populate + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +translate_io_req_to_iovec(subfiling_context_t *sf_context, size_t iovec_idx, size_t iovec_len, + size_t iovec_count, H5FD_mem_t type, haddr_t addr, size_t io_size, + H5_flexible_const_ptr_t io_buf, H5FD_subfiling_io_type_t io_type, + H5FD_mem_t *io_types, haddr_t *io_addrs, size_t *io_sizes, + H5_flexible_const_ptr_t *io_bufs) +{ int64_t stripe_idx = 0; int64_t final_stripe_idx = 0; - int64_t curr_stripe_idx = 0; + int64_t stripe_size = 0; + int64_t block_size = 0; + int64_t file_offset = 0; int64_t offset_in_stripe = 0; int64_t offset_in_block = 0; int64_t final_offset = 0; int64_t start_length = 0; int64_t final_length = 0; - int64_t first_subfile = 0; - int64_t last_subfile = 0; + int64_t first_subfile_idx = 0; + int64_t last_subfile_idx = 0; int64_t start_row = 0; int64_t row_offset = 0; int64_t row_stripe_idx_start = 0; int64_t row_stripe_idx_final = 0; + int64_t cur_stripe_idx = 0; int64_t max_iovec_depth = 0; - int64_t curr_max_iovec_depth = 0; - int64_t total_bytes = 0; int64_t mem_offset = 0; + size_t total_bytes = 0; int num_subfiles = 0; herr_t ret_value = SUCCEED; assert(sf_context); - assert(sf_context->sf_stripe_size > 0); - assert(sf_context->sf_blocksize_per_stripe > 0); - assert(sf_context->sf_num_subfiles > 0); - assert(sf_context->topology); - assert(mem_buf_offset); - assert(target_file_offset); - assert(io_block_len); - assert(first_subfile_index); - assert(n_subfiles_used); - assert(max_io_req_per_subfile); - - *first_subfile_index = 0; - *n_subfiles_used = 0; - *max_io_req_per_subfile = 0; + assert(io_types); + assert(io_addrs); + assert(io_sizes); + assert(io_bufs); /* - * Retrieve the needed fields from the subfiling context. + * Retrieve some needed fields from the subfiling context. * * stripe_size * - the size of the data striping across the file's subfiles @@ -2723,15 +2965,13 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne * num_subfiles * - the total number of subfiles for the logical * HDF5 file - * num_io_concentrators - * - the number of I/O concentrators currently being - * used */ stripe_size = sf_context->sf_stripe_size; block_size = sf_context->sf_blocksize_per_stripe; num_subfiles = sf_context->sf_num_subfiles; - H5_CHECKED_ASSIGN(data_size, int64_t, (io_nelemts * dtype_extent), size_t); + H5_CHECKED_ASSIGN(file_offset, int64_t, addr, haddr_t); + H5_CHECK_OVERFLOW(io_size, size_t, int64_t); /* * Calculate the following from the starting file offset: @@ -2740,8 +2980,8 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne * - a stripe "index" given by the file offset divided by the * stripe size. Note that when the file offset equals or exceeds * the block size, we simply wrap around. So, for example, if 4 - * subfiles are being used with a stripe size of 1MiB, the block - * size would be 4MiB and file offset 4096 would have a stripe + * subfiles are being used with a stripe size of 1KiB, the block + * size would be 4KiB and file offset 4096 would have a stripe * index of 4 and reside in the same subfile as stripe index 0 * (offsets 0-1023) * offset_in_stripe @@ -2752,17 +2992,22 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne * subfiles * final_offset * - the last offset in the virtual file covered by this I/O - * operation. Simply the I/O size added to the starting file - * offset. + * request. Simply the I/O size minus one byte added to the + * starting file offset. */ stripe_idx = file_offset / stripe_size; offset_in_stripe = file_offset % stripe_size; offset_in_block = file_offset % block_size; - final_offset = file_offset + data_size; + final_offset = file_offset + (int64_t)(io_size > 0 ? io_size - 1 : 0); /* Determine the size of data written to the first and last stripes */ - start_length = MIN(data_size, (stripe_size - offset_in_stripe)); - final_length = (start_length == data_size ? 0 : final_offset % stripe_size); + start_length = MIN((int64_t)io_size, (stripe_size - offset_in_stripe)); + if (start_length == (int64_t)io_size) + final_length = 0; + else if (((final_offset + 1) % stripe_size) == 0) + final_length = stripe_size; + else + final_length = (final_offset + 1) % stripe_size; assert(start_length <= stripe_size); assert(final_length <= stripe_size); @@ -2776,9 +3021,9 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne * file offsets that are multiples of the block size begin a new * "row". */ - start_row = stripe_idx / num_subfiles; - first_subfile = stripe_idx % num_subfiles; - H5_CHECK_OVERFLOW(first_subfile, int64_t, int); + start_row = stripe_idx / num_subfiles; + first_subfile_idx = stripe_idx % num_subfiles; + H5_CHECK_OVERFLOW(first_subfile_idx, int64_t, int); /* * Set initial file offset for starting "row" @@ -2792,34 +3037,62 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne * the I/O request ends in. */ final_stripe_idx = final_offset / stripe_size; - last_subfile = final_stripe_idx % num_subfiles; + last_subfile_idx = final_stripe_idx % num_subfiles; /* - * Determine how "deep" the resulting I/O vectors are at - * most by calculating the maximum number of "rows" spanned - * for any particular subfile; e.g. the maximum number of - * I/O requests for any particular subfile + * Determine how "deep" the current I/O vector is at most + * by calculating the maximum number of "rows" spanned for + * any particular subfile; e.g. the maximum number of I/O + * requests for any particular subfile */ - row_stripe_idx_start = stripe_idx - first_subfile; - row_stripe_idx_final = final_stripe_idx - last_subfile; + row_stripe_idx_start = stripe_idx - first_subfile_idx; + row_stripe_idx_final = final_stripe_idx - last_subfile_idx; max_iovec_depth = ((row_stripe_idx_final - row_stripe_idx_start) / num_subfiles) + 1; - if (last_subfile < first_subfile) + /* + * If the I/O request "wrapped around" and ends in a subfile + * less than the subfile we started in, subtract one from the + * I/O vector length to account for "empty space". This can be + * visualized as follows: + * + * SUBFILE 0 SUBFILE 1 SUBFILE 2 SUBFILE 3 + * _______________________________________________ + * | | | XXXXX | XXXXX | ROW 0 + * | XXXXX | XXXXX | XXXXX | XXXXX | ROW 1 + * | XXXXX | XXXXX | | | ROW 2 + * | | | | | ROW ... + * | | | | | + * | | | | | + * | | | | | + * |___________|___________|___________|___________| + * + * Here, `stripe_idx` would be calculated as 2 (I/O begins in + * the 3rd stripe, or subfile index 2), `first_subfile` would be + * calculated as 2 and the starting "row" (row_stripe_idx_start) + * would be calculated as "row" index 0. `final_stripe_idx` would + * be calculated as 9, `last_subfile` would be calculated as + * (9 % 4) = 1 and the ending "row" (row_stripe_idx_final) would + * be calculated as (9 - 1) = 8. Thus, the calculated I/O vector + * length would be ((8 - 0) / 4) + 1 = 3. However, since there is + * no I/O to stripe indices 0 and 1 (residing in "row" 0 of subfile + * index 0 and 1, respectively), it can be seen that the real I/O + * vector length is 2. + */ + if (last_subfile_idx < first_subfile_idx) max_iovec_depth--; - /* Set returned parameters early */ - *first_subfile_index = (int)first_subfile; - *n_subfiles_used = num_subfiles; - *max_io_req_per_subfile = max_iovec_depth; - #ifdef H5_SUBFILING_DEBUG - H5_subfiling_log(sf_context->sf_context_id, - "%s: FILE OFFSET = %" PRId64 ", DATA SIZE = %zu, STRIPE SIZE = %" PRId64, __func__, - file_offset, io_nelemts, stripe_size); - H5_subfiling_log(sf_context->sf_context_id, - "%s: FIRST SUBFILE = %" PRId64 ", LAST SUBFILE = %" PRId64 ", " - "MAX IOVEC DEPTH = %" PRId64 ", START LENGTH = %" PRId64 ", FINAL LENGTH = %" PRId64, - __func__, first_subfile, last_subfile, max_iovec_depth, start_length, final_length); + H5_subfiling_log( + sf_context->sf_context_id, + "%s: TRANSLATING I/O REQUEST (MEMORY TYPE: %d, ADDR: %" PRIuHADDR ", I/O SIZE: %zu, BUF: %p)\n" + "STRIPE SIZE: %" PRId64 ", BLOCK SIZE: %" PRId64 ", NUM SUBFILES: %d\n" + "STRIPE IDX: %" PRId64 ", LAST STRIPE IDX: %" PRId64 ", FIRST SUBFILE IDX: %" PRId64 + ", LAST SUBFILE IDX: %" PRId64 "\n" + "START SEGMENT LENGTH: %" PRId64 ", LAST SEGMENT LENGTH: %" PRId64 ", MAX IOVEC DEPTH: %" PRId64, + __func__, type, addr, io_size, + (io_type == IO_TYPE_WRITE) ? (const void *)io_buf.cvp : (void *)io_buf.vp, stripe_size, block_size, + num_subfiles, stripe_idx, final_stripe_idx, first_subfile_idx, last_subfile_idx, start_length, + final_length, max_iovec_depth); #endif /* @@ -2827,131 +3100,162 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne * vector components for each. Subfiles whose data size is * zero will not have I/O requests passed to them. */ - curr_stripe_idx = stripe_idx; - curr_max_iovec_depth = max_iovec_depth; - for (int i = 0, k = (int)first_subfile; i < num_subfiles; i++) { - int64_t *_mem_buf_offset; - int64_t *_target_file_offset; - int64_t *_io_block_len; - int64_t subfile_bytes = 0; - int64_t iovec_depth; - bool is_first = false; - bool is_last = false; - size_t output_offset; - - iovec_depth = curr_max_iovec_depth; + cur_stripe_idx = stripe_idx; + for (int i = 0, subfile_idx = (int)first_subfile_idx; i < num_subfiles; i++) { + H5_flexible_const_ptr_t *_io_bufs_ptr; + H5FD_mem_t *_io_types_ptr; + haddr_t *_io_addrs_ptr; + size_t *_io_sizes_ptr; + int64_t iovec_depth; + int64_t num_full_stripes; + int64_t subfile_bytes = 0; + bool is_first = false; + bool is_last = false; + + if (total_bytes >= io_size) + break; - /* - * Setup the pointers to the next set of I/O vectors in - * the output arrays and clear those vectors - */ - output_offset = (size_t)(k)*max_iovec_len; - _mem_buf_offset = mem_buf_offset + output_offset; - _target_file_offset = target_file_offset + output_offset; - _io_block_len = io_block_len + output_offset; - - memset(_mem_buf_offset, 0, (max_iovec_len * sizeof(*_mem_buf_offset))); - memset(_target_file_offset, 0, (max_iovec_len * sizeof(*_target_file_offset))); - memset(_io_block_len, 0, (max_iovec_len * sizeof(*_io_block_len))); - - if (total_bytes == data_size) { - *n_subfiles_used = i; - goto done; - } + iovec_depth = max_iovec_depth; + num_full_stripes = iovec_depth; + + if (subfile_idx == first_subfile_idx) { + is_first = true; - if (total_bytes < data_size) { - int64_t num_full_stripes = iovec_depth; + /* + * Add partial segment length if not + * starting on a stripe boundary + */ + if (start_length < stripe_size) { + subfile_bytes += start_length; + num_full_stripes--; + } + } - if (k == first_subfile) { - is_first = true; + if (subfile_idx == last_subfile_idx) { + is_last = true; - /* - * Add partial segment length if not - * starting on a stripe boundary - */ - if (start_length < stripe_size) { - subfile_bytes += start_length; + /* + * Add partial segment length if not + * ending on a stripe boundary + */ + if (final_length < stripe_size) { + subfile_bytes += final_length; + if (num_full_stripes) num_full_stripes--; - } } + } - if (k == last_subfile) { - is_last = true; + /* Account for subfiles with uniform segments */ + if (!is_first && !is_last) { + bool thin_uniform_section = false; + if (last_subfile_idx >= first_subfile_idx) { /* - * Add partial segment length if not - * ending on a stripe boundary + * In the case where the subfile with the final data + * segment has an index value greater than or equal + * to the subfile with the first data segment, I/O + * vectors directed to a subfile with an index value + * that is greater than the last subfile or less than + * the first subfile will be "thin", or rather will + * have a vector depth of 1 less than normal, which + * will be accounted for below. This can be visualized + * with the following I/O pattern: + * + * SUBFILE 0 SUBFILE 1 SUBFILE 2 SUBFILE 3 + * _______________________________________________ + * | | XXXXX | XXXXX | XXXXX | ROW 0 + * | XXXXX | XXXXX | XXXXX | | ROW 1 + * | | | | | ROW 2 + * | | | | | ROW ... + * | | | | | + * | | | | | + * | | | | | + * |___________|___________|___________|___________| + * (thin) (thin) */ - if (final_length < stripe_size) { - subfile_bytes += final_length; - if (num_full_stripes) - num_full_stripes--; - } + thin_uniform_section = (subfile_idx > last_subfile_idx) || (subfile_idx < first_subfile_idx); + } + else { /* last_subfile_idx < first_subfile_idx */ + /* + * This can also happen when the subfile with the final + * data segment has a smaller subfile index than the + * subfile with the first data segment and the current + * subfile index falls between the two. + */ + thin_uniform_section = + ((last_subfile_idx < subfile_idx) && (subfile_idx < first_subfile_idx)); } - /* Account for subfiles with uniform segments */ - if (!is_first && !is_last) { - bool thin_uniform_section = false; - - if (last_subfile >= first_subfile) { - /* - * When a subfile has an index value that is greater - * than both the starting subfile and ending subfile - * indices, it is a "thinner" section with a smaller - * I/O vector depth. - */ - thin_uniform_section = (k > first_subfile) && (k > last_subfile); - } + if (thin_uniform_section) { + assert(iovec_depth > 1); + assert(num_full_stripes > 1); - if (last_subfile < first_subfile) { - /* - * This can also happen when the subfile with the final - * data segment has a smaller subfile index than the - * subfile with the first data segment and the current - * subfile index falls between the two. - */ - thin_uniform_section = - thin_uniform_section || ((last_subfile < k) && (k < first_subfile)); - } + iovec_depth--; + num_full_stripes--; + } + } - if (thin_uniform_section) { - assert(iovec_depth > 1); - assert(num_full_stripes > 1); + /* + * After accounting for the length of the initial + * and/or final data segments, add the combined + * size of the fully selected I/O stripes to the + * running bytes total + */ + subfile_bytes += num_full_stripes * stripe_size; + total_bytes += (size_t)subfile_bytes; - iovec_depth--; - num_full_stripes--; - } - } + /* + * Setup the pointers to the next set of I/O vectors + * in the output arrays + */ + _io_types_ptr = &io_types[iovec_idx + (size_t)i]; + _io_addrs_ptr = &io_addrs[iovec_idx + (size_t)i]; + _io_sizes_ptr = &io_sizes[iovec_idx + (size_t)i]; + _io_bufs_ptr = &io_bufs[iovec_idx + (size_t)i]; - /* - * After accounting for the length of the initial - * and/or final data segments, add the combined - * size of the fully selected I/O stripes to the - * running bytes total - */ - subfile_bytes += num_full_stripes * stripe_size; - total_bytes += subfile_bytes; - } + /* + * Fill in I/O vector with initial values. If more than 1 + * subfile is involved, these values will be adjusted below. + */ + for (size_t vec_idx = 0; vec_idx < iovec_count; vec_idx++) + *(_io_types_ptr + (vec_idx * iovec_len)) = type; + *_io_addrs_ptr = (haddr_t)(row_offset + offset_in_block); + *_io_sizes_ptr = (size_t)subfile_bytes; - _mem_buf_offset[0] = mem_offset; - _target_file_offset[0] = row_offset + offset_in_block; - _io_block_len[0] = subfile_bytes; + if (io_type == IO_TYPE_WRITE) + _io_bufs_ptr->cvp = (const char *)(io_buf.cvp) + mem_offset; + else + _io_bufs_ptr->vp = (char *)(io_buf.vp) + mem_offset; if (num_subfiles > 1) { - int64_t curr_file_offset = row_offset + offset_in_block; + int64_t cur_file_offset = row_offset + offset_in_block; - /* Fill the I/O vectors */ + assert(iovec_depth <= max_iovec_depth); + + /* Fill the I/O vectors for the current subfile */ if (is_first) { - if (is_last) { /* First + Last */ - if (iovec_fill_first_last(sf_context, iovec_depth, subfile_bytes, mem_offset, - curr_file_offset, start_length, final_length, _mem_buf_offset, - _target_file_offset, _io_block_len) < 0) + if (is_last) { + /* + * The current subfile being processed is both the first + * subfile touched by I/O and the last subfile touched by + * I/O. In this case, we may have to deal with partial + * stripe I/O in the first and last I/O segments. + */ + if (iovec_fill_first_last(sf_context, iovec_len, iovec_depth, subfile_bytes, mem_offset, + cur_file_offset, start_length, final_length, io_buf, io_type, + _io_addrs_ptr, _io_sizes_ptr, _io_bufs_ptr) < 0) H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't fill I/O vectors"); } - else { /* First ONLY */ - if (iovec_fill_first(sf_context, iovec_depth, subfile_bytes, mem_offset, curr_file_offset, - start_length, _mem_buf_offset, _target_file_offset, - _io_block_len) < 0) + else { + /* + * The current subfile being processed is the first + * subfile touched by I/O. In this case, we may have + * to deal with partial stripe I/O in the first I/O + * segment. + */ + if (iovec_fill_first(sf_context, iovec_len, iovec_depth, subfile_bytes, mem_offset, + cur_file_offset, start_length, io_buf, io_type, _io_addrs_ptr, + _io_sizes_ptr, _io_bufs_ptr) < 0) H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't fill I/O vectors"); } /* Move the memory pointer to the starting location @@ -2959,31 +3263,43 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne */ mem_offset += start_length; } - else if (is_last) { /* Last ONLY */ - if (iovec_fill_last(sf_context, iovec_depth, subfile_bytes, mem_offset, curr_file_offset, - final_length, _mem_buf_offset, _target_file_offset, _io_block_len) < 0) + else if (is_last) { + /* + * The current subfile being processed is the last subfile + * touched by I/O. In this case, we may have to deal with + * partial stripe I/O in the last I/O segment. + */ + if (iovec_fill_last(sf_context, iovec_len, iovec_depth, subfile_bytes, mem_offset, + cur_file_offset, final_length, io_buf, io_type, _io_addrs_ptr, + _io_sizes_ptr, _io_bufs_ptr) < 0) H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't fill I/O vectors"); mem_offset += stripe_size; } - else { /* Everything else (uniform) */ - if (iovec_fill_uniform(sf_context, iovec_depth, subfile_bytes, mem_offset, curr_file_offset, - _mem_buf_offset, _target_file_offset, _io_block_len) < 0) + else { + /* + * The current subfile being processed is neither the first + * nor the last subfile touched by I/O. In this case, no + * partial stripe I/O will need to be dealt with; all I/O + * segments will cover a full I/O stripe. + */ + if (iovec_fill_uniform(sf_context, iovec_len, iovec_depth, subfile_bytes, mem_offset, + cur_file_offset, io_buf, io_type, _io_addrs_ptr, _io_sizes_ptr, + _io_bufs_ptr) < 0) H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't fill I/O vectors"); mem_offset += stripe_size; } } - offset_in_block += _io_block_len[0]; + offset_in_block += (int64_t)*_io_sizes_ptr; - k++; - curr_stripe_idx++; + subfile_idx++; + cur_stripe_idx++; - if (k == num_subfiles) { - k = 0; - offset_in_block = 0; - curr_max_iovec_depth = ((final_stripe_idx - curr_stripe_idx) / num_subfiles) + 1; + if (subfile_idx == num_subfiles) { + subfile_idx = 0; + offset_in_block = 0; row_offset += block_size; } @@ -2991,13 +3307,12 @@ init_indep_io(subfiling_context_t *sf_context, int64_t file_offset, size_t io_ne assert(offset_in_block <= block_size); } - if (total_bytes != data_size) - H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, - "total bytes (%" PRId64 ") didn't match data size (%" PRId64 ")!", - total_bytes, data_size); + if (total_bytes != io_size) + H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "total bytes (%zu) didn't match data size (%zu)!", + total_bytes, io_size); done: - return ret_value; + H5_SUBFILING_FUNC_LEAVE; } /*------------------------------------------------------------------------- @@ -3020,9 +3335,10 @@ done: *------------------------------------------------------------------------- */ static herr_t -iovec_fill_first(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t target_datasize, - int64_t start_mem_offset, int64_t start_file_offset, int64_t first_io_len, - int64_t *mem_offset_out, int64_t *target_file_offset_out, int64_t *io_block_len_out) +iovec_fill_first(subfiling_context_t *sf_context, size_t iovec_len, int64_t cur_iovec_depth, + int64_t target_datasize, int64_t start_mem_offset, int64_t start_file_offset, + int64_t first_io_len, H5_flexible_const_ptr_t buf, H5FD_subfiling_io_type_t io_type, + haddr_t *io_addrs_ptr, size_t *io_sizes_ptr, H5_flexible_const_ptr_t *io_bufs_ptr) { int64_t stripe_size; int64_t block_size; @@ -3030,10 +3346,10 @@ iovec_fill_first(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t t herr_t ret_value = SUCCEED; assert(sf_context); - assert(mem_offset_out); - assert(target_file_offset_out); - assert(io_block_len_out); - assert(iovec_depth > 0); + assert(cur_iovec_depth > 0); + assert(io_addrs_ptr); + assert(io_sizes_ptr); + assert(io_bufs_ptr); stripe_size = sf_context->sf_stripe_size; block_size = sf_context->sf_blocksize_per_stripe; @@ -3045,16 +3361,13 @@ iovec_fill_first(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t t __func__, start_mem_offset, start_file_offset, first_io_len); #endif - mem_offset_out[0] = start_mem_offset; - target_file_offset_out[0] = start_file_offset; - io_block_len_out[0] = first_io_len; + *io_addrs_ptr = (haddr_t)start_file_offset; + *io_sizes_ptr = (size_t)first_io_len; -#ifdef H5_SUBFILING_DEBUG - H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[0] = %" PRId64 ", file_offset[0] = %" PRId64 - ", io_block_len[0] = %" PRId64, - __func__, mem_offset_out[0], target_file_offset_out[0], io_block_len_out[0]); -#endif + if (io_type == IO_TYPE_WRITE) + io_bufs_ptr->cvp = (const char *)(buf.cvp) + start_mem_offset; + else + io_bufs_ptr->vp = (char *)(buf.vp) + start_mem_offset; if (first_io_len == target_datasize) H5_SUBFILING_GOTO_DONE(SUCCEED); @@ -3066,17 +3379,20 @@ iovec_fill_first(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t t total_bytes = first_io_len; - for (int64_t i = 1; i < iovec_depth; i++) { - mem_offset_out[i] = next_mem_offset; - target_file_offset_out[i] = next_file_offset; - io_block_len_out[i] = stripe_size; + for (size_t i = 1; i < (size_t)cur_iovec_depth; i++) { + *(io_addrs_ptr + (i * iovec_len)) = (haddr_t)next_file_offset; + *(io_sizes_ptr + (i * iovec_len)) = (size_t)stripe_size; + + if (io_type == IO_TYPE_WRITE) + (io_bufs_ptr + (i * iovec_len))->cvp = (const char *)(buf.cvp) + next_mem_offset; + else + (io_bufs_ptr + (i * iovec_len))->vp = (char *)(buf.vp) + next_mem_offset; #ifdef H5_SUBFILING_DEBUG H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[%" PRId64 "] = %" PRId64 ", file_offset[%" PRId64 "] = %" PRId64 - ", io_block_len[%" PRId64 "] = %" PRId64, - __func__, i, mem_offset_out[i], i, target_file_offset_out[i], i, - io_block_len_out[i]); + "%s: mem_offset[%zu] = %" PRId64 ", file_offset[%zu] = %" PRId64 + ", io_block_len[%zu] = %" PRId64, + __func__, i, next_mem_offset, i, next_file_offset, i, stripe_size); #endif next_mem_offset += block_size; @@ -3116,9 +3432,10 @@ done: *------------------------------------------------------------------------- */ static herr_t -iovec_fill_last(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t target_datasize, - int64_t start_mem_offset, int64_t start_file_offset, int64_t last_io_len, - int64_t *mem_offset_out, int64_t *target_file_offset_out, int64_t *io_block_len_out) +iovec_fill_last(subfiling_context_t *sf_context, size_t iovec_len, int64_t cur_iovec_depth, + int64_t target_datasize, int64_t start_mem_offset, int64_t start_file_offset, + int64_t last_io_len, H5_flexible_const_ptr_t buf, H5FD_subfiling_io_type_t io_type, + haddr_t *io_addrs_ptr, size_t *io_sizes_ptr, H5_flexible_const_ptr_t *io_bufs_ptr) { int64_t stripe_size; int64_t block_size; @@ -3126,10 +3443,10 @@ iovec_fill_last(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t ta herr_t ret_value = SUCCEED; assert(sf_context); - assert(mem_offset_out); - assert(target_file_offset_out); - assert(io_block_len_out); - assert(iovec_depth > 0); + assert(cur_iovec_depth > 0); + assert(io_addrs_ptr); + assert(io_sizes_ptr); + assert(io_bufs_ptr); stripe_size = sf_context->sf_stripe_size; block_size = sf_context->sf_blocksize_per_stripe; @@ -3141,52 +3458,45 @@ iovec_fill_last(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t ta __func__, start_mem_offset, start_file_offset, last_io_len); #endif - mem_offset_out[0] = start_mem_offset; - target_file_offset_out[0] = start_file_offset; - io_block_len_out[0] = last_io_len; + *io_addrs_ptr = (haddr_t)start_file_offset; + *io_sizes_ptr = (size_t)last_io_len; - if (last_io_len == target_datasize) { -#ifdef H5_SUBFILING_DEBUG - H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[0] = %" PRId64 ", file_offset[0] = %" PRId64 - ", io_block_len[0] = %" PRId64, - __func__, mem_offset_out[0], target_file_offset_out[0], io_block_len_out[0]); -#endif + if (io_type == IO_TYPE_WRITE) + io_bufs_ptr->cvp = (const char *)(buf.cvp) + start_mem_offset; + else + io_bufs_ptr->vp = (char *)(buf.vp) + start_mem_offset; + if (last_io_len == target_datasize) H5_SUBFILING_GOTO_DONE(SUCCEED); - } - else { + + { int64_t next_mem_offset = start_mem_offset + block_size; int64_t next_file_offset = start_file_offset + block_size; - int64_t i; + size_t i; /* * If the last I/O size doesn't cover the target data * size, there is at least one full stripe preceding * the last I/O block */ - io_block_len_out[0] = stripe_size; - -#ifdef H5_SUBFILING_DEBUG - H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[0] = %" PRId64 ", file_offset[0] = %" PRId64 - ", io_block_len[0] = %" PRId64, - __func__, mem_offset_out[0], target_file_offset_out[0], io_block_len_out[0]); -#endif + *io_sizes_ptr = (size_t)stripe_size; total_bytes = stripe_size; - for (i = 1; i < iovec_depth - 1;) { - mem_offset_out[i] = next_mem_offset; - target_file_offset_out[i] = next_file_offset; - io_block_len_out[i] = stripe_size; + for (i = 1; i < (size_t)cur_iovec_depth - 1;) { + *(io_addrs_ptr + (i * iovec_len)) = (haddr_t)next_file_offset; + *(io_sizes_ptr + (i * iovec_len)) = (size_t)stripe_size; + + if (io_type == IO_TYPE_WRITE) + (io_bufs_ptr + (i * iovec_len))->cvp = (const char *)(buf.cvp) + next_mem_offset; + else + (io_bufs_ptr + (i * iovec_len))->vp = (char *)(buf.vp) + next_mem_offset; #ifdef H5_SUBFILING_DEBUG H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[%" PRId64 "] = %" PRId64 ", file_offset[%" PRId64 "] = %" PRId64 - ", io_block_len[%" PRId64 "] = %" PRId64, - __func__, i, mem_offset_out[i], i, target_file_offset_out[i], i, - io_block_len_out[i]); + "%s: mem_offset[%zu] = %" PRId64 ", file_offset[%zu] = %" PRId64 + ", io_block_len[%zu] = %" PRId64, + __func__, i, next_mem_offset, i, next_file_offset, i, stripe_size); #endif next_mem_offset += block_size; @@ -3196,16 +3506,19 @@ iovec_fill_last(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t ta i++; } - mem_offset_out[i] = next_mem_offset; - target_file_offset_out[i] = next_file_offset; - io_block_len_out[i] = last_io_len; + *(io_addrs_ptr + (i * iovec_len)) = (haddr_t)next_file_offset; + *(io_sizes_ptr + (i * iovec_len)) = (size_t)last_io_len; + + if (io_type == IO_TYPE_WRITE) + (io_bufs_ptr + (i * iovec_len))->cvp = (const char *)(buf.cvp) + next_mem_offset; + else + (io_bufs_ptr + (i * iovec_len))->vp = (char *)(buf.vp) + next_mem_offset; #ifdef H5_SUBFILING_DEBUG H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[%" PRId64 "] = %" PRId64 ", file_offset[%" PRId64 "] = %" PRId64 - ", io_block_len[%" PRId64 "] = %" PRId64, - __func__, i, mem_offset_out[i], i, target_file_offset_out[i], i, - io_block_len_out[i]); + "%s: mem_offset[%zu] = %" PRId64 ", file_offset[%zu] = %" PRId64 + ", io_block_len[%zu] = %" PRId64, + __func__, i, next_mem_offset, i, next_file_offset, i, last_io_len); #endif total_bytes += last_io_len; @@ -3244,10 +3557,11 @@ done: *------------------------------------------------------------------------- */ static herr_t -iovec_fill_first_last(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t target_datasize, - int64_t start_mem_offset, int64_t start_file_offset, int64_t first_io_len, - int64_t last_io_len, int64_t *mem_offset_out, int64_t *target_file_offset_out, - int64_t *io_block_len_out) +iovec_fill_first_last(subfiling_context_t *sf_context, size_t iovec_len, int64_t cur_iovec_depth, + int64_t target_datasize, int64_t start_mem_offset, int64_t start_file_offset, + int64_t first_io_len, int64_t last_io_len, H5_flexible_const_ptr_t buf, + H5FD_subfiling_io_type_t io_type, haddr_t *io_addrs_ptr, size_t *io_sizes_ptr, + H5_flexible_const_ptr_t *io_bufs_ptr) { int64_t stripe_size; int64_t block_size; @@ -3255,10 +3569,10 @@ iovec_fill_first_last(subfiling_context_t *sf_context, int64_t iovec_depth, int6 herr_t ret_value = SUCCEED; assert(sf_context); - assert(mem_offset_out); - assert(target_file_offset_out); - assert(io_block_len_out); - assert(iovec_depth > 0); + assert(cur_iovec_depth > 0); + assert(io_addrs_ptr); + assert(io_sizes_ptr); + assert(io_bufs_ptr); stripe_size = sf_context->sf_stripe_size; block_size = sf_context->sf_blocksize_per_stripe; @@ -3270,16 +3584,13 @@ iovec_fill_first_last(subfiling_context_t *sf_context, int64_t iovec_depth, int6 __func__, start_mem_offset, start_file_offset, first_io_len, last_io_len); #endif - mem_offset_out[0] = start_mem_offset; - target_file_offset_out[0] = start_file_offset; - io_block_len_out[0] = first_io_len; + *io_addrs_ptr = (haddr_t)start_file_offset; + *io_sizes_ptr = (size_t)first_io_len; -#ifdef H5_SUBFILING_DEBUG - H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[0] = %" PRId64 ", file_offset[0] = %" PRId64 - ", io_block_len[0] = %" PRId64, - __func__, mem_offset_out[0], target_file_offset_out[0], io_block_len_out[0]); -#endif + if (io_type == IO_TYPE_WRITE) + io_bufs_ptr->cvp = (const char *)(buf.cvp) + start_mem_offset; + else + io_bufs_ptr->vp = (char *)(buf.vp) + start_mem_offset; if (first_io_len == target_datasize) H5_SUBFILING_GOTO_DONE(SUCCEED); @@ -3288,21 +3599,24 @@ iovec_fill_first_last(subfiling_context_t *sf_context, int64_t iovec_depth, int6 int64_t offset_in_stripe = start_file_offset % stripe_size; int64_t next_mem_offset = block_size - offset_in_stripe; int64_t next_file_offset = start_file_offset + (block_size - offset_in_stripe); - int64_t i; + size_t i; total_bytes = first_io_len; - for (i = 1; i < iovec_depth - 1;) { - mem_offset_out[i] = next_mem_offset; - target_file_offset_out[i] = next_file_offset; - io_block_len_out[i] = stripe_size; + for (i = 1; i < (size_t)cur_iovec_depth - 1;) { + *(io_addrs_ptr + (i * iovec_len)) = (haddr_t)next_file_offset; + *(io_sizes_ptr + (i * iovec_len)) = (size_t)stripe_size; + + if (io_type == IO_TYPE_WRITE) + (io_bufs_ptr + (i * iovec_len))->cvp = (const char *)(buf.cvp) + next_mem_offset; + else + (io_bufs_ptr + (i * iovec_len))->vp = (char *)(buf.vp) + next_mem_offset; #ifdef H5_SUBFILING_DEBUG H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[%" PRId64 "] = %" PRId64 ", file_offset[%" PRId64 "] = %" PRId64 - ", io_block_len[%" PRId64 "] = %" PRId64, - __func__, i, mem_offset_out[i], i, target_file_offset_out[i], i, - io_block_len_out[i]); + "%s: mem_offset[%zu] = %" PRId64 ", file_offset[%zu] = %" PRId64 + ", io_block_len[%zu] = %" PRId64, + __func__, i, next_mem_offset, i, next_file_offset, i, stripe_size); #endif next_mem_offset += block_size; @@ -3312,16 +3626,19 @@ iovec_fill_first_last(subfiling_context_t *sf_context, int64_t iovec_depth, int6 i++; } - mem_offset_out[i] = next_mem_offset; - target_file_offset_out[i] = next_file_offset; - io_block_len_out[i] = last_io_len; + *(io_addrs_ptr + (i * iovec_len)) = (haddr_t)next_file_offset; + *(io_sizes_ptr + (i * iovec_len)) = (size_t)last_io_len; + + if (io_type == IO_TYPE_WRITE) + (io_bufs_ptr + (i * iovec_len))->cvp = (const char *)(buf.cvp) + next_mem_offset; + else + (io_bufs_ptr + (i * iovec_len))->vp = (char *)(buf.vp) + next_mem_offset; #ifdef H5_SUBFILING_DEBUG H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[%" PRId64 "] = %" PRId64 ", file_offset[%" PRId64 "] = %" PRId64 - ", io_block_len[%" PRId64 "] = %" PRId64, - __func__, i, mem_offset_out[i], i, target_file_offset_out[i], i, - io_block_len_out[i]); + "%s: mem_offset[%zu] = %" PRId64 ", file_offset[%zu] = %" PRId64 + ", io_block_len[%zu] = %" PRId64, + __func__, i, next_mem_offset, i, next_file_offset, i, last_io_len); #endif total_bytes += last_io_len; @@ -3352,9 +3669,10 @@ done: *------------------------------------------------------------------------- */ static herr_t -iovec_fill_uniform(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t target_datasize, - int64_t start_mem_offset, int64_t start_file_offset, int64_t *mem_offset_out, - int64_t *target_file_offset_out, int64_t *io_block_len_out) +iovec_fill_uniform(subfiling_context_t *sf_context, size_t iovec_len, int64_t cur_iovec_depth, + int64_t target_datasize, int64_t start_mem_offset, int64_t start_file_offset, + H5_flexible_const_ptr_t buf, H5FD_subfiling_io_type_t io_type, haddr_t *io_addrs_ptr, + size_t *io_sizes_ptr, H5_flexible_const_ptr_t *io_bufs_ptr) { int64_t stripe_size; int64_t block_size; @@ -3362,10 +3680,10 @@ iovec_fill_uniform(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t herr_t ret_value = SUCCEED; assert(sf_context); - assert(mem_offset_out); - assert(target_file_offset_out); - assert(io_block_len_out); - assert((iovec_depth > 0) || (target_datasize == 0)); + assert((cur_iovec_depth > 0) || (target_datasize == 0)); + assert(io_addrs_ptr); + assert(io_sizes_ptr); + assert(io_bufs_ptr); stripe_size = sf_context->sf_stripe_size; block_size = sf_context->sf_blocksize_per_stripe; @@ -3377,23 +3695,20 @@ iovec_fill_uniform(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t __func__, start_mem_offset, start_file_offset, stripe_size); #endif - mem_offset_out[0] = start_mem_offset; - target_file_offset_out[0] = start_file_offset; - io_block_len_out[0] = stripe_size; + *io_addrs_ptr = (haddr_t)start_file_offset; + *io_sizes_ptr = (size_t)stripe_size; -#ifdef H5_SUBFILING_DEBUG - H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[0] = %" PRId64 ", file_offset[0] = %" PRId64 - ", io_block_len[0] = %" PRId64, - __func__, mem_offset_out[0], target_file_offset_out[0], io_block_len_out[0]); -#endif + if (io_type == IO_TYPE_WRITE) + io_bufs_ptr->cvp = (const char *)(buf.cvp) + start_mem_offset; + else + io_bufs_ptr->vp = (char *)(buf.vp) + start_mem_offset; if (target_datasize == 0) { #ifdef H5_SUBFILING_DEBUG H5_subfiling_log(sf_context->sf_context_id, "%s: target_datasize = 0", __func__); #endif - io_block_len_out[0] = 0; + *io_sizes_ptr = (size_t)0; H5_SUBFILING_GOTO_DONE(SUCCEED); } @@ -3403,17 +3718,20 @@ iovec_fill_uniform(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t total_bytes = stripe_size; - for (int64_t i = 1; i < iovec_depth; i++) { - mem_offset_out[i] = next_mem_offset; - target_file_offset_out[i] = next_file_offset; - io_block_len_out[i] = stripe_size; + for (size_t i = 1; i < (size_t)cur_iovec_depth; i++) { + *(io_addrs_ptr + (i * iovec_len)) = (haddr_t)next_file_offset; + *(io_sizes_ptr + (i * iovec_len)) = (size_t)stripe_size; + + if (io_type == IO_TYPE_WRITE) + (io_bufs_ptr + (i * iovec_len))->cvp = (const char *)(buf.cvp) + next_mem_offset; + else + (io_bufs_ptr + (i * iovec_len))->vp = (char *)(buf.vp) + next_mem_offset; #ifdef H5_SUBFILING_DEBUG H5_subfiling_log(sf_context->sf_context_id, - "%s: mem_offset[%" PRId64 "] = %" PRId64 ", file_offset[%" PRId64 "] = %" PRId64 - ", io_block_len[%" PRId64 "] = %" PRId64, - __func__, i, mem_offset_out[i], i, target_file_offset_out[i], i, - io_block_len_out[i]); + "%s: mem_offset[%zu] = %" PRId64 ", file_offset[%zu] = %" PRId64 + ", io_block_len[%zu] = %" PRId64, + __func__, i, next_mem_offset, i, next_file_offset, i, stripe_size); #endif next_mem_offset += block_size; @@ -3430,3 +3748,38 @@ iovec_fill_uniform(subfiling_context_t *sf_context, int64_t iovec_depth, int64_t done: return ret_value; } + +#ifdef H5_SUBFILING_DEBUG +void +H5_subfiling_dump_iovecs(subfiling_context_t *sf_context, size_t ioreq_count, size_t iovec_len, + H5FD_subfiling_io_type_t io_type, H5FD_mem_t *io_types, haddr_t *io_addrs, + size_t *io_sizes, H5_flexible_const_ptr_t *io_bufs) +{ + assert(sf_context); + assert(io_types); + assert(io_addrs); + assert(io_sizes); + assert(io_bufs); + + H5_subfiling_log(sf_context->sf_context_id, + "%s: I/O REQUEST VECTORS (mem type, addr, size, buf):", __func__); + + for (size_t ioreq_idx = 0; ioreq_idx < ioreq_count; ioreq_idx++) { + H5_subfiling_log_nonewline(sf_context->sf_context_id, " -> I/O REQUEST %zu: ", ioreq_idx); + + H5_subfiling_log_nonewline(sf_context->sf_context_id, "["); + for (size_t i = 0; i < iovec_len; i++) { + if (i > 0) + H5_subfiling_log_nonewline(sf_context->sf_context_id, ", "); + + H5_subfiling_log_nonewline( + sf_context->sf_context_id, "(%d, %" PRIuHADDR ", %zu, %p)", + *(io_types + (ioreq_idx * iovec_len) + i), *(io_addrs + (ioreq_idx * iovec_len) + i), + *(io_sizes + (ioreq_idx * iovec_len) + i), + (io_type == IO_TYPE_WRITE) ? (const void *)(io_bufs + (ioreq_idx * iovec_len) + i)->cvp + : (void *)(io_bufs + (ioreq_idx * iovec_len) + i)->vp); + } + H5_subfiling_log_nonewline(sf_context->sf_context_id, "]\n"); + } +} +#endif diff --git a/src/H5FDsubfiling/H5subfiling_common.c b/src/H5FDsubfiling/H5subfiling_common.c index f9cc0dc..1127ae0 100644 --- a/src/H5FDsubfiling/H5subfiling_common.c +++ b/src/H5FDsubfiling/H5subfiling_common.c @@ -3156,4 +3156,37 @@ done: return; } + +void +H5_subfiling_log_nonewline(int64_t sf_context_id, const char *fmt, ...) +{ + subfiling_context_t *sf_context = NULL; + va_list log_args; + + va_start(log_args, fmt); + + /* Retrieve the subfiling object for the newly-created context ID */ + if (NULL == (sf_context = H5_get_subfiling_object(sf_context_id))) { + printf("%s: couldn't get subfiling object from context ID\n", __func__); + goto done; + } + + H5FD_ioc_begin_thread_exclusive(); + + if (sf_context->sf_logfile) { + vfprintf(sf_context->sf_logfile, fmt, log_args); + fflush(sf_context->sf_logfile); + } + else { + vprintf(fmt, log_args); + fflush(stdout); + } + + H5FD_ioc_end_thread_exclusive(); + +done: + va_end(log_args); + + return; +} #endif diff --git a/src/H5FDsubfiling/H5subfiling_common.h b/src/H5FDsubfiling/H5subfiling_common.h index 395183a..156902a 100644 --- a/src/H5FDsubfiling/H5subfiling_common.h +++ b/src/H5FDsubfiling/H5subfiling_common.h @@ -284,7 +284,10 @@ H5_DLL herr_t H5_subfiling_validate_config(const H5FD_subfiling_params_t *subf_c H5_DLL herr_t H5_subfiling_terminate(void); +#ifdef H5_SUBFILING_DEBUG H5_DLL void H5_subfiling_log(int64_t sf_context_id, const char *fmt, ...); +H5_DLL void H5_subfiling_log_nonewline(int64_t sf_context_id, const char *fmt, ...); +#endif #ifdef __cplusplus } diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h index cc0bf2f..5485f6b 100644 --- a/src/H5Fpublic.h +++ b/src/H5Fpublic.h @@ -354,6 +354,9 @@ H5_DLL hid_t H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_ * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Fcreate} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Fcreate_async(const char *app_file, const char *app_func, unsigned app_line, @@ -450,14 +453,20 @@ H5_DLL hid_t H5Fcreate_async(const char *filename, unsigned flags, hid_t fcpl_id * * \version 1.10.0 The #H5F_ACC_SWMR_WRITE and #H5F_ACC_SWMR_READ flags were added. * + * \since 1.0.0 + * * \see H5Fclose() * + * */ H5_DLL hid_t H5Fopen(const char *filename, unsigned flags, hid_t fapl_id); /** * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Fopen} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Fopen_async(const char *app_file, const char *app_func, unsigned app_line, @@ -489,12 +498,17 @@ H5_DLL hid_t H5Fopen_async(const char *filename, unsigned flags, hid_t access_pl * active \p file_id. E.g., one cannot close a file with H5Fclose() on * \p file_id then use H5Freopen() on \p file_id to reopen it. * + * \since 1.0.0 + * */ H5_DLL hid_t H5Freopen(hid_t file_id); /** * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Freopen} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Freopen_async(const char *app_file, const char *app_func, unsigned app_line, hid_t file_id, @@ -533,12 +547,17 @@ H5_DLL hid_t H5Freopen_async(hid_t file_id, hid_t es_id); * that, the OS is responsible for ensuring that the data is * actually flushed to disk. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Fflush(hid_t object_id, H5F_scope_t scope); /** * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Fflush} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Fflush_async(const char *app_file, const char *app_func, unsigned app_line, hid_t object_id, @@ -586,6 +605,8 @@ H5_DLL herr_t H5Fflush_async(hid_t object_id, H5F_scope_t scope, hid_t es_id); * before calling H5Fclose. It is generally recommended to do so in all * cases. * + * \since 1.0.0 + * * \see H5Fopen() * */ @@ -594,6 +615,9 @@ H5_DLL herr_t H5Fclose(hid_t file_id); * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Fclose} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Fclose_async(const char *app_file, const char *app_func, unsigned app_line, hid_t file_id, @@ -656,6 +680,8 @@ H5_DLL herr_t H5Fdelete(const char *filename, hid_t fapl_id); * The creation property list identifier should be released with * H5Pclose(). * + * \since 1.0.0 + * */ H5_DLL hid_t H5Fget_create_plist(hid_t file_id); /** @@ -669,6 +695,8 @@ H5_DLL hid_t H5Fget_create_plist(hid_t file_id); * \details H5Fget_access_plist() returns the file access property list * identifier of the specified file. * + * \since 1.0.0 + * */ H5_DLL hid_t H5Fget_access_plist(hid_t file_id); /** @@ -749,6 +777,8 @@ H5_DLL herr_t H5Fget_fileno(hid_t file_id, unsigned long *fileno); * of objects to be counted. #H5F_OBJ_LOCAL restricts the * search to objects opened through current file identifier. * + * \since 1.6.0 + * */ H5_DLL ssize_t H5Fget_obj_count(hid_t file_id, unsigned types); /** @@ -842,6 +872,8 @@ H5_DLL herr_t H5Fget_vfd_handle(hid_t file_id, hid_t fapl, void **file_handle); * proper value to pass for \p plist is #H5P_DEFAULT, indicating the * default file mount property list. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist); /** @@ -864,6 +896,8 @@ H5_DLL herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist); * parent; if it was opened after the mount then it is the root group * of the child. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Funmount(hid_t loc, const char *name); /** @@ -1067,6 +1101,8 @@ H5_DLL herr_t H5Fset_mdc_config(hid_t file_id, const H5AC_cache_config_t *config * See the overview of the metadata cache in the special topics section of the user manual for * details on the metadata cache and its adaptive resize algorithms. * + * \since 1.8.0 + * */ H5_DLL herr_t H5Fget_mdc_hit_rate(hid_t file_id, double *hit_rate_ptr); /** @@ -1098,6 +1134,8 @@ H5_DLL herr_t H5Fget_mdc_hit_rate(hid_t file_id, double *hit_rate_ptr); * Current size can exceed maximum size under certain conditions. See the overview of the * metadata cache in the special topics section of the user manual for a discussion of this. * + * \since 1.8.0 + * */ H5_DLL herr_t H5Fget_mdc_size(hid_t file_id, size_t *max_size_ptr, size_t *min_clean_size_ptr, size_t *cur_size_ptr, int *cur_num_entries_ptr); @@ -1127,6 +1165,8 @@ H5_DLL herr_t H5Fget_mdc_size(hid_t file_id, size_t *max_size_ptr, size_t *min_c * you should not be using this API call. * \endparblock * + * \since 1.8.0 + * */ H5_DLL herr_t H5Freset_mdc_hit_rate_stats(hid_t file_id); /** diff --git a/src/H5Gpublic.h b/src/H5Gpublic.h index cc04680..4c0e2de 100644 --- a/src/H5Gpublic.h +++ b/src/H5Gpublic.h @@ -214,6 +214,9 @@ H5_DLL hid_t H5Gopen2(hid_t loc_id, const char *name, hid_t gapl_id); * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Gopen} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Gopen_async(const char *app_file, const char *app_func, unsigned app_line, hid_t loc_id, @@ -273,6 +276,9 @@ H5_DLL herr_t H5Gget_info(hid_t loc_id, H5G_info_t *ginfo); * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Gget_info} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Gget_info_async(const char *app_file, const char *app_func, unsigned app_line, hid_t loc_id, @@ -317,6 +323,9 @@ H5_DLL herr_t H5Gget_info_by_name(hid_t loc_id, const char *name, H5G_info_t *gi * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Gget_info_by_name} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Gget_info_by_name_async(const char *app_file, const char *app_func, unsigned app_line, @@ -377,6 +386,9 @@ H5_DLL herr_t H5Gget_info_by_idx(hid_t loc_id, const char *group_name, H5_index_ * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Gget_info_by_idx} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Gget_info_by_idx_async(const char *app_file, const char *app_func, unsigned app_line, @@ -468,6 +480,9 @@ H5_DLL herr_t H5Gclose(hid_t group_id); * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Gclose} + * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Gclose_async(const char *app_file, const char *app_func, unsigned app_line, hid_t group_id, @@ -683,6 +698,8 @@ H5_DLL hid_t H5Gopen1(hid_t loc_id, const char *name); * \version 1.8.0 Function deprecated in this release. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Glink(hid_t cur_loc_id, H5G_link_t type, const char *cur_name, const char *new_name); /** @@ -716,9 +733,11 @@ H5_DLL herr_t H5Glink(hid_t cur_loc_id, H5G_link_t type, const char *cur_name, c * current_name is \Code{./foo}, \p new_name is \Code{./x/y/bar}, and a * request is made for \Code{./x/y/bar}, then the actual object looked * up is \Code{./x/y/./foo}. - + * * \version 1.8.0 Function deprecated in this release. * + * \since 1.6.0 + * */ H5_DLL herr_t H5Glink2(hid_t cur_loc_id, const char *cur_name, H5G_link_t type, hid_t new_loc_id, const char *new_name); @@ -748,6 +767,8 @@ H5_DLL herr_t H5Glink2(hid_t cur_loc_id, const char *cur_name, H5G_link_t type, * * \version 1.8.0 Function deprecated in this release. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Gmove(hid_t src_loc_id, const char *src_name, const char *dst_name); /** @@ -779,6 +800,8 @@ H5_DLL herr_t H5Gmove(hid_t src_loc_id, const char *src_name, const char *dst_na * * \version 1.8.0 Function deprecated in this release. * + * \since 1.6.0 + * */ H5_DLL herr_t H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *dst_name); /** @@ -820,6 +843,8 @@ H5_DLL herr_t H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, * * \version 1.8.0 Function deprecated in this release. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Gunlink(hid_t loc_id, const char *name); /** @@ -858,6 +883,8 @@ H5_DLL herr_t H5Gunlink(hid_t loc_id, const char *name); * * \version 1.8.0 Function deprecated in this release. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Gget_linkval(hid_t loc_id, const char *name, size_t size, char *buf /*out*/); /** @@ -898,6 +925,8 @@ H5_DLL herr_t H5Gget_linkval(hid_t loc_id, const char *name, size_t size, char * * * \version 1.8.0 Function deprecated in this release. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Gset_comment(hid_t loc_id, const char *name, const char *comment); /** @@ -943,6 +972,8 @@ H5_DLL herr_t H5Gset_comment(hid_t loc_id, const char *name, const char *comment * * \version 1.8.0 Function deprecated in this release. * + * \since 1.0.0 + * */ H5_DLL int H5Gget_comment(hid_t loc_id, const char *name, size_t bufsize, char *buf); /** @@ -1008,6 +1039,8 @@ H5_DLL int H5Gget_comment(hid_t loc_id, const char *name, size_t bufsize, char * * * \version 1.8.0 Function deprecated in this release. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Giterate(hid_t loc_id, const char *name, int *idx, H5G_iterate_t op, void *op_data); /** @@ -1029,6 +1062,8 @@ H5_DLL herr_t H5Giterate(hid_t loc_id, const char *name, int *idx, H5G_iterate_t * * \version 1.8.0 Function deprecated in this release. * + * \since 1.6.0 + * */ H5_DLL herr_t H5Gget_num_objs(hid_t loc_id, hsize_t *num_objs); /** @@ -1086,6 +1121,8 @@ H5_DLL herr_t H5Gget_num_objs(hid_t loc_id, hsize_t *num_objs); * \version 1.6.1 Two new fields were added to the \ref H5G_stat_t struct in * this release. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Gget_objinfo(hid_t loc_id, const char *name, hbool_t follow_link, H5G_stat_t *statbuf /*out*/); diff --git a/src/H5Idbg.c b/src/H5Idbg.c index 4c7d1ec..7910b1c 100644 --- a/src/H5Idbg.c +++ b/src/H5Idbg.c @@ -83,13 +83,13 @@ H5I__id_dump_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) fprintf(stderr, " id = %" PRIdHID "\n", info->id); fprintf(stderr, " count = %u\n", info->count); - fprintf(stderr, " obj = 0x%8p\n", info->object); + fprintf(stderr, " obj = 0x%8p\n", info->u.c_object); fprintf(stderr, " marked = %d\n", info->marked); /* Get the group location, so we get get the name */ switch (type) { case H5I_GROUP: { - const H5VL_object_t *vol_obj = (const H5VL_object_t *)info->object; + const H5VL_object_t *vol_obj = (const H5VL_object_t *)info->u.c_object; object = H5VL_object_data(vol_obj); if (H5_VOL_NATIVE == vol_obj->connector->cls->value) @@ -98,7 +98,7 @@ H5I__id_dump_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) } case H5I_DATASET: { - const H5VL_object_t *vol_obj = (const H5VL_object_t *)info->object; + const H5VL_object_t *vol_obj = (const H5VL_object_t *)info->u.c_object; object = H5VL_object_data(vol_obj); if (H5_VOL_NATIVE == vol_obj->connector->cls->value) @@ -107,13 +107,10 @@ H5I__id_dump_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) } case H5I_DATATYPE: { - const H5T_t *dt = (const H5T_t *)info->object; + H5T_t *dt = info->u.object; - H5_GCC_CLANG_DIAG_OFF("cast-qual") - object = (void *)H5T_get_actual_type((H5T_t *)dt); - H5_GCC_CLANG_DIAG_ON("cast-qual") - - path = H5T_nameof(object); + object = H5T_get_actual_type((H5T_t *)dt); + path = H5T_nameof(object); break; } diff --git a/src/H5Idevelop.h b/src/H5Idevelop.h index d0ff200..2eaa61a 100644 --- a/src/H5Idevelop.h +++ b/src/H5Idevelop.h @@ -128,6 +128,8 @@ extern "C" { * \note The H5Iregister_future() function is primarily targeted at VOL connector * authors and is _not_ designed for general-purpose application use. * + * \since 1.14.0 + * */ H5_DLL hid_t H5Iregister_future(H5I_type_t type, const void *object, H5I_future_realize_func_t realize_cb, H5I_future_discard_func_t discard_cb); diff --git a/src/H5Iint.c b/src/H5Iint.c index 7d8b4ac..1c53214 100644 --- a/src/H5Iint.c +++ b/src/H5Iint.c @@ -369,17 +369,16 @@ H5I__mark_node(void *_info, void H5_ATTR_UNUSED *key, void *_udata) */ if (udata->force || (info->count - (!udata->app_ref * info->app_count)) <= 1) { /* Check if this is an un-realized future object */ - H5_GCC_CLANG_DIAG_OFF("cast-qual") if (info->is_future) { /* Discard the future object */ - if ((info->discard_cb)((void *)info->object) < 0) { + if ((info->discard_cb)(info->u.object) < 0) { if (udata->force) { #ifdef H5I_DEBUG if (H5DEBUG(I)) { fprintf(H5DEBUG(I), "H5I: discard type=%d obj=%p " "failure ignored\n", - (int)udata->type_info->cls->type, info->object); + (int)udata->type_info->cls->type, info->u.c_object); } #endif /* H5I_DEBUG */ @@ -395,14 +394,14 @@ H5I__mark_node(void *_info, void H5_ATTR_UNUSED *key, void *_udata) else { /* Check for a 'free' function and call it, if it exists */ if (udata->type_info->cls->free_func && - (udata->type_info->cls->free_func)((void *)info->object, H5_REQUEST_NULL) < 0) { + (udata->type_info->cls->free_func)(info->u.object, H5_REQUEST_NULL) < 0) { if (udata->force) { #ifdef H5I_DEBUG if (H5DEBUG(I)) { fprintf(H5DEBUG(I), "H5I: free type=%d obj=%p " "failure ignored\n", - (int)udata->type_info->cls->type, info->object); + (int)udata->type_info->cls->type, info->u.c_object); } #endif /* H5I_DEBUG */ @@ -415,7 +414,6 @@ H5I__mark_node(void *_info, void H5_ATTR_UNUSED *key, void *_udata) mark = true; } } - H5_GCC_CLANG_DIAG_ON("cast-qual") /* Remove ID if requested */ if (mark) { @@ -524,7 +522,7 @@ H5I__register(H5I_type_t type, const void *object, bool app_ref, H5I_future_real info->id = new_id; info->count = 1; /* initial reference count */ info->app_count = !!app_ref; - info->object = object; + info->u.c_object = object; info->is_future = (NULL != realize_cb); info->realize_cb = realize_cb; info->discard_cb = discard_cb; @@ -633,7 +631,7 @@ H5I_register_using_existing_id(H5I_type_t type, void *object, bool app_ref, hid_ info->id = existing_id; info->count = 1; /* initial reference count*/ info->app_count = !!app_ref; - info->object = object; + info->u.object = object; /* This API call is only used by the native VOL connector, which is * not asynchronous. */ @@ -677,12 +675,10 @@ H5I_subst(hid_t id, const void *new_object) HGOTO_ERROR(H5E_ID, H5E_NOTFOUND, NULL, "can't get ID ref count"); /* Get the old object pointer to return */ - H5_GCC_CLANG_DIAG_OFF("cast-qual") - ret_value = (void *)info->object; - H5_GCC_CLANG_DIAG_ON("cast-qual") + ret_value = info->u.object; /* Set the new object pointer for the ID */ - info->object = new_object; + info->u.c_object = new_object; done: FUNC_LEAVE_NOAPI(ret_value) @@ -709,12 +705,9 @@ H5I_object(hid_t id) FUNC_ENTER_NOAPI_NOERR /* General lookup of the ID */ - if (NULL != (info = H5I__find_id(id))) { + if (NULL != (info = H5I__find_id(id))) /* Get the object pointer to return */ - H5_GCC_CLANG_DIAG_OFF("cast-qual") - ret_value = (void *)info->object; - H5_GCC_CLANG_DIAG_ON("cast-qual") - } + ret_value = info->u.object; FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_object() */ @@ -742,12 +735,9 @@ H5I_object_verify(hid_t id, H5I_type_t type) assert(type >= 1 && (int)type < H5I_next_type_g); /* Verify that the type of the ID is correct & lookup the ID */ - if (type == H5I_TYPE(id) && NULL != (info = H5I__find_id(id))) { + if (type == H5I_TYPE(id) && NULL != (info = H5I__find_id(id))) /* Get the object pointer to return */ - H5_GCC_CLANG_DIAG_OFF("cast-qual") - ret_value = (void *)info->object; - H5_GCC_CLANG_DIAG_ON("cast-qual") - } + ret_value = info->u.object; FUNC_LEAVE_NOAPI(ret_value) } /* H5I_object_verify() */ @@ -898,9 +888,7 @@ H5I__remove_common(H5I_type_info_t *type_info, hid_t id) if (type_info->last_id_info == info) type_info->last_id_info = NULL; - H5_GCC_CLANG_DIAG_OFF("cast-qual") - ret_value = (void *)info->object; - H5_GCC_CLANG_DIAG_ON("cast-qual") + ret_value = info->u.object; if (!H5I_marking_s) info = H5FL_FREE(H5I_id_info_t, info); @@ -1000,8 +988,7 @@ H5I__dec_ref(hid_t id, void **request) /* Get the ID's type */ type_info = H5I_type_info_array_g[H5I_TYPE(id)]; - H5_GCC_CLANG_DIAG_OFF("cast-qual") - if (!type_info->cls->free_func || (type_info->cls->free_func)((void *)info->object, request) >= 0) { + if (!type_info->cls->free_func || (type_info->cls->free_func)(info->u.object, request) >= 0) { /* Remove the node from the type */ if (NULL == H5I__remove_common(type_info, id)) HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, (-1), "can't remove ID node"); @@ -1009,7 +996,6 @@ H5I__dec_ref(hid_t id, void **request) } /* end if */ else ret_value = -1; - H5_GCC_CLANG_DIAG_ON("cast-qual") } /* end if */ else { --(info->count); @@ -1482,9 +1468,7 @@ H5I__iterate_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) /* The stored object pointer might be an H5VL_object_t, in which * case we'll need to get the wrapped object struct (H5F_t *, etc.). */ - H5_GCC_CLANG_DIAG_OFF("cast-qual") - object = H5I__unwrap((void *)info->object, type); - H5_GCC_CLANG_DIAG_ON("cast-qual") + object = H5I__unwrap(info->u.object, type); /* Invoke callback function */ cb_ret_val = (*udata->user_func)((void *)object, info->id, udata->user_udata); @@ -1607,14 +1591,13 @@ H5I__find_id(hid_t id) } /* Check if this is a future ID */ - H5_GCC_CLANG_DIAG_OFF("cast-qual") if (id_info && id_info->is_future) { hid_t actual_id = H5I_INVALID_HID; /* ID for actual object */ void *future_object; /* Pointer to the future object */ void *actual_object; /* Pointer to the actual object */ /* Invoke the realize callback, to get the actual object */ - if ((id_info->realize_cb)((void *)id_info->object, &actual_id) < 0) + if ((id_info->realize_cb)(id_info->u.object, &actual_id) < 0) HGOTO_DONE(NULL); /* Verify that we received a valid ID, of the same type */ @@ -1624,10 +1607,10 @@ H5I__find_id(hid_t id) HGOTO_DONE(NULL); /* Swap the actual object in for the future object */ - future_object = (void *)id_info->object; + future_object = id_info->u.object; actual_object = H5I__remove_common(type_info, actual_id); assert(actual_object); - id_info->object = actual_object; + id_info->u.object = actual_object; /* Discard the future object */ if ((id_info->discard_cb)(future_object) < 0) @@ -1639,7 +1622,6 @@ H5I__find_id(hid_t id) id_info->realize_cb = NULL; id_info->discard_cb = NULL; } - H5_GCC_CLANG_DIAG_ON("cast-qual") /* Set return value */ ret_value = id_info; @@ -1674,9 +1656,7 @@ H5I__find_id_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) assert(udata); /* Get a pointer to the VOL connector's data */ - H5_GCC_CLANG_DIAG_OFF("cast-qual") - object = H5I__unwrap((void *)info->object, type); - H5_GCC_CLANG_DIAG_ON("cast-qual") + object = H5I__unwrap(info->u.object, type); /* Check for a match */ if (object == udata->object) { diff --git a/src/H5Ipkg.h b/src/H5Ipkg.h index 6207962..c42c61d 100644 --- a/src/H5Ipkg.h +++ b/src/H5Ipkg.h @@ -56,10 +56,13 @@ /* ID information structure used */ typedef struct H5I_id_info_t { - hid_t id; /* ID for this info */ - unsigned count; /* Ref. count for this ID */ - unsigned app_count; /* Ref. count of application visible IDs */ - const void *object; /* Pointer associated with the ID */ + hid_t id; /* ID for this info */ + unsigned count; /* Ref. count for this ID */ + unsigned app_count; /* Ref. count of application visible IDs */ + union { + const void *c_object; /* Const pointer associated with the ID */ + void *object; /* Pointer associated with the ID */ + } u; /* Future ID info */ bool is_future; /* Whether this ID represents a future object */ diff --git a/src/H5Ipublic.h b/src/H5Ipublic.h index ce78ae3..3e429ec 100644 --- a/src/H5Ipublic.h +++ b/src/H5Ipublic.h @@ -125,6 +125,8 @@ extern "C" { * will be a reference to. This pointer will be stored by the library * and returned via a call to H5Iobject_verify(). * + * \since 1.8.0 + * */ H5_DLL hid_t H5Iregister(H5I_type_t type, const void *object); /** @@ -148,6 +150,8 @@ H5_DLL hid_t H5Iregister(H5I_type_t type, const void *object); * * \see H5Iregister() * + * \since 1.8.0 + * */ H5_DLL void *H5Iobject_verify(hid_t id, H5I_type_t type); /** @@ -178,6 +182,8 @@ H5_DLL void *H5Iobject_verify(hid_t id, H5I_type_t type); * The pointer returned by H5Iregister() must be deallocated by the user * to avoid memory leaks. * + * \since 1.8.0 + * */ H5_DLL void *H5Iremove_verify(hid_t id, H5I_type_t type); /** @@ -202,6 +208,8 @@ H5_DLL void *H5Iremove_verify(hid_t id, H5I_type_t type); * is valid identifier. Validity can be determined with a call to * H5Iis_valid(). * + * \since 1.0.0 + * */ H5_DLL H5I_type_t H5Iget_type(hid_t id); /** @@ -311,7 +319,7 @@ H5_DLL ssize_t H5Iget_name(hid_t id, char *name /*out*/, size_t size); * safely closed or decremented and the HDF5 object will be closed * when the reference count for that that object drops to zero. * - * \since 1.6.2 + * \since 1.6.3 * */ H5_DLL int H5Iinc_ref(hid_t id); @@ -357,7 +365,7 @@ H5_DLL int H5Iinc_ref(hid_t id); * safely closed or decremented and the HDF5 object will be closed * when the reference count for that object drops to zero. * - * \since 1.6.2 + * \since 1.6.3 * */ H5_DLL int H5Idec_ref(hid_t id); @@ -381,7 +389,7 @@ H5_DLL int H5Idec_ref(hid_t id); * The function H5Iis_valid() is used to determine whether a specific * object identifier is valid. * - * \since 1.6.2 + * \since 1.6.3 * */ H5_DLL int H5Iget_ref(hid_t id); @@ -415,6 +423,8 @@ H5_DLL int H5Iget_ref(hid_t id); * pointer which was passed in to the H5Iregister() function. The \p * free_func function should return 0 on success and -1 on failure. * + * \since 1.8.0 + * */ H5_DLL H5I_type_t H5Iregister_type(size_t hash_size, unsigned reserved, H5I_free_t free_func); /** @@ -439,6 +449,8 @@ H5_DLL H5I_type_t H5Iregister_type(size_t hash_size, unsigned reserved, H5I_free * identifiers will be entirely unchanged. If the force flag is true, * all identifiers of this type will be deleted. * + * \since 1.8.0 + * */ H5_DLL herr_t H5Iclear_type(H5I_type_t type, hbool_t force); /** @@ -462,6 +474,8 @@ H5_DLL herr_t H5Iclear_type(H5I_type_t type, hbool_t force); * reused when new types are registered, it is a good idea to set the * variable holding the value of the destroyed type to #H5I_UNINIT. * + * \since 1.8.0 + * */ H5_DLL herr_t H5Idestroy_type(H5I_type_t type); /** @@ -481,6 +495,8 @@ H5_DLL herr_t H5Idestroy_type(H5I_type_t type); * reference count is to be incremented. This identifier must have * been created by a call to H5Iregister_type(). * + * \since 1.8.0 + * */ H5_DLL int H5Iinc_type_ref(H5I_type_t type); /** @@ -501,6 +517,8 @@ H5_DLL int H5Iinc_type_ref(H5I_type_t type); * reference count is to be decremented. This identifier must have * been created by a call to H5Iregister_type(). * + * \since 1.8.0 + * */ H5_DLL int H5Idec_type_ref(H5I_type_t type); /** @@ -520,6 +538,8 @@ H5_DLL int H5Idec_type_ref(H5I_type_t type); * reference count is to be retrieved. This identifier must have been * created by a call to H5Iregister_type(). * + * \since 1.8.0 + * */ H5_DLL int H5Iget_type_ref(H5I_type_t type); /** @@ -561,6 +581,8 @@ H5_DLL int H5Iget_type_ref(H5I_type_t type); * The \p key parameter will be passed to the search function as a * parameter. It can be used to further define the search at run-time. * + * \since 1.8.0 + * */ H5_DLL void *H5Isearch(H5I_type_t type, H5I_search_func_t func, void *key); /** @@ -613,6 +635,8 @@ H5_DLL herr_t H5Iiterate(H5I_type_t type, H5I_iterate_func_t op, void *op_data); * exist, or it has been destroyed, \p num_members is returned with * the value 0. * + * \since 1.8.0 + * */ H5_DLL herr_t H5Inmembers(H5I_type_t type, hsize_t *num_members); /** diff --git a/src/H5Pprivate.h b/src/H5Pprivate.h index fa70e38..36c2457 100644 --- a/src/H5Pprivate.h +++ b/src/H5Pprivate.h @@ -175,7 +175,7 @@ H5_DLL herr_t H5P_insert(H5P_genplist_t *plist, const char *name, size_t size, v H5_DLL herr_t H5P_remove(H5P_genplist_t *plist, const char *name); H5_DLL htri_t H5P_exist_plist(const H5P_genplist_t *plist, const char *name); H5_DLL htri_t H5P_class_isa(const H5P_genclass_t *pclass1, const H5P_genclass_t *pclass2); -H5_DLL char *H5P_get_class_name(H5P_genclass_t *pclass); +H5_DLL char *H5P_get_class_name(H5P_genclass_t *pclass) H5_ATTR_MALLOC; /* Internal helper routines */ H5_DLL herr_t H5P_get_nprops_pclass(const H5P_genclass_t *pclass, size_t *nprops, bool recurse); diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 8410a82..1b5d2f4 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -3370,7 +3370,7 @@ H5_DLL herr_t H5Pget_core_write_tracking(hid_t fapl_id, hbool_t *is_enabled, siz * file driver remains registered. * * - * \since 1.4.0 + * \since 1.2.0 * */ H5_DLL hid_t H5Pget_driver(hid_t plist_id); @@ -3410,6 +3410,8 @@ H5_DLL hid_t H5Pget_driver(hid_t plist_id); * described this function only in the virtual file driver * documentation. * + * \since 1.4.0 + * */ H5_DLL const void *H5Pget_driver_info(hid_t plist_id); /** @@ -3436,7 +3438,7 @@ H5_DLL const void *H5Pget_driver_info(hid_t plist_id); * string is simply returned. The caller can then allocate a buffer * of the appropriate size and call this routine again. * - * \version 1.14.0 Function publicized in this release. + * \since 1.14.0 * */ H5_DLL ssize_t H5Pget_driver_config_str(hid_t fapl_id, char *config_buf, size_t buf_size); @@ -4274,6 +4276,8 @@ H5_DLL herr_t H5Pset_core_write_tracking(hid_t fapl_id, hbool_t is_enabled, size * described this function only in the virtual file driver * documentation. * + * \since 1.4.0 + * */ H5_DLL herr_t H5Pset_driver(hid_t plist_id, hid_t driver_id, const void *driver_info); /** @@ -4297,7 +4301,7 @@ H5_DLL herr_t H5Pset_driver(hid_t plist_id, hid_t driver_id, const void *driver_ * registered, an attempt will be made to load the driver as a * plugin. * - * \version 1.14.0 Function publicized in this release. + * \since 1.14.0 * */ H5_DLL herr_t H5Pset_driver_by_name(hid_t plist_id, const char *driver_name, const char *driver_config); @@ -4322,7 +4326,7 @@ H5_DLL herr_t H5Pset_driver_by_name(hid_t plist_id, const char *driver_name, con * registered, an attempt will be made to load the driver as a * plugin. * - * \version 1.14.0 Function publicized in this release. + * \since 1.14.0 * */ H5_DLL herr_t H5Pset_driver_by_value(hid_t plist_id, H5FD_class_value_t driver_value, @@ -4796,6 +4800,8 @@ H5_DLL herr_t H5Pset_file_locking(hid_t fapl_id, hbool_t use_file_locking, hbool * * The default value for garbage collecting references is off. * + * \since 1.2.0 + * */ H5_DLL herr_t H5Pset_gc_references(hid_t fapl_id, unsigned gc_ref); /** @@ -5584,8 +5590,7 @@ H5_DLL herr_t H5Pget_coll_metadata_write(hid_t plist_id, hbool_t *is_collective) * \details H5Pget_mpi_params() gets the MPI communicator and info stored in * the file access property list \p fapl_id. * - * \todo When was this introduced? - * + * \since 1.12.0 */ H5_DLL herr_t H5Pget_mpi_params(hid_t fapl_id, MPI_Comm *comm, MPI_Info *info); @@ -5602,7 +5607,7 @@ H5_DLL herr_t H5Pget_mpi_params(hid_t fapl_id, MPI_Comm *comm, MPI_Info *info); * \details H5Pset_mpi_params() sets the MPI communicator and info stored in * the file access property list \p fapl_id. * - * \todo When was this introduced? + * \since 1.12.0 * */ H5_DLL herr_t H5Pset_mpi_params(hid_t fapl_id, MPI_Comm comm, MPI_Info info); @@ -7146,7 +7151,7 @@ H5_DLL herr_t H5Pget_chunk_cache(hid_t dapl_id, size_t *rdcc_nslots /*out*/, siz * file location behavior and for notes on the use of the * HDF5_EXTFILE_PREFIX environment variable. * - * \since 1.10.0, 1.8.17 + * \since 1.8.17 * */ H5_DLL ssize_t H5Pget_efile_prefix(hid_t dapl_id, char *prefix /*out*/, size_t size); @@ -7491,7 +7496,7 @@ H5_DLL herr_t H5Pset_chunk_cache(hid_t dapl_id, size_t rdcc_nslots, size_t rdcc_ * \note On Windows, the prefix must be an ASCII string since the Windows * standard C library's I/O functions cannot handle UTF-8 file names. * - * \since 1.10.0, 1.8.17 + * \since 1.8.17 * */ H5_DLL herr_t H5Pset_efile_prefix(hid_t dapl_id, const char *prefix); @@ -7618,6 +7623,8 @@ H5_DLL herr_t H5Pset_virtual_view(hid_t dapl_id, H5D_vds_view_t view); * \p left, \p middle, and \p right, as set by the H5Pset_btree_ratios() * function. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Pget_btree_ratios(hid_t plist_id, double *left /*out*/, double *middle /*out*/, double *right /*out*/); @@ -7640,6 +7647,8 @@ H5_DLL herr_t H5Pget_btree_ratios(hid_t plist_id, double *left /*out*/, double * * \version 1.6.0 The return type changed from \p hsize_t to \p size_t. * \version 1.4.0 The return type changed to \p hsize_t. * + * \since 1.0.0 + * */ H5_DLL size_t H5Pget_buffer(hid_t plist_id, void **tconv /*out*/, void **bkg /*out*/); /** @@ -7830,6 +7839,8 @@ H5_DLL herr_t H5Pget_vlen_mem_manager(hid_t plist_id, H5MM_allocate_t *alloc_fun * * All ratios are real numbers between 0 and 1, inclusive. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Pset_btree_ratios(hid_t plist_id, double left, double middle, double right); @@ -7871,6 +7882,8 @@ H5_DLL herr_t H5Pset_btree_ratios(hid_t plist_id, double left, double middle, do * \version 1.6.0 The \p size parameter has changed from type hsize_t to \c size_t. * \version 1.4.0 The \p size parameter has changed to type hsize_t. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Pset_buffer(hid_t plist_id, size_t size, void *tconv, void *bkg); @@ -8582,7 +8595,7 @@ H5_DLL herr_t H5Pget_create_intermediate_group(hid_t plist_id, unsigned *crt_int * * \details H5Pset_create_intermediate_group() * - * \since + * \since 1.8.0 * */ H5_DLL herr_t H5Pset_create_intermediate_group(hid_t plist_id, unsigned crt_intmd); @@ -9922,6 +9935,8 @@ H5_DLL herr_t H5Pset_mcdt_search_cb(hid_t plist_id, H5O_mcdt_search_cb_t func, v * The #H5P_prp_cb2_t is as follows: * \snippet this H5P_prp_cb2_t_snip * + * \since 1.4.0 + * */ /* Function prototypes */ @@ -10036,6 +10051,8 @@ H5_DLL herr_t H5Pregister1(hid_t cls_id, const char *name, size_t size, void *de * The #H5P_prp_cb2_t is as follows: * \snippet this H5P_prp_cb2_t_snip * + * \since 1.4.0 + * */ H5_DLL herr_t H5Pinsert1(hid_t plist_id, const char *name, size_t size, void *value, H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get, @@ -10135,6 +10152,8 @@ H5_DLL herr_t H5Pencode1(hid_t plist_id, void *buf, size_t *nalloc); * deprecated in this release. * \version 1.6.4 \p filter parameter type changed to unsigned. * + * \since 1.0.0 + * */ H5_DLL H5Z_filter_t H5Pget_filter1(hid_t plist_id, unsigned filter, unsigned int *flags /*out*/, size_t *cd_nelmts /*out*/, unsigned cd_values[] /*out*/, size_t namelen, @@ -10189,7 +10208,9 @@ H5_DLL H5Z_filter_t H5Pget_filter1(hid_t plist_id, unsigned filter, unsigned int * lists. * \version 1.8.0 Function H5Pget_filter_by_id() renamed to * H5Pget_filter_by_id1() and deprecated in this release. - * \version 1.6.0 Function introduced in this release. + * + * \since 1.6.0 + * */ H5_DLL herr_t H5Pget_filter_by_id1(hid_t plist_id, H5Z_filter_t id, unsigned int *flags /*out*/, size_t *cd_nelmts /*out*/, unsigned cd_values[] /*out*/, size_t namelen, @@ -10218,6 +10239,8 @@ H5_DLL herr_t H5Pget_filter_by_id1(hid_t plist_id, H5Z_filter_t id, unsigned int * \version 1.6.4 \p boot, \p freelist, \p stab, \p shhdr parameter types * changed to unsigned. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Pget_version(hid_t plist_id, unsigned *boot /*out*/, unsigned *freelist /*out*/, unsigned *stab /*out*/, unsigned *shhdr /*out*/); @@ -10239,6 +10262,8 @@ H5_DLL herr_t H5Pget_version(hid_t plist_id, unsigned *boot /*out*/, unsigned *f * * \details Maps to the function H5Pset_file_space_strategy(). * + * \since 1.10.0 + * */ H5_DLL herr_t H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t threshold); /** @@ -10257,6 +10282,7 @@ H5_DLL herr_t H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, * * \details Maps to the function H5Pget_file_space_strategy() * + * \since 1.10.0 * */ H5_DLL herr_t H5Pget_file_space(hid_t plist_id, H5F_file_space_type_t *strategy, hsize_t *threshold); diff --git a/src/H5Rpublic.h b/src/H5Rpublic.h index 3f63d59..a28262c 100644 --- a/src/H5Rpublic.h +++ b/src/H5Rpublic.h @@ -143,6 +143,8 @@ extern "C" { * H5Rdestroy() should be used to release the resource from the * reference. * + * \since 1.12.0 + * */ H5_DLL herr_t H5Rcreate_object(hid_t loc_id, const char *name, hid_t oapl_id, H5R_ref_t *ref_ptr); @@ -179,6 +181,8 @@ H5_DLL herr_t H5Rcreate_object(hid_t loc_id, const char *name, hid_t oapl_id, H5 * H5Rdestroy() should be used to release the resource from the * reference. * + * \since 1.12.0 + * */ H5_DLL herr_t H5Rcreate_region(hid_t loc_id, const char *name, hid_t space_id, hid_t oapl_id, H5R_ref_t *ref_ptr); @@ -216,6 +220,8 @@ H5_DLL herr_t H5Rcreate_region(hid_t loc_id, const char *name, hid_t space_id, h * H5Rdestroy() should be used to release the resource from the * reference. * + * \since 1.12.0 + * */ H5_DLL herr_t H5Rcreate_attr(hid_t loc_id, const char *name, const char *attr_name, hid_t oapl_id, H5R_ref_t *ref_ptr); @@ -237,6 +243,8 @@ H5_DLL herr_t H5Rcreate_attr(hid_t loc_id, const char *name, const char *attr_na * \ref H5R_ref_t is defined in H5Rpublic.h as: * \snippet this H5R_ref_t_snip * + * \since 1.12.0 + * */ H5_DLL herr_t H5Rdestroy(H5R_ref_t *ref_ptr); @@ -265,6 +273,8 @@ H5_DLL herr_t H5Rdestroy(H5R_ref_t *ref_ptr); * \ref H5R_ref_t is defined in H5Rpublic.h as: * \snippet this H5R_ref_t_snip * + * \since 1.12.0 + * */ H5_DLL H5R_type_t H5Rget_type(const H5R_ref_t *ref_ptr); @@ -287,6 +297,8 @@ H5_DLL H5R_type_t H5Rget_type(const H5R_ref_t *ref_ptr); * \ref H5R_ref_t is defined in H5Rpublic.h as: * \snippet this H5R_ref_t_snip * + * \since 1.12.0 + * */ H5_DLL htri_t H5Requal(const H5R_ref_t *ref1_ptr, const H5R_ref_t *ref2_ptr); @@ -305,6 +317,8 @@ H5_DLL htri_t H5Requal(const H5R_ref_t *ref1_ptr, const H5R_ref_t *ref2_ptr); * \p src_ref_ptr points to the reference to copy, and \p dst_ref_ptr is the * pointer to the destination reference. * + * \since 1.12.0 + * */ H5_DLL herr_t H5Rcopy(const H5R_ref_t *src_ref_ptr, H5R_ref_t *dst_ref_ptr); @@ -339,6 +353,8 @@ H5_DLL herr_t H5Rcopy(const H5R_ref_t *src_ref_ptr, H5R_ref_t *dst_ref_ptr); * the appropriate close function, such as H5Oclose() or H5Dclose() * for datasets. * + * \since 1.12.0 + * */ H5_DLL hid_t H5Ropen_object(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t oapl_id); @@ -346,6 +362,9 @@ H5_DLL hid_t H5Ropen_object(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t oapl_id); * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Ropen_object} + * + * \since 1.14.0 + * */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Ropen_object_async(const char *app_file, const char *app_func, unsigned app_line, @@ -385,6 +404,8 @@ H5_DLL hid_t H5Ropen_object_async(unsigned app_line, H5R_ref_t *ref_ptr, hid_t r * Use H5Sclose() to release the dataspace identifier returned by * this function when the identifier is no longer needed. * + * \since 1.12.0 + * */ H5_DLL hid_t H5Ropen_region(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t oapl_id); @@ -392,6 +413,9 @@ H5_DLL hid_t H5Ropen_region(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t oapl_id); * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Ropen_region} + * + * \since 1.14.0 + * */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Ropen_region_async(const char *app_file, const char *app_func, unsigned app_line, @@ -427,6 +451,8 @@ H5_DLL hid_t H5Ropen_region_async(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t oapl_ * The attribute opened with this function should be closed with * H5Aclose() when it is no longer needed. * + * \since 1.12.0 + * */ H5_DLL hid_t H5Ropen_attr(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t aapl_id); @@ -434,6 +460,8 @@ H5_DLL hid_t H5Ropen_attr(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t aapl_id); * -------------------------------------------------------------------------- * \ingroup ASYNC * \async_variant_of{H5Ropen_attr} + * + * \since 1.14.0 */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Ropen_attr_async(const char *app_file, const char *app_func, unsigned app_line, @@ -469,6 +497,8 @@ H5_DLL hid_t H5Ropen_attr_async(H5R_ref_t *ref_ptr, hid_t rapl_id, hid_t aapl_id * referenced object type are as followed (defined in H5Opublic.h): * \snippet H5Opublic.h H5O_type_t_snip * + * \since 1.12.0 + * */ H5_DLL herr_t H5Rget_obj_type3(H5R_ref_t *ref_ptr, hid_t rapl_id, H5O_type_t *obj_type); @@ -498,6 +528,8 @@ H5_DLL herr_t H5Rget_obj_type3(H5R_ref_t *ref_ptr, hid_t rapl_id, H5O_type_t *ob * passed in for size in the second call to H5Rget_file_name(), * which will retrieve the actual name. * + * \since 1.12.0 + * */ H5_DLL ssize_t H5Rget_file_name(const H5R_ref_t *ref_ptr, char *name, size_t size); @@ -544,6 +576,8 @@ H5_DLL ssize_t H5Rget_file_name(const H5R_ref_t *ref_ptr, char *name, size_t siz * if there are multiple links pointing to it. This function may * return any one of these paths. * + * \since 1.12.0 + * */ H5_DLL ssize_t H5Rget_obj_name(H5R_ref_t *ref_ptr, hid_t rapl_id, char *name, size_t size); @@ -571,6 +605,8 @@ H5_DLL ssize_t H5Rget_obj_name(H5R_ref_t *ref_ptr, hid_t rapl_id, char *name, si * be passed in for size in the second call to H5Rget_attr_name(), * which will retrieve the actual name. * + * \since 1.12.0 + * */ H5_DLL ssize_t H5Rget_attr_name(const H5R_ref_t *ref_ptr, char *name, size_t size); @@ -663,7 +699,8 @@ H5_DLL ssize_t H5Rget_attr_name(const H5R_ref_t *ref_ptr, char *name, size_t siz * * \version 1.8.0 Function H5Rget_obj_type() renamed to H5Rget_obj_type1() and * deprecated in this release. - * \since 1.6.0 + * + * \since 1.2.0 * */ H5_DLL H5G_obj_t H5Rget_obj_type1(hid_t id, H5R_type_t ref_type, const void *ref); @@ -705,7 +742,7 @@ H5_DLL H5G_obj_t H5Rget_obj_type1(hid_t id, H5R_type_t ref_type, const void *ref * * \version 1.10.0 Function H5Rdereference() renamed to H5Rdereference1() and * deprecated in this release. - * \since 1.8.0 + * \since 1.0.0 * */ H5_DLL hid_t H5Rdereference1(hid_t obj_id, H5R_type_t ref_type, const void *ref); @@ -742,7 +779,7 @@ H5_DLL hid_t H5Rdereference1(hid_t obj_id, H5R_type_t ref_type, const void *ref) * dataset region references and should be set to -1 if the reference * is an object reference, #H5R_OBJECT. * - * \since 1.8.0 + * \since 1.0.0 */ H5_DLL herr_t H5Rcreate(void *ref, hid_t loc_id, const char *name, H5R_type_t ref_type, hid_t space_id); @@ -873,6 +910,8 @@ H5_DLL hid_t H5Rdereference2(hid_t obj_id, hid_t oapl_id, H5R_type_t ref_type, c * Use H5Sclose() to release the dataspace identifier returned by this * function when the identifier is no longer needed. * + * \since 1.0.0 + * */ H5_DLL hid_t H5Rget_region(hid_t dataset, H5R_type_t ref_type, const void *ref); diff --git a/src/H5Tpkg.h b/src/H5Tpkg.h index 7a79d44..b9e24be 100644 --- a/src/H5Tpkg.h +++ b/src/H5Tpkg.h @@ -870,7 +870,7 @@ H5_DLL herr_t H5T__enum_insert(const H5T_t *dt, const char *name, const void *va H5_DLL herr_t H5T__get_member_value(const H5T_t *dt, unsigned membno, void *value); /* Field functions (for both compound & enumerated types) */ -H5_DLL char *H5T__get_member_name(H5T_t const *dt, unsigned membno); +H5_DLL char *H5T__get_member_name(H5T_t const *dt, unsigned membno) H5_ATTR_MALLOC; H5_DLL herr_t H5T__sort_value(const H5T_t *dt, int *map); H5_DLL herr_t H5T__sort_name(const H5T_t *dt, int *map); diff --git a/src/H5Tpublic.h b/src/H5Tpublic.h index 1a16301..a117075 100644 --- a/src/H5Tpublic.h +++ b/src/H5Tpublic.h @@ -1044,7 +1044,7 @@ H5_DLLVAR hid_t H5T_NATIVE_UINT_FAST64_g; * * \see H5Tclose() * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL hid_t H5Tcreate(H5T_class_t type, size_t size); @@ -1069,6 +1069,8 @@ H5_DLL hid_t H5Tcreate(H5T_class_t type, size_t size); * The returned datatype identifier should be released with H5Tclose() * to prevent resource leaks. * + * \since 1.0.0 + * */ H5_DLL hid_t H5Tcopy(hid_t type_id); /** @@ -1084,6 +1086,8 @@ H5_DLL hid_t H5Tcopy(hid_t type_id); * through this datatype identifier is illegal. Failure to release * a datatype with this call will result in resource leaks. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Tclose(hid_t type_id); /** @@ -1091,6 +1095,8 @@ H5_DLL herr_t H5Tclose(hid_t type_id); * * \brief Asynchronous version of H5Tclose(). * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Tclose_async(const char *app_file, const char *app_func, unsigned app_line, hid_t type_id, @@ -1111,7 +1117,7 @@ H5_DLL herr_t H5Tclose_async(hid_t type_id, hid_t es_id); * \details H5Tequal() determines whether two datatype identifiers refer to * the same datatype. * - * \since 1.6 or earlier + * \since 1.0.0 * */ H5_DLL htri_t H5Tequal(hid_t type1_id, hid_t type2_id); @@ -1130,6 +1136,8 @@ H5_DLL htri_t H5Tequal(hid_t type1_id, hid_t type2_id); * inadvertently change or delete a predefined type. Once a datatype * is locked it can never be unlocked. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Tlock(hid_t type_id); /** @@ -1185,6 +1193,8 @@ H5_DLL herr_t H5Tcommit2(hid_t loc_id, const char *name, hid_t type_id, hid_t lc * * \brief Asynchronous version of H5Tcommit2(). * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL herr_t H5Tcommit_async(const char *app_file, const char *app_func, unsigned app_line, hid_t loc_id, @@ -1223,6 +1233,8 @@ H5_DLL hid_t H5Topen2(hid_t loc_id, const char *name, hid_t tapl_id); * * \brief Asynchronous version of H5Topen2(). * + * \since 1.12.0 + * */ #ifndef H5_DOXYGEN H5_DLL hid_t H5Topen_async(const char *app_file, const char *app_func, unsigned app_line, hid_t loc_id, @@ -1322,7 +1334,7 @@ H5_DLL hid_t H5Tget_create_plist(hid_t type_id); * * \version 1.8.0 Fortran API was added * - * \since 1.6 or earlier + * \since 1.0.0 * */ H5_DLL htri_t H5Tcommitted(hid_t type_id); @@ -1380,6 +1392,8 @@ H5_DLL herr_t H5Tencode(hid_t obj_id, void *buf, size_t *nalloc); * with H5Tclose() when the identifier is no longer needed so that * resource leaks will not develop. * + * \since 1.2.0 + * */ H5_DLL hid_t H5Tdecode(const void *buf); /** @@ -1403,7 +1417,7 @@ H5_DLL hid_t H5Tdecode(const void *buf); * * \return \herr_t * - * \since 1.10.0 C function introduced with this release. + * \since 1.10.0 * * \see H5Dflush() * H5Drefresh() @@ -1439,7 +1453,7 @@ H5_DLL herr_t H5Tflush(hid_t type_id); * datatype. The reopened datatype is automatically re-registered * with the same identifier. * - * \since 1.2.0 + * \since 1.10.0 * */ H5_DLL herr_t H5Trefresh(hid_t type_id); @@ -1469,7 +1483,7 @@ H5_DLL herr_t H5Trefresh(hid_t type_id); * datatypes; a compound datatype can have a member which is a * compound datatype. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tinsert(hid_t parent_id, const char *name, size_t offset, hid_t member_id); @@ -1485,7 +1499,7 @@ H5_DLL herr_t H5Tinsert(hid_t parent_id, const char *name, size_t offset, hid_t * \details H5Tpack() recursively removes padding from within a compound * datatype to make it more efficient (space-wise) to store that data. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tpack(hid_t type_id); @@ -1631,6 +1645,8 @@ H5_DLL herr_t H5Tenum_valueof(hid_t type, const char *name, void *value /*out*/) * the array being of the string or character base type.\n * To create a variable-length string datatype, see \ref_vlen_strings. * + * \since 1.2.0 + * */ H5_DLL hid_t H5Tvlen_create(hid_t base_id); @@ -1719,6 +1735,8 @@ H5_DLL int H5Tget_array_dims2(hid_t type_id, hsize_t dims[]); * maximum size of an opaque datatype tag, was added in * H5Tpublic.h. * + * \since 1.2.0 + * */ H5_DLL herr_t H5Tset_tag(hid_t type, const char *tag); /** @@ -1737,6 +1755,8 @@ H5_DLL herr_t H5Tset_tag(hid_t type, const char *tag); * \attention The tag is returned via a pointer to an allocated string, which * the caller must free. * + * \since 1.2.0 + * */ H5_DLL char *H5Tget_tag(hid_t type); @@ -1758,6 +1778,8 @@ H5_DLL char *H5Tget_tag(hid_t type); * with H5Tclose() when the identifier is no longer needed so that * resource leaks will not develop. * + * \since 1.2.0 + * */ H5_DLL hid_t H5Tget_super(hid_t type); /** @@ -1781,6 +1803,8 @@ H5_DLL hid_t H5Tget_super(hid_t type); * be readable and modifiable only on the originating computing * platform; it will not be portable to other platforms. * + * \since 1.0.0 + * */ H5_DLL H5T_class_t H5Tget_class(hid_t type_id); /** @@ -1835,7 +1859,7 @@ H5_DLL htri_t H5Tdetect_class(hid_t type_id, H5T_class_t cls); * * \see H5Tset_size() * - * \since 1.2.0 + * \since 1.0.0 */ H5_DLL size_t H5Tget_size(hid_t type_id); /** @@ -1860,7 +1884,7 @@ H5_DLL size_t H5Tget_size(hid_t type_id); * but all other members have byte order #H5T_ORDER_LE, H5Tget_order() * will return #H5T_ORDER_LE for the compound datatype. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL H5T_order_t H5Tget_order(hid_t type_id); @@ -1880,7 +1904,7 @@ H5_DLL H5T_order_t H5Tget_order(hid_t type_id); * unless padding is present, is 8 times larger than the value * returned by H5Tget_size(). * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL size_t H5Tget_precision(hid_t type_id); @@ -1909,7 +1933,7 @@ H5_DLL size_t H5Tget_precision(hid_t type_id); * 3: [0x22] [ pad] [ pad] [0x11] * \endcode * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL int H5Tget_offset(hid_t type_id); @@ -1928,7 +1952,7 @@ H5_DLL int H5Tget_offset(hid_t type_id); * most-significant bit padding. Valid padding types are: * \snippet this H5T_pad_t_snip * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tget_pad(hid_t type_id, H5T_pad_t *lsb /*out*/, H5T_pad_t *msb /*out*/); @@ -1945,7 +1969,7 @@ H5_DLL herr_t H5Tget_pad(hid_t type_id, H5T_pad_t *lsb /*out*/, H5T_pad_t *msb / * Valid types are: * \snippet this H5T_sign_t_snip * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL H5T_sign_t H5Tget_sign(hid_t type_id); @@ -1969,7 +1993,7 @@ H5_DLL H5T_sign_t H5Tget_sign(hid_t type_id); * datatype. Bits are numbered with the least significant bit number * zero. Any (or even all) of the arguments can be null pointers. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tget_fields(hid_t type_id, size_t *spos /*out*/, size_t *epos /*out*/, size_t *esize /*out*/, @@ -1985,7 +2009,7 @@ H5_DLL herr_t H5Tget_fields(hid_t type_id, size_t *spos /*out*/, size_t *epos /* * * \details H5Tget_ebias() retrieves the exponent bias of a floating-point type. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL size_t H5Tget_ebias(hid_t type_id); @@ -2004,7 +2028,7 @@ H5_DLL size_t H5Tget_ebias(hid_t type_id); * floating-point datatype. Valid normalization types are: * \snippet this H5T_norm_t_snip * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL H5T_norm_t H5Tget_norm(hid_t type_id); @@ -2023,7 +2047,7 @@ H5_DLL H5T_norm_t H5Tget_norm(hid_t type_id); * bits in floating-point datatypes. Valid padding types are: * \snippet this H5T_pad_t_snip * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL H5T_pad_t H5Tget_inpad(hid_t type_id); @@ -2044,7 +2068,7 @@ H5_DLL H5T_pad_t H5Tget_inpad(hid_t type_id); * values returned are: * \str_pad_type * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL H5T_str_t H5Tget_strpad(hid_t type_id); @@ -2061,7 +2085,7 @@ H5_DLL H5T_str_t H5Tget_strpad(hid_t type_id); * \details H5Tget_nmembers() retrieves the number of fields in a compound * datatype or the number of members of an enumeration datatype. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL int H5Tget_nmembers(hid_t type_id); @@ -2088,7 +2112,7 @@ H5_DLL int H5Tget_nmembers(hid_t type_id); * the field. The caller must subsequently free the buffer with * H5free_memory(). * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL char *H5Tget_member_name(hid_t type_id, unsigned membno); @@ -2110,7 +2134,7 @@ H5_DLL char *H5Tget_member_name(hid_t type_id, unsigned membno); * Fields are stored in no particular order with index values of 0 * through N-1, where N is the value returned by H5Tget_nmembers() . * - * \since 1.2.0 + * \since 1.4.0 * */ H5_DLL int H5Tget_member_index(hid_t type_id, const char *name); @@ -2134,7 +2158,7 @@ H5_DLL int H5Tget_member_index(hid_t type_id, const char *name); * * \version 1.6.4 \p member_no parameter type changed to unsigned. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL size_t H5Tget_member_offset(hid_t type_id, unsigned membno); @@ -2155,7 +2179,7 @@ H5_DLL size_t H5Tget_member_offset(hid_t type_id, unsigned membno); * Valid class identifiers, as defined in H5Tpublic.h, are: * \snippet this H5T_class_t_snip * - * \since 1.2.0 + * \since 1.4.0 * */ H5_DLL H5T_class_t H5Tget_member_class(hid_t type_id, unsigned membno); @@ -2176,7 +2200,7 @@ H5_DLL H5T_class_t H5Tget_member_class(hid_t type_id, unsigned membno); * * \version 1.6.4 \p membno parameter type changed to unsigned. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL hid_t H5Tget_member_type(hid_t type_id, unsigned membno); @@ -2203,7 +2227,7 @@ H5_DLL hid_t H5Tget_member_type(hid_t type_id, unsigned membno); * of that base type. If the size is unknown, you can determine it * with H5Tget_size(). * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tget_member_value(hid_t type_id, unsigned membno, void *value /*out*/); @@ -2221,7 +2245,7 @@ H5_DLL herr_t H5Tget_member_value(hid_t type_id, unsigned membno, void *value /* * Valid character set types are: * \csets * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL H5T_cset_t H5Tget_cset(hid_t type_id); @@ -2378,7 +2402,7 @@ H5_DLL hid_t H5Tget_native_type(hid_t type_id, H5T_direction_t direction); * * \see H5Tget_size() * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_size(hid_t type_id, size_t size); @@ -2417,7 +2441,7 @@ H5_DLL herr_t H5Tset_size(hid_t type_id, size_t size); * have the same byte order. * \li Opaque datatypes: Byte order can be set but has no effect. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_order(hid_t type_id, H5T_order_t order); @@ -2447,7 +2471,7 @@ H5_DLL herr_t H5Tset_order(hid_t type_id, H5T_order_t order); * locations and sizes of the sign, mantissa, and exponent fields * first. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_precision(hid_t type_id, size_t prec); @@ -2481,7 +2505,7 @@ H5_DLL herr_t H5Tset_precision(hid_t type_id, size_t prec); * * The offset of an #H5T_STRING cannot be set to anything but zero. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_offset(hid_t type_id, size_t offset); @@ -2517,7 +2541,7 @@ H5_DLL herr_t H5Tset_pad(hid_t type_id, H5T_pad_t lsb, H5T_pad_t msb); * \details H5Tset_sign() sets the sign property for an integer type: * \sign_prop * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_sign(hid_t type_id, H5T_sign_t sign); @@ -2544,7 +2568,7 @@ H5_DLL herr_t H5Tset_sign(hid_t type_id, H5T_sign_t sign); * Fields are not allowed to extend beyond the number of bits of * precision, nor are they allowed to overlap with one another. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_fields(hid_t type_id, size_t spos, size_t epos, size_t esize, size_t mpos, size_t msize); @@ -2560,7 +2584,7 @@ H5_DLL herr_t H5Tset_fields(hid_t type_id, size_t spos, size_t epos, size_t esiz * * \details H5Tset_ebias() sets the exponent bias of a floating-point type. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_ebias(hid_t type_id, size_t ebias); @@ -2578,7 +2602,7 @@ H5_DLL herr_t H5Tset_ebias(hid_t type_id, size_t ebias); * datatype. Valid normalization types are: * \snippet this H5T_norm_t_snip * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_norm(hid_t type_id, H5T_norm_t norm); @@ -2599,7 +2623,7 @@ H5_DLL herr_t H5Tset_norm(hid_t type_id, H5T_norm_t norm); * padding types are: * \snippet this H5T_pad_t_snip * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_inpad(hid_t type_id, H5T_pad_t pad); @@ -2632,7 +2656,7 @@ H5_DLL herr_t H5Tset_inpad(hid_t type_id, H5T_pad_t pad); * string datatype while H5Pset_char_encoding() sets the character * set used for an HDF5 link or attribute name. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_cset(hid_t type_id, H5T_cset_t cset); @@ -2664,7 +2688,7 @@ H5_DLL herr_t H5Tset_cset(hid_t type_id, H5T_cset_t cset); * When converting from a shorter string to a longer string, the * longer string is padded on the end by appending nulls or spaces. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL herr_t H5Tset_strpad(hid_t type_id, H5T_str_t strpad); @@ -2708,6 +2732,8 @@ H5_DLL herr_t H5Tset_strpad(hid_t type_id, H5T_str_t strpad); * \version 1.6.3 \p nelmts parameter type changed to size_t. * \version 1.4.0 \p nelmts parameter type changed to hsize_t. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Tconvert(hid_t src_id, hid_t dst_id, size_t nelmts, void *buf, void *background, hid_t plist_id); @@ -2829,7 +2855,7 @@ H5_DLL herr_t H5Tcommit1(hid_t loc_id, const char *name, hid_t type_id); * \version 1.8.0 Function H5Topen() renamed to H5Topen1() and deprecated in * this release. * - * \since 1.2.0 + * \since 1.0.0 * */ H5_DLL hid_t H5Topen1(hid_t loc_id, const char *name); @@ -2864,6 +2890,7 @@ H5_DLL hid_t H5Topen1(hid_t loc_id, const char *name); * * \version 1.8.0 Function H5Tarray_create() renamed to H5Tarray_create1() * and deprecated in this release. + * * \since 1.4.0 * */ @@ -2892,7 +2919,8 @@ H5_DLL hid_t H5Tarray_create1(hid_t base_id, int ndims, const hsize_t dim[/* ndi * * \version 1.8.0 Function H5Tarray_create() renamed to H5Tarray_create1() * and deprecated in this release. - * \since 1.2.0 + * + * \since 1.4.0 * */ H5_DLL int H5Tget_array_dims1(hid_t type_id, hsize_t dims[], int perm[]); diff --git a/src/H5Zdevelop.h b/src/H5Zdevelop.h index 736c283..fb3b71b 100644 --- a/src/H5Zdevelop.h +++ b/src/H5Zdevelop.h @@ -145,6 +145,9 @@ typedef herr_t (*H5Z_set_local_func_t)(hid_t dcpl_id, hid_t type_id, hid_t space * The return value from the filter is the number of bytes in the * output buffer. If an error occurs then the function should return * zero and leave all pointer arguments unchanged. + * + * \since 1.0.0 + * */ //! <!-- [H5Z_func_t_snip] --> typedef size_t (*H5Z_func_t)(unsigned int flags, size_t cd_nelmts, const unsigned int cd_values[], @@ -379,6 +382,8 @@ extern "C" { * a new #H5Z_class_t struct and new set local and can apply * callback functions. * + * \since 1.0.0 + * */ H5_DLL herr_t H5Zregister(const void *cls); /** diff --git a/src/H5Zpublic.h b/src/H5Zpublic.h index d906e3c..44d91c0 100644 --- a/src/H5Zpublic.h +++ b/src/H5Zpublic.h @@ -304,7 +304,7 @@ H5_DLL htri_t H5Zfilter_avail(H5Z_filter_t id); * such as H5Pset_szip(), that might require a particular filter * configuration. * - * \since 1.6.3 + * \since 1.6.0 */ H5_DLL herr_t H5Zget_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags); diff --git a/src/H5private.h b/src/H5private.h index 3aaa0d5..5663c00 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -497,8 +497,16 @@ #define H5_DIAG_DO_PRAGMA(x) _Pragma(#x) #define H5_DIAG_PRAGMA(x) H5_DIAG_DO_PRAGMA(GCC diagnostic x) +/* Allow suppression of compiler diagnostics unless H5_SHOW_ALL_WARNINGS is + * defined (enabled with '--enable-show-all-warnings' configure option). + */ +#ifndef H5_SHOW_ALL_WARNINGS #define H5_DIAG_OFF(x) H5_DIAG_PRAGMA(push) H5_DIAG_PRAGMA(ignored H5_DIAG_JOINSTR("-W", x)) #define H5_DIAG_ON(x) H5_DIAG_PRAGMA(pop) +#else +#define H5_DIAG_OFF(x) +#define H5_DIAG_ON(x) +#endif /* Macros for enabling/disabling particular GCC-only warnings. * These pragmas are only implemented usefully in gcc 4.6+ diff --git a/src/H5public.h b/src/H5public.h index a40ca00..9eb0d93 100644 --- a/src/H5public.h +++ b/src/H5public.h @@ -429,6 +429,9 @@ extern "C" { * H5open() before an application issues any other function calls to * the HDF5 library, as there are no damaging side effects in calling * it more than once. + * + * \since 1.0.0 + * */ H5_DLL herr_t H5open(void); /** @@ -468,6 +471,9 @@ H5_DLL herr_t H5atclose(H5_atclose_func_t func, void *ctx); * generally called when the application calls exit(), but may be * called earlier in the event of an emergency shutdown or out of a * desire to free all resources used by the HDF5 library. + * + * \since 1.0.0 + * */ H5_DLL herr_t H5close(void); /** @@ -487,6 +493,9 @@ H5_DLL herr_t H5close(void); * before any other HDF5 function calls, and must be called each * time the library is loaded/linked into the application (the first * time and after it's been unloaded). + * + * \since 1.0.0 + * */ H5_DLL herr_t H5dont_atexit(void); /** @@ -507,6 +516,9 @@ H5_DLL herr_t H5dont_atexit(void); * * \note The library automatically garbage collects all the free lists when the * application ends. + * + * \since 1.4.0 + * */ H5_DLL herr_t H5garbage_collect(void); /** @@ -559,7 +571,7 @@ H5_DLL herr_t H5garbage_collect(void); * \version 1.8.3 Function changed in this release to set factory free list * memory limits. * - * \since 1.6.0 + * \since 1.4.0 */ H5_DLL herr_t H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim); @@ -595,6 +607,8 @@ H5_DLL herr_t H5get_free_list_sizes(size_t *reg_size, size_t *arr_size, size_t * * of the version of the HDF5 library which is linked to the * application. * + * \since 1.0.0 + * */ H5_DLL herr_t H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *relnum); /** @@ -643,6 +657,8 @@ H5_DLL herr_t H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *rel * informational warning is printed but the application is allowed to * run. * + * \since 1.0.0 + * */ H5_DLL herr_t H5check_version(unsigned majnum, unsigned minnum, unsigned relnum); /** @@ -675,6 +691,9 @@ H5_DLL herr_t H5is_library_terminating(hbool_t *is_terminating); * data structures with a mutex. In certain circumstances, it may be * useful to determine, at run-time, whether the linked HDF5 library * was built with the thread-safety feature enabled. + * + * \since 1.10.0 + * */ H5_DLL herr_t H5is_library_threadsafe(hbool_t *is_ts); /** |