Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SWMR in HDF5 (updated) #2653

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
633182a
Initial implementation
eivindlm Jul 10, 2019
757207f
Move up call to flush
eivindlm Jul 31, 2019
ba9362a
Merge branch 'master' into hdf5_swmr
eivindlm Jul 31, 2019
932d6e0
Expand test
eivindlm Jul 31, 2019
f0f3543
Add flag H5F_ACC_SWMR_WRITE to H5Fcreate if we do not have H5P_set_li…
eivindlm Jul 31, 2019
cd4cd05
Protect usage of swmr by ifdefs
eivindlm Aug 6, 2019
9a4e0b5
Merge branch 'master' into hdf5_swmr
eivindlm Aug 6, 2019
f5b8580
Merge branch 'main' into hdf5_swmr
ZedThree Mar 6, 2023
31c2ddd
Fix typo in option name
ZedThree Mar 6, 2023
8f0a2fc
Add preprocessor define for HDF5 SWMR to `config.h`
ZedThree Mar 6, 2023
0579c47
Add `--enable-hdf5-swmr` argument to `configure.ac`
ZedThree Mar 7, 2023
ea1d617
Remove use of deleted `HAVE_H5PSET_LIBVER_BOUNDS` macro
ZedThree Mar 7, 2023
cbbb873
Call `H5Pset_libver_bounds` when opening HDF5 file for SWMR
ZedThree Mar 7, 2023
ccdc9ff
Rely on file open flag to enable SWMR rather than manual start
ZedThree Mar 7, 2023
2509d84
Set feature flags for HDF5 SWMR support in netcdf_meta.h/nc-config
ZedThree Mar 7, 2023
feaa758
Merge branch 'main' into hdf5_swmr
ZedThree Nov 14, 2023
3614023
Merge branch 'main' into hdf5_swmr
ZedThree Nov 20, 2023
c8a85c4
CMake: Fix detecting HDF5 SWMR support
ZedThree Nov 20, 2023
cfdb7ef
Refresh dataset metadata before reading, if using HDF5 SWMR
ZedThree Nov 20, 2023
2d1725b
Only auto-flush data if in SWMR mode
ZedThree Nov 20, 2023
cae96c9
Don't set libver bounds for SWMR mode
ZedThree Nov 23, 2023
da731ec
Use unique flag for SWMR mode
ZedThree Nov 23, 2023
6935930
Refresh variable metadata when getting dimension length for SWMR
ZedThree Nov 23, 2023
ff7bde5
Add test that properly exercises SWMR mode
ZedThree Nov 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,8 @@ IF(ENABLE_HDF4)
ENDIF()
ENDIF()

OPTION(ENABLE_HDF5_SWMR "Support SWMR in HDF5. This requires HDF version 1.10 or later" OFF)

# Option to Build DLL
IF(WIN32)
OPTION(ENABLE_DLL "Build a Windows DLL." ${BUILD_SHARED_LIBS})
Expand Down Expand Up @@ -653,7 +655,10 @@ IF(USE_HDF5)
# Assert HDF5 version meets minimum required version.
##
SET(HDF5_VERSION_REQUIRED 1.8.10)

IF(ENABLE_HDF5_SWMR)
SET(HDF5_VERSION_REQUIRED 1.10)
MESSAGE(STATUS "HDF5 SWMR is enabled. This implies that HDF5 version at least ${HDF5_VERSION_REQUIRED} is required.")
ENDIF()

##
# Accommodate developers who have hdf5 libraries and
Expand Down Expand Up @@ -774,8 +779,6 @@ IF(USE_HDF5)
MESSAGE(FATAL_ERROR "netCDF requires at least HDF5 ${HDF5_VERSION_REQUIRED}. Found ${HDF5_VERSION}.")
ENDIF()



##
# Include the HDF5 include directory.
##
Expand Down Expand Up @@ -840,6 +843,11 @@ IF(USE_HDF5)

ENDIF(HDF5_C_LIBRARY AND HDF5_HL_LIBRARY AND HDF5_INCLUDE_DIR)

# Requesting SWMR support sets the minimum version to 1.10, so if
# we've got this far, we've got SWMR support
set(HDF5_HAS_SWMR ${ENABLE_HDF5_SWMR})
message(STATUS "HDF5 SWMR support: ${HDF5_HAS_SWMR}")

