From e4ce81f923f10190c11b8a57197bc0c61931d935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20P=C3=B6schel?= Date: Mon, 25 Mar 2024 19:13:56 +0100 Subject: [PATCH] Fix dirtyRecursive() performance for Series with many steps (#1598) * Don't check closed iterations if they are dirty * WIP: Alternative way of checking for errors * Re-enable some tests * Clear dirty files after flushing in ADIOS2 * [WIP] Track dirtyRecursive from the beginning * Continue fixing things * Further fixes * Test cleanup * CI fixes * Replace drop() with a condition check * Move printDirty to debug::printDirty * Update include/openPMD/RecordComponent.hpp Co-authored-by: Axel Huebl * Revert to older verification logic It's more performant now with the new implementation for dirtyRecursive * Document * Remove stale changes --------- Co-authored-by: Axel Huebl --- include/openPMD/Iteration.hpp | 10 -- include/openPMD/ParticleSpecies.hpp | 10 -- include/openPMD/RecordComponent.hpp | 12 +-- include/openPMD/RecordComponent.tpp | 2 +- include/openPMD/Series.hpp | 5 + include/openPMD/backend/Attributable.hpp | 55 ++++++++++- include/openPMD/backend/BaseRecord.hpp | 30 +----- .../openPMD/backend/PatchRecordComponent.hpp | 6 +- include/openPMD/backend/Writable.hpp | 27 ++++- src/IO/ADIOS/ADIOS2File.cpp | 8 +- src/IO/ADIOS/ADIOS2IOHandler.cpp | 1 + src/Iteration.cpp | 50 +++------- src/ParticlePatches.cpp | 3 +- src/ParticleSpecies.cpp | 31 ++---- src/RecordComponent.cpp | 35 ++++--- src/Series.cpp | 98 +++++++++++++++++-- src/backend/Attributable.cpp | 10 +- src/backend/PatchRecord.cpp | 6 +- src/backend/PatchRecordComponent.cpp | 2 +- 19 files changed, 248 insertions(+), 153 deletions(-) diff --git a/include/openPMD/Iteration.hpp b/include/openPMD/Iteration.hpp index 3ede7a6a37..e40cce5a28 100644 --- a/include/openPMD/Iteration.hpp +++ b/include/openPMD/Iteration.hpp @@ -380,16 +380,6 @@ class Iteration : public Attributable */ void setStepStatus(StepStatus); - /* - * @brief Check recursively whether this Iteration is dirty. - * It is dirty if any attribute or dataset is read from or written to - * the backend. - * - * @return true If dirty. - * @return false Otherwise. - */ - bool dirtyRecursive() const; - /** * @brief Link with parent. * diff --git a/include/openPMD/ParticleSpecies.hpp b/include/openPMD/ParticleSpecies.hpp index 808412d0b9..933fad1979 100644 --- a/include/openPMD/ParticleSpecies.hpp +++ b/include/openPMD/ParticleSpecies.hpp @@ -44,16 +44,6 @@ class ParticleSpecies : public Container void read(); void flush(std::string const &, internal::FlushParams const &) override; - - /** - * @brief Check recursively whether this ParticleSpecies is dirty. - * It is dirty if any attribute or dataset is read from or written to - * the backend. - * - * @return true If dirty. - * @return false Otherwise. - */ - bool dirtyRecursive() const; }; namespace traits diff --git a/include/openPMD/RecordComponent.hpp b/include/openPMD/RecordComponent.hpp index deec871d9c..c0b04a2a4c 100644 --- a/include/openPMD/RecordComponent.hpp +++ b/include/openPMD/RecordComponent.hpp @@ -69,6 +69,8 @@ namespace internal * Chunk reading/writing requests on the contained dataset. */ std::queue m_chunks; + + void push_chunk(IOTask &&task); /** * Stores the value for constant record components. * Ignored otherwise. @@ -497,16 +499,6 @@ class RecordComponent : public BaseRecordComponent void storeChunk( auxiliary::WriteBuffer buffer, Datatype datatype, Offset o, Extent e); - /** - * @brief Check recursively whether this RecordComponent is dirty. - * It is dirty if any attribute or dataset is read from or written to - * the backend. - * - * @return true If dirty. - * @return false Otherwise. - */ - bool dirtyRecursive() const; - // clang-format off OPENPMD_protected // clang-format on diff --git a/include/openPMD/RecordComponent.tpp b/include/openPMD/RecordComponent.tpp index 91498b05eb..db6f68636c 100644 --- a/include/openPMD/RecordComponent.tpp +++ b/include/openPMD/RecordComponent.tpp @@ -172,7 +172,7 @@ RecordComponent::loadChunk(std::shared_ptr data, Offset o, Extent e) dRead.extent = extent; dRead.dtype = getDatatype(); dRead.data = std::static_pointer_cast(data); - rc.m_chunks.push(IOTask(this, dRead)); + rc.push_chunk(IOTask(this, dRead)); } } diff --git a/include/openPMD/Series.hpp b/include/openPMD/Series.hpp index 8f49afd491..7f4306ad07 100644 --- a/include/openPMD/Series.hpp +++ b/include/openPMD/Series.hpp @@ -837,6 +837,11 @@ OPENPMD_private AbstractIOHandler *IOHandler(); AbstractIOHandler const *IOHandler() const; }; // Series + +namespace debug +{ + void printDirty(Series const &); +} } // namespace openPMD // Make sure that this one is always included if Series.hpp is included, diff --git a/include/openPMD/backend/Attributable.hpp b/include/openPMD/backend/Attributable.hpp index 410559c66f..c7f01491e1 100644 --- a/include/openPMD/backend/Attributable.hpp +++ b/include/openPMD/backend/Attributable.hpp @@ -83,8 +83,15 @@ namespace internal template class BaseRecordData; + + class RecordComponentData; } // namespace internal +namespace debug +{ + void printDirty(Series const &); +} + /** @brief Layer to manage storage of attributes associated with file objects. * * Mandatory and user-defined Attributes and their data for every object in the @@ -109,6 +116,8 @@ class Attributable friend class Series; friend class Writable; friend class WriteIterations; + friend class internal::RecordComponentData; + friend void debug::printDirty(Series const &); protected: // tag for internal constructor @@ -378,11 +387,49 @@ OPENPMD_protected bool dirty() const { - return writable().dirty; + return writable().dirtySelf; + } + /** O(1). + */ + bool dirtyRecursive() const + { + return writable().dirtyRecursive; + } + void setDirty(bool dirty_in) + { + auto &w = writable(); + w.dirtySelf = dirty_in; + setDirtyRecursive(dirty_in); } - bool &dirty() + /* Amortized O(1) if dirty_in is true, else O(1). + * + * Must be used carefully with `dirty_in == false` since it is assumed that + * all children are not dirty. + * + * Invariant of dirtyRecursive: + * this->dirtyRecursive implies parent->dirtyRecursive. + * + * Hence: + * + * * If dirty_in is true: This needs only go up far enough until a parent is + * found that itself is dirtyRecursive. + * * If dirty_in is false: Only sets `this` to `dirtyRecursive == false`. + * The caller must ensure that the invariant holds (e.g. clearing + * everything during flushing or reading logic). + */ + void setDirtyRecursive(bool dirty_in) { - return writable().dirty; + auto &w = writable(); + w.dirtyRecursive = dirty_in; + if (dirty_in) + { + auto current = w.parent; + while (current && !current->dirtyRecursive) + { + current->dirtyRecursive = true; + current = current->parent; + } + } } bool written() const { @@ -417,7 +464,7 @@ inline bool Attributable::setAttribute(std::string const &key, T value) error::throwNoSuchAttribute(out_of_range_msg(key)); } - dirty() = true; + setDirty(true); auto it = attri.m_attributes.lower_bound(key); if (it != attri.m_attributes.end() && !attri.m_attributes.key_comp()(key, it->first)) diff --git a/include/openPMD/backend/BaseRecord.hpp b/include/openPMD/backend/BaseRecord.hpp index 88bd73b247..db69e03835 100644 --- a/include/openPMD/backend/BaseRecord.hpp +++ b/include/openPMD/backend/BaseRecord.hpp @@ -494,15 +494,6 @@ class BaseRecord virtual void flush_impl(std::string const &, internal::FlushParams const &) = 0; - /** - * @brief Check recursively whether this BaseRecord is dirty. - * It is dirty if any attribute or dataset is read from or written to - * the backend. - * - * @return true If dirty. - * @return false Otherwise. - */ - bool dirtyRecursive() const; void eraseScalar(); }; // BaseRecord @@ -999,25 +990,12 @@ inline void BaseRecord::flush( } this->flush_impl(name, flushParams); - // flush_impl must take care to correctly set the dirty() flag so this - // method doesn't do it -} - -template -inline bool BaseRecord::dirtyRecursive() const -{ - if (this->dirty()) + if (flushParams.flushLevel != FlushLevel::SkeletonOnly) { - return true; + this->setDirty(false); } - for (auto const &pair : *this) - { - if (pair.second.dirtyRecursive()) - { - return true; - } - } - return false; + // flush_impl must take care to correctly set the dirty() flag so this + // method doesn't do it } template diff --git a/include/openPMD/backend/PatchRecordComponent.hpp b/include/openPMD/backend/PatchRecordComponent.hpp index 4620f9be0b..63875b11e2 100644 --- a/include/openPMD/backend/PatchRecordComponent.hpp +++ b/include/openPMD/backend/PatchRecordComponent.hpp @@ -143,7 +143,7 @@ inline void PatchRecordComponent::load(std::shared_ptr data) dRead.dtype = getDatatype(); dRead.data = std::static_pointer_cast(data); auto &rc = get(); - rc.m_chunks.push(IOTask(this, dRead)); + rc.push_chunk(IOTask(this, dRead)); } template @@ -182,7 +182,7 @@ inline void PatchRecordComponent::store(uint64_t idx, T data) dWrite.dtype = dtype; dWrite.data = std::make_shared(data); auto &rc = get(); - rc.m_chunks.push(IOTask(this, std::move(dWrite))); + rc.push_chunk(IOTask(this, std::move(dWrite))); } template @@ -211,6 +211,6 @@ inline void PatchRecordComponent::store(T data) dWrite.dtype = dtype; dWrite.data = std::make_shared(data); auto &rc = get(); - rc.m_chunks.push(IOTask(this, std::move(dWrite))); + rc.push_chunk(IOTask(this, std::move(dWrite))); } } // namespace openPMD diff --git a/include/openPMD/backend/Writable.hpp b/include/openPMD/backend/Writable.hpp index 68daa94778..d0b8b4f3c7 100644 --- a/include/openPMD/backend/Writable.hpp +++ b/include/openPMD/backend/Writable.hpp @@ -44,6 +44,7 @@ template class AbstractIOHandlerImplCommon; template class Span; +class Series; namespace internal { @@ -55,6 +56,11 @@ namespace detail class ADIOS2File; } +namespace debug +{ + void printDirty(Series const &); +} + /** @brief Layer to mirror structure of logical data and persistent data in * file. * @@ -94,6 +100,7 @@ class Writable final friend std::string concrete_bp1_file_position(Writable *); template friend class Span; + friend void debug::printDirty(Series const &); private: Writable(internal::AttributableData *); @@ -135,7 +142,25 @@ OPENPMD_private IOHandler = nullptr; internal::AttributableData *attributable = nullptr; Writable *parent = nullptr; - bool dirty = true; + + /** Tracks if there are unwritten changes for this specific Writable. + * + * Manipulate via Attributable::dirty() and Attributable::setDirty(). + */ + bool dirtySelf = true; + /** + * Tracks if there are unwritten changes anywhere in the + * tree whose ancestor this Writable is. + * + * Invariant: this->dirtyRecursive implies parent->dirtyRecursive. + * + * dirtySelf and dirtyRecursive are separated since that allows specifying + * that `this` is not dirty, but some child is. + * + * Manipulate via Attributable::dirtyRecursive() and + * Attributable::setDirtyRecursive(). + */ + bool dirtyRecursive = true; /** * If parent is not null, then this is a key such that: * &(*parent)[key] == this diff --git a/src/IO/ADIOS/ADIOS2File.cpp b/src/IO/ADIOS/ADIOS2File.cpp index 4d113c7b4e..2ba0fee981 100644 --- a/src/IO/ADIOS/ADIOS2File.cpp +++ b/src/IO/ADIOS/ADIOS2File.cpp @@ -20,6 +20,7 @@ */ #include "openPMD/IO/ADIOS/ADIOS2File.hpp" +#include "openPMD/Error.hpp" #include "openPMD/IO/ADIOS/ADIOS2IOHandler.hpp" #include "openPMD/auxiliary/Environment.hpp" @@ -1188,7 +1189,12 @@ AdvanceStatus ADIOS2File::advance(AdvanceMode mode) void ADIOS2File::drop() { - m_buffer.clear(); + if (!m_buffer.empty()) + { + throw error::Internal( + "ADIOS2 backend: File data for '" + m_file + + "' dropped, but there were enqueued operations."); + } } static std::vector availableAttributesOrVariablesPrefixed( diff --git a/src/IO/ADIOS/ADIOS2IOHandler.cpp b/src/IO/ADIOS/ADIOS2IOHandler.cpp index 8cae74bcd7..2d93837980 100644 --- a/src/IO/ADIOS/ADIOS2IOHandler.cpp +++ b/src/IO/ADIOS/ADIOS2IOHandler.cpp @@ -543,6 +543,7 @@ ADIOS2IOHandlerImpl::flush(internal::ParsedFlushParams &flushParams) p.second->drop(); } } + m_dirty.clear(); return res; } diff --git a/src/Iteration.cpp b/src/Iteration.cpp index 593e38066f..c50758ed92 100644 --- a/src/Iteration.cpp +++ b/src/Iteration.cpp @@ -21,6 +21,7 @@ #include "openPMD/Iteration.hpp" #include "openPMD/Dataset.hpp" #include "openPMD/Datatype.hpp" +#include "openPMD/IO/AbstractIOHandler.hpp" #include "openPMD/Series.hpp" #include "openPMD/auxiliary/DerefDynamicCast.hpp" #include "openPMD/auxiliary/Filesystem.hpp" @@ -331,7 +332,7 @@ void Iteration::flush(internal::FlushParams const &flushParams) } else { - meshes.dirty() = false; + meshes.setDirty(false); } if (!particles.empty() || s.containsAttribute("particlesPath")) @@ -347,11 +348,17 @@ void Iteration::flush(internal::FlushParams const &flushParams) } else { - particles.dirty() = false; + particles.setDirty(false); } flushAttributes(flushParams); } + if (flushParams.flushLevel != FlushLevel::SkeletonOnly) + { + setDirty(false); + meshes.setDirty(false); + particles.setDirty(false); + } } void Iteration::deferParseAccess(DeferredParseAccess dr) @@ -509,13 +516,9 @@ void Iteration::read_impl(std::string const &groupPath) << " and will skip them due to read error:\n" << err.what() << std::endl; meshes = {}; - meshes.dirty() = false; } } - else - { - meshes.dirty() = false; - } + meshes.setDirty(false); if (hasParticles) { @@ -529,13 +532,9 @@ void Iteration::read_impl(std::string const &groupPath) << " and will skip them due to read error:\n" << err.what() << std::endl; particles = {}; - particles.dirty() = false; } } - else - { - particles.dirty() = false; - } + particles.setDirty(false); readAttributes(ReadMode::FullyReread); #ifdef openPMD_USE_INVASIVE_TESTS @@ -822,33 +821,6 @@ void Iteration::setStepStatus(StepStatus status) } } -bool Iteration::dirtyRecursive() const -{ - if (dirty()) - { - return true; - } - if (particles.dirty() || meshes.dirty()) - { - return true; - } - for (auto const &pair : particles) - { - if (pair.second.dirtyRecursive()) - { - return true; - } - } - for (auto const &pair : meshes) - { - if (pair.second.dirtyRecursive()) - { - return true; - } - } - return false; -} - void Iteration::linkHierarchy(Writable &w) { Attributable::linkHierarchy(w); diff --git a/src/ParticlePatches.cpp b/src/ParticlePatches.cpp index a14001962b..9b110e48a4 100644 --- a/src/ParticlePatches.cpp +++ b/src/ParticlePatches.cpp @@ -97,7 +97,7 @@ void ParticlePatches::read() prc.resetDataset(Dataset(*dOpen.dtype, *dOpen.extent)); prc.written() = true; - pr.dirty() = false; + pr.setDirty(false); try { prc.PatchRecordComponent::read(/* require_unit_si = */ false); @@ -111,5 +111,6 @@ void ParticlePatches::read() Container::container().erase(component_name); } } + setDirty(false); } } // namespace openPMD diff --git a/src/ParticleSpecies.cpp b/src/ParticleSpecies.cpp index 7f57450acf..b741130fba 100644 --- a/src/ParticleSpecies.cpp +++ b/src/ParticleSpecies.cpp @@ -104,6 +104,7 @@ void ParticleSpecies::read() auto &container = particlePatches.container(); container.erase("numParticles"); container.erase("numParticlesOffset"); + particlePatches.setDirty(false); } /* obtain all scalar records */ @@ -163,6 +164,10 @@ void ParticleSpecies::flush( record.second.flush(record.first, flushParams); for (auto &patch : particlePatches) patch.second.flush(patch.first, flushParams); + if (flushParams.flushLevel != FlushLevel::SkeletonOnly) + { + particlePatches.setDirty(false); + } } else { @@ -184,32 +189,14 @@ void ParticleSpecies::flush( for (auto &patch : particlePatches) patch.second.flush(patch.first, flushParams); } - } -} - -bool ParticleSpecies::dirtyRecursive() const -{ - if (dirty()) - { - return true; - } - for (auto const &pair : *this) - { - if (pair.second.dirtyRecursive()) + else { - return true; + particlePatches.setDirty(false); } } - if (flushParticlePatches(particlePatches)) + if (flushParams.flushLevel != FlushLevel::SkeletonOnly) { - for (auto const &pair : particlePatches) - { - if (pair.second.dirtyRecursive()) - { - return true; - } - } + setDirty(false); } - return false; } } // namespace openPMD diff --git a/src/RecordComponent.cpp b/src/RecordComponent.cpp index a8f7d734ba..0011363bc4 100644 --- a/src/RecordComponent.cpp +++ b/src/RecordComponent.cpp @@ -25,6 +25,7 @@ #include "openPMD/IO/Format.hpp" #include "openPMD/Series.hpp" #include "openPMD/auxiliary/Memory.hpp" +#include "openPMD/backend/Attributable.hpp" #include "openPMD/backend/BaseRecord.hpp" #include @@ -39,6 +40,21 @@ namespace openPMD namespace internal { RecordComponentData::RecordComponentData() = default; + auto RecordComponentData::push_chunk(IOTask &&task) -> void + { + Attributable a; + a.setData(std::shared_ptr{this, [](auto const &) {}}); +// this check can be too costly in some setups +#if 0 + if (a.containingIteration().closed()) + { + throw error::WrongAPIUsage( + "Cannot write/read chunks to/from closed Iterations."); + } +#endif + a.setDirtyRecursive(true); + m_chunks.push(std::move(task)); + } } // namespace internal RecordComponent::RecordComponent() : BaseRecordComponent(NoInit()) @@ -108,7 +124,7 @@ RecordComponent &RecordComponent::resetDataset(Dataset d) rc.m_dataset = std::move(d); } - dirty() = true; + setDirty(true); return *this; } @@ -201,7 +217,7 @@ RecordComponent &RecordComponent::makeEmpty(Dataset d) throw std::runtime_error("Dataset extent must be at least 1D."); rc.m_isEmpty = true; - dirty() = true; + setDirty(true); if (!written()) { switchType >( @@ -336,6 +352,10 @@ void RecordComponent::flush( flushAttributes(flushParams); } + if (flushParams.flushLevel != FlushLevel::SkeletonOnly) + { + setDirty(false); + } } void RecordComponent::read(bool require_unit_si) @@ -439,15 +459,6 @@ void RecordComponent::readBase(bool require_unit_si) } } -bool RecordComponent::dirtyRecursive() const -{ - if (this->dirty()) - { - return true; - } - return !get().m_chunks.empty(); -} - void RecordComponent::storeChunk( auxiliary::WriteBuffer buffer, Datatype dtype, Offset o, Extent e) { @@ -460,7 +471,7 @@ void RecordComponent::storeChunk( /* std::static_pointer_cast correctly reference-counts the pointer */ dWrite.data = std::move(buffer); auto &rc = get(); - rc.m_chunks.push(IOTask(this, std::move(dWrite))); + rc.push_chunk(IOTask(this, std::move(dWrite))); } void RecordComponent::verifyChunk( diff --git a/src/Series.cpp b/src/Series.cpp index a4897c3c97..9079f4d791 100644 --- a/src/Series.cpp +++ b/src/Series.cpp @@ -32,6 +32,7 @@ #include "openPMD/auxiliary/Filesystem.hpp" #include "openPMD/auxiliary/JSON_internal.hpp" #include "openPMD/auxiliary/StringManip.hpp" +#include "openPMD/backend/Attributable.hpp" #include "openPMD/version.hpp" #include @@ -185,7 +186,7 @@ Series &Series::setMeshesPath(std::string const &mp) setAttribute("meshesPath", mp); else setAttribute("meshesPath", mp + "/"); - dirty() = true; + setDirty(true); return *this; } @@ -211,7 +212,7 @@ Series &Series::setParticlesPath(std::string const &pp) setAttribute("particlesPath", pp); else setAttribute("particlesPath", pp + "/"); - dirty() = true; + setDirty(true); return *this; } @@ -402,7 +403,7 @@ Series &Series::setName(std::string const &n) } series.m_name = n; - dirty() = true; + setDirty(true); return *this; } @@ -1076,7 +1077,7 @@ void Series::flushFileBased( written() = false; series.iterations.written() = false; - dirty() |= it->second.dirty(); + setDirty(dirty() || it->second.dirty()); std::string filename = iterationFilename(it->first); if (!it->second.written()) @@ -1115,9 +1116,9 @@ void Series::flushFileBased( /* reset the dirty bit for every iteration (i.e. file) * otherwise only the first iteration will have updates attributes */ - dirty() = allDirty; + setDirty(allDirty); } - dirty() = false; + setDirty(false); break; } } @@ -2802,4 +2803,89 @@ namespace : std::nullopt); } } // namespace + +namespace debug +{ + void printDirty(Series const &series) + { + auto print = [](Attributable const &attr) { + size_t indent = 0; + { + auto current = attr.parent(); + while (current) + { + ++indent; + current = current->parent; + } + } + auto make_indent = [&]() { + for (size_t i = 0; i < indent; ++i) + { + std::cout << "\t"; + } + }; + make_indent(); + auto const &w = attr.writable(); + std::cout << w.ownKeyWithinParent << '\n'; + make_indent(); + std::cout << "Self: " << w.dirtySelf + << "\tRec: " << w.dirtyRecursive << '\n'; + std::cout << std::endl; + }; + print(series); + print(series.iterations); + for (auto const &[it_name, it] : series.iterations) + { + (void)it_name; + print(it); + print(it.meshes); + for (auto const &[mesh_name, mesh] : it.meshes) + { + (void)mesh_name; + print(mesh); + if (!mesh.scalar()) + { + for (auto const &[comp_name, comp] : mesh) + { + (void)comp_name; + print(comp); + } + } + } + print(it.particles); + for (auto const &[species_name, species] : it.particles) + { + (void)species_name; + print(species); + print(species.particlePatches); + for (auto const &[patch_name, patch] : species.particlePatches) + { + (void)patch_name; + print(patch); + if (!patch.scalar()) + { + for (auto const &[component_name, component] : patch) + { + (void)component_name; + print(component); + } + } + } + for (auto const &[record_name, record] : species) + { + (void)record_name; + print(record); + if (!record.scalar()) + { + for (auto const &[comp_name, comp] : record) + { + (void)comp_name; + print(comp); + } + } + } + } + } + } +} // namespace debug } // namespace openPMD diff --git a/src/backend/Attributable.cpp b/src/backend/Attributable.cpp index 357914d8b9..2388b1726d 100644 --- a/src/backend/Attributable.cpp +++ b/src/backend/Attributable.cpp @@ -261,8 +261,11 @@ void Attributable::flushAttributes(internal::FlushParams const &flushParams) aWrite.dtype = getAttribute(att_name).dtype; IOHandler()->enqueue(IOTask(this, aWrite)); } - - dirty() = false; + } + // Do this outside the if branch to also setDirty to dirtyRecursive + if (flushParams.flushLevel != FlushLevel::SkeletonOnly) + { + setDirty(false); } } @@ -472,7 +475,7 @@ void Attributable::readAttributes(ReadMode mode) } } - dirty() = false; + setDirty(false); } void Attributable::linkHierarchy(Writable &w) @@ -480,5 +483,6 @@ void Attributable::linkHierarchy(Writable &w) auto handler = w.IOHandler; writable().IOHandler = handler; writable().parent = &w; + setDirty(true); } } // namespace openPMD diff --git a/src/backend/PatchRecord.cpp b/src/backend/PatchRecord.cpp index 84047c028f..9b87835194 100644 --- a/src/backend/PatchRecord.cpp +++ b/src/backend/PatchRecord.cpp @@ -52,9 +52,9 @@ void PatchRecord::flush_impl( } else T_RecordComponent::flush(path, flushParams); - if (flushParams.flushLevel == FlushLevel::UserFlush) + if (flushParams.flushLevel != FlushLevel::SkeletonOnly) { - this->dirty() = false; + setDirty(false); } } @@ -106,6 +106,6 @@ void PatchRecord::read() this->container().erase(component_name); } } - dirty() = false; + setDirty(false); } } // namespace openPMD diff --git a/src/backend/PatchRecordComponent.cpp b/src/backend/PatchRecordComponent.cpp index 9252eb19ad..af19923fad 100644 --- a/src/backend/PatchRecordComponent.cpp +++ b/src/backend/PatchRecordComponent.cpp @@ -47,7 +47,7 @@ PatchRecordComponent &PatchRecordComponent::resetDataset(Dataset d) "Dataset extent must not be zero in any dimension."); get().m_dataset = std::move(d); - dirty() = true; + setDirty(true); return *this; }