Add definable timeout for SyncStorage APIs
[ric-plt/sdl.git] / include / sdl / syncstorage.hpp
1 /*
2    Copyright (c) 2018-2019 Nokia.
3
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15 */
16
17 /*
18  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19  * platform project (RICP).
20 */
21
22 #ifndef SHAREDDATALAYER_SYNCSTORAGE_HPP_
23 #define SHAREDDATALAYER_SYNCSTORAGE_HPP_
24
25 #include <cstdint>
26 #include <functional>
27 #include <map>
28 #include <memory>
29 #include <set>
30 #include <string>
31 #include <utility>
32 #include <vector>
33 #include <chrono>
34 #include <sdl/exception.hpp>
35 #include <sdl/publisherid.hpp>
36
37 namespace shareddatalayer
38 {
39     /**
40      * @brief Class providing synchronous access to shared data layer storage.
41      *
42      * SyncStorage class provides synchronous access to all namespaces in
43      * shared data layer storage. Data can be saved, read and removed based on keys known
44      * to clients. Keys are unique within a namespace, namespace identifier is passed as
45      * a parameter to all operations.
46      *
47      * SyncStorage is primarily intended for command-line interface-typed applications, or
48      * non-event-loop based, such as multi-threaded applications, where shareddatalayer
49      * operations are carried out in a separate thread.
50      *
51      * @note The same instance of SyncStorage must not be shared between multiple threads
52      *       without explicit application level locking.
53      *
54      * @see AsyncStorage for asynchronous interface.
55      * @see AsyncStorage::SEPARATOR for namespace format restrictions.
56      */
57     class SyncStorage
58     {
59     public:
60         SyncStorage(const SyncStorage&) = delete;
61
62         SyncStorage& operator = (const SyncStorage&) = delete;
63
64         SyncStorage(SyncStorage&&) = delete;
65
66         SyncStorage& operator = (SyncStorage&&) = delete;
67
68         virtual ~SyncStorage() = default;
69
70         using Namespace = std::string;
71
72         using Key = std::string;
73
74         using Data = std::vector<uint8_t>;
75
76         using DataMap = std::map<Key, Data>;
77
78         /**
79          * Write data to shared data layer storage. Writing is done atomically, i.e. either
80          * all succeeds or all fails.
81          *
82          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
83          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
84          * for different shareddatalayer error situations is not needed.
85          *
86          * @param ns Namespace under which this operation is targeted.
87          * @param dataMap Data to be written.
88          *
89          * @throw BackendError if the backend data storage fails to process the request.
90          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
91          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
92          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
93          */
94         virtual void set(const Namespace& ns,
95                          const DataMap& dataMap) = 0;
96
97         /**
98          * Conditionally modify the value of a key if the current value in data storage
99          * matches the user's last known value.
100          *
101          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
102          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
103          * for different shareddatalayer error situations is not needed.
104          *
105          * @param ns Namespace under which this operation is targeted.
106          * @param key Key for which data modification will be executed.
107          * @param oldData Last known data.
108          * @param newData Data to be written.
109          *
110          * @return True for successful modification, false if the user's last known data did
111          *         not match the current value in data storage.
112          *
113          * @throw BackendError if the backend data storage fails to process the request.
114          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
115          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
116          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
117          */
118         virtual bool setIf(const Namespace& ns,
119                            const Key& key,
120                            const Data& oldData,
121                            const Data& newData) = 0;
122
123         /**
124          * Conditionally set the value of a key. If key already exists, then it's value
125          * is not modified. Checking the key existence and potential set operation is done
126          * as a one atomic operation.
127          *
128          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
129          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
130          * for different shareddatalayer error situations is not needed.
131          *
132          * @param ns Namespace under which this operation is targeted.
133          * @param key Key.
134          * @param data Data to be written.
135          *
136          * @return True if key didn't exist yet and set operation was executed, false if
137          *         key already existed and thus its value was left untouched.
138          *
139          * @throw BackendError if the backend data storage fails to process the request.
140          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
141          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
142          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
143          */
144         virtual bool setIfNotExists(const Namespace& ns,
145                                     const Key& key,
146                                     const Data& data) = 0;
147
148         using Keys = std::set<Key>;
149
150         /**
151          * Read data from shared data layer storage. Only those entries that are found will
152          * be returned.
153          *
154          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
155          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
156          * for different shareddatalayer error situations is not needed.
157          *
158          * @param ns Namespace under which this operation is targeted.
159          * @param keys Data to be read.
160          *
161          * @return Data from the storage.
162          *
163          * @throw BackendError if the backend data storage fails to process the request.
164          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
165          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
166          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
167          */
168         virtual DataMap get(const Namespace& ns,
169                             const Keys& keys) = 0;
170
171         /**
172          * Remove data from shared data layer storage. Existing keys are removed. Removing
173          * is done atomically, i.e. either all succeeds or all fails.
174          *
175          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
176          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
177          * for different shareddatalayer error situations is not needed.
178          *
179          * @param ns Namespace under which this operation is targeted.
180          * @param keys Data to be removed.
181          *
182          * @throw BackendError if the backend data storage fails to process the request.
183          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
184          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
185          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
186          */
187         virtual void remove(const Namespace& ns,
188                             const Keys& keys) = 0;
189
190         /**
191          * Conditionally remove data from shared data layer storage if the current data value
192          * matches the user's last known value.
193          *
194          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
195          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
196          * for different shareddatalayer error situations is not needed.
197          *
198          * @param ns Namespace under which this operation is targeted.
199          * @param key Data to be removed.
200          * @param data Last known value of data
201          *
202          * @return True if successful removal, false if the user's last known data did
203          *         not match the current value in data storage.
204          *
205          * @throw BackendError if the backend data storage fails to process the request.
206          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
207          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
208          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
209          */
210         virtual bool removeIf(const Namespace& ns,
211                               const Key& key,
212                               const Data& data) = 0;
213
214         /**
215          * Find all keys matching search key prefix under the namespace. No prior knowledge about the keys in the given
216          * namespace exists, thus operation is not guaranteed to be atomic or isolated.
217          *
218          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
219          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
220          * for different shareddatalayer error situations is not needed.
221          *
222          * @param ns Namespace under which this operation is targeted.
223          * @param keyPrefix Only keys starting with given keyPrefix are returned. Passing empty string as
224          *                  keyPrefix will return all keys.
225          *
226          * @return Found keys.
227          *
228          * @throw BackendError if the backend data storage fails to process the request.
229          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
230          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
231          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
232          */
233         virtual Keys findKeys(const Namespace& ns,
234                               const std::string& keyPrefix) = 0;
235
236         /**
237          * Remove all keys under the namespace. Found keys are removed atomically, i.e.
238          * either all succeeds or all fails.
239          *
240          * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
241          * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
242          * for different shareddatalayer error situations is not needed.
243          *
244          * @param ns Namespace under which this operation is targeted.
245          *
246          * @throw BackendError if the backend data storage fails to process the request.
247          * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
248          * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
249          * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
250          */
251         virtual void removeAll(const Namespace& ns) = 0;
252
253         /**
254          * Set a timeout value for the synchronous SDL read, write and remove operations.
255          * By default synchronous read, write and remove operations do not have any timeout
256          * for the backend data storage readiness, operations are pending interminable to
257          * finish until backend is ready. With this API function default behaviour can be
258          * changed and when a timeout happens, an error exception is risen for the SDL
259          * operation in question. To avoid unnecessary timeout failure due to a temporal
260          * connection issue, it is recommended not to set too short timeout value.
261          * Reasonable timeout value is 5 seconds or bigger value. On a side note, timeout
262          * value 0 means interminable pending time.
263          *
264          * @param timeout Timeout value to set.
265          */
266          virtual void setOperationTimeout(const std::chrono::steady_clock::duration& timeout) = 0;
267
268         /**
269          * Create a new instance of SyncStorage.
270          *
271          * @return New instance of SyncStorage.
272          *
273          * @throw EmptyNamespace if namespace string is an empty string.
274          * @throw InvalidNamespace if namespace contains illegal characters.
275          *
276          */
277         static std::unique_ptr<SyncStorage> create();
278
279     protected:
280         SyncStorage() = default;
281     };
282 }
283
284 #endif