FIND_PACKAGE(Threads)

# There is a missing case in the above code so default it
Expand Down Expand Up @@ -2575,6 +2583,7 @@ is_enabled(ENABLE_V2_API HAS_NC2)
is_enabled(ENABLE_NETCDF_4 HAS_NC4)
is_enabled(ENABLE_HDF4 HAS_HDF4)
is_enabled(USE_HDF5 HAS_HDF5)
is_enabled(HDF5_HAS_SWMR HAS_HDF5_SWMR)
is_enabled(OFF HAS_BENCHMARKS)
is_enabled(STATUS_PNETCDF HAS_PNETCDF)
is_enabled(STATUS_PARALLEL HAS_PARALLEL)
Expand Down
3 changes: 3 additions & 0 deletions config.h.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,9 @@ with zip */
/* if true, HDF5 is at least version 1.10.5 and supports UTF8 paths */
#cmakedefine HDF5_UTF8_PATHS 1

/* if true, HDF5 is at least version 1.10 and supports single-writer multiple-reader IO */
#cmakedefine HDF5_HAS_SWMR 1

/* if true, include JNA bug fix */
#cmakedefine JNA 1

Expand Down
20 changes: 19 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ if test "x$enable_netcdf4" = xno ; then enable_hdf5=no ; fi
# disable-netcdf4 is synonym for disable-hdf5
AC_MSG_RESULT([$enable_hdf5])

AC_MSG_CHECKING([whether we should build with HDF5 SWMR support])
AC_ARG_ENABLE([hdf5_swmr], [AS_HELP_STRING([--enable-hdf5-swmr],
[build with HDF5 SWMR support (requires HDF5 version 1.10 or later)])])
test "x$enable_hdf5_swmr" = xyes || enable_hdf5_swmr=no
if test "x$enable_hdf5" = xno ; then enable_hdf5_swmr=no ; fi
# Don't enable HDF5 SWMR if we're not using HDF5
AC_MSG_RESULT([$enable_hdf5_swmr])

