Handle read-only requests concurrently if possible 06/313406/6
authorKrzysztof Malysa <k.malysa@samsung.com>
Tue, 25 Jun 2024 11:58:45 +0000 (13:58 +0200)
committerKrzysztof Malysa <k.malysa@samsung.com>
Fri, 9 Aug 2024 17:09:36 +0000 (19:09 +0200)
AdminCheck, List and sometimes Check and SimpleCheck as "read-only"
requests can be handled with the old policy while other requests install
a new policy.

This commit implements this logic, by creating a thread for handling
non-read-only requests and handling read-only requests in the current
thread.

This optimization makes cynara favour the read-only operations, reducing
request latency during writes to the database. In the below benchmark we can
see that although the median time did rise up due to overhead, the average time
to complete the response is 10 times lower and the max time is also reasonable.

The benchmark runs N threads that execute checks concurrently and one thread
that executes modifications to the cynara database. If either all modifications
are done or all threads are done executing checks, the benchmark ends. Number
of completed checks and modifications is shown below as well.

cynara-test tc02_concurrent_checks_and_modifications_online:
- before:
  - T1 concurrent checks = 41 and T1 modifications = 60:
      min 135.888us max 355409.247us avg 72164.196us median 51363.480us stddev 54810.217us
  - T2 concurrent checks = 4 and T1 modifications = 60:
      min 89501.124us max 2780571.441us avg 1434964.172us median 2756211.420us stddev 1321470.468us
  - T4 concurrent checks = 88 and T1 modifications = 60:
      min 172.504us max 507472.011us avg 127967.290us median 94624.078us stddev 90096.334us
  - T8 concurrent checks = 115 and T1 modifications = 60:
      min 182.550us max 643392.305us avg 201632.817us median 152837.071us stddev 114870.449us
  - T16 concurrent checks = 117 and T1 modifications = 60:
      min 251.474us max 1442323.541us avg 408241.545us median 278515.998us stddev 298364.669us
- after:
  - T1 concurrent checks = 4036 and T1 modifications = 41:
      min 27.113us max 40540.287us avg 469.489us median 122.090us stddev 3404.852us
  - T2 concurrent checks = 8072 and T1 modifications = 41:
      min 35.319us max 38290.327us avg 472.353us median 133.938us stddev 3082.039us
  - T4 concurrent checks = 16144 and T1 modifications = 42:
      min 32.213us max 36620.530us avg 467.503us median 122.385us stddev 2843.337us
  - T8 concurrent checks = 32288 and T1 modifications = 42:
      min 30.648us max 32727.901us avg 386.306us median 166.153us stddev 1972.602us
  - T16 concurrent checks = 64576 and T1 modifications = 55:
      min 34.016us max 38859.047us avg 456.097us median 315.623us stddev 1541.104us

With this change:
- Cynara does not choke when writes are happening.
- The variance of the measurements improves greatly.
- The max time the request takes is always low.

Change-Id: Ic5e8824a84ac08128a035f1e27e3013d96d12b71

73 files changed:
src/agent/logic/Logic.cpp
src/agent/logic/Logic.h
src/agent/socket/AgentSocketClient.cpp
src/agent/socket/AgentSocketClient.h
src/chsgen/CMakeLists.txt
src/chsgen/ChecksumGenerator.cpp
src/client-async/sockets/SocketClientAsync.cpp
src/client-async/sockets/SocketClientAsync.h
src/common/containers/MutexedBinaryQueue.h [new file with mode: 0644]
src/common/plugin/PluginManager.cpp
src/common/plugin/PluginManager.h
src/common/protocol/ProtocolAdmin.cpp
src/common/protocol/ProtocolAgent.cpp
src/common/protocol/ProtocolClient.cpp
src/common/protocol/ProtocolMonitorGet.cpp
src/common/request/AdminCheckRequest.cpp
src/common/request/AdminCheckRequest.h
src/common/request/AgentActionRequest.cpp
src/common/request/AgentActionRequest.h
src/common/request/AgentRegisterRequest.cpp
src/common/request/AgentRegisterRequest.h
src/common/request/CancelRequest.cpp
src/common/request/CancelRequest.h
src/common/request/CheckRequest.cpp
src/common/request/CheckRequest.h
src/common/request/DescriptionListRequest.cpp
src/common/request/DescriptionListRequest.h
src/common/request/EraseRequest.cpp
src/common/request/EraseRequest.h
src/common/request/InsertOrUpdateBucketRequest.cpp
src/common/request/InsertOrUpdateBucketRequest.h
src/common/request/ListRequest.cpp
src/common/request/ListRequest.h
src/common/request/MonitorEntriesPutRequest.cpp
src/common/request/MonitorEntriesPutRequest.h
src/common/request/MonitorEntryPutRequest.cpp
src/common/request/MonitorEntryPutRequest.h
src/common/request/MonitorGetEntriesRequest.cpp
src/common/request/MonitorGetEntriesRequest.h
src/common/request/MonitorGetFlushRequest.cpp
src/common/request/MonitorGetFlushRequest.h
src/common/request/RemoveBucketRequest.cpp
src/common/request/RemoveBucketRequest.h
src/common/request/Request.h
src/common/request/RequestContext.h
src/common/request/RequestTaker.h
src/common/request/SetPoliciesRequest.cpp
src/common/request/SetPoliciesRequest.h
src/common/request/SignalRequest.cpp
src/common/request/SignalRequest.h
src/common/request/SimpleCheckRequest.cpp
src/common/request/SimpleCheckRequest.h
src/common/sockets/SocketClient.cpp
src/common/sockets/SocketClient.h
src/common/types/Link.h
src/monitor/socket/MonitorSocketClient.cpp
src/service/CMakeLists.txt
src/service/logic/Logic.cpp
src/service/logic/Logic.h
src/service/sockets/Descriptor.cpp
src/service/sockets/Descriptor.h
src/service/sockets/SocketManager.cpp
src/service/sockets/SocketManager.h
src/service/utils/Channel.h [new file with mode: 0644]
src/storage/InMemoryStorageBackend.cpp
src/storage/InMemoryStorageBackend.h
src/storage/Storage.cpp
src/storage/Storage.h
src/storage/StorageBackend.h
test/common/protocols/NegativeTestHelper.h
test/common/protocols/RequestTestHelper.h
test/common/protocols/ResponseTestHelper.h
test/storage/storage/fakestoragebackend.h

index 47709ed80704b93eb07594d3270ab024c1fd13b9..e9dc3bb9d032d51ac3e3c60fb241504f40ba74e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -30,6 +30,7 @@
 
 #include <common.h>
 #include <config/PathConfig.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <log/log.h>
 #include <protocol/Protocol.h>
 #include <protocol/ProtocolAgent.h>
