Make UserSubscription as shared_ptr in Subscription

Currently UserSubscription are used as value in Subscription. This
causes the copy of the object between subscriptionsMap and
subscriptionConfigMap when doing PATCH.

Using a shared_ptr for UserSubscription avoids the memory copy of it.

Tested:

- Using Redfish Event Listener, test subscriptions and eventing.
- Redfish Service Validator passes

Change-Id: I5821b72f28ba737a5c9b75288d377766c84c6a6a
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
diff --git a/include/event_service_store.hpp b/include/event_service_store.hpp
index bf4e545..b0a1d97 100644
--- a/include/event_service_store.hpp
+++ b/include/event_service_store.hpp
@@ -310,7 +310,7 @@
 class EventServiceStore
 {
   public:
-    boost::container::flat_map<std::string, UserSubscription>
+    boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>>
         subscriptionsConfigMap;
     EventServiceConfig eventServiceConfig;
 
@@ -324,18 +324,6 @@
     {
         return eventServiceConfig;
     }
-
-    void updateUserSubscriptionConfig(const UserSubscription& userSub)
-    {
-        const std::string& id = userSub.id;
-        auto obj = subscriptionsConfigMap.find(id);
-        if (obj == subscriptionsConfigMap.end())
-        {
-            BMCWEB_LOG_INFO("No UserSubscription exist with ID:{}", id);
-            return;
-        }
-        obj->second = userSub;
-    }
 };
 
 } // namespace persistent_data
diff --git a/include/persistent_data.hpp b/include/persistent_data.hpp
index ef2adf3..afcdb14 100644
--- a/include/persistent_data.hpp
+++ b/include/persistent_data.hpp
@@ -172,11 +172,11 @@
                             BMCWEB_LOG_DEBUG("Restored subscription: {} {}",
                                              newSub->id, newSub->customText);
 
-                            boost::container::flat_map<
-                                std::string, UserSubscription>& configMap =
-                                EventServiceStore::getInstance()
-                                    .subscriptionsConfigMap;
-                            configMap.emplace(newSub->id, *newSub);
+                            EventServiceStore::getInstance()
+                                .subscriptionsConfigMap.emplace(
+                                    newSub->id,
+                                    std::make_shared<UserSubscription>(
+                                        std::move(*newSub)));
                         }
                     }
                     else
@@ -299,7 +299,11 @@
         for (const auto& it :
              EventServiceStore::getInstance().subscriptionsConfigMap)
         {
-            const UserSubscription& subValue = it.second;
+            if (it.second == nullptr)
+            {
+                continue;
+            }
+            const UserSubscription& subValue = *it.second;
             if (subValue.subscriptionType == "SSE")
             {
                 BMCWEB_LOG_DEBUG("The subscription type is SSE, so skipping.");
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index 5a64472..41f1be9 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -51,6 +51,7 @@
 #include <span>
 #include <string>
 #include <string_view>
+#include <utility>
 
 namespace redfish
 {
@@ -260,18 +261,20 @@
     Subscription(Subscription&&) = delete;
     Subscription& operator=(Subscription&&) = delete;
 
-    Subscription(const persistent_data::UserSubscription& userSubIn,
+    Subscription(std::shared_ptr<persistent_data::UserSubscription> userSubIn,
                  const boost::urls::url_view_base& url,
                  boost::asio::io_context& ioc) :
-        userSub(userSubIn), policy(std::make_shared<crow::ConnectionPolicy>())
+        userSub{std::move(userSubIn)},
+        policy(std::make_shared<crow::ConnectionPolicy>())
     {
-        userSub.destinationUrl = url;
+        userSub->destinationUrl = url;
         client.emplace(ioc, policy);
         // Subscription constructor
         policy->invalidResp = retryRespHandler;
     }
 
     explicit Subscription(crow::sse_socket::Connection& connIn) :
+        userSub{std::make_shared<persistent_data::UserSubscription>()},
         sseConn(&connIn)
     {}
 
@@ -291,7 +294,7 @@
             return;
         }
 
-        if (userSub.retryPolicy != "TerminateAfterRetries")
+        if (userSub->retryPolicy != "TerminateAfterRetries")
         {
             return;
         }
@@ -301,7 +304,7 @@
             {
                 BMCWEB_LOG_INFO(
                     "Subscription {} is deleted after MaxRetryAttempts",
-                    userSub.id);
+                    userSub->id);
                 deleter();
             }
         }
@@ -320,10 +323,10 @@
         if (client)
         {
             client->sendDataWithCallback(
-                std::move(msg), userSub.destinationUrl,
+                std::move(msg), userSub->destinationUrl,
                 static_cast<ensuressl::VerifyCertificate>(
-                    userSub.verifyCertificate),
-                userSub.httpHeaders, boost::beast::http::verb::post,
+                    userSub->verifyCertificate),
+                userSub->httpHeaders, boost::beast::http::verb::post,
                 std::bind_front(&Subscription::resHandler, this,
                                 shared_from_this()));
             return true;
@@ -351,7 +354,7 @@
         logEntryJson["MessageArgs"] = nlohmann::json::array();
         logEntryJson["EventTimestamp"] =
             redfish::time_utils::getDateTimeOffsetNow().first;
-        logEntryJson["Context"] = userSub.customText;
+        logEntryJson["Context"] = userSub->customText;
 
         nlohmann::json msg;
         msg["@odata.type"] = "#Event.v1_4_0.Event";
@@ -376,13 +379,13 @@
             nlohmann::json::object_t bmcLogEntry;
             if (event_log::formatEventLogEntry(
                     logEntry.id, logEntry.messageId, messageArgsView,
-                    logEntry.timestamp, userSub.customText, bmcLogEntry) != 0)
+                    logEntry.timestamp, userSub->customText, bmcLogEntry) != 0)
             {
                 BMCWEB_LOG_DEBUG("Read eventLog entry failed");
                 continue;
             }
 