# Check whether we want to enable CDF5 support.
AC_MSG_CHECKING([whether CDF5 support should be disabled])
AC_ARG_ENABLE([cdf5],
Expand Down Expand Up @@ -1593,6 +1601,7 @@ fi
hdf5_parallel=no
hdf5_supports_par_filters=no
enable_hdf5_szip=no
hdf5_swmr=no
has_hdf5_ros3=no

if test "x$enable_hdf5" = xyes; then
Expand All @@ -1619,7 +1628,7 @@ if test "x$enable_hdf5" = xyes; then
# H5Pset_fapl_mpiposix and H5Pget_fapl_mpiposix have been removed since HDF5 1.8.12.
# Use H5Pset_fapl_mpio and H5Pget_fapl_mpio, instead.

AC_CHECK_FUNCS([H5Pget_fapl_mpio H5Pset_deflate H5Z_SZIP H5Pset_all_coll_metadata_ops H5Literate])
AC_CHECK_FUNCS([H5Pget_fapl_mpio H5Pset_deflate H5Z_SZIP H5Pset_all_coll_metadata_ops H5Literate H5Fstart_swmr_write])

# Check to see if HDF5 library has collective metadata APIs, (HDF5 >= 1.10.0)
if test "x$ac_cv_func_H5Pset_all_coll_metadata_ops" = xyes; then
Expand Down Expand Up @@ -1681,6 +1690,13 @@ if test "x$enable_hdf5" = xyes; then
AC_DEFINE([HDF5_UTF8_PATHS], [1], [if true, HDF5 paths can be utf-8])
fi

if test "x$enable_hdf5_swmr" = xyes && test "x$ac_cv_func_H5Fstart_swmr_write" = xyes; then
hdf5_swmr=yes
AC_DEFINE([HDF5_HAS_SWMR], [1], [if true, HDF5 supports single-writer multiple-reader])
fi
AC_MSG_CHECKING([whether HDF5 supports SWMR])
AC_MSG_RESULT([$hdf5_swmr])

fi

AM_CONDITIONAL(ENABLE_NCDUMPCHUNKS, [test "x$has_readchunks" = xyes ])
Expand Down Expand Up @@ -2029,6 +2045,7 @@ AC_SUBST(HAS_CDF5,[$enable_cdf5])
AC_SUBST(HAS_HDF4,[$enable_hdf4])
AC_SUBST(HAS_BENCHMARKS,[$enable_benchmarks])
AC_SUBST(HAS_HDF5,[$enable_hdf5])
AC_SUBST(HAS_HDF5_SWMR,[$hdf5_swmr])
AC_SUBST(HAS_PNETCDF,[$enable_pnetcdf])
AC_SUBST(HAS_LOGGING, [$enable_logging])
AC_SUBST(HAS_PARALLEL,[$enable_parallel])
Expand Down Expand Up @@ -2194,6 +2211,7 @@ AX_SET_META([NC_HAS_NC4],[$enable_netcdf_4],[yes])
AX_SET_META([NC_HAS_HDF4],[$enable_hdf4],[yes])
AX_SET_META([NC_HAS_BENCHMARKS],[$enable_benchmarks],[yes])
AX_SET_META([NC_HAS_HDF5],[$enable_hdf5],[yes])
AX_SET_META([NC_HAS_HDF5_SWMR],[$enable_hdf5_swmr],[yes])
AX_SET_META([NC_HAS_DAP2],[$enable_dap],[yes])
AX_SET_META([NC_HAS_DAP4],[$enable_dap4],[yes])
AX_SET_META([NC_HAS_DISKLESS],[yes],[yes])
Expand Down
1 change: 1 addition & 0 deletions include/netcdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ Use this in mode flags for both nc_create() and nc_open(). */

#define NC_PERSIST 0x4000 /**< Save diskless contents to disk. Mode flag for nc_open() or nc_create() */
#define NC_INMEMORY 0x8000 /**< Read from memory. Mode flag for nc_open() or nc_create() */
#define NC_HDF5_SWMR 0x10000 /**< Enable HDF5's Single Writer Multiple Reader mode **/

/* Upper 16 bits */
#define NC_NOATTCREORD 0x20000 /**< Disable the netcdf-4 (hdf5) attribute creation order tracking */
Expand Down
1 change: 1 addition & 0 deletions include/netcdf_meta.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define NC_HAS_NC4 @NC_HAS_NC4@ /*!< API version 4 support. */
#define NC_HAS_HDF4 @NC_HAS_HDF4@ /*!< HDF4 support. */
#define NC_HAS_HDF5 @NC_HAS_HDF5@ /*!< HDF5 support. */
#define NC_HAS_HDF5_SWMR @NC_HAS_HDF5_SWMR@ /*!< HDF5 single-writer multiple reader support. */
#define NC_HAS_SZIP @NC_HAS_SZIP@ /*!< szip support */
#define NC_HAS_SZIP_WRITE @NC_HAS_SZIP@ /*!< szip write support */
#define NC_HAS_DAP2 @NC_HAS_DAP2@ /*!< DAP2 support. */
Expand Down
6 changes: 6 additions & 0 deletions libhdf5/hdf5create.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ nc4_create_file(const char *path, int cmode, size_t initialsz,
NC_FILE_INFO_T *nc4_info;
NC_HDF5_FILE_INFO_T *hdf5_info;
NC_HDF5_GRP_INFO_T *hdf5_grp;
H5F_libver_t low, high;

#ifdef USE_PARALLEL4
NC_MPI_INFO *mpiinfo = NULL;
Expand Down Expand Up @@ -103,6 +104,11 @@ nc4_create_file(const char *path, int cmode, size_t initialsz,
else
flags = H5F_ACC_TRUNC;

#ifdef HDF5_HAS_SWMR
if (cmode & NC_HDF5_SWMR)
flags |= H5F_ACC_SWMR_WRITE;
#endif

/* If this file already exists, and NC_NOCLOBBER is specified,
return an error (unless diskless|inmemory) */
if (!nc4_info->mem.diskless && !nc4_info->mem.inmemory) {
Expand Down
17 changes: 16 additions & 1 deletion libhdf5/hdf5open.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* @author Ed Hartnett
*/

#include "H5version.h"
#include "config.h"
#include "hdf5internal.h"
#include "hdf5err.h"
Expand Down Expand Up @@ -724,7 +725,21 @@ nc4_open_file(const char *path, int mode, void* parameters, int ncid)
assert(nc);

/* Determine the HDF5 open flag to use. */
flags = (mode & NC_WRITE) ? H5F_ACC_RDWR : H5F_ACC_RDONLY;
if((mode & NC_WRITE)) {
flags = H5F_ACC_RDWR;
#ifdef HDF5_HAS_SWMR
if((mode & NC_HDF5_SWMR)) {
flags |= H5F_ACC_SWMR_WRITE;
}
#endif
} else {
flags = H5F_ACC_RDONLY;
#ifdef HDF5_HAS_SWMR
if((mode & NC_HDF5_SWMR)) {
flags |= H5F_ACC_SWMR_READ;
}
#endif
}

/* Add necessary structs to hold netcdf-4 file data. */
if ((retval = nc4_nc4f_list_add(nc, path, mode)))
Expand Down
19 changes: 19 additions & 0 deletions libhdf5/hdf5var.c
Original file line number Diff line number Diff line change
Expand Up @@ -1796,6 +1796,15 @@ NC4_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
BAIL(NC_EHDFERR);

#ifdef HDF5_HAS_SWMR
/* Flush data for SWMR */
if (h5->cmode & NC_HDF5_SWMR)
{
if (H5Dflush(hdf5_var->hdf_datasetid) < 0)
BAIL(NC_EHDFERR);
}
#endif

/* Remember that we have written to this var so that Fill Value
* can't be set for it. */
if (!var->written_to)
Expand Down Expand Up @@ -1824,6 +1833,7 @@ NC4_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
return retval;
if (range_error)
return NC_ERANGE;

return NC_NOERR;
}

Expand Down Expand Up @@ -1898,6 +1908,15 @@ NC4_get_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__,
var->hdr.name, mem_nc_type));

#ifdef HDF5_HAS_SWMR
/* Refresh dataset metadata, required if opened in SWMR mode */
if (h5->cmode & NC_HDF5_SWMR)
{
if (H5Drefresh(hdf5_var->hdf_datasetid) < 0)
BAIL(NC_EHDFERR);
}
#endif

/* Check some stuff about the type and the file. Also end define
* mode, if needed. */
if ((retval = check_for_vara(&mem_nc_type, var, h5)))
Expand Down
10 changes: 10 additions & 0 deletions libhdf5/nc4hdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,16 @@ nc4_open_var_grp2(NC_GRP_INFO_T *grp, int varid, hid_t *dataset)
if ((hdf5_var->hdf_datasetid = H5Dopen2(hdf5_grp->hdf_grpid,
var->hdr.name, H5P_DEFAULT)) < 0)
return NC_ENOTVAR;
} else {
#ifdef HDF5_HAS_SWMR
/* If file is opened in SWMR mode, we need to refresh the
* dataset's metadata */
if (grp->nc4_info->cmode & NC_HDF5_SWMR)
{
if (H5Drefresh(hdf5_var->hdf_datasetid) < 0)
return NC_EHDFERR;
}
#endif
}

