diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h index 8c1ed546b3d8699ea4eed9225f055323510745d6..559d3a38eaa391bbc9893fec991327fc08165fba 100644 --- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h @@ -3,14 +3,14 @@ #include <map> #include <string> +#include <ArmarXCore/core/logging/Logging.h> + #include "ProviderSegmentBase.h" #include "detail/AronTyped.h" #include "detail/MemoryContainerBase.h" +#include "detail/Predictive.h" #include "detail/iteration_mixins.h" #include "detail/lookup_mixins.h" -#include "detail/Predictive.h" - -#include <ArmarXCore/core/logging/Logging.h> namespace armarx::armem::base { @@ -20,22 +20,22 @@ namespace armarx::armem::base */ template <class _ProviderSegmentT, class _Derived> class CoreSegmentBase : - public detail::MemoryContainerBase<std::map<std::string, _ProviderSegmentT>, _Derived> - , public detail::AronTyped - , public detail::PredictiveContainer<_Derived> - , public detail::ForEachEntityInstanceMixin<_Derived> - , public detail::ForEachEntitySnapshotMixin<_Derived> - , public detail::ForEachEntityMixin<_Derived> - , public detail::GetFindInstanceMixin<_Derived> - , public detail::GetFindSnapshotMixin<_Derived> - , public detail::GetFindEntityMixin<_Derived> + public detail::MemoryContainerBase<std::map<std::string, _ProviderSegmentT>, _Derived>, + public detail::AronTyped, + public detail::PredictiveContainer<_Derived>, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived>, + public detail::ForEachEntityMixin<_Derived>, + public detail::GetFindInstanceMixin<_Derived>, + public detail::GetFindSnapshotMixin<_Derived>, + public detail::GetFindEntityMixin<_Derived> { - using Base = detail::MemoryContainerBase<std::map<std::string, _ProviderSegmentT>, _Derived>; + using Base = + detail::MemoryContainerBase<std::map<std::string, _ProviderSegmentT>, _Derived>; public: - - using typename Base::DerivedT; using typename Base::ContainerT; + using typename Base::DerivedT; using ProviderSegmentT = _ProviderSegmentT; using EntityT = typename ProviderSegmentT::EntityT; @@ -44,7 +44,6 @@ namespace armarx::armem::base using ChildT = ProviderSegmentT; - struct UpdateResult { armarx::armem::UpdateType coreSegmentUpdateType; @@ -54,26 +53,29 @@ namespace armarx::armem::base std::vector<EntitySnapshotT> removedSnapshots; UpdateResult() = default; + UpdateResult(const typename ProviderSegmentT::UpdateResult& c) : providerSegmentUpdateType(c.providerSegmentUpdateType), entityUpdateType(c.entityUpdateType), id(c.id), removedSnapshots(c.removedSnapshots) - {} + { + } }; public: - CoreSegmentBase() { } + explicit CoreSegmentBase(const std::string& name, aron::type::ObjectPtr aronType = nullptr, const std::vector<PredictionEngine>& predictionEngines = {}) : CoreSegmentBase(name, MemoryID(), aronType, predictionEngines) { } + explicit CoreSegmentBase(const std::string& name, const MemoryID& parentID, aron::type::ObjectPtr aronType = nullptr, @@ -81,6 +83,7 @@ namespace armarx::armem::base CoreSegmentBase(parentID.withCoreSegmentName(name), aronType, predictionEngines) { } + explicit CoreSegmentBase(const MemoryID& id, aron::type::ObjectPtr aronType = nullptr, const std::vector<PredictionEngine>& predictionEngines = {}) : @@ -93,71 +96,86 @@ namespace armarx::armem::base CoreSegmentBase& operator=(const CoreSegmentBase& other) = default; CoreSegmentBase& operator=(CoreSegmentBase&& other) = default; - // READ ACCESS // Get key - inline std::string& name() + inline std::string& + name() { return this->id().coreSegmentName; } - inline const std::string& name() const + + inline const std::string& + name() const { return this->id().coreSegmentName; } - // Has child by key - bool hasProviderSegment(const std::string& name) const + bool + hasProviderSegment(const std::string& name) const { return this->findProviderSegment(name) != nullptr; } + // Has child by memory ID - bool hasProviderSegment(const MemoryID& providerSegmentID) const + bool + hasProviderSegment(const MemoryID& providerSegmentID) const { return this->findProviderSegment(providerSegmentID) != nullptr; } - // Find child by key - ProviderSegmentT* findProviderSegment(const std::string& name) + ProviderSegmentT* + findProviderSegment(const std::string& name) { return detail::findChildByKey(name, this->_container); } - const ProviderSegmentT* findProviderSegment(const std::string& name) const + + const ProviderSegmentT* + findProviderSegment(const std::string& name) const { return detail::findChildByKey(name, this->_container); } // Get child by key - ProviderSegmentT& getProviderSegment(const std::string& name) + ProviderSegmentT& + getProviderSegment(const std::string& name) { return detail::getChildByKey(name, this->_container, *this); } - const ProviderSegmentT& getProviderSegment(const std::string& name) const + + const ProviderSegmentT& + getProviderSegment(const std::string& name) const { return detail::getChildByKey(name, this->_container, *this); } // Find child by MemoryID - ProviderSegmentT* findProviderSegment(const MemoryID& providerSegmentID) + ProviderSegmentT* + findProviderSegment(const MemoryID& providerSegmentID) { detail::checkHasProviderSegmentName(providerSegmentID); return this->findProviderSegment(providerSegmentID.providerSegmentName); } - const ProviderSegmentT* findProviderSegment(const MemoryID& providerSegmentID) const + + const ProviderSegmentT* + findProviderSegment(const MemoryID& providerSegmentID) const { detail::checkHasProviderSegmentName(providerSegmentID); return this->findProviderSegment(providerSegmentID.providerSegmentName); } // Get child by MemoryID - ProviderSegmentT& getProviderSegment(const MemoryID& providerSegmentID) + ProviderSegmentT& + getProviderSegment(const MemoryID& providerSegmentID) { detail::checkHasProviderSegmentName(providerSegmentID); return this->getProviderSegment(providerSegmentID.providerSegmentName); } - const ProviderSegmentT& getProviderSegment(const MemoryID& providerSegmentID) const + + const ProviderSegmentT& + getProviderSegment(const MemoryID& providerSegmentID) const { detail::checkHasProviderSegmentName(providerSegmentID); return this->getProviderSegment(providerSegmentID.providerSegmentName); @@ -171,35 +189,42 @@ namespace armarx::armem::base // Search all provider segments for the first matching entity. - bool hasEntity(const std::string& entityName) const + bool + hasEntity(const std::string& entityName) const { return this->findEntity(entityName) != nullptr; } - EntityT* findEntity(const std::string& entityName) + + EntityT* + findEntity(const std::string& entityName) { return _findEntity(*this, entityName); } - const EntityT* findEntity(const std::string& entityName) const + + const EntityT* + findEntity(const std::string& entityName) const { return _findEntity(*this, entityName); } - // ITERATION /** * @param func Function like: bool process(ProviderSegmentT& provSeg) */ template <class ProviderSegmentFunctionT> - bool forEachProviderSegment(ProviderSegmentFunctionT&& func) + bool + forEachProviderSegment(ProviderSegmentFunctionT&& func) { return this->forEachChild(func); } + /** * @param func Function like: bool process(const ProviderSegmentT& provSeg) */ template <class ProviderSegmentFunctionT> - bool forEachProviderSegment(ProviderSegmentFunctionT&& func) const + bool + forEachProviderSegment(ProviderSegmentFunctionT&& func) const { return this->forEachChild(func); } @@ -213,33 +238,41 @@ namespace armarx::armem::base * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) { - return detail::forEachInstanceIn( - id, func, *this, - id.hasProviderSegmentName(), - id.hasProviderSegmentName() ? this->findProviderSegment(id.providerSegmentName) : nullptr); + return detail::forEachInstanceIn(id, + func, + *this, + id.hasProviderSegmentName(), + id.hasProviderSegmentName() + ? this->findProviderSegment(id.providerSegmentName) + : nullptr); } + /** * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const { - return detail::forEachInstanceIn( - id, func, *this, - id.hasProviderSegmentName(), - id.hasProviderSegmentName() ? this->findProviderSegment(id.providerSegmentName) : nullptr); + return detail::forEachInstanceIn(id, + func, + *this, + id.hasProviderSegmentName(), + id.hasProviderSegmentName() + ? this->findProviderSegment(id.providerSegmentName) + : nullptr); } - // Get child keys - std::vector<std::string> getProviderSegmentNames() const + std::vector<std::string> + getProviderSegmentNames() const { return simox::alg::get_keys(this->_container); } - // MODIFICATION /** @@ -247,11 +280,13 @@ namespace armarx::armem::base * * Missing entity entries are added before updating. */ - UpdateResult update(const EntityUpdate& update) + UpdateResult + update(const EntityUpdate& update) { this->_checkContainerName(update.entityID.coreSegmentName, this->name()); - auto [inserted, provSeg] = _addProviderSegmentIfMissing(update.entityID.providerSegmentName); + auto [inserted, provSeg] = + _addProviderSegmentIfMissing(update.entityID.providerSegmentName); // Update entry. @@ -267,20 +302,34 @@ namespace armarx::armem::base return ret; } - template <class OtherDerivedT> - void append(const OtherDerivedT& other) + void + append(const OtherDerivedT& other) { - other.forEachProviderSegment([this](const auto& provSeg) - { - auto it = this->_container.find(provSeg.name()); - if (it == this->_container.end()) + other.forEachProviderSegment( + [this](const auto& provSeg) { - it = this->_container.emplace(provSeg.name(), this->id().withProviderSegmentName(provSeg.name())).first; - } - it->second.append(provSeg); - return true; - }); + auto it = this->_container.find(provSeg.name()); + if (it == this->_container.end()) + { + it = this->_container + .emplace(provSeg.name(), + this->id().withProviderSegmentName(provSeg.name())) + .first; + it->second.aronType() = provSeg.aronType(); + } + + /*TODO: if (it->second.aronType() != provSeg.aronType()) + { + ARMARX_WARNING + << "When appending a coreseg to another coreseg type conflicts have " + "been found. Setting the type to NULL..."; + it->second.aronType() = nullptr; + }*/ + + it->second.append(provSeg); + return true; + }); } /** @@ -296,36 +345,41 @@ namespace armarx::armem::base aron::type::ObjectPtr providerSegmentType = nullptr, const std::vector<PredictionEngine>& predictionEngines = {}) { - aron::type::ObjectPtr type = providerSegmentType ? providerSegmentType : this->aronType(); + aron::type::ObjectPtr type = + providerSegmentType ? providerSegmentType : this->aronType(); return this->_derived().addProviderSegment(name, name, type, predictionEngines); } /// Copy and insert a provider segment. - ProviderSegmentT& addProviderSegment(const ProviderSegmentT& providerSegment) + ProviderSegmentT& + addProviderSegment(const ProviderSegmentT& providerSegment) { - return this->_derived().addProviderSegment(providerSegment.name(), ProviderSegmentT(providerSegment)); + return this->_derived().addProviderSegment(providerSegment.name(), + ProviderSegmentT(providerSegment)); } /// Move and insert a provider segment. - ProviderSegmentT& addProviderSegment(ProviderSegmentT&& providerSegment) + ProviderSegmentT& + addProviderSegment(ProviderSegmentT&& providerSegment) { - const std::string name = providerSegment.name(); // Copy before move. + const std::string name = providerSegment.name(); // Copy before move. return this->_derived().addProviderSegment(name, std::move(providerSegment)); } /// Insert a provider segment in-place. - template <class ...Args> - ProviderSegmentT& addProviderSegment(const std::string& name, Args... args) + template <class... Args> + ProviderSegmentT& + addProviderSegment(const std::string& name, Args... args) { ChildT& child = this->template _addChild<ChildT>(name, args...); child.id() = this->id().withProviderSegmentName(name); return child; } - // MISC - bool equalsDeep(const DerivedT& other) const + bool + equalsDeep(const DerivedT& other) const { //std::cout << "CoreSegment::equalsDeep" << std::endl; if (this->size() != other.size()) @@ -346,34 +400,34 @@ namespace armarx::armem::base return true; } - static std::string getLevelName() + static std::string + getLevelName() { return "core segment"; } - std::string getKeyString() const + std::string + getKeyString() const { return this->name(); } protected: - template <class ParentT> - static - auto* + static auto* _findEntity(ParentT&& parent, const std::string& entityName) { decltype(parent.findEntity(entityName)) result = nullptr; - parent.forEachProviderSegment([&result, &entityName](auto & provSeg) - { - result = provSeg.findEntity(entityName); - return result == nullptr; // Keep going if null, break if not null. - }); + parent.forEachProviderSegment( + [&result, &entityName](auto& provSeg) + { + result = provSeg.findEntity(entityName); + return result == nullptr; // Keep going if null, break if not null. + }); return result; } - std::pair<bool, ProviderSegmentT*> _addProviderSegmentIfMissing(const std::string& providerSegmentName) { @@ -402,9 +456,7 @@ namespace armarx::armem::base private: - bool _addMissingProviderSegmentDuringUpdate = true; - }; -} +} // namespace armarx::armem::base diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h index a5a521c8ea8983dde16e8481ae1079d16ffc3229..1ab0659f1b65ecf17897475d885bb2568558c31d 100644 --- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h +++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h @@ -5,10 +5,9 @@ #include "CoreSegmentBase.h" #include "detail/MemoryContainerBase.h" +#include "detail/Predictive.h" #include "detail/iteration_mixins.h" #include "detail/lookup_mixins.h" -#include "detail/Predictive.h" - namespace armarx::armem::base { @@ -18,23 +17,22 @@ namespace armarx::armem::base */ template <class _CoreSegmentT, class _Derived> class MemoryBase : - public detail::MemoryContainerBase<std::map<std::string, _CoreSegmentT>, _Derived> - , public detail::PredictiveContainer<_Derived> - , public detail::ForEachEntityInstanceMixin<_Derived> - , public detail::ForEachEntitySnapshotMixin<_Derived> - , public detail::ForEachEntityMixin<_Derived> - , public detail::ForEachProviderSegmentMixin<_Derived> - , public detail::GetFindInstanceMixin<_Derived> - , public detail::GetFindSnapshotMixin<_Derived> - , public detail::GetFindEntityMixin<_Derived> - , public detail::GetFindProviderSegmentMixin<_Derived> + public detail::MemoryContainerBase<std::map<std::string, _CoreSegmentT>, _Derived>, + public detail::PredictiveContainer<_Derived>, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived>, + public detail::ForEachEntityMixin<_Derived>, + public detail::ForEachProviderSegmentMixin<_Derived>, + public detail::GetFindInstanceMixin<_Derived>, + public detail::GetFindSnapshotMixin<_Derived>, + public detail::GetFindEntityMixin<_Derived>, + public detail::GetFindProviderSegmentMixin<_Derived> { using Base = detail::MemoryContainerBase<std::map<std::string, _CoreSegmentT>, _Derived>; public: - - using typename Base::DerivedT; using typename Base::ContainerT; + using typename Base::DerivedT; using CoreSegmentT = _CoreSegmentT; using ProviderSegmentT = typename CoreSegmentT::ProviderSegmentT; @@ -44,7 +42,6 @@ namespace armarx::armem::base using ChildT = CoreSegmentT; - struct UpdateResult { armarx::armem::UpdateType memoryUpdateType; @@ -55,25 +52,28 @@ namespace armarx::armem::base std::vector<EntitySnapshotT> removedSnapshots; UpdateResult() = default; + UpdateResult(const typename CoreSegmentT::UpdateResult& c) : coreSegmentUpdateType(c.coreSegmentUpdateType), providerSegmentUpdateType(c.providerSegmentUpdateType), entityUpdateType(c.entityUpdateType), id(c.id), removedSnapshots(c.removedSnapshots) - {} + { + } }; public: - MemoryBase() { } + explicit MemoryBase(const std::string& name, const std::vector<PredictionEngine>& predictionEngines = {}) : MemoryBase(MemoryID().withMemoryName(name), predictionEngines) { } + explicit MemoryBase(const MemoryID& id, const std::vector<PredictionEngine>& predictionEngines = {}) : Base(id), detail::PredictiveContainer<_Derived>(predictionEngines) @@ -85,70 +85,86 @@ namespace armarx::armem::base MemoryBase& operator=(const MemoryBase& other) = default; MemoryBase& operator=(MemoryBase&& other) = default; - // READ ACCESS // Get key - inline std::string& name() + inline std::string& + name() { return this->id().memoryName; } - inline const std::string& name() const + + inline const std::string& + name() const { return this->id().memoryName; } - // Has child by key - bool hasCoreSegment(const std::string& name) const + bool + hasCoreSegment(const std::string& name) const { return this->findCoreSegment(name) != nullptr; } + // Has child by MemoryID - bool hasCoreSegment(const MemoryID& coreSegmentID) const + bool + hasCoreSegment(const MemoryID& coreSegmentID) const { return this->findCoreSegment(coreSegmentID) != nullptr; } // Find child by key - CoreSegmentT* findCoreSegment(const std::string& name) + CoreSegmentT* + findCoreSegment(const std::string& name) { return detail::findChildByKey(name, this->_container); } - const CoreSegmentT* findCoreSegment(const std::string& name) const + + const CoreSegmentT* + findCoreSegment(const std::string& name) const { return detail::findChildByKey(name, this->_container); } // Get child by key - CoreSegmentT& getCoreSegment(const std::string& name) + CoreSegmentT& + getCoreSegment(const std::string& name) { return detail::getChildByKey(name, this->_container, *this); } - const CoreSegmentT& getCoreSegment(const std::string& name) const + + const CoreSegmentT& + getCoreSegment(const std::string& name) const { return detail::getChildByKey(name, this->_container, *this); } // Find child by MemoryID - CoreSegmentT* findCoreSegment(const MemoryID& coreSegmentID) + CoreSegmentT* + findCoreSegment(const MemoryID& coreSegmentID) { detail::checkHasCoreSegmentName(coreSegmentID); return this->findCoreSegment(coreSegmentID.coreSegmentName); } - const CoreSegmentT* findCoreSegment(const MemoryID& coreSegmentID) const + + const CoreSegmentT* + findCoreSegment(const MemoryID& coreSegmentID) const { detail::checkHasCoreSegmentName(coreSegmentID); return this->findCoreSegment(coreSegmentID.coreSegmentName); } // Get child by MemoryID - CoreSegmentT& getCoreSegment(const MemoryID& coreSegmentID) + CoreSegmentT& + getCoreSegment(const MemoryID& coreSegmentID) { detail::checkHasCoreSegmentName(coreSegmentID); return this->getCoreSegment(coreSegmentID.coreSegmentName); } - const CoreSegmentT& getCoreSegment(const MemoryID& coreSegmentID) const + + const CoreSegmentT& + getCoreSegment(const MemoryID& coreSegmentID) const { detail::checkHasCoreSegmentName(coreSegmentID); return this->getCoreSegment(coreSegmentID.coreSegmentName); @@ -160,22 +176,24 @@ namespace armarx::armem::base // get/findProviderSegment are provided by GetFindProviderSegmentMixin - // ITERATION /** * @param func Function like: bool process(CoreSegmentT& coreSeg) */ template <class CoreSegmentFunctionT> - bool forEachCoreSegment(CoreSegmentFunctionT&& func) + bool + forEachCoreSegment(CoreSegmentFunctionT&& func) { return this->forEachChild(func); } + /** * @param func Function like: bool process(const CoreSegmentT& coreSeg) */ template <class CoreSegmentFunctionT> - bool forEachCoreSegment(CoreSegmentFunctionT&& func) const + bool + forEachCoreSegment(CoreSegmentFunctionT&& func) const { return this->forEachChild(func); } @@ -190,35 +208,42 @@ namespace armarx::armem::base * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) { return detail::forEachInstanceIn( - id, func, *this, - id.hasCoreSegmentName(), - id.hasCoreSegmentName() ? this->findCoreSegment(id.coreSegmentName) : nullptr); + id, + func, + *this, + id.hasCoreSegmentName(), + id.hasCoreSegmentName() ? this->findCoreSegment(id.coreSegmentName) : nullptr); } + /** * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const { return detail::forEachInstanceIn( - id, func, *this, - id.hasCoreSegmentName(), - id.hasCoreSegmentName() ? this->findCoreSegment(id.coreSegmentName) : nullptr); + id, + func, + *this, + id.hasCoreSegmentName(), + id.hasCoreSegmentName() ? this->findCoreSegment(id.coreSegmentName) : nullptr); } - - std::vector<std::string> getCoreSegmentNames() const + std::vector<std::string> + getCoreSegmentNames() const { return simox::alg::get_keys(this->_container); } - // MODIFICATION - void setName(const std::string& name) + void + setName(const std::string& name) { this->id().memoryName = name; } @@ -239,39 +264,45 @@ namespace armarx::armem::base } /// Copy and insert a core segment. - CoreSegmentT& addCoreSegment(const CoreSegmentT& coreSegment) + CoreSegmentT& + addCoreSegment(const CoreSegmentT& coreSegment) { return this->_derived().addCoreSegment(coreSegment.name(), CoreSegmentT(coreSegment)); } /// Move and insert a core segment. - CoreSegmentT& addCoreSegment(CoreSegmentT&& coreSegment) + CoreSegmentT& + addCoreSegment(CoreSegmentT&& coreSegment) { - const std::string name = coreSegment.name(); // Copy before move. + const std::string name = coreSegment.name(); // Copy before move. return this->_derived().addCoreSegment(name, std::move(coreSegment)); } /// Move and insert a core segment. - template <class ...Args> - CoreSegmentT& addCoreSegment(const std::string& name, Args... args) + template <class... Args> + CoreSegmentT& + addCoreSegment(const std::string& name, Args... args) { CoreSegmentT& child = this->template _addChild<ChildT>(name, args...); child.id() = this->id().withCoreSegmentName(name); return child; } - /** * @brief Store all updates in `commit`. * @param commit The commit. * @return The resulting memory IDs. */ - std::vector<UpdateResult> update(const Commit& commit, const bool addMissingCoreSegmentDuringUpdate = false, const bool checkMemoryName = true) + std::vector<UpdateResult> + update(const Commit& commit, + const bool addMissingCoreSegmentDuringUpdate = false, + const bool checkMemoryName = true) { std::vector<UpdateResult> results; for (const EntityUpdate& update : commit.updates) { - results.push_back(this->update(update, addMissingCoreSegmentDuringUpdate, checkMemoryName)); + results.push_back( + this->update(update, addMissingCoreSegmentDuringUpdate, checkMemoryName)); } return results; } @@ -281,14 +312,18 @@ namespace armarx::armem::base * @param update The update. * @return The resulting entity snapshot's ID. */ - UpdateResult update(const EntityUpdate& update, const bool addMissingCoreSegmentDuringUpdate = false, const bool checkMemoryName = true) + UpdateResult + update(const EntityUpdate& update, + const bool addMissingCoreSegmentDuringUpdate = false, + const bool checkMemoryName = true) { if (checkMemoryName) { this->_checkContainerName(update.entityID.memoryName, this->name()); } - auto [inserted, coreSeg] = _addCoreSegmentIfMissing(update.entityID.coreSegmentName, addMissingCoreSegmentDuringUpdate); + auto [inserted, coreSeg] = _addCoreSegmentIfMissing(update.entityID.coreSegmentName, + addMissingCoreSegmentDuringUpdate); // Update entry. UpdateResult ret(coreSeg->update(update)); @@ -303,27 +338,42 @@ namespace armarx::armem::base return ret; } - /** - * @brief Merge another memory into this one. Append all data + * @brief Merge another memory into this one. Append all data and types if possible * @param m The other memory */ template <class OtherDerivedT> - void append(const OtherDerivedT& other) + void + append(const OtherDerivedT& other) { - other.forEachCoreSegment([this](const auto& coreSeg) - { - auto it = this->_container.find(coreSeg.name()); - if (it == this->_container.end()) + other.forEachCoreSegment( + [this](const auto& coreSeg) { - it = this->_container.emplace(coreSeg.name(), this->id().withCoreSegmentName(coreSeg.name())).first; - } - it->second.append(coreSeg); - return true; - }); + auto it = this->_container.find(coreSeg.name()); + if (it == this->_container.end()) + { + it = this->_container + .emplace(coreSeg.name(), + this->id().withCoreSegmentName(coreSeg.name())) + .first; + it->second.aronType() = coreSeg.aronType(); + } + + /*TODO: if (it->second.aronType() != coreSeg.aronType()) + { + ARMARX_WARNING << "When appending a wm to another wm type conflicts have " + "been found. Setting the type to NULL..."; + it->second.aronType() = nullptr; + }*/ + + it->second.append(coreSeg); + return true; + }); } - bool equalsDeep(const MemoryBase& other) const + bool + equalsDeep(const MemoryBase& other) const + { //std::cout << "Memory::equalsDeep" << std::endl; if (this->size() != other.size()) @@ -344,20 +394,23 @@ namespace armarx::armem::base return true; } - static std::string getLevelName() + static std::string + getLevelName() { return "memory"; } - std::string getKeyString() const + std::string + getKeyString() const { return this->name(); } protected: - - std::pair<bool, CoreSegmentT*> _addCoreSegmentIfMissing(const std::string& coreSegmentName, const bool addMissingCoreSegmentDuringUpdate) + std::pair<bool, CoreSegmentT*> + _addCoreSegmentIfMissing(const std::string& coreSegmentName, + const bool addMissingCoreSegmentDuringUpdate) { CoreSegmentT* coreSeg = nullptr; @@ -382,4 +435,4 @@ namespace armarx::armem::base } } }; -} +} // namespace armarx::armem::base diff --git a/source/RobotAPI/libraries/armem/server/CMakeLists.txt b/source/RobotAPI/libraries/armem/server/CMakeLists.txt index f2967422eaf548e5f040bd5b1685f7555e42bdb5..6d388b607f365bce965d8fc9e834ae5c512a874f 100644 --- a/source/RobotAPI/libraries/armem/server/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/server/CMakeLists.txt @@ -7,18 +7,9 @@ SET(INSTALL_SCRIPT_MSG "Please use the installation script in RobotAPI/etc/mongocxx to install libmongocxx and libbsoncxx." ) - - # MongoLTM -#find_package(libmongocxx QUIET) -#armarx_build_if(libmongocxx_FOUND "libmongocxx not available. ${INSTALL_SCRIPT_MSG}") - -# DiskLTM TODO: switch to FindMinizip file? -INCLUDE (FindPkgConfig) -if (PKG_CONFIG_FOUND) - PKG_CHECK_MODULES(UNZIP minizip) -endif (PKG_CONFIG_FOUND) -armarx_build_if(UNZIP_FOUND "MiniZip not available.") +find_package(libmongocxx QUIET) +armarx_build_if(libmongocxx_FOUND "libmongocxx not available. ${INSTALL_SCRIPT_MSG}") # LTM Encoding stuff find_package(libbsoncxx QUIET) @@ -35,9 +26,8 @@ set(LIBS # LTM RobotAPI::aron::converter::json RobotAPI::aron::converter::opencv - #${LIBMONGOCXX_LIBRARIES} + ${LIBMONGOCXX_LIBRARIES} ${LIBBSONCXX_LIBRARIES} - ${UNZIP_LIBRARIES} ) set(LIB_FILES @@ -45,50 +35,55 @@ set(LIB_FILES MemoryRemoteGui.cpp RemoteGuiAronDataVisitor.cpp + + # LTM ltm/io/Recording.cpp ltm/io/Replaying.cpp - ltm/base/detail/Processors.cpp - ltm/base/detail/MemoryItem.cpp - ltm/base/detail/MemoryBase.cpp - ltm/base/detail/BufferedMemoryBase.cpp - ltm/base/detail/LUTMemoryBase.cpp - ltm/base/detail/CoreSegmentBase.cpp - ltm/base/detail/ProviderSegmentBase.cpp - ltm/base/detail/EntityBase.cpp - ltm/base/detail/EntitySnapshotBase.cpp - - ltm/base/filter/Filter.cpp - ltm/base/filter/frequencyFilter/FrequencyFilter.cpp - ltm/base/filter/equalityFilter/EqualityFilter.cpp - - ltm/base/extractor/Extractor.cpp - ltm/base/extractor/imageExtractor/ImageExtractor.cpp - ltm/base/extractor/imageExtractor/DepthImageExtractor.cpp - - ltm/base/converter/Converter.cpp - ltm/base/typeConverter/Converter.cpp - ltm/base/typeConverter/json/JsonConverter.cpp - ltm/base/converter/object/Converter.cpp - ltm/base/converter/object/json/JsonConverter.cpp - ltm/base/converter/object/bson/BsonConverter.cpp - ltm/base/converter/image/Converter.cpp - ltm/base/converter/image/png/PngConverter.cpp - ltm/base/converter/image/exr/ExrConverter.cpp - - ltm/base/forgetter/Forgetter.cpp - ltm/base/forgetter/LRUForgetter/LRUForgetter.cpp - - ltm/disk/detail/util/util.cpp - ltm/disk/detail/util/filesystem_util.cpp - ltm/disk/detail/util/minizip_util.cpp - ltm/disk/detail/DiskStorage.cpp - ltm/disk/Memory.cpp - ltm/disk/CoreSegment.cpp - ltm/disk/ProviderSegment.cpp - ltm/disk/Entity.cpp - ltm/disk/EntitySnapshot.cpp - + ltm/detail/mixins/util/filesystem.cpp + ltm/detail/mixins/util/mongodb.cpp + ltm/detail/mixins/CachedMemoryMixin.cpp + ltm/detail/mixins/BufferedMemoryMixin.cpp + ltm/detail/mixins/DiskStorageMixin.cpp + ltm/detail/mixins/MongoDBStorageMixin.cpp + + ltm/detail/MemoryItem.cpp + ltm/detail/MemoryBase.cpp + ltm/detail/CoreSegmentBase.cpp + ltm/detail/ProviderSegmentBase.cpp + ltm/detail/EntityBase.cpp + ltm/detail/EntitySnapshotBase.cpp + ltm/detail/EntityInstanceBase.cpp + + ltm/processors/Processors.cpp + + ltm/processors/filter/Filter.cpp + ltm/processors/filter/frequencyFilter/FrequencyFilter.cpp + ltm/processors/filter/equalityFilter/EqualityFilter.cpp + + ltm/processors/extractor/Extractor.cpp + ltm/processors/extractor/imageExtractor/ImageExtractor.cpp + ltm/processors/extractor/imageExtractor/DepthImageExtractor.cpp + + ltm/processors/converter/type/Converter.cpp + ltm/processors/converter/type/object/Converter.cpp + ltm/processors/converter/type/object/json/JsonConverter.cpp + ltm/processors/converter/data/Converter.cpp + ltm/processors/converter/data/object/Converter.cpp + ltm/processors/converter/data/object/json/JsonConverter.cpp + ltm/processors/converter/data/object/bson/BsonConverter.cpp + ltm/processors/converter/data/image/Converter.cpp + ltm/processors/converter/data/image/png/PngConverter.cpp + ltm/processors/converter/data/image/exr/ExrConverter.cpp + + ltm/Memory.cpp + ltm/CoreSegment.cpp + ltm/ProviderSegment.cpp + ltm/Entity.cpp + ltm/EntitySnapshot.cpp + ltm/EntityInstance.cpp + + # WM wm/memory_definitions.cpp wm/ice_conversions.cpp wm/detail/MaxHistorySize.cpp @@ -128,51 +123,54 @@ set(LIB_HEADERS MemoryRemoteGui.h RemoteGuiAronDataVisitor.h + # LTM ltm/io/Recording.h ltm/io/Replaying.h - ltm/base/detail/Processors.h - ltm/base/detail/MemoryItem.h - ltm/base/detail/MemoryBase.h - ltm/base/detail/BufferedMemoryBase.h - ltm/base/detail/LUTMemoryBase.h - ltm/base/detail/CoreSegmentBase.h - ltm/base/detail/ProviderSegmentBase.h - ltm/base/detail/EntityBase.h - ltm/base/detail/EntitySnapshotBase.h - - ltm/base/filter/Filter.h - ltm/base/filter/frequencyFilter/FrequencyFilter.h - ltm/base/filter/equalityFilter/EqualityFilter.h - - ltm/base/extractor/Extractor.h - ltm/base/extractor/imageExtractor/ImageExtractor.h - ltm/base/extractor/imageExtractor/DepthImageExtractor.h - - ltm/base/converter/Converter.h - ltm/base/typeConverter/Converter.h - ltm/base/typeConverter/json/JsonConverter.h - ltm/base/converter/object/Converter.h - ltm/base/converter/object/json/JsonConverter.h - ltm/base/converter/object/bson/BsonConverter.h - ltm/base/converter/image/Converter.h - ltm/base/converter/image/png/PngConverter.h - ltm/base/converter/image/exr/ExrConverter.h - - - ltm/base/forgetter/Forgetter.h - ltm/base/forgetter/LRUForgetter/LRUForgetter.h - - ltm/disk/detail/util/util.h - ltm/disk/detail/util/filesystem_util.h - ltm/disk/detail/util/minizip_util.h - ltm/disk/detail/DiskStorage.h - ltm/disk/Memory.h - ltm/disk/CoreSegment.h - ltm/disk/ProviderSegment.h - ltm/disk/Entity.h - ltm/disk/EntitySnapshot.h - + ltm/detail/mixins/util/filesystem.h + ltm/detail/mixins/util/mongodb.h + ltm/detail/mixins/CachedMemoryMixin.h + ltm/detail/mixins/BufferedMemoryMixin.h + ltm/detail/mixins/DiskStorageMixin.h + ltm/detail/mixins/MongoDBStorageMixin.h + + ltm/detail/MemoryItem.h + ltm/detail/MemoryBase.h + ltm/detail/CoreSegmentBase.h + ltm/detail/ProviderSegmentBase.h + ltm/detail/EntityBase.h + ltm/detail/EntitySnapshotBase.h + ltm/detail/EntityInstanceBase.h + + ltm/processors/Processors.h + + ltm/processors/filter/Filter.h + ltm/processors/filter/frequencyFilter/FrequencyFilter.h + ltm/processors/filter/equalityFilter/EqualityFilter.h + + ltm/processors/extractor/Extractor.h + ltm/processors/extractor/imageExtractor/ImageExtractor.h + ltm/processors/extractor/imageExtractor/DepthImageExtractor.h + + ltm/processors/converter/type/Converter.h + ltm/processors/converter/type/object/Converter.h + ltm/processors/converter/type/object/json/JsonConverter.h + ltm/processors/converter/data/Converter.h + ltm/processors/converter/data/object/Converter.h + ltm/processors/converter/data/object/json/JsonConverter.h + ltm/processors/converter/data/object/bson/BsonConverter.h + ltm/processors/converter/data/image/Converter.h + ltm/processors/converter/data/image/png/PngConverter.h + ltm/processors/converter/data/image/exr/ExrConverter.h + + ltm/Memory.h + ltm/CoreSegment.h + ltm/ProviderSegment.h + ltm/Entity.h + ltm/EntitySnapshot.h + ltm/EntityInstance.h + + # WM wm/memory_definitions.h wm/ice_conversions.h wm/detail/MaxHistorySize.h diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp index d307d8e4e50bbde926147c5c68047533001005d2..a77e8a3ee7ff6d59a1ffebe6756ab43a0977d36e 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp @@ -20,7 +20,7 @@ namespace armarx::armem::server { MemoryToIceAdapter::MemoryToIceAdapter(wm::Memory* workingMemory, - server::ltm::disk::Memory* longtermMemory) : + server::ltm::Memory* longtermMemory) : workingMemory(workingMemory), longtermMemory(longtermMemory) { } @@ -249,7 +249,7 @@ namespace armarx::armem::server armem::query::data::Result result; - query_proc::ltm_server::disk::MemoryQueryProcessor ltmProcessor; + query_proc::ltm_server::MemoryQueryProcessor ltmProcessor; armem::wm::Memory ltmResult = ltmProcessor.process(input, *longtermMemory); if (not ltmResult.empty()) diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h index 41b0312e6518ebcf78471f42efe23d5bf0eb9634..a451054a2fb667e99c9472d847c86e3e2cb48dea 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h @@ -1,14 +1,12 @@ #pragma once -#include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/interface/armem/client/MemoryListenerInterface.h> - -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -#include <RobotAPI/libraries/armem/server/ltm/disk/Memory.h> +#include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/libraries/armem/client/Query.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/ltm/Memory.h> #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> - namespace armarx::armem::server { @@ -21,20 +19,19 @@ namespace armarx::armem::server class MemoryToIceAdapter { public: - /// Construct an MemoryToIceAdapter from an existing Memory. MemoryToIceAdapter(server::wm::Memory* workingMemory = nullptr, - server::ltm::disk::Memory* longtermMemory = nullptr); + server::ltm::Memory* longtermMemory = nullptr); void setMemoryListener(client::MemoryListenerInterfacePrx memoryListenerTopic); // WRITING - data::AddSegmentResult addSegment( - const data::AddSegmentInput& input, bool addCoreSegments = false); + data::AddSegmentResult addSegment(const data::AddSegmentInput& input, + bool addCoreSegments = false); - data::AddSegmentsResult addSegments( - const data::AddSegmentsInput& input, bool addCoreSegments = false); + data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, + bool addCoreSegments = false); data::CommitResult commit(const data::Commit& commitIce, Time timeArrived); @@ -63,18 +60,15 @@ namespace armarx::armem::server prediction::data::EngineSupportMap getAvailableEngines(); public: - server::wm::Memory* workingMemory; - server::ltm::disk::Memory* longtermMemory; + server::ltm::Memory* longtermMemory; client::MemoryListenerInterfacePrx memoryListenerTopic; private: - armem::CommitResult _commit(const armem::Commit& commit, bool locking); - }; -} +} // namespace armarx::armem::server diff --git a/source/RobotAPI/libraries/armem/server/forward_declarations.h b/source/RobotAPI/libraries/armem/server/forward_declarations.h index 956a92b96ea8a75f7526fc5d111b0cc63bec26b8..5239bb8784473afe300d95d933f6920350fc9f28 100644 --- a/source/RobotAPI/libraries/armem/server/forward_declarations.h +++ b/source/RobotAPI/libraries/armem/server/forward_declarations.h @@ -2,11 +2,11 @@ #include <RobotAPI/libraries/armem/core/forward_declarations.h> - namespace armarx::armem::server { class MemoryToIceAdapter; } + namespace armarx::armem::server::wm { using EntityInstance = armem::wm::EntityInstance; @@ -15,12 +15,9 @@ namespace armarx::armem::server::wm class ProviderSegment; class CoreSegment; class Memory; -} -namespace armarx::armem::server::ltm::mongodb -{ - class Memory; -} -namespace armarx::armem::server::ltm::disk +} // namespace armarx::armem::server::wm + +namespace armarx::armem::server::ltm { class Memory; } diff --git a/source/RobotAPI/libraries/armem/server/ltm/CoreSegment.cpp b/source/RobotAPI/libraries/armem/server/ltm/CoreSegment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13a6fbe8b888332981c12a1c4ba3bf079435b97c --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/CoreSegment.cpp @@ -0,0 +1,218 @@ +#include "CoreSegment.h" + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> + +namespace armarx::armem::server::ltm +{ + CoreSegment::CoreSegment(const detail::mixin::Path& p, + const detail::mixin::MongoDBSettings& s, + + const std::string& exportName, + const armem::MemoryID& id /* UNESCAPED */, + const std::shared_ptr<Processors>& filters) : + CoreSegmentBase(exportName, id, filters), + DiskMemoryItemMixin(p, exportName, id), + MongoDBStorageMixin(s, exportName, id) + { + start(); + } + + bool + CoreSegment::forEachProviderSegment(std::function<void(ProviderSegment&)> func) const + { + std::lock_guard l(ltm_mutex); + + if (connected() && collectionExists()) + { + for (const auto& doc : getAllDocuments()) + { + std::string id_str = doc[FOREIGN_KEY]; + armem::MemoryID segment_id(id_str); + ProviderSegment c( + getMemoryBasePath(), getSettings(), getExportName(), segment_id, processors); + func(c); + } + } + + // legacy + /*else if (fullPathExists()) + { + for (const auto& subdirName : getAllDirectories()) + { + std::string segmentName = util::fs::detail::unescapeName(subdirName); + ProviderSegment c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withProviderSegmentName(segmentName), + processors); + func(c); + } + }*/ + return true; + } + + bool + CoreSegment::hasProviderSegment(const std::string& name) const + { + std::lock_guard l(ltm_mutex); + + if (connected() && collectionExists()) + { + auto c = ProviderSegment(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withProviderSegmentName(name), + processors); + + return (bool)c.collectionExists(); + } + + /*if (fullPathExists()) + { + auto c = ProviderSegment(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withProviderSegmentName(name), + processors); + + return c.fullPathExists(); + }*/ + + return false; + } + + std::shared_ptr<ProviderSegment> + CoreSegment::findProviderSegment(const std::string& providerSegmentName) const + { + std::lock_guard l(ltm_mutex); + + if (!hasProviderSegment(providerSegmentName)) + { + return nullptr; + } + + return std::make_shared<ProviderSegment>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withProviderSegmentName(providerSegmentName), + processors); + } + + void + CoreSegment::_loadAllReferences(armem::wm::CoreSegment& e) + { + std::lock_guard l(ltm_mutex); + + e.id() = id(); + + auto& conv = processors->defaultTypeConverter; + auto setType = [&conv, &e](const std::vector<unsigned char>& aronJson) + { + auto typeAron = conv.convert(aronJson, ""); + e.aronType() = aron::type::Object::DynamicCastAndCheck(typeAron); + }; + + if (connected() && collectionExists()) + { + // TODO: + } + + /*else if (std::string filename = TYPE_FILENAME + conv.suffix; + fullPathExists() && fileExists(filename)) + { + auto typeFileContent = readDataFromFile(filename); + setType(typeFileContent); + }*/ + + forEachProviderSegment( + [&e](auto& x) + { + armem::wm::ProviderSegment s; + x.loadAllReferences(s); + e.addProviderSegment(s); + }); + } + + void + CoreSegment::_resolve(armem::wm::CoreSegment& c) + { + std::lock_guard l(ltm_mutex); + + if ((connected() && collectionExists()) /* || fullPathExists()*/) + { + c.forEachProviderSegment( + [&](auto& e) + { + ProviderSegment c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withProviderSegmentName(e.id().providerSegmentName), + processors); + c.resolve(e); + }); + } + } + + void + CoreSegment::_store(const armem::wm::CoreSegment& c) + { + std::lock_guard l(ltm_mutex); + + if (id().coreSegmentName.empty()) + { + ARMARX_WARNING + << "During storage of segment '" << c.id().str() + << "' I noticed that the corresponding LTM has no id set. " + << "I set the id of the LTM to the same name, however this should not happen!"; + id().coreSegmentName = c.id().coreSegmentName; + }; + + if (!connected()) + { + ARMARX_WARNING << "LTM CORE SEGMENT NOT CONNECTED ALTHOUGH ENABLED " << id().str(); + return; + } + + // add foreign key to memory collection + if (c.hasAronType()) + { + auto& conv = processors->defaultTypeConverter; + + auto [vec, modeSuffix] = conv.convert(c.aronType()); + ARMARX_CHECK_EMPTY(modeSuffix); + + std::string dataStr{vec.begin(), vec.end()}; + auto dataJson = nlohmann::json::parse(dataStr); + + writeForeignKeyToPreviousDocument(dataJson); + } + else + { + writeForeignKeyToPreviousDocument(); + } + + // legacy: also ensure filesystem exists + //ensureFullPathExists(true); + /*else + { + std::string filename = (TYPE_FILENAME + conv.suffix); + writeDataToFile(filename, vec); + }*/ + + c.forEachProviderSegment( + [&](const auto& prov) + { + ProviderSegment c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withProviderSegmentName(prov.id().providerSegmentName), + processors); + + c.store(prov); + statistics.recordedProviderSegments++; + }); + } +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/CoreSegment.h b/source/RobotAPI/libraries/armem/server/ltm/CoreSegment.h new file mode 100644 index 0000000000000000000000000000000000000000..14d8b0abab73608e6eba0de5fa97734764a1a9ad --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/CoreSegment.h @@ -0,0 +1,37 @@ +#pragma once + +#include <filesystem> + +// Base Class +#include "ProviderSegment.h" +#include "detail/CoreSegmentBase.h" +#include "detail/mixins/DiskStorageMixin.h" +#include "detail/mixins/MongoDBStorageMixin.h" + +namespace armarx::armem::server::ltm +{ + class CoreSegment : + public detail::CoreSegmentBase<ProviderSegment>, + public detail::mixin::DiskMemoryItemMixin, + public detail::mixin::MongoDBStorageMixin + { + public: + CoreSegment(const detail::mixin::Path&, + const detail::mixin::MongoDBSettings&, + const std::string&, + const MemoryID&, + const std::shared_ptr<Processors>&); + + bool forEachProviderSegment(std::function<void(ProviderSegment&)> func) const override; + bool hasProviderSegment(const std::string& name) const override; + std::shared_ptr<ProviderSegment> findProviderSegment(const std::string&) const override; + + protected: + void _loadAllReferences(armem::wm::CoreSegment&) override; + void _resolve(armem::wm::CoreSegment&) override; + void _store(const armem::wm::CoreSegment&) override; + + private: + }; + +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/Entity.cpp b/source/RobotAPI/libraries/armem/server/ltm/Entity.cpp new file mode 100644 index 0000000000000000000000000000000000000000..116c4d91b40e6e7b98267bab3c459ba9cb80c39c --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/Entity.cpp @@ -0,0 +1,478 @@ +// Header +#include "Entity.h" + +// SImox +#include <SimoxUtility/algorithm/string.h> + +// ArmarX +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> + +#include "processors/filter/frequencyFilter/FrequencyFilter.h" + +namespace armarx::armem::server::ltm +{ + namespace util + { + + + } // namespace util + + Entity::Entity(const detail::mixin::Path& p, + const detail::mixin::MongoDBSettings& s, + + const std::string& exportName, + const armem::MemoryID& id /* UNESCAPED */, + const std::shared_ptr<Processors>& filters) : + EntityBase(exportName, id, filters), + DiskMemoryItemMixin(p, exportName, id), + MongoDBStorageMixin(s, exportName, id) + { + start(); + } + + bool + Entity::forEachSnapshot(std::function<void(EntitySnapshot&)> func) const + { + std::lock_guard l(ltm_mutex); + + if (connected() && collectionExists()) + { + for (const auto& doc : getAllDocuments()) + { + std::string id_str = doc[ID]; + + armem::MemoryID segment_id = id(); + segment_id.timestampFromStr(id_str); + + EntitySnapshot c( + getMemoryBasePath(), getSettings(), getExportName(), segment_id, processors); + func(c); + } + } + /*else if (fullPathExists()) + { + + for (const auto& d : getAllDirectories()) // days + { + if (!util::fs::detail::isDateString(d.filename())) + { + ARMARX_WARNING << "Found a non-date folder inside an entity '" << id().str() + << "' with name '" << d.filename() << "'. " + << "Ignoring this folder, however this is a bad situation."; + continue; + } + + + // check if this is already a microsec folder (legacy export support) + //if (std::stol(secName) > 1647524607 ) // the time in us the new export was implemented + //{ + // EntitySnapshot c(memoryParentPath, id().withTimestamp(timeFromStringMicroSeconds(secName)), processors, currentMode, currentExport); + // func(c); + // continue; + //} + + + for (const auto& s : util::fs::getAllDirectories(d)) // seconds + { + if (!util::fs::detail::isNumberString(s.filename())) + { + ARMARX_WARNING << "Found a non-timestamp folder inside an entity '" + << id().str() << "' hours folder with name '" << s.filename() + << "'. " + << "Ignoring this folder, however this is a bad situation."; + continue; + } + + for (const auto& us : util::fs::getAllDirectories(s)) // microseconds + { + if (!util::fs::detail::isNumberString(us.filename())) + { + ARMARX_WARNING + << "Found a non-timestamp folder inside an entity '" << id().str() + << "' seconds folder with name '" << us.filename() << "'. " + << "Ignoring this folder, however this is a bad situation."; + continue; + } + + + EntitySnapshot c( + getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(timeFromStringMicroSeconds(us.filename())), + processors); + func(c); + } + } + } + } + */ + return true; + } + + bool + Entity::forEachSnapshotInIndexRange(long first, + long last, + std::function<void(EntitySnapshot&)> func) const + { + std::lock_guard l(ltm_mutex); + //ARMARX_WARNING << "PLEASE NOTE THAT QUERYING THE LTM INDEX WISE MAY BE BUGGY BECAUSE THE FILESYSTEM ITERATOR IS UNSORTED!"; + + if (first < 0 or last < 0) + { + // We need to know what the size of the memory is... May be slow + unsigned long size = 0; + auto f = [&](EntitySnapshot& e) { size++; }; + forEachSnapshot(std::move(f)); + + first = armarx::armem::base::detail::negativeIndexSemantics(first, size); + last = armarx::armem::base::detail::negativeIndexSemantics(last, size); + } + + long checked = 0; + auto f = [&](EntitySnapshot& e) + { + if (checked >= first && checked <= last) + { + func(e); + } + checked++; + }; + + return forEachSnapshot(std::move(f)); + } + + bool + Entity::forEachSnapshotInTimeRange(const Time& min, + const Time& max, + std::function<void(EntitySnapshot&)> func) const + { + std::lock_guard l(ltm_mutex); + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts >= min && ts <= max) + { + func(e); + } + }; + + return forEachSnapshot(std::move(f)); + } + + bool + Entity::forEachSnapshotBeforeOrAt(const Time& time, + std::function<void(EntitySnapshot&)> func) const + { + std::lock_guard l(ltm_mutex); + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts <= time) + { + func(e); + } + }; + + return forEachSnapshot(std::move(f)); + } + + bool + Entity::forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)> func) const + { + std::lock_guard l(ltm_mutex); + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts < time) + { + func(e); + } + }; + + return forEachSnapshot(std::move(f)); + } + + bool + Entity::hasSnapshot(const Time& n) const + { + std::lock_guard l(ltm_mutex); + if (connected() && collectionExists()) + { + auto c = EntitySnapshot(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(n), + processors); + return (bool)c.documentExists(); + } + + /*if (fullPathExists()) + { + auto c = EntitySnapshot(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(n), + processors); + return c.fullPathExists(); + }*/ + return false; + } + + std::shared_ptr<EntitySnapshot> + Entity::findSnapshot(const Time& n) const + { + std::lock_guard l(ltm_mutex); + if (!hasSnapshot(n)) + { + return nullptr; + } + return std::make_shared<EntitySnapshot>( + getMemoryBasePath(), getSettings(), getExportName(), id().withTimestamp(n), processors); + } + + std::shared_ptr<EntitySnapshot> + Entity::findLatestSnapshot() const + { + std::lock_guard l(ltm_mutex); + Time bestMatch = Time::Invalid(); + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts > bestMatch) + { + bestMatch = ts; + } + }; + + forEachSnapshot(std::move(f)); + + if (bestMatch == Time::Invalid()) + { + return nullptr; + } + + return std::make_shared<EntitySnapshot>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(bestMatch), + processors); + } + + std::shared_ptr<EntitySnapshot> + Entity::findLatestSnapshotBefore(const Time& time) const + { + std::lock_guard l(ltm_mutex); + Time bestMatch = Time::Invalid(); + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts < time && ts > bestMatch) + { + bestMatch = ts; + } + }; + + forEachSnapshot(std::move(f)); + + if (bestMatch == Time::Invalid()) + { + return nullptr; + } + + return std::make_shared<EntitySnapshot>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(bestMatch), + processors); + } + + std::shared_ptr<EntitySnapshot> + Entity::findLatestSnapshotBeforeOrAt(const Time& time) const + { + std::lock_guard l(ltm_mutex); + Time bestMatch = Time::Invalid(); + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts <= time && ts > bestMatch) + { + bestMatch = ts; + } + }; + + forEachSnapshot(std::move(f)); + + if (bestMatch == Time::Invalid()) + { + return nullptr; + } + + return std::make_shared<EntitySnapshot>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(bestMatch), + processors); + } + + std::shared_ptr<EntitySnapshot> + Entity::findFirstSnapshotAfter(const Time& time) const + { + std::lock_guard l(ltm_mutex); + Time bestMatch{Duration::MicroSeconds(std::numeric_limits<long>::max())}; + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts > time && ts < bestMatch) + { + bestMatch = ts; + } + }; + + forEachSnapshot(std::move(f)); + + if (bestMatch == Time(Duration::MicroSeconds(std::numeric_limits<long>::max()))) + { + return nullptr; + } + + return std::make_shared<EntitySnapshot>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(bestMatch), + processors); + } + + std::shared_ptr<EntitySnapshot> + Entity::findFirstSnapshotAfterOrAt(const Time& time) const + { + std::lock_guard l(ltm_mutex); + Time bestMatch{Duration::MicroSeconds(std::numeric_limits<long>::max())}; + auto f = [&](EntitySnapshot& e) + { + auto ts = e.id().timestamp; + if (ts >= time && ts < bestMatch) + { + bestMatch = ts; + } + }; + + forEachSnapshot(std::move(f)); + + if (bestMatch == Time(Duration::MicroSeconds(std::numeric_limits<long>::max()))) + { + return nullptr; + } + + return std::make_shared<EntitySnapshot>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(bestMatch), + processors); + } + + void + Entity::_loadAllReferences(armem::wm::Entity& e) + { + std::lock_guard l(ltm_mutex); + e.id() = id(); + + forEachSnapshot( + [&e](auto& x) + { + if (!e.hasSnapshot( + x.id() + .timestamp)) // we only load the references if the snapshot is not existant + { + armem::wm::EntitySnapshot s; + x.loadAllReferences(s); + e.addSnapshot(s); + } + }); + } + + void + Entity::_resolve(armem::wm::Entity& p) + { + std::lock_guard l(ltm_mutex); + + if ((connected() && collectionExists()) /* || fullPathExists()*/) + { + + p.forEachSnapshot( + [&](auto& e) + { + EntitySnapshot c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(e.id().timestamp), + processors); + c.resolve(e); + }); + } + } + + void + Entity::_store(const armem::wm::Entity& c) + { + std::lock_guard l(ltm_mutex); + if (id().entityName.empty()) + { + ARMARX_WARNING + << "During storage of segment '" << c.id().str() + << "' I noticed that the corresponding LTM has no id set. " + << "I set the id of the LTM to the same name, however this should not happen!"; + id().entityName = c.id().entityName; + } + + if (!connected()) + { + ARMARX_WARNING << "LTM ENTITY NOT CONNECTED ALTHOUGH ENABLED " << id().str(); + return; + } + + writeForeignKeyToPreviousDocument(); + + // legacy: also ensure filesystem exists + //ensureFullPathExists(true); + + c.forEachSnapshot( + [&](const auto& snap) + { + EntitySnapshot c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withTimestamp(snap.id().timestamp), + processors); + + // check if snapshot already exists + + if (hasSnapshot(snap.id().timestamp)) + { + ARMARX_INFO << deactivateSpam() + << "Ignoring to put an EntitiySnapshot into the LTM because " + "the timestamp already existed (we assume snapshots are " + "const and do not change outside the ltm)."; + return; + } + + for (auto& f : processors->snapFilters) + { + if (!f->accept(snap)) + { + ARMARX_INFO << deactivateSpam() + << "Ignoring to put an EntitiySnapshot into the LTM because it " + "got filtered."; + return; + } + } + + c.store(snap); + statistics.recordedSnapshots++; + }); + } +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/Entity.h b/source/RobotAPI/libraries/armem/server/ltm/Entity.h new file mode 100644 index 0000000000000000000000000000000000000000..6afeed78767669a6ac6a445be7324a53d667967a --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/Entity.h @@ -0,0 +1,56 @@ +#pragma once + +#include <filesystem> + +// Base Class +#include "EntitySnapshot.h" +#include "detail/EntityBase.h" +#include "detail/mixins/DiskStorageMixin.h" +#include "detail/mixins/MongoDBStorageMixin.h" + +namespace armarx::armem::server::ltm +{ + /// @brief A memory storing data in mongodb (needs 'armarx memory start' to start the mongod instance) + class Entity : + public detail::EntityBase<EntitySnapshot>, + public detail::mixin::DiskMemoryItemMixin, + public detail::mixin::MongoDBStorageMixin + { + public: + Entity(const detail::mixin::Path&, + const detail::mixin::MongoDBSettings&, + const std::string&, + const MemoryID& id, + const std::shared_ptr<Processors>&); + + bool hasSnapshot(const Time&) const override; + + bool forEachSnapshot(std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotInIndexRange(long first, + long last, + std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotInTimeRange(const Time& min, + const Time& max, + std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotBeforeOrAt(const Time& time, + std::function<void(EntitySnapshot&)> func) const override; + bool forEachSnapshotBefore(const Time& time, + std::function<void(EntitySnapshot&)> func) const override; + + std::shared_ptr<EntitySnapshot> findSnapshot(const Time&) const override; + std::shared_ptr<EntitySnapshot> findLatestSnapshot() const override; + std::shared_ptr<EntitySnapshot> findLatestSnapshotBefore(const Time& time) const override; + std::shared_ptr<EntitySnapshot> + findLatestSnapshotBeforeOrAt(const Time& time) const override; + std::shared_ptr<EntitySnapshot> findFirstSnapshotAfter(const Time& time) const override; + std::shared_ptr<EntitySnapshot> findFirstSnapshotAfterOrAt(const Time& time) const override; + + protected: + void _loadAllReferences(armem::wm::Entity&) override; + void _resolve(armem::wm::Entity&) override; + void _store(const armem::wm::Entity&) override; + + private: + }; + +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/EntityInstance.cpp b/source/RobotAPI/libraries/armem/server/ltm/EntityInstance.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9afb3c269354999e9193184f7462028f8061a16e --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/EntityInstance.cpp @@ -0,0 +1,232 @@ +// Header +#include "EntityInstance.h" + +// STD / STL +#include <fstream> +#include <iostream> + +// ArmarX +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +namespace armarx::armem::server::ltm +{ + EntityInstance::EntityInstance(const detail::mixin::Path& p, + const detail::mixin::MongoDBSettings& s, + + const std::string& exportName, + const armem::MemoryID& id /* UNESCAPED */, + const std::shared_ptr<Processors>& filters) : + EntityInstanceBase(exportName, id, filters), + DiskMemoryItemMixin(p, exportName, id), + MongoDBStorageMixin(s, exportName, id) + { + start(); + } + + void + EntityInstance::_loadAllReferences(armem::wm::EntitySnapshot& e) const + { + std::lock_guard l(ltm_mutex); + // assure that we put the right index to the snapshot + ARMARX_CHECK(e.size() == (size_t)id().instanceIndex); + + // add instance. Do not set data, since we only return references + e.addInstance(); + } + + void + EntityInstance::_resolve(armem::wm::EntityInstance& e) const + { + std::lock_guard l(ltm_mutex); + auto& dictConverter = processors->defaultObjectConverter; + + aron::data::DictPtr datadict = nullptr; + aron::data::DictPtr metadatadict = nullptr; + + if (connected() && collectionExists()) + { + if (auto d = documentExists(); d) + { + nlohmann::json doc = *d; + + if (doc.contains(DATA)) + { + std::vector<nlohmann::json> instances = doc[DATA]; + if (instances.size() > (size_t)id().instanceIndex) + { + nlohmann::json data = instances[id().instanceIndex]; + std::string dataStr = data.dump(); + + std::vector<unsigned char> dataVec{dataStr.begin(), dataStr.end()}; + auto dataaron = dictConverter.convert({dataVec, ""}, {}); + datadict = aron::data::Dict::DynamicCastAndCheck(dataaron); + } + else + { + ARMARX_ERROR << "Could not find the instance key. Continuing without data."; + } + } + else + { + ARMARX_ERROR << "Could not find the data key. Continuing without data."; + } + + if (doc.contains(METADATA)) + { + nlohmann::json metadata = doc[METADATA]; + std::string metadataStr = metadata.dump(); + std::vector<unsigned char> metadataVec{metadataStr.begin(), metadataStr.end()}; + auto metadataaron = dictConverter.convert({metadataVec, ""}, {}); + metadatadict = aron::data::Dict::DynamicCastAndCheck(metadataaron); + } + else + { + ARMARX_ERROR << "Could not find the metadata key. Continuing without metadata."; + } + } + } + + /*else if (fullPathExists()) + { + + std::string dataFilename = (DATA_FILENAME + dictConverter.suffix); + std::string metadataFilename = (METADATA_FILENAME + dictConverter.suffix); + std::filesystem::path dataPath = getFullPath() / dataFilename; + std::filesystem::path metadataPath = getFullPath() / metadataFilename; + + if (util::fs::fileExists(dataPath)) + { + //ARMARX_INFO << "Convert data for entity " << id(); + auto datafilecontent = readDataFromFile(dataFilename); + auto dataaron = dictConverter.convert({datafilecontent, ""}, {}); + datadict = aron::data::Dict::DynamicCastAndCheck(dataaron); + } + else + { + ARMARX_ERROR << "Could not find the data file '" << dataPath.string() + << "'. Continuing without data."; + } + + //ARMARX_INFO << "Convert metadata for entity " << id(); + if (util::fs::fileExists(metadataPath)) + { + auto metadatafilecontent = readDataFromFile(metadataFilename); + auto metadataaron = dictConverter.convert({metadatafilecontent, ""}, {}); + metadatadict = aron::data::Dict::DynamicCastAndCheck(metadataaron); + } + else + { + ARMARX_ERROR << "Could not find the metadata file '" << metadataPath.string() + << "'. Continuing without metadata."; + } + }*/ + + // check for special members TODO: only allowed for direct children? + auto allFilesInIndexFolder = getAllFiles(); + for (const auto& [key, m] : datadict->getElements()) + { + for (auto& f : processors->converters) + { + // iterate over all files and search for matching ones. + // We cannot simply check for the existence of a file because we do not know the + // mode (filename = memberName.mode.suffix) + for (const auto& filepath : allFilesInIndexFolder) + { + if (simox::alg::starts_with(filepath.filename(), key) and + simox::alg::ends_with(filepath, f->suffix)) + { + std::string mode = simox::alg::remove_suffix( + simox::alg::remove_prefix(filepath.filename(), key), f->suffix); + + auto memberfilecontent = readDataFromFile(filepath.filename()); + auto memberaron = f->convert( + {memberfilecontent, mode}, + armarx::aron::Path(datadict->getPath(), std::vector<std::string>{key})); + datadict->setElement(key, memberaron); + break; + } + } + } + } + + from_aron(metadatadict, datadict, e); + } + + nlohmann::json + EntityInstance::_store(const armem::wm::EntityInstance& e) + { + std::lock_guard l(ltm_mutex); + if (id().instanceIndex < 0) + { + ARMARX_WARNING + << "During storage of segment '" << e.id().str() + << "' I noticed that the corresponding LTM has no id set. " + << "I set the id of the LTM to the same name, however this should not happen!"; + id().timestamp = e.id().timestamp; + } + + auto& dictConverter = processors->defaultObjectConverter; + + if (!connected()) + { + ARMARX_WARNING << "LTM ENTITY INSTANCE NOT CONNECTED ALTHOUGH ENABLED " << id().str(); + return {}; + } + + // legacy: also ensure filesystem exists + // ensureFullPathExists(true); + + // data + auto dataAron = std::make_shared<aron::data::Dict>(); + auto metadataAron = std::make_shared<aron::data::Dict>(); + to_aron(metadataAron, dataAron, e); + + // check special members for special converters + for (auto& c : processors->converters) + { + ARMARX_CHECK_NOT_NULL(c); + ARMARX_CHECK_NOT_NULL(c->extractor); + + auto dataExt = c->extractor->extract(dataAron); + + for (const auto& [memberName, var] : dataExt.extraction) + { + ARMARX_CHECK_NOT_NULL(var); + + auto [memberDataVec, memberDataModeSuffix] = c->convert(var); + + std::string filename = (memberName + memberDataModeSuffix + c->suffix); + + ensureFileExists(filename, true); + writeDataToFile(filename, memberDataVec); + } + + dataAron = dataExt.dataWithoutExtraction; + } + + // convert dict and metadata + auto [dataVec, dataVecModeSuffix] = dictConverter.convert(dataAron); + auto [metadataVec, metadataVecModeSuffix] = dictConverter.convert(metadataAron); + ARMARX_CHECK_EMPTY(dataVecModeSuffix); + ARMARX_CHECK_EMPTY(metadataVecModeSuffix); + + return nlohmann::json::parse(std::string(dataVec.begin(), dataVec.end())); + + /*else + { + std::string dataFilename = (DATA_FILENAME + dictConverter.suffix); + std::string metadataFilename = (METADATA_FILENAME + dictConverter.suffix); + std::filesystem::path dataPath = getFullPath() / dataFilename; + std::filesystem::path metadataPath = getFullPath() / metadataFilename; + + writeDataToFile(dataFilename, dataVec); + writeDataToFile(metadataFilename, metadataVec); + }*/ + + //statistics.recordedData++; + //statistics.recordedMetaData++; + } +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/EntityInstance.h b/source/RobotAPI/libraries/armem/server/ltm/EntityInstance.h new file mode 100644 index 0000000000000000000000000000000000000000..d6f0b48a474a8b0b59aadb8f52d4f2a4e6ef0ef1 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/EntityInstance.h @@ -0,0 +1,33 @@ +#pragma once + +#include <filesystem> + +// Base Class +#include "detail/EntityInstanceBase.h" +#include "detail/mixins/DiskStorageMixin.h" +#include "detail/mixins/MongoDBStorageMixin.h" + +namespace armarx::armem::server::ltm +{ + + class EntityInstance : + public detail::EntityInstanceBase, + public detail::mixin::DiskMemoryItemMixin, + public detail::mixin::MongoDBStorageMixin + { + public: + EntityInstance(const detail::mixin::Path&, + const detail::mixin::MongoDBSettings&, + const std::string&, + const MemoryID& id, + const std::shared_ptr<Processors>& p); + + protected: + void _loadAllReferences(armem::wm::EntitySnapshot&) const override; + void _resolve(armem::wm::EntityInstance&) const override; + nlohmann::json _store(const armem::wm::EntityInstance&) override; + + private: + }; + +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/server/ltm/EntitySnapshot.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd030f54b6b353c3354b4800ea24f30b807aed67 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/EntitySnapshot.cpp @@ -0,0 +1,189 @@ +// Header +#include "EntitySnapshot.h" + +// STD / STL +#include <fstream> +#include <iostream> + +// ArmarX +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +namespace armarx::armem::server::ltm +{ + EntitySnapshot::EntitySnapshot(const detail::mixin::Path& p, + const detail::mixin::MongoDBSettings& s, + + const std::string& exportName, + const armem::MemoryID& id /* UNESCAPED */, + const std::shared_ptr<Processors>& filters) : + EntitySnapshotBase(exportName, id, filters), + DiskMemoryItemMixin(p, exportName, id), + MongoDBStorageMixin(s, exportName, id) + { + start(); + } + + bool + EntitySnapshot::forEachInstance(std::function<void(EntityInstance&)> func) const + { + std::lock_guard l(ltm_mutex); + + if (connected() && collectionExists()) + { + if (auto d = documentExists(); d) + { + nlohmann::json doc = *d; + std::vector<nlohmann::json> instances = doc[DATA]; + for (unsigned int i = 0; i < instances.size(); ++i) + { + EntityInstance c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withInstanceIndex(i), + processors); + func(c); + } + } + } + + /*else if (fullPathExists()) + { + for (const auto& i : getAllDirectories()) + { + if (!util::fs::detail::isNumberString(i.filename())) + { + ARMARX_WARNING << "Found a non-index folder inside an entity '" << id().str() + << "' with name '" << i.filename() << "'. " + << "Ignoring this folder, however this is a bad situation."; + continue; + } + + EntityInstance c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withInstanceIndex(std::stoi(i.filename())), + processors); + func(c); + } + }*/ + return true; + } + + bool + EntitySnapshot::hasInstance(const int index) const + { + std::lock_guard l(ltm_mutex); + + if (connected() && collectionExists()) + { + if (auto d = documentExists(); d) + { + nlohmann::json doc = *d; + std::vector<nlohmann::json> instances = doc[DATA]; + return (size_t)index < instances.size(); + } + } + + /*if (fullPathExists()) + { + auto c = EntityInstance(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withInstanceIndex(index), + processors); + return c.fullPathExists(); + }*/ + + return false; + } + + std::shared_ptr<EntityInstance> + EntitySnapshot::findInstance(const int index) const + { + std::lock_guard l(ltm_mutex); + + if (!hasInstance(index)) + { + return nullptr; + } + return std::make_shared<EntityInstance>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withInstanceIndex(index), + processors); + } + + void + EntitySnapshot::_loadAllReferences(armem::wm::EntitySnapshot& e) const + { + std::lock_guard l(ltm_mutex); + + e.id() = id(); + forEachInstance([&e](auto& x) { x.loadAllReferences(e); }); + } + + void + EntitySnapshot::_resolve(armem::wm::EntitySnapshot& p) const + { + std::lock_guard l(ltm_mutex); + + if ((connected() && collectionExists() && documentExists()) /* || fullPathExists()*/) + { + p.forEachInstance( + [&](auto& e) + { + EntityInstance c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withInstanceIndex(e.id().instanceIndex), + processors); + //c.resolve(e); + }); + } + } + + void + EntitySnapshot::_store(const armem::wm::EntitySnapshot& p) + { + std::lock_guard l(ltm_mutex); + + if (id().timestamp.isInvalid()) + { + ARMARX_WARNING + << "During storage of segment '" << p.id().str() + << "' I noticed that the corresponding LTM has no id set. " + << "I set the id of the LTM to the same name, however this should not happen!"; + id().timestamp = p.id().timestamp; + } + + if (!connected()) + { + ARMARX_WARNING << "LTM ENTITY SNAPSHOT NOT CONNECTED ALTHOUGH ENABLED " << id().str(); + return; + } + + // legacy: also ensure filesystem exists + //ensureFullPathExists(true); + + nlohmann::json data; + data[DATA] = std::vector<nlohmann::json>(); + + p.forEachInstance( + [&](const auto& e) + { + EntityInstance c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withInstanceIndex(e.id().instanceIndex), + processors); + + data[DATA].push_back(c.store(e)); + statistics.recordedInstances++; + }); + + writeDataToDocument(data); + } +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/EntitySnapshot.h b/source/RobotAPI/libraries/armem/server/ltm/EntitySnapshot.h new file mode 100644 index 0000000000000000000000000000000000000000..58c7d41bdae3009d60664680859ea902894f0c04 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/EntitySnapshot.h @@ -0,0 +1,38 @@ +#pragma once + +#include <filesystem> + +// Base Class +#include "EntityInstance.h" +#include "detail/EntitySnapshotBase.h" +#include "detail/mixins/DiskStorageMixin.h" +#include "detail/mixins/MongoDBStorageMixin.h" + +namespace armarx::armem::server::ltm +{ + + class EntitySnapshot : + public detail::EntitySnapshotBase<EntityInstance>, + public detail::mixin::DiskMemoryItemMixin, + public detail::mixin::MongoDBStorageMixin + { + public: + EntitySnapshot(const detail::mixin::Path&, + const detail::mixin::MongoDBSettings&, + const std::string&, + const MemoryID& id, + const std::shared_ptr<Processors>& p); + + bool forEachInstance(std::function<void(EntityInstance&)> func) const override; + bool hasInstance(const int) const override; + std::shared_ptr<EntityInstance> findInstance(const int) const override; + + protected: + void _loadAllReferences(armem::wm::EntitySnapshot&) const override; + void _resolve(armem::wm::EntitySnapshot&) const override; + void _store(const armem::wm::EntitySnapshot&) override; + + private: + }; + +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/Memory.cpp b/source/RobotAPI/libraries/armem/server/ltm/Memory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe87a47ba0be32b6a441355c786f4d10a6d02423 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/Memory.cpp @@ -0,0 +1,254 @@ +#include "Memory.h" + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> + +namespace armarx::armem::server::ltm +{ + void + Memory::_configure(const nlohmann::json& json) + { + std::lock_guard l(ltm_mutex); + + BufferedBase::configureMixin(json); + CachedBase::configureMixin(json); + DiskMemoryBase::configureMixin(json); + MongoDBStorageMixin::configureMixin(json); + } + + Memory::Memory() : Memory(std::filesystem::path("/tmp"), {}, "MemoryExport", "Test") + { + } + + Memory::Memory(const detail::mixin::Path& p, + + const std::string& exportName, + const std::string& memoryName /* UNESCAPED */) : + Memory(p, {}, exportName, memoryName) + { + } + + Memory::Memory(const detail::mixin::Path& p, + const detail::mixin::MongoDBSettings& s, + + const std::string& exportName, + const std::string& memoryName /* UNESCAPED */) : + MemoryBase(exportName, MemoryID(memoryName, "")), + BufferedBase(MemoryID(memoryName, "")), + CachedBase(MemoryID(memoryName, "")), + DiskMemoryItemMixin(p, exportName, MemoryID(memoryName, "")), + MongoDBStorageMixin(s, exportName, MemoryID(memoryName, "")) + { + } + + void + Memory::_setExportName(const std::string& n) + { + DiskMemoryBase::setMixinExportName(n); + MongoDBStorageMixin::setMixinExportName(n); + } + + void + Memory::_enable() + { + BufferedBase::start(); + MongoDBStorageMixin::start(); + } + + void + Memory::_disable() + { + BufferedBase::stop(); + MongoDBStorageMixin::stop(); + } + + void + Memory::_setMemoryID(const MemoryID& id) + { + std::lock_guard l(ltm_mutex); + + BufferedBase::setMixinMemoryID(id); + CachedBase::setMixinMemoryID(id); + DiskMemoryBase::setMixinMemoryID(id); + MongoDBStorageMixin::setMixinMemoryID(id); + } + + bool + Memory::forEachCoreSegment(std::function<void(CoreSegment&)> func) const + { + std::lock_guard l(ltm_mutex); + + // for each + if (connected() && collectionExists()) + { + for (const auto& doc : getAllDocuments()) + { + std::string segmentName = doc[FOREIGN_KEY]; + CoreSegment c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withCoreSegmentName(segmentName), + processors); + func(c); + } + } + + /*// legacy: check fs + else if (fullPathExists()) + { + for (const auto& subdirName : getAllDirectories()) + { + std::string segmentName = util::fs::detail::unescapeName(subdirName); + CoreSegment c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withCoreSegmentName(segmentName), + processors); + func(c); + } + }*/ + + return true; + } + + bool + Memory::hasCoreSegment(const std::string& name) const + { + std::lock_guard l(ltm_mutex); + + if (cacheHasCoreSegment(name)) + { + return true; + } + + // check if collection exists + if (connected() && collectionExists()) + { + auto c = CoreSegment(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withCoreSegmentName(name), + processors); + + return (bool)c.collectionExists(); + } + + /*// legacy: check if segment is stored on hard drive without db + if (fullPathExists()) + { + auto c = CoreSegment(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withCoreSegmentName(name), + processors); + + return c.fullPathExists(); + }*/ + + return false; + } + + std::unique_ptr<CoreSegment> + Memory::findCoreSegment(const std::string& coreSegmentName) const + { + std::lock_guard l(ltm_mutex); + + if (!hasCoreSegment(coreSegmentName)) + { + return nullptr; + } + + return std::make_unique<CoreSegment>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withCoreSegmentName(coreSegmentName), + processors); + } + + void + Memory::_loadAllReferences(armem::wm::Memory& m) + { + std::lock_guard l(ltm_mutex); + + m.id() = id(); + + forEachCoreSegment( + [&m](auto& x) + { + armem::wm::CoreSegment s; + x.loadAllReferences(s); + m.addCoreSegment(s); + }); + } + + void + Memory::_resolve(armem::wm::Memory& m) + { + std::lock_guard l(ltm_mutex); // we cannot load a memory multiple times simultaneously + + if ((connected() && collectionExists()) /* || fullPathExists()*/) + { + m.forEachCoreSegment( + [&](auto& e) + { + CoreSegment c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withCoreSegmentName(e.id().coreSegmentName), + processors); + c.resolve(e); + }); + } + } + + void + Memory::_store(const armem::wm::Memory& m) + { + BufferedBase::addToBuffer(m); + } + + void + Memory::_directlyStore(const armem::wm::Memory& memory) + { + std::lock_guard l(ltm_mutex); // we cannot store a memory multiple times simultaneously + + if (id().memoryName.empty()) + { + ARMARX_WARNING + << "During storage of memory '" << memory.id().str() + << "' I noticed that the corresponding LTM has no id set. " + << "I set the id of the LTM to the same name, however this should not happen!"; + setMemoryID(memory.id()); + } + + if (!connected()) + { + ARMARX_WARNING << "LTM NOT CONNECTED ALTHOUGH ENABLED " << id().str(); + return; + } + + // legacy: also ensure filesystem exists + // ensureFullPathExists(true); + + memory.forEachCoreSegment( + [&](const auto& core) + { + CoreSegment c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withCoreSegmentName(core.id().coreSegmentName), + processors); + + // 2. store data + c.store(core); + + // 3. update statistics + statistics.recordedCoreSegments++; + }); + + // 4. update cache + CachedBase::addToCache(memory); + } +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/Memory.h b/source/RobotAPI/libraries/armem/server/ltm/Memory.h new file mode 100644 index 0000000000000000000000000000000000000000..30e1929dd3156dfb0f9d4412ac78e44bb62ce664 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/Memory.h @@ -0,0 +1,56 @@ +#pragma once + +#include <filesystem> + +// Base Class +#include "detail/MemoryBase.h" +#include "detail/mixins/BufferedMemoryMixin.h" +#include "detail/mixins/CachedMemoryMixin.h" +#include "detail/mixins/DiskStorageMixin.h" +#include "detail/mixins/MongoDBStorageMixin.h" + +// Segmnet Type +#include "CoreSegment.h" + +namespace armarx::armem::server::ltm +{ + /// @brief A memory storing data on the hard drive and in mongodb (needs 'armarx memory start' to start the mongod instance) + class Memory : + public detail::MemoryBase<CoreSegment>, + public detail::mixin::BufferedMemoryMixin<CoreSegment>, + public detail::mixin::CachedMemoryMixin<CoreSegment>, + public detail::mixin::DiskMemoryItemMixin, + public detail::mixin::MongoDBStorageMixin + { + public: + using MemoryBase = detail::MemoryBase<CoreSegment>; + using BufferedBase = detail::mixin::BufferedMemoryMixin<CoreSegment>; + using CachedBase = detail::mixin::CachedMemoryMixin<CoreSegment>; + using DiskMemoryBase = detail::mixin::DiskMemoryItemMixin; + using MongoDBStorageMixin = detail::mixin::MongoDBStorageMixin; + + Memory(); + Memory(const detail::mixin::Path&, const std::string&, const std::string&); + Memory(const detail::mixin::Path&, + const detail::mixin::MongoDBSettings&, + const std::string&, + const std::string&); + + void _setExportName(const std::string& n) final; + void _setMemoryID(const MemoryID& id) final; + void _enable() final; + void _disable() final; + void _configure(const nlohmann::json& config) final; + + bool forEachCoreSegment(std::function<void(CoreSegment&)> func) const final; + bool hasCoreSegment(const std::string& name) const final; + std::unique_ptr<CoreSegment> + findCoreSegment(const std::string& coreSegmentName) const final; + + protected: + void _loadAllReferences(armem::wm::Memory&) final; + void _resolve(armem::wm::Memory&) final; + void _store(const armem::wm::Memory&) final; + void _directlyStore(const armem::wm::Memory&) final; + }; +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/server/ltm/ProviderSegment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb64b87c395c5837afb41daca249bdd390a3944c --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/ProviderSegment.cpp @@ -0,0 +1,218 @@ +// Header +#include "ProviderSegment.h" + +// ArmarX +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> + +namespace armarx::armem::server::ltm +{ + ProviderSegment::ProviderSegment(const detail::mixin::Path& p, + const detail::mixin::MongoDBSettings& s, + + const std::string& exportName, + const armem::MemoryID& id /* UNESCAPED */, + const std::shared_ptr<Processors>& filters) : + ProviderSegmentBase(exportName, id, filters), + DiskMemoryItemMixin(p, exportName, id), + MongoDBStorageMixin(s, exportName, id) + { + start(); + } + + bool + ProviderSegment::forEachEntity(std::function<void(Entity&)> func) const + { + std::lock_guard l(ltm_mutex); + + if (connected() && collectionExists()) + { + for (const auto& doc : getAllDocuments()) + { + std::string id_str = doc[FOREIGN_KEY]; + armem::MemoryID segment_id(id_str); + Entity c( + getMemoryBasePath(), getSettings(), getExportName(), segment_id, processors); + func(c); + } + } + + /*else if (fullPathExists()) + { + + for (const auto& subdirName : getAllDirectories()) + { + std::string segmentName = util::fs::detail::unescapeName(subdirName); + Entity c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withEntityName(segmentName), + processors); + func(c); + } + }*/ + return true; + } + + bool + ProviderSegment::hasEntity(const std::string& name) const + { + std::lock_guard l(ltm_mutex); + + if (connected() && collectionExists()) + { + auto c = Entity(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withEntityName(name), + processors); + return (bool)c.collectionExists(); + } + + /*if (fullPathExists()) + { + auto c = Entity(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withEntityName(name), + processors); + return c.fullPathExists(); + }*/ + + return false; + } + + std::shared_ptr<Entity> + ProviderSegment::findEntity(const std::string& entityName) const + { + std::lock_guard l(ltm_mutex); + + if (!hasEntity(entityName)) + { + return nullptr; + } + return std::make_shared<Entity>(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withEntityName(entityName), + processors); + } + + void + ProviderSegment::_loadAllReferences(armem::wm::ProviderSegment& e) + { + std::lock_guard l(ltm_mutex); + + e.id() = id(); + + auto& conv = processors->defaultTypeConverter; + auto setType = [&conv, &e](const std::vector<unsigned char>& aronJson) + { + auto typeAron = conv.convert(aronJson, ""); + e.aronType() = aron::type::Object::DynamicCastAndCheck(typeAron); + }; + + if (connected() && collectionExists()) + { + // TODO: + } + + /*else if (std::string filename = TYPE_FILENAME + conv.suffix; + fullPathExists() && fileExists(filename)) + { + auto typeFileContent = readDataFromFile(filename); + setType(typeFileContent); + }*/ + + forEachEntity( + [&e](auto& x) + { + armem::wm::Entity s; + x.loadAllReferences(s); + e.addEntity(s); + }); + } + + void + ProviderSegment::_resolve(armem::wm::ProviderSegment& p) + { + std::lock_guard l(ltm_mutex); + + if ((connected() && collectionExists()) /* || fullPathExists()*/) + { + p.forEachEntity( + [&](auto& e) + { + Entity c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withEntityName(e.id().entityName), + processors); + c.resolve(e); + }); + } + } + + void + ProviderSegment::_store(const armem::wm::ProviderSegment& p) + { + std::lock_guard l(ltm_mutex); + + if (id().providerSegmentName.empty()) + { + ARMARX_WARNING + << "During storage of segment '" << p.id().str() + << "' I noticed that the corresponding LTM has no id set. " + << "I set the id of the LTM to the same name, however this should not happen!"; + id().providerSegmentName = p.id().providerSegmentName; + } + + if (!connected()) + { + ARMARX_WARNING << "LTM PROVIDER SEGMENT NOT CONNECTED ALTHOUGH ENABLED " << id().str(); + return; + } + + // add foreign key to memory collection + if (p.hasAronType()) + { + auto& conv = processors->defaultTypeConverter; + + auto [vec, modeSuffix] = conv.convert(p.aronType()); + ARMARX_CHECK_EMPTY(modeSuffix); + + std::string dataStr{vec.begin(), vec.end()}; + auto dataJson = nlohmann::json::parse(dataStr); + + writeForeignKeyToPreviousDocument(dataJson); + } + else + { + writeForeignKeyToPreviousDocument(); + } + + // legacy: also ensure filesystem exists + //ensureFullPathExists(true); + /*else + { + std::string filename = (TYPE_FILENAME + conv.suffix); + writeDataToFile(filename, vec); + }*/ + + p.forEachEntity( + [&](const auto& e) + { + Entity c(getMemoryBasePath(), + getSettings(), + getExportName(), + id().withEntityName(e.id().entityName), + processors); + + c.store(e); + statistics.recordedEntities++; + }); + } + +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/ProviderSegment.h b/source/RobotAPI/libraries/armem/server/ltm/ProviderSegment.h new file mode 100644 index 0000000000000000000000000000000000000000..5f880676c43f483c6ae66a65c41a7a17bf93aa70 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/ProviderSegment.h @@ -0,0 +1,37 @@ +#pragma once + +#include <filesystem> + +// Base Class +#include "Entity.h" +#include "detail/ProviderSegmentBase.h" +#include "detail/mixins/DiskStorageMixin.h" +#include "detail/mixins/MongoDBStorageMixin.h" + +namespace armarx::armem::server::ltm +{ + class ProviderSegment : + public detail::ProviderSegmentBase<Entity>, + public detail::mixin::DiskMemoryItemMixin, + public detail::mixin::MongoDBStorageMixin + { + public: + ProviderSegment(const detail::mixin::Path&, + const detail::mixin::MongoDBSettings&, + const std::string&, + const MemoryID& id, + const std::shared_ptr<Processors>&); + + bool forEachEntity(std::function<void(Entity&)> func) const override; + bool hasEntity(const std::string&) const override; + std::shared_ptr<Entity> findEntity(const std::string&) const override; + + protected: + void _loadAllReferences(armem::wm::ProviderSegment&) override; + void _resolve(armem::wm::ProviderSegment&) override; + void _store(const armem::wm::ProviderSegment&) override; + + private: + }; + +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/converter/Converter.cpp deleted file mode 100644 index fd719807eb069bcf62db065ed42bb649c38d225d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/Converter.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Converter.h" diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/base/converter/Converter.h deleted file mode 100644 index 0ed3d9b08188179d17e5baaf0087b0c33e75eaa0..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/Converter.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -// STD/STL -#include <memory> - -// ArmarX -#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> - -namespace armarx::armem::server::ltm -{ - class Converter - { - public: - enum class ConverterType - { - Str, - Binary - }; - - Converter(const ConverterType t, const std::string& id, const std::string& s, const aron::type::Descriptor c): - type(t), - identifier(id), - suffix(s), - convertsType(c) - {} - virtual ~Converter() = default; - - virtual std::pair<std::vector<unsigned char>, std::string> convert(const aron::data::VariantPtr& data) = 0; - virtual aron::data::VariantPtr convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) = 0; - - public: - const ConverterType type; - const std::string identifier; - const std::string suffix; - const aron::type::Descriptor convertsType; - bool enabled = false; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/Converter.cpp deleted file mode 100644 index 30349fd4faa55ab513d6c080251138cb16bafe77..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/Converter.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Converter.h" - -namespace armarx::armem::server::ltm -{ - - std::pair<std::vector<unsigned char>, std::string> ImageConverter::convert(const aron::data::VariantPtr& data) - { - auto d = aron::data::NDArray::DynamicCastAndCheck(data); - return _convert(d); - } - - aron::data::VariantPtr ImageConverter::convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string& m) - { - auto d = _convert(data, p, m); - return d; - } - -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/Converter.h deleted file mode 100644 index 440c1c6c50815eb56576fca2cd1bb65d1185f0ec..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/Converter.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -// STD/STL -#include <memory> - -// BaseClass -#include "../Converter.h" - -// ArmarX -#include <RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h> - -namespace armarx::armem::server::ltm -{ - class ImageConverter : public Converter - { - public: - ImageConverter(const ConverterType t, const std::string& id, const std::string& s): - Converter(t, id, s, aron::type::Descriptor::IMAGE) - {} - - virtual ~ImageConverter() = default; - - std::pair<std::vector<unsigned char>, std::string> convert(const aron::data::VariantPtr& data) final; - aron::data::VariantPtr convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) final; - - protected: - virtual std::pair<std::vector<unsigned char>, std::string> _convert(const aron::data::NDArrayPtr& data) = 0; - virtual aron::data::NDArrayPtr _convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) = 0; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/exr/ExrConverter.h b/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/exr/ExrConverter.h deleted file mode 100644 index 07e94a5b2c8ef2951949854600e25f4a901d6478..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/exr/ExrConverter.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -// Base Class -#include "../Converter.h" - -namespace armarx::armem::server::ltm::converter::image -{ - class ExrConverter : public ImageConverter - { - public: - ExrConverter() : - ImageConverter(ConverterType::Binary, "depthimage", ".exr") - { - enabled = true; // enabled by default - } - - protected: - std::pair<std::vector<unsigned char>, std::string> _convert(const aron::data::NDArrayPtr& data) final; - aron::data::NDArrayPtr _convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) final; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/png/PngConverter.h b/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/png/PngConverter.h deleted file mode 100644 index 0c443fa794d22a6a7a6f5c837565693f8cf2e28c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/png/PngConverter.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -// Base Class -#include "../Converter.h" - -namespace armarx::armem::server::ltm::converter::image -{ - class PngConverter : public ImageConverter - { - public: - PngConverter() : - ImageConverter(ConverterType::Binary, "image", ".png") - { - enabled = true; // enabled by default - } - - protected: - std::pair<std::vector<unsigned char>, std::string> _convert(const aron::data::NDArrayPtr& data) final; - aron::data::NDArrayPtr _convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) final; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/Converter.cpp deleted file mode 100644 index e6c3345028e9c3af35636d0f509412c4e8ca925a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/Converter.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Converter.h" - -namespace armarx::armem::server::ltm -{ - - std::pair<std::vector<unsigned char>, std::string> ObjectConverter::convert(const aron::data::VariantPtr& data) - { - auto d = aron::data::Dict::DynamicCastAndCheck(data); - return _convert(d); - } - - aron::data::VariantPtr ObjectConverter::convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string& m) - { - auto d = _convert(data, p, m); - return d; - } - -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/Converter.h deleted file mode 100644 index 113dd7a5b726f9b75efa07875f0a07fa443fc3a1..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/Converter.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -// STD/STL -#include <memory> - -// BaseClass -#include "../Converter.h" - -// ArmarX -#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> - -namespace armarx::armem::server::ltm -{ - class ObjectConverter : public Converter - { - public: - ObjectConverter(const ConverterType t, const std::string& id, const std::string& s): - Converter(t, id, s, aron::type::Descriptor::OBJECT) - {} - - virtual ~ObjectConverter() = default; - - std::pair<std::vector<unsigned char>, std::string> convert(const aron::data::VariantPtr& data) final; - aron::data::VariantPtr convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) final; - - protected: - virtual std::pair<std::vector<unsigned char>, std::string> _convert(const aron::data::DictPtr& data) = 0; - virtual aron::data::DictPtr _convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) = 0; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/bson/BsonConverter.h b/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/bson/BsonConverter.h deleted file mode 100644 index fddf6870f2bbcbc6580e1eb8bf8907e40416e3a0..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/bson/BsonConverter.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -// Base Class -#include "../Converter.h" - -// ArmarX -#include "../json/JsonConverter.h" - -namespace armarx::armem::server::ltm::converter::object -{ - class BsonConverter; - using BsonConverterPtr = std::shared_ptr<BsonConverter>; - - class BsonConverter : public ObjectConverter - { - public: - BsonConverter() : - ObjectConverter(ConverterType::Binary, "dict", ".bson") - {} - - protected: - std::pair<std::vector<unsigned char>, std::string> _convert(const aron::data::DictPtr& data) final; - aron::data::DictPtr _convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) final; - - private: - JsonConverter jsonConverter; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.h b/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.h deleted file mode 100644 index 0c6d71d119396ff7e0293ea5196c252c9ba3cc7c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -// Base Class -#include "../Converter.h" - -// Simox -#include <SimoxUtility/json.h> - -namespace armarx::armem::server::ltm::converter::object -{ - class JsonConverter : public ObjectConverter - { - public: - JsonConverter() : - ObjectConverter(ConverterType::Str, "dict", ".json") - { - enabled = true; // always true! - } - - protected: - std::pair<std::vector<unsigned char>, std::string> _convert(const aron::data::DictPtr& data) final; - aron::data::DictPtr _convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string&) final; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/BufferedMemoryBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/detail/BufferedMemoryBase.cpp deleted file mode 100644 index 864266ce87d1e01a2f8eea0e0133a67ed14e7528..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/BufferedMemoryBase.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "BufferedMemoryBase.h" - -namespace armarx::armem::server::ltm -{ - - -} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/LUTMemoryBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/detail/LUTMemoryBase.cpp deleted file mode 100644 index 1078e776d6ef68d2f7e102bff78676bb28d9b351..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/LUTMemoryBase.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "LUTMemoryBase.h" - -namespace armarx::armem::server::ltm -{ - -} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/LUTMemoryBase.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/LUTMemoryBase.h deleted file mode 100644 index be92704ab2c2e3a8c14d380bfa1b62f4826f34fb..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/LUTMemoryBase.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "MemoryBase.h" - -namespace armarx::armem::server::ltm -{ - /*// TODO refactor to mixin (see buffered) - template <class _CoreSegmentT> - class CachedMemoryBase : virtual public MemoryBase<_CoreSegmentT> - { - public: - using MemoryBase<_CoreSegmentT>::MemoryBase; - - armem::wm::Memory getCache() const - { - std::lock_guard l(this->ltm_mutex); - return cache; - } - - void setMemoryID(const MemoryID& id) override - { - MemoryBase<_CoreSegmentT>::setMemoryID(id); - cache.name() = this->name(); - } - - protected: - static bool EntitySnapshotHasData(const armem::wm::EntitySnapshot& e) - { - // check whether all data is nullptr - bool allDataIsNull = e.size() > 0; - e.forEachInstance([&allDataIsNull](armem::wm::EntityInstance & e) - { - if (e.data()) - { - allDataIsNull = false; - return false; // means break - } - return true; - }); - return !allDataIsNull; - } - - protected: - - armem::wm::Memory cache; - - };*/ -} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp deleted file mode 100644 index d5318e1f1e6ec9933ddc7e6b50f3894044111917..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "MemoryItem.h" - -#include <ArmarXCore/core/logging/Logging.h> -#include <ArmarXCore/core/time/TimeUtil.h> - -#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> - -namespace armarx::armem::server::ltm -{ - MemoryItem::MemoryItem(const MemoryID& id) : - processors(std::make_shared<Processors>()), - _id(id) - { - } - - MemoryItem::MemoryItem(const MemoryID& id, const std::shared_ptr<Processors>& p) : - processors(p), - _id(id) - { - } - - void MemoryItem::setMemoryID(const MemoryID& id) - { - _id = id; - } - - MemoryID MemoryItem::id() const - { - return _id; - } - - std::string MemoryItem::name() const - { - return _id.getLeafItem(); - } - - void MemoryItem::setMemoryName(const std::string& memoryName) - { - _id.memoryName = memoryName; - } -} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h deleted file mode 100644 index b8d17fe471c17e62aa188406648515e5a32f384a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryItem.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include <map> -#include <mutex> -#include <optional> -#include <string> - -#include "Processors.h" - -namespace armarx::armem::server::ltm -{ - /// @brief Interface functions for the longterm memory classes - class MemoryItem - { - public: - MemoryItem(const MemoryID&); // only used by memory - MemoryItem(const MemoryID&, const std::shared_ptr<Processors>&); // used by all other segments - virtual ~MemoryItem() = default; - - MemoryID id() const; - std::string name() const; - - virtual void setMemoryID(const MemoryID&); - void setMemoryName(const std::string& memoryName); - - protected: - std::shared_ptr<Processors> processors; - - private: - MemoryID _id; - }; -} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/Processors.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/detail/Processors.cpp deleted file mode 100644 index 33934e1af67f1b1b11c72c54fdc43335a115fe42..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/Processors.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Processors.h" - -namespace armarx::armem::server::ltm -{ - Processors::Processors() - { - // setup containers - memFilters.push_back(&memFreqFilter); - snapFilters.push_back(&snapFreqFilter); - snapFilters.push_back(&snapEqFilter); - extractors.push_back(&imageExtractor); - extractors.push_back(&depthImageExtractor); - converters.insert({pngConverter.identifier, &pngConverter}); - converters.insert({exrConverter.identifier, &exrConverter}); - } - - void Processors::configure(const nlohmann::json& config) - { - - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/Processors.h b/source/RobotAPI/libraries/armem/server/ltm/base/detail/Processors.h deleted file mode 100644 index 43677cb9bb019fb61610ff977b0e57b2ce9b238a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/Processors.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include <map> -#include <mutex> -#include <optional> -#include <string> - -#include <ArmarXCore/core/application/properties/Properties.h> - -#include "../filter/frequencyFilter/FrequencyFilter.h" -#include "../filter/equalityFilter/EqualityFilter.h" -#include "../extractor/imageExtractor/ImageExtractor.h" -#include "../extractor/imageExtractor/DepthImageExtractor.h" -#include "../converter/object/json/JsonConverter.h" -#include "../converter/image/png/PngConverter.h" -#include "../converter/image/exr/ExrConverter.h" -#include "../typeConverter/json/JsonConverter.h" - -#include <RobotAPI/libraries/armem/core/MemoryID.h> - -namespace armarx::armem::server::ltm -{ - /// all necessary classes to filter and convert an entry of the ltm to some other format(s) - class Processors - { - public: - Processors(); - void configure(const nlohmann::json& config); - - public: - // Unique Memory Filters - std::vector<MemoryFilter*> memFilters; - filter::MemoryFrequencyFilter memFreqFilter; - - // Unique Snapshot filters - std::vector<SnapshotFilter*> snapFilters; - filter::SnapshotFrequencyFilter snapFreqFilter; - filter::SnapshotEqualityFilter snapEqFilter; - - // Special Extractors - std::vector<Extractor*> extractors; - extractor::ImageExtractor imageExtractor; - extractor::DepthImageExtractor depthImageExtractor; - - // Special Converters - std::map<std::string, Converter*> converters; - converter::image::PngConverter pngConverter; - converter::image::ExrConverter exrConverter; - - // Default converter - converter::object::JsonConverter defaultObjectConverter; - converter::type::JsonConverter defaultTypeConverter; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/Extractor.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/extractor/Extractor.cpp deleted file mode 100644 index 57443153937c94fc7f218ec2ce427d7c5f45a7b5..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/Extractor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Extractor.h" diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/Filter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/filter/Filter.cpp deleted file mode 100644 index 088af9712ebf2e93637acfa5ec982e05e9cfd66e..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/Filter.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "Filter.h" - diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.cpp deleted file mode 100644 index 6ca0a944c2f2bd59681128ac22f86eaa58e50b51..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "EqualityFilter.h" - -#include <IceUtil/Time.h> - -namespace armarx::armem::server::ltm::filter -{ - bool SnapshotEqualityFilter::accept(const armem::wm::EntitySnapshot& e) - { - auto entityID = e.id().getEntityID(); - auto genMs = e.time().toMilliSecondsSinceEpoch(); - - long lastMs = 0; - std::vector<aron::data::DictPtr> lastData; - if (timestampLastCommitInMs.count(entityID) > 0) - { - lastData = dataLastCommit.at(entityID); - lastMs = timestampLastCommitInMs.at(entityID); - } - - auto timePassedSinceLastStored = genMs - lastMs; - if (maxWaitingTimeInMs < 0 || timePassedSinceLastStored > maxWaitingTimeInMs) - { - bool accept = false; - std::vector<aron::data::DictPtr> genData; - for (unsigned int i = 0; i != e.size(); ++i) - { - const auto& d = e.getInstance(i).data(); - genData.push_back(d); - - if (lastMs == 0 || e.size() != lastData.size()) // nothing stored yet or we cannot compare - { - accept = true; - break; - } - - const auto& el = lastData.at(i); - if ((!d and el) || (d and !el) || (d && el && !(*d == *el))) // data unequal? - { - accept = true; - break; - } - } - - if (!accept) return false; - - dataLastCommit[entityID] = genData; - timestampLastCommitInMs[entityID] = genMs; - return true; - } - return false; - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.h b/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.h deleted file mode 100644 index f8427b2b70e41cd603702cb60b5664ddef3126da..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include <map> - -// Base Class -#include "../Filter.h" - -namespace armarx::armem::server::ltm::filter -{ - class MemoryFrequencyFilter : - public MemoryFilter - { - public: - MemoryFrequencyFilter() = default; - - virtual bool accept(const armem::wm::Memory& e) override; - - public: - int waitingTimeInMs = -1; - - private: - long timestampLastCommitInMs = 0; - }; - - class SnapshotFrequencyFilter : - public SnapshotFilter - { - public: - SnapshotFrequencyFilter() = default; - - virtual bool accept(const armem::wm::EntitySnapshot& e) override; - - public: - int waitingTimeInMs = -1; - - private: - std::map<MemoryID, long> timestampLastCommitInMs; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/Converter.cpp deleted file mode 100644 index c846adcbd45ddb152a4525207a9bbde30bd897af..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/Converter.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "Converter.h" - -namespace armarx::armem::server::ltm -{ - -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/Converter.h deleted file mode 100644 index 8290e17c03f3e32e4d7b417b2269699869a85a0a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/Converter.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -// STD/STL -#include <memory> - -// ArmarX -#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h> - -namespace armarx::armem::server::ltm -{ - class TypeConverter - { - public: - TypeConverter(const std::string& id, const std::string& s): - identifier(id), - suffix(s) - {} - virtual ~TypeConverter() = default; - - virtual std::pair<std::vector<unsigned char>, std::string> convert(const aron::type::ObjectPtr& data) = 0; - virtual aron::type::ObjectPtr convert(const std::vector<unsigned char>& data, const std::string&) = 0; - - public: - const std::string identifier; - const std::string suffix; - bool enabled = false; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/json/JsonConverter.h b/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/json/JsonConverter.h deleted file mode 100644 index 1f95674b5398d910468b1335617efdb3591a9f7c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/json/JsonConverter.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -// Base Class -#include "../Converter.h" - -// Simox -#include <SimoxUtility/json.h> - -namespace armarx::armem::server::ltm::converter::type -{ - class JsonConverter : public TypeConverter - { - public: - JsonConverter() : - TypeConverter("dict", ".json") - { - enabled = true; // always true! - } - - std::pair<std::vector<unsigned char>, std::string> convert(const aron::type::ObjectPtr& data) final; - aron::type::ObjectPtr convert(const std::vector<unsigned char>& data, const std::string&) final; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/CoreSegmentBase.cpp similarity index 62% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.cpp rename to source/RobotAPI/libraries/armem/server/ltm/detail/CoreSegmentBase.cpp index cdeac54146741ac16c611098a57166b7316bb5e6..bb0860e4228ac731fb03e67f9b05befcab0c5059 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/CoreSegmentBase.cpp @@ -1,6 +1,6 @@ #include "CoreSegmentBase.h" -namespace armarx::armem::server::ltm +namespace armarx::armem::server::ltm::detail { } // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/server/ltm/detail/CoreSegmentBase.h similarity index 75% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.h rename to source/RobotAPI/libraries/armem/server/ltm/detail/CoreSegmentBase.h index ebe21f4c1c35a03ab8a0b5219d26e57417c4533a..e5a425016e06ff19c46ef7d768cf4e18b8dc8a02 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/CoreSegmentBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/CoreSegmentBase.h @@ -3,15 +3,14 @@ #include <functional> // BaseClass -#include "MemoryItem.h" - -#include "ProviderSegmentBase.h" - #include <RobotAPI/libraries/armem/core/MemoryID.h> -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -namespace armarx::armem::server::ltm +#include "MemoryItem.h" +#include "ProviderSegmentBase.h" + +namespace armarx::armem::server::ltm::detail { /// @brief Interface functions for the longterm memory classes template <class _ProviderSegmentT> @@ -21,7 +20,6 @@ namespace armarx::armem::server::ltm struct Statistics { long recordedProviderSegments = 0; - }; public: @@ -31,35 +29,35 @@ namespace armarx::armem::server::ltm /// return the full sub-ltm as a wm::CoreSegment with only references /// the ltm may be huge, use with caution - void loadAllReferences(armem::wm::CoreSegment& coreSeg) + void + loadAllReferences(armem::wm::CoreSegment& coreSeg) { _loadAllReferences(coreSeg); } /// convert the references of the input into a wm::Memory - void resolve(armem::wm::CoreSegment& coreSeg) + void + resolve(armem::wm::CoreSegment& coreSeg) { _resolve(coreSeg); } /// encode the content of a wm::Memory and store - void store(const armem::wm::CoreSegment& coreSeg) + void + store(const armem::wm::CoreSegment& coreSeg) { _store(coreSeg); } - /// store the type of the core segment - void storeType(const armem::wm::CoreSegment& coreSeg) - { - _storeType(coreSeg); - } - /// statistics - void resetStatistics() + void + resetStatistics() { statistics.recordedProviderSegments = 0; } - Statistics getStatistics() const + + Statistics + getStatistics() const { return statistics; } @@ -67,17 +65,22 @@ namespace armarx::armem::server::ltm /// iterate over all provider segments of this ltm virtual bool forEachProviderSegment(std::function<void(ProviderSegmentT&)> func) const = 0; + /// check if provider segment exists + virtual bool hasProviderSegment(const std::string&) const = 0; + /// find provider segment virtual std::shared_ptr<ProviderSegmentT> findProviderSegment(const std::string&) const = 0; /// get aron type - aron::type::ObjectPtr aronType() const + aron::type::ObjectPtr + aronType() const { return nullptr; } /// get level name - static std::string getLevelName() + static std::string + getLevelName() { return "LT-CoreSegment"; } @@ -86,11 +89,10 @@ namespace armarx::armem::server::ltm virtual void _loadAllReferences(armem::wm::CoreSegment&) = 0; virtual void _resolve(armem::wm::CoreSegment&) = 0; virtual void _store(const armem::wm::CoreSegment&) = 0; - virtual void _storeType(const armem::wm::CoreSegment&) = 0; protected: mutable std::recursive_mutex ltm_mutex; Statistics statistics; }; -} // namespace armarx::armem::server::ltm +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityBase.cpp similarity index 83% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.cpp rename to source/RobotAPI/libraries/armem/server/ltm/detail/EntityBase.cpp index a0f93fc4711a3dec9e1a2be658ab749134aa0013..8b2d05c28d61ede50f8bbe9643d4fc3d05c56be1 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityBase.cpp @@ -5,6 +5,6 @@ #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> -namespace armarx::armem::server::ltm +namespace armarx::armem::server::ltm::detail { } // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.h b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityBase.h similarity index 55% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.h rename to source/RobotAPI/libraries/armem/server/ltm/detail/EntityBase.h index 15ebde328ec72b9f189f542087fd7753c2a3faf0..ab61c63e0b82cfa6fba6cbb16d76331ff0027d73 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntityBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityBase.h @@ -3,15 +3,14 @@ #include <functional> // BaseClass -#include "MemoryItem.h" - -#include "EntitySnapshotBase.h" - #include <RobotAPI/libraries/armem/core/MemoryID.h> -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -namespace armarx::armem::server::ltm +#include "EntitySnapshotBase.h" +#include "MemoryItem.h" + +namespace armarx::armem::server::ltm::detail { /// @brief Interface functions for the longterm memory classes template <class _EntitySnapshotT> @@ -21,7 +20,6 @@ namespace armarx::armem::server::ltm struct Statistics { long recordedSnapshots = 0; - }; public: @@ -31,49 +29,71 @@ namespace armarx::armem::server::ltm /// return the full sub-ltm as a wm::Entity with only references /// the ltm may be huge, use with caution - void loadAllReferences(armem::wm::Entity& e) + void + loadAllReferences(armem::wm::Entity& e) { _loadAllReferences(e); } /// convert the references of the input into a wm::Memory - void resolve(armem::wm::Entity& e) + void + resolve(armem::wm::Entity& e) { _resolve(e); } /// encode the content of a wm::Memory and store - void store(const armem::wm::Entity& e) + void + store(const armem::wm::Entity& e) { _store(e); } /// statistics - void resetStatistics() + void + resetStatistics() { statistics.recordedSnapshots = 0; } - Statistics getStatistics() const + + Statistics + getStatistics() const { return statistics; } /// iterate over all entity snapshots of this ltm virtual bool forEachSnapshot(std::function<void(EntitySnapshotT&)> func) const = 0; - virtual bool forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshotT&)> func) const = 0; - virtual bool forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshotT&)> func) const = 0; - virtual bool forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshotT&)> func) const = 0; - virtual bool forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool + forEachSnapshotInIndexRange(long first, + long last, + std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool + forEachSnapshotInTimeRange(const Time& min, + const Time& max, + std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool + forEachSnapshotBeforeOrAt(const Time& time, + std::function<void(EntitySnapshotT&)> func) const = 0; + virtual bool forEachSnapshotBefore(const Time& time, + std::function<void(EntitySnapshotT&)> func) const = 0; + + /// check if snapshot segment exists + virtual bool hasSnapshot(const Time&) const = 0; /// find entity snapshot segment virtual std::shared_ptr<EntitySnapshotT> findSnapshot(const Time&) const = 0; virtual std::shared_ptr<EntitySnapshotT> findLatestSnapshot() const = 0; - virtual std::shared_ptr<EntitySnapshotT> findLatestSnapshotBefore(const Time& time) const = 0; - virtual std::shared_ptr<EntitySnapshotT> findLatestSnapshotBeforeOrAt(const Time& time) const = 0; + virtual std::shared_ptr<EntitySnapshotT> + findLatestSnapshotBefore(const Time& time) const = 0; + virtual std::shared_ptr<EntitySnapshotT> + findLatestSnapshotBeforeOrAt(const Time& time) const = 0; virtual std::shared_ptr<EntitySnapshotT> findFirstSnapshotAfter(const Time& time) const = 0; - virtual std::shared_ptr<EntitySnapshotT> findFirstSnapshotAfterOrAt(const Time& time) const = 0; + virtual std::shared_ptr<EntitySnapshotT> + findFirstSnapshotAfterOrAt(const Time& time) const = 0; - static std::string getLevelName() + static std::string + getLevelName() { return "LT-Entity"; } @@ -88,4 +108,4 @@ namespace armarx::armem::server::ltm Statistics statistics; }; -} // namespace armarx::armem::server::ltm +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/EntityInstanceBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityInstanceBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b3c23fddbf72565312d291da8e3c179b2293d57 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityInstanceBase.cpp @@ -0,0 +1,15 @@ +#include "EntityInstanceBase.h" + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> + +namespace armarx::armem::server::ltm::detail +{ + std::string + EntityInstanceBase::getLevelName() + { + return "LT-EntityInstance"; + } +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/EntityInstanceBase.h b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityInstanceBase.h new file mode 100644 index 0000000000000000000000000000000000000000..4568f1827e924b0be22296fec71bce303096a069 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/EntityInstanceBase.h @@ -0,0 +1,75 @@ +#pragma once + +#include <functional> + +// BaseClass +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> + +#include "MemoryItem.h" + +namespace armarx::armem::server::ltm::detail +{ + /// @brief Interface functions for the longterm memory classes + class EntityInstanceBase : public MemoryItem + { + public: + struct Statistics + { + long recordedData = 0; + long recordedMetaData = 0; + }; + + public: + using MemoryItem::MemoryItem; + + /// return the full sub-ltm as a wm::EntitySnapshot with only references + /// the ltm may be huge, use with caution + void + loadAllReferences(armem::wm::EntitySnapshot& e) const + { + _loadAllReferences(e); + } + + /// convert the references of the input into a wm::Memory + void + resolve(armem::wm::EntityInstance& e) const + { + _resolve(e); + } + + /// encode the content of a wm::Memory and store + nlohmann::json + store(const armem::wm::EntityInstance& e) + { + return _store(e); + } + + /// statistics + void + resetStatistics() + { + statistics.recordedData = 0; + statistics.recordedMetaData = 0; + } + + Statistics + getStatistics() const + { + return statistics; + } + + static std::string getLevelName(); + + protected: + virtual void _loadAllReferences(armem::wm::EntitySnapshot&) const = 0; + virtual void _resolve(armem::wm::EntityInstance&) const = 0; + virtual nlohmann::json _store(const armem::wm::EntityInstance&) = 0; + + protected: + mutable std::recursive_mutex ltm_mutex; + + Statistics statistics; + }; +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntitySnapshotBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/EntitySnapshotBase.cpp similarity index 51% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/EntitySnapshotBase.cpp rename to source/RobotAPI/libraries/armem/server/ltm/detail/EntitySnapshotBase.cpp index 1b053d008f1900e323628c5be5b2324be6d0eb22..5b64878d0371bbe47a28a92f71f3502156e9bb2c 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntitySnapshotBase.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/EntitySnapshotBase.cpp @@ -5,10 +5,6 @@ #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> -namespace armarx::armem::server::ltm +namespace armarx::armem::server::ltm::detail { - std::string EntitySnapshotBase::getLevelName() - { - return "LT-EntitySnapshot"; - } -} // namespace armarx::armem::server::ltm +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntitySnapshotBase.h b/source/RobotAPI/libraries/armem/server/ltm/detail/EntitySnapshotBase.h similarity index 60% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/EntitySnapshotBase.h rename to source/RobotAPI/libraries/armem/server/ltm/detail/EntitySnapshotBase.h index 411dd43cca301fda3c835572406ea175d231c8b5..cebbca9555f09e09da6b143056a024ac15b9d6a9 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/EntitySnapshotBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/EntitySnapshotBase.h @@ -3,58 +3,77 @@ #include <functional> // BaseClass -#include "MemoryItem.h" - #include <RobotAPI/libraries/armem/core/MemoryID.h> -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -namespace armarx::armem::server::ltm +#include "EntityBase.h" +#include "MemoryItem.h" + +namespace armarx::armem::server::ltm::detail { /// @brief Interface functions for the longterm memory classes + template <class InstanceT> class EntitySnapshotBase : public MemoryItem { public: struct Statistics { long recordedInstances = 0; - }; public: - using MemoryItem::MemoryItem; /// return the full sub-ltm as a wm::EntitySnapshot with only references /// the ltm may be huge, use with caution - void loadAllReferences(armem::wm::EntitySnapshot& e) const + void + loadAllReferences(armem::wm::EntitySnapshot& e) const { _loadAllReferences(e); } /// convert the references of the input into a wm::Memory - void resolve(armem::wm::EntitySnapshot& e) const + void + resolve(armem::wm::EntitySnapshot& e) const { _resolve(e); } /// encode the content of a wm::Memory and store - void store(const armem::wm::EntitySnapshot& e) + void + store(const armem::wm::EntitySnapshot& e) { _store(e); } /// statistics - void resetStatistics() + void + resetStatistics() { statistics.recordedInstances = 0; } - Statistics getStatistics() const + + Statistics + getStatistics() const { return statistics; } - static std::string getLevelName(); + static std::string + getLevelName() + { + return "LT-EntitySnapshot"; + } + + /// iterate over all Instance segments of this ltm + virtual bool forEachInstance(std::function<void(InstanceT&)> func) const = 0; + + /// check if Instance segment exists + virtual bool hasInstance(const int) const = 0; + + /// find Instance segment + virtual std::shared_ptr<InstanceT> findInstance(const int) const = 0; protected: virtual void _loadAllReferences(armem::wm::EntitySnapshot&) const = 0; @@ -66,4 +85,4 @@ namespace armarx::armem::server::ltm Statistics statistics; }; -} // namespace armarx::armem::server::ltm +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryBase.cpp similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.cpp rename to source/RobotAPI/libraries/armem/server/ltm/detail/MemoryBase.cpp diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.h b/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryBase.h similarity index 55% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.h rename to source/RobotAPI/libraries/armem/server/ltm/detail/MemoryBase.h index 1b32ee2c9fc10bdb476b36b7046f46fc8518e462..4ca25b8cb1944e345bf6c1f8c285b84c65ad648c 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/MemoryBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryBase.h @@ -9,17 +9,17 @@ #include "CoreSegmentBase.h" // ArmarX -#include <ArmarXCore/core/time/TimeUtil.h> +#include <ArmarXCore/core/Component.h> #include <ArmarXCore/core/logging/LoggingUtil.h> +#include <ArmarXCore/core/time.h> #include <RobotAPI/libraries/armem/core/MemoryID.h> -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -#include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> #include <RobotAPI/libraries/armem/core/operations.h> +#include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> - -namespace armarx::armem::server::ltm +namespace armarx::armem::server::ltm::detail { /// @brief Interface functions for the longterm memory classes template <class _CoreSegmentT> @@ -35,38 +35,69 @@ namespace armarx::armem::server::ltm public: using CoreSegmentT = _CoreSegmentT; - MemoryBase(const MemoryID& id) : - MemoryItem(id) + MemoryBase(const std::string& exportName, const MemoryID& id) : + MemoryItem(exportName, id), enabled(false) { } /// initialize config - virtual void init() + void + configure() { - enabled = enabled_on_startup; - ARMARX_INFO << VAROUT(configuration_on_startup); + bool en = p.enabled_on_startup; + ARMARX_INFO << VAROUT(p.configuration_on_startup); try { - const auto j = nlohmann::json::parse(configuration_on_startup); - this->configure(j); + const auto j = nlohmann::json::parse(p.configuration_on_startup); + + // Processors are shared. So we only need to configure the root + processors->configure(j); + + this->_configure(j); } - catch(...) + catch (...) { - ARMARX_WARNING << "Failed to parse `" << configuration_on_startup << "`"; - enabled = false; + ARMARX_WARNING << "Failed to parse `" << p.configuration_on_startup << "`"; + en = false; } + + if (en) + { + this->startRecording(); + } + } + + /// enable this LTM + void + enable() + { + ARMARX_INFO << "Enabling LTM " << id().str(); + enabled = true; + this->_enable(); + } + + /// disable this LTM + void + disable() + { + ARMARX_INFO << "Disabling LTM " << id().str(); + enabled = false; + this->_disable(); } /// return the full ltm as a wm::Memory with only references /// the ltm may be huge, use with caution - armem::wm::Memory loadAllReferences() + armem::wm::Memory + loadAllReferences() { armem::wm::Memory ret; loadAllReferences(ret); return ret; } - void loadAllReferences(armem::wm::Memory& memory) + + void + loadAllReferences(armem::wm::Memory& memory) { TIMING_START(LTM_Memory_LoadAll); _loadAllReferences(memory); @@ -75,14 +106,16 @@ namespace armarx::armem::server::ltm /// return the full ltm as a wm::Memory and resolves the references /// the ltm may be huge, use with caution - armem::wm::Memory loadAllAndResolve() + armem::wm::Memory + loadAllAndResolve() { armem::wm::Memory ret; loadAllAndResolve(ret); return ret; } - void loadAllAndResolve(armem::wm::Memory& memory) + void + loadAllAndResolve(armem::wm::Memory& memory) { TIMING_START(LTM_Memory_LoadAllAndResolve); _loadAllReferences(memory); @@ -91,7 +124,8 @@ namespace armarx::armem::server::ltm } /// convert the references of the input into a wm::Memory - void resolve(armem::wm::Memory& memory) + void + resolve(armem::wm::Memory& memory) { TIMING_START(LTM_Memory_Load); _resolve(memory); @@ -99,14 +133,16 @@ namespace armarx::armem::server::ltm } /// append a wm::Memory instance to the ltm - void store(const armem::wm::Memory& memory) + void + store(const armem::wm::Memory& memory) { TIMING_START(LTM_Memory_Append); for (auto& f : processors->memFilters) { - if (f->enabled && !f->accept(memory)) + if (!f->accept(memory)) { - ARMARX_INFO << deactivateSpam() << "Ignoring to put a Memory into the LTM because it got filtered."; + ARMARX_INFO << deactivateSpam() + << "Ignoring to put a Memory into the LTM because it got filtered."; return; } } @@ -115,7 +151,8 @@ namespace armarx::armem::server::ltm } /// append a wm::Memory instance to the ltm - void store(const armem::server::wm::Memory& serverMemory) + void + store(const armem::server::wm::Memory& serverMemory) { wm::Memory memory; memory.update(armem::toCommit(serverMemory)); @@ -125,74 +162,102 @@ namespace armarx::armem::server::ltm /// iterate over all core segments of this ltm virtual bool forEachCoreSegment(std::function<void(CoreSegmentT&)> func) const = 0; + /// check if core segment exists + virtual bool hasCoreSegment(const std::string&) const = 0; + /// find core segment - virtual std::shared_ptr<CoreSegmentT> findCoreSegment(const std::string&) const = 0; // TODO make unique!! + virtual std::unique_ptr<CoreSegmentT> findCoreSegment(const std::string&) const = 0; /// default parameters. Implementation should use the configuration to configure - virtual void createPropertyDefinitions(PropertyDefinitionsPtr& defs, const std::string& prefix) - { - defs->optional(enabled_on_startup, prefix + "enabled"); - defs->optional(configuration_on_startup, prefix + "configuration"); - //processors->createPropertyDefinitions(defs, prefix); - } - - /// configuration - virtual void configure(const nlohmann::json& config) + virtual void + createPropertyDefinitions(PropertyDefinitionsPtr& defs, const std::string& prefix) { - // Processors are shared. So we only need to configure the root - processors->configure(config); + defs->optional(p.enabled_on_startup, prefix + "enabled"); + defs->optional(p.configuration_on_startup, prefix + "configuration"); } /// enable/disable - void startRecording() + void + startRecording() { statistics.lastEnabled = armarx::core::time::DateTime::Now(); - enabled = true; + enable(); } - void stopRecording() + + void + stopRecording() { - enabled = false; + disable(); } - bool isRecording() const + + bool + isRecording() const { return enabled; } /// statistics - virtual void resetStatistics() + virtual void + resetStatistics() { // enabled stays the same statistics.lastEnabled = armarx::core::time::DateTime::Invalid(); statistics.recordedCoreSegments = 0; } - Statistics getStatistics() const + + Statistics + getStatistics() const { return statistics; } /// get level name - static std::string getLevelName() + static std::string + getLevelName() { return "LT-Memory"; } protected: + /// configuration + virtual void + _configure(const nlohmann::json&) + { + } + + virtual void + _enable() + { + } + + virtual void + _disable() + { + } + + virtual void + _setExportName(const std::string&) + { + } + virtual void _loadAllReferences(armem::wm::Memory& memory) = 0; virtual void _resolve(armem::wm::Memory& memory) = 0; virtual void _store(const armem::wm::Memory& memory) = 0; public: // stuff for scenario parameters - bool enabled_on_startup = false; - std::string configuration_on_startup = "{}"; + struct Properties + { + bool enabled_on_startup = false; + std::string configuration_on_startup = + "{\"SnapshotFrequencyFilter\": { \"WaitingTimeInMs\": 1000}, \"PngConverter\": {}}"; + } p; protected: mutable std::recursive_mutex ltm_mutex; - Statistics statistics; + mutable Statistics statistics; - private: std::atomic_bool enabled = false; - }; -} // namespace armarx::armem::server::ltm +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryItem.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99dfcfee345d5d2015baffa7ef389a0c6879b3f9 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryItem.cpp @@ -0,0 +1,53 @@ +#include "MemoryItem.h" + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> + +namespace armarx::armem::server::ltm::detail +{ + MemoryItem::MemoryItem(const std::string& exportName, const MemoryID& id) : + processors(std::make_shared<Processors>()), exportName(exportName), _id(id) + { + } + + MemoryItem::MemoryItem(const std::string& exportName, + const MemoryID& id, + const std::shared_ptr<Processors>& p) : + processors(p), exportName(exportName), _id(id) + { + } + + void + MemoryItem::setExportName(const std::string& id) + { + exportName = id; + _setExportName(id); + } + + void + MemoryItem::setMemoryID(const MemoryID& id) + { + _id = id; + _setMemoryID(id); + } + + MemoryID + MemoryItem::id() const + { + return _id; + } + + std::string + MemoryItem::name() const + { + return _id.getLeafItem(); + } + + void + MemoryItem::setMemoryName(const std::string& memoryName) + { + _id.memoryName = memoryName; + } +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryItem.h b/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryItem.h new file mode 100644 index 0000000000000000000000000000000000000000..bf212bb37f252afb3e848c8fe322d74a4b550b22 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/MemoryItem.h @@ -0,0 +1,60 @@ +#pragma once + +#include <map> +#include <mutex> +#include <optional> +#include <string> + +#include <RobotAPI/libraries/armem/server/ltm/processors/Processors.h> + +namespace armarx::armem::server::ltm::detail +{ + /// @brief Interface functions for the longterm memory classes + class MemoryItem + { + public: + MemoryItem(const std::string& exportName, const MemoryID&); // only used by memory + MemoryItem(const std::string& exportName, + const MemoryID&, + const std::shared_ptr<Processors>&); // used by all other segments + virtual ~MemoryItem() = default; + + void setExportName(const std::string& n); + void setMemoryID(const MemoryID&); + void setMemoryName(const std::string& memoryName); + + std::string + getExportName() const + { + return exportName; + } + + MemoryID + getMemoryID() const + { + return id(); + } + + // aliases + MemoryID id() const; + std::string name() const; + + protected: + virtual void + _setExportName(const std::string&) + { + } + + virtual void + _setMemoryID(const MemoryID&) + { + } + + protected: + std::shared_ptr<Processors> processors; + + private: + std::string exportName = "MemoryExport"; + MemoryID _id; + }; +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/ProviderSegmentBase.cpp similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.cpp rename to source/RobotAPI/libraries/armem/server/ltm/detail/ProviderSegmentBase.cpp diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/server/ltm/detail/ProviderSegmentBase.h similarity index 73% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.h rename to source/RobotAPI/libraries/armem/server/ltm/detail/ProviderSegmentBase.h index c241d7889621f534991733baf82973e28428a641..65021cdbb9a7487dc20f2ea930cb7a37d109e8fc 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/ProviderSegmentBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/ProviderSegmentBase.h @@ -2,16 +2,14 @@ #include <functional> -// BaseClass -#include "MemoryItem.h" - -#include "EntityBase.h" - #include <RobotAPI/libraries/armem/core/MemoryID.h> -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -namespace armarx::armem::server::ltm +#include "EntityBase.h" +#include "MemoryItem.h" + +namespace armarx::armem::server::ltm::detail { /// @brief Interface functions for the longterm memory classes template <class _EntityT> @@ -21,7 +19,6 @@ namespace armarx::armem::server::ltm struct Statistics { long recordedEntities = 0; - }; public: @@ -31,35 +28,35 @@ namespace armarx::armem::server::ltm /// return the full sub-ltm as a wm::ProviderSegment with only references /// the ltm may be huge, use with caution - void loadAllReferences(armem::wm::ProviderSegment& provSeg) + void + loadAllReferences(armem::wm::ProviderSegment& provSeg) { _loadAllReferences(provSeg); } /// convert the references of the input into a wm::Memory - void resolve(armem::wm::ProviderSegment& provSeg) + void + resolve(armem::wm::ProviderSegment& provSeg) { _resolve(provSeg); } /// encode the content of a wm::Memory and store - void store(const armem::wm::ProviderSegment& provSeg) + void + store(const armem::wm::ProviderSegment& provSeg) { _store(provSeg); } - /// store the type of the segment - void storeType(const armem::wm::ProviderSegment& coreSeg) - { - _storeType(coreSeg); - } - /// statistics - void resetStatistics() + void + resetStatistics() { statistics.recordedEntities = 0; } - Statistics getStatistics() const + + Statistics + getStatistics() const { return statistics; } @@ -67,15 +64,20 @@ namespace armarx::armem::server::ltm /// iterate over all core segments of this ltm virtual bool forEachEntity(std::function<void(EntityT&)> func) const = 0; + /// check if entity segment exists + virtual bool hasEntity(const std::string&) const = 0; + /// find entity segment virtual std::shared_ptr<EntityT> findEntity(const std::string&) const = 0; - aron::type::ObjectPtr aronType() const + aron::type::ObjectPtr + aronType() const { return nullptr; } - static std::string getLevelName() + static std::string + getLevelName() { return "LT-ProviderSegment"; } @@ -84,11 +86,10 @@ namespace armarx::armem::server::ltm virtual void _loadAllReferences(armem::wm::ProviderSegment&) = 0; virtual void _resolve(armem::wm::ProviderSegment&) = 0; virtual void _store(const armem::wm::ProviderSegment&) = 0; - virtual void _storeType(const armem::wm::ProviderSegment&) = 0; protected: mutable std::recursive_mutex ltm_mutex; Statistics statistics; }; -} // namespace armarx::armem::server::ltm +} // namespace armarx::armem::server::ltm::detail diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/BufferedMemoryMixin.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/BufferedMemoryMixin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80982baf62c2bd7e20e0e7960deac373831c9614 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/BufferedMemoryMixin.cpp @@ -0,0 +1,7 @@ +#include "BufferedMemoryMixin.h" + +namespace armarx::armem::server::ltm::detail::mixin +{ + + +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/detail/BufferedMemoryBase.h b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/BufferedMemoryMixin.h similarity index 53% rename from source/RobotAPI/libraries/armem/server/ltm/base/detail/BufferedMemoryBase.h rename to source/RobotAPI/libraries/armem/server/ltm/detail/mixins/BufferedMemoryMixin.h index 1104da67e9c19488daa3cc4d508a4355095d1704..0bbf62f24ab3dd9427a9854bfadf8fe048c98bb1 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/detail/BufferedMemoryBase.h +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/BufferedMemoryMixin.h @@ -1,64 +1,84 @@ #pragma once -#include "MemoryBase.h" +#include <SimoxUtility/json.h> #include <ArmarXCore/core/services/tasks/PeriodicTask.h> -namespace armarx::armem::server::ltm +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> + +namespace armarx::armem::server::ltm::detail::mixin { template <class _CoreSegmentT> - class BufferedMemoryBase : public MemoryBase<_CoreSegmentT> + class BufferedMemoryMixin { - using Base = MemoryBase<_CoreSegmentT>; public: - BufferedMemoryBase(const MemoryID& id) : - Base(id), - buffer(std::make_shared<armem::wm::Memory>(id)), - to_store(std::make_shared<armem::wm::Memory>(id)) + BufferedMemoryMixin(const MemoryID& id) : + buffer(std::make_unique<armem::wm::Memory>(id)), + to_store(std::make_unique<armem::wm::Memory>(id)) { } - virtual ~BufferedMemoryBase() = default; + virtual ~BufferedMemoryMixin() = default; - void setMemoryID(const MemoryID& id) override + void + directlyStore(const armem::wm::Memory& memory) { - ARMARX_CHECK_NOT_EMPTY(id.memoryName) << " The full id was: " << id.str(); + std::lock_guard l(storeMutex); + + TIMING_START(LTM_Memory_DirectlyStore); + _directlyStore(memory); + TIMING_END_STREAM(LTM_Memory_DirectlyStore, ARMARX_DEBUG); + } - Base::setMemoryID(id.getMemoryID()); + protected: + void + setMixinMemoryID(const MemoryID& id) + { + ARMARX_CHECK_NOT_EMPTY(id.memoryName) << " The full id was: " << id.str(); buffer->id() = id.getMemoryID(); to_store->id() = id.getMemoryID(); } - armem::wm::Memory getBuffer() const + void + start() { - std::lock_guard l(bufferMutex); - return *buffer; + // create task if not already exists + if (!task) + { + int waitingTimeMs = 1000.f / storeFrequency; + task = new armarx::PeriodicTask<BufferedMemoryMixin>( + this, &BufferedMemoryMixin::storeBuffer, waitingTimeMs); + task->start(); + } } - void directlyStore(const armem::wm::Memory& memory) + void + stop() { - TIMING_START(LTM_Memory_DirectlyStore); - for (auto& f : this->processors->memFilters) + if (task) { - if (!f->accept(memory)) - { - ARMARX_WARNING << deactivateSpam() << "Ignoring to commit a Memory into the LTM because the full commit got filtered."; - return; - } + task->stop(); + task = nullptr; } - _directlyStore(memory); - TIMING_END_STREAM(LTM_Memory_DirectlyStore, ARMARX_DEBUG); } - void storeBuffer() + armem::wm::Memory + getBuffer() const + { + std::lock_guard l(bufferMutex); + return *buffer; + } + + void + storeBuffer() { std::lock_guard l(storeMutex); { std::lock_guard l(bufferMutex); - to_store = buffer; - buffer = std::make_shared<armem::wm::Memory>(this->id()); + to_store = std::move(buffer); + buffer = std::make_unique<armem::wm::Memory>(to_store->id()); } if (to_store->empty()) @@ -71,30 +91,22 @@ namespace armarx::armem::server::ltm } /// configuration - void configure(const nlohmann::json& json) override + void + configureMixin(const nlohmann::json& json) { - Base::configure(json); - if (json.find("BufferedMemoryBase.storeFrequency") != json.end()) + if (json.find("BufferedMemory.storeFrequency") != json.end()) { - storeFrequency = json.at("BufferedMemoryBase.storeFrequency"); + storeFrequency = json.at("BufferedMemory.storeFrequency"); } } - protected: virtual void _directlyStore(const armem::wm::Memory& memory) = 0; - void _store(const armem::wm::Memory& memory) override + void + addToBuffer(const armem::wm::Memory& memory) { std::lock_guard l(bufferMutex); buffer->append(memory); - - // create task if not already exists - if (!task) - { - int waitingTimeMs = 1000.f / storeFrequency; - task = new armarx::PeriodicTask<BufferedMemoryBase>(this, &BufferedMemoryBase::storeBuffer, waitingTimeMs); - task->start(); - } } protected: @@ -102,18 +114,18 @@ namespace armarx::armem::server::ltm /// The to-put-to-ltm buffer (contains data in plain text) /// This buffer may still be filtered (e.g. snapshot filters). /// This means that it is not guaranteed that all data in the buffer will be stored in the ltm - std::shared_ptr<armem::wm::Memory> buffer; - std::shared_ptr<armem::wm::Memory> to_store; - - /// The periodic'task to store the content of the buffer to the ltm - typename armarx::PeriodicTask<BufferedMemoryBase>::pointer_type task = nullptr; + std::unique_ptr<armem::wm::Memory> buffer; + std::unique_ptr<armem::wm::Memory> to_store; /// The frequency (Hz) to store data to the ltm float storeFrequency = 10; - /// a mutex to access the buffer object - mutable std::mutex bufferMutex; - mutable std::mutex storeMutex; + private: + /// The periodic'task to store the content of the buffer to the ltm + typename armarx::PeriodicTask<BufferedMemoryMixin>::pointer_type task = nullptr; + /// a mutex to access the buffer object + mutable std::recursive_mutex bufferMutex; + mutable std::recursive_mutex storeMutex; }; -} // namespace armarx::armem::server::ltm +} // namespace armarx::armem::server::ltm::detail::mixin diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/CachedMemoryMixin.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/CachedMemoryMixin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50083aa97e06f4da65d15fa0a417df476e41bb41 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/CachedMemoryMixin.cpp @@ -0,0 +1,6 @@ +#include "CachedMemoryMixin.h" + +namespace armarx::armem::server::ltm::detail::mixin +{ + +} // namespace armarx::armem::server::ltm::detail::mixin diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/CachedMemoryMixin.h b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/CachedMemoryMixin.h new file mode 100644 index 0000000000000000000000000000000000000000..250484f07c95132a1de7b579cf6aac8b580b0cd4 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/CachedMemoryMixin.h @@ -0,0 +1,98 @@ +#pragma once + +#include <SimoxUtility/json.h> + +#include <ArmarXCore/core/services/tasks/PeriodicTask.h> + +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> + +namespace armarx::armem::server::ltm::detail::mixin +{ + template <class _CoreSegmentT> + class CachedMemoryMixin + { + public: + CachedMemoryMixin(const MemoryID& id) : cache(std::make_unique<armem::wm::Memory>(id)) + { + } + + protected: + armem::wm::Memory + getCache() const + { + std::lock_guard l(this->cache_mutex); + return *cache; + } + + /// configuration + void + configureMixin(const nlohmann::json& json) + { + // TODO: Max cache size + } + + void + setMixinMemoryID(const MemoryID& id) + { + ARMARX_CHECK_NOT_EMPTY(id.memoryName) << " The full id was: " << id.str(); + + cache->id() = id.getMemoryID(); + } + + void + addToCache(const armem::wm::Memory& memory) + { + std::lock_guard l(cache_mutex); + cache->append(memory); + } + + bool + cacheHasCoreSegment(const std::string& n) const + { + std::lock_guard l(cache_mutex); + return cache->hasCoreSegment(n); + } + + bool + cacheHasCoreSegment(const MemoryID& n) const + { + std::lock_guard l(cache_mutex); + return cache->hasCoreSegment(n); + } + + bool + cacheHasProviderSegment(const MemoryID& n) const + { + std::lock_guard l(cache_mutex); + return cache->hasProviderSegment(n); + } + + bool + cacheHasEntity(const MemoryID& n) const + { + std::lock_guard l(cache_mutex); + return cache->hasEntity(n); + } + + bool + cacheHasEntitySnapshot(const MemoryID& n) const + { + std::lock_guard l(cache_mutex); + return cache->hasSnapshot(n); + } + + bool + cacheHasEntityInstance(const MemoryID& n) const + { + std::lock_guard l(cache_mutex); + return cache->hasInstance(n); + } + + + protected: + std::unique_ptr<armem::wm::Memory> cache; + + private: + mutable std::recursive_mutex cache_mutex; + }; +} // namespace armarx::armem::server::ltm::detail::mixin diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/DiskStorageMixin.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/DiskStorageMixin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ceaf84eb19deaa0db3efdd5595179ed8d4bcbd4 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/DiskStorageMixin.cpp @@ -0,0 +1,137 @@ +// Header +#include "DiskStorageMixin.h" + +// STD/STL +#include <algorithm> +#include <fstream> +#include <iostream> + +// Simox +#include <SimoxUtility/algorithm/string.h> + +// ArmarX +#include <ArmarXCore/core/exceptions/LocalException.h> +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + +namespace armarx::armem::server::ltm::detail::mixin +{ + DiskMemoryItemMixin::DiskMemoryItemMixin(const Path& memoryParentPath, + const std::string& exportName, + const armem::MemoryID& id) : + memoryBasePath(memoryParentPath), exportName(exportName), _id(id) + { + } + + void + DiskMemoryItemMixin::setMemoryBasePath(const Path& n) + { + memoryBasePath = n; + } + + void + DiskMemoryItemMixin::setMixinExportName(const std::string& n) + { + exportName = n; + } + + void + DiskMemoryItemMixin::setMixinMemoryID(const MemoryID& n) + { + ARMARX_CHECK_NOT_EMPTY(_id.memoryName) << " The full id was: " << _id.str(); + + _id = n; + } + + void + DiskMemoryItemMixin::configureMixin(const nlohmann::json& json) + { + if (json.find("DiskMemory.memoryParentPath") != json.end()) + { + memoryBasePath = Path(json.at("DiskMemory.memoryParentPath")); + } + } + + Path + DiskMemoryItemMixin::getMemoryBasePath() const + { + return memoryBasePath; + } + + Path + DiskMemoryItemMixin::getFullPath() const + { + auto p = getMemoryBasePath() / exportName; + return util::fs::toPath(p, _id); + } + + bool + DiskMemoryItemMixin::memoryBasePathExists() const + { + return util::fs::directoryExists(getMemoryBasePath()); + } + + bool + DiskMemoryItemMixin::fullPathExists() const + { + auto p = getFullPath(); + return util::fs::directoryExists(p); + } + + bool + DiskMemoryItemMixin::fileExists(const std::string& filename) const + { + auto p = getFullPath() / filename; + return util::fs::fileExists(p); + } + + void + DiskMemoryItemMixin::ensureMemoryBasePathExists(bool createIfNotExistent) const + { + util::fs::ensureDirectoryExists(getMemoryBasePath(), createIfNotExistent); + } + + void + DiskMemoryItemMixin::ensureFullPathExists(bool createIfNotExistent) const + { + auto p = getFullPath(); + util::fs::ensureDirectoryExists(p, createIfNotExistent); + } + + void + DiskMemoryItemMixin::ensureFileExists(const std::string& filename, + bool createIfNotExistent) const + { + auto p = getFullPath() / filename; + util::fs::ensureFileExists(p, createIfNotExistent); + } + + void + DiskMemoryItemMixin::writeDataToFile(const std::string& filename, + const std::vector<unsigned char>& data) const + { + auto p = getFullPath() / filename; + util::fs::writeDataToFile(p, data); + } + + std::vector<unsigned char> + DiskMemoryItemMixin::readDataFromFile(const std::string& filename) const + { + auto p = getFullPath() / filename; + return util::fs::readDataFromFile(p); + } + + std::vector<Path> + DiskMemoryItemMixin::getAllDirectories() const + { + auto p = getFullPath(); + return util::fs::getAllDirectories(p); + } + + std::vector<Path> + DiskMemoryItemMixin::getAllFiles() const + { + auto p = getFullPath(); + return util::fs::getAllFiles(p); + } +} // namespace armarx::armem::server::ltm::detail::mixin diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/DiskStorageMixin.h b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/DiskStorageMixin.h new file mode 100644 index 0000000000000000000000000000000000000000..b9550d4117a0c06675b3788e3c0065c040677fd3 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/DiskStorageMixin.h @@ -0,0 +1,73 @@ +#pragma once + +#include <filesystem> +#include <map> +#include <string> + +#include <SimoxUtility/json.h> + +#include <ArmarXCore/core/services/tasks/PeriodicTask.h> + +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> + +#include "util/filesystem.h" + +namespace armarx::armem::server::ltm::detail::mixin +{ + using Path = std::filesystem::path; + + class DiskMemoryItemMixin + { + public: + DiskMemoryItemMixin() = default; + DiskMemoryItemMixin(const Path& memoryParentPath, + const std::string& exportName, + const armem::MemoryID& id); + virtual ~DiskMemoryItemMixin() = default; + + Path getMemoryBasePath() const; + Path getFullPath() const; + + // Filesystem interaction + bool memoryBasePathExists() const; + bool fullPathExists() const; + bool fileExists(const std::string& filename) const; + + void ensureMemoryBasePathExists(bool createIfNotExistent = false) const; + void ensureFullPathExists(bool createIfNotExistent = false) const; + void ensureFileExists(const std::string& filename, bool createIfNotExistent = false) const; + + void writeDataToFile(const std::string& filename, + const std::vector<unsigned char>& data) const; + + std::vector<unsigned char> readDataFromFile(const std::string& filename) const; + std::vector<Path> getAllDirectories() const; + std::vector<Path> getAllFiles() const; + + + protected: + // setter + void setMixinMemoryID(const MemoryID& n); + void setMemoryBasePath(const std::filesystem::path& n); + void setMixinExportName(const std::string& n); + + /// configuration + void configureMixin(const nlohmann::json& json); + + public: + static const int DEPTH_TO_DATA_FILES = + 7; // from memory folder = 1 (cseg) + 1 (pseg) + 1 (ent) + 3 (snap) + 1 (inst) + + protected: + static const constexpr char* TYPE_FILENAME = "type.aron"; + static const constexpr char* DATA_FILENAME = "data.aron"; + static const constexpr char* METADATA_FILENAME = "metadata.aron"; + + static const constexpr char* MEMORY_EXPORT_SUFFIX = "_"; + + private: + std::filesystem::path memoryBasePath; + std::string exportName; + armem::MemoryID _id; + }; +} // namespace armarx::armem::server::ltm::detail::mixin diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/MongoDBStorageMixin.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/MongoDBStorageMixin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd29022893ab55f818a9e12c93f1fe37b515caf2 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/MongoDBStorageMixin.cpp @@ -0,0 +1,459 @@ +#include "MongoDBStorageMixin.h" + +#include <SimoxUtility/algorithm/string.h> + +#include <ArmarXCore/core/exceptions/LocalException.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/logging/Logging.h> + +#include "util/filesystem.h" + +namespace armarx::armem::server::ltm::detail::mixin +{ + std::unique_ptr<mongocxx::instance> MongoDBStorageMixin::MongoCXXInstance = nullptr; + std::atomic_bool MongoDBStorageMixin::MongoCXXInitialized = false; + std::recursive_mutex MongoDBStorageMixin::MongoCXXConnectionPoolMutex; + std::map<std::string, std::unique_ptr<mongocxx::pool>> + MongoDBStorageMixin::MongoCXXConnectionPool = {}; + + void + MongoDBSettings::initializeFromArmarXConfig() + { + std::filesystem::path armarx_config_home = std::string(getenv("ARMARX_USER_CONFIG_DIR")); + if (!util::fs::directoryExists(armarx_config_home)) + { + ARMARX_WARNING << ("Could not find an ArmarX Config folder. Tried: '" + + armarx_config_home.string() + + "' (from ARMARX_USER_CONFIG_DIR). If not set via scenario params " + "this means that LTM is disabled."); + return; + } + + std::ifstream cFile(armarx_config_home / "default.cfg"); + if (cFile.is_open()) + { + std::string line; + while (getline(cFile, line)) + { + line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end()); + if (line.empty() || line[0] == '#') + { + continue; + } + auto delimiterPos = line.find("="); + const auto name = simox::alg::to_lower(line.substr(0, delimiterPos)); + const auto value = line.substr(delimiterPos + 1); + if (host.empty() && name == "armarx.mongohost") + { + host = value; + } + if (port == 0 && name == "armarx.mongoport") + { + port = (unsigned int)std::stoi(value); + } + if (user.empty() && name == "armarx.mongouser") + { + user = value; + } + if (password.empty() && name == "armarx.mongopassword") + { + password = value; + } + } + } + } + + bool + MongoDBSettings::isSet() const + { + // we always need a host and a port + return !host.empty() and port != 0; + } + + std::string + MongoDBSettings::baseUri() const + { + std::stringstream ss; + ss << "mongodb://"; + + if (!user.empty()) + { + ss << user; + if (!password.empty()) + { + ss << ":" << password; + } + ss << "@"; + } + ss << host; + return ss.str(); + } + + std::string + MongoDBSettings::key() const + { + // TODO: What happens if a connection exists and you would like to open another one with a different user (e.g. that sees different things)? + return "mongodb://" + host + ":" + std::to_string(port); + } + + std::string + MongoDBSettings::uri() const + { + return baseUri() + ":" + std::to_string(port) + + "/?minPoolSize=" + std::to_string(minPoolSize) + + "&maxPoolSize=" + std::to_string(maxPoolSize); + } + + std::string + MongoDBSettings::toString() const + { + return uri(); + } + + MongoDBStorageMixin::MongoDBStorageMixin(const MongoDBSettings& settings, + const std::string& en, + const armem::MemoryID& id) : + settings(settings), exportName(en), _id(id) + { + } + + void + MongoDBStorageMixin::setHost(const std::string& n) + { + settings.host = n; + } + + void + MongoDBStorageMixin::setPort(const unsigned int n) + { + settings.port = n; + } + + void + MongoDBStorageMixin::setUser(const std::string& n) + { + settings.user = n; + } + + void + MongoDBStorageMixin::setPassword(const std::string& n) + { + settings.password = n; + } + + void + MongoDBStorageMixin::connect() const + { + std::lock_guard l(MongoCXXConnectionPoolMutex); + if (!MongoCXXInitialized.exchange(true)) + { + ARMARX_IMPORTANT << "INITIALIZE MONGODB"; + MongoCXXInstance = + std::make_unique<mongocxx::instance>(); // This should be done only once. + } + + const auto key = settings.key(); + const auto uri = settings.uri(); + auto it = MongoCXXConnectionPool.find(key); + if (it == MongoCXXConnectionPool.end()) + { + ARMARX_INFO << "Establishing new connection to: " << uri << " from id: " << _id.str(); + mongocxx::uri u(uri); + auto pool = std::make_unique<mongocxx::pool>(u); + MongoCXXConnectionPool.emplace(settings.key(), std::move(pool)); + } + } + + mongocxx::pool* + MongoDBStorageMixin::getPool(bool tryToConnect) const + { + std::lock_guard l(MongoCXXConnectionPoolMutex); + const auto key = settings.key(); + auto it = MongoCXXConnectionPool.find(key); + if (it == MongoCXXConnectionPool.end()) + { + if (tryToConnect) + { + // try to establish a connection and try again + connect(); + return getPool(false); + } + return nullptr; + } + else + { + return it->second.get(); + } + } + + mongocxx::pool* + MongoDBStorageMixin::ensurePool() const + { + std::lock_guard l(MongoCXXConnectionPoolMutex); + auto pool = getPool(); + if (pool) + { + return pool; + } + else + { + throw armarx::LocalException("Pool could not be ensured..."); + } + } + + void + MongoDBStorageMixin::start() + { + // ensure a connection is made if not done already + connect(); + } + + void + MongoDBStorageMixin::stop() + { + } + + bool + MongoDBStorageMixin::connected() const + { + std::lock_guard l(MongoCXXConnectionPoolMutex); + + try + { + auto client = ensurePool()->acquire(); + auto admin = client->database("admin"); + auto result = admin.run_command(bsoncxx::builder::basic::make_document( + bsoncxx::builder::basic::kvp("isMaster", 1))); + return true; + } + catch (const std::exception& xcp) + { + return false; + } + return false; // should never happen + } + + std::string + MongoDBStorageMixin::getDocumentName() const + { + return util::mongodb::toDocumentID(_id); + } + + std::string + MongoDBStorageMixin::getCollectionName() const + { + return util::mongodb::toCollectionName(_id); + } + + std::string + MongoDBStorageMixin::getPreviousCollectionName() const + { + ARMARX_CHECK(!_id.memoryName.empty() and !_id.coreSegmentName.empty()); + return util::mongodb::toCollectionName(_id.removeLeafItem()); + } + + std::string + MongoDBStorageMixin::getDatabaseName() const + { + return exportName; + } + + std::optional<mongocxx::database> + MongoDBStorageMixin::databaseExists() const + { + auto client = this->ensurePool()->acquire(); + return util::mongodb::databaseExists(*client, getDatabaseName()); + } + + std::optional<mongocxx::collection> + MongoDBStorageMixin::collectionExists() const + { + auto db = databaseExists(); + if (!db) + { + return std::nullopt; + } + + return util::mongodb::collectionExists(*db, getCollectionName()); + } + + std::optional<mongocxx::collection> + MongoDBStorageMixin::previousCollectionExists() const + { + auto db = databaseExists(); + if (!db) + { + return std::nullopt; + } + + return util::mongodb::collectionExists(*db, getPreviousCollectionName()); + } + + std::optional<nlohmann::json> + MongoDBStorageMixin::documentExists() const + { + return documentExists(getDocumentName()); + } + + std::optional<nlohmann::json> + MongoDBStorageMixin::documentExists(const std::string& id) const + { + auto coll = collectionExists(); + if (!coll) + { + return std::nullopt; + } + + nlohmann::json query; + query[ID] = getDocumentName(); + return util::mongodb::documentExists(*coll, query); + } + + mongocxx::database + MongoDBStorageMixin::ensureDatabaseExists(bool createIfNotExistent) + { + auto client = this->ensurePool()->acquire(); + return util::mongodb::ensureDatabaseExists(*client, getDatabaseName(), createIfNotExistent); + } + + mongocxx::collection + MongoDBStorageMixin::ensureCollectionExists(bool createIfNotExistent) + { + auto db = ensureDatabaseExists(createIfNotExistent); + return util::mongodb::ensureCollectionExists(db, getCollectionName(), createIfNotExistent); + } + + mongocxx::collection + MongoDBStorageMixin::ensurePreviousCollectionExists(bool createIfNotExistent) + { + auto db = ensureDatabaseExists(createIfNotExistent); + return util::mongodb::ensureCollectionExists( + db, getPreviousCollectionName(), createIfNotExistent); + } + + nlohmann::json + MongoDBStorageMixin::ensureDocumentExists(bool createIfNotExistent) + { + return ensureDocumentExists(getDocumentName(), createIfNotExistent); + } + + nlohmann::json + MongoDBStorageMixin::ensureDocumentExists(const std::string& id, bool createIfNotExistent) + { + auto coll = ensureCollectionExists(createIfNotExistent); + + nlohmann::json query; + query[ID] = getDocumentName(); + return util::mongodb::ensureDocumentExists(coll, query, createIfNotExistent); + } + + void + MongoDBStorageMixin::writeDataToDocument(const std::string& id, const nlohmann::json& data) + { + auto coll = ensureCollectionExists(true); + + nlohmann::json query; + query[ID] = getDocumentName(); + + nlohmann::json update; + update[DATA] = data; + util::mongodb::writeDataToDocument(coll, query, update); + } + + void + MongoDBStorageMixin::writeForeignKeyToPreviousDocument() + { + auto coll = ensurePreviousCollectionExists(true); + + nlohmann::json query; + query[ID] = _id.str(); + + nlohmann::json update; + update[FOREIGN_KEY] = getCollectionName(); + util::mongodb::writeDataToDocument(coll, query, update); + } + + void + MongoDBStorageMixin::writeForeignKeyToPreviousDocument(const nlohmann::json& type) + { + auto coll = ensurePreviousCollectionExists(true); + + nlohmann::json query; + query[ID] = _id.str(); + + nlohmann::json update; + update[FOREIGN_KEY] = getCollectionName(); + update[TYPE] = type; + + util::mongodb::writeDataToDocument(coll, query, update); + } + + nlohmann::json + MongoDBStorageMixin::readDataFromDocument(const std::string& id) const + { + auto coll = collectionExists(); + if (!coll) + { + // What to do here? + return {}; + } + + if (!documentExists()) + { + // What to do here? + return {}; + } + + auto query = + nlohmann::json::parse(std::string("{\"") + ID + "\": " + getDocumentName() + "}"); + return util::mongodb::readDataFromDocument(*coll, query); + } + + void + MongoDBStorageMixin::writeDataToDocument(const nlohmann::json& data) + { + writeDataToDocument(getDocumentName(), data); + } + + nlohmann::json + MongoDBStorageMixin::readDataFromDocument() const + { + return readDataFromDocument(getDocumentName()); + } + + std::vector<nlohmann::json> + MongoDBStorageMixin::getAllDocuments() const + { + auto coll = collectionExists(); + if (!coll) + { + return {}; + } + return util::mongodb::getAllDocuments(*coll); + } + + MongoDBSettings + MongoDBStorageMixin::getSettings() const + { + return settings; + } + + void + MongoDBStorageMixin::setMixinMemoryID(const MemoryID& n) + { + ARMARX_CHECK_NOT_EMPTY(_id.memoryName) << " The full id was: " << _id.str(); + + _id = n; + } + + void + MongoDBStorageMixin::setMixinExportName(const std::string& n) + { + exportName = n; + } + + void + MongoDBStorageMixin::configureMixin(const nlohmann::json& json) + { + } +} // namespace armarx::armem::server::ltm::detail::mixin diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/MongoDBStorageMixin.h b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/MongoDBStorageMixin.h new file mode 100644 index 0000000000000000000000000000000000000000..ff605b45193947abf4f4aa53a2ed28f941dccc24 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/MongoDBStorageMixin.h @@ -0,0 +1,125 @@ +#pragma once + +#include <atomic> +#include <fstream> +#include <map> +#include <memory> +#include <mutex> +#include <sstream> +#include <string> + +#include "util/mongodb.h" + +namespace armarx::armem::server::ltm::detail::mixin +{ + class MongoDBSettings + { + public: + std::string host = ""; + unsigned int port = 0; + std::string user = ""; + std::string password = ""; + int minPoolSize = 5; + int maxPoolSize = 100; + + public: + MongoDBSettings() + { + initializeFromArmarXConfig(); + }; + + /// Fills missing fields from armarx config file + void initializeFromArmarXConfig(); + + bool isSet() const; + + std::string baseUri() const; + + std::string key() const; + + std::string uri() const; + + std::string toString() const; + }; + + class MongoDBStorageMixin + { + public: + MongoDBStorageMixin() = default; + MongoDBStorageMixin(const MongoDBSettings& settings, + const std::string& exportName, + const armem::MemoryID& id); + + MongoDBSettings getSettings() const; + + std::string getDocumentName() const; + std::string getCollectionName() const; + std::string getPreviousCollectionName() const; + std::string getDatabaseName() const; + + std::optional<mongocxx::database> databaseExists() const; + std::optional<mongocxx::collection> collectionExists() const; + std::optional<mongocxx::collection> previousCollectionExists() const; + std::optional<nlohmann::json> documentExists() const; + std::optional<nlohmann::json> documentExists(const std::string& id) const; + + mongocxx::database ensureDatabaseExists(bool createIfNotExistent = false); + mongocxx::collection ensureCollectionExists(bool createIfNotExistent = false); + mongocxx::collection ensurePreviousCollectionExists(bool createIfNotExistent = false); + nlohmann::json ensureDocumentExists(bool createIfNotExistent = false); + nlohmann::json ensureDocumentExists(const std::string& id, + bool createIfNotExistent = false); + + void writeForeignKeyToPreviousDocument(); + void writeForeignKeyToPreviousDocument(const nlohmann::json& type); + + void writeDataToDocument(const nlohmann::json& data); + nlohmann::json readDataFromDocument() const; + + void writeDataToDocument(const std::string& id, const nlohmann::json& data); + nlohmann::json readDataFromDocument(const std::string& id) const; + + std::vector<nlohmann::json> getAllDocuments() const; + + protected: + void connect() const; + bool connected() const; + + /// setter + void setMixinMemoryID(const armem::MemoryID&); + void setMixinExportName(const std::string& n); + void setHost(const std::string&); + void setPort(const unsigned int); + void setUser(const std::string&); + void setPassword(const std::string&); + + /// start + void start(); + void stop(); + + /// configuration + void configureMixin(const nlohmann::json& json); + + private: + mongocxx::pool* getPool(bool tryToConnect = true) const; + mongocxx::pool* ensurePool() const; + + protected: + static const constexpr char* ID = "_id"; + static const constexpr char* FOREIGN_KEY = "_foreign_key"; + static const constexpr char* TYPE = "_type"; + static const constexpr char* DATA = "_data"; + static const constexpr char* METADATA = "_metadata"; + + private: + MongoDBSettings settings; + std::string exportName; + armem::MemoryID _id; + + static std::unique_ptr<mongocxx::instance> MongoCXXInstance; + static std::atomic_bool MongoCXXInitialized; + static std::recursive_mutex MongoCXXConnectionPoolMutex; + static std::map<std::string, std::unique_ptr<mongocxx::pool>> MongoCXXConnectionPool; + }; + +} // namespace armarx::armem::server::ltm::detail::mixin diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/filesystem.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/filesystem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b1f29b70126a7efdd303690e3cc111ba668a5ff --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/filesystem.cpp @@ -0,0 +1,226 @@ +#include "filesystem.h" + +#include <fstream> +#include <iostream> + +#include <SimoxUtility/algorithm/string.h> + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/core/error.h> + +namespace armarx::armem::server::ltm ::util::fs +{ + + namespace detail + { + std::string + escapeName(const std::string& segmentName) + { + std::string ret = segmentName; + //simox::alg::replace_all(ret, Prefix, PrefixEscaped); + for (const auto& [s, r] : EscapeTable) + { + ret = simox::alg::replace_all(ret, s, r); + } + return ret; + } + + std::string + unescapeName(const std::string& escapedName) + { + std::string ret = escapedName; + for ( + const auto& [s, r] : + EscapeTable) // Here we assume that noone uses the replaced char usually in the segment name... TODO + { + ret = simox::alg::replace_all(ret, r, s); + } + return ret; + } + + std::string + toDayString(const Time& t) + { + return t.toDateString(); + } + + std::string + toSecondsString(const Time& t) + { + return std::to_string(t.toSecondsSinceEpoch()); + } + + bool + isNumberString(const std::string& s) + { + for (char const& ch : s) + { + if (std::isdigit(ch) == 0) + { + return false; + } + } + return true; + } + + bool + isDateString(const std::string& s) + { + auto split = simox::alg::split(s, "-"); + if (split.size() != 3) + { + return false; + } + + return isNumberString(split[0]) && isNumberString(split[1]) && isNumberString(split[2]); + } + } // namespace detail + + std::filesystem::path + toPath(const std::filesystem::path& base, const armem::MemoryID& id) + { + ARMARX_CHECK(id.isWellDefined()); + + std::filesystem::path p = base; + if (id.hasMemoryName()) + { + p /= detail::escapeName(id.memoryName); + } + if (id.hasCoreSegmentName()) + { + p /= detail::escapeName(id.coreSegmentName); + } + if (id.hasProviderSegmentName()) + { + p /= detail::escapeName(id.providerSegmentName); + } + if (id.hasEntityName()) + { + p /= detail::escapeName(id.entityName); + } + if (id.hasTimestamp()) + { + p /= detail::toDayString(id.timestamp); + p /= detail::toSecondsString(id.timestamp); + p /= id.timestampStr(); + } + if (id.hasInstanceIndex()) + { + p /= id.instanceIndexStr(); + } + + return p; + } + + bool + directoryExists(const std::filesystem::path& p) + { + return std::filesystem::exists(p) and std::filesystem::is_directory(p); + } + + bool + fileExists(const std::filesystem::path& p) + { + return std::filesystem::exists(p) && std::filesystem::is_regular_file(p); + } + + void + ensureDirectoryExists(const std::filesystem::path& p, bool createIfNotExistent) + { + if (!directoryExists(p)) + { + if (createIfNotExistent) + { + std::filesystem::create_directories(p); + } + else + { + throw armarx::LocalException("Directory existence cannot be ensured: " + + p.string()); + } + } + } + + void + ensureFileExists(const std::filesystem::path& p, bool createIfNotExistent) + { + ensureDirectoryExists(p.parent_path(), createIfNotExistent); + if (!fileExists(p)) + { + if (createIfNotExistent) + { + std::string content = ""; + writeDataToFile(p, {content.begin(), content.end()}); + } + else + { + // not found + throw armarx::LocalException("Could not find file: " + p.string()); + } + } + } + + void + writeDataToFile(const std::filesystem::path& p, const std::vector<unsigned char>& data) + { + std::ofstream dataofs; + dataofs.open(p); + if (!dataofs) + { + throw armarx::LocalException("Could not write data to filesystem file '" + p.string() + + "'. Skipping this file."); + } + dataofs.write(reinterpret_cast<const char*>(data.data()), data.size()); + dataofs.close(); + } + + std::vector<unsigned char> + readDataFromFile(const std::filesystem::path& p) + { + std::ifstream dataifs(p); + std::vector<unsigned char> datafilecontent((std::istreambuf_iterator<char>(dataifs)), + (std::istreambuf_iterator<char>())); + dataifs.close(); + return datafilecontent; + } + + std::vector<std::filesystem::path> + getAllDirectories(const std::filesystem::path& p) + { + std::vector<std::filesystem::path> ret; + for (const auto& subdir : std::filesystem::directory_iterator(p)) + { + std::filesystem::path subdirPath = subdir.path(); + if (std::filesystem::is_directory(subdirPath)) + { + ret.push_back(subdirPath); + } + } + std::sort(ret.begin(), + ret.end(), + [](const std::filesystem::path& a, const std::filesystem::path& b) -> bool + { return a.string() > b.string(); }); + return ret; + } + + std::vector<std::filesystem::path> + getAllFiles(const std::filesystem::path& p) + { + std::vector<std::filesystem::path> ret; + for (const auto& subdir : std::filesystem::directory_iterator(p)) + { + std::filesystem::path subdirPath = subdir.path(); + if (std::filesystem::is_regular_file(subdirPath)) + { + ret.push_back(subdirPath); + } + } + std::sort(ret.begin(), + ret.end(), + [](const std::filesystem::path& a, const std::filesystem::path& b) -> bool + { return a.string() > b.string(); }); + return ret; + } +} // namespace armarx::armem::server::ltm::util::fs diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/filesystem.h b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/filesystem.h new file mode 100644 index 0000000000000000000000000000000000000000..9b5b778cc7ee6b7466685537eebd07b5dfe08326 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/filesystem.h @@ -0,0 +1,47 @@ +#pragma once + +#include <filesystem> +#include <map> +#include <string> +#include <vector> + +#include <RobotAPI/libraries/armem/core/MemoryID.h> + +namespace armarx::armem::server::ltm::util::fs +{ + namespace detail + { + inline const std::map<std::string, std::string> EscapeTable = {{"/", "|"}}; + + std::string escapeName(const std::string& segmentName); + + std::string unescapeName(const std::string& escapedName); + + std::string toDayString(const Time& t); + + std::string toSecondsString(const Time& t); + + bool isNumberString(const std::string& s); + + bool isDateString(const std::string& s); + } // namespace detail + + std::filesystem::path toPath(const std::filesystem::path& base, const armem::MemoryID& id); + + bool directoryExists(const std::filesystem::path& p); + + bool fileExists(const std::filesystem::path& p); + + void ensureDirectoryExists(const std::filesystem::path& p, bool createIfNotExistent = false); + + void ensureFileExists(const std::filesystem::path& p, bool createIfNotExistent = false); + + void writeDataToFile(const std::filesystem::path& p, const std::vector<unsigned char>& data); + + std::vector<unsigned char> readDataFromFile(const std::filesystem::path& p); + + std::vector<std::filesystem::path> getAllDirectories(const std::filesystem::path& p); + + std::vector<std::filesystem::path> getAllFiles(const std::filesystem::path& p); + +} // namespace armarx::armem::server::ltm::util::fs diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/mongodb.cpp b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/mongodb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a85e3e4f1eedc1fbd74d06119617c7660fcfe36c --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/mongodb.cpp @@ -0,0 +1,251 @@ +#include "mongodb.h" + +// Simox +#include <SimoxUtility/json.h> + +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> + +namespace armarx::armem::server::ltm::util::mongodb +{ + namespace bbuilder = bsoncxx::builder; + namespace bdoc = bsoncxx::document; + + namespace detail + { + std::string + escapeName(const std::string& segmentName) + { + std::string ret = segmentName; + //simox::alg::replace_all(ret, Prefix, PrefixEscaped); + for (const auto& [s, r] : EscapeTable) + { + ret = simox::alg::replace_all(ret, s, r); + } + return ret; + } + + std::string + unescapeName(const std::string& escapedName) + { + std::string ret = escapedName; + for ( + const auto& [s, r] : + EscapeTable) // Here we assume that noone uses the replaced char usually in the segment name... TODO + { + ret = simox::alg::replace_all(ret, r, s); + } + return ret; + } + + bool + insert(mongocxx::collection& coll, const nlohmann::json& value) + { + std::string v = value.dump(); + auto q = bsoncxx::from_json(v); + auto res = coll.insert_one(q.view()); + + return (bool)res; + } + + std::optional<nlohmann::json> + contains(mongocxx::collection& coll, const nlohmann::json& value) + { + // check mongodb + std::string v = value.dump(); + auto q = bsoncxx::from_json(v); + auto res = coll.find_one(q.view()); + if (res) + { + return nlohmann::json::parse(bsoncxx::to_json(*res)); + } + return std::nullopt; + } + + bool + update(mongocxx::collection& coll, + const nlohmann::json& query, + const nlohmann::json& update) + { + // check mongodb + auto q = bsoncxx::from_json(query.dump()); + auto udoc = bsoncxx::from_json(update.dump()); + auto u = bbuilder::basic::make_document(bbuilder::basic::kvp("$set", udoc)); + + auto res = coll.update_one(q.view(), u.view()); + + return (bool)res; + } + } // namespace detail + + std::optional<mongocxx::database> + databaseExists(mongocxx::client& client, const std::string& databaseName) + { + auto names = client.list_database_names(); + if (auto it = std::find(names.begin(), names.end(), databaseName); it != names.end()) + { + return client[databaseName]; + } + return std::nullopt; + } + + mongocxx::database + ensureDatabaseExists(mongocxx::client& client, + const std::string& databaseName, + bool createIfNotExistent) + { + auto db = databaseExists(client, databaseName); + if (!db) + { + if (!createIfNotExistent) + { + throw armarx::LocalException("Database existence can not be ensured: " + + databaseName); + } + } + return client[databaseName]; + } + + std::optional<mongocxx::collection> + collectionExists(mongocxx::database& db, const std::string& collectionName) + { + if (db.has_collection(collectionName)) + { + return db[collectionName]; + } + return std::nullopt; + } + + mongocxx::collection + ensureCollectionExists(mongocxx::database& db, + const std::string& collectionName, + bool createIfNotExistent) + { + auto coll = collectionExists(db, collectionName); + if (!coll) + { + if (!createIfNotExistent) + { + throw armarx::LocalException("Collection existence can not be ensured: " + + collectionName); + } + } + return db[collectionName]; + } + + std::string + toDocumentID(const armem::MemoryID& id) + { + if (id.hasTimestamp()) + { + return id.timestampStr(); + } + + // fallback + throw armarx::LocalException("Called toDocumentName() on non-snapshot id: " + id.str()); + } + + std::string + toCollectionName(const armem::MemoryID& id) + { + ARMARX_CHECK(id.isWellDefined()); + std::stringstream ss; + if (id.hasMemoryName()) + { + ss << detail::escapeName(id.memoryName); + } + if (id.hasCoreSegmentName()) + { + ss << "." << detail::escapeName(id.coreSegmentName); + } + if (id.hasProviderSegmentName()) + { + ss << "." << detail::escapeName(id.providerSegmentName); + } + if (id.hasEntityName()) + { + ss << "." << detail::escapeName(id.entityName); + } + + return ss.str(); + } + + std::optional<nlohmann::json> + documentExists(mongocxx::collection& collection, const nlohmann::json& json) + { + return detail::contains(collection, json); + } + + nlohmann::json + ensureDocumentExists(mongocxx::collection& collection, + const nlohmann::json& json, + bool createIfNotExistent) + { + auto op = documentExists(collection, json); + if (!op) + { + if (!createIfNotExistent) + { + throw armarx::LocalException("Document existence can not be ensured: " + + json.dump()); + } + } + + if (!op) + { + detail::insert(collection, json); + } + + auto find = detail::contains(collection, json); + if (!find) + { + throw armarx::LocalException( + "Even after creating the docuemnt it wasnt found.. error: " + json.dump()); + } + return *find; + } + + nlohmann::json + readDataFromDocument(mongocxx::collection& collection, const nlohmann::json& json) + { + auto doc = detail::contains(collection, json); + + ARMARX_CHECK((bool)doc) << " Could not find document matching: " << json.dump() + << " in collection " << collection.name(); + + return *doc; + } + + void + writeDataToDocument(mongocxx::collection& collection, + const nlohmann::json& query, + const nlohmann::json& update) + { + if (documentExists(collection, query)) + { + detail::update(collection, query, update); + } + else + { + nlohmann::json full; + full.update(query); + full.update(update); + detail::insert(collection, full); + } + } + + std::vector<nlohmann::json> + getAllDocuments(mongocxx::collection& collection) + { + std::vector<nlohmann::json> ret; + mongocxx::cursor cursor = collection.find({}); + for (const auto& doc : cursor) + { + ret.push_back( + nlohmann::json::parse(bsoncxx::to_json(doc, bsoncxx::ExtendedJsonMode::k_relaxed))); + } + return ret; + } + +} // namespace armarx::armem::server::ltm::util::mongodb diff --git a/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/mongodb.h b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/mongodb.h new file mode 100644 index 0000000000000000000000000000000000000000..9908e6c5b7f379be2ab7207a28610183c87395f5 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/detail/mixins/util/mongodb.h @@ -0,0 +1,74 @@ +#pragma once + +#include <map> +#include <memory> +#include <string> + +#include <SimoxUtility/json.h> + +#include <RobotAPI/libraries/armem/core/MemoryID.h> + +#include <bsoncxx/builder/stream/array.hpp> +#include <bsoncxx/builder/stream/document.hpp> +#include <bsoncxx/builder/stream/helpers.hpp> +#include <bsoncxx/json.hpp> +#include <mongocxx/client.hpp> +#include <mongocxx/instance.hpp> +#include <mongocxx/pool.hpp> +#include <mongocxx/stdx.hpp> +#include <mongocxx/uri.hpp> + +namespace armarx::armem::server::ltm::util::mongodb +{ + + namespace detail + { + inline const std::map<std::string, std::string> EscapeTable = {{"/", "|"}}; + + std::string escapeName(const std::string& segmentName); + + std::string unescapeName(const std::string& escapedName); + + bool insert(mongocxx::collection& coll, const nlohmann::json& value); + + std::optional<nlohmann::json> contains(mongocxx::collection& coll, + const nlohmann::json& value); + + bool update(mongocxx::collection& coll, + const nlohmann::json& query, + const std::string& vkey, + const nlohmann::json& vdata); + } // namespace detail + + std::string toDocumentID(const armem::MemoryID&); + std::string toCollectionName(const armem::MemoryID&); + + std::optional<mongocxx::database> databaseExists(mongocxx::client&, + const std::string& databaseName); + mongocxx::database ensureDatabaseExists(mongocxx::client&, + const std::string& databaseName, + bool createIfNotExistent); + + std::optional<mongocxx::collection> collectionExists(mongocxx::database&, + const std::string& collectionName); + mongocxx::collection ensureCollectionExists(mongocxx::database&, + const std::string& collectionName, + bool createIfNotExistent); + + std::optional<nlohmann::json> documentExists(mongocxx::collection& collection, + const nlohmann::json& query); + + nlohmann::json ensureDocumentExists(mongocxx::collection& collection, + const nlohmann::json& query, + bool createIfNotExistent = false); + + nlohmann::json readDataFromDocument(mongocxx::collection& collection, + const nlohmann::json& query); + + void writeDataToDocument(mongocxx::collection& collection, + const nlohmann::json& query, + const nlohmann::json& data); + + std::vector<nlohmann::json> getAllDocuments(mongocxx::collection& collection); + +} // namespace armarx::armem::server::ltm::util::mongodb diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.cpp deleted file mode 100644 index a6a7aa48e28f697254755e857df6c7c70ceb01e3..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "CoreSegment.h" - -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/logging/Logging.h> - -#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> - - -namespace armarx::armem::server::ltm::disk -{ - CoreSegment::CoreSegment(const std::filesystem::path& p, const MemoryID& id /* UNESCAPED */, const std::shared_ptr<Processors>& filters, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e) : - CoreSegmentBase(id, filters), - DiskMemoryItem(p, EscapeSegmentName(id.memoryName), std::filesystem::path(EscapeSegmentName(id.coreSegmentName))), - currentMode(mode), - currentExport(e) - { - } - - bool CoreSegment::forEachProviderSegment(std::function<void(ProviderSegment&)> func) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return false; - } - - for (const auto& subdirName : util::getAllDirectories(mPath, relPath)) - { - std::string segmentName = UnescapeSegmentName(subdirName); - ProviderSegment c(memoryParentPath, id().withProviderSegmentName(segmentName), processors, currentMode, currentExport); - func(c); - } - return true; - } - - std::shared_ptr<ProviderSegment> CoreSegment::findProviderSegment(const std::string& providerSegmentName) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return nullptr; - } - - auto c = std::make_shared<ProviderSegment>(memoryParentPath, id().withProviderSegmentName(providerSegmentName), processors, currentMode, currentExport); - if (!util::checkIfFolderExists(mPath, c->getRelativePathForMode(currentMode))) - { - return nullptr; - } - - return c; - } - - void CoreSegment::_loadAllReferences(armem::wm::CoreSegment& e) - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - e.id() = id(); - - auto& conv = processors->defaultTypeConverter; - auto relTPath = relPath / (constantes::TYPE_FILENAME + conv.suffix); - - if (util::checkIfFileExists(mPath, relTPath)) - { - auto typeFileContent = util::readDataFromFile(mPath, relTPath); - auto typeAron = conv.convert(typeFileContent, ""); - e.aronType() = aron::type::Object::DynamicCastAndCheck(typeAron); - } - - forEachProviderSegment([&e](auto& x) { - armem::wm::ProviderSegment s; - x.loadAllReferences(s); - e.addProviderSegment(s); - }); - } - - void CoreSegment::_resolve(armem::wm::CoreSegment& c) - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - c.forEachProviderSegment([&](auto& e) - { - ProviderSegment c(memoryParentPath, id().withProviderSegmentName(e.id().providerSegmentName), processors, currentMode, currentExport); - if (util::checkIfFolderExists(mPath, c.getRelativePathForMode(currentMode))) - { - c.resolve(e); - } - }); - } - - void CoreSegment::_store(const armem::wm::CoreSegment& c) - { - auto currentMaxExport = currentExport; - auto encodingModeOfPast = currentMode; - - if (id().coreSegmentName.empty()) - { - ARMARX_WARNING << "During storage of segment '" << c.id().str() << "' I noticed that the corresponding LTM has no id set. " << - "I set the id of the LTM to the same name, however this should not happen!"; - id().coreSegmentName = c.id().coreSegmentName; - } - - auto defaultMode = MemoryEncodingMode::FILESYSTEM; - - auto defaultMPath = getMemoryBasePathForMode(defaultMode, 0); - auto defaultRelPath = getRelativePathForMode(defaultMode); - if (!util::checkIfFolderExists(defaultMPath, defaultRelPath)) - { - ARMARX_WARNING << "The segment folder for segment '"+id().str()+"'was not created. I will create the folder by myself, however it seems like there is a bug in the ltm pipeline."; - util::ensureFolderExists(defaultMPath, defaultRelPath, true); - } - - c.forEachProviderSegment([&](const auto& prov) - { - ProviderSegment c(memoryParentPath, id().withProviderSegmentName(prov.id().providerSegmentName), processors, encodingModeOfPast, currentMaxExport); - util::ensureFolderExists(defaultMPath, c.getRelativePathForMode(defaultMode), true); - - statistics.recordedProviderSegments++; - - c.storeType(prov); - c.store(prov); - }); - } - - void CoreSegment::_storeType(const armem::wm::CoreSegment& c) - { - if (id().coreSegmentName.empty()) - { - ARMARX_WARNING << "During storage of segment '" << c.id().str() << "' I noticed that the corresponding LTM has no id set. " << - "I set the id of the LTM to the same name, however this should not happen!"; - id().coreSegmentName = c.id().coreSegmentName; - } - - auto defaultMode = MemoryEncodingMode::FILESYSTEM; - - auto defaultMPath = getMemoryBasePathForMode(defaultMode, 0); - auto defaultRelPath = getRelativePathForMode(defaultMode); - if (!util::checkIfFolderExists(defaultMPath, defaultRelPath)) - { - ARMARX_WARNING << "The segment folder for segment '"+id().str()+"'was not created. I will create the folder by myself, however it seems like there is a bug in the ltm pipeline."; - util::ensureFolderExists(defaultMPath, defaultRelPath, true); - } - - if(c.hasAronType()) - { - auto& conv = processors->defaultTypeConverter; - - auto [vec, modeSuffix] = conv.convert(c.aronType()); - ARMARX_CHECK_EMPTY(modeSuffix); - std::filesystem::path relTypePath = defaultRelPath / (constantes::TYPE_FILENAME + conv.suffix); - util::writeDataToFileRepeated(defaultMPath, relTypePath, vec); - } - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.h b/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.h deleted file mode 100644 index 78ff8be3f12d35eeebbed370cc04559b37a57822..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/CoreSegment.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <filesystem> - -// Base Class -#include "../base/detail/CoreSegmentBase.h" -#include "detail/DiskStorage.h" - -#include "ProviderSegment.h" - -namespace armarx::armem::server::ltm::disk -{ - class CoreSegment : - public CoreSegmentBase<ProviderSegment>, - public DiskMemoryItem - { - public: - - CoreSegment(const std::filesystem::path& parentPath, const MemoryID& id, const std::shared_ptr<Processors>& p, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e); - - bool forEachProviderSegment(std::function<void(ProviderSegment&)> func) const override; - - std::shared_ptr<ProviderSegment> findProviderSegment(const std::string&) const override; - - protected: - void _loadAllReferences(armem::wm::CoreSegment&) override; - void _resolve(armem::wm::CoreSegment&) override; - void _store(const armem::wm::CoreSegment&) override; - void _storeType(const armem::wm::CoreSegment&) override; - - private: - MemoryEncodingMode currentMode; - unsigned long currentExport; - }; - -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp deleted file mode 100644 index ea5ad1757f2d71e955d41a80a416a2c10474feb7..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp +++ /dev/null @@ -1,372 +0,0 @@ -// Header -#include "Entity.h" - -// ArmarX -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/logging/Logging.h> - -#include <RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.h> -#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> - -#include "../base/filter/frequencyFilter/FrequencyFilter.h" - - -namespace armarx::armem::server::ltm::disk -{ - Entity::Entity(const std::filesystem::path& p, const MemoryID& id, const std::shared_ptr<Processors>& filters, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e) : - EntityBase(id, filters), - DiskMemoryItem(p, EscapeSegmentName(id.memoryName), std::filesystem::path(EscapeSegmentName(id.coreSegmentName)) / EscapeSegmentName(id.providerSegmentName) / EscapeSegmentName(id.entityName)), - currentMode(mode), - currentExport(e) - { - } - - bool Entity::forEachSnapshot(std::function<void(EntitySnapshot&)> func) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return false; - } - - for (const auto& hName : util::getAllDirectories(mPath, relPath)) - { - if (!util::isNumber(hName)) - { - ARMARX_WARNING << "Found a non-timestamp folder inside an entity '" << id().str() << "' with name '" << hName << "'. " << - "Ignoring this folder, however this is a bad situation."; - continue; - } - - // check if this is already a microsec folder (legacy export support) - //if (std::stol(secName) > 1647524607 /* the time in us the new export was implemented */) - //{ - // EntitySnapshot c(memoryParentPath, id().withTimestamp(timeFromStringMicroSeconds(secName)), processors, currentMode, currentExport); - // func(c); - // continue; - //} - - auto hRelPath = relPath / hName; - for (const auto& secName : util::getAllDirectories(mPath, hRelPath)) - { - if (!util::isNumber(secName)) - { - ARMARX_WARNING << "Found a non-timestamp folder inside an entity '" << id().str() << "' with name '" << secName << "'. " << - "Ignoring this folder, however this is a bad situation."; - continue; - } - - auto secRelPath = hRelPath / secName; - for (const auto& usecName : util::getAllDirectories(mPath, secRelPath)) - { - if (!util::isNumber(usecName)) - { - ARMARX_WARNING << "Found a non-timestamp folder inside an entity '" << id().str() << "' with name '" << usecName << "'. " << - "Ignoring this folder, however this is a bad situation."; - continue; - } - - - EntitySnapshot c(memoryParentPath, id().withTimestamp(timeFromStringMicroSeconds(usecName)), processors, currentMode, currentExport); - func(c); - } - } - } - return true; - } - - bool Entity::forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshot&)> func) const - { - //ARMARX_WARNING << "PLEASE NOTE THAT QUERYING THE LTM INDEX WISE MAY BE BUGGY BECAUSE THE FILESYSTEM ITERATOR IS UNSORTED!"; - - if (first < 0 or last < 0) - { - // We need to know what the size of the memory is... May be slow - unsigned long size = 0; - auto f = [&](EntitySnapshot& e) - { - size++; - }; - forEachSnapshot(std::move(f)); - - first = armarx::armem::base::detail::negativeIndexSemantics(first, size); - last = armarx::armem::base::detail::negativeIndexSemantics(last, size); - } - - long checked = 0; - auto f = [&](EntitySnapshot& e) - { - if (checked >= first && checked <= last) - { - func(e); - } - checked++; - }; - - return forEachSnapshot(std::move(f)); - } - - bool Entity::forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshot&)> func) const - { - auto f = [&](EntitySnapshot& e) - { - auto ts = e.id().timestamp; - if (ts >= min && ts <= max) - { - func(e); - } - }; - - return forEachSnapshot(std::move(f)); - } - - bool Entity::forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshot&)> func) const - { - auto f = [&](EntitySnapshot& e) - { - auto ts = e.id().timestamp; - if (ts <= time) - { - func(e); - } - }; - - return forEachSnapshot(std::move(f)); - } - - bool Entity::forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)> func) const - { - auto f = [&](EntitySnapshot& e) - { - auto ts = e.id().timestamp; - if (ts < time) - { - func(e); - } - }; - - return forEachSnapshot(std::move(f)); - } - - std::shared_ptr<EntitySnapshot> Entity::findSnapshot(const Time& n) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return nullptr; - } - - auto c = std::make_shared<EntitySnapshot>(memoryParentPath, id().withTimestamp(n), processors, currentMode, currentExport); - if (!util::checkIfFolderExists(mPath, c->getRelativePathForMode(currentMode))) - { - return nullptr; - } - - return c; - } - - std::shared_ptr<EntitySnapshot> Entity::findLatestSnapshot() const - { - Time bestMatch = Time::Invalid(); - auto f = [&](EntitySnapshot& e) { - auto ts = e.id().timestamp; - if (ts > bestMatch) - { - bestMatch = ts; - } - }; - - forEachSnapshot(std::move(f)); - - if (bestMatch == Time::Invalid()) - { - return nullptr; - } - - return std::make_shared<EntitySnapshot>(memoryParentPath, id().withTimestamp(bestMatch), processors, currentMode, currentExport); - } - - std::shared_ptr<EntitySnapshot> Entity::findLatestSnapshotBefore(const Time& time) const - { - Time bestMatch = Time::Invalid(); - auto f = [&](EntitySnapshot& e) { - auto ts = e.id().timestamp; - if (ts < time && ts > bestMatch) - { - bestMatch = ts; - } - }; - - forEachSnapshot(std::move(f)); - - if (bestMatch == Time::Invalid()) - { - return nullptr; - } - - return std::make_shared<EntitySnapshot>(memoryParentPath, id().withTimestamp(bestMatch), processors, currentMode, currentExport); - } - - std::shared_ptr<EntitySnapshot> Entity::findLatestSnapshotBeforeOrAt(const Time& time) const - { - Time bestMatch = Time::Invalid(); - auto f = [&](EntitySnapshot& e) { - auto ts = e.id().timestamp; - if (ts <= time && ts > bestMatch) - { - bestMatch = ts; - } - }; - - forEachSnapshot(std::move(f)); - - if (bestMatch == Time::Invalid()) - { - return nullptr; - } - - return std::make_shared<EntitySnapshot>(memoryParentPath, id().withTimestamp(bestMatch), processors, currentMode, currentExport); - } - - std::shared_ptr<EntitySnapshot> Entity::findFirstSnapshotAfter(const Time& time) const - { - Time bestMatch { Duration::MicroSeconds(std::numeric_limits<long>::max()) }; - auto f = [&](EntitySnapshot& e) - { - auto ts = e.id().timestamp; - if (ts > time && ts < bestMatch) - { - bestMatch = ts; - } - }; - - forEachSnapshot(std::move(f)); - - if (bestMatch == Time(Duration::MicroSeconds(std::numeric_limits<long>::max()))) - { - return nullptr; - } - - return std::make_shared<EntitySnapshot>(memoryParentPath, id().withTimestamp(bestMatch), processors, currentMode, currentExport); - } - - std::shared_ptr<EntitySnapshot> Entity::findFirstSnapshotAfterOrAt(const Time& time) const - { - Time bestMatch { Duration::MicroSeconds(std::numeric_limits<long>::max()) }; - auto f = [&](EntitySnapshot& e) - { - auto ts = e.id().timestamp; - if (ts >= time && ts < bestMatch) - { - bestMatch = ts; - } - }; - - forEachSnapshot(std::move(f)); - - if (bestMatch == Time(Duration::MicroSeconds(std::numeric_limits<long>::max()))) - { - return nullptr; - } - - return std::make_shared<EntitySnapshot>(memoryParentPath, id().withTimestamp(bestMatch), processors, currentMode, currentExport); - } - - void Entity::_loadAllReferences(armem::wm::Entity& e) - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - e.id() = id(); - - forEachSnapshot([&e](auto& x) - { - if (!e.hasSnapshot(x.id().timestamp)) // we only load the references if the snapshot is not existant - { - armem::wm::EntitySnapshot s; - x.loadAllReferences(s); - e.addSnapshot(s); - } - }); - } - - void Entity::_resolve(armem::wm::Entity& p) - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - p.forEachSnapshot([&](auto& e) - { - EntitySnapshot c(memoryParentPath, id().withTimestamp(e.id().timestamp), processors, currentMode, currentExport); - if (util::checkIfFolderExists(mPath, c.getRelativePathForMode(currentMode))) - { - c.resolve(e); - } - }); - } - - void Entity::_store(const armem::wm::Entity& c) - { - if (id().entityName.empty()) - { - ARMARX_WARNING << "During storage of segment '" << c.id().str() << "' I noticed that the corresponding LTM has no id set. " << - "I set the id of the LTM to the same name, however this should not happen!"; - id().entityName = c.id().entityName; - } - - auto defaultMode = MemoryEncodingMode::FILESYSTEM; - - auto defaultMPath = getMemoryBasePathForMode(defaultMode, 0); - auto defaultRelPath = getRelativePathForMode(defaultMode); - if (!util::checkIfFolderExists(defaultMPath, defaultRelPath)) - { - ARMARX_WARNING << "The segment folder for segment '"+id().str()+"'was not created. I will create the folder by myself, however it seems like there is a bug in the ltm pipeline."; - util::ensureFolderExists(defaultMPath, defaultRelPath, true); - } - - c.forEachSnapshot([&](const auto& snap) - { - auto currentMaxExport = currentExport; - auto encodingModeOfPast = currentMode; - - for (unsigned long i = 0; i < currentMaxExport; ++i) - { - MemoryEncodingMode mode = i == 0 ? defaultMode : encodingModeOfPast; - auto mPath = getMemoryBasePathForMode(mode, i); - - EntitySnapshot c(memoryParentPath, id().withTimestamp(snap.id().timestamp), processors, mode, i); - if (util::checkIfFolderExists(mPath, c.getRelativePathForMode(mode))) - { - ARMARX_INFO << deactivateSpam() << "Ignoring to put an EntitiySnapshot into the LTM because the timestamp already existed (we assume snapshots are const and do not change outside the ltm)."; - return; - } - } - - for (auto& f : processors->snapFilters) - { - if (f->enabled && !f->accept(snap)) - { - ARMARX_INFO << deactivateSpam() << "Ignoring to put an EntitiySnapshot into the LTM because it got filtered."; - return; - } - } - - EntitySnapshot c(memoryParentPath, id().withTimestamp(snap.id().timestamp), processors, encodingModeOfPast, currentMaxExport); - util::ensureFolderExists(defaultMPath, c.getRelativePathForMode(defaultMode)); - - statistics.recordedSnapshots++; - - c.store(snap); - }); - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.h b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.h deleted file mode 100644 index 3d98ef1bf8abe315e005a110ad6fa807f373d7ba..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include <filesystem> - -// Base Class -#include "../base/detail/EntityBase.h" -#include "detail/DiskStorage.h" - -#include "EntitySnapshot.h" - -namespace armarx::armem::server::ltm::disk -{ - /// @brief A memory storing data in mongodb (needs 'armarx memory start' to start the mongod instance) - class Entity : - public EntityBase<EntitySnapshot>, - public DiskMemoryItem - { - public: - Entity(const std::filesystem::path& parentPath, const MemoryID& id, const std::shared_ptr<Processors>& p, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e); - - bool forEachSnapshot(std::function<void(EntitySnapshot&)> func) const override; - bool forEachSnapshotInIndexRange(long first, long last, std::function<void(EntitySnapshot&)> func) const override; - bool forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshot&)> func) const override; - bool forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshot&)> func) const override; - bool forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)> func) const override; - - std::shared_ptr<EntitySnapshot> findSnapshot(const Time&) const override; - std::shared_ptr<EntitySnapshot> findLatestSnapshot() const override; - std::shared_ptr<EntitySnapshot> findLatestSnapshotBefore(const Time& time) const override; - std::shared_ptr<EntitySnapshot> findLatestSnapshotBeforeOrAt(const Time& time) const override; - std::shared_ptr<EntitySnapshot> findFirstSnapshotAfter(const Time& time) const override; - std::shared_ptr<EntitySnapshot> findFirstSnapshotAfterOrAt(const Time& time) const override; - - protected: - void _loadAllReferences(armem::wm::Entity&) override; - void _resolve(armem::wm::Entity&) override; - void _store(const armem::wm::Entity&) override; - - private: - MemoryEncodingMode currentMode; - unsigned long currentExport; - }; - -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp deleted file mode 100644 index aea0141b662e58a1dda66b261ccec875bcdf0768..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp +++ /dev/null @@ -1,229 +0,0 @@ -// Header -#include "EntitySnapshot.h" - -// STD / STL -#include <iostream> -#include <fstream> - -// ArmarX -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/logging/Logging.h> -#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> - -namespace armarx::armem::server::ltm::disk -{ - EntitySnapshot::EntitySnapshot(const std::filesystem::path& p, const MemoryID& id /* UNESCAPED */, const std::shared_ptr<Processors>& filters, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e) : - EntitySnapshotBase(id, filters), - DiskMemoryItem(p, EscapeSegmentName(id.memoryName), - std::filesystem::path(EscapeSegmentName(id.coreSegmentName)) - / EscapeSegmentName(id.providerSegmentName) - / EscapeSegmentName(id.entityName) - / std::to_string(id.timestamp.toSecondsSinceEpoch() / 3600 /* hours */) - / std::to_string(id.timestamp.toSecondsSinceEpoch()) /* seconds */ / id.timestampStr()), - currentMode(mode), - currentExport(e) - { - } - - void EntitySnapshot::_loadAllReferences(armem::wm::EntitySnapshot& e) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - e.id() = id(); - - for (unsigned int i = 0; i < 1000; ++i) // 1000 is max size for instances in a single timestamp - { - std::filesystem::path relIPath = relPath / std::to_string(i) / ""; - if (!util::checkIfFolderExists(mPath, relIPath)) - { - break; - } - - // add instance. Do not set data, since we only return references - e.addInstance(); - } - } - - void EntitySnapshot::_resolve(armem::wm::EntitySnapshot& e) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - auto& dictConverter = processors->defaultObjectConverter; - - // Get data from disk - for (unsigned int i = 0; i < e.size(); ++i) - { - std::filesystem::path relIPath = relPath / std::to_string(i) / ""; - if (util::checkIfFolderExists(mPath, relIPath)) - { - std::string dataFilename = (constantes::DATA_FILENAME + dictConverter.suffix); - std::string metadataFilename = (constantes::METADATA_FILENAME + dictConverter.suffix); - std::filesystem::path relDataPath = relIPath / dataFilename; - std::filesystem::path relMetadataPath = relIPath / metadataFilename; - - auto& ins = e.getInstance(i); - aron::data::DictPtr datadict = nullptr; - aron::data::DictPtr metadatadict = nullptr; - - // get list of all files. This ensures that we only have to call fs::exists once for each file - auto allFilesInIndexFolder = util::getAllFiles(mPath, relIPath); - - if (std::find(allFilesInIndexFolder.begin(), allFilesInIndexFolder.end(), dataFilename) != allFilesInIndexFolder.end()) - { - //ARMARX_INFO << "Convert data for entity " << id(); - auto datafilecontent = util::readDataFromFile(mPath, relDataPath); - auto dataaron = dictConverter.convert(datafilecontent, {}, ""); - datadict = aron::data::Dict::DynamicCastAndCheck(dataaron); - - // check for special members TODO: only allowed for direct children? - for (const auto& [key, m] : datadict->getElements()) - { - for (auto& [t, f] : processors->converters) - { - for (const auto& filename : allFilesInIndexFolder) // iterate over all files and search for matching ones - { - if (simox::alg::starts_with(filename, key) and simox::alg::ends_with(filename, f->suffix)) - { - std::filesystem::path relMemberPath = relIPath / filename; - std::string mode = simox::alg::remove_suffix(simox::alg::remove_prefix(filename, key), f->suffix); - - auto memberfilecontent = util::readDataFromFile(mPath, relMemberPath); - auto memberaron = f->convert(memberfilecontent, armarx::aron::Path(datadict->getPath(), std::vector<std::string>{key}), mode); - datadict->setElement(key, memberaron); - break; - } - } - } - } - } - else - { - ARMARX_ERROR << "Could not find the data file '" << relDataPath.string() << "'. Continuing without data."; - } - - //ARMARX_INFO << "Convert metadata for entity " << id(); - if (std::find(allFilesInIndexFolder.begin(), allFilesInIndexFolder.end(), metadataFilename) != allFilesInIndexFolder.end()) - { - auto metadatafilecontent = util::readDataFromFile(mPath, relMetadataPath); - auto metadataaron = dictConverter.convert(metadatafilecontent, {}, ""); - metadatadict = aron::data::Dict::DynamicCastAndCheck(metadataaron); - } - else - { - ARMARX_ERROR << "Could not find the metadata file '" << relMetadataPath.string() << "'. Continuing without metadata."; - } - - from_aron(metadatadict, datadict, ins); - } - else - { - ARMARX_WARNING << "Could not find the index segment folder for segment '" << e.id().str() << "'."; - } - } - } - - void EntitySnapshot::_store(const armem::wm::EntitySnapshot& e) - { - //auto currentMaxExport = currentExport; - //auto encodingModeOfPast = currentMode; - - if (id().timestampStr().empty()) - { - ARMARX_WARNING << "During storage of segment '" << e.id().str() << "' I noticed that the corresponding LTM has no id set. " << - "I set the id of the LTM to the same name, however this should not happen!"; - id().timestamp = e.id().timestamp; - } - - auto defaultMode = MemoryEncodingMode::FILESYSTEM; - - auto& dictConverter = processors->defaultObjectConverter; - - auto defaultMPath = getMemoryBasePathForMode(defaultMode, 0); - auto defaultRelPath = getRelativePathForMode(defaultMode); - if (!util::checkIfFolderExists(defaultMPath, defaultRelPath)) - { - ARMARX_WARNING << "The segment folder for segment '"+id().str()+"'was not created. I will create the folder by myself, however it seems like there is a bug in the ltm pipeline."; - util::ensureFolderExists(defaultMPath, defaultRelPath, true); - } - - for (unsigned int i = 0; i < e.size(); ++i) - { - std::filesystem::path defaultRelIPath = defaultRelPath / std::to_string(i) / ""; - - // For performance reasons we skip to check whether the index folder already exists somewhere. - // We already check if the ts exists on entity level. - - if (!util::checkIfFolderExists(defaultMPath, defaultRelIPath)) - { - util::ensureFolderExists(defaultMPath, defaultRelIPath); - - std::filesystem::path relDataPath = defaultRelIPath / (constantes::DATA_FILENAME + dictConverter.suffix); - std::filesystem::path relMetadataPath = defaultRelIPath / (constantes::METADATA_FILENAME + dictConverter.suffix); - - auto& ins = e.getInstance(i); - - // data - auto dataAron = std::make_shared<aron::data::Dict>(); - auto metadataAron = std::make_shared<aron::data::Dict>(); - to_aron(metadataAron, dataAron, ins); - - // check special members for special extractions - for (auto& x : processors->extractors) - { - if (!x->enabled) continue; - - const auto& t = x->identifier; - - Converter* conv = nullptr; // find suitable converter - for (const auto& [ct, c] : processors->converters) - { - if (!c->enabled) continue; - if (t != ct) continue; - conv = c; - } - - if (conv) - { - auto dataExt = x->extract(dataAron); - - for (const auto& [memberName, var] : dataExt.extraction) - { - ARMARX_CHECK_NOT_NULL(var); - - auto [memberDataVec, memberDataModeSuffix] = conv->convert(var); - std::filesystem::path relMemberPath = defaultRelIPath / (memberName + memberDataModeSuffix + conv->suffix); - - util::writeDataToFileRepeated(defaultMPath, relMemberPath, memberDataVec); - } - - dataAron = dataExt.dataWithoutExtraction; - } - // else we could not convert the extracted data so it makes no sense to extract it at all... - } - - // convert dict and metadata - auto [dataVec, dataVecModeSuffix] = dictConverter.convert(dataAron); - auto [metadataVec, metadataVecModeSuffix] = dictConverter.convert(metadataAron); - ARMARX_CHECK_EMPTY(dataVecModeSuffix); - ARMARX_CHECK_EMPTY(metadataVecModeSuffix); - - statistics.recordedInstances++; - - util::writeDataToFileRepeated(defaultMPath, relDataPath, dataVec); - util::writeDataToFileRepeated(defaultMPath, relMetadataPath, metadataVec); - } - // Ignore if the full index already exists. Actually this should not happen since the existence of the ts folder is checked on entity level - } - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.h b/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.h deleted file mode 100644 index aa72ea3e12e82e7f5787af2649b09a9cc29f0109..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include <filesystem> - -// Base Class -#include "../base/detail/EntitySnapshotBase.h" -#include "detail/DiskStorage.h" - -namespace armarx::armem::server::ltm::disk -{ - - class EntitySnapshot : - public EntitySnapshotBase, - public DiskMemoryItem - { - public: - EntitySnapshot(const std::filesystem::path& parentPath, const MemoryID& id, const std::shared_ptr<Processors>& p, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e); - - protected: - void _loadAllReferences(armem::wm::EntitySnapshot&) const override; - void _resolve(armem::wm::EntitySnapshot&) const override; - void _store(const armem::wm::EntitySnapshot&) override; - - private: - MemoryEncodingMode currentMode; - unsigned long currentExport; - }; - -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.cpp deleted file mode 100644 index 31f5bd8106a32172540db9692b166cdd7fb9d858..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "Memory.h" - -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/logging/Logging.h> - -#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> - -namespace armarx::armem::server::ltm::disk -{ - void Memory::configure(const nlohmann::json& json) - { - Base::configure(json); - if (json.find("Memory.memoryParentPath") != json.end()) - { - memoryParentPath = std::filesystem::path(json.at("Memory.memoryParentPath")); - } - if (json.find("Memory.sizeToCompressDataInMegaBytes") != json.end()) - { - sizeToCompressDataInMegaBytes = json.at("Memory.sizeToCompressDataInMegaBytes"); - } - } - - Memory::Memory() : - Memory(std::filesystem::path("/tmp/MemoryExport"), "Test") - { - } - - Memory::Memory(const std::filesystem::path& p, const std::string& memoryName /* UNESCAPED */, const MemoryEncodingMode defaultEncodingMode) : - Base(MemoryID(memoryName, "")), - DiskMemoryItem(p, EscapeSegmentName(memoryName), ""), - defaultExportEncodingMode(defaultEncodingMode) - { - } - - void Memory::setMemoryID(const MemoryID &id) - { - Base::setMemoryID(id); - escapedMemoryName = EscapeSegmentName(id.memoryName); - } - void Memory::setMemoryID(const MemoryID& id, const std::string& componentNameFallback) - { - MemoryID _id = id; - if (id.memoryName.empty()) - { - ARMARX_WARNING << "ATTENTION: A memory id passed to some LTM is empty. Either you used the wrong setter (always use setMemoryName(..) before onInitComponent()) or you emptied the scenario parameter. Using a the component name as fallback."; - _id.memoryName = componentNameFallback; - } - - setMemoryID(_id); - } - - void Memory::init() - { - Base::init(); - - // Discover how many exports already exists - for (unsigned long i = 1; i < 10000; ++i) - { - std::filesystem::path exportPath = getMemoryBasePathForMode(defaultExportEncodingMode, i); - if (!std::filesystem::exists(exportPath)) - { - break; - } - maxExportIndex = i; - } - } - - bool Memory::forEachCoreSegment(std::function<void(CoreSegment&)> func) const - { - for (unsigned long i = 0; i <= maxExportIndex; ++i) - { - MemoryEncodingMode mode = i == 0 ? MemoryEncodingMode::FILESYSTEM : defaultExportEncodingMode; - auto mPath = getMemoryBasePathForMode(mode, i); - - if (util::checkIfBasePathExists(mPath)) - { - for (const auto& subdirName : util::getAllDirectories(mPath, getRelativePathForMode(mode))) - { - std::string segmentName = UnescapeSegmentName(subdirName); - CoreSegment c(memoryParentPath, id().withCoreSegmentName(segmentName), processors, mode, i); - func(c); - } - } - } - - return true; - } - - std::shared_ptr<CoreSegment> Memory::findCoreSegment(const std::string& coreSegmentName) const - { - for (unsigned long i = 0; i <= maxExportIndex; ++i) - { - MemoryEncodingMode mode = i == 0 ? MemoryEncodingMode::FILESYSTEM : defaultExportEncodingMode; - - auto mPath = getMemoryBasePathForMode(mode, i); - if (!util::checkIfBasePathExists(mPath)) - { - continue; - } - - auto c = std::make_shared<CoreSegment>(memoryParentPath, id().withCoreSegmentName(coreSegmentName), processors, mode, i); - if (!util::checkIfFolderExists(mPath, c->getRelativePathForMode(mode))) - { - continue; - } - - return c; - } - return nullptr; - } - - void Memory::_loadAllReferences(armem::wm::Memory& m) - { - m.id() = id(); - - forEachCoreSegment([&m](auto& x) { - armem::wm::CoreSegment s; - x.loadAllReferences(s); - m.addCoreSegment(s); - }); - } - - void Memory::_resolve(armem::wm::Memory& m) - { - std::lock_guard l(ltm_mutex); // we cannot load a memory multiple times simultaneously - - for (unsigned long i = 0; i <= maxExportIndex; ++i) - { - MemoryEncodingMode mode = i == 0 ? MemoryEncodingMode::FILESYSTEM : defaultExportEncodingMode; - - auto mPath = getMemoryBasePathForMode(mode, i); - if (!util::checkIfBasePathExists(mPath)) - { - continue; - } - - m.forEachCoreSegment([&](auto& e) - { - CoreSegment c(memoryParentPath, id().withCoreSegmentName(e.id().coreSegmentName), processors, mode, i); - if (util::checkIfFolderExists(mPath, c.getRelativePathForMode(mode))) - { - c.resolve(e); - } - }); - } - } - - void Memory::_directlyStore(const armem::wm::Memory& memory) - { - std::lock_guard l(ltm_mutex); // we cannot store a memory multiple times simultaneously - - MemoryEncodingMode defaultMode = MemoryEncodingMode::FILESYSTEM; - MemoryEncodingMode encodeModeOfPast = defaultExportEncodingMode; - // Storage will always be in filesystem mode! - // Somehow, minizip was not able to write data to images. It always created a folder named xyz.png without any data in it... - // Another problem is that storing data directly in compressed format will require a lot of time when the compressed file is big (>20MB) - - if (id().memoryName.empty()) - { - ARMARX_WARNING << "During storage of memory '" << memory.id().str() << "' I noticed that the corresponding LTM has no id set. " << - "I set the id of the LTM to the same name, however this should not happen!"; - setMemoryID(memory.id()); - } - - auto defaultMPath = getMemoryBasePathForMode(defaultMode, 0); - - // Check if we have to compress the memory! - // See above mentioned issues with directly compressing the data. Therefore we store data in plain text and compress from time to time - // using system calls. Also increase the index of all old exports - auto size = filesystem::util::getSizeOfDirectory(defaultMPath); - //std::cout << "Current maxExportIndex is: " << maxExportIndex << std::endl; - if (size >= (sizeToCompressDataInMegaBytes * 1024 * 1024)) - { - ARMARX_INFO << "Compressen of memory " + id().memoryName + " needed because the size of last export is " + std::to_string(size / 1024.f / 1024.f) + " (>= " + std::to_string(sizeToCompressDataInMegaBytes) + ")"; - - // increase index of old memories - for (unsigned long i = maxExportIndex; i >= 1; --i) - { - ARMARX_INFO << "Increasing the index of old compressed memory " + id().memoryName + " (" + std::to_string(i) + " to " + std::to_string(i+1) + ")"; - auto exportPath = getMemoryBasePathForMode(encodeModeOfPast, i); - auto newExportPath = getMemoryBasePathForMode(encodeModeOfPast, i+1); - std::string moveCommand = "mv " + exportPath.string() + " " + newExportPath.string(); - //std::cout << "Exec command: " << moveCommand << std::endl; - int ret = system(moveCommand.c_str()); - (void) ret; - } - - // zip away current export - ARMARX_INFO << "Compressing the last export of " + id().memoryName; - auto newExportPath = getMemoryBasePathForMode(encodeModeOfPast, 1); // 1 will be the new export - std::string zipCommand = "cd " + memoryParentPath.string() + " && zip -r " + newExportPath.string() + " " + escapedMemoryName; - //std::cout << "Exec command: " << zipCommand << std::endl; - int ret = system(zipCommand.c_str()); - (void) ret; - - // remove unzipped memory export - ARMARX_INFO << "Removing the last export of " + id().memoryName; - std::string rmCommand = "rm -r " + defaultMPath.string(); - ret = system(rmCommand.c_str()); - (void) ret; - - maxExportIndex++; - } - - util::ensureBasePathExists(defaultMPath, true); // create if not exists - - memory.forEachCoreSegment([&](const auto& core) - { - CoreSegment c(memoryParentPath, id().withCoreSegmentName(core.id().coreSegmentName), processors, encodeModeOfPast, 0 /* how far to look back in past on enity level. For full lookup use maxExportIndex. */); - util::ensureFolderExists(defaultMPath, c.getRelativePathForMode(defaultMode), true); // create subfolder - - statistics.recordedCoreSegments++; - - // 1. store type - c.storeType(core); - - // 2. store data - c.store(core); - }); - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.h b/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.h deleted file mode 100644 index afd3a09004eea72c406ebfea844ffa80b257fc84..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/Memory.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include <filesystem> - -// Base Class -#include <RobotAPI/libraries/armem/server/ltm/base/detail/BufferedMemoryBase.h> -#include "detail/DiskStorage.h" - -// Segmnet Type -#include "CoreSegment.h" - - -namespace armarx::armem::server::ltm::disk -{ - /// @brief A memory storing data in mongodb (needs 'armarx memory start' to start the mongod instance) - class Memory : - public BufferedMemoryBase<CoreSegment>, - public DiskMemoryItem - { - public: - using Base = BufferedMemoryBase<CoreSegment>; - - Memory(); - Memory(const std::filesystem::path&, const std::string&, const MemoryEncodingMode defaultEncodingMode = MemoryEncodingMode::MINIZIP); - - void init() final; - void setMemoryID(const MemoryID& id) final; - void setMemoryID(const MemoryID& id, const std::string& fallback); - - void configure(const nlohmann::json& config) final; - - bool forEachCoreSegment(std::function<void(CoreSegment&)> func) const final; - std::shared_ptr<CoreSegment> findCoreSegment(const std::string& coreSegmentName) const final; - - protected: - void _loadAllReferences(armem::wm::Memory&) final; - void _resolve(armem::wm::Memory&) final; - void _directlyStore(const armem::wm::Memory&) final; - - private: - MemoryEncodingMode defaultExportEncodingMode = MemoryEncodingMode::MINIZIP; - unsigned long maxExportIndex = 0; - unsigned long sizeToCompressDataInMegaBytes = long(1) * 1024; // 1GB - - public: - static const int DEPTH_TO_DATA_FILES = 7; // from memory folder = 1 (cseg) + 1 (pseg) + 1 (ent) + 3 (snap) + 1 (inst) - }; -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.cpp deleted file mode 100644 index 631461f464f25977fddbb518c9332bc51e273ce9..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// Header -#include "ProviderSegment.h" - -// ArmarX -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/logging/Logging.h> - -#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> - - -namespace armarx::armem::server::ltm::disk -{ - ProviderSegment::ProviderSegment(const std::filesystem::path& p, const MemoryID& id /* UNESCAPED */, const std::shared_ptr<Processors>& filters, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e) : - ProviderSegmentBase(id, filters), - DiskMemoryItem(p, EscapeSegmentName(id.memoryName), std::filesystem::path(EscapeSegmentName(id.coreSegmentName)) / EscapeSegmentName(id.providerSegmentName)), - currentMode(mode), - currentExport(e) - { - } - - bool ProviderSegment::forEachEntity(std::function<void(Entity&)> func) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return false; - } - - for (const auto& subdirName : util::getAllDirectories(mPath, relPath)) - { - std::string segmentName = UnescapeSegmentName(subdirName); - Entity c(memoryParentPath, id().withEntityName(segmentName), processors, currentMode, currentExport); - func(c); - } - return true; - } - - std::shared_ptr<Entity> ProviderSegment::findEntity(const std::string& entityName) const - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return nullptr; - } - - auto c = std::make_shared<Entity>(memoryParentPath, id().withEntityName(entityName), processors, currentMode, currentExport); - if (!util::checkIfFolderExists(mPath, c->getRelativePathForMode(currentMode))) - { - return nullptr; - } - - return c; - } - - void ProviderSegment::_loadAllReferences(armem::wm::ProviderSegment& e) - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - e.id() = id(); - - auto& conv = processors->defaultTypeConverter; - auto relTPath = relPath / (constantes::TYPE_FILENAME + conv.suffix); - - if (util::checkIfFileExists(mPath, relTPath)) - { - auto typeFileContent = util::readDataFromFile(mPath, relTPath); - auto typeAron = conv.convert(typeFileContent, ""); - e.aronType() = aron::type::Object::DynamicCastAndCheck(typeAron); - } - - forEachEntity([&e](auto& x) { - armem::wm::Entity s; - x.loadAllReferences(s); - e.addEntity(s); - }); - } - - void ProviderSegment::_resolve(armem::wm::ProviderSegment& p) - { - auto mPath = getMemoryBasePathForMode(currentMode, currentExport); - auto relPath = getRelativePathForMode(currentMode); - if (!util::checkIfBasePathExists(mPath) || !util::checkIfFolderExists(mPath, relPath)) - { - return; - } - - p.forEachEntity([&](auto& e) - { - Entity c(memoryParentPath, id().withEntityName(e.id().entityName), processors, currentMode, currentExport); - if (util::checkIfFolderExists(mPath, c.getRelativePathForMode(currentMode))) - { - c.resolve(e); - } - }); - } - - void ProviderSegment::_store(const armem::wm::ProviderSegment& p) - { - auto currentMaxExport = currentExport; - auto encodingModeOfPast = currentMode; - - if (id().providerSegmentName.empty()) - { - ARMARX_WARNING << "During storage of segment '" << p.id().str() << "' I noticed that the corresponding LTM has no id set. " << - "I set the id of the LTM to the same name, however this should not happen!"; - id().providerSegmentName = p.id().providerSegmentName; - } - - auto defaultMode = MemoryEncodingMode::FILESYSTEM; - - auto defaultMPath = getMemoryBasePathForMode(defaultMode, 0); - auto defaultRelPath = getRelativePathForMode(defaultMode); - if (!util::checkIfFolderExists(defaultMPath, defaultRelPath)) - { - ARMARX_WARNING << "The segment folder for segment '"+id().str()+"'was not created. I will create the folder by myself, however it seems like there is a bug in the ltm pipeline."; - util::ensureFolderExists(defaultMPath, defaultRelPath, true); - } - - p.forEachEntity([&](const auto& e) - { - Entity c(memoryParentPath, id().withEntityName(e.id().entityName), processors, encodingModeOfPast, currentMaxExport); - util::ensureFolderExists(defaultMPath, c.getRelativePathForMode(defaultMode), true); - - statistics.recordedEntities++; - - c.store(e); - }); - } - - void ProviderSegment::_storeType(const armem::wm::ProviderSegment& p) - { - if (id().providerSegmentName.empty()) - { - ARMARX_WARNING << "During storage of segment '" << p.id().str() << "' I noticed that the corresponding LTM has no id set. " << - "I set the id of the LTM to the same name, however this should not happen!"; - id().providerSegmentName = p.id().providerSegmentName; - } - - auto defaultMode = MemoryEncodingMode::FILESYSTEM; - - auto defaultMPath = getMemoryBasePathForMode(defaultMode, 0); - auto defaultRelPath = getRelativePathForMode(defaultMode); - if (!util::checkIfFolderExists(defaultMPath, defaultRelPath)) - { - ARMARX_WARNING << "The segment folder for segment '"+id().str()+"'was not created. I will create the folder by myself, however it seems like there is a bug in the ltm pipeline."; - util::ensureFolderExists(defaultMPath, defaultRelPath, true); - } - - if(p.hasAronType()) - { - auto& conv = processors->defaultTypeConverter; - - auto [vec, modeSuffix] = conv.convert(p.aronType()); - ARMARX_CHECK_EMPTY(modeSuffix); - std::filesystem::path relTypePath = defaultRelPath / (constantes::TYPE_FILENAME + conv.suffix); - util::writeDataToFileRepeated(defaultMPath, relTypePath, vec); - } - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.h b/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.h deleted file mode 100644 index dfa7c42714310a042dc344c043794eca4536ea00..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/ProviderSegment.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include <filesystem> - -// Base Class -#include "../base/detail/ProviderSegmentBase.h" -#include "detail/DiskStorage.h" - -#include "Entity.h" - -namespace armarx::armem::server::ltm::disk -{ - class ProviderSegment : - public ProviderSegmentBase<Entity>, - public DiskMemoryItem - { - public: - ProviderSegment(const std::filesystem::path& parentPath, const MemoryID& id, const std::shared_ptr<Processors>& p, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e); - - bool forEachEntity(std::function<void(Entity&)> func) const override; - - std::shared_ptr<Entity> findEntity(const std::string&) const override; - - protected: - void _loadAllReferences(armem::wm::ProviderSegment&) override; - void _resolve(armem::wm::ProviderSegment&) override; - void _store(const armem::wm::ProviderSegment&) override; - void _storeType(const armem::wm::ProviderSegment&) override; - - private: - MemoryEncodingMode currentMode; - unsigned long currentExport; - }; - -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/DiskStorage.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/DiskStorage.cpp deleted file mode 100644 index 284f289842b88c888195ac4ac8f5d48a196e9a66..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/DiskStorage.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Header -#include "DiskStorage.h" - -// Simox -#include <SimoxUtility/algorithm/string.h> - -// ArmarX -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/logging/Logging.h> -#include <ArmarXCore/core/exceptions/LocalException.h> - -namespace armarx::armem::server::ltm::disk -{ - //const std::string DiskMemoryItem::Prefix = "_"; - //const std::string DiskMemoryItem::PrefixEscaped = "__"; - - const std::string DiskMemoryItem::MEMORY_EXPORT_SUFFIX = "_"; - const std::map<std::string, std::string> DiskMemoryItem::EscapeTable = { - {"/", "|"} - }; - - DiskMemoryItem::DiskMemoryItem(const std::filesystem::path& memoryParentPath, const std::string& memoryName, const std::filesystem::path relativePath) : - memoryParentPath(memoryParentPath), - escapedMemoryName(memoryName), - relativeSegmentPath(relativePath) - { - } - - std::filesystem::path DiskMemoryItem::getMemoryBasePathForMode(const MemoryEncodingMode m, const unsigned long e) const - { - std::string escapedMemoryNameSuffixed = escapedMemoryName; - if (e > 0) - { - escapedMemoryNameSuffixed = escapedMemoryName + MEMORY_EXPORT_SUFFIX + std::to_string(e); - } - - switch(m) - { - case MemoryEncodingMode::FILESYSTEM: - return memoryParentPath / escapedMemoryNameSuffixed; - case MemoryEncodingMode::MINIZIP: - return memoryParentPath / (escapedMemoryNameSuffixed + minizip::util::MINIZIP_SUFFIX); - } - return ""; - } - - std::filesystem::path DiskMemoryItem::getRelativePathForMode(const MemoryEncodingMode m) const - { - switch(m) // ensure a tailing "/" - { - case MemoryEncodingMode::FILESYSTEM: - return relativeSegmentPath / ""; - case MemoryEncodingMode::MINIZIP: - return std::filesystem::path(escapedMemoryName) / relativeSegmentPath / ""; - } - return ""; - } - - std::string DiskMemoryItem::EscapeSegmentName(const std::string& segmentName) - { - std::string ret = segmentName; - //simox::alg::replace_all(ret, Prefix, PrefixEscaped); - for (const auto& [s, r] : EscapeTable) - { - ret = simox::alg::replace_all(ret, s, r); - } - return ret; - } - - std::string DiskMemoryItem::UnescapeSegmentName(const std::string& escapedName) - { - std::string ret = escapedName; - for (const auto& [s, r] : EscapeTable) // Here we assume that noone uses the replaced char usually in the segment name... TODO - { - ret = simox::alg::replace_all(ret, r, s); - } - return ret; - } -} diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/DiskStorage.h b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/DiskStorage.h deleted file mode 100644 index 2185220ec794b5506d4e909ed41a0073bca5c5b8..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/DiskStorage.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include <filesystem> -#include <map> -#include <string> - -// util -#include "util/util.h" - -namespace armarx::armem::server::ltm::disk -{ - class DiskMemoryItem - { - public: - enum class MemoryEncodingMode - { - FILESYSTEM = 0, - MINIZIP = 1 - }; - - DiskMemoryItem() = default; - DiskMemoryItem(const std::filesystem::path& memoryParentPath, const std::string& escapedMemoryName, const std::filesystem::path relativePath); - virtual ~DiskMemoryItem() = default; - - std::filesystem::path getMemoryBasePathForMode(const MemoryEncodingMode m = MemoryEncodingMode::FILESYSTEM, const unsigned long e = 0) const; - std::filesystem::path getRelativePathForMode(const MemoryEncodingMode m = MemoryEncodingMode::FILESYSTEM) const; - - protected: - static std::string EscapeSegmentName(const std::string& segmentName); - static std::string UnescapeSegmentName(const std::string& escapedName); - - protected: - //static const std::string PREFIX; - //static const std::string PREFIX_ESCAPED; - static const std::string MEMORY_EXPORT_SUFFIX; - static const std::map<std::string, std::string> EscapeTable; - - std::filesystem::path memoryParentPath; - std::string escapedMemoryName; - std::filesystem::path relativeSegmentPath; - }; -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/minizip_util.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/minizip_util.cpp deleted file mode 100644 index 2995afc21cba2caa75e5dc093398b900bb81e819..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/minizip_util.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include "minizip_util.h" - -namespace armarx::armem::server::ltm::disk -{ - namespace minizip::util - { - bool checkZipFile(const std::filesystem::path& pathToZip) - { - bool ret = false; - zipFile z = NULL; - if (std::filesystem::exists(pathToZip)) - { - if (std::filesystem::is_regular_file(pathToZip) && pathToZip.extension() == MINIZIP_SUFFIX) - { - z = zipOpen64(pathToZip.string().c_str(), APPEND_STATUS_ADDINZIP); - ret = (bool) z; - zipClose(z, NULL); - } - } - return ret; - } - - zipFile ensureZipFile(const std::filesystem::path& pathToZip, bool createIfNotExistent) - { - zipFile z = NULL; - if (!checkZipFile(pathToZip)) - { - if (createIfNotExistent) - { - z = zipOpen64(pathToZip.string().c_str(), APPEND_STATUS_CREATE); - } - else - { - throw error::ArMemError("Could not find zip file: " + pathToZip.string()); - } - } - else - { - z = zipOpen64(pathToZip.string().c_str(), APPEND_STATUS_ADDINZIP); - } - - if (!z) - { - throw error::ArMemError("Unknown error occured during opening zip file: " + pathToZip.string()); - } - return z; - } - - unzFile getUnzFile(const std::filesystem::path& pathToZip) - { - unzFile z = NULL; - if (std::filesystem::exists(pathToZip)) - { - if (std::filesystem::is_regular_file(pathToZip) && pathToZip.extension() == MINIZIP_SUFFIX) - { - z = unzOpen64(pathToZip.string().c_str()); - } - else - { - throw error::ArMemError("Existing file is not a zip file: " + pathToZip.string()); - } - } - - // if z is NULL then the zip file might be empty - - return z; - } - - bool checkIfElementInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p) - { - if (!checkZipFile(pathToZip)) return false; - auto uzf = getUnzFile(pathToZip); - - bool ret = (unzLocateFile(uzf, p.string().c_str(), MINIZIP_CASE_SENSITIVITY) == UNZ_OK); - - unzClose(uzf); - return ret; - } - - void ensureElementInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p, bool createIfNotExistent) - { - auto zf = ensureZipFile(pathToZip, createIfNotExistent); - auto uzf = getUnzFile(pathToZip); - - if (auto r = unzLocateFile(uzf, p.string().c_str(), MINIZIP_CASE_SENSITIVITY); r != UNZ_OK) - { - if (createIfNotExistent) - { - zip_fileinfo zfi; - zipOpenNewFileInZip64(zf, p.string().c_str(), &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 1); - zipCloseFileInZip(zf); - } - else - { - unzClose(uzf); - zipClose(zf, NULL); - throw error::ArMemError("Could not find element '" + p.string() + "' in zip file: " + pathToZip.string()); - } - } - // else folder exists - - unzClose(uzf); - zipClose(zf, NULL); - } - - void ensureFolderInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p, bool createIfNotExistent) - { - if (!p.filename().empty()) - { - throw error::ArMemError("The specified path is not a folder (it needs tailing /): " + p.string()); - } - - ensureElementInZipExists(pathToZip, p, createIfNotExistent); - } - - void ensureFileInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p) - { - if (p.filename().empty()) - { - throw error::ArMemError("The specified path is not a file (it needs a filename): " + p.string()); - } - - ensureElementInZipExists(pathToZip, p, true); - } - - bool checkIfFolderInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p) - { - if (!p.filename().empty()) - { - throw error::ArMemError("The specified path is not a folder (it needs tailing /): " + p.string()); - } - - return checkIfElementInZipExists(pathToZip, p); - } - - bool checkIfFileInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p) - { - if (p.filename().empty()) - { - throw error::ArMemError("The specified path is not a file (it needs a filename): " + p.string()); - } - - return checkIfElementInZipExists(pathToZip, p); - } - - void writeDataInFileInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path& p, const std::vector<unsigned char>& data) - { - auto zf = ensureZipFile(pathToZip); - - zip_fileinfo zfi; - if(zipOpenNewFileInZip64(zf, p.string().c_str(), &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 1) == Z_OK) - { - if(zipWriteInFileInZip(zf, data.data(), data.size()) != Z_OK) - { - throw error::ArMemError("Could not write a file '"+p.string()+"' to zip '" + pathToZip.string() + "'."); - } - } - else - { - throw error::ArMemError("Could not add a new file '"+p.string()+"' to zip '" + pathToZip.string() + "'."); - } - zipCloseFileInZip(zf); - zipClose(zf, NULL); - } - - std::vector<unsigned char> readDataFromFileInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path& p) - { - auto uzf = getUnzFile(pathToZip); - if (unzLocateFile(uzf, p.string().c_str(), MINIZIP_CASE_SENSITIVITY) == UNZ_OK) // set current file - { - // File located - unz_file_info uzfi; - if (unzGetCurrentFileInfo(uzf, &uzfi, NULL, 0, NULL, 0, NULL, 0) == UNZ_OK) - { - std::vector<unsigned char> data(uzfi.uncompressed_size); - - if (unzOpenCurrentFile(uzf) == UNZ_OK) // open current file - { - if (unzReadCurrentFile(uzf, data.data(), uzfi.uncompressed_size) == UNZ_OK) // read file in buffer - { - unzCloseCurrentFile(uzf); - unzClose(uzf); - return data; - } - } - } - } - unzClose(uzf); - throw error::ArMemError("Could not read data from zip file '" + pathToZip.string() + "' and internal path '" + p.string() + "'."); - } - - std::vector<std::string> getAllDirectoriesInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path p) - { - std::vector<std::string> ret; - - unzFile uzf = getUnzFile(pathToZip); - if (unzLocateFile(uzf, p.string().c_str(), MINIZIP_CASE_SENSITIVITY) == UNZ_OK) // set current file - { - while(unzGoToNextFile(uzf) == UNZ_OK) - { - unz_file_info uzfi; - unzGetCurrentFileInfo(uzf, &uzfi, NULL, 0, NULL, 0, NULL, 0); // get file info - std::vector<char> filenameVec(uzfi.size_filename); - unzGetCurrentFileInfo(uzf, NULL, filenameVec.data(), uzfi.size_filename, NULL, 0, NULL, 0); // get file name - std::string filename(filenameVec.begin(), filenameVec.end()); - - auto pString = p.string(); - if (!simox::alg::starts_with(filename, pString)) - { - // we moved out of the folder. Abort - break; - } - - std::string filenameWithoutPrefix = simox::alg::remove_prefix(filename, pString); - - if (!simox::alg::ends_with(filenameWithoutPrefix, "/")) - { - // this is not a directory - continue; - } - - if (simox::alg::count(filenameWithoutPrefix, "/") != 1) - { - // we are in a subfolder of the subfolder - continue; - } - - ret.push_back(filenameWithoutPrefix); - } - } - return ret; - } - - std::vector<std::string> getAllFilesInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path p) - { - std::vector<std::string> ret; - - unzFile uzf = getUnzFile(pathToZip); - if (unzLocateFile(uzf, p.string().c_str(), MINIZIP_CASE_SENSITIVITY) == UNZ_OK) // set current file - { - while(unzGoToNextFile(uzf) == UNZ_OK) - { - unz_file_info uzfi; - unzGetCurrentFileInfo(uzf, &uzfi, NULL, 0, NULL, 0, NULL, 0); // get file info - std::vector<char> filenameVec(uzfi.size_filename); - unzGetCurrentFileInfo(uzf, NULL, filenameVec.data(), uzfi.size_filename, NULL, 0, NULL, 0); // get file name - std::string filename(filenameVec.begin(), filenameVec.end()); - - auto pString = p.string(); - if (!simox::alg::starts_with(filename, pString)) - { - // we moved out of the folder. Abort - break; - } - - std::string filenameWithoutPrefix = simox::alg::remove_prefix(filename, pString); - - if (simox::alg::ends_with(filenameWithoutPrefix, "/")) - { - // this is a directory - continue; - } - - if (simox::alg::count(filenameWithoutPrefix, "/") != 1) - { - // we are in a subfolder of the subfolder - continue; - } - - ret.push_back(filenameWithoutPrefix); - } - } - return ret; - } - } -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/minizip_util.h b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/minizip_util.h deleted file mode 100644 index 99ebab93572afd50cccb194c1aa827635a6c585d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/minizip_util.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -// STD / STL -#include <filesystem> -#include <iostream> - -#include <minizip/zip.h> -#include <minizip/unzip.h> - -#include <SimoxUtility/algorithm/string.h> - -#include "../../../../../core/error.h" - -namespace armarx::armem::server::ltm::disk -{ - namespace minizip::util - { - const std::string MINIZIP_SUFFIX = ".zip"; - const int MINIZIP_CASE_SENSITIVITY = 1; - - bool checkZipFile(const std::filesystem::path& pathToZip); - - zipFile ensureZipFile(const std::filesystem::path& pathToZip, bool createIfNotExistent = true); - - unzFile getUnzFile(const std::filesystem::path& pathToZip); - - bool checkIfElementInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p); - - void ensureElementInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p, bool createIfNotExistent = true); - - void ensureFolderInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p, bool createIfNotExistent = true); - - void ensureFileInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p); - - bool checkIfFolderInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p); - - bool checkIfFileInZipExists(const std::filesystem::path& pathToZip, const std::filesystem::path& p); - - void writeDataInFileInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path& p, const std::vector<unsigned char>& data); - - std::vector<unsigned char> readDataFromFileInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path& p); - - std::vector<std::string> getAllDirectoriesInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path p); - - std::vector<std::string> getAllFilesInZipFile(const std::filesystem::path& pathToZip, const std::filesystem::path p); - } -} // namespace armarx::armem::server::ltm::disk diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp b/source/RobotAPI/libraries/armem/server/ltm/legacy/util/filesystem_util.cpp similarity index 96% rename from source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp rename to source/RobotAPI/libraries/armem/server/ltm/legacy/util/filesystem_util.cpp index 1a40e26a04923bccb123b4b07f00ab9be190efa9..d3b307eab0c5bb8cc9b8487d7429fc46ab2a76a6 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/legacy/util/filesystem_util.cpp @@ -118,4 +118,5 @@ namespace armarx::armem::server::ltm::disk return ret; } } -} // namespace armarx::armem::server::ltm::disk +} // namespace armarx::armem::server::ltm::diskfile:///home/fabian/code/armarx/RobotAPI/source/RobotAPI/libraries/armem/server/ltm/legacy/util/util.h + diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.h b/source/RobotAPI/libraries/armem/server/ltm/legacy/util/filesystem_util.h similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.h rename to source/RobotAPI/libraries/armem/server/ltm/legacy/util/filesystem_util.h diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/forgetter/Forgetter.cpp b/source/RobotAPI/libraries/armem/server/ltm/legacy/util/minizip_util.cpp similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/base/forgetter/Forgetter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/legacy/util/minizip_util.cpp diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/forgetter/Forgetter.h b/source/RobotAPI/libraries/armem/server/ltm/legacy/util/minizip_util.h similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/base/forgetter/Forgetter.h rename to source/RobotAPI/libraries/armem/server/ltm/legacy/util/minizip_util.h diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/util.cpp b/source/RobotAPI/libraries/armem/server/ltm/legacy/util/util.cpp similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/util.cpp rename to source/RobotAPI/libraries/armem/server/ltm/legacy/util/util.cpp diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/util.h b/source/RobotAPI/libraries/armem/server/ltm/legacy/util/util.h similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/util.h rename to source/RobotAPI/libraries/armem/server/ltm/legacy/util/util.h diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b4f5afa549ab239b91d05ceafe3e49e13c2b36d --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.cpp @@ -0,0 +1,35 @@ +#include "Processors.h" + +#include <ArmarXCore/core/logging/Logging.h> + +#include "converter/data/image/exr/ExrConverter.h" +#include "converter/data/image/png/PngConverter.h" +#include "extractor/imageExtractor/DepthImageExtractor.h" +#include "extractor/imageExtractor/ImageExtractor.h" +#include "filter/equalityFilter/EqualityFilter.h" +#include "filter/frequencyFilter/FrequencyFilter.h" + +namespace armarx::armem::server::ltm +{ + void + Processors::configure(const nlohmann::json& config) + { + // Filters: + if (config.contains(processor::filter::SnapshotFrequencyFilter::NAME)) + { + ARMARX_IMPORTANT << "ADDING SNAPSHOT FILTER"; + auto f = std::make_unique<processor::filter::SnapshotFrequencyFilter>(); + f->configure(config[processor::filter::SnapshotFrequencyFilter::NAME]); + snapFilters.push_back(std::move(f)); + } + + // Converters + if (config.contains(processor::converter::data::image::PngConverter::NAME)) + { + ARMARX_IMPORTANT << "ADDING IMG CONVERTER"; + auto f = std::make_unique<processor::converter::data::image::PngConverter>(); + f->configure(config[processor::converter::data::image::PngConverter::NAME]); + converters.push_back(std::move(f)); + } + } +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.h b/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.h new file mode 100644 index 0000000000000000000000000000000000000000..0f4186a2c872f30d6ef1bb9b3ce7652232e0c669 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.h @@ -0,0 +1,43 @@ +#pragma once + +#include <map> +#include <mutex> +#include <optional> +#include <string> + +#include <RobotAPI/libraries/armem/core/MemoryID.h> + +#include "converter/data/Converter.h" +#include "converter/data/object/json/JsonConverter.h" +#include "converter/type/object/json/JsonConverter.h" +#include "extractor/Extractor.h" +#include "filter/Filter.h" + +namespace armarx::armem::server::ltm +{ + /// all necessary classes to filter and convert an entry of the ltm to some other format(s) + class Processors + { + public: + Processors() = default; + + void configure(const nlohmann::json& config); + + public: + // Unique Memory Filters + std::vector<std::unique_ptr<processor::MemoryFilter>> memFilters; + + // Unique Snapshot filters + std::vector<std::unique_ptr<processor::SnapshotFilter>> snapFilters; + + // Special Extractors + std::vector<std::unique_ptr<processor::Extractor>> extractors; + + // Special Converters + std::vector<std::unique_ptr<processor::DataConverter>> converters; + + // Default converters + processor::converter::data::object::JsonConverter defaultObjectConverter; + processor::converter::type::object::JsonConverter defaultTypeConverter; + }; +} // namespace armarx::armem::server::ltm diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/Converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f32e7fc341ec3ea9ea9d395cc737af4c3b5989ee --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/Converter.cpp @@ -0,0 +1,9 @@ +#include "Converter.h" + +namespace armarx::armem::server::ltm::processor +{ + void + DataConverter::configure(const nlohmann::json& json) + { + } +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/Converter.h new file mode 100644 index 0000000000000000000000000000000000000000..b5e4eee857c0873d8c66c83f7bdbc2faf672d13a --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/Converter.h @@ -0,0 +1,56 @@ +#pragma once + +// STD/STL +#include <memory> + +// Simox +#include <SimoxUtility/json.h> + +// ArmarX +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +#include "../../extractor/Extractor.h" + +namespace armarx::armem::server::ltm::processor +{ + class DataConverter + { + public: + enum class ConverterType + { + Str, + Binary + }; + + struct ConversionResult + { + std::vector<unsigned char> data; + std::string suffix; + }; + + DataConverter(const ConverterType t, + const std::string& id, + const std::string& s, + const aron::type::Descriptor c, + std::unique_ptr<Extractor>&& ex) : + type(t), identifier(id), suffix(s), convertsType(c), extractor(std::move(ex)) + { + } + + virtual ~DataConverter() = default; + + virtual ConversionResult convert(const aron::data::VariantPtr& data) = 0; + virtual aron::data::VariantPtr convert(const ConversionResult&, + const armarx::aron::Path& p) = 0; + + virtual void configure(const nlohmann::json& json); + + public: + const ConverterType type; + const std::string identifier; + const std::string suffix; + const aron::type::Descriptor convertsType; + + const std::unique_ptr<Extractor> extractor; + }; +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/Converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3975f36dd82d57b6a2adb43ae9f826bc8acb372 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/Converter.cpp @@ -0,0 +1,24 @@ +#include "Converter.h" + +namespace armarx::armem::server::ltm::processor::converter::data +{ + void + ImageConverter::configure(const nlohmann::json& json) + { + } + + ImageConverter::ConversionResult + ImageConverter::convert(const aron::data::VariantPtr& data) + { + auto d = aron::data::NDArray::DynamicCastAndCheck(data); + return _convert(d); + } + + aron::data::VariantPtr + ImageConverter::convert(const ConversionResult& data, const armarx::aron::Path& p) + { + auto d = _convert(data, p); + return d; + } + +} // namespace armarx::armem::server::ltm::processor::converter::data diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/Converter.h new file mode 100644 index 0000000000000000000000000000000000000000..9daec4a624b8a4bd35aee44fb9639014f122a044 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/Converter.h @@ -0,0 +1,40 @@ +#pragma once + +// STD/STL +#include <memory> + +// BaseClass +#include "../Converter.h" + +// ArmarX +#include <RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h> + +#include "../../../extractor/imageExtractor/ImageExtractor.h" + +namespace armarx::armem::server::ltm::processor::converter::data +{ + class ImageConverter : public DataConverter + { + public: + ImageConverter(const ConverterType t, + const std::string& id, + const std::string& s, + std::unique_ptr<Extractor>&& ex) : + DataConverter(t, id, s, aron::type::Descriptor::IMAGE, std::move(ex)) + { + } + + virtual ~ImageConverter() = default; + + ConversionResult convert(const aron::data::VariantPtr& data) final; + aron::data::VariantPtr convert(const ConversionResult& data, + const armarx::aron::Path& p) final; + + void configure(const nlohmann::json& json) override; + + protected: + virtual ConversionResult _convert(const aron::data::NDArrayPtr& data) = 0; + virtual aron::data::NDArrayPtr _convert(const ConversionResult& data, + const armarx::aron::Path& p) = 0; + }; +} // namespace armarx::armem::server::ltm::processor::converter::data diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/exr/ExrConverter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/exr/ExrConverter.cpp similarity index 64% rename from source/RobotAPI/libraries/armem/server/ltm/base/converter/image/exr/ExrConverter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/exr/ExrConverter.cpp index 4cc2c2868627ef8883ee5167e24d558d68a44e15..f55138796815ead0f27af90bbf9a4d8fc6e9c089 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/exr/ExrConverter.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/exr/ExrConverter.cpp @@ -7,9 +7,9 @@ #include <RobotAPI/libraries/aron/converter/opencv/OpenCVConverter.h> -namespace armarx::armem::server::ltm::converter::image +namespace armarx::armem::server::ltm::processor::converter::data::image { - std::pair<std::vector<unsigned char>, std::string> + ExrConverter::ConversionResult ExrConverter::_convert(const aron::data::NDArrayPtr& data) { ARMARX_CHECK_NOT_NULL(data); @@ -22,15 +22,13 @@ namespace armarx::armem::server::ltm::converter::image ARMARX_CHECK_EQUAL(shape[2], 4); cv::imencode(".exr", img, buffer); - return std::make_pair(buffer, ""); + return {buffer, ""}; } aron::data::NDArrayPtr - ExrConverter::_convert(const std::vector<unsigned char>& data, - const armarx::aron::Path& p, - const std::string& m) + ExrConverter::_convert(const ConversionResult& data, const armarx::aron::Path& p) { - cv::Mat img = cv::imdecode(data, cv::IMREAD_ANYDEPTH); + cv::Mat img = cv::imdecode(data.data, cv::IMREAD_ANYDEPTH); return aron::data::converter::AronOpenCVConverter::ConvertFromMat(img, p); } -} // namespace armarx::armem::server::ltm::converter::image +} // namespace armarx::armem::server::ltm::processor::converter::data::image diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/exr/ExrConverter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/exr/ExrConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..ce9cc7ab220fd794442b69c4b826b647122d022e --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/exr/ExrConverter.h @@ -0,0 +1,25 @@ +#pragma once + +// Base Class +#include "../../../../extractor/imageExtractor/DepthImageExtractor.h" +#include "../Converter.h" + +namespace armarx::armem::server::ltm::processor::converter::data::image +{ + class ExrConverter : public ImageConverter + { + public: + ExrConverter() : + ImageConverter(ConverterType::Binary, + "depthimage", + ".exr", + std::make_unique<extractor::DepthImageExtractor>()) + { + } + + protected: + ConversionResult _convert(const aron::data::NDArrayPtr& data) final; + aron::data::NDArrayPtr _convert(const ConversionResult& data, + const armarx::aron::Path& p) final; + }; +} // namespace armarx::armem::server::ltm::processor::converter::data::image diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/png/PngConverter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/png/PngConverter.cpp similarity index 65% rename from source/RobotAPI/libraries/armem/server/ltm/base/converter/image/png/PngConverter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/png/PngConverter.cpp index e9ba33ead6943777f2bac696421ad681590916e2..b9d4a92d4514075c72d9f70948ab9d39a7428d65 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/image/png/PngConverter.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/png/PngConverter.cpp @@ -7,9 +7,14 @@ #include <RobotAPI/libraries/aron/converter/opencv/OpenCVConverter.h> -namespace armarx::armem::server::ltm::converter::image +namespace armarx::armem::server::ltm::processor::converter::data::image { - std::pair<std::vector<unsigned char>, std::string> + void + PngConverter::configure(const nlohmann::json& json) + { + } + + PngConverter::ConversionResult PngConverter::_convert(const aron::data::NDArrayPtr& data) { ARMARX_CHECK_NOT_NULL(data); @@ -25,40 +30,38 @@ namespace armarx::armem::server::ltm::converter::image { cv::cvtColor(img, img, CV_RGB2BGR); cv::imencode(suffix, img, buffer); - return std::make_pair(buffer, ".rgb"); + return {buffer, ".rgb"}; } if (shape[2] == 1) // its probably a grayscale image { cv::imencode(suffix, img, buffer); - return std::make_pair(buffer, ".gs"); + return {buffer, ".gs"}; } // try to export without conversion cv::imencode(suffix, img, buffer); - return std::make_pair(buffer, ""); + return {buffer, ""}; } aron::data::NDArrayPtr - PngConverter::_convert(const std::vector<unsigned char>& data, - const armarx::aron::Path& p, - const std::string& m) + PngConverter::_convert(const ConversionResult& data, const armarx::aron::Path& p) { - if (m == ".rgb") + if (data.suffix == ".rgb") { - cv::Mat img = cv::imdecode(data, cv::IMREAD_COLOR); + cv::Mat img = cv::imdecode(data.data, cv::IMREAD_COLOR); cv::cvtColor(img, img, CV_BGR2RGB); return aron::data::converter::AronOpenCVConverter::ConvertFromMat(img, p); } - if (m == ".gs") + if (data.suffix == ".gs") { - cv::Mat img = cv::imdecode(data, cv::IMREAD_GRAYSCALE); + cv::Mat img = cv::imdecode(data.data, cv::IMREAD_GRAYSCALE); return aron::data::converter::AronOpenCVConverter::ConvertFromMat(img, p); } // try to load without conversion - cv::Mat img = cv::imdecode(data, cv::IMREAD_ANYCOLOR); + cv::Mat img = cv::imdecode(data.data, cv::IMREAD_ANYCOLOR); return aron::data::converter::AronOpenCVConverter::ConvertFromMat(img, p); } -} // namespace armarx::armem::server::ltm::converter::image +} // namespace armarx::armem::server::ltm::processor::converter::data::image diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/png/PngConverter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/png/PngConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..8fb622d281147068c2c01d4902258867ce3545e3 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/image/png/PngConverter.h @@ -0,0 +1,29 @@ +#pragma once + +// Base Class +#include "../../../../extractor/imageExtractor/ImageExtractor.h" +#include "../Converter.h" + +namespace armarx::armem::server::ltm::processor::converter::data::image +{ + class PngConverter : public ImageConverter + { + public: + static const constexpr char* NAME = "PngConverter"; + + PngConverter() : + ImageConverter(ConverterType::Binary, + "image", + ".png", + std::make_unique<extractor::ImageExtractor>()) + { + } + + void configure(const nlohmann::json& json) override; + + protected: + ConversionResult _convert(const aron::data::NDArrayPtr& data) final; + aron::data::NDArrayPtr _convert(const ConversionResult& data, + const armarx::aron::Path& p) final; + }; +} // namespace armarx::armem::server::ltm::processor::converter::data::image diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/Converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c710675a99277631478ff97ccae0147ad5c025b7 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/Converter.cpp @@ -0,0 +1,20 @@ +#include "Converter.h" + +namespace armarx::armem::server::ltm::processor::converter::data +{ + + ObjectConverter::ConversionResult + ObjectConverter::convert(const aron::data::VariantPtr& data) + { + auto d = aron::data::Dict::DynamicCastAndCheck(data); + return _convert(d); + } + + aron::data::VariantPtr + ObjectConverter::convert(const ConversionResult& data, const armarx::aron::Path& p) + { + auto d = _convert(data, p); + return d; + } + +} // namespace armarx::armem::server::ltm::processor::converter::data diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/Converter.h new file mode 100644 index 0000000000000000000000000000000000000000..9b46ad4341fd464bfca5e90a9416925b13c7b86d --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/Converter.h @@ -0,0 +1,33 @@ +#pragma once + +// STD/STL +#include <memory> + +// BaseClass +#include "../Converter.h" + +// ArmarX +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +namespace armarx::armem::server::ltm::processor::converter::data +{ + class ObjectConverter : public DataConverter + { + public: + ObjectConverter(const ConverterType t, const std::string& id, const std::string& s) : + DataConverter(t, id, s, aron::type::Descriptor::OBJECT, nullptr) + { + } + + virtual ~ObjectConverter() = default; + + ConversionResult convert(const aron::data::VariantPtr& data) final; + aron::data::VariantPtr convert(const ConversionResult& data, + const armarx::aron::Path& p) final; + + protected: + virtual ConversionResult _convert(const aron::data::DictPtr& data) = 0; + virtual aron::data::DictPtr _convert(const ConversionResult& data, + const armarx::aron::Path& p) = 0; + }; +} // namespace armarx::armem::server::ltm::processor::converter::data diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/bson/BsonConverter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/bson/BsonConverter.cpp similarity index 53% rename from source/RobotAPI/libraries/armem/server/ltm/base/converter/object/bson/BsonConverter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/bson/BsonConverter.cpp index 4155808d3c7dc5818bfb48112a6e77f41a74b681..010fd1406996c3b44aa873e31e89934352483e85 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/bson/BsonConverter.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/bson/BsonConverter.cpp @@ -1,16 +1,17 @@ #include "BsonConverter.h" -#include <bsoncxx/json.hpp> -#include <bsoncxx/builder/stream/helpers.hpp> -#include <bsoncxx/builder/stream/document.hpp> #include <bsoncxx/builder/stream/array.hpp> +#include <bsoncxx/builder/stream/document.hpp> +#include <bsoncxx/builder/stream/helpers.hpp> +#include <bsoncxx/json.hpp> -namespace armarx::armem::server::ltm::converter::object +namespace armarx::armem::server::ltm::processor::converter::data::object { namespace bsoncxxbuilder = bsoncxx::builder::stream; namespace bsoncxxdoc = bsoncxx::document; - std::pair<std::vector<unsigned char>, std::string> BsonConverter::_convert(const aron::data::DictPtr& data) + BsonConverter::ConversionResult + BsonConverter::_convert(const aron::data::DictPtr& data) { auto [jsonVec, str] = jsonConverter.convert(data); std::string json(jsonVec.begin(), jsonVec.end()); @@ -21,16 +22,21 @@ namespace armarx::armem::server::ltm::converter::object { std::memcpy(bson.data(), view.data(), view.length()); } - return std::make_pair(bson, str); + return {bson, str}; } - aron::data::DictPtr BsonConverter::_convert(const std::vector<unsigned char>& data, const armarx::aron::Path& p, const std::string& m) + aron::data::DictPtr + BsonConverter::_convert(const ConversionResult& data, const armarx::aron::Path& p) { - bsoncxx::document::view view(data.data(), data.size()); + bsoncxx::document::view view(data.data.data(), data.data.size()); nlohmann::json json = bsoncxx::to_json(view); - std::string str = json.dump(2); - std::vector<unsigned char> jsonVec(str.begin(), str.end()); - auto v = jsonConverter.convert(jsonVec, p, m); + std::string str = json.dump(); + + ConversionResult j; + j.data = std::vector<unsigned char>(str.begin(), str.end()); + j.suffix = data.suffix; + + auto v = jsonConverter.convert(j, p); return aron::data::Dict::DynamicCast(v); } -} +} // namespace armarx::armem::server::ltm::processor::converter::data::object diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/bson/BsonConverter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/bson/BsonConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..d0f18daddeb5fd5a23ddbc10cca9dfc2d42182e5 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/bson/BsonConverter.h @@ -0,0 +1,29 @@ +#pragma once + +// Base Class +#include "../Converter.h" + +// ArmarX +#include "../json/JsonConverter.h" + +namespace armarx::armem::server::ltm::processor::converter::data::object +{ + class BsonConverter; + using BsonConverterPtr = std::shared_ptr<BsonConverter>; + + class BsonConverter : public ObjectConverter + { + public: + BsonConverter() : ObjectConverter(ConverterType::Binary, "dict", ".bson") + { + } + + protected: + ConversionResult _convert(const aron::data::DictPtr& data) final; + aron::data::DictPtr _convert(const ConversionResult& data, + const armarx::aron::Path& p) final; + + private: + JsonConverter jsonConverter; + }; +} // namespace armarx::armem::server::ltm::processor::converter::data::object diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/json/JsonConverter.cpp similarity index 57% rename from source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/json/JsonConverter.cpp index 468a6afb8aaa39b6a0476746b7676e61e04eacd2..c22eebc62497ebed29ef5da5645d622a805606d2 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/converter/object/json/JsonConverter.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/json/JsonConverter.cpp @@ -4,25 +4,23 @@ #include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> -namespace armarx::armem::server::ltm::converter::object +namespace armarx::armem::server::ltm::processor::converter::data::object { - std::pair<std::vector<unsigned char>, std::string> + JsonConverter::ConversionResult JsonConverter::_convert(const aron::data::DictPtr& data) { nlohmann::json j = aron::data::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON(data); auto str = j.dump(2); - return std::make_pair(std::vector<unsigned char>(str.begin(), str.end()), ""); + return {std::vector<unsigned char>(str.begin(), str.end()), ""}; } aron::data::DictPtr - JsonConverter::_convert(const std::vector<unsigned char>& data, - const armarx::aron::Path& p, - const std::string&) + JsonConverter::_convert(const ConversionResult& data, const armarx::aron::Path& p) { - std::string str(data.begin(), data.end()); + std::string str(data.data.begin(), data.data.end()); nlohmann::json j = nlohmann::json::parse(str); return aron::data::converter::AronNlohmannJSONConverter::ConvertFromNlohmannJSONObject(j, p); } -} // namespace armarx::armem::server::ltm::converter::object +} // namespace armarx::armem::server::ltm::processor::converter::data::object diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/json/JsonConverter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/json/JsonConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..dff7d4dfbc0aaa4033cc08831b43a2ff4e7d4912 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/data/object/json/JsonConverter.h @@ -0,0 +1,23 @@ +#pragma once + +// Base Class +#include "../Converter.h" + +// Simox +#include <SimoxUtility/json.h> + +namespace armarx::armem::server::ltm::processor::converter::data::object +{ + class JsonConverter : public ObjectConverter + { + public: + JsonConverter() : ObjectConverter(ConverterType::Str, "dict", ".json") + { + } + + protected: + ConversionResult _convert(const aron::data::DictPtr& data) final; + aron::data::DictPtr _convert(const ConversionResult& data, + const armarx::aron::Path& p) final; + }; +} // namespace armarx::armem::server::ltm::processor::converter::data::object diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/Converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be24f0e4076e54807192e51fbfe5dc35a9a47155 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/Converter.cpp @@ -0,0 +1,9 @@ +#include "Converter.h" + +namespace armarx::armem::server::ltm::processor +{ + void + TypeConverter::configure(const nlohmann::json& json) + { + } +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/Converter.h new file mode 100644 index 0000000000000000000000000000000000000000..cc9cab4d83e8a03c51d22f80740464744f6499f1 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/Converter.h @@ -0,0 +1,35 @@ +#pragma once + +// STD/STL +#include <memory> + +// Simox +#include <SimoxUtility/json.h> + +// ArmarX +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +#include "../../extractor/Extractor.h" + +namespace armarx::armem::server::ltm::processor +{ + class TypeConverter + { + public: + TypeConverter(const std::string& id, const std::string& s) : identifier(id), suffix(s) + { + } + + virtual ~TypeConverter() = default; + + virtual std::pair<std::vector<unsigned char>, std::string> + convert(const aron::type::ObjectPtr& data) = 0; + virtual aron::type::ObjectPtr convert(const std::vector<unsigned char>& data, + const std::string&) = 0; + virtual void configure(const nlohmann::json& json); + + public: + const std::string identifier; + const std::string suffix; + }; +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/Converter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/Converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64a74c17e2e35cb738d0a5a46b44ecc97b7b5d82 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/Converter.cpp @@ -0,0 +1,5 @@ +#include "Converter.h" + +namespace armarx::armem::server::ltm::processor::converter::type +{ +} // namespace armarx::armem::server::ltm::processor::converter::type diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/Converter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/Converter.h new file mode 100644 index 0000000000000000000000000000000000000000..959af6cdfe7c5760b4afecfd1ab8ba1e2a0b2569 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/Converter.h @@ -0,0 +1,23 @@ +#pragma once + +// STD/STL +#include <memory> + +// Simox +#include <SimoxUtility/json.h> + +// ArmarX +#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h> + +#include "../Converter.h" + +namespace armarx::armem::server::ltm::processor::converter::type +{ + class ObjectConverter : public TypeConverter + { + public: + ObjectConverter(const std::string& id, const std::string& s) : TypeConverter(id, s) + { + } + }; +} // namespace armarx::armem::server::ltm::processor::converter::type diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/json/JsonConverter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/json/JsonConverter.cpp similarity index 84% rename from source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/json/JsonConverter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/json/JsonConverter.cpp index 41180550733fc601a4b209d5f22237d954b9fe08..dbea5198d6be6d08bddacc7023c6c75d0f3f63a2 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/typeConverter/json/JsonConverter.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/json/JsonConverter.cpp @@ -2,7 +2,7 @@ #include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> -namespace armarx::armem::server::ltm::converter::type +namespace armarx::armem::server::ltm::processor::converter::type::object { std::pair<std::vector<unsigned char>, std::string> JsonConverter::convert(const aron::type::ObjectPtr& data) @@ -21,4 +21,4 @@ namespace armarx::armem::server::ltm::converter::type return aron::type::converter::AronNlohmannJSONConverter::ConvertFromNlohmannJSONTypeObject( j); } -} // namespace armarx::armem::server::ltm::converter::type +} // namespace armarx::armem::server::ltm::processor::converter::type::object diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/json/JsonConverter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/json/JsonConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..886192287c98ab2241e45e1a416be910304f6bf8 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/converter/type/object/json/JsonConverter.h @@ -0,0 +1,23 @@ +#pragma once + +// Base Class +#include "../Converter.h" + +// Simox +#include <SimoxUtility/json.h> + +namespace armarx::armem::server::ltm::processor::converter::type::object +{ + class JsonConverter : public ObjectConverter + { + public: + JsonConverter() : ObjectConverter("dict", ".json") + { + } + + std::pair<std::vector<unsigned char>, std::string> + convert(const aron::type::ObjectPtr& data) final; + aron::type::ObjectPtr convert(const std::vector<unsigned char>& data, + const std::string&) final; + }; +} // namespace armarx::armem::server::ltm::processor::converter::type::object diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/Extractor.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/Extractor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6fab07ccc648b821d4cc4e6d32e1735221fad074 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/Extractor.cpp @@ -0,0 +1,9 @@ +#include "Extractor.h" + +namespace armarx::armem::server::ltm::processor +{ + void + Extractor::configure(const nlohmann::json& json) + { + } +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/Extractor.h b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/Extractor.h similarity index 57% rename from source/RobotAPI/libraries/armem/server/ltm/base/extractor/Extractor.h rename to source/RobotAPI/libraries/armem/server/ltm/processors/extractor/Extractor.h index 0fd5ca5adc0f82010d1a4f0ac85cc836301bac4f..aff91989a3f02c226aa6751c546158ef258ed698 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/Extractor.h +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/Extractor.h @@ -3,29 +3,34 @@ // STD/STL #include <memory> +// Simox +#include <SimoxUtility/json.h> + // ArmarX -#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> #include <RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> -namespace armarx::armem::server::ltm +namespace armarx::armem::server::ltm::processor { class Extractor { public: - struct Extraction + struct ExtractionResult { aron::data::DictPtr dataWithoutExtraction; std::map<std::string, aron::data::VariantPtr> extraction; }; - Extractor(const aron::type::Descriptor t, const std::string& id) : extractsType(t), identifier(id) {}; + Extractor(const aron::type::Descriptor t, const std::string& id) : + extractsType(t), identifier(id){}; virtual ~Extractor() = default; - virtual Extraction extract(aron::data::DictPtr& data) = 0; - virtual aron::data::DictPtr merge(Extraction& encoding) = 0; + virtual ExtractionResult extract(aron::data::DictPtr& data) = 0; + virtual aron::data::DictPtr merge(ExtractionResult& encoding) = 0; + + virtual void configure(const nlohmann::json& json); const aron::type::Descriptor extractsType; const std::string identifier; - bool enabled = false; }; -} +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/DepthImageExtractor.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/DepthImageExtractor.cpp similarity index 84% rename from source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/DepthImageExtractor.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/DepthImageExtractor.cpp index e0b4c1c6a59c48f9dc144239d4023eb85370b347..2222482857e3148659f3c00bdb978aa0e3125381 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/DepthImageExtractor.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/DepthImageExtractor.cpp @@ -1,7 +1,7 @@ #include "DepthImageExtractor.h" -namespace armarx::armem::server::ltm::extractor +namespace armarx::armem::server::ltm::processor::extractor { void DepthImageExtractorVisitor::visitDictOnEnter(Input& data) { @@ -28,20 +28,20 @@ namespace armarx::armem::server::ltm::extractor // A member is null. Simply ignore... } - Extractor::Extraction DepthImageExtractor::extract(aron::data::DictPtr& data) + Extractor::ExtractionResult DepthImageExtractor::extract(aron::data::DictPtr& data) { DepthImageExtractorVisitor visitor; aron::data::VariantPtr var = std::static_pointer_cast<aron::data::Variant>(data); aron::data::VariantPtr p; aron::data::visitRecursive(visitor, var); - Extraction encoding; + ExtractionResult encoding; encoding.dataWithoutExtraction = data; encoding.extraction = visitor.depthImages; return encoding; } - aron::data::DictPtr DepthImageExtractor::merge(Extraction& encoding) + aron::data::DictPtr DepthImageExtractor::merge(ExtractionResult& encoding) { return encoding.dataWithoutExtraction; } diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/DepthImageExtractor.h b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/DepthImageExtractor.h similarity index 57% rename from source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/DepthImageExtractor.h rename to source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/DepthImageExtractor.h index f7857c267f560159bce9d3e82aa230b103baf864..92d7f3fdfd9557d9dc696def70b5eb921b37c5ac 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/DepthImageExtractor.h +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/DepthImageExtractor.h @@ -1,11 +1,11 @@ #pragma once // Base Class -#include "../Extractor.h" - #include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h> -namespace armarx::armem::server::ltm::extractor +#include "../Extractor.h" + +namespace armarx::armem::server::ltm::processor::extractor { class DepthImageExtractorVisitor : public aron::data::RecursiveVariantVisitor { @@ -19,13 +19,9 @@ namespace armarx::armem::server::ltm::extractor class DepthImageExtractor : public Extractor { public: - DepthImageExtractor() : - Extractor(aron::type::Descriptor::IMAGE, "depthimage") - { - enabled = true; - }; + DepthImageExtractor() : Extractor(aron::type::Descriptor::IMAGE, "depthimage"){}; - virtual Extraction extract(aron::data::DictPtr& data) override; - virtual aron::data::DictPtr merge(Extraction& encoding) override; + ExtractionResult extract(aron::data::DictPtr& data) override; + aron::data::DictPtr merge(ExtractionResult& encoding) override; }; -} +} // namespace armarx::armem::server::ltm::processor::extractor diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/ImageExtractor.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/ImageExtractor.cpp similarity index 58% rename from source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/ImageExtractor.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/ImageExtractor.cpp index 767de1c5c2cb6ffc54ba90d421fbd95a03819197..b1fd4650973c0aaebd97c08fb32a533672756fa3 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/ImageExtractor.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/ImageExtractor.cpp @@ -1,9 +1,9 @@ #include "ImageExtractor.h" - -namespace armarx::armem::server::ltm::extractor +namespace armarx::armem::server::ltm::processor::extractor { - void ImageExtractorVisitor::visitDictOnEnter(Input& data) + void + ImageExtractorVisitor::visitDictOnEnter(Input& data) { ARMARX_CHECK_NOT_NULL(data); @@ -14,7 +14,10 @@ namespace armarx::armem::server::ltm::extractor { auto ndarray = aron::data::NDArray::DynamicCastAndCheck(child); auto shape = ndarray->getShape(); - if (shape.size() == 3 && (shape[2] == 3 || shape[2] == 1 /* 3 channel color or grayscale */) && std::accumulate(std::begin(shape), std::end(shape), 1, std::multiplies<int>()) > 200) // must be big enough to assume an image (instead of 4x4x4 poses) + if (shape.size() == 3 && + (shape[2] == 3 || shape[2] == 1 /* 3 channel color or grayscale */) && + std::accumulate(std::begin(shape), std::end(shape), 1, std::multiplies<int>()) > + 200) // must be big enough to assume an image (instead of 4x4x4 poses) { images[key] = ndarray; dict->setElement(key, nullptr); @@ -23,26 +26,29 @@ namespace armarx::armem::server::ltm::extractor } } - void ImageExtractorVisitor::visitUnknown(Input&) + void + ImageExtractorVisitor::visitUnknown(Input&) { // A member is null. Simply ignore... } - Extractor::Extraction ImageExtractor::extract(aron::data::DictPtr& data) + Extractor::ExtractionResult + ImageExtractor::extract(aron::data::DictPtr& data) { ImageExtractorVisitor visitor; aron::data::VariantPtr var = std::static_pointer_cast<aron::data::Variant>(data); aron::data::VariantPtr p; aron::data::visitRecursive(visitor, var); - Extraction encoding; + ExtractionResult encoding; encoding.dataWithoutExtraction = data; encoding.extraction = visitor.images; return encoding; } - aron::data::DictPtr ImageExtractor::merge(Extraction& encoding) + aron::data::DictPtr + ImageExtractor::merge(ExtractionResult& encoding) { return encoding.dataWithoutExtraction; } -} +} // namespace armarx::armem::server::ltm::extractor diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/ImageExtractor.h b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/ImageExtractor.h similarity index 57% rename from source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/ImageExtractor.h rename to source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/ImageExtractor.h index c8ef9669dea0e8d45ff0b7a100b276aa6c106b98..63381f62108ae68253a9fb9352a15e1d9c1e9d66 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/extractor/imageExtractor/ImageExtractor.h +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/extractor/imageExtractor/ImageExtractor.h @@ -1,11 +1,11 @@ #pragma once // Base Class -#include "../Extractor.h" - #include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h> -namespace armarx::armem::server::ltm::extractor +#include "../Extractor.h" + +namespace armarx::armem::server::ltm::processor::extractor { class ImageExtractorVisitor : public aron::data::RecursiveVariantVisitor { @@ -19,13 +19,9 @@ namespace armarx::armem::server::ltm::extractor class ImageExtractor : public Extractor { public: - ImageExtractor() : - Extractor(aron::type::Descriptor::IMAGE, "image") - { - enabled = true; - }; + ImageExtractor() : Extractor(aron::type::Descriptor::IMAGE, "image"){}; - virtual Extraction extract(aron::data::DictPtr& data) override; - virtual aron::data::DictPtr merge(Extraction& encoding) override; + ExtractionResult extract(aron::data::DictPtr& data) override; + aron::data::DictPtr merge(ExtractionResult& encoding) override; }; -} +} // namespace armarx::armem::server::ltm::processor::extractor diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/Filter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/Filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4c53c68888b5fe576572ef8166f9a20807d27ba --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/Filter.cpp @@ -0,0 +1,14 @@ +#include "Filter.h" + +namespace armarx::armem::server::ltm::processor +{ + void + MemoryFilter::configure(const nlohmann::json& json) + { + } + + void + SnapshotFilter::configure(const nlohmann::json& json) + { + } +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/Filter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/Filter.h similarity index 68% rename from source/RobotAPI/libraries/armem/server/ltm/base/filter/Filter.h rename to source/RobotAPI/libraries/armem/server/ltm/processors/filter/Filter.h index e75969bfa50b86379b1a0db47ab99c9f533ddc05..9d84c0a0ffdd976b54deb4585279d28161223da6 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/Filter.h +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/Filter.h @@ -3,11 +3,14 @@ // STD/STL #include <memory> +// Simox +#include <SimoxUtility/json.h> + // ArmarX #include <RobotAPI/libraries/armem/core/MemoryID.h> #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -namespace armarx::armem::server::ltm +namespace armarx::armem::server::ltm::processor { class MemoryFilter { @@ -16,8 +19,7 @@ namespace armarx::armem::server::ltm virtual ~MemoryFilter() = default; virtual bool accept(const armem::wm::Memory& e) = 0; - - bool enabled = false; + virtual void configure(const nlohmann::json& json); }; class SnapshotFilter @@ -27,7 +29,6 @@ namespace armarx::armem::server::ltm virtual ~SnapshotFilter() = default; virtual bool accept(const armem::wm::EntitySnapshot& e) = 0; - - bool enabled = false; + virtual void configure(const nlohmann::json& json); }; -} +} // namespace armarx::armem::server::ltm::processor diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92c8bb26ecf818492401e938b1c95cecb17519e1 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.cpp @@ -0,0 +1,51 @@ +#include "EqualityFilter.h" + +#include <IceUtil/Time.h> + +namespace armarx::armem::server::ltm::processor::filter +{ + bool + SnapshotSimilarityFilter::accept(const armem::wm::EntitySnapshot& e) + { + auto entityID = e.id().getEntityID(); + auto genMs = e.time().toMilliSecondsSinceEpoch(); + + long lastMs = 0; + std::vector<aron::data::DictPtr> lastData; + if (timestampLastCommitInMs.count(entityID) > 0) + { + lastData = dataLastCommit.at(entityID); + lastMs = timestampLastCommitInMs.at(entityID); + } + + + bool accept = false; + std::vector<aron::data::DictPtr> genData; + for (unsigned int i = 0; i != e.size(); ++i) + { + const auto& d = e.getInstance(i).data(); + genData.push_back(d); + + if (lastMs == 0 || + e.size() != lastData.size()) // nothing stored yet or we cannot compare + { + accept = true; + break; + } + + const auto& el = lastData.at(i); + if ((!d and el) || (d and !el) || (d && el && !(*d == *el))) // data unequal? + { + accept = true; + break; + } + } + + if (!accept) + return false; + + dataLastCommit[entityID] = genData; + timestampLastCommitInMs[entityID] = genMs; + return true; + } +} // namespace armarx::armem::server::ltm::filter diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.h similarity index 56% rename from source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.h rename to source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.h index 1ad630b4fb4add2cd318b6b3e8cdf5eddd52e5fa..203b1fe3fa87108b144c604a59ebf46e58ab350f 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.h +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.h @@ -1,7 +1,7 @@ #pragma once -#include <vector> #include <map> +#include <vector> // Base Class #include "../Filter.h" @@ -9,21 +9,22 @@ // Aron #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> -namespace armarx::armem::server::ltm::filter +namespace armarx::armem::server::ltm::processor::filter { - class SnapshotEqualityFilter : - public SnapshotFilter + class SnapshotSimilarityFilter : public SnapshotFilter { public: - SnapshotEqualityFilter() = default; + static const constexpr char* NAME = "SnapshotSimilarityFilter"; + + SnapshotSimilarityFilter() = default; virtual bool accept(const armem::wm::EntitySnapshot& e) override; public: - int maxWaitingTimeInMs = -1; + // TODO link aron/similarity private: std::map<MemoryID, std::vector<aron::data::DictPtr>> dataLastCommit; std::map<MemoryID, long> timestampLastCommitInMs; }; -} +} // namespace armarx::armem::server::ltm::processor::filter diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/frequencyFilter/FrequencyFilter.cpp similarity index 59% rename from source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/filter/frequencyFilter/FrequencyFilter.cpp index a98aab7f756e42be8d995401964170e64c83e537..56c7250c37988efd1b5fc824aec8aabd2e040a17 100644 --- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.cpp +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/frequencyFilter/FrequencyFilter.cpp @@ -2,9 +2,10 @@ #include <IceUtil/Time.h> -namespace armarx::armem::server::ltm::filter +namespace armarx::armem::server::ltm::processor::filter { - bool MemoryFrequencyFilter::accept(const armem::wm::Memory& e) + bool + MemoryFrequencyFilter::accept(const armem::wm::Memory& e) { auto now = armem::Time::Now().toMilliSecondsSinceEpoch(); if (waitingTimeInMs < 0 || (now - timestampLastCommitInMs) > waitingTimeInMs) @@ -15,7 +16,17 @@ namespace armarx::armem::server::ltm::filter return false; } - bool SnapshotFrequencyFilter::accept(const armem::wm::EntitySnapshot& e) + void + MemoryFrequencyFilter::configure(const nlohmann::json& json) + { + if (json.find(PARAM_WAITING_TIME) != json.end()) + { + waitingTimeInMs = json.at(PARAM_WAITING_TIME); + } + } + + bool + SnapshotFrequencyFilter::accept(const armem::wm::EntitySnapshot& e) { auto entityID = e.id().getEntityID(); auto genMs = e.time().toMilliSecondsSinceEpoch(); @@ -36,4 +47,13 @@ namespace armarx::armem::server::ltm::filter } return false; } -} + + void + SnapshotFrequencyFilter::configure(const nlohmann::json& json) + { + if (json.find(PARAM_WAITING_TIME) != json.end()) + { + waitingTimeInMs = json.at(PARAM_WAITING_TIME); + } + } +} // namespace armarx::armem::server::ltm::processor::filter diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/frequencyFilter/FrequencyFilter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/frequencyFilter/FrequencyFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..00ba1e9db0162d4d866a359c920008838ad5e279 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/frequencyFilter/FrequencyFilter.h @@ -0,0 +1,45 @@ +#pragma once + +#include <map> + +// Base Class +#include "../Filter.h" + +namespace armarx::armem::server::ltm::processor::filter +{ + class MemoryFrequencyFilter : public MemoryFilter + { + public: + static const constexpr char* NAME = "MemoryFrequencyFilter"; + static const constexpr char* PARAM_WAITING_TIME = "WaitingTimeInMs"; + + MemoryFrequencyFilter() = default; + + virtual bool accept(const armem::wm::Memory& e) override; + void configure(const nlohmann::json& json) override; + + public: + int waitingTimeInMs = -1; + + private: + long timestampLastCommitInMs = 0; + }; + + class SnapshotFrequencyFilter : public SnapshotFilter + { + public: + static const constexpr char* NAME = "SnapshotFrequencyFilter"; + static const constexpr char* PARAM_WAITING_TIME = "WaitingTimeInMs"; + + SnapshotFrequencyFilter() = default; + + virtual bool accept(const armem::wm::EntitySnapshot& e) override; + void configure(const nlohmann::json& json) override; + + public: + int waitingTimeInMs = -1; + + private: + std::map<MemoryID, long> timestampLastCommitInMs; + }; +} // namespace armarx::armem::server::ltm::processor::filter diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/forgetter/LRUForgetter/LRUForgetter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/Forgetter.cpp similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/base/forgetter/LRUForgetter/LRUForgetter.cpp rename to source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/Forgetter.cpp diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/forgetter/LRUForgetter/LRUForgetter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/Forgetter.h similarity index 100% rename from source/RobotAPI/libraries/armem/server/ltm/base/forgetter/LRUForgetter/LRUForgetter.h rename to source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/Forgetter.h diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/LRUForgetter/LRUForgetter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/LRUForgetter/LRUForgetter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/LRUForgetter/LRUForgetter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/forgetter/LRUForgetter/LRUForgetter.h new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/RobotAPI/libraries/armem/server/plugins/Plugin.cpp b/source/RobotAPI/libraries/armem/server/plugins/Plugin.cpp index b8b422bff746b435a1503b84af330bca5c66e524..d379cf033d76392d07417b0345aa09a3cca900bf 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/Plugin.cpp +++ b/source/RobotAPI/libraries/armem/server/plugins/Plugin.cpp @@ -1,20 +1,18 @@ #include "Plugin.h" -#include "ArmarXCore/util/CPPUtility/trace.h" - -#include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/client/util/MemoryListener.h> -#include <RobotAPI/libraries/armem/client/plugins/Plugin.h> +#include "ArmarXCore/util/CPPUtility/trace.h" #include <ArmarXCore/core/Component.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/libraries/armem/client/plugins/Plugin.h> +#include <RobotAPI/libraries/armem/client/util/MemoryListener.h> +#include <RobotAPI/libraries/armem/core/error.h> namespace armarx::armem::server::plugins { Plugin::~Plugin() = default; - Plugin::Plugin(ManagedIceObject& parent, std::string prefix) : armarx::ComponentPlugin(parent, prefix) { @@ -24,8 +22,8 @@ namespace armarx::armem::server::plugins addPluginDependency(clientPlugin); } - - void Plugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) + void + Plugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) { const std::string prefix = "mem."; @@ -39,36 +37,45 @@ namespace armarx::armem::server::plugins // also add scenario param to overwrite the chosen name if (not properties->hasDefinition(prefix + "MemoryName")) { - properties->optional(workingMemory.name(), prefix + "MemoryName", "Name of this memory server."); + properties->optional( + workingMemory.name(), prefix + "MemoryName", "Name of this memory server."); } // stuff for ltm longtermMemory.createPropertyDefinitions(properties, prefix + "ltm."); } - - void Plugin::preOnInitComponent() + void + Plugin::preOnInitComponent() { ARMARX_TRACE; - memoryTopicName = client::util::MemoryListener::MakeMemoryTopicName(MemoryID(workingMemory.name())); + memoryTopicName = + client::util::MemoryListener::MakeMemoryTopicName(MemoryID(workingMemory.name())); parent().offeringTopic(memoryTopicName); } - - void Plugin::postOnInitComponent() + void + Plugin::postOnInitComponent() { Component& parent = this->parent<Component>(); // activate LTM ARMARX_TRACE; - longtermMemory.setMemoryID(workingMemory.id(), parent.getName()); - longtermMemory.init(); + if (not workingMemory.id().memoryName.empty()) + { + longtermMemory.setMemoryID(workingMemory.id()); + } + else + { + longtermMemory.setMemoryID(MemoryID(parent.getDefaultName(), "")); + } + longtermMemory.configure(); initialized = true; } - - void Plugin::postOnConnectComponent() + void + Plugin::postOnConnectComponent() { Component& parent = this->parent<Component>(); @@ -83,8 +90,8 @@ namespace armarx::armem::server::plugins connected = true; } - - void Plugin::preOnDisconnectComponent() + void + Plugin::preOnDisconnectComponent() { if (clientPlugin->isMemoryNameSystemEnabled() and clientPlugin->getMemoryNameSystemClient()) { @@ -92,19 +99,20 @@ namespace armarx::armem::server::plugins } } - - void Plugin::setMemoryName(const std::string& memoryName) + void + Plugin::setMemoryName(const std::string& memoryName) { if (initialized) { - ARMARX_WARNING << "Please set the memory name before initializing the component. Otherwise the WM and LTM may have different names"; + ARMARX_WARNING << "Please set the memory name before initializing the component. " + "Otherwise the WM and LTM may have different names"; } workingMemory.name() = memoryName; } - - mns::dto::RegisterServerResult Plugin::registerServer(armarx::Component& parent) + mns::dto::RegisterServerResult + Plugin::registerServer(armarx::Component& parent) { ARMARX_TRACE; @@ -120,7 +128,8 @@ namespace armarx::armem::server::plugins { clientPlugin->getMemoryNameSystemClient().registerServer(id, server); result.success = true; - ARMARX_DEBUG << "Registered memory server for " << id << " in the Memory Name System (MNS)."; + ARMARX_DEBUG << "Registered memory server for " << id + << " in the Memory Name System (MNS)."; } catch (const armem::error::ServerRegistrationOrRemovalFailed& e) { @@ -131,8 +140,8 @@ namespace armarx::armem::server::plugins return result; } - - mns::dto::RemoveServerResult Plugin::removeServer() + mns::dto::RemoveServerResult + Plugin::removeServer() { MemoryID id = MemoryID().withMemoryName(workingMemory.name()); @@ -141,7 +150,8 @@ namespace armarx::armem::server::plugins { clientPlugin->getMemoryNameSystemClient().removeServer(id); result.success = true; - ARMARX_DEBUG << "Removed memory server for " << id << " from the Memory Name System (MNS)."; + ARMARX_DEBUG << "Removed memory server for " << id + << " from the Memory Name System (MNS)."; } catch (const armem::error::ServerRegistrationOrRemovalFailed& e) { @@ -158,4 +168,4 @@ namespace armarx::armem::server::plugins return result; } -} +} // namespace armarx::armem::server::plugins diff --git a/source/RobotAPI/libraries/armem/server/plugins/Plugin.h b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h index aa6afd8171ff50cf43b955ff145a4770cf8f24b7..e37c5e093232af4aae66114703a7debb8f122ba4 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/Plugin.h +++ b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h @@ -1,19 +1,17 @@ #pragma once -#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> - -#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> +#include <ArmarXCore/core/ComponentPlugin.h> #include <RobotAPI/interface/armem/client/MemoryListenerInterface.h> #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h> - -#include <ArmarXCore/core/ComponentPlugin.h> - +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> namespace armarx { class Component; } + namespace armarx::armem::client::plugins { class Plugin; @@ -22,11 +20,9 @@ namespace armarx::armem::client::plugins namespace armarx::armem::server::plugins { - class Plugin : - public armarx::ComponentPlugin + class Plugin : public armarx::ComponentPlugin { public: - Plugin(ManagedIceObject& parent, std::string prefix); virtual ~Plugin() override; @@ -40,13 +36,11 @@ namespace armarx::armem::server::plugins public: - /// Set the name of the wm and the ltm void setMemoryName(const std::string& memoryName); protected: - /** * @brief Register the parent component in the MNS. * @@ -62,16 +56,14 @@ namespace armarx::armem::server::plugins mns::dto::RemoveServerResult removeServer(); - public: - // Working Memory /// The actual memory. server::wm::Memory workingMemory; /// Helps connecting `memory` to ice. Used to handle Ice callbacks. - MemoryToIceAdapter iceAdapter { &workingMemory, &longtermMemory}; + MemoryToIceAdapter iceAdapter{&workingMemory, &longtermMemory}; // Working Memory Updates (publishing) @@ -85,18 +77,16 @@ namespace armarx::armem::server::plugins // Long-Term Memory /// A manager class for the ltm. It internally holds a normal wm instance as a cache. - server::ltm::disk::Memory longtermMemory; + server::ltm::Memory longtermMemory; private: - client::plugins::Plugin* clientPlugin = nullptr; std::atomic_bool initialized = false; std::atomic_bool connected = false; - }; -} +} // namespace armarx::armem::server::plugins namespace armarx::armem::server { diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp index 299e8242ee540df8c5397d86a03a7cae2d1a0eb8..0578214ecb8270828d6de3a9d7764c945c170311 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp +++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp @@ -1,14 +1,13 @@ #include "ReadWritePluginUser.h" -#include "Plugin.h" - -#include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/Prediction.h> -#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <ArmarXCore/core/Component.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/libraries/armem/core/Prediction.h> +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> +#include "Plugin.h" namespace armarx::armem::server::plugins { @@ -18,126 +17,133 @@ namespace armarx::armem::server::plugins addPlugin(plugin); } - ReadWritePluginUser::~ReadWritePluginUser() { } - - void ReadWritePluginUser::setMemoryName(const std::string& memoryName) + void + ReadWritePluginUser::setMemoryName(const std::string& memoryName) { plugin->setMemoryName(memoryName); } - // WRITING - data::AddSegmentsResult ReadWritePluginUser::addSegments(const data::AddSegmentsInput& input, const Ice::Current&) + data::AddSegmentsResult + ReadWritePluginUser::addSegments(const data::AddSegmentsInput& input, const Ice::Current&) { ARMARX_TRACE; bool addCoreSegmentOnUsage = false; return addSegments(input, addCoreSegmentOnUsage); } - data::AddSegmentsResult ReadWritePluginUser::addSegments(const data::AddSegmentsInput& input, bool addCoreSegments) + data::AddSegmentsResult + ReadWritePluginUser::addSegments(const data::AddSegmentsInput& input, bool addCoreSegments) { ARMARX_TRACE; data::AddSegmentsResult result = iceAdapter().addSegments(input, addCoreSegments); return result; } - - data::CommitResult ReadWritePluginUser::commit(const data::Commit& commitIce, const Ice::Current&) + data::CommitResult + ReadWritePluginUser::commit(const data::Commit& commitIce, const Ice::Current&) { ARMARX_TRACE; return iceAdapter().commit(commitIce); } - // READING - armem::query::data::Result ReadWritePluginUser::query(const armem::query::data::Input& input, const Ice::Current&) + armem::query::data::Result + ReadWritePluginUser::query(const armem::query::data::Input& input, const Ice::Current&) { ARMARX_TRACE; return iceAdapter().query(input); } - structure::data::GetServerStructureResult ReadWritePluginUser::getServerStructure(const Ice::Current&) + structure::data::GetServerStructureResult + ReadWritePluginUser::getServerStructure(const Ice::Current&) { ARMARX_TRACE; return iceAdapter().getServerStructure(); } - // LTM STORING AND RECORDING - dto::DirectlyStoreResult ReadWritePluginUser::directlyStore(const dto::DirectlyStoreInput& input, const Ice::Current&) + dto::DirectlyStoreResult + ReadWritePluginUser::directlyStore(const dto::DirectlyStoreInput& input, const Ice::Current&) { ARMARX_TRACE; return iceAdapter().directlyStore(input); } - dto::StartRecordResult ReadWritePluginUser::startRecord(const dto::StartRecordInput& startRecordInput, const Ice::Current&) + dto::StartRecordResult + ReadWritePluginUser::startRecord(const dto::StartRecordInput& startRecordInput, + const Ice::Current&) { ARMARX_TRACE; return iceAdapter().startRecord(startRecordInput); } - dto::StopRecordResult ReadWritePluginUser::stopRecord(const Ice::Current&) + dto::StopRecordResult + ReadWritePluginUser::stopRecord(const Ice::Current&) { ARMARX_TRACE; return iceAdapter().stopRecord(); } - dto::RecordStatusResult ReadWritePluginUser::getRecordStatus(const Ice::Current&) + dto::RecordStatusResult + ReadWritePluginUser::getRecordStatus(const Ice::Current&) { ARMARX_TRACE; return iceAdapter().getRecordStatus(); } - - Plugin& ReadWritePluginUser::memoryServerPlugin() + Plugin& + ReadWritePluginUser::memoryServerPlugin() { return *plugin; } - - wm::Memory& ReadWritePluginUser::workingMemory() + wm::Memory& + ReadWritePluginUser::workingMemory() { return plugin->workingMemory; } - - MemoryToIceAdapter& ReadWritePluginUser::iceAdapter() + MemoryToIceAdapter& + ReadWritePluginUser::iceAdapter() { return plugin->iceAdapter; } - - ltm::disk::Memory& ReadWritePluginUser::longtermMemory() + ltm::Memory& + ReadWritePluginUser::longtermMemory() { return plugin->longtermMemory; } // ACTIONS - armem::actions::GetActionsOutputSeq ReadWritePluginUser::getActions( - const armem::actions::GetActionsInputSeq& inputs, const ::Ice::Current& /*unused*/) + armem::actions::GetActionsOutputSeq + ReadWritePluginUser::getActions(const armem::actions::GetActionsInputSeq& inputs, + const ::Ice::Current& /*unused*/) { return getActions(inputs); } - armem::actions::GetActionsOutputSeq ReadWritePluginUser::getActions( - const armem::actions::GetActionsInputSeq& inputs) + armem::actions::GetActionsOutputSeq + ReadWritePluginUser::getActions(const armem::actions::GetActionsInputSeq& inputs) { - (void) inputs; + (void)inputs; return {}; } - armem::actions::ExecuteActionOutputSeq ReadWritePluginUser::executeActions( - const armem::actions::ExecuteActionInputSeq& inputs, const ::Ice::Current& /*unused*/) + armem::actions::ExecuteActionOutputSeq + ReadWritePluginUser::executeActions(const armem::actions::ExecuteActionInputSeq& inputs, + const ::Ice::Current& /*unused*/) { return executeActions(inputs); } - armem::actions::ExecuteActionOutputSeq ReadWritePluginUser::executeActions( - const armem::actions::ExecuteActionInputSeq& inputs) + armem::actions::ExecuteActionOutputSeq + ReadWritePluginUser::executeActions(const armem::actions::ExecuteActionInputSeq& inputs) { return {}; } diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h index 3c29eb693b49df92b1fe82fcd84f416ed4152141..89dcb3239cc6a62275dbd744732f4a262474d447 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h +++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h @@ -1,32 +1,28 @@ #pragma once -#include <RobotAPI/libraries/armem/server/forward_declarations.h> +#include <ArmarXCore/core/ManagedIceObject.h> +#include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/libraries/armem/client/plugins/ListeningPluginUser.h> #include <RobotAPI/libraries/armem/core/actions.h> -#include <RobotAPI/interface/armem/server/MemoryInterface.h> - -#include <ArmarXCore/core/ManagedIceObject.h> - +#include <RobotAPI/libraries/armem/server/forward_declarations.h> namespace armarx::armem::server::plugins { class Plugin; - /** * @brief Base class of memory server components. * * Implements the server ice interfaces using the ice adapter of the plugin. */ class ReadWritePluginUser : - virtual public ManagedIceObject - , virtual public MemoryInterface - , virtual public client::plugins::ListeningPluginUser + virtual public ManagedIceObject, + virtual public MemoryInterface, + virtual public client::plugins::ListeningPluginUser { public: - ReadWritePluginUser(); virtual ~ReadWritePluginUser() override; @@ -35,61 +31,78 @@ namespace armarx::armem::server::plugins // WritingInterface interface - virtual data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, const Ice::Current& = Ice::emptyCurrent) override; - data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, bool addCoreSegments); + virtual data::AddSegmentsResult + addSegments(const data::AddSegmentsInput& input, + const Ice::Current& = Ice::emptyCurrent) override; + data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, + bool addCoreSegments); - virtual data::CommitResult commit(const data::Commit& commit, const Ice::Current& = Ice::emptyCurrent) override; + virtual data::CommitResult commit(const data::Commit& commit, + const Ice::Current& = Ice::emptyCurrent) override; // ReadingInterface interface - virtual armem::query::data::Result query(const armem::query::data::Input& input, const Ice::Current& = Ice::emptyCurrent) override; - virtual armem::structure::data::GetServerStructureResult getServerStructure(const Ice::Current& = Ice::emptyCurrent) override; + virtual armem::query::data::Result query(const armem::query::data::Input& input, + const Ice::Current& = Ice::emptyCurrent) override; + virtual armem::structure::data::GetServerStructureResult + getServerStructure(const Ice::Current& = Ice::emptyCurrent) override; // StoringInterface interface - virtual dto::DirectlyStoreResult directlyStore(const dto::DirectlyStoreInput&, const Ice::Current& = Ice::emptyCurrent) override; - virtual dto::StartRecordResult startRecord(const dto::StartRecordInput& startRecordInput, const Ice::Current& = Ice::emptyCurrent) override; + virtual dto::DirectlyStoreResult + directlyStore(const dto::DirectlyStoreInput&, + const Ice::Current& = Ice::emptyCurrent) override; + virtual dto::StartRecordResult + startRecord(const dto::StartRecordInput& startRecordInput, + const Ice::Current& = Ice::emptyCurrent) override; virtual dto::StopRecordResult stopRecord(const Ice::Current& = Ice::emptyCurrent) override; - virtual dto::RecordStatusResult getRecordStatus(const Ice::Current& = Ice::emptyCurrent) override; + virtual dto::RecordStatusResult + getRecordStatus(const Ice::Current& = Ice::emptyCurrent) override; // ActionsInterface interface - virtual armem::actions::GetActionsOutputSeq getActions(const armem::actions::GetActionsInputSeq& inputs); - virtual armem::actions::ExecuteActionOutputSeq executeActions(const armem::actions::ExecuteActionInputSeq& inputs); - - virtual armem::actions::GetActionsOutputSeq getActions(const armem::actions::GetActionsInputSeq& inputs, const ::Ice::Current&) override; - virtual armem::actions::ExecuteActionOutputSeq executeActions(const armem::actions::ExecuteActionInputSeq& inputs, const ::Ice::Current&) override; + virtual armem::actions::GetActionsOutputSeq + getActions(const armem::actions::GetActionsInputSeq& inputs); + virtual armem::actions::ExecuteActionOutputSeq + executeActions(const armem::actions::ExecuteActionInputSeq& inputs); + + virtual armem::actions::GetActionsOutputSeq + getActions(const armem::actions::GetActionsInputSeq& inputs, + const ::Ice::Current&) override; + virtual armem::actions::ExecuteActionOutputSeq + executeActions(const armem::actions::ExecuteActionInputSeq& inputs, + const ::Ice::Current&) override; // PredictingInterface interface - virtual armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests); + virtual armem::prediction::data::PredictionResultSeq + predict(const armem::prediction::data::PredictionRequestSeq& requests); // Unless you need very unusual behavior from this method for your memory server, // it is better to set the available prediction engines in the memory itself // and let it handle the requests than to override this. virtual armem::prediction::data::EngineSupportMap getAvailableEngines(); - virtual armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests, const ::Ice::Current&) override; - virtual armem::prediction::data::EngineSupportMap getAvailableEngines(const ::Ice::Current&) override; + virtual armem::prediction::data::PredictionResultSeq + predict(const armem::prediction::data::PredictionRequestSeq& requests, + const ::Ice::Current&) override; + virtual armem::prediction::data::EngineSupportMap + getAvailableEngines(const ::Ice::Current&) override; public: - Plugin& memoryServerPlugin(); server::wm::Memory& workingMemory(); MemoryToIceAdapter& iceAdapter(); - server::ltm::disk::Memory& longtermMemory(); + server::ltm::Memory& longtermMemory(); private: - plugins::Plugin* plugin = nullptr; - }; -} +} // namespace armarx::armem::server::plugins namespace armarx::armem::server { using plugins::ReadWritePluginUser; } - diff --git a/source/RobotAPI/libraries/armem/server/query_proc/ltm/disk/ltm.h b/source/RobotAPI/libraries/armem/server/query_proc/ltm/disk/ltm.h index f569e986a57832def5e1343f20da9f0b007d664f..aa7349eadafcbafd40472ba2b19adf21041cd5ce 100644 --- a/source/RobotAPI/libraries/armem/server/query_proc/ltm/disk/ltm.h +++ b/source/RobotAPI/libraries/armem/server/query_proc/ltm/disk/ltm.h @@ -1,35 +1,37 @@ #pragma once -#include <RobotAPI/libraries/armem/server/ltm/disk/Memory.h> +#include <RobotAPI/libraries/armem/server/ltm/Memory.h> #include <RobotAPI/libraries/armem/server/query_proc/base.h> -#include "../detail/MemoryQueryProcessorBase.h" #include "../detail/CoreSegmentQueryProcessorBase.h" -#include "../detail/ProviderSegmentQueryProcessorBase.h" #include "../detail/EntityQueryProcessorBase.h" +#include "../detail/MemoryQueryProcessorBase.h" +#include "../detail/ProviderSegmentQueryProcessorBase.h" -namespace armarx::armem::server::query_proc::ltm_server::disk +namespace armarx::armem::server::query_proc::ltm_server { class EntityQueryProcessor : - public ltm::detail::EntityQueryProcessorBase<armem::server::ltm::disk::Entity, armem::wm::Entity> + public ltm::detail::EntityQueryProcessorBase<armem::server::ltm::Entity, armem::wm::Entity> { protected: - - using Base = ltm::detail::EntityQueryProcessorBase<armem::server::ltm::disk::Entity, armem::wm::Entity>; + using Base = + ltm::detail::EntityQueryProcessorBase<armem::server::ltm::Entity, armem::wm::Entity>; public: - using Base::process; - }; class ProviderSegmentQueryProcessor : - public ltm::detail::ProviderSegmentQueryProcessorBase<armem::server::ltm::disk::ProviderSegment, armem::wm::ProviderSegment, EntityQueryProcessor> + public ltm::detail::ProviderSegmentQueryProcessorBase<armem::server::ltm::ProviderSegment, + armem::wm::ProviderSegment, + EntityQueryProcessor> { protected: - - using Base = ltm::detail::ProviderSegmentQueryProcessorBase<armem::server::ltm::disk::ProviderSegment, armem::wm::ProviderSegment, EntityQueryProcessor>; + using Base = + ltm::detail::ProviderSegmentQueryProcessorBase<armem::server::ltm::ProviderSegment, + armem::wm::ProviderSegment, + EntityQueryProcessor>; public: @@ -37,11 +39,14 @@ namespace armarx::armem::server::query_proc::ltm_server::disk }; class CoreSegmentQueryProcessor : - public ltm::detail::CoreSegmentQueryProcessorBase<armem::server::ltm::disk::CoreSegment, armem::wm::CoreSegment, ProviderSegmentQueryProcessor> + public ltm::detail::CoreSegmentQueryProcessorBase<armem::server::ltm::CoreSegment, + armem::wm::CoreSegment, + ProviderSegmentQueryProcessor> { protected: - - using Base = ltm::detail::CoreSegmentQueryProcessorBase<armem::server::ltm::disk::CoreSegment, armem::wm::CoreSegment, ProviderSegmentQueryProcessor>; + using Base = ltm::detail::CoreSegmentQueryProcessorBase<armem::server::ltm::CoreSegment, + armem::wm::CoreSegment, + ProviderSegmentQueryProcessor>; public: @@ -49,14 +54,17 @@ namespace armarx::armem::server::query_proc::ltm_server::disk }; class MemoryQueryProcessor : - public ltm::detail::MemoryQueryProcessorBase<armem::server::ltm::disk::Memory, armem::wm::Memory, CoreSegmentQueryProcessor> + public ltm::detail::MemoryQueryProcessorBase<armem::server::ltm::Memory, + armem::wm::Memory, + CoreSegmentQueryProcessor> { protected: - - using Base = ltm::detail::MemoryQueryProcessorBase<armem::server::ltm::disk::Memory, armem::wm::Memory, CoreSegmentQueryProcessor>; + using Base = ltm::detail::MemoryQueryProcessorBase<armem::server::ltm::Memory, + armem::wm::Memory, + CoreSegmentQueryProcessor>; public: using Base::process; }; -} +} // namespace armarx::armem::server::query_proc::ltm_server diff --git a/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp b/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp index ecf13ddc3a54c6000ae7e9d6abcbfa32bec84057..d2bbeb2f8d1ec31e4b69beacd1e30a3994d00752 100644 --- a/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp +++ b/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp @@ -24,19 +24,17 @@ #define ARMARX_BOOST_TEST +#include <filesystem> +#include <iostream> + +#include <ArmarXCore/core/time/StopWatch.h> + #include <RobotAPI/Test.h> -#include <RobotAPI/libraries/armem/server/ltm/disk/Memory.h> #include <RobotAPI/libraries/armem/core/error.h> - +#include <RobotAPI/libraries/armem/server/ltm/Memory.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> #include <RobotAPI/libraries/aron/core/type/variant/All.h> -#include <ArmarXCore/core/time/StopWatch.h> - - -#include <filesystem> -#include <iostream> - namespace armem = armarx::armem; namespace aron = armarx::aron; namespace fs = std::filesystem; @@ -51,12 +49,14 @@ namespace ArMemLTMBenchmark { clearStoragePath(); } + ~Fixture() { //clearStoragePath(); } - void clearStoragePath() + void + clearStoragePath() { if (fs::exists(storagePath)) { @@ -66,9 +66,13 @@ namespace ArMemLTMBenchmark BOOST_REQUIRE(!fs::exists(storagePath)); } - void storeElementNTimes(const std::string& memoryName, const aron::data::DictPtr& dict, int waitingTimeMs, int n) + void + storeElementNTimes(const std::string& memoryName, + const aron::data::DictPtr& dict, + int waitingTimeMs, + int n) { - armem::server::ltm::disk::Memory ltm(storagePath, memoryName); + armem::server::ltm::Memory ltm(storagePath, "MemoryExport", memoryName); armem::wm::Memory wm(memoryName); auto& core = wm.addCoreSegment("CoreS"); @@ -85,29 +89,25 @@ namespace ArMemLTMBenchmark auto cloned = aron::data::Dict::DynamicCastAndCheck(dict->clone()); ins.data() = cloned; - ltm.store(wm); - ltm.storeBuffer(); - + ltm.directlyStore(wm); usleep(waitingTimeMs * 1000.0); } } }; -} +} // namespace ArMemLTMBenchmark BOOST_FIXTURE_TEST_SUITE(ArMemLTMBenchmark, Fixture) - BOOST_AUTO_TEST_CASE(test_memory_export__single_image_benchmark) { auto data = std::make_shared<aron::data::Dict>(); std::vector<int> dimensions = {720, 1280, 3}; std::string type = "16"; - std::vector<unsigned char> d(720*1280*3, 255); + std::vector<unsigned char> d(720 * 1280 * 3, 255); data->addElement("image", std::make_shared<aron::data::NDArray>(dimensions, type, d)); storeElementNTimes("SingleImageBenchmark", data, 100, 2); } BOOST_AUTO_TEST_SUITE_END() - diff --git a/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp b/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp index fd326aa038d122cb76a26ad34825dcab4f85b933..db6c68b2d4c6142ef3e7716b1d80245b02b93734 100644 --- a/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp +++ b/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp @@ -25,24 +25,23 @@ #define ARMARX_BOOST_TEST #include <RobotAPI/Test.h> -#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/core/error.h> - +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> +#include <RobotAPI/libraries/armem/server/ltm/Memory.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> #include <RobotAPI/libraries/aron/core/type/variant/All.h> -#include <RobotAPI/libraries/armem/server/ltm/disk/Memory.h> - //#include "../core/io/diskWriter/NlohmannJSON/NlohmannJSONDiskWriter.h" // TODO: REMOVE ME!! +#include <filesystem> +#include <iostream> + +#include <VirtualRobot/Import/SimoxXMLFactory.h> #include <VirtualRobot/Robot.h> #include <VirtualRobot/RobotNodeSet.h> -#include <VirtualRobot/Import/SimoxXMLFactory.h> -#include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h> -#include <filesystem> -#include <iostream> +#include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h> namespace armem = armarx::armem; namespace aron = armarx::aron; @@ -59,12 +58,14 @@ namespace ArMemLTMTest clearStoragePath(); assureStoragePath(); } + ~Fixture() { //clearStoragePath(); } - void assureStoragePath() + void + assureStoragePath() { if (!fs::is_directory(storagePath)) { @@ -74,7 +75,8 @@ namespace ArMemLTMTest BOOST_REQUIRE(fs::exists(storagePath) && fs::is_directory(storagePath)); } - void clearStoragePath() + void + clearStoragePath() { if (fs::exists(storagePath)) { @@ -84,13 +86,12 @@ namespace ArMemLTMTest BOOST_REQUIRE(!fs::exists(storagePath)); } - - static armem::wm::Memory setupMemoryWithType( - const std::string& memoryName, - const aron::type::ObjectPtr& t1, - const aron::type::ObjectPtr& t2, - unsigned int numSnapshots, - unsigned int numInstances) + static armem::wm::Memory + setupMemoryWithType(const std::string& memoryName, + const aron::type::ObjectPtr& t1, + const aron::type::ObjectPtr& t2, + unsigned int numSnapshots, + unsigned int numInstances) { /*aron::Randomizer r; @@ -134,7 +135,8 @@ namespace ArMemLTMTest } template <class TypeNavigatorT> - aron::type::ObjectPtr makeType(const std::string& memberPrefix, int numMembers = 4) + aron::type::ObjectPtr + makeType(const std::string& memberPrefix, int numMembers = 4) { /*aron::type::ObjectPtr t = std::make_shared<aron::type::Object>(aron::Path()); t->setObjectName("TestObjectType1"); @@ -149,7 +151,8 @@ namespace ArMemLTMTest } template <class TypeNavigatorT> - void run(const std::string& memoryName, const std::string& memberNamePrefix) + void + run(const std::string& memoryName, const std::string& memberNamePrefix) { /*aron::typenavigator::ObjectNavigatorPtr t = makeType<TypeNavigatorT>(memberNamePrefix); armem::Memory memory = setupMemoryWithType(memoryName, t, nullptr, 15, 1); @@ -177,11 +180,10 @@ namespace ArMemLTMTest BOOST_CHECK_EQUAL(memory.equalsDeep(memory2), true);*/ } }; -} +} // namespace ArMemLTMTest BOOST_FIXTURE_TEST_SUITE(ArMemLTMTest, Fixture) - BOOST_AUTO_TEST_CASE(test_memory_export__easy_int_setup) { run<aron::type::Int>("TestMemory_IntSetup", "theInt"); @@ -216,40 +218,45 @@ BOOST_AUTO_TEST_CASE(test_memory_export__easy_fabian_setup) { std::filesystem::path memoryExport = "/home/fabian/repos/projects/ltmtools/data/sim_2022_09_15"; - armem::server::ltm::disk::Memory ltm(memoryExport, "Object"); + armem::server::ltm::Memory ltm(memoryExport, "MemoryExportTest", "Object"); auto ltm_c_seg = ltm.findCoreSegment("Instance"); - ltm_c_seg->forEachProviderSegment([](const armem::server::ltm::disk::ProviderSegment& ltm_p_seg){ - ltm_p_seg.forEachEntity([](const armem::server::ltm::disk::Entity& ltm_e){ - ltm_e.forEachSnapshot([](const armem::server::ltm::disk::EntitySnapshot& ltm_snapshot){ - armem::wm::EntitySnapshot s; - ltm_snapshot.loadAllReferences(s); - ltm_snapshot.resolve(s); - - auto i = s.getInstance(0); - auto data = i.data(); + ltm_c_seg->forEachProviderSegment( + [](const armem::server::ltm::ProviderSegment& ltm_p_seg) + { + ltm_p_seg.forEachEntity( + [](const armem::server::ltm::Entity& ltm_e) + { + ltm_e.forEachSnapshot( + [](const armem::server::ltm::EntitySnapshot& ltm_snapshot) + { + armem::wm::EntitySnapshot s; + ltm_snapshot.loadAllReferences(s); + ltm_snapshot.resolve(s); + auto i = s.getInstance(0); + auto data = i.data(); - auto p = data->getElement("pose"); - auto p2 = armarx::aron::data::Dict::DynamicCastAndCheck(p); + auto p = data->getElement("pose"); + auto p2 = armarx::aron::data::Dict::DynamicCastAndCheck(p); - armarx::objpose::arondto::ObjectPose px; - px.fromAron(p2); + armarx::objpose::arondto::ObjectPose px; + px.fromAron(p2); - auto a = p2->getElement("attachment"); - auto a2 = armarx::aron::data::Dict::DynamicCastAndCheck(a); + auto a = p2->getElement("attachment"); + auto a2 = armarx::aron::data::Dict::DynamicCastAndCheck(a); - armarx::objpose::arondto::ObjectAttachmentInfo ax; - ax.fromAron(a2); + armarx::objpose::arondto::ObjectAttachmentInfo ax; + ax.fromAron(a2); - if (ax.agentName != "") - { - ARMARX_INFO << (ax.poseInFrame); - } - }); + if (ax.agentName != "") + { + ARMARX_INFO << (ax.poseInFrame); + } + }); + }); }); - }); //auto ltm_p_seg = ltm_c_seg->findProviderSegment("Armar3"); @@ -263,8 +270,6 @@ BOOST_AUTO_TEST_CASE(test_memory_export__easy_fabian_setup) //e.forEachSnapshot(f); //auto wm = ltm.loadAllAndResolve(); - - } /* @@ -315,4 +320,3 @@ BOOST_AUTO_TEST_CASE(test_memory_export__easy_rainer_setup) BOOST_AUTO_TEST_SUITE_END() - diff --git a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp index a490d63436a484cee322d167a02675710c695260..cb828b64fdb412ce6e7faa30def48e91867173b0 100644 --- a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp @@ -1,19 +1,17 @@ #include "ControlWidget.h" -#include <RobotAPI/libraries/armem/server/ltm/disk/Memory.h> -#include <RobotAPI/libraries/armem/server/query_proc/ltm/disk/ltm.h> - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <cmath> +#include <filesystem> -#include <QHBoxLayout> -#include <QSpacerItem> #include <QFileDialog> +#include <QHBoxLayout> #include <QPushButton> +#include <QSpacerItem> -#include <filesystem> - -#include <cmath> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/libraries/armem/server/ltm/Memory.h> +#include <RobotAPI/libraries/armem/server/query_proc/ltm/disk/ltm.h> namespace armarx::armem::gui::disk { @@ -28,7 +26,7 @@ namespace armarx::armem::gui::disk _storeOnDiskButton->setIcon(QIcon(":/icons/document-save.svg")); // Allow horizontal shrinking of buttons - std::vector<QPushButton*> buttons { _storeOnDiskButton, _loadFromDiskButton }; + std::vector<QPushButton*> buttons{_storeOnDiskButton, _loadFromDiskButton}; for (QPushButton* button : buttons) { button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); @@ -48,46 +46,47 @@ namespace armarx::armem::gui::disk // Connections - connect(_loadFromDiskButton, &QPushButton::pressed, [this]() - { - QString directory = chooseDirectoryDialog(); - if (directory.size() > 0) - { - emit requestedLoadFromDisk(directory); - } - }); - connect(_storeOnDiskButton, &QPushButton::pressed, [this]() - { - QString directory = chooseDirectoryDialog(); - if (directory.size() > 0) - { - emit requestedStoreOnDisk(directory); - } - }); + connect(_loadFromDiskButton, + &QPushButton::pressed, + [this]() + { + QString directory = chooseDirectoryDialog(); + if (directory.size() > 0) + { + emit requestedLoadFromDisk(directory); + } + }); + connect(_storeOnDiskButton, + &QPushButton::pressed, + [this]() + { + QString directory = chooseDirectoryDialog(); + if (directory.size() > 0) + { + emit requestedStoreOnDisk(directory); + } + }); } - - static - const std::string& + static const std::string& handleSingular(int num, const std::string& singular, const std::string& plural) { return num == 1 ? singular : plural; } - void - ControlWidget::storeOnDisk( - QString directory, - const std::vector<wm::Memory> memoryData, - std::string* outStatus) + ControlWidget::storeOnDisk(QString directory, + const std::vector<wm::Memory> memoryData, + std::string* outStatus) { std::filesystem::path path(directory.toUtf8().constData()); - ARMARX_CHECK_POSITIVE(path.string().size()); // An empty path indicates an error. + ARMARX_CHECK_POSITIVE(path.string().size()); // An empty path indicates an error. std::stringstream status; if (std::filesystem::is_regular_file(path)) { - status << "Could not export memories contents to " << path << ": Cannot overwrite existing file."; + status << "Could not export memories contents to " << path + << ": Cannot overwrite existing file."; } else { @@ -97,17 +96,19 @@ namespace armarx::armem::gui::disk std::string name = data.id().memoryName; if (std::filesystem::is_regular_file(path / name)) { - status << "Could not export memory '" << name << "' to " << path << ": Cannot overwrite existing file.\n"; + status << "Could not export memory '" << name << "' to " << path + << ": Cannot overwrite existing file.\n"; } else { - armem::server::ltm::disk::Memory memory(path, name); + armem::server::ltm::Memory memory(path, "MemoryExport", name); memory.directlyStore(data); numStored++; } } - status << "Exported " << numStored << " " << handleSingular(numStored, "memory", "memories") << " to " << path << "."; + status << "Exported " << numStored << " " + << handleSingular(numStored, "memory", "memories") << " to " << path << "."; } if (outStatus) @@ -116,18 +117,17 @@ namespace armarx::armem::gui::disk } } - std::map<std::filesystem::path, wm::Memory> - ControlWidget::loadFromDisk( - QString directory, - const armem::client::QueryInput& _queryInput, - std::string* outStatus) + ControlWidget::loadFromDisk(QString directory, + const armem::client::QueryInput& _queryInput, + std::string* outStatus) { std::filesystem::path path(directory.toUtf8().constData()); std::map<std::filesystem::path, wm::Memory> memoryData; - auto setStatus = [&](const std::string& s){ + auto setStatus = [&](const std::string& s) + { if (outStatus) { *outStatus = s; @@ -136,28 +136,33 @@ namespace armarx::armem::gui::disk if (not std::filesystem::is_directory(path)) { - setStatus("Could not import a memory from " + path.string() + ". It is not a directory. Skipping import."); + setStatus("Could not import a memory from " + path.string() + + ". It is not a directory. Skipping import."); return memoryData; } // Find out whether this is a single memory or a collection of memories by searching // for a data.aron.* or metadata.aron.* file at depth 5 (if 6 then it is collection of memories) bool isSingleMemory = false; - for (auto i = std::filesystem::recursive_directory_iterator(path); i != std::filesystem::recursive_directory_iterator(); ++i) + for (auto i = std::filesystem::recursive_directory_iterator(path); + i != std::filesystem::recursive_directory_iterator(); + ++i) { - if (i.depth() > armem::server::ltm::disk::Memory::DEPTH_TO_DATA_FILES + 2) + if (i.depth() > armem::server::ltm::Memory::DEPTH_TO_DATA_FILES + 2) { // After some depth we stop searching to not freeze GUI too long - setStatus("Could not import a memory from " + path.string() + ". Data files were not found until max-depth 7. Skipping import."); + setStatus("Could not import a memory from " + path.string() + + ". Data files were not found until max-depth 7. Skipping import."); return memoryData; } auto& dir = *i; // if one matches it is enough to check - if (std::filesystem::is_regular_file(dir.path()) && simox::alg::starts_with(dir.path().filename(), "data.aron")) + if (std::filesystem::is_regular_file(dir.path()) && + simox::alg::starts_with(dir.path().filename(), "data.aron")) { - isSingleMemory = (i.depth() == armem::server::ltm::disk::Memory::DEPTH_TO_DATA_FILES); + isSingleMemory = (i.depth() == armem::server::ltm::Memory::DEPTH_TO_DATA_FILES); break; } } @@ -169,11 +174,13 @@ namespace armarx::armem::gui::disk // const query::data::Input queryIce = queryInput.toIce(); int numLoaded = 0; - auto loadMemory = [&](const std::filesystem::path& p) { + auto loadMemory = [&](const std::filesystem::path& p) + { if (std::filesystem::is_directory(p)) { - armem::server::ltm::disk::Memory ltm(p.parent_path(), p.filename()); - armem::wm::Memory memory = ltm.loadAllAndResolve(); // load list of references and load data + armem::server::ltm::Memory ltm(p.parent_path(), "MemoryExport", p.filename()); + armem::wm::Memory memory = + ltm.loadAllAndResolve(); // load list of references and load data memoryData[p] = memory; numLoaded++; @@ -193,20 +200,21 @@ namespace armarx::armem::gui::disk } } - setStatus("Loaded " + std::to_string(numLoaded) + " " + handleSingular(numLoaded, "memory", "memories") + " from " + path.string() + "."); + setStatus("Loaded " + std::to_string(numLoaded) + " " + + handleSingular(numLoaded, "memory", "memories") + " from " + path.string() + "."); return memoryData; } - - QString ControlWidget::chooseDirectoryDialog() + QString + ControlWidget::chooseDirectoryDialog() { - _latestDirectory = QFileDialog::getExistingDirectory(this, "Open query result", + _latestDirectory = QFileDialog::getExistingDirectory(this, + "Open query result", _latestDirectory, - QFileDialog::ShowDirsOnly - | QFileDialog::DontResolveSymlinks); + QFileDialog::ShowDirsOnly | + QFileDialog::DontResolveSymlinks); return _latestDirectory; } -} - +} // namespace armarx::armem::gui::disk diff --git a/source/RobotAPI/libraries/armem_skills/CMakeLists.txt b/source/RobotAPI/libraries/armem_skills/CMakeLists.txt index 6e1e52fe32d7fcb877685c1f66489ca570f19bc2..5dea7fd336d310010fdd6a15be653b6c5cdeba46 100644 --- a/source/RobotAPI/libraries/armem_skills/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_skills/CMakeLists.txt @@ -13,8 +13,7 @@ armarx_add_library( RobotAPI::armem_server RobotAPI::skills aronjsonconverter - aroncommonconverter - aronaronconverter + arondatatypeconverter SOURCES ./aron_conversions.cpp diff --git a/source/RobotAPI/libraries/aron/converter/datatype/CMakeLists.txt b/source/RobotAPI/libraries/aron/converter/datatype/CMakeLists.txt index 6d176fdc275fef8c2aa5c1a188f9f98d6a3dd1f0..2f77f156296882acce0f470fd1c06a584b57bbde 100644 --- a/source/RobotAPI/libraries/aron/converter/datatype/CMakeLists.txt +++ b/source/RobotAPI/libraries/aron/converter/datatype/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIB_NAME aronaronconverter) +set(LIB_NAME arondatatypeconverter) armarx_component_set_name("${LIB_NAME}") armarx_set_target("Library: ${LIB_NAME}") @@ -23,4 +23,4 @@ set(LIB_HEADERS armarx_add_library("${LIB_NAME}" "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}") -add_library(RobotAPI::aron::converter::aron ALIAS aronaronconverter) +add_library(RobotAPI::aron::converter::datatype ALIAS arondatatypeconverter) diff --git a/source/RobotAPI/libraries/skills/CMakeLists.txt b/source/RobotAPI/libraries/skills/CMakeLists.txt index 8f92d10a862a5253871e29d275ed98826ce3bc15..53f82b11a33901183e7eb321e7b3a18829f15527 100644 --- a/source/RobotAPI/libraries/skills/CMakeLists.txt +++ b/source/RobotAPI/libraries/skills/CMakeLists.txt @@ -11,8 +11,7 @@ armarx_add_library( RobotAPI::Core aronjsonconverter - aroncommonconverter - aronaronconverter + arondatatypeconverter SOURCES ./error/Exception.cpp