From cbd9ed12eb5248887e83d818aa2017f717b602f3 Mon Sep 17 00:00:00 2001
From: "fabian.peller-konrad@kit.edu" <fabian.peller-konrad@kit.edu>
Date: Wed, 28 Jul 2021 08:39:29 +0200
Subject: [PATCH] memory can add coresegments on commit if enabled (useful for
 LTM)

---
 .../armem/core/base/CoreSegmentBase.h         | 37 ++++++++-----
 .../libraries/armem/core/base/MemoryBase.h    | 54 +++++++++++++++++--
 .../armem/core/workingmemory/Memory.cpp       | 28 ++--------
 .../armem/core/workingmemory/Memory.h         |  3 --
 .../armem/server/MemoryToIceAdapter.cpp       |  1 +
 5 files changed, 77 insertions(+), 46 deletions(-)

diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
index 6dc77c576..5e22ba703 100644
--- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
@@ -150,38 +150,49 @@ namespace armarx::armem::base
          *
          * Missing entity entries are added before updating.
          */
-        UpdateResult update(const EntityUpdate& update)
+        virtual UpdateResult update(const EntityUpdate& update)
         {
             this->_checkContainerName(update.entityID.coreSegmentName, this->name());
 
+            auto [inserted, provSeg] = addProviderSegmentIfMissing(update.entityID.providerSegmentName);
+
+
+            // Update entry.
+            UpdateResult ret(provSeg->update(update));
+            if (inserted)
+            {
+                ret.coreSegmentUpdateType = UpdateType::InsertedNew;
+            }
+            else
+            {
+                ret.coreSegmentUpdateType = UpdateType::UpdatedExisting;
+            }
+            return ret;
+        }
+
+        std::pair<bool, ProviderSegmentT*> addProviderSegmentIfMissing(const std::string& providerSegmentName)
+        {
             ProviderSegmentT* provSeg;
-            UpdateType updateType = UpdateType::InsertedNew;
 
-            auto it = this->_container.find(update.entityID.providerSegmentName);
+            auto it = this->_container.find(providerSegmentName);
             if (it == this->_container.end())
             {
                 if (_addMissingProviderSegmentDuringUpdate)
                 {
                     // Insert into map.
-                    provSeg = &addProviderSegment(update.entityID.providerSegmentName);
-                    provSeg->setMaxHistorySize(_maxHistorySize);
-                    updateType = UpdateType::InsertedNew;
+                    provSeg = &addProviderSegment(providerSegmentName);
+                    return {true, provSeg};
                 }
                 else
                 {
-                    throw error::MissingEntry::create<EntitySnapshotT>(update.entityID.providerSegmentName, *this);
+                    throw error::MissingEntry::create<EntitySnapshotT>(providerSegmentName, *this);
                 }
             }
             else
             {
                 provSeg = &it->second;
-                updateType = UpdateType::UpdatedExisting;
+                return {false, provSeg};
             }
-
-            // Update entry.
-            UpdateResult ret(provSeg->update(update));
-            ret.coreSegmentUpdateType = updateType;
-            return ret;
         }
 
         void append(const _Derived& m)
diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
index 73e70478f..781322b54 100644
--- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
@@ -242,16 +242,43 @@ namespace armarx::armem::base
         {
             this->_checkContainerName(update.entityID.memoryName, this->name());
 
-            auto it = this->_container.find(update.entityID.coreSegmentName);
-            if (it != this->_container.end())
+            auto [inserted, coreSeg] = addCoreSegmentIfMissing(update.entityID.coreSegmentName);
+
+            // Update entry.
+            UpdateResult ret(coreSeg->update(update));
+            if (inserted)
+            {
+                ret.memoryUpdateType = UpdateType::InsertedNew;
+            }
+            else
             {
-                UpdateResult ret(it->second.update(update));
                 ret.memoryUpdateType = UpdateType::UpdatedExisting;
-                return ret;
+            }
+            return ret;
+        }
+
+        std::pair<bool, CoreSegmentT*> addCoreSegmentIfMissing(const std::string& coreSegmentName)
+        {
+            CoreSegmentT* coreSeg;
+
+            auto it = this->_container.find(coreSegmentName);
+            if (it == this->_container.end())
+            {
+                if (_addMissingCoreSegmentDuringUpdate)
+                {
+                    // Insert into map.
+                    coreSeg = &addCoreSegment(coreSegmentName);
+                    return {true, coreSeg};
+                }
+                else
+                {
+                    throw error::MissingEntry::create<EntitySnapshotT>(coreSegmentName, *this);
+                }
             }
             else
             {
-                throw armem::error::MissingEntry::create<CoreSegmentT>(update.entityID.coreSegmentName, *this);
+                coreSeg = &it->second;
+                return {false, coreSeg};
             }
         }
 