*dataset = hdf5_var->hdf_datasetid;
Expand Down
13 changes: 13 additions & 0 deletions nc-config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ else
has_hdf5="yes"
fi

has_hdf5_swmr="@HDF5_HAS_SWMR@"
if [ -z "$has_hdf5_swmr" -o "$has_hdf5_swmr" = "OFF" ]; then
has_hdf5_swmr="no"
else
has_hdf5_swmr="yes"
fi

has_szlib="@USE_SZIP@"
if [ -z "$has_szlib" -o "$has_szlib" = "OFF" ]; then
has_szlib="no"
Expand Down Expand Up @@ -152,6 +159,7 @@ Available values for OPTION include:
--has-nc2 whether NetCDF-2 API is enabled
--has-nc4 whether NetCDF-4/HDF-5 is enabled in this build
--has-hdf5 whether HDF5 is used in build (always the same as --has-nc4)
--has-hdf5-swmr whether HDF5 single-writer multiple-reader mode is supported
--has-hdf4 whether HDF4 was used in build
--has-logging whether logging is enabled with --enable-logging.
--has-pnetcdf whether PnetCDF was used in build
Expand Down Expand Up @@ -197,6 +205,7 @@ all()
echo " --has-nc2 -> $has_nc2"
echo " --has-nc4 -> $has_nc4"
echo " --has-hdf5 -> $has_hdf5"
echo " --has-hdf5-swmr -> $has_hdf5_swmr"
echo " --has-hdf4 -> $has_hdf4"
echo " --has-logging -> $has_logging"
echo " --has-pnetcdf -> $has_pnetcdf"
Expand Down Expand Up @@ -288,6 +297,10 @@ while test $# -gt 0; do
echo $has_hdf5
;;