-            if (!eventMatchesFilter(userSub, bmcLogEntry, ""))
+            if (!eventMatchesFilter(*userSub, bmcLogEntry, ""))
             {
                 BMCWEB_LOG_DEBUG("Event {} did not match the filter",
                                  nlohmann::json(bmcLogEntry).dump());
@@ -426,11 +429,11 @@
             reportId);
 
         // Empty list means no filter. Send everything.
-        if (!userSub.metricReportDefinitions.empty())
+        if (!userSub->metricReportDefinitions.empty())
         {
-            if (std::ranges::find(userSub.metricReportDefinitions,
+            if (std::ranges::find(userSub->metricReportDefinitions,
                                   mrdUri.buffer()) ==
-                userSub.metricReportDefinitions.end())
+                userSub->metricReportDefinitions.end())
             {
                 return;
             }
@@ -447,9 +450,9 @@
 
         // Context is set by user during Event subscription and it must be
         // set for MetricReport response.
-        if (!userSub.customText.empty())
+        if (!userSub->customText.empty())
         {
-            msg["Context"] = userSub.customText;
+            msg["Context"] = userSub->customText;
         }
 
         std::string strMsg =
@@ -496,7 +499,7 @@
             boost::system::errc::success);
     }
 
-    persistent_data::UserSubscription userSub;
+    std::shared_ptr<persistent_data::UserSubscription> userSub;
     std::function<void()> deleter;
 
   private:
