diff --git a/writer/HDF5Objects.cpp b/writer/HDF5Objects.cpp index 6c0d0cc0..616a5d6d 100644 --- a/writer/HDF5Objects.cpp +++ b/writer/HDF5Objects.cpp @@ -94,7 +94,12 @@ void HDF5DataSpace::SelectHyperslabWithStride(const std::vector &start, } HDF5DataSpace::~HDF5DataSpace() { - if (id >= 0) H5Sclose(id); + if (id >= 0) { + H5E_BEGIN_TRY { + H5Sclose(id); + } H5E_END_TRY; + id = -1; + } } uint8_t HDF5DataSpace::GetNumOfDimensions() const { @@ -208,7 +213,12 @@ HDF5DataType::HDF5DataType(const HDF5DataSet &data_set) :HDF5Id() { } HDF5DataType::~HDF5DataType() { - if (id >= 0) H5Tclose(id); + if (id >= 0) { + H5E_BEGIN_TRY { + H5Tclose(id); + } H5E_END_TRY; + id = -1; + } } size_t HDF5DataType::GetElemSize() const { @@ -258,7 +268,12 @@ HDF5Dcpl::HDF5Dcpl(const HDF5DataSet &data_set) : HDF5Id() { } HDF5Dcpl::~HDF5Dcpl() { - if (id >= 0) H5Pclose(id); + if (id >= 0) { + H5E_BEGIN_TRY { + H5Pclose(id); + } H5E_END_TRY; + id = -1; + } } void HDF5Dcpl::SetChunking(const std::vector &dims) { @@ -321,7 +336,12 @@ HDF5Fapl::HDF5Fapl() : HDF5Id() { } HDF5Fapl::~HDF5Fapl() { - H5Pclose(id); + if (id >= 0) { + H5E_BEGIN_TRY { + H5Pclose(id); + } H5E_END_TRY; + id = -1; + } } void HDF5Fapl::SetVersionTo1p10orNewer() { @@ -698,7 +718,12 @@ HDF5Group::HDF5Group(const HDF5Object& parent, const char *name) : HDF5Object() } HDF5Group::~HDF5Group() { - H5Gclose(id); + if (id >= 0) { + H5E_BEGIN_TRY { + H5Gclose(id); + } H5E_END_TRY; + id = -1; + } } HDF5File::HDF5File(const std::string& filename, bool v1_10) : HDF5Object() { @@ -711,8 +736,37 @@ HDF5File::HDF5File(const std::string& filename, bool v1_10) : HDF5Object() { throw JFJochException(JFJochExceptionCategory::HDF5, "Cannot open/create data HDF5 file " + filename); } +void HDF5File::Close() { + if (id < 0) + return; + + // Invalidate first; if anything below fails (e.g. ENOSPC) we must NOT + // leave a live id behind for the destructor or later code to touch. + const hid_t local_id = id; + id = -1; + + herr_t flush_err = 0; + H5E_BEGIN_TRY { + flush_err = H5Fflush(local_id, H5F_SCOPE_GLOBAL); + } H5E_END_TRY; + + herr_t close_err = 0; + H5E_BEGIN_TRY { + close_err = H5Fclose(local_id); + } H5E_END_TRY; + + if (flush_err < 0 || close_err < 0) + throw JFJochException(JFJochExceptionCategory::HDF5, + "Failed to flush/close HDF5 file (likely no space left on device)"); +} + HDF5File::~HDF5File() { - if (id >= 0) H5Fclose(id); + if (id >= 0) { + H5E_BEGIN_TRY { + H5Fclose(id); + } H5E_END_TRY; + id = -1; + } } void HDF5File::Delete(const std::string& path) { @@ -726,7 +780,10 @@ HDF5ReadOnlyFile::HDF5ReadOnlyFile(const std::string &filename) { } HDF5ReadOnlyFile::~HDF5ReadOnlyFile() { - if (id >= 0) H5Fclose(id); + if (id >= 0) { + H5E_BEGIN_TRY {H5Fclose(id); } H5E_END_TRY; + id = -1; + } } HDF5DataSet::HDF5DataSet(const HDF5Object &parent, const std::string &name, const HDF5DataType &data_type, @@ -812,8 +869,29 @@ std::string HDF5DataSet::ReadString() const { return buffer; } +void HDF5DataSet::Close() { + if (id < 0) + return; + + const hid_t local_id = id; + id = -1; + + herr_t err = 0; + H5E_BEGIN_TRY { + err = H5Dclose(local_id); + } H5E_END_TRY; + + if (err < 0) + throw JFJochException(JFJochExceptionCategory::HDF5, "Cannot close HDF5 dataset"); +} + HDF5DataSet::~HDF5DataSet() { - if (id >= 0) H5Dclose(id); + if (id >= 0) { + H5E_BEGIN_TRY { + H5Dclose(id); + } H5E_END_TRY; + id = -1; + } } void HDF5DataSet::ReadDirectChunk(std::vector &val, const std::vector &offset) { diff --git a/writer/HDF5Objects.h b/writer/HDF5Objects.h index f006f039..0408fbe5 100644 --- a/writer/HDF5Objects.h +++ b/writer/HDF5Objects.h @@ -196,6 +196,7 @@ public: explicit HDF5File(const std::string& filename, bool v1_10 = false); ~HDF5File(); void Delete(const std::string& path); + void Close(); }; class HDF5ReadOnlyFile : public HDF5Object { @@ -348,6 +349,7 @@ public: } std::string ReadString() const; + void Close(); }; inline std::unique_ptr SaveScalar(const HDF5Object& parent, const std::string &name, const char* val) {