--has-hdf5-swmr)
echo $has_hdf5_swmr
;;

--has-hdf4)
echo $has_hdf4
;;
Expand Down
7 changes: 7 additions & 0 deletions nc-config.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ has_nc4="@HAS_NC4@"
has_hdf4="@HAS_HDF4@"
has_pnetcdf="@HAS_PNETCDF@"
has_hdf5="@HAS_HDF5@"
has_hdf5_swmr="@HAS_HDF5_SWMR@"
has_logging="@HAS_LOGGING@"
has_cdf5="@HAS_CDF5@"
has_szlib="@HAS_SZLIB@"
Expand Down Expand Up @@ -59,6 +60,7 @@ Available values for OPTION include:
--has-nc2 whether NetCDF-2 API is enabled
--has-nc4 whether NetCDF-4/HDF-5 is enabled in this build
--has-hdf5 whether HDF5 is used in build (always the same as --has-nc4)
--has-hdf5-swmr whether HDF5 single-writer multiple-reader mode is supported
--has-hdf4 whether HDF4 was used in build
--has-logging whether logging is enabled with --enable-logging.
--has-pnetcdf whether PnetCDF was used in build
Expand Down Expand Up @@ -101,6 +103,7 @@ all()
echo " --has-nc2 -> $has_nc2"
echo " --has-nc4 -> $has_nc4"
echo " --has-hdf5 -> $has_hdf5"
echo " --has-hdf5-swmr -> $has_hdf5_swmr"
echo " --has-hdf4 -> $has_hdf4"
echo " --has-logging -> $has_logging"
echo " --has-pnetcdf -> $has_pnetcdf"
Expand Down Expand Up @@ -193,6 +196,10 @@ while test $# -gt 0; do
echo $has_hdf5
;;

--has-hdf5-swmr)
echo $has_hdf5_swmr
;;

--has-hdf4)
echo $has_hdf4
;;
Expand Down
6 changes: 6 additions & 0 deletions nc_test4/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ IF(${HDF5_VERSION} VERSION_GREATER "1.10.0")
SET(NC4_TESTS ${NC4_TESTS} tst_virtual_datasets)
ENDIF(${HDF5_VERSION} VERSION_GREATER "1.10.0")

if (ENABLE_HDF5_SWMR)
build_bin_test(test_hdf5_swmr_writer)
build_bin_test(test_hdf5_swmr_reader)
add_sh_test(nc_test4 test_hdf5_swmr)
endif()

##
# The shell script, run_empty_vlen_test.sh,
# depends on the 'tst_empty_vlen_unlim' binary.
Expand Down
35 changes: 35 additions & 0 deletions nc_test4/test_hdf5_swmr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env bash

# Test ability to use HDF5's SWMR functionality to simultaneously
# write to and read from a file in different processes.
#
# 1. Create file, enabling SWMR mode; create all variables
# 2. Close and reopen file for writing in SWMR mode
# 3. Then open file in a separate process for SWMR reading
#
# Note that these *must* happen sequentially -- the reader process
# *must not* start until the writer process in step 2 has started.
#
# At this point we can perform some tests on the file.

if test "x$srcdir" = x ; then srcdir=`pwd`; fi
. ../test_common.sh

set -e

# Clean up any test files
rm -f ./test_hdf5_swmr_file.nc

echo " *** Testing SWMR mode"

# Launch the writer process in the background
${execdir}/test_hdf5_swmr_writer &

# Pause briefly here to ensure writer process has both created file
# and then *reopened it*
sleep 0.5

# Now we're safe to launch the reader process
${execdir}/test_hdf5_swmr_reader

echo " *** Pass: SWMR mode"
Loading
Loading