@@ -573,10 +576,11 @@
         for (const auto& it : persistent_data::EventServiceStore::getInstance()
                                   .subscriptionsConfigMap)
         {
-            const persistent_data::UserSubscription& newSub = it.second;
+            std::shared_ptr<persistent_data::UserSubscription> newSub =
+                it.second;
 
             boost::system::result<boost::urls::url> url =
-                boost::urls::parse_absolute_uri(newSub.destinationUrl);
+                boost::urls::parse_absolute_uri(newSub->destinationUrl);
 
             if (!url)
             {
@@ -586,7 +590,7 @@
             }
             std::shared_ptr<Subscription> subValue =
                 std::make_shared<Subscription>(newSub, *url, ioc);
-            std::string id = subValue->userSub.id;
+            std::string id = subValue->userSub->id;
             subValue->deleter = [id]() {
                 EventServiceManager::getInstance().deleteSubscription(id);
             };
@@ -664,8 +668,10 @@
                         newSub.id = id;
                         auto inserted =
                             persistent_data::EventServiceStore::getInstance()
-                                .subscriptionsConfigMap.insert(
-                                    std::pair(id, newSub));
+                                .subscriptionsConfigMap.insert(std::pair(
+                                    id, std::make_shared<
+                                            persistent_data::UserSubscription>(
+                                            newSub)));
                         if (inserted.second)
                         {
                             break;
@@ -767,11 +773,11 @@
         for (const auto& it : subscriptionsMap)
         {
             std::shared_ptr<Subscription> entry = it.second;
-            if (entry->userSub.eventFormatType == eventFormatType)
+            if (entry->userSub->eventFormatType == eventFormatType)
             {
                 eventLogSubCount++;
             }
-            else if (entry->userSub.eventFormatType == metricReportFormatType)
+            else if (entry->userSub->eventFormatType == metricReportFormatType)
             {
                 metricReportSubCount++;
             }
@@ -836,12 +842,10 @@
         }
 
         // Set Subscription ID for back trace
-        subValue->userSub.id = id;
-
-        persistent_data::UserSubscription newSub(subValue->userSub);
+        subValue->userSub->id = id;
 
         persistent_data::EventServiceStore::getInstance()
-            .subscriptionsConfigMap.emplace(newSub.id, newSub);
+            .subscriptionsConfigMap.emplace(id, subValue->userSub);
 
         updateNoOfSubscribersCount();
 
@@ -947,7 +951,7 @@
             if (entryIsThisConn)
             {
                 persistent_data::EventServiceStore::getInstance()
-                    .subscriptionsConfigMap.erase(entry->userSub.id);
+                    .subscriptionsConfigMap.erase(entry->userSub->id);
                 it = subscriptionsMap.erase(it);
                 return;
             }
@@ -966,7 +970,7 @@
             subscriptionsMap,
             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
                    entry) {
-                return (entry.second->userSub.subscriptionType ==
+                return (entry.second->userSub->subscriptionType ==
                         subscriptionTypeSSE);
             });
         return static_cast<size_t>(size);
@@ -1012,7 +1016,8 @@
         for (auto& it : subscriptionsMap)
         {
             std::shared_ptr<Subscription>& entry = it.second;
-            if (!eventMatchesFilter(entry->userSub, eventMessage, resourceType))
+            if (!eventMatchesFilter(*entry->userSub, eventMessage,
+                                    resourceType))
             {
                 BMCWEB_LOG_DEBUG("Filter didn't match");
                 continue;
@@ -1133,7 +1138,7 @@
         for (const auto& it : subscriptionsMap)
         {
             std::shared_ptr<Subscription> entry = it.second;
-            if (entry->userSub.eventFormatType == "Event")
+            if (entry->userSub->eventFormatType == "Event")
             {
                 entry->filterAndSendEventLogs(eventRecords);
             }
@@ -1331,7 +1336,7 @@
              EventServiceManager::getInstance().subscriptionsMap)
         {
             Subscription& entry = *it.second;
-            if (entry.userSub.eventFormatType == metricReportFormatType)
+            if (entry.userSub->eventFormatType == metricReportFormatType)
             {
                 entry.filterAndSendReports(id, *readings);
             }
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index 7510f0f..a75da35 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -444,9 +444,8 @@
 
             std::shared_ptr<Subscription> subValue =
                 std::make_shared<Subscription>(
-                    persistent_data::UserSubscription{}, *url, app.ioContext());
-
-            subValue->userSub.destinationUrl = std::move(*url);
+                    std::make_shared<persistent_data::UserSubscription>(), *url,
+                    app.ioContext());
 
             if (subscriptionType)
             {
@@ -456,12 +455,12 @@
                         asyncResp->res, *subscriptionType, "SubscriptionType");
                     return;
                 }
-                subValue->userSub.subscriptionType = *subscriptionType;
+                subValue->userSub->subscriptionType = *subscriptionType;
             }
             else
             {
                 // Default
-                subValue->userSub.subscriptionType = "RedfishEvent";
+                subValue->userSub->subscriptionType = "RedfishEvent";
             }
 
             if (protocol != "Redfish")
@@ -470,11 +469,11 @@
                                                  "Protocol");
                 return;
             }
-            subValue->userSub.protocol = protocol;
+            subValue->userSub->protocol = protocol;
 
             if (verifyCertificate)
             {
-                subValue->userSub.verifyCertificate = *verifyCertificate;
+                subValue->userSub->verifyCertificate = *verifyCertificate;
             }
 
             if (eventFormatType2)
@@ -487,12 +486,12 @@
                         asyncResp->res, *eventFormatType2, "EventFormatType");
                     return;
                 }
-                subValue->userSub.eventFormatType = *eventFormatType2;
+                subValue->userSub->eventFormatType = *eventFormatType2;
             }
             else
             {
                 // If not specified, use default "Event"
-                subValue->userSub.eventFormatType = "Event";
+                subValue->userSub->eventFormatType = "Event";
             }
 
             if (context)
@@ -505,7 +504,7 @@
                                                  maxContextSize);
                     return;
                 }
-                subValue->userSub.customText = *context;
+                subValue->userSub->customText = *context;
             }
 
             if (headers)
@@ -538,7 +537,7 @@
                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
                             return;
                         }
-                        subValue->userSub.httpHeaders.set(item.first, *value);
+                        subValue->userSub->httpHeaders.set(item.first, *value);
                     }
                 }
             }
@@ -555,12 +554,12 @@
                         return;
                     }
                 }
-                subValue->userSub.registryPrefixes = *regPrefixes;
+                subValue->userSub->registryPrefixes = *regPrefixes;
             }
 
             if (originResources)
             {
-                subValue->userSub.originResources = *originResources;
+                subValue->userSub->originResources = *originResources;
             }
 
             if (resTypes)