@@ -60,7 +61,7 @@ namespace Cynara {
 Logic::Logic(const AgentType &agentType) : m_agentType(agentType),
         m_socketClient(PathConfig::SocketPath::agent, std::make_shared<ProtocolAgent>()) {
     m_responseTakerPtr = std::make_shared<ProtocolAgent>();
-    m_responseBuffer = std::make_shared<BinaryQueue>();
+    m_responseBuffer = std::make_shared<MutexedBinaryQueue>();
     if (!m_notify.init()) {
         LOGW("Couldn't initialize notification object.");
         return;
@@ -172,11 +173,12 @@ int Logic::putResponse(const AgentResponseType responseType,
     }
 
     AgentActionRequest request(responseType, pluginData, sequenceNumber);
-    m_responseBuffer->clear();
+    m_responseBuffer->lock()->clear();
     RequestContext context(ResponseTakerPtr(), m_responseBuffer);
     request.execute(*m_responseTakerPtr, context);
-    return m_socketClient.sendDataToServer(*m_responseBuffer) ? CYNARA_API_SUCCESS :
-                                                     CYNARA_API_SERVICE_NOT_AVAILABLE;
+    auto lockedResponseBuffer = m_responseBuffer->lock();
+    return m_socketClient.sendDataToServer(lockedResponseBuffer) ?
+        CYNARA_API_SUCCESS : CYNARA_API_SERVICE_NOT_AVAILABLE;
 }
 
 int Logic::cancelWaiting(void) {
index d41db774a346ee49f26f1b0945f5ae74d2d4b9d3..a9c3cbf9295141fb1ec638a87c62cb05be35bdf3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -34,6 +34,7 @@
 #include <types/Agent.h>
 
 #include <api/ApiInterface.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <socket/AgentSocketClient.h>
 
 namespace Cynara {
@@ -58,7 +59,7 @@ private:
     AgentSocketClient m_socketClient;
 
     RequestTakerPtr m_responseTakerPtr;
-    BinaryQueuePtr m_responseBuffer;
+    MutexedBinaryQueuePtr m_responseBuffer;
 
     FdNotifyObject m_notify;
 
index 457ad5734d6dd68ac8e9c9437e72280d7fa49797..f75e0dc043d4ccd348cc1fba77aceaf68c7f358c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -32,6 +32,7 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
+#include <containers/MutexedBinaryQueue.h>
 #include <error/SafeStrError.h>
 #include <log/log.h>
 #include <protocol/Protocol.h>
@@ -47,7 +48,7 @@ namespace Cynara {
 
 AgentSocketClient::AgentSocketClient(const std::string &socketPath, ProtocolPtr protocol)
         : m_socket(socketPath), m_protocol(protocol), m_notifyFd(-1) {
-    m_writeQueue = std::make_shared<BinaryQueue>();
+    m_writeQueue = std::make_shared<MutexedBinaryQueue>();
     m_readQueue = std::make_shared<BinaryQueue>();
 }
 
@@ -61,7 +62,8 @@ ResponsePtr AgentSocketClient::askCynaraServer(const Request &request) {
     request.execute(*m_protocol, context);
 
     //send request to cynara
-    if (!sendDataToServer(*m_writeQueue)) {
+    auto lockedWriteQueue = m_writeQueue->lock();
+    if (!sendDataToServer(lockedWriteQueue)) {
         return nullptr;
     }
 
@@ -120,8 +122,8 @@ ResponsePtr AgentSocketClient::receiveResponseFromServer(void) {
     return response;
 }
 
-bool AgentSocketClient::sendDataToServer(BinaryQueue &data) {
-    if (m_socket.sendToServer(data) == Socket::SendStatus::CONNECTION_LOST) {
+bool AgentSocketClient::sendDataToServer(MutexedBinaryQueue::LockedBinaryQueue &data) {
+    if (m_socket.sendToServer(*data) == Socket::SendStatus::CONNECTION_LOST) {
         LOGW("Error sending data to Cynara. Service not available.");
         return false;
     }
@@ -147,7 +149,7 @@ AgentSocketState AgentSocketClient::connect(void) {
 
 void AgentSocketClient::resetState(void) {
     m_readQueue->clear();
-    m_writeQueue->clear();
+    m_writeQueue->lock()->clear();
 }
 
 } // namespace Cynara
index 215a73405a31dfd66d0ef0751f47341bab817f6d..e071efbf5b6d97a941960408b580df1984900d5f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -32,6 +32,7 @@
 #include <string>
 
 #include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <protocol/Protocol.h>
 #include <request/pointers.h>
 #include <response/pointers.h>
@@ -63,14 +64,14 @@ public:
 
     ResponsePtr getBufferedResponse(void);
     ResponsePtr receiveResponseFromServer(void);
-    bool sendDataToServer(BinaryQueue &data);
+    bool sendDataToServer(MutexedBinaryQueue::LockedBinaryQueue &data);
     ResponsePtr askCynaraServer(const Request &request);
 
 private:
     Socket m_socket;
     ProtocolPtr m_protocol;
     BinaryQueuePtr m_readQueue;
-    BinaryQueuePtr m_writeQueue;
+    MutexedBinaryQueuePtr m_writeQueue;
     int m_notifyFd;
 
     void resetState(void);
index c48ff7a83410e063e5e3d126a6405f22ed1f9eed..7f001e8c851eb244dd8665c70d46bc040dabd217 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2015-2020 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2015-2024 Samsung Electronics Co., Ltd All Rights Reserved
 #
 # This file is licensed under the terms of MIT License or the Apache License
 # Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -28,6 +28,7 @@ SET(CHSGEN_SOURCES
     ${CHSGEN_PATH}/main.cpp
     ${CYNARA_EXTERNAL_SRC_PATH}/md5.c
     ${CYNARA_EXTERNAL_SRC_PATH}/md5wrapper.cpp
+    ${CYNARA_PATH}/common/error/SafeStrError.cpp
     )
 
 INCLUDE_DIRECTORIES(
index 105257ef51a10ea246c9b2ddf793d600c2ea5bfb..620dff8c3a48dcd6d1fc95aab0d31421305f5539 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2015-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -37,6 +37,7 @@
 #include <unistd.h>
 
 #include <cynara-error.h>
+#include <error/SafeStrError.h>
 #include <md5wrapper.h>
 
 #include "ChecksumGenerator.h"
@@ -77,12 +78,12 @@ std::string generateCrypt(const std::string &data) {
         int err = errno;
         if (err == ENOSYS) {
             std::cerr << "'crypt' function was not implemented; error [" << err << "] : <"
-                << strerror(err) << ">" << std::endl;
+                << safeStrError(err) << ">" << std::endl;
         } else {
-            std::cerr << "'crypt' function error [" << err << "] : <" << strerror(err) << ">"
+            std::cerr << "'crypt' function error [" << err << "] : <" << safeStrError(err) << ">"
                 << std::endl;
         }
-        throw std::runtime_error(strerror(err));
+        throw std::runtime_error(safeStrError(err));
     }
 }
 
index 24cc2531bcc96040c9f78de8da707ddadeb54d15..ef6a4f84aa0d6046f62203956403fcc8fb0f5710 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -26,6 +26,7 @@
  *              client
  */
 
+#include <containers/MutexedBinaryQueue.h>
 #include <request/Request.h>
 #include <request/RequestContext.h>
 
@@ -36,7 +37,7 @@ namespace Cynara {
 SocketClientAsync::SocketClientAsync(const std::string &socketPath, ProtocolPtr protocol)
     : m_socket(socketPath, 0), m_protocol(protocol) {
     m_readQueue = std::make_shared<BinaryQueue>();
-    m_writeQueue = std::make_shared<BinaryQueue>();
+    m_writeQueue = std::make_shared<MutexedBinaryQueue>();
 }
 
 Socket::ConnectionStatus SocketClientAsync::connect(void) {
@@ -67,11 +68,11 @@ void SocketClientAsync::appendRequest(const Request &request) {
 }
 
 bool SocketClientAsync::isDataToSend(void) {
-    return m_socket.isDataToSend() || !m_writeQueue->empty();
+    return m_socket.isDataToSend() || !m_writeQueue->lock()->empty();
 }
 
 Socket::SendStatus SocketClientAsync::sendToCynara(void) {
-    return m_socket.sendToServer(*m_writeQueue);
+    return m_socket.sendToServer(*m_writeQueue->lock());
 }
 
 bool SocketClientAsync::receiveFromCynara(void) {
@@ -85,7 +86,7 @@ ResponsePtr SocketClientAsync::getResponse(void) {
 void SocketClientAsync::clear(void)
 {
     m_readQueue->clear();
-    m_writeQueue->clear();
+    m_writeQueue->lock()->clear();
 }
 
 } // namespace Cynara
index fbd02bde8f84b3fc9b71a3280c52ca095ac45628..8f7b1b3dd1cf7282279690a8f8d62115f40cfa79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -32,7 +32,7 @@
 #include <memory>
 #include <string>
 
-#include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <protocol/Protocol.h>
 #include <request/pointers.h>
 #include <response/pointers.h>
@@ -62,7 +62,7 @@ private:
     Socket m_socket;
     ProtocolPtr m_protocol;
     BinaryQueuePtr m_readQueue;
-    BinaryQueuePtr m_writeQueue;
+    MutexedBinaryQueuePtr m_writeQueue;
 
     void clear(void);
 };
diff --git a/src/common/containers/MutexedBinaryQueue.h b/src/common/containers/MutexedBinaryQueue.h
new file mode 100644 (file)
index 0000000..711474a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * This file is licensed under the terms of MIT License or the Apache License
+ * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
+ * See the LICENSE file or the notice below for Apache License Version 2.0
+ * details.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file        src/common/containers/MutexedBinaryQueue.h
+ * @author      Krzysztof MaÅ‚ysa <k.malysa@samsung.com>
+ * @version     1.0
+ * @brief       This file is the header and implementation file of binary queue with mutex
+ */
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <utility>
+
+#include "BinaryQueue.h"
+
+namespace Cynara {
+
+class MutexedBinaryQueue;
+
+using MutexedBinaryQueuePtr = std::shared_ptr<MutexedBinaryQueue>;
+using MutexedBinaryQueueWeakPtr = std::weak_ptr<MutexedBinaryQueue>;
+
+class MutexedBinaryQueue {
+public:
+    explicit MutexedBinaryQueue(BinaryQueuePtr ptr = std::make_shared<BinaryQueue>())
+    : m_mutex{std::make_shared<std::mutex>()}, m_binaryQueue{std::move(ptr)} {}
+
+    struct LockedBinaryQueue : public BinaryQueuePtr {
+        LockedBinaryQueue(std::shared_ptr<std::mutex> mtx, BinaryQueuePtr binaryQueue)
+        : BinaryQueuePtr{std::move(binaryQueue)}, m_mutex{std::move(mtx)}, m_guard{*m_mutex} {}
+
+    private:
+        std::shared_ptr<std::mutex> m_mutex;
+        std::lock_guard<std::mutex> m_guard;
+    };
+
+    LockedBinaryQueue lock() { return {m_mutex, m_binaryQueue}; }
+
+private:
+    std::shared_ptr<std::mutex> m_mutex;
+    BinaryQueuePtr m_binaryQueue;
+};
+
+} // namespace Cynara
index 06bcc8e03cea2e997c8376a9eda7a45674d23cc2..9e9318699ac65bad10130dd2ea62538d74f38646 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2023 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -169,5 +169,9 @@ void PluginManager::openPlugin(const std::string &path) {
     m_pluginLibs.push_back(std::move(handlePtr));
 }
 
+std::unique_ptr<PluginManagerReadOnlyCopy> PluginManager::clone() const {
+    return std::make_unique<PluginManagerReadOnlyCopy>(getPolicyDescriptions());
+}
+
 } // namespace Cynara
 
index aaca84a01eaafd86e2e58d546af741e342abdb92..94e44213acd63506b16cbb75711ed653d442ef27 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -43,6 +43,8 @@
 namespace Cynara {
 typedef std::shared_ptr<ExternalPluginInterface> ExternalPluginPtr;
 
+class PluginManagerReadOnlyCopy;
+
 class PluginManager {
 public:
     PluginManager(const std::string &pluginDir);
@@ -56,6 +58,8 @@ public:
 
     void checkPolicyType(PolicyType pType) const;
 
+    std::unique_ptr<PluginManagerReadOnlyCopy> clone() const;
+
 private:
     typedef std::unique_ptr<void, std::function<void (void*)>> PluginLibPtr;
     typedef std::list<PluginLibPtr> PluginLibs;
@@ -67,6 +71,19 @@ private:
     void openPlugin(const std::string &path);
 };
 
+class PluginManagerReadOnlyCopy {
+public:
+    explicit PluginManagerReadOnlyCopy(std::vector<PolicyDescription> descriptions)
+    : m_descriptions{std::move(descriptions)} {}
+
+    const std::vector<PolicyDescription>& getPolicyDescriptions() const noexcept {
+        return m_descriptions;
+    }
+
+private:
+    std::vector<PolicyDescription> m_descriptions;
+};
+
 } // namespace Cynara
 
 #endif /* SRC_COMMON_PLUGIN_PLUGINMANAGER_H_ */
index a8632e00e52515c4e83aa1285b4e3332e6ae22e7..1266ef38213ae6cf60b82492a18eb8d051b43386 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -298,7 +298,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const AdminCheckReque
     ProtocolSerialization::serialize(frame, request.startBucket());
     ProtocolSerialization::serialize(frame, request.recursive());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const DescriptionListRequest &request) {
@@ -307,7 +308,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const DescriptionList
 
     ProtocolSerialization::serialize(frame, OpDescriptionListRequest);
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const EraseRequest &request) {
@@ -324,7 +326,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const EraseRequest &r
     ProtocolSerialization::serialize(frame, request.recursive());
     ProtocolSerialization::serialize(frame, request.filter());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context,
@@ -340,7 +343,8 @@ void ProtocolAdmin::execute(const RequestContext &context,
     ProtocolSerialization::serialize(frame, request.bucketId());
     ProtocolSerialization::serialize(frame, request.result());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const ListRequest &request) {
@@ -355,7 +359,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const ListRequest &re
     ProtocolSerialization::serialize(frame, request.bucket());
     ProtocolSerialization::serialize(frame, request.filter());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const RemoveBucketRequest &request) {
@@ -367,7 +372,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const RemoveBucketReq
     ProtocolSerialization::serialize(frame, OpRemoveBucket);
     ProtocolSerialization::serialize(frame, request.bucketId());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const SetPoliciesRequest &request) {
@@ -383,7 +389,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const SetPoliciesRequ
     ProtocolSerialization::serialize(frame, request.policiesToBeInsertedOrUpdated());
     ProtocolSerialization::serialize(frame, request.policiesToBeRemoved());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const AdminCheckResponse &response) {
@@ -401,7 +408,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const AdminCheckRespo
     ProtocolSerialization::serialize(frame, response.isBucketValid());
     ProtocolSerialization::serialize(frame, response.isDbCorrupted());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const CodeResponse &response) {
@@ -414,7 +422,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const CodeResponse &r
     ProtocolSerialization::serialize(frame, OpCodeResponse);
     ProtocolSerialization::serialize(frame, static_cast<ProtocolResponseCode>(response.m_code));
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const DescriptionListResponse &response)
@@ -430,7 +439,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const DescriptionList
     ProtocolSerialization::serialize(frame, response.descriptions());
     ProtocolSerialization::serialize(frame, response.isDbCorrupted());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAdmin::execute(const RequestContext &context, const ListResponse &response) {
@@ -446,7 +456,8 @@ void ProtocolAdmin::execute(const RequestContext &context, const ListResponse &r
     ProtocolSerialization::serialize(frame, response.isBucketValid());
     ProtocolSerialization::serialize(frame, response.isDbCorrupted());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 } // namespace Cynara
index f194933169f7688d02ce55f998982f7dde978647..5ee7a773ebf08ad5d18fa30cbf4b2966fba28f3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -157,7 +157,8 @@ void ProtocolAgent::execute(const RequestContext &context, const AgentActionRequ
     ProtocolSerialization::serialize(frame, request.type());
     ProtocolSerialization::serialize(frame, request.data());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAgent::execute(const RequestContext &context, const AgentRegisterRequest &request) {
@@ -169,7 +170,8 @@ void ProtocolAgent::execute(const RequestContext &context, const AgentRegisterRe
     ProtocolSerialization::serialize(frame, OpAgentRegisterRequest);
     ProtocolSerialization::serialize(frame, request.agentType());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAgent::execute(const RequestContext &context, const AgentRegisterResponse &response) {
@@ -181,7 +183,8 @@ void ProtocolAgent::execute(const RequestContext &context, const AgentRegisterRe
     ProtocolSerialization::serialize(frame, OpAgentRegisterResponse);
     ProtocolSerialization::serialize(frame, static_cast<ProtocolResponseCode>(response.m_code));
 
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolAgent::execute(const RequestContext &context, const AgentActionResponse &response) {
@@ -194,7 +197,8 @@ void ProtocolAgent::execute(const RequestContext &context, const AgentActionResp
     ProtocolSerialization::serialize(frame, response.type());
     ProtocolSerialization::serialize(frame, response.data());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 } // namespace Cynara
index 45373c08f3e75f76ef504d391b268ebb5fa97845..bf8a12c6e82273e04b6e7632f1d1adb8d4fdefe3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -212,7 +212,8 @@ void ProtocolClient::execute(const RequestContext &context, const CancelRequest
 
     ProtocolSerialization::serialize(frame, OpCancelRequest);
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolClient::execute(const RequestContext &context, const CheckRequest &request) {
@@ -225,7 +226,8 @@ void ProtocolClient::execute(const RequestContext &context, const CheckRequest &
     ProtocolSerialization::serialize(frame, OpCheckPolicyRequest);
     ProtocolSerialization::serialize(frame, request.key());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolClient::execute(const RequestContext &context, const SimpleCheckRequest &request) {
@@ -238,7 +240,8 @@ void ProtocolClient::execute(const RequestContext &context, const SimpleCheckReq
     ProtocolSerialization::serialize(frame, OpSimpleCheckPolicyRequest);
     ProtocolSerialization::serialize(frame, request.key());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolClient::execute(const RequestContext &context,
@@ -251,7 +254,8 @@ void ProtocolClient::execute(const RequestContext &context,
 
     ProtocolSerialization::serialize(frame, OpMonitorEntriesPutRequest);
     ProtocolSerialization::serialize(frame, request.monitorEntries());
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolClient::execute(const RequestContext &context, const MonitorEntryPutRequest &request) {
@@ -262,7 +266,8 @@ void ProtocolClient::execute(const RequestContext &context, const MonitorEntryPu
     const auto &entry = request.monitorEntry();
     ProtocolSerialization::serialize(frame, OpMonitorEntryPutRequest);
     ProtocolSerialization::serialize(frame, entry);
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolClient::execute(const RequestContext &context, const CancelResponse &response) {
@@ -273,7 +278,8 @@ void ProtocolClient::execute(const RequestContext &context, const CancelResponse
 
     ProtocolSerialization::serialize(frame, OpCancelResponse);
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolClient::execute(const RequestContext &context, const CheckResponse &response) {
@@ -288,7 +294,8 @@ void ProtocolClient::execute(const RequestContext &context, const CheckResponse
     ProtocolSerialization::serialize(frame, response.m_resultRef.policyType());
     ProtocolSerialization::serialize(frame, response.m_resultRef.metadata());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolClient::execute(const RequestContext &context, const SimpleCheckResponse &response) {
@@ -305,7 +312,8 @@ void ProtocolClient::execute(const RequestContext &context, const SimpleCheckRes
     ProtocolSerialization::serialize(frame, response.getResult().policyType());
     ProtocolSerialization::serialize(frame, response.getResult().metadata());
 
-    ProtocolFrameSerializer::finishSerialization(frame, *(context.responseQueue()));
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 } // namespace Cynara
index 2ca589ff8cb0bae4f93790adb1b18f5e78de1ccd..529a510407edab9198ddbd72a0b7e365c08438ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -133,7 +133,8 @@ void ProtocolMonitorGet::execute(const RequestContext &context,
     ProtocolSerialization::serialize(frame, OpMonitorGetEntriesRequest);
     ProtocolSerialization::serialize(frame,
                                      static_cast<ProtocolFrameFieldsCount>(request.bufferSize()));
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolMonitorGet::execute(const RequestContext &context,
@@ -143,7 +144,8 @@ void ProtocolMonitorGet::execute(const RequestContext &context,
 
     ProtocolFrame frame = ProtocolFrameSerializer::startSerialization(request.sequenceNumber());
     ProtocolSerialization::serialize(frame, OpMonitorGetFlushRequest);
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 void ProtocolMonitorGet::execute(const RequestContext &context,
@@ -158,7 +160,8 @@ void ProtocolMonitorGet::execute(const RequestContext &context,
     ProtocolSerialization::serializeCustomLimit(frame, response.entries(),
                                                 CYNARA_MAX_MONITOR_BUFFER_SIZE);
 
-    ProtocolFrameSerializer::finishSerialization(frame, *context.responseQueue());
+    ProtocolFrameSerializer::finishSerialization(frame,
+                                                 *context.responseQueue()->lock());
 }
 
 } // namespace Cynara
index e14591c9ab05e021a6458f8f67a0790bbf7f3e5c..f7a01f04f2293427bb944c5fc2c09a6f6f56207e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void AdminCheckRequest::execute(RequestTaker &taker, const RequestContext &conte
     taker.execute(context, *this);
 }
 
+bool AdminCheckRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index b032a62df4dae6e6b1e156ab476b0023cd91a1ca..04150acaeac3fe76c0cdad1c8b29cbbed9fa4af1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -63,6 +63,8 @@ public:
     }
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index 356f2bcde4822153b5d884dbeef658bf2e4fc2b2..541b9bc16eb00fe6d60aa6ff7052ea9c07d3551a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void AgentActionRequest::execute(RequestTaker &taker, const RequestContext &cont
     taker.execute(context, *this);
 }
 
+bool AgentActionRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 8cfb4736ecb512c2a807e10f42bf0c1843253201..030349fc88b59979bbc60b94b2e7c3f29215aabf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -55,6 +55,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
 
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
+
 private:
     const AgentRequestType m_type;
     const RawBuffer m_data;
index cef6a86a9f3104462d788489eba8de11bfa0b60a..0b0dd8dc2712679c998c5dc24f8b33d1ecced96a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void AgentRegisterRequest::execute(RequestTaker &taker, const RequestContext &co
     taker.execute(context, *this);
 }
 
+bool AgentRegisterRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 6785f582a0ab1620a8ecd936cb46317c32cc1a56..150efae9adb9fa326ed9330308db49fe67c6a221 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -49,6 +49,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
 
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
+
 private:
     AgentType m_agentType;
 };
index 0becb387e1f8688b47b8167d941464f348f28bde..49e69930021bb62b3fda41eb9966feadba0fa188 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void CancelRequest::execute(RequestTaker &taker, const RequestContext &context)
     taker.execute(context, *this);
 }
 
+bool CancelRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 9c585fc0343366505bec96921dc4d4517adaa7a7..0014d1a945f9859b6b453e3802c48f0637c8cf56 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -41,6 +41,8 @@ public:
     virtual ~CancelRequest() {};
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index ea738971dc700699ab3dcee38157ad28fa86cde2..55ff4be000e5eea0c83de262bc917aee3a935665 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void CheckRequest::execute(RequestTaker &taker, const RequestContext &context) c
     taker.execute(context, *this);
 }
 
+bool CheckRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 08539515234007d3e68c6c1a31442cb614d264c8..faeb49c29034c355f600ce0c5f8bfc5145ccefeb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -51,6 +51,8 @@ public:
     }
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index 745fa76855b1b37de9f6fcba8d5adf1e55a19d2e..7d166439f0d0cc390796f230fc2df0ff2d011f17 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void DescriptionListRequest::execute(RequestTaker &taker, const RequestContext &
     taker.execute(context, *this);
 }
 
+bool DescriptionListRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 6c7d9cd5f3c9fd2f0b41f92a3c22146d983e4eef..c6b258ff3ee5a60e099bb3f0c59b691fafe283c0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -42,6 +42,8 @@ public:
     virtual ~DescriptionListRequest() {};
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index b9059d4e7f969d42381e2bafce1b21d8a93d8052..f450da729126767cd3cfeca7110237073913a198 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void EraseRequest::execute(RequestTaker &taker, const RequestContext &context) c
     taker.execute(context, *this);
 }
 
+bool EraseRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index bb751e28b9b3225b1e50d111dd579bc5c4ee16ae..a188c26a5c0566a3a7a7dcb4c2cb9b735cae3dfa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -60,6 +60,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
 
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
+
 private:
     PolicyBucketId m_startBucket;
     bool m_recursive;
index 09b9bbeeac7e61ffff472fc7ae59672c4f9e8f66..cf2d487d0da15167d9e664785eaafbb678eaaba6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -36,4 +36,8 @@ void InsertOrUpdateBucketRequest::execute(RequestTaker &taker,
     taker.execute(context, *this);
 }
 
+bool InsertOrUpdateBucketRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 6db1259a4a08de0b094cf3e58602c01e89db712c..8dd16d0da04aa517675cce07db572264ced56eb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -58,6 +58,8 @@ public:
     }
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index 9e6fb838e98d2ce0eba86381bd38837a2271c622..44e4e584f992e51767b5f4fa274742c8e38c35f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void ListRequest::execute(RequestTaker &taker, const RequestContext &context) co
     taker.execute(context, *this);
 }
 
+bool ListRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 707cae9122c64270c5890ae069d5366ea5e463ae..ad8e263c8f1bff92120b12203c17e244dc1cc59e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -58,6 +58,8 @@ public:
     }
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index 905c8696c849fab852192f0acf91de3879206a12..c8dcdd2f45ba1d7d9f2f590d16104832f1f9742a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void MonitorEntriesPutRequest::execute(RequestTaker &taker, const RequestContext
     taker.execute(context, *this);
 }
 
+bool MonitorEntriesPutRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index f05cf7a2a60dfec3002c249125eaa167337a2424..afc902ff0849552fe24566f5739991f401a43705 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -48,6 +48,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
 
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
+
     const std::vector<MonitorEntry> &monitorEntries(void) const {
         return m_monitorEntries;
     }
index b095a23ea2c4c5b3930dca2dfc2df035771c9991..91ee8e7ea3b7dd5e2c3bd8c292561f48d166a1c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void MonitorEntryPutRequest::execute(RequestTaker &taker, const RequestContext &
     taker.execute(context, *this);
 }
 
+bool MonitorEntryPutRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 7e3a1df91cc8ca2b4db62048e71be6c6512c16c1..eb567b4a7628d4d938f9f74bf5bf018259caa2fe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -46,6 +46,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
 
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
+
     const MonitorEntry &monitorEntry(void) const {
         return m_monitorEntry;
     }
index e310d9581bf194e0e4cbb90aa486236a6cb3d897..b7aa7cee98fd38c26888a9f246f66f63749aac5d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void MonitorGetEntriesRequest::execute(RequestTaker &taker, const RequestContext
     taker.execute(context, *this);
 }
 
+bool MonitorGetEntriesRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index bc3477ba3f584489aa92d1e4b934210fdc171e11..7eb9b3e121f558d23c7e85c2124dfe8b5b72997b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -46,6 +46,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
 
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
+
 private:
     const size_t m_bufferSize;
 };
index 59644aef9219b01942fc0532ea528c2e9648840a..407156d31ec259d940460fc18e64d25f7752cd98 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -36,4 +36,8 @@ void MonitorGetFlushRequest::execute(RequestTaker &taker, const RequestContext &
     taker.execute(context, *this);
 }
 
+bool MonitorGetFlushRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index ec3ce02f8221f088907f0d0dbe6f6fe159cfea19..eeaa09d90bb18721d836374e69121d1abdd05807 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -42,6 +42,8 @@ public:
     virtual ~MonitorGetFlushRequest() {};
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index 5180ce311405a8a1bf566f4ae57fa0391777764f..5717a8aa636bd2a4c51f88843b25626c4f72acec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void RemoveBucketRequest::execute(RequestTaker &taker, const RequestContext &con
     taker.execute(context, *this);
 }
 
+bool RemoveBucketRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index cb107e2e9c704a9c410e3c554e4a63b422c0fe6d..ebf3c3cd4be938486fd761ce57b89ea306af985b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -51,6 +51,8 @@ public:
     }
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index eedb8f271dfeb4cb58eb6b9b5dfaf64970a6f738..71ca16a5740a6bb7d63d6962caee421c440c8457 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -29,6 +29,8 @@
 #define SRC_COMMON_REQUEST_REQUEST_H_
 
 #include <request/pointers.h>
+#include <request/RequestContext.h>
+#include <request/RequestTaker.h>
 #include <types/ProtocolFields.h>
 
 namespace Cynara {
@@ -41,6 +43,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const = 0;
 
+    virtual bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const = 0;
+
     ProtocolFrameSequenceNumber sequenceNumber(void) const {
         return m_sequenceNumber;
     }
index 504198d14d83d0dc19b5ab4989e85d1d3834310d..6651a262adebe4cb9a6a95057f115402baecbbf2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -28,7 +28,7 @@
 #ifndef SRC_COMMON_REQUEST_REQUESTCONTEXT_H_
 #define SRC_COMMON_REQUEST_REQUESTCONTEXT_H_
 
-#include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <exceptions/ContextErrorException.h>
 #include <request/pointers.h>
 #include <response/pointers.h>
@@ -42,7 +42,7 @@ public:
     typedef int ClientId;
     static const int InvalidClientId = -1;
 
-    RequestContext(ResponseTakerPtr responseTaker, BinaryQueuePtr responseQueue,
+    RequestContext(ResponseTakerPtr responseTaker, MutexedBinaryQueuePtr responseQueue,
                    ClientId clientId = InvalidClientId)
         : m_responseTaker(responseTaker), m_responseQueue(responseQueue), m_clientId(clientId) {
     }
@@ -53,7 +53,7 @@ public:
             response.execute(*taker, *this);
     }
 
-    BinaryQueuePtr responseQueue(void) const {
+    MutexedBinaryQueuePtr responseQueue(void) const {
         auto bbqPtr = m_responseQueue.lock();
         if (bbqPtr)
             return bbqPtr;
@@ -66,7 +66,7 @@ public:
 
 private:
     ResponseTakerWeakPtr m_responseTaker;
-    BinaryQueueWeakPtr m_responseQueue;
+    MutexedBinaryQueueWeakPtr m_responseQueue;
     ClientId m_clientId;
 };
 
index d0b9859caab41df5dde3d2dd871ba71a9ded7d82..e3d37a4a9ccea582e8768e34ba47962990d86009 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -59,6 +59,27 @@ public:
     virtual void contextClosed(const RequestContext &context);
 };
 
+class ReadOnlyRequestTaker : public RequestTaker {
+public:
+    virtual bool canBeExecutedReadOnly(const AdminCheckRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const AgentActionRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const AgentRegisterRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const CancelRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const CheckRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const DescriptionListRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const EraseRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const InsertOrUpdateBucketRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const ListRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const MonitorGetEntriesRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const MonitorGetFlushRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const MonitorEntriesPutRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const MonitorEntryPutRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const RemoveBucketRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const SetPoliciesRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const SignalRequest &request) const = 0;
+    virtual bool canBeExecutedReadOnly(const SimpleCheckRequest &request) const = 0;
+};
+
 } // namespace Cynara
 
 #endif /* SRC_COMMON_REQUEST_REQUESTTAKER_H_ */
index 0d9e9f24d9135d9d4253a86bc015ce203d7eaa8b..9562efb31879e33e91daf09582ef48e4fa18d733 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void SetPoliciesRequest::execute(RequestTaker &taker, const RequestContext &cont
     taker.execute(context, *this);
 }
 
+bool SetPoliciesRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index a77c9d0a0c2fbd887c26c3e4c54d4c1826261c0b..d93b12378836b1e403515746d9eafd220da06d63 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -64,6 +64,8 @@ public:
     }
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index 8efb014800e80769bca64acaa011175317f8bef9..a626d9e70d84bb6d56cfc3859655275beaa0578b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void SignalRequest::execute(RequestTaker &taker, const RequestContext &context)
     taker.execute(context, *this);
 }
 
+bool SignalRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 97350bfb7019218925573a5b65775f6855b4a463..2c89e97f4a149ae5716c9f956f02477f2ecd0cdb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -47,6 +47,8 @@ public:
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
 
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
+
     uint32_t signalNumber(void) const {
         return m_sigInfo.ssi_signo;
     }
index 9391a03392300e40d961aa4520cd99c6065925e0..d108a60d336200e68d4f5ba66e6ab3cd3122c713 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -35,4 +35,8 @@ void SimpleCheckRequest::execute(RequestTaker &taker, const RequestContext &cont
     taker.execute(context, *this);
 }
 
+bool SimpleCheckRequest::canBeExecutedReadOnly(const ReadOnlyRequestTaker &taker) const {
+    return taker.canBeExecutedReadOnly(*this);
+}
+
 } // namespace Cynara
index 5e27bd2c4a0a546b483fafd4bccd01ef3c59f63b..a8f2860571a63814bddd63978f5ede52ccadce2d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -50,6 +50,8 @@ public:
     }
 
     virtual void execute(RequestTaker &taker, const RequestContext &context) const;
+
+    bool canBeExecutedReadOnly(const ReadOnlyRequestTaker& taker) const override;
 };
 
 } // namespace Cynara
index 0265d42aa7206123e4f36ab3673df366ad955a8b..9a25fe9471cff55e43c84d565e16d0fe01d3a090 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -36,7 +36,7 @@ namespace Cynara {
 
 SocketClient::SocketClient(const std::string &socketPath, ProtocolPtr protocol)
         : m_socket(socketPath), m_protocol(protocol) {
-    m_writeQueue = std::make_shared<BinaryQueue>();
+    m_writeQueue = std::make_shared<MutexedBinaryQueue>();
     m_readQueue = std::make_shared<BinaryQueue>();
 }
 
@@ -66,7 +66,8 @@ ResponsePtr SocketClient::askCynaraServer(const Request &request) {
     request.execute(*m_protocol, context);
 
     //send request to cynara
-    if (m_socket.sendToServer(*m_writeQueue) == Socket::SendStatus::CONNECTION_LOST) {
+    if (m_socket.sendToServer(*m_writeQueue->lock()) ==
+            Socket::SendStatus::CONNECTION_LOST) {
         LOGW("Disconnected while sending request to Cynara.");
         return nullptr;
     }
@@ -90,7 +91,8 @@ bool SocketClient::sendAndForget(const Request &request) {
     request.execute(*m_protocol, context);
 
     //send request to cynara
-    if (m_socket.sendToServer(*m_writeQueue) == Socket::SendStatus::CONNECTION_LOST) {
+    if (m_socket.sendToServer(*m_writeQueue->lock()) ==
+            Socket::SendStatus::CONNECTION_LOST) {
         LOGW("Disconnected while sending request to Cynara.");
         return false;
     }
index 34c52e4d81c37bdf25f64b646846342600f8dedb..16acb71e10322992f59708825bc1c5b9958f2810 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -31,7 +31,7 @@
 #include <memory>
 #include <string>
 
-#include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <protocol/Protocol.h>
 #include <request/pointers.h>
 #include <response/pointers.h>
@@ -47,7 +47,7 @@ private:
     Socket m_socket;
     ProtocolPtr m_protocol;
     BinaryQueuePtr m_readQueue;
-    BinaryQueuePtr m_writeQueue;
+    MutexedBinaryQueuePtr m_writeQueue;
 
 public:
     SocketClient(const std::string &socketPath, ProtocolPtr protocol);
index b28025cbc4797440af6fb72c5eb5db7aa6e0b6a2..e9d563360d79ae8d17936e5e6276f8620397edc4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
 #ifndef SRC_COMMON_TYPES_LINK_H_
 #define SRC_COMMON_TYPES_LINK_H_
 
-#include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
 
 namespace Cynara {
 
-typedef BinaryQueuePtr LinkId;
+typedef MutexedBinaryQueuePtr LinkId;
 
 } // namespace Cynara
 
index 92ce3d5d38f80fbdd867c19df2d5c103768f20ea..f43292f887c0a465db4a6e6392c25aaba3b60030 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Contact: Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
  *
  */
 
 #include <cerrno>
-#include <cstdio>
-#include <cstring>
 #include <fcntl.h>
+#include <memory>
 #include <poll.h>
 #include <unistd.h>
 
 #include <config/PathConfig.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <error/SafeStrError.h>
 #include <log/log.h>
 #include <request/Request.h>
@@ -74,7 +74,9 @@ bool MonitorSocketClient::sendRequest(const Request &request) {
     std::lock_guard<std::mutex> lock(m_mutex);
     //pass request to protocol
     BinaryQueuePtr bbqSharedPtr(&m_writeQueue, [](BinaryQueue *) {});
-    RequestContext context(ResponseTakerPtr(), bbqSharedPtr);
+    auto mbbqSharedPtr = std::make_shared<MutexedBinaryQueue>(bbqSharedPtr);
+
+    RequestContext context(ResponseTakerPtr(), mbbqSharedPtr);
     request.execute(m_protocol, context);
 
     //send request to cynara
index a5215796a9704dcf9568e315ae2d3bde529a48f6..6368b188d24e6345388c2f52d80807fe2bb243b8 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
 #
 # This file is licensed under the terms of MIT License or the Apache License
 # Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -61,6 +61,7 @@ ADD_EXECUTABLE(${TARGET_CYNARA} ${CYNARA_SOURCES})
 TARGET_LINK_LIBRARIES(${TARGET_CYNARA}
     ${CYNARA_COMMON_AND_STORAGE_LIB}
     ${CYNARA_DEP_LIBRARIES}
+    pthread
     )
 
 INSTALL(TARGETS ${TARGET_CYNARA} DESTINATION ${BIN_DIR})
index 48a7aaf1c55495823c5d421fe16763495ec1cb34..8f0febf98e2f3b883e846a79dbe834ec9de3232a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -27,9 +27,9 @@
  * @brief       This file implements main class of logic layer in cynara service
  */
 
+#include <cassert>
 #include <csignal>
 #include <cinttypes>
-#include <functional>
 #include <memory>
 #include <vector>
 
@@ -102,28 +102,15 @@ void Logic::execute(const RequestContext &context UNUSED, const SignalRequest &r
     switch (request.signalNumber()) {
     case SIGTERM:
         LOGI("SIGTERM received!");
-        m_socketManager->mainLoopStop();
+        m_socketManager->signalStopMainLoop();
         break;
     }
 }
 
-void Logic::execute(const RequestContext &context, const AdminCheckRequest &request) {
-    PolicyResult result;
-    bool bucketValid = true;
-
-    if (m_dbCorrupted) {
-        bucketValid = false;
-    } else {
-        try {
-            result = m_storage->checkPolicy(request.key(), request.startBucket(),
-                                            request.recursive());
-        } catch (const BucketNotExistsException &ex) {
-            bucketValid = false;
-        }
-    }
-
-    context.returnResponse(AdminCheckResponse(result, bucketValid, m_dbCorrupted,
-                                              request.sequenceNumber()));
+void Logic::execute(const RequestContext &/*context*/, const AdminCheckRequest &/*request*/) {
+    auto msg = std::string("This function (") + __PRETTY_FUNCTION__ + ") should not be called";
+    LOGE(msg.c_str());
+    throw UnexpectedErrorException{std::move(msg)};
 }
 
 void Logic::execute(const RequestContext &context, const AgentActionRequest &request) {
@@ -201,16 +188,9 @@ bool Logic::check(const RequestContext &context, const PolicyKey &key,
     }
 
     result = (m_dbCorrupted ? PredefinedPolicyType::DENY : m_storage->checkPolicy(key));
-
-    switch (result.policyType()) {
-        case PredefinedPolicyType::ALLOW :
-            LOGD("check of policy key <%s> returned ALLOW", key.toString().c_str());
-            return true;
-        case PredefinedPolicyType::DENY :
-            LOGD("check of policy key <%s> returned DENY", key.toString().c_str());
-            return true;
-    }
-
+    // result was already checked in canBeExecutedReadOnly(const CheckRequest&)
+    assert(result.policyType() != PredefinedPolicyType::ALLOW);
+    assert(result.policyType() != PredefinedPolicyType::DENY);
     return pluginCheck(context, key, checkId, result);
 }
 
@@ -298,12 +278,10 @@ bool Logic::update(const PolicyKey &key, ProtocolFrameSequenceNumber checkId,
     return false;
 }
 
-void Logic::execute(const RequestContext &context, const DescriptionListRequest &request) {
-    auto descriptions = m_pluginManager->getPolicyDescriptions();
-    descriptions.insert(descriptions.begin(), predefinedPolicyDescr.begin(),
-                        predefinedPolicyDescr.end());
-    context.returnResponse(DescriptionListResponse(descriptions, m_dbCorrupted,
-                                                   request.sequenceNumber()));
+void Logic::execute(const RequestContext &/*context*/, const DescriptionListRequest &/*request*/) {
+    auto msg = std::string("This function (") + __PRETTY_FUNCTION__ + ") should not be called";
+    LOGE(msg.c_str());
+    throw UnexpectedErrorException{std::move(msg)};
 }
 
 void Logic::execute(const RequestContext &context, const EraseRequest &request) {
@@ -349,22 +327,10 @@ void Logic::execute(const RequestContext &context, const InsertOrUpdateBucketReq
     context.returnResponse(CodeResponse(code, request.sequenceNumber()));
 }
 
-void Logic::execute(const RequestContext &context, const ListRequest &request) {
-    bool bucketValid = true;
-    std::vector<Policy> policies;
-
-    if (m_dbCorrupted) {
-        bucketValid = false;
-    } else {
-        try {
-            policies = m_storage->listPolicies(request.bucket(), request.filter());
-        } catch (const BucketNotExistsException &ex) {
-            bucketValid = false;
-        }
-    }
-
-    context.returnResponse(ListResponse(policies, bucketValid, m_dbCorrupted,
-                                        request.sequenceNumber()));
+void Logic::execute(const RequestContext &/*context*/, const ListRequest &/*request*/) {
+    auto msg = std::string("This function (") + __PRETTY_FUNCTION__ + ") should not be called";
+    LOGE(msg.c_str());
+    throw UnexpectedErrorException{std::move(msg)};
 }
 
 void Logic::execute(const RequestContext &context, const RemoveBucketRequest &request) {
@@ -416,20 +382,17 @@ void Logic::execute(const RequestContext &context, const SimpleCheckRequest &req
     PolicyKey key = request.key();
     result = m_storage->checkPolicy(key);
 
-    switch (result.policyType()) {
-    case PredefinedPolicyType::ALLOW:
-        LOGD("simple check of policy key <%s> returned ALLOW", key.toString().c_str());
-        break;
-    case PredefinedPolicyType::DENY:
-        LOGD("simple check of policy key <%s> returned DENY", key.toString().c_str());
-        break;
-    default: {
+    // result was already checked in canBeExecutedReadOnly
+    assert(result.policyType() != PredefinedPolicyType::ALLOW);
+    assert(result.policyType() != PredefinedPolicyType::DENY);
+
+    [&] {
         ExternalPluginPtr plugin = m_pluginManager->getPlugin(result.policyType());
         if (!plugin) {
             LOGE("Plugin not found for policy: [0x%x]", result.policyType());
             result = PolicyResult(PredefinedPolicyType::DENY);
             retValue = CYNARA_API_SUCCESS;
-            break;
+            return;
         }
 
         ServicePluginInterfacePtr servicePlugin =
@@ -438,7 +401,7 @@ void Logic::execute(const RequestContext &context, const SimpleCheckRequest &req
             LOGE("Couldn't cast plugin pointer to ServicePluginInterface");
             result = PolicyResult(PredefinedPolicyType::DENY);
             retValue = CYNARA_API_SUCCESS;
-            break;
+            return;
         }
 
         AgentType requiredAgent;
@@ -449,7 +412,7 @@ void Logic::execute(const RequestContext &context, const SimpleCheckRequest &req
         switch (ret) {
         case ServicePluginInterface::PluginStatus::ANSWER_READY:
             LOGD("simple check of policy key <%s> in plugin returned [" PRIu16 "]",
-                 key.toString().c_str(), result.policyType());
+                    key.toString().c_str(), result.policyType());
             break;
         case ServicePluginInterface::PluginStatus::ANSWER_NOTREADY:
             retValue = CYNARA_API_ACCESS_NOT_RESOLVED;
@@ -458,8 +421,8 @@ void Logic::execute(const RequestContext &context, const SimpleCheckRequest &req
             result = PolicyResult(PredefinedPolicyType::DENY);
             retValue = CYNARA_API_SUCCESS;
         }
-    }
-    }
+    }();
+
     m_auditLog.log(request.key(), result);
     context.returnResponse(SimpleCheckResponse(retValue, result,
                                                request.sequenceNumber()));
@@ -536,7 +499,7 @@ void Logic::contextClosed(const RequestContext &context) {
 
 void Logic::onPoliciesChanged(void) {
     m_storage->save();
-    m_socketManager->disconnectAllClients();
+    m_socketManager->signalDisconnectAllClients();
     m_pluginManager->invalidateAll();
     //todo remove all saved contexts (if there will be any saved contexts)
 }
@@ -575,4 +538,191 @@ void Logic::loadDb(void) {
     }
 }
 
+std::unique_ptr<ReadOnlyLogic> Logic::createReadOnlyCopy() {
+    return std::make_unique<ReadOnlyLogic>(m_dbCorrupted, m_storage->clone(),
+                                           m_pluginManager->clone());
+}
+
+ReadOnlyLogic::ReadOnlyLogic(bool dbCorrupted, std::unique_ptr<StorageReadOnlyCopy> storageClone,
+                             std::unique_ptr<PluginManagerReadOnlyCopy> pluginManagerClone)
+    : m_dbCorrupted{dbCorrupted}, m_storageClone{std::move(storageClone)},
+      m_pluginManagerClone{std::move(pluginManagerClone)} {}
+
+void ReadOnlyLogic::execute(const RequestContext &context,
+                            const AdminCheckRequest &request) {
+    PolicyResult result;
+    bool bucketValid = true;
+
+    if (m_dbCorrupted) {
+        bucketValid = false;
+    } else {
+        try {
+            result = m_storageClone->checkPolicy(request.key(), request.startBucket(),
+                                                 request.recursive());
+        } catch (const BucketNotExistsException &ex) {
+            bucketValid = false;
+        }
+    }
+
+    context.returnResponse(AdminCheckResponse(result, bucketValid, m_dbCorrupted,
+                                              request.sequenceNumber()));
+}
+
+void ReadOnlyLogic::execute(const RequestContext &context, const CheckRequest &request) {
+    const auto& key = request.key();
+
+    auto result = (m_dbCorrupted ? PredefinedPolicyType::DENY : m_storageClone->checkPolicy(key));
+    // result was already checked in canBeExecutedReadOnly
+    m_auditLog.log(key, result);
+    context.returnResponse(CheckResponse(result, request.sequenceNumber()));
+}
+
+void ReadOnlyLogic::execute(const RequestContext &context, const DescriptionListRequest &request) {
+    auto descriptions = m_pluginManagerClone->getPolicyDescriptions();
+    descriptions.insert(descriptions.begin(), predefinedPolicyDescr.begin(),
+                        predefinedPolicyDescr.end());
+    context.returnResponse(DescriptionListResponse(descriptions, m_dbCorrupted,
+                                                   request.sequenceNumber()));
+}
+
+void ReadOnlyLogic::execute(const RequestContext &context, const ListRequest &request) {
+    bool bucketValid = true;
+    std::vector<Policy> policies;
+
+    if (m_dbCorrupted) {
+        bucketValid = false;
+    } else {
+        try {
+            policies = m_storageClone->listPolicies(request.bucket(), request.filter());
+        } catch (const BucketNotExistsException &ex) {
+            bucketValid = false;
+        }
+    }
+
+    context.returnResponse(ListResponse(policies, bucketValid, m_dbCorrupted,
+                                        request.sequenceNumber()));
+}
+
+void ReadOnlyLogic::execute(const RequestContext &context,
+                            const SimpleCheckRequest &request) {
+
+    int retValue = CYNARA_API_SUCCESS;
+    PolicyResult result;
+    PolicyKey key = request.key();
+    result = m_storageClone->checkPolicy(key);
+
+    switch (result.policyType()) {
+    case PredefinedPolicyType::ALLOW:
+        LOGD("simple check of policy key <%s> returned ALLOW", key.toString().c_str());
+        break;
+    case PredefinedPolicyType::DENY:
+        LOGD("simple check of policy key <%s> returned DENY", key.toString().c_str());
+        break;
+    default: {
+        auto msg = std::string("This function (") + __PRETTY_FUNCTION__ +
+            ") should not be called with this parameters";
+        LOGE(msg.c_str());
+        throw UnexpectedErrorException{std::move(msg)};
+    }
+    }
+    m_auditLog.log(request.key(), result);
+    context.returnResponse(SimpleCheckResponse(retValue, result,
+                                               request.sequenceNumber()));
+}
+
+void ReadOnlyLogic::contextClosed(const RequestContext &/*context*/) {
+    auto msg = std::string("This function (") + __PRETTY_FUNCTION__ + ") should not be called";
+    LOGE(msg.c_str());
+    throw UnexpectedErrorException{std::move(msg)};
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const AdminCheckRequest &/*request*/) const {
+    return true;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const AgentActionRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const AgentRegisterRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const CancelRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const CheckRequest &request) const {
+    PolicyResult result(PredefinedPolicyType::DENY);
+    const auto& key = request.key();
+
+    result = (m_dbCorrupted ? PredefinedPolicyType::DENY : m_storageClone->checkPolicy(key));
+
+    switch (result.policyType()) {
+    case PredefinedPolicyType::ALLOW:
+    case PredefinedPolicyType::DENY:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const DescriptionListRequest &/*request*/) const {
+    return true;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const EraseRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const InsertOrUpdateBucketRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const ListRequest &/*request*/) const {
+    return true;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const MonitorGetEntriesRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const MonitorGetFlushRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const MonitorEntriesPutRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const MonitorEntryPutRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const RemoveBucketRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const SetPoliciesRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const SignalRequest &/*request*/) const {
+    return false;
+}
+
+bool ReadOnlyLogic::canBeExecutedReadOnly(const SimpleCheckRequest &request) const {
+    PolicyResult result;
+    PolicyKey key = request.key();
+    result = m_storageClone->checkPolicy(key);
+
+    switch (result.policyType()) {
+    case PredefinedPolicyType::ALLOW:
+    case PredefinedPolicyType::DENY:
+        return true;
+    default:
+        return false;
+    }
+}
+
 } // namespace Cynara
index df33de0a3e2517c0f92434330ce69b9a142ca680..f3dd15729d644c27b741c6b0148f001fd9400825 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -31,6 +31,7 @@
 #define SRC_SERVICE_LOGIC_LOGIC_H_
 
 #include <map>
+#include <memory>
 #include <vector>
 
 #include <log/AuditLog.h>
@@ -45,6 +46,7 @@
 #include <request/CheckRequestManager.h>
 #include <request/pointers.h>
 #include <request/RequestTaker.h>
+#include <storage/Storage.h>
 
 #include <cynara-plugin.h>
 
@@ -52,6 +54,8 @@
 
 namespace Cynara {
 
+class ReadOnlyLogic;
+
 class Logic : public RequestTaker {
 public:
     Logic();
@@ -106,7 +110,9 @@ public:
     virtual void contextClosed(const RequestContext &context);
     virtual void loadDb(void);
 
-private:
+    virtual std::unique_ptr<ReadOnlyLogic> createReadOnlyCopy();
+
+protected:
     AgentManagerPtr m_agentManager;
     CheckRequestManager m_checkRequestManager;
     PluginManagerPtr m_pluginManager;
@@ -134,6 +140,44 @@ private:
     void onPoliciesChanged(void);
 };
 
+class ReadOnlyLogic : public ReadOnlyRequestTaker {
+public:
+    ReadOnlyLogic(bool dbCorrupted, std::unique_ptr<StorageReadOnlyCopy> storageClone,
+                  std::unique_ptr<PluginManagerReadOnlyCopy> pluginManagerClone);
+
+    void execute(const RequestContext &context, const AdminCheckRequest &request) override;
+    void execute(const RequestContext &context, const CheckRequest &request) override;
+    void execute(const RequestContext &context, const DescriptionListRequest &request) override;
+    void execute(const RequestContext &context, const ListRequest &request) override;
+    void execute(const RequestContext &context, const SimpleCheckRequest &request) override;
+
+    void contextClosed(const RequestContext &context) override;
+
+    bool canBeExecutedReadOnly(const AdminCheckRequest &request) const override;
+    bool canBeExecutedReadOnly(const AgentActionRequest &request) const override;
+    bool canBeExecutedReadOnly(const AgentRegisterRequest &request) const override;
+    bool canBeExecutedReadOnly(const CancelRequest &request) const override;
+    bool canBeExecutedReadOnly(const CheckRequest &request) const override;
+    bool canBeExecutedReadOnly(const DescriptionListRequest &request) const override;
+    bool canBeExecutedReadOnly(const EraseRequest &request) const override;
+    bool canBeExecutedReadOnly(const InsertOrUpdateBucketRequest &request) const override;
+    bool canBeExecutedReadOnly(const ListRequest &request) const override;
+    bool canBeExecutedReadOnly(const MonitorGetEntriesRequest &request) const override;
+    bool canBeExecutedReadOnly(const MonitorGetFlushRequest &request) const override;
+    bool canBeExecutedReadOnly(const MonitorEntriesPutRequest &request) const override;
+    bool canBeExecutedReadOnly(const MonitorEntryPutRequest &request) const override;
+    bool canBeExecutedReadOnly(const RemoveBucketRequest &request) const override;
+    bool canBeExecutedReadOnly(const SetPoliciesRequest &request) const override;
+    bool canBeExecutedReadOnly(const SignalRequest &request) const override;
+    bool canBeExecutedReadOnly(const SimpleCheckRequest &request) const override;
+
+private:
+    AuditLog m_auditLog;
+    bool m_dbCorrupted;
+    std::unique_ptr<StorageReadOnlyCopy> m_storageClone;
+    std::unique_ptr<PluginManagerReadOnlyCopy> m_pluginManagerClone;
+};
+
 } // namespace Cynara
 
 #endif /* SRC_SERVICE_LOGIC_LOGIC_H_ */
index 5deea66643fd76c509142a7c22cb677c1dd53ddd..3efe95c30886119e900d6101f93397f21d07bdb6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -27,6 +27,8 @@
 
 #include "Descriptor.h"
 
+#include <containers/MutexedBinaryQueue.h>
+
 namespace Cynara {
 
 Descriptor::Descriptor() : m_listen(false), m_used(false), m_client(false), m_protocol(nullptr) {
@@ -34,19 +36,21 @@ Descriptor::Descriptor() : m_listen(false), m_used(false), m_client(false), m_pr
 
 void Descriptor::checkQueues(void) {
     if (!m_writeQueue)
-        m_writeQueue = std::make_shared<BinaryQueue>();
+        m_writeQueue = std::make_shared<MutexedBinaryQueue>();
     if (!m_readQueue)
         m_readQueue = std::make_shared<BinaryQueue>();
 }
 
-BinaryQueuePtr Descriptor::writeQueue(void) {
+MutexedBinaryQueuePtr Descriptor::writeQueue(void) {
     checkQueues();
     return m_writeQueue;
 }
 
 bool Descriptor::hasDataToWrite(void) const {
-    if (m_writeQueue)
-        return !(m_writeQueue->empty() && m_writeBuffer.empty());
+    if (m_writeQueue) {
+        auto lockedWriteQueue = m_writeQueue->lock();
+        return !(lockedWriteQueue->empty() && m_writeBuffer.empty());
+    }
     return false;
 }
 
@@ -66,11 +70,13 @@ RequestPtr Descriptor::extractRequest(void) {
 
 RawBuffer &Descriptor::prepareWriteBuffer(void) {
     checkQueues();
-    size_t queuedDataSize = m_writeQueue->size();
+    auto lockedWriteQueue = m_writeQueue->lock();
+
+    size_t queuedDataSize = lockedWriteQueue->size();
     size_t bufferDataSize = m_writeBuffer.size();
 
     m_writeBuffer.resize(queuedDataSize + bufferDataSize);
-    m_writeQueue->flattenConsume(m_writeBuffer.data() + bufferDataSize, queuedDataSize);
+    lockedWriteQueue->flattenConsume(m_writeBuffer.data() + bufferDataSize, queuedDataSize);
 
     return m_writeBuffer;
 }
@@ -83,6 +89,7 @@ void Descriptor::clear(void) {
     m_writeQueue.reset();
     m_writeBuffer.clear();
     m_protocol.reset();
+    ++m_generation;
 }
 
 } // namespace Cynara
index 86b51a865f407ad4a76e5ab07aa90be9db529b67..1fb1b8431be993c27073570cc59e1cb814e229ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
 #ifndef SRC_SERVICE_SOCKETS_DESCRIPTOR_H_
 #define SRC_SERVICE_SOCKETS_DESCRIPTOR_H_
 
-#include <memory>
+#include <cstdint>
 
 #include <common.h>
 
+#include <containers/MutexedBinaryQueue.h>
 #include <protocol/Protocol.h>
 #include <request/Request.h>
 #include <response/pointers.h>
@@ -60,14 +61,22 @@ public:
         return m_protocol;
     }
 
+    const ProtocolPtr readOnlyProtocol(void) const {
+        return m_readOnlyProtocol;
+    }
+
     ResponseTakerPtr responseTaker(void) const;
 
-    BinaryQueuePtr writeQueue(void);
+    MutexedBinaryQueuePtr writeQueue(void);
 
     void setProtocol(ProtocolPtr protocol) {
         m_protocol = protocol;
     }
 
+    void setReadOnlyProtocol(ProtocolPtr protocol) {
+        m_readOnlyProtocol = protocol;
+    }
+
     void setListen(bool listen) {
         m_listen = listen;
     }
@@ -87,16 +96,25 @@ public:
 
     void clear(void);
 
+    uint64_t getGeneration() const noexcept {
+        return m_generation;
+    }
+
 private:
     bool m_listen;
     bool m_used;
     bool m_client;
+    // In a multithread server, one thread may produce the response to the request coming from some
+    // descriptor. But the descriptor may get reused in the meantime by the other thread.
+    // m_generation is for ensuring that such response will not be sent via the reused descriptor.
+    uint64_t m_generation = 0;
 
     BinaryQueuePtr m_readQueue;
-    BinaryQueuePtr m_writeQueue;
+    MutexedBinaryQueuePtr m_writeQueue;
     RawBuffer m_writeBuffer;
 
     ProtocolPtr m_protocol;
+    ProtocolPtr m_readOnlyProtocol;
 
     void checkQueues(void);
 };
index 5ee92691a4ca0d06c87cf72849efe076901c688f..a3ed7e660f0580a49bcfbb71ff90d1fd30982b7e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
  * @brief       This file implements socket layer manager for cynara
  */
 
+#include <csignal>
+#include <cstdint>
+#include <cstring>
 #include <errno.h>
 #include <fcntl.h>
 #include <memory>
-#include <signal.h>
+#include <mutex>
+#include <sys/eventfd.h>
 #include <sys/select.h>
 #include <sys/signalfd.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
 #include <unistd.h>
+#include <utility>
+#include <variant>
 
 #ifdef BUILD_WITH_SYSTEMD_DAEMON
 #include <systemd/sd-daemon.h>
 #endif
 
 #include <attributes/attributes.h>
-#include <log/log.h>
 #include <common.h>
 #include <config/PathConfig.h>
+#include <error/SafeStrError.h>
 #include <exceptions/DescriptorNotExistsException.h>
 #include <exceptions/InitException.h>
 #include <exceptions/UnexpectedErrorException.h>
+#include <log/log.h>
 
+#include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
+#include <containers/RawBuffer.h>
 #include <logic/Logic.h>
 #include <main/Cynara.h>
 #include <protocol/ProtocolAdmin.h>
@@ -59,7 +69,7 @@
 #include <protocol/ProtocolSignal.h>
 #include <request/pointers.h>
 #include <request/RequestContext.h>
-#include <stdexcept>
+#include <response/pointers.h>
 
 #include "SocketManager.h"
 
@@ -94,11 +104,74 @@ void SocketManager::init(void) {
     createDomainSocket(std::make_shared<ProtocolMonitorGet>(), PathConfig::SocketPath::monitorGet,
                        monitorSocketUMask, false);
     createSignalSocket(std::make_shared<ProtocolSignal>());
+    createNonReadOnlyRequestResultsNumEventFd();
+    // Initialize RO logic
+    m_readOnlyLogic = m_logic->createReadOnlyCopy();
+
     LOGI("SocketManger init done");
 }
 
 void SocketManager::mainLoop(void) {
     LOGI("SocketManger mainLoop start");
+
+    m_nonReadOnlyWorkerThread = std::thread([this] {
+        for (;;) {
+            auto reqV = m_nonReadOnlyRequests.recv();
+            if (std::holds_alternative<NoMoreRequests>(reqV))
+                break; // No more requests
+
+            auto notifyTheMainThread = [&]{
+                uint64_t x = 1;
+                if (write(m_nonReadOnlyRequestResultsNumEventFd, &x, sizeof(x)) != sizeof(x)) {
+                    int err = errno;
+                    LOGE("write(m_nonReadOnlyRequestResultsNumEventFd) failed <%s>",
+                         safeStrError(err).c_str());
+                }
+            };
+
+            if (std::holds_alternative<CloseContext>(reqV)) {
+                auto& req = std::get<CloseContext>(reqV);
+                m_logic->contextClosed(
+                    RequestContext(nullptr, req.closedWriteQueue, req.closedSocketFd));
+                // Send result to the main thread
+                m_nonReadOnlyRequestResults.send(CloseContextResult{});
+                notifyTheMainThread();
+                continue;
+            }
+
+            if (std::holds_alternative<NonReadOnlyRequest>(reqV)) {
+                auto& req = std::get<NonReadOnlyRequest>(reqV);
+                LOGD("non-read-only logic worker thread: handling request with socket fd [%i] with"
+                     " generation [%i] and sequence number [%i]", req.socketFd,
+                     req.socketFdGeneration, static_cast<int>(req.request->sequenceNumber()));
+                // Execute the request.
+                auto context = RequestContext(req.protocol, req.writeQueue, req.socketFd);
+                req.request->execute(*m_logic, context);
+                LOGD("Response size: [%i]",
+                     static_cast<int>(req.writeQueue->lock()->size()));
+                // Install new RO logic
+                {
+                    auto readOnlyLogic = m_logic->createReadOnlyCopy();
+                    auto readOnlyGuard = std::lock_guard{m_readOnlyLogicLock};
+                    m_readOnlyLogic = std::move(readOnlyLogic);
+                }
+                LOGD("non-read-only logic worker thread: sending response to request with socket fd"
+                     " [%i] with generation [%i] and sequence number [%i] of size [%i]",
+                     req.socketFd, req.socketFdGeneration,
+                     static_cast<int>(req.request->sequenceNumber()),
+                     static_cast<int>(req.writeQueue->lock()->size()));
+                // Send result to the main thread
+                m_nonReadOnlyRequestResults.send(NonReadOnlyRequestResult{
+                    req.socketFd,
+                    req.socketFdGeneration,
+                    std::exchange(m_needToDisconnectAllClients, false),
+                    std::exchange(m_needToStopMainLoop, false),
+                });
+                notifyTheMainThread();
+            }
+        }
+    });
+
     m_working  = true;
     while (m_working) {
         fd_set readSet = m_readSet;
@@ -112,7 +185,7 @@ void SocketManager::mainLoop(void) {
                 continue;
             default:
                 int err = errno;
-                throw UnexpectedErrorException(err, strerror(err));
+                throw UnexpectedErrorException(err, safeStrError(err));
             }
         } else if (ret > 0) {
             for (int i = 0; i < m_maxDesc + 1 && ret; ++i) {
@@ -126,12 +199,19 @@ void SocketManager::mainLoop(void) {
                 }
             }
 
+            LOGD("checking sockets <= %i for data to write", m_maxDesc);
             for (int i = 0; i < m_maxDesc + 1; ++i) {
-                if (m_fds[i].isUsed() && m_fds[i].hasDataToWrite())
+                if (m_fds[i].isUsed() && m_fds[i].hasDataToWrite()) {
+                    LOGD("socket [%i] has data to write", i);
                     addWriteSocket(i);
+                }
             }
         }
     }
+
+    m_nonReadOnlyRequests.send(NoMoreRequests{});
+    m_nonReadOnlyWorkerThread.join();
+
     LOGI("SocketManger mainLoop done");
 }
 
@@ -141,6 +221,46 @@ void SocketManager::mainLoopStop(void) {
 
 void SocketManager::readyForRead(int fd) {
     LOGD("SocketManger readyForRead on fd [%d] start", fd);
+
+    if (fd == m_nonReadOnlyRequestResultsNumEventFd) {
+        LOGD("SocketManager m_nonReadOnlyRequestResultsNumEventFd is ready for read");
+        uint64_t resNum = 0;
+        if (read(fd, &resNum, sizeof(resNum)) != sizeof(resNum)) {
+            int err = errno;
+            LOGE("Failed to read from eventfd <%s>", safeStrError(err).c_str());
+            throw UnexpectedErrorException(err, safeStrError(err));
+        }
+        for (uint64_t i = 0; i < resNum; ++i) {
+            auto resV = m_nonReadOnlyRequestResults.recv();
+            if (std::holds_alternative<CloseContextResult>(resV))
+                continue;
+
+            if (std::holds_alternative<NonReadOnlyRequestResult>(resV)) {
+                auto& res = std::get<NonReadOnlyRequestResult>(resV);
+                LOGD("main thread: handling response to request with socket fd [%i] with"
+                    " generation [%i]",
+                    res.socketFd, res.socketFdGeneration);
+                if (res.socketFd == -1)
+                    continue;
+                // Handle the response
+                auto& desc = m_fds[res.socketFd];
+                if (desc.isUsed() && desc.getGeneration() == res.socketFdGeneration) {
+                    // Descriptor was not closed and was not reused.
+                    // Now we can safely read and process the other requests from the socket.
+                    addReadSocket(res.socketFd);
+                    // Process next requests if there are any on this socket
+                    handleRead(res.socketFd, RawBuffer{});
+                }
+                // Process extra events
+                if (res.disconnectAllClients)
+                    disconnectAllClients();
+                if (res.stopMainLoop)
+                    mainLoopStop();
+            }
+        }
+        return;
+    }
+
     auto &desc = m_fds[fd];
     if (desc.isListen()) {
         readyForAccept(fd);
@@ -169,7 +289,7 @@ void SocketManager::readyForRead(int fd) {
                 return;
             default:
                 LOGW("While reading from [%d] socket, error [%d]:<%s>",
-                     fd, err, strerror(err));
+                     fd, err, safeStrError(err).c_str());
         }
     } else {
         LOGN("Socket [%d] closed on other end", fd);
@@ -193,7 +313,7 @@ void SocketManager::readyForWrite(int fd) {
             break;
         case EPIPE:
         default:
-            LOGD("Error during write to fd [%d]:<%s> ", fd, strerror(err));
+            LOGD("Error during write to fd [%d]:<%s> ", fd, safeStrError(err).c_str());
             closeSocket(fd);
             break;
         }
@@ -215,7 +335,7 @@ void SocketManager::readyForAccept(int fd) {
     int clientFd = accept4(fd, (struct sockaddr*) &clientAddr, &clientLen, SOCK_NONBLOCK);
     if (clientFd == -1) {
         UNUSED int err = errno;
-        LOGW("Error in accept on socket [%d]: <%s>", fd, strerror(err));
+        LOGW("Error in accept on socket [%d]: <%s>", fd, safeStrError(err).c_str());
         return;
     }
     LOGD("Accept on sock [%d]. New client socket opened [%d]", fd, clientFd);
@@ -223,6 +343,7 @@ void SocketManager::readyForAccept(int fd) {
     auto &desc = createDescriptor(clientFd, m_fds[fd].isClient());
     desc.setListen(false);
     desc.setProtocol(m_fds[fd].protocol()->clone());
+    desc.setReadOnlyProtocol(m_fds[fd].protocol()->clone());
     addReadSocket(clientFd);
     LOGD("SocketManger readyForAccept on fd [%d] done", fd);
 }
@@ -230,7 +351,10 @@ void SocketManager::readyForAccept(int fd) {
 void SocketManager::closeSocket(int fd) {
     LOGD("SocketManger closeSocket fd [%d] start", fd);
     Descriptor &desc = m_fds[fd];
-    requestTaker()->contextClosed(RequestContext(nullptr, desc.writeQueue(), fd));
+    m_nonReadOnlyRequests.send(CloseContext{
+        fd,
+        desc.writeQueue(),
+    });
     removeReadSocket(fd);
     removeWriteSocket(fd);
     desc.clear();
@@ -251,10 +375,35 @@ bool SocketManager::handleRead(int fd, const RawBuffer &readbuffer) {
                 break;
             LOGD("request extracted");
 
-            //build context
-            RequestContext context(desc.responseTaker(), desc.writeQueue(), fd);
-            //pass request to request taker
-            req->execute(*requestTaker(), context);
+            auto guard = std::unique_lock{m_readOnlyLogicLock};
+            if (req->canBeExecutedReadOnly(*m_readOnlyLogic)) {
+                LOGD("Executing request with read-only logic");
+                // Build context. dest.writeQueue() is safe to use since sockets for which request
+                // is handled in non-read-only worker thread are not read from during the request
+                // handling.
+                auto contextForROLogic = std::make_shared<RequestContext>(
+                    desc.readOnlyProtocol(), desc.writeQueue(), fd);
+                // Pass request to the request taker.
+                req->execute(*m_readOnlyLogic, *contextForROLogic);
+            } else {
+                guard.unlock();
+                // Stop listening on the socket so that we don't have a situation where a read
+                // request comes after the write request, but we handle it before the write request
+                // finishes and return the answer based on the old policy. Or use desc.writeQueue()
+                // by read-only logic.
+                removeReadSocket(fd);
+
+                LOGD("Passing request to the non-read-only logic");
+                // Pass the request to the m_nonReadOnlyWorkerThread.
+                m_nonReadOnlyRequests.send(NonReadOnlyRequest{
+                    fd,
+                    desc.getGeneration(),
+                    std::move(req),
+                    desc.protocol(),
+                    desc.writeQueue(),
+                });
+                break;
+            }
         }
     } catch (const Exception &ex) {
         LOGE("Error handling request <%s>. Closing socket", ex.what());
@@ -276,6 +425,7 @@ void SocketManager::createDomainSocket(ProtocolPtr protocol, const std::string &
     auto &desc = createDescriptor(fd, client);
     desc.setListen(true);
     desc.setProtocol(protocol);
+    desc.setReadOnlyProtocol(protocol->clone());
     addReadSocket(fd);
 
     LOGD("Domain socket: [%d] added.", fd);
@@ -286,7 +436,7 @@ int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask)
 
     if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
         UNUSED int err = errno;
-        LOGE("Error during UNIX socket creation: <%s>",  strerror(err));
+        LOGE("Error during UNIX socket creation: <%s>",  safeStrError(err).c_str());
         throw InitException();
     }
 
@@ -297,7 +447,7 @@ int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask)
         UNUSED int err = errno;
         close(fd);
         LOGE("Error setting \"O_NONBLOCK\" on descriptor [%d] with fcntl: <%s>",
-             fd, strerror(err));
+             fd, safeStrError(err).c_str());
         throw InitException();
     }
 
@@ -319,7 +469,7 @@ int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask)
         UNUSED int err = errno;
         close(fd);
         LOGE("Error in bind socket descriptor [%d] to path <%s>: <%s>",
-             fd, path.c_str(), strerror(err));
+             fd, path.c_str(), safeStrError(err).c_str());
         throw InitException();
     }
 
@@ -329,7 +479,7 @@ int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask)
         UNUSED int err = errno;
         close(fd);
         LOGE("Error setting listen on file descriptor [%d], path <%s>: <%s>",
-             fd, path.c_str(), strerror(err));
+             fd, path.c_str(), safeStrError(err).c_str());
         throw InitException();
     }
 
@@ -366,24 +516,42 @@ void SocketManager::createSignalSocket(ProtocolPtr protocol) {
     sigaddset(&mask, SIGTERM); // systemd terminates service sending this signal
 
     if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
-        LOGE("sigprocmask failed: <%s>", strerror(errno));
+        LOGE("sigprocmask failed: <%s>", safeStrError(errno).c_str());
         return;
     }
 
     int fd = signalfd(-1, &mask, SFD_NONBLOCK);
     if (fd < 0) {
-        LOGE("Creating signal file descriptor failed: <%s>", strerror(errno));
+        LOGE("Creating signal file descriptor failed: <%s>", safeStrError(errno).c_str());
         return;
     }
 
     auto &desc = createDescriptor(fd, false);
     desc.setListen(false);
     desc.setProtocol(protocol);
+    desc.setReadOnlyProtocol(protocol->clone());
     addReadSocket(fd);
 
     LOGD("Signal socket: [%d] added.", fd);
 }
 
+void SocketManager::createNonReadOnlyRequestResultsNumEventFd() {
+    int efd = eventfd(0, EFD_CLOEXEC);
+    if (efd < 0) {
+        int err = errno;
+        LOGE("eventfd() failed <%s>", safeStrError(err).c_str());
+        throw UnexpectedErrorException(err, safeStrError(err));
+    }
+    m_nonReadOnlyRequestResultsNumEventFd = efd;
+    // Mark the efd to be listened on for read events
+    auto& desc = createDescriptor(efd, false);
+    desc.setListen(false);
+    desc.setProtocol(nullptr);
+    desc.setReadOnlyProtocol(nullptr);
+    addReadSocket(efd);
+    LOGD("SocketManger created nonReadOnlyRequestResultsNumEventFd [%d]", efd);
+}
+
 Descriptor &SocketManager::createDescriptor(int fd, bool client) {
     if (fd > m_maxDesc) {
         m_maxDesc = fd;
@@ -412,10 +580,6 @@ void SocketManager::removeWriteSocket(int fd) {
     FD_CLR(fd, &m_writeSet);
 }
 
-RequestTakerPtr SocketManager::requestTaker(void) {
-    return std::static_pointer_cast<RequestTaker>(m_logic);
-}
-
 void SocketManager::disconnectAllClients(void) {
     for(int i = 0; i <= m_maxDesc; ++i) {
         auto &desc = m_fds[i];
index 737e5ee455b4ff95436bbb1f6c5bc5ba97657be7..0860ae78da10ecb69763132bd3b34c1f307ad38b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
 #ifndef SRC_SERVICE_SOCKETS_SOCKETMANAGER_H_
 #define SRC_SERVICE_SOCKETS_SOCKETMANAGER_H_
 
-#include <vector>
+#include <cstdio>
 #include <memory>
-#include <stdio.h>
+#include <thread>
+#include <variant>
+#include <vector>
 
 #include <common.h>
 
+#include <containers/MutexedBinaryQueue.h>
+#include <exceptions/UnexpectedErrorException.h>
 #include <main/pointers.h>
 #include <protocol/Protocol.h>
 #include <request/RequestTaker.h>
 #include "Descriptor.h"
+#include "logic/Logic.h"
+#include "utils/Channel.h"
 
 namespace Cynara {
 
@@ -49,7 +55,6 @@ public:
     ~SocketManager();
 
     void run(void);
-    void mainLoopStop(void);
 
     void bindLogic(LogicPtr logic) {
         m_logic = logic;
@@ -59,10 +64,54 @@ public:
         m_logic.reset();
     }
 
-    void disconnectAllClients(void);
+    // Only safe to call from m_nonReadOnlyWorkerThread
+    void signalDisconnectAllClients() {
+        if (std::this_thread::get_id() != m_nonReadOnlyWorkerThread.get_id())
+            throw UnexpectedErrorException{"signalDisconnectAllClients() call in the wrong thread"};
+        m_needToDisconnectAllClients = true;
+    }
+
+    // Only safe to call from m_nonReadOnlyWorkerThread
+    void signalStopMainLoop() {
+        if (std::this_thread::get_id() != m_nonReadOnlyWorkerThread.get_id())
+            throw UnexpectedErrorException{"signalDisconnectAllClients() call in the wrong thread"};
+        m_needToStopMainLoop = true;
+    }
 
 private:
+    struct NoMoreRequests {};
+    struct NonReadOnlyRequest {
+        int socketFd;
+        uint64_t socketFdGeneration;
+        RequestPtr request;
+        ProtocolPtr protocol;
+        MutexedBinaryQueuePtr writeQueue;
+    };
+    struct CloseContext {
+        int closedSocketFd;
+        MutexedBinaryQueuePtr closedWriteQueue;
+    };
+
+    struct NonReadOnlyRequestResult {
+        int socketFd;
+        uint64_t socketFdGeneration;
+        bool disconnectAllClients;
+        bool stopMainLoop;
+    };
+    // Used to break the event loop and write the created responses
+    struct CloseContextResult {};
+
+    std::mutex m_readOnlyLogicLock;
+    std::unique_ptr<ReadOnlyLogic> m_readOnlyLogic;
+
     LogicPtr m_logic;
+    std::thread m_nonReadOnlyWorkerThread;
+    Channel<std::variant<NoMoreRequests, NonReadOnlyRequest, CloseContext>> m_nonReadOnlyRequests;
+    Channel<std::variant<NonReadOnlyRequestResult, CloseContextResult>> m_nonReadOnlyRequestResults;
+    int m_nonReadOnlyRequestResultsNumEventFd = -1;
+    // Only accessed from m_nonReadOnlyWorkerThread
+    bool m_needToDisconnectAllClients = false;
+    bool m_needToStopMainLoop = false;
 
     typedef std::vector<Descriptor> FDVector;
     FDVector m_fds;
@@ -76,6 +125,8 @@ private:
     void init(void);
     void mainLoop(void);
 
+    void mainLoopStop(void);
+
     void readyForRead(int fd);
     void readyForWrite(int fd);
     void readyForAccept(int fd);
@@ -89,6 +140,7 @@ private:
     static int getSocketFromSystemD(const std::string &path);
 #endif
     void createSignalSocket(ProtocolPtr protocol);
+    void createNonReadOnlyRequestResultsNumEventFd();
 
     Descriptor &createDescriptor(int fd, bool client);
 
@@ -96,8 +148,7 @@ private:
     void removeReadSocket(int fd);
     void addWriteSocket(int fd);
     void removeWriteSocket(int fd);
-
-    RequestTakerPtr requestTaker(void);
+    void disconnectAllClients(void);
 };
 
 } // namespace Cynara
diff --git a/src/service/utils/Channel.h b/src/service/utils/Channel.h
new file mode 100644 (file)
index 0000000..21859d2
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This file is licensed under the terms of MIT License or the Apache License
+ * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
+ * See the LICENSE file or the notice below for Apache License Version 2.0
+ * details.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file        src/service/utils/Channel.h
+ * @author      Krzysztof MaÅ‚ysa <k.malysa@samsung.com>
+ * @version     1.0
+ * @brief       This file defines and implements a channel across threads
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <utility>
+
+namespace Cynara {
+
+template<class T>
+class Channel {
+public:
+    Channel() = default;
+    ~Channel() = default;
+
+    Channel(const Channel&) = delete;
+    Channel(Channel&&) = delete;
+    Channel& operator=(const Channel&) = delete;
+    Channel& operator=(Channel&&) = delete;
+
+    void send(T&& msg) {
+        {
+            auto guard = std::lock_guard{m_lock};
+            m_messages.push_back(std::move(msg));
+        }
+        m_condVar.notify_one();
+    }
+
+    T recv() {
+        auto lock = std::unique_lock{m_lock};
+        m_condVar.wait(lock, [&] { return !m_messages.empty(); });
+        auto msg = std::move(m_messages.front());
+        m_messages.pop_front();
+        return msg;
+    }
+
+private:
+    std::mutex m_lock;
+    std::condition_variable m_condVar;
+    std::deque<T> m_messages;
+};
+
+} // namespace Cynara
index f7f220a9a2cf3a4e92e40afb8a0317f3b390a1f7..9c5a33685a417521fc60d02e4e174a1d23a5a9b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -238,6 +238,12 @@ void InMemoryStorageBackend::erasePolicies(const PolicyBucketId &bucketId, bool
     }
 }
 
+std::unique_ptr<StorageBackend> InMemoryStorageBackend::clone() {
+    auto copy = std::make_unique<InMemoryStorageBackend>(m_dbPath);
+    copy->m_buckets = m_buckets;
+    return copy;
+}
+
 void InMemoryStorageBackend::dumpDatabase(const std::shared_ptr<std::ofstream> &chsStream) {
     auto indexStream = std::make_shared<ChecksumStream>(PathConfig::StoragePath::indexFilename,
             chsStream);
index 51858ed7b21081f4e48bb240ff840198d1658fbe..4dfa78e835397a5092d2f24cedb60798df9ef15e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -77,6 +77,8 @@ public:
     virtual void erasePolicies(const PolicyBucketId &bucketId, bool recursive,
                                const PolicyKey &filter);
 
+    std::unique_ptr<StorageBackend> clone() override;
+
 protected:
     // Saves database as backup files and stores checksums to @p chsStream
     void dumpDatabase(const std::shared_ptr<std::ofstream> &chsStream);
index 078afc9ffd61301ce499aaa65767f12711e43955..524dd6dd69cc072627e7d3dccc7801542293937d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
 
 #include "Storage.h"
 
-namespace Cynara {
+namespace {
 
-PolicyResult Storage::checkPolicy(const PolicyKey &key,
-                                  const PolicyBucketId &startBucketId /*= defaultPolicyBucketId*/,
-                                  bool recursive /*= true*/) {
-    auto policies = m_backend.searchBucket(startBucketId, key);
-    return minimalPolicy(policies, key, recursive);
-};
-
-PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey &key,
-                                    bool recursive) {
+Cynara::PolicyResult minimalPolicy(Cynara::StorageBackend& storageBackend,
+                                   const Cynara::PolicyBucket &bucket, const Cynara::PolicyKey &key,
+                                   bool recursive) {
     bool hasMinimal = false;
-    PolicyResult minimal = bucket.defaultPolicy();
+    Cynara::PolicyResult minimal = bucket.defaultPolicy();
 
-    auto proposeMinimal = [&minimal, &hasMinimal](const PolicyResult &candidate) {
+    auto proposeMinimal = [&minimal, &hasMinimal](const Cynara::PolicyResult &candidate) {
         if (hasMinimal == false) {
             minimal = candidate;
         } else if (candidate < minimal) {
@@ -69,19 +63,21 @@ PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey
         const auto &policyResult = policy->result();
 
         switch (policyResult.policyType()) {
-            case PredefinedPolicyType::DENY:
+            case Cynara::PredefinedPolicyType::DENY:
                 return policyResult; // Do not expect lower value than DENY
-            case PredefinedPolicyType::BUCKET: {
+            case Cynara::PredefinedPolicyType::BUCKET: {
                     if (recursive == true) {
-                        auto bucketResults = m_backend.searchBucket(policyResult.metadata(), key);
-                        auto minimumOfBucket = minimalPolicy(bucketResults, key, true);
-                        if (minimumOfBucket != PredefinedPolicyType::NONE) {
+                        auto bucketResults = storageBackend.searchBucket(policyResult.metadata(),
+                                                                         key);
+                        auto minimumOfBucket = minimalPolicy(storageBackend, bucketResults, key,
+                                                             true);
+                        if (minimumOfBucket != Cynara::PredefinedPolicyType::NONE) {
                             proposeMinimal(minimumOfBucket);
                         }
                     }
                     continue;
                 }
-            case PredefinedPolicyType::ALLOW:
+            case Cynara::PredefinedPolicyType::ALLOW:
             default:
                 break;
         }
@@ -92,6 +88,17 @@ PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey
     return minimal;
 }
 
+} // namespace
+
+namespace Cynara {
+
+PolicyResult Storage::checkPolicy(const PolicyKey &key,
+                                  const PolicyBucketId &startBucketId /*= defaultPolicyBucketId*/,
+                                  bool recursive /*= true*/) {
+    auto policies = m_backend.searchBucket(startBucketId, key);
+    return minimalPolicy(m_backend, policies, key, recursive);
+}
+
 void Storage::insertPolicies(const std::map<PolicyBucketId, std::vector<Policy>> &policiesByBucketId) {
 
     auto pointedBucketExists = [this] (const Policy &policy) -> void {
@@ -177,4 +184,23 @@ void Storage::save(void) {
     m_backend.save();
 }
 
+std::unique_ptr<StorageReadOnlyCopy> Storage::clone() {
+    return std::make_unique<StorageReadOnlyCopy>(m_backend.clone());
+}
+
+StorageReadOnlyCopy::StorageReadOnlyCopy(std::unique_ptr<StorageBackend> backend)
+    : m_backend{std::move(backend)} {}
+
+PolicyResult StorageReadOnlyCopy::checkPolicy(const PolicyKey &key,
+                                  const PolicyBucketId &startBucketId /*= defaultPolicyBucketId*/,
+                                  bool recursive /*= true*/) {
+    auto policies = m_backend->searchBucket(startBucketId, key);
+    return minimalPolicy(*m_backend, policies, key, recursive);
+}
+
+PolicyBucket::Policies StorageReadOnlyCopy::listPolicies(const PolicyBucketId &bucketId,
+                                             const PolicyKey &filter) const {
+    return m_backend->listPolicies(bucketId, filter);
+}
+
 } // namespace Cynara
index 76413c583e0d5f0ad23cc44e24363a5736514989..7833fe70a98ac1751f3feddcc80e844249203676 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -30,7 +30,7 @@
 #define SRC_STORAGE_STORAGE_H_
 
 #include <map>
-#include <string>
+#include <memory>
 #include <vector>
 
 #include <types/Policy.h>
@@ -43,6 +43,8 @@
 
 namespace Cynara {
 
+class StorageReadOnlyCopy;
+
 class Storage
 {
 public:
@@ -66,13 +68,27 @@ public:
     void load(void);
     void save(void);
 
-protected:
-    PolicyResult minimalPolicy(const PolicyBucket &bucket, const PolicyKey &key, bool recursive);
+    std::unique_ptr<StorageReadOnlyCopy> clone();
 
 private:
     StorageBackend &m_backend; // backend strategy
 };
 
+class StorageReadOnlyCopy {
+public:
+    explicit StorageReadOnlyCopy(std::unique_ptr<StorageBackend> backend);
+
+    PolicyResult checkPolicy(const PolicyKey &key,
+                             const PolicyBucketId &startBucketId = defaultPolicyBucketId,
+                             bool recursive = true);
+
+    PolicyBucket::Policies listPolicies(const PolicyBucketId &bucketId,
+                                        const PolicyKey &filter) const;
+
+private:
+    std::unique_ptr<StorageBackend> m_backend;
+};
+
 } // namespace Cynara
 
 #endif /* SRC_STORAGE_STORAGE_H_ */
index 4b3ad00e5c4e4f4f03b2b5ebf7a12ac6aac2ba4c..338ad5206bf14eaf23ee60b16db2f9dc15109a91 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -63,6 +63,8 @@ public:
                                const PolicyKey &filter) = 0;
     virtual void load(void) = 0;
     virtual void save(void) = 0;
+
+    virtual std::unique_ptr<StorageBackend> clone() = 0;
 };
 
 } /* namespace Cynara */
index e99038cf0f21d55c32e9e0c9ca074516ff447e64..d15e951501e1a015e0acc60728494f0e96be0b5e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2020-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -53,7 +53,7 @@ namespace NegativeTestHelper {
 
 template <class Protocol, class Exception, class Message, class...MessageArg>
 void testProtocolException(MessageArg&&...messageArg) {
-    auto queue = std::make_shared<Cynara::BinaryQueue>();
+    auto queue = std::make_shared<Cynara::MutexedBinaryQueue>();
     Cynara::RequestContext context(Cynara::ResponseTakerPtr(), queue);
     Protocol protocol;
     Message message(std::forward<MessageArg>(messageArg)...);
index 6d0dd0dbd0f8c42b85d07e8aad9f7b849fcda2cd..95be4bbf59c6eb6f7318655608ce41c2d07b1e48 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -32,7 +32,7 @@
 
 #include <gtest/gtest.h>
 
-#include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <containers/RawBuffer.h>
 #include <protocol/Protocol.h>
 #include <request/pointers.h>
@@ -46,33 +46,33 @@ namespace RequestTestHelper {
 
 template <typename R>
 void testRequest(std::shared_ptr<R> request, Cynara::ProtocolPtr protocol) {
-    auto queue = std::make_shared<Cynara::BinaryQueue>();
+    auto queue = std::make_shared<Cynara::MutexedBinaryQueue>();
     Cynara::RequestContext context(Cynara::ResponseTakerPtr(), queue);
 
     request->execute(*protocol, context);
 
-    auto extractedRequest = protocol->extractRequestFromBuffer(queue);
+    auto extractedRequest = protocol->extractRequestFromBuffer(queue->lock());
     ASSERT_TRUE(bool(extractedRequest));
-    ASSERT_EQ(queue->size(), static_cast<size_t>(0));
+    ASSERT_EQ(queue->lock()->size(), static_cast<size_t>(0));
 
     compare(*request, dynamic_cast<R &>(*extractedRequest));
 }
 
 void binaryTestRequest(Cynara::RequestPtr request, Cynara::ProtocolPtr protocol) {
-    auto queue = std::make_shared<Cynara::BinaryQueue>();
+    auto queue = std::make_shared<Cynara::MutexedBinaryQueue>();
     Cynara::RequestContext context(Cynara::ResponseTakerPtr(), queue);
 
     request->execute(*protocol, context);
-    Cynara::RawBuffer data(queue->size());
-    queue->flatten(data.data(), queue->size());
+    Cynara::RawBuffer data(queue->lock()->size());
+    queue->lock()->flatten(data.data(), data.size());
 
-    auto extractedRequest = protocol->extractRequestFromBuffer(queue);
+    auto extractedRequest = protocol->extractRequestFromBuffer(queue->lock());
     ASSERT_TRUE(bool(extractedRequest));
-    ASSERT_EQ(queue->size(), static_cast<size_t>(0));
+    ASSERT_EQ(queue->lock()->size(), static_cast<size_t>(0));
 
     extractedRequest->execute(*protocol, context);
-    Cynara::RawBuffer data2(queue->size());
-    queue->flatten(data2.data(), queue->size());
+    Cynara::RawBuffer data2(queue->lock()->size());
+    queue->lock()->flatten(data2.data(), data2.size());
 
     ASSERT_EQ(data, data2);
 }
index 1579f36550cdb3c4128b0ddea866af8f18239606..821705f76c2c84214866f48b4cdd18f34b3e720b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -32,7 +32,7 @@
 
 #include <gtest/gtest.h>
 
-#include <containers/BinaryQueue.h>
+#include <containers/MutexedBinaryQueue.h>
 #include <containers/RawBuffer.h>
 #include <protocol/Protocol.h>
 #include <request/RequestContext.h>
@@ -46,33 +46,33 @@ namespace ResponseTestHelper {
 
 template <typename R>
 void testResponse(std::shared_ptr<R> response, Cynara::ProtocolPtr protocol) {
-    auto queue = std::make_shared<Cynara::BinaryQueue>();
+    auto queue = std::make_shared<Cynara::MutexedBinaryQueue>();
     auto context = Cynara::RequestContext(Cynara::ResponseTakerPtr(), queue);
 
     response->execute(*protocol, context);
 
-    auto extractedResponse = protocol->extractResponseFromBuffer(queue);
+    auto extractedResponse = protocol->extractResponseFromBuffer(queue->lock());
     ASSERT_TRUE(bool(extractedResponse));
-    ASSERT_EQ(queue->size(), static_cast<size_t>(0));
+    ASSERT_EQ(queue->lock()->size(), static_cast<size_t>(0));
 
     compare(*response, dynamic_cast<R &>(*extractedResponse));
 }
 
 void binaryTestResponse(Cynara::ResponsePtr response, Cynara::ProtocolPtr protocol) {
-    auto queue = std::make_shared<Cynara::BinaryQueue>();
+    auto queue = std::make_shared<Cynara::MutexedBinaryQueue>();
     auto context = Cynara::RequestContext(Cynara::ResponseTakerPtr(), queue);
 
     response->execute(*protocol, context);
-    Cynara::RawBuffer data(queue->size());
-    queue->flatten(data.data(), queue->size());
+    Cynara::RawBuffer data(queue->lock()->size());
+    queue->lock()->flatten(data.data(), data.size());
 
-    auto extractedResponse = protocol->extractResponseFromBuffer(queue);
+    auto extractedResponse = protocol->extractResponseFromBuffer(queue->lock());
     ASSERT_TRUE(bool(extractedResponse));
-    ASSERT_EQ(queue->size(), static_cast<size_t>(0));
+    ASSERT_EQ(queue->lock()->size(), static_cast<size_t>(0));
 
     extractedResponse->execute(*protocol, context);
-    Cynara::RawBuffer data2(queue->size());
-    queue->flatten(data2.data(), queue->size());
+    Cynara::RawBuffer data2(queue->lock()->size());
+    queue->lock()->flatten(data2.data(), data2.size());
 
     ASSERT_EQ(data, data2);
 }
index 3adf8620c17c987a4710a91f1d75bc2caf9244aa..99f77648678636ce8f9ffb71b498f7668b28ffd3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2024 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -51,6 +51,8 @@ public:
                                                             const PolicyKey &filter));
     MOCK_METHOD3(erasePolicies, void(const PolicyBucketId &bucketId, bool recursive,
                                      const PolicyKey &filter));
+
+    MOCK_METHOD0(clone, std::unique_ptr<StorageBackend>(void));
 };
 
 #endif /* FAKESTORAGEBACKEND_H_ */