@@ -308,5 +335,22 @@ namespace armarx::armem::base
         {
             return this->name();
         }
+
+    protected:
+
+        virtual void _copySelf(DerivedT& other) const override
+        {
+            Base::_copySelf(other);
+            other._addMissingCoreSegmentDuringUpdate = _addMissingCoreSegmentDuringUpdate;
+        }
+        virtual void _copySelfEmpty(DerivedT& other) const override
+        {
+            Base::_copySelfEmpty(other);
+            other._addMissingCoreSegmentDuringUpdate = _addMissingCoreSegmentDuringUpdate;
+        }
+
+    public:
+
+        bool _addMissingCoreSegmentDuringUpdate = false;
     };
 }
diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/Memory.cpp
index cd6c9cc58..70fd41e7c 100644
--- a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.cpp
+++ b/source/RobotAPI/libraries/armem/core/workingmemory/Memory.cpp
@@ -7,18 +7,7 @@
 namespace armarx::armem::wm
 {
 
-    std::vector<Memory::Base::UpdateResult>
-    Memory::update(const Commit& commit)
-    {
-        std::vector<Memory::Base::UpdateResult> result;
-        for (const EntityUpdate& update : commit.updates)
-        {
-            result.push_back(this->update(update));
-        }
-        return result;
-    }
-
-
+    // TODO: add core segment if param is set
     std::vector<Memory::Base::UpdateResult>
     Memory::updateLocking(const Commit& commit)
     {
@@ -30,7 +19,7 @@ namespace armarx::armem::wm
         }
 
         std::vector<Memory::Base::UpdateResult> result;
-        // To throw an exception after the commit if a core segment is missing.
+        // To throw an exception after the commit if a core segment is missing and the memory should not create new ones
         std::vector<std::string> missingCoreSegmentNames;
         for (const auto& [coreSegmentName, updates] : updatesPerCoreSegment)
         {
@@ -66,18 +55,7 @@ namespace armarx::armem::wm
     }
 
 
-    Memory::Base::UpdateResult
-    Memory::update(const EntityUpdate& update)
-    {
-        this->_checkContainerName(update.entityID.memoryName, this->name());
-
-        CoreSegment& segment = getCoreSegment(update.entityID.coreSegmentName);
-        Base::UpdateResult result = segment.update(update);
-        result.memoryUpdateType = UpdateType::UpdatedExisting;
-        return result;
-    }
-
-
+    // TODO: Add core segment if param is set
     Memory::Base::UpdateResult
     Memory::updateLocking(const EntityUpdate& update)
     {
diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.h b/source/RobotAPI/libraries/armem/core/workingmemory/Memory.h
index 99a14dbdd..d52bce5ca 100644
--- a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.h
+++ b/source/RobotAPI/libraries/armem/core/workingmemory/Memory.h
@@ -27,8 +27,6 @@ namespace armarx::armem::wm
         Memory& operator=(const Memory& other) = default;
         Memory& operator=(Memory&& other) = default;
 
-
-        virtual std::vector<Base::UpdateResult> update(const Commit& commit) override;
         /**
          * @brief Perform the commit, locking the core segments.
          *
@@ -37,7 +35,6 @@ namespace armarx::armem::wm
          */
         std::vector<Base::UpdateResult> updateLocking(const Commit& commit);
 
-        virtual Base::UpdateResult update(const EntityUpdate& update) override;
         /**
          * @brief Update the memory, locking the updated core segment.
          */
diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
index 0d6685c45..801536883 100644
--- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
+++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
@@ -178,6 +178,7 @@ namespace armarx::armem::server
                     if (longtermMemory->alwaysTransferSettings.enabled)
                     {
                         wm::Memory tmp(longtermMemory->name());
+                        tmp._addMissingCoreSegmentDuringUpdate = true;
                         tmp.update(update);
                         longtermMemory->append(tmp);
                     }
-- 
GitLab