From 6c85d3e05bfcf87222e8b1c86549a8becdeb2111 Mon Sep 17 00:00:00 2001 From: Mike Gevaert Date: Tue, 7 Apr 2026 15:13:40 +0200 Subject: [PATCH 1/5] Add support for setting the locking behavior when opening file * useful when on a shared filesystem that limits the number of locks, and files are only being read --- doc/developer_guide.md | 2 +- include/highfive/H5PropertyList.hpp | 21 +++++++++++++++++++ include/highfive/bits/H5PropertyList_misc.hpp | 7 +++++++ include/highfive/bits/h5p_wrapper.hpp | 8 +++++++ tests/unit/tests_high_five_base.cpp | 11 ++++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/doc/developer_guide.md b/doc/developer_guide.md index 8c378d12..2c697f5d 100644 --- a/doc/developer_guide.md +++ b/doc/developer_guide.md @@ -206,7 +206,7 @@ is a sensible thing to do. We assume similar about `bool` and Anything `H5Easy` related goes in files with the appropriate name. #### Everything Else -What's left goes in `tests/unit/test_high_five_base.cpp`. This covers opening +What's left goes in `tests/unit/tests_high_five_base.cpp`. This covers opening files, groups, dataset or attributes; checking certain pathological edge cases; etc. diff --git a/include/highfive/H5PropertyList.hpp b/include/highfive/H5PropertyList.hpp index ee48e6ae..6ccb3994 100644 --- a/include/highfive/H5PropertyList.hpp +++ b/include/highfive/H5PropertyList.hpp @@ -714,6 +714,27 @@ class AttributePhaseChange { unsigned _min_dense; }; +/// +/// \brief Set locking FileAccessProps +/// +/// Since HDF5 in version 1.10.0, `single-writer / multiple-readers` support was added. +/// To achieve this, locks were added when accessing the file. +/// They can be disabled with the `HDF5_USE_FILE_LOCKING` environment variable. +/// However, if it's known at access time that one will never have another process writing the file, +/// the locks can be avoided. +/// +/// See more in https://support.hdfgroup.org/documentation/hdf5/latest/_file_lock.html +/// +class FileLocking { + public: + explicit FileLocking(bool use_file_locking, bool ignore_when_disabled); + void apply(const hid_t list) const; + private: + friend FileAccessProps; + bool _use_file_locking; + bool _ignore_when_disabled; +}; + /// @} } // namespace HighFive diff --git a/include/highfive/bits/H5PropertyList_misc.hpp b/include/highfive/bits/H5PropertyList_misc.hpp index 8116e8c7..35ac0dac 100644 --- a/include/highfive/bits/H5PropertyList_misc.hpp +++ b/include/highfive/bits/H5PropertyList_misc.hpp @@ -501,5 +501,12 @@ inline void AttributePhaseChange::apply(hid_t hid) const { detail::h5p_set_attr_phase_change(hid, _max_compact, _min_dense); } +inline FileLocking::FileLocking(bool use_file_locking, bool ignore_when_disabled) + : _use_file_locking(use_file_locking) + , _ignore_when_disabled(ignore_when_disabled) { } + +inline void FileLocking::apply(hid_t hid) const { + detail::h5p_set_file_locking(hid, _use_file_locking, _ignore_when_disabled); +} } // namespace HighFive diff --git a/include/highfive/bits/h5p_wrapper.hpp b/include/highfive/bits/h5p_wrapper.hpp index 88872f51..249123c1 100644 --- a/include/highfive/bits/h5p_wrapper.hpp +++ b/include/highfive/bits/h5p_wrapper.hpp @@ -371,6 +371,14 @@ inline herr_t h5p_set_attr_phase_change(hid_t plist_id, unsigned max_compact, un return err; } +inline herr_t h5p_set_file_locking(hid_t plist_id, bool use_file_locking, bool ignore_when_disabled) { + herr_t err = H5Pset_file_locking(plist_id, use_file_locking, ignore_when_disabled); + if (err < 0) { + HDF5ErrMapper::ToException("Unable to set locking"); + } + return err; +} + } // namespace detail } // namespace HighFive diff --git a/tests/unit/tests_high_five_base.cpp b/tests/unit/tests_high_five_base.cpp index 59bf6f89..d219637e 100644 --- a/tests/unit/tests_high_five_base.cpp +++ b/tests/unit/tests_high_five_base.cpp @@ -1273,6 +1273,17 @@ TEST_CASE("AttributePhaseChange") { } } +TEST_CASE("Locking") { + auto fapl = HighFive::FileAccessProps::Default(); + fapl.add(HighFive::FileLocking(true, false)); + std::string path = "openmodes.h5"; + HighFive::File file(path, HighFive::File::ReadOnly, fapl); + + // can't open the same file twice with different locking + CHECK_THROWS_AS(HighFive::File(path), FileException); +} + + TEST_CASE("datasetOffset") { std::string filename = "datasetOffset.h5"; std::string dsetname = "dset"; From b3a9fa0a73eba96146c11bc1c128c4165e9c0922 Mon Sep 17 00:00:00 2001 From: Mike Gevaert Date: Wed, 15 Apr 2026 15:54:48 +0200 Subject: [PATCH 2/5] explicit difference in locking while opening the same file --- tests/unit/tests_high_five_base.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/unit/tests_high_five_base.cpp b/tests/unit/tests_high_five_base.cpp index d219637e..60249ab0 100644 --- a/tests/unit/tests_high_five_base.cpp +++ b/tests/unit/tests_high_five_base.cpp @@ -1274,13 +1274,15 @@ TEST_CASE("AttributePhaseChange") { } TEST_CASE("Locking") { - auto fapl = HighFive::FileAccessProps::Default(); - fapl.add(HighFive::FileLocking(true, false)); + auto fapl0 = HighFive::FileAccessProps::Default(); + fapl0.add(HighFive::FileLocking(true, false)); std::string path = "openmodes.h5"; - HighFive::File file(path, HighFive::File::ReadOnly, fapl); + HighFive::File file(path, HighFive::File::ReadOnly, fapl0); // can't open the same file twice with different locking - CHECK_THROWS_AS(HighFive::File(path), FileException); + auto fapl1 = HighFive::FileAccessProps::Default(); + fapl1.add(HighFive::FileLocking(false, false)); + CHECK_THROWS_AS(HighFive::File(path, HighFive::File::ReadOnly, fapl1), FileException); } From f4860e2568b10e65095ebecddbbcd2518cc36add Mon Sep 17 00:00:00 2001 From: Mike Gevaert Date: Wed, 15 Apr 2026 15:55:46 +0200 Subject: [PATCH 3/5] fix format --- include/highfive/H5PropertyList.hpp | 1 + include/highfive/bits/H5PropertyList_misc.hpp | 2 +- include/highfive/bits/h5p_wrapper.hpp | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/highfive/H5PropertyList.hpp b/include/highfive/H5PropertyList.hpp index 6ccb3994..6cdcd461 100644 --- a/include/highfive/H5PropertyList.hpp +++ b/include/highfive/H5PropertyList.hpp @@ -729,6 +729,7 @@ class FileLocking { public: explicit FileLocking(bool use_file_locking, bool ignore_when_disabled); void apply(const hid_t list) const; + private: friend FileAccessProps; bool _use_file_locking; diff --git a/include/highfive/bits/H5PropertyList_misc.hpp b/include/highfive/bits/H5PropertyList_misc.hpp index 35ac0dac..bdcffed2 100644 --- a/include/highfive/bits/H5PropertyList_misc.hpp +++ b/include/highfive/bits/H5PropertyList_misc.hpp @@ -503,7 +503,7 @@ inline void AttributePhaseChange::apply(hid_t hid) const { inline FileLocking::FileLocking(bool use_file_locking, bool ignore_when_disabled) : _use_file_locking(use_file_locking) - , _ignore_when_disabled(ignore_when_disabled) { } + , _ignore_when_disabled(ignore_when_disabled) {} inline void FileLocking::apply(hid_t hid) const { detail::h5p_set_file_locking(hid, _use_file_locking, _ignore_when_disabled); diff --git a/include/highfive/bits/h5p_wrapper.hpp b/include/highfive/bits/h5p_wrapper.hpp index 249123c1..1daf17b9 100644 --- a/include/highfive/bits/h5p_wrapper.hpp +++ b/include/highfive/bits/h5p_wrapper.hpp @@ -371,7 +371,9 @@ inline herr_t h5p_set_attr_phase_change(hid_t plist_id, unsigned max_compact, un return err; } -inline herr_t h5p_set_file_locking(hid_t plist_id, bool use_file_locking, bool ignore_when_disabled) { +inline herr_t h5p_set_file_locking(hid_t plist_id, + bool use_file_locking, + bool ignore_when_disabled) { herr_t err = H5Pset_file_locking(plist_id, use_file_locking, ignore_when_disabled); if (err < 0) { HDF5ErrMapper::ToException("Unable to set locking"); From 7b9c74642f9aca27c4333523711ea5fc14d67aff Mon Sep 17 00:00:00 2001 From: Mike Gevaert Date: Wed, 22 Apr 2026 13:28:12 +0200 Subject: [PATCH 4/5] test simple call --- tests/unit/tests_high_five_base.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/unit/tests_high_five_base.cpp b/tests/unit/tests_high_five_base.cpp index 60249ab0..a2c1b8b4 100644 --- a/tests/unit/tests_high_five_base.cpp +++ b/tests/unit/tests_high_five_base.cpp @@ -1273,16 +1273,10 @@ TEST_CASE("AttributePhaseChange") { } } -TEST_CASE("Locking") { - auto fapl0 = HighFive::FileAccessProps::Default(); - fapl0.add(HighFive::FileLocking(true, false)); - std::string path = "openmodes.h5"; - HighFive::File file(path, HighFive::File::ReadOnly, fapl0); - - // can't open the same file twice with different locking - auto fapl1 = HighFive::FileAccessProps::Default(); - fapl1.add(HighFive::FileLocking(false, false)); - CHECK_THROWS_AS(HighFive::File(path, HighFive::File::ReadOnly, fapl1), FileException); +TEST_CASE("FileAccessProps-FileLocking") { + auto fapl = HighFive::FileAccessProps::Default(); + fapl.add(HighFive::FileLocking(false, false)); + HighFive::File file("openmodes.h5", HighFive::File::ReadOnly, fapl); } From d4838cd0aca55897d7648a4f145858c111b17ed2 Mon Sep 17 00:00:00 2001 From: Mike Gevaert Date: Wed, 22 Apr 2026 13:33:59 +0200 Subject: [PATCH 5/5] only applicable to hdf5 > v1.10.0 --- include/highfive/H5PropertyList.hpp | 2 ++ include/highfive/bits/H5PropertyList_misc.hpp | 2 ++ include/highfive/bits/h5p_wrapper.hpp | 2 ++ tests/unit/tests_high_five_base.cpp | 2 ++ 4 files changed, 8 insertions(+) diff --git a/include/highfive/H5PropertyList.hpp b/include/highfive/H5PropertyList.hpp index 6cdcd461..cbd387f7 100644 --- a/include/highfive/H5PropertyList.hpp +++ b/include/highfive/H5PropertyList.hpp @@ -714,6 +714,7 @@ class AttributePhaseChange { unsigned _min_dense; }; +#if H5_VERSION_GE(1, 10, 0) /// /// \brief Set locking FileAccessProps /// @@ -735,6 +736,7 @@ class FileLocking { bool _use_file_locking; bool _ignore_when_disabled; }; +#endif /// @} diff --git a/include/highfive/bits/H5PropertyList_misc.hpp b/include/highfive/bits/H5PropertyList_misc.hpp index bdcffed2..8635d26d 100644 --- a/include/highfive/bits/H5PropertyList_misc.hpp +++ b/include/highfive/bits/H5PropertyList_misc.hpp @@ -501,6 +501,7 @@ inline void AttributePhaseChange::apply(hid_t hid) const { detail::h5p_set_attr_phase_change(hid, _max_compact, _min_dense); } +#if H5_VERSION_GE(1, 10, 0) inline FileLocking::FileLocking(bool use_file_locking, bool ignore_when_disabled) : _use_file_locking(use_file_locking) , _ignore_when_disabled(ignore_when_disabled) {} @@ -508,5 +509,6 @@ inline FileLocking::FileLocking(bool use_file_locking, bool ignore_when_disabled inline void FileLocking::apply(hid_t hid) const { detail::h5p_set_file_locking(hid, _use_file_locking, _ignore_when_disabled); } +#endif } // namespace HighFive diff --git a/include/highfive/bits/h5p_wrapper.hpp b/include/highfive/bits/h5p_wrapper.hpp index 1daf17b9..82a880f5 100644 --- a/include/highfive/bits/h5p_wrapper.hpp +++ b/include/highfive/bits/h5p_wrapper.hpp @@ -371,6 +371,7 @@ inline herr_t h5p_set_attr_phase_change(hid_t plist_id, unsigned max_compact, un return err; } +#if H5_VERSION_GE(1, 10, 0) inline herr_t h5p_set_file_locking(hid_t plist_id, bool use_file_locking, bool ignore_when_disabled) { @@ -380,6 +381,7 @@ inline herr_t h5p_set_file_locking(hid_t plist_id, } return err; } +#endif } // namespace detail diff --git a/tests/unit/tests_high_five_base.cpp b/tests/unit/tests_high_five_base.cpp index a2c1b8b4..42a22ca4 100644 --- a/tests/unit/tests_high_five_base.cpp +++ b/tests/unit/tests_high_five_base.cpp @@ -1273,11 +1273,13 @@ TEST_CASE("AttributePhaseChange") { } } +#if H5_VERSION_GE(1, 10, 1) TEST_CASE("FileAccessProps-FileLocking") { auto fapl = HighFive::FileAccessProps::Default(); fapl.add(HighFive::FileLocking(false, false)); HighFive::File file("openmodes.h5", HighFive::File::ReadOnly, fapl); } +#endif TEST_CASE("datasetOffset") {