Add first version
[ric-plt/sdl.git] / include / sdl / syncstorage.hpp
diff --git a/include/sdl/syncstorage.hpp b/include/sdl/syncstorage.hpp
new file mode 100644 (file)
index 0000000..58417e3
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+   Copyright (c) 2018-2019 Nokia.
+
+   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.
+*/
+
+#ifndef SHAREDDATALAYER_SYNCSTORAGE_HPP_
+#define SHAREDDATALAYER_SYNCSTORAGE_HPP_
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+#include <sdl/exception.hpp>
+#include <sdl/publisherid.hpp>
+
+namespace shareddatalayer
+{
+    /**
+     * @brief Class providing synchronous access to shared data layer storage.
+     *
+     * SyncStorage class provides synchronous access to all namespaces in
+     * shared data layer storage. Data can be saved, read and removed based on keys known
+     * to clients. Keys are unique within a namespace, namespace identifier is passed as
+     * a parameter to all operations.
+     *
+     * SyncStorage is primarily intended for command-line interface-typed applications, or
+     * non-event-loop based, such as multi-threaded applications, where shareddatalayer
+     * operations are carried out in a separate thread.
+     *
+     * @note The same instance of SyncStorage must not be shared between multiple threads
+     *       without explicit application level locking.
+     *
+     * @see AsyncStorage for asynchronous interface.
+     * @see AsyncStorage::SEPARATOR for namespace format restrictions.
+     */
+    class SyncStorage
+    {
+    public:
+        SyncStorage(const SyncStorage&) = delete;
+
+        SyncStorage& operator = (const SyncStorage&) = delete;
+
+        SyncStorage(SyncStorage&&) = delete;
+
+        SyncStorage& operator = (SyncStorage&&) = delete;
+
+        virtual ~SyncStorage() = default;
+
+        using Namespace = std::string;
+
+        using Key = std::string;
+
+        using Data = std::vector<uint8_t>;
+
+        using DataMap = std::map<Key, Data>;
+
+        /**
+         * Write data to shared data layer storage. Writing is done atomically, i.e. either
+         * all succeeds or all fails.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         * @param dataMap Data to be written.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual void set(const Namespace& ns,
+                         const DataMap& dataMap) = 0;
+
+        /**
+         * Conditionally modify the value of a key if the current value in data storage
+         * matches the user's last known value.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         * @param key Key for which data modification will be executed.
+         * @param oldData Last known data.
+         * @param newData Data to be written.
+         *
+         * @return True for successful modification, false if the user's last known data did
+         *         not match the current value in data storage.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual bool setIf(const Namespace& ns,
+                           const Key& key,
+                           const Data& oldData,
+                           const Data& newData) = 0;
+
+        /**
+         * Conditionally set the value of a key. If key already exists, then it's value
+         * is not modified. Checking the key existence and potential set operation is done
+         * as a one atomic operation.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         * @param key Key.
+         * @param data Data to be written.
+         *
+         * @return True if key didn't exist yet and set operation was executed, false if
+         *         key already existed and thus its value was left untouched.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual bool setIfNotExists(const Namespace& ns,
+                                    const Key& key,
+                                    const Data& data) = 0;
+
+        using Keys = std::set<Key>;
+
+        /**
+         * Read data from shared data layer storage. Only those entries that are found will
+         * be returned.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         * @param keys Data to be read.
+         *
+         * @return Data from the storage.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual DataMap get(const Namespace& ns,
+                            const Keys& keys) = 0;
+
+        /**
+         * Remove data from shared data layer storage. Existing keys are removed. Removing
+         * is done atomically, i.e. either all succeeds or all fails.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         * @param keys Data to be removed.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual void remove(const Namespace& ns,
+                            const Keys& keys) = 0;
+
+        /**
+         * Conditionally remove data from shared data layer storage if the current data value
+         * matches the user's last known value.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         * @param key Data to be removed.
+         * @param data Last known value of data
+         *
+         * @return True if successful removal, false if the user's last known data did
+         *         not match the current value in data storage.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual bool removeIf(const Namespace& ns,
+                              const Key& key,
+                              const Data& data) = 0;
+
+        /**
+         * Find all keys matching search pattern under the namespace. No prior knowledge about the keys in the given
+         * namespace exists, thus operation is not guaranteed to be atomic or isolated.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         * @param keyPrefix Only keys starting with given keyPrefix are returned. Passing empty string as
+         *                  keyPrefix will return all keys.
+         *
+         * @return Found keys.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual Keys findKeys(const Namespace& ns,
+                              const std::string& keyPrefix) = 0;
+
+        /**
+         * Remove all keys under the namespace. Found keys are removed atomically, i.e.
+         * either all succeeds or all fails.
+         *
+         * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
+         * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
+         * for different shareddatalayer error situations is not needed.
+         *
+         * @param ns Namespace under which this operation is targeted.
+         *
+         * @throw BackendError if the backend data storage fails to process the request.
+         * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+         * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+         * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+         */
+        virtual void removeAll(const Namespace& ns) = 0;
+
+        /**
+         * Create a new instance of SyncStorage.
+         *
+         * @return New instance of SyncStorage.
+         *
+         * @throw EmptyNamespace if namespace string is an empty string.
+         * @throw InvalidNamespace if namespace contains illegal characters.
+         *
+         */
+        static std::unique_ptr<SyncStorage> create();
+
+    protected:
+        SyncStorage() = default;
+    };
+}
+
+#endif