@@ -575,7 +574,7 @@
                         return;
                     }
                 }
-                subValue->userSub.resourceTypes = *resTypes;
+                subValue->userSub->resourceTypes = *resTypes;
             }
 
             if (msgIds)
@@ -584,14 +583,14 @@
 
                 // If no registry prefixes are mentioned, consider all
                 // supported prefixes
-                if (subValue->userSub.registryPrefixes.empty())
+                if (subValue->userSub->registryPrefixes.empty())
                 {
                     registryPrefix.assign(supportedRegPrefixes.begin(),
                                           supportedRegPrefixes.end());
                 }
                 else
                 {
-                    registryPrefix = subValue->userSub.registryPrefixes;
+                    registryPrefix = subValue->userSub->registryPrefixes;
                 }
 
                 for (const std::string& id : *msgIds)
@@ -625,7 +624,7 @@
                     }
                 }
 
-                subValue->userSub.registryMsgIds = *msgIds;
+                subValue->userSub->registryMsgIds = *msgIds;
             }
 
             if (retryPolicy)
@@ -637,12 +636,12 @@
                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
                     return;
                 }
-                subValue->userSub.retryPolicy = *retryPolicy;
+                subValue->userSub->retryPolicy = *retryPolicy;
             }
             else
             {
                 // Default "TerminateAfterRetries"
-                subValue->userSub.retryPolicy = "TerminateAfterRetries";
+                subValue->userSub->retryPolicy = "TerminateAfterRetries";
             }
 
             if (mrdJsonArray)
@@ -657,7 +656,7 @@
                     {
                         return;
                     }
-                    subValue->userSub.metricReportDefinitions.emplace_back(
+                    subValue->userSub->metricReportDefinitions.emplace_back(
                         mrdUri);
                 }
             }
@@ -707,7 +706,7 @@
                 const std::string& id = param;
 
                 const persistent_data::UserSubscription& userSub =
-                    subValue->userSub;
+                    *subValue->userSub;
 
                 nlohmann::json& jVal = asyncResp->res.jsonValue;
                 jVal["@odata.type"] =
@@ -780,7 +779,7 @@
 
                 if (context)
                 {
-                    subValue->userSub.customText = *context;
+                    subValue->userSub->customText = *context;
                 }
 
                 if (headers)
@@ -802,7 +801,7 @@
                             fields.set(it.first, *value);
                         }
                     }
-                    subValue->userSub.httpHeaders = std::move(fields);
+                    subValue->userSub->httpHeaders = std::move(fields);
                 }
 
                 if (retryPolicy)
@@ -816,18 +815,14 @@
                                                          "DeliveryRetryPolicy");
                         return;
                     }
-                    subValue->userSub.retryPolicy = *retryPolicy;
+                    subValue->userSub->retryPolicy = *retryPolicy;
                 }
 
                 if (verifyCertificate)
                 {
-                    subValue->userSub.verifyCertificate = *verifyCertificate;
+                    subValue->userSub->verifyCertificate = *verifyCertificate;
                 }
 
-                // Sync Subscription to UserSubscriptionConfig
-                persistent_data::EventServiceStore::getInstance()
-                    .updateUserSubscriptionConfig(subValue->userSub);
-
                 EventServiceManager::getInstance().updateSubscriptionData();
             });
     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
diff --git a/redfish-core/lib/eventservice_sse.hpp b/redfish-core/lib/eventservice_sse.hpp
index 80c0a3a..8625c63 100644
--- a/redfish-core/lib/eventservice_sse.hpp
+++ b/redfish-core/lib/eventservice_sse.hpp
@@ -47,12 +47,19 @@
     std::shared_ptr<Subscription> subValue =
         std::make_shared<Subscription>(conn);
 
-    // GET on this URI means, Its SSE subscriptionType.
-    subValue->userSub.subscriptionType = redfish::subscriptionTypeSSE;
+    if (subValue->userSub == nullptr)
+    {
+        BMCWEB_LOG_ERROR("Subscription data is null");
+        conn.close("Internal Error");
+        return;
+    }
 
-    subValue->userSub.protocol = "Redfish";
-    subValue->userSub.retryPolicy = "TerminateAfterRetries";
-    subValue->userSub.eventFormatType = "Event";
+    // GET on this URI means, Its SSE subscriptionType.
+    subValue->userSub->subscriptionType = redfish::subscriptionTypeSSE;
+
+    subValue->userSub->protocol = "Redfish";
+    subValue->userSub->retryPolicy = "TerminateAfterRetries";
+    subValue->userSub->eventFormatType = "Event";
 
     std::string id = manager.addSSESubscription(subValue, lastEventId);
     if (id.empty())