2 Copyright (c) 2018-2019 Nokia.
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
22 #ifndef SHAREDDATALAYER_SYNCSTORAGE_HPP_
23 #define SHAREDDATALAYER_SYNCSTORAGE_HPP_
34 #include <sdl/exception.hpp>
35 #include <sdl/publisherid.hpp>
37 namespace shareddatalayer
40 * @brief Class providing synchronous access to shared data layer storage.
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.
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.
51 * @note The same instance of SyncStorage must not be shared between multiple threads
52 * without explicit application level locking.
54 * @see AsyncStorage for asynchronous interface.
55 * @see AsyncStorage::SEPARATOR for namespace format restrictions.
60 SyncStorage(const SyncStorage&) = delete;
62 SyncStorage& operator = (const SyncStorage&) = delete;
64 SyncStorage(SyncStorage&&) = delete;
66 SyncStorage& operator = (SyncStorage&&) = delete;
68 virtual ~SyncStorage() = default;
70 using Namespace = std::string;
72 using Key = std::string;
74 using Data = std::vector<uint8_t>;
76 using DataMap = std::map<Key, Data>;
79 * Wait for the service to become ready to serve. There is typically a waiting period
80 * when product cluster is brought up (deploying container orchestrated service,
81 * container restart etc.). The function can be called and used to synchronize the
82 * application startup with the readiness of the underlying data storage.
84 * This function can also be used if SDL returns an error indicating connection cut
85 * to backend data storage. In that situation client can use this function to get an
86 * indication when SDL is again ready to serve. SDL error code documentation indicates
87 * the error codes for which the usage of this function is applicable.
89 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all
90 * derived from shareddatalayer::Exception base class. Client can catch only that
91 * exception if separate handling for different shareddatalayer error situations is not
94 * @param ns Namespace under which this operation is targeted. As it is possible to
95 * use different DB backend instances for namespaces, it is necessary to
96 * provide namespace for this call to test the DB backend readiness of that
97 * particular namespace. it is recommended to call this always when starting
98 * to use new namespace.
100 * @param timeout Timeout value after which readiness waiting will be expired in case
101 * the SDL service won't come up. It is recommended to use rather long
102 * timeout value to have enough time for a system to recover for example
103 * from restart scenarios. Suitable timeout value depends greatly from
104 * the environment itself. As an example an application could use 10
105 * seconds timeout value and have a loop what does a re-try every time
106 * when previous waitReady call has failed. On a side note, timeout
107 * value 0 means that readiness is waited interminable.
109 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
110 * @throw RejectedBySdl if SDL rejects the request.
111 * @throw BackendError if the backend data storage fails to process the request.
113 virtual void waitReady(const Namespace& ns, const std::chrono::steady_clock::duration& timeout) = 0;
116 * Write data to shared data layer storage. Writing is done atomically, i.e. either
117 * all succeeds or all fails.
119 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
120 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
121 * for different shareddatalayer error situations is not needed.
123 * @param ns Namespace under which this operation is targeted.
124 * @param dataMap Data to be written.
126 * @throw BackendError if the backend data storage fails to process the request.
127 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
128 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
129 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
131 virtual void set(const Namespace& ns,
132 const DataMap& dataMap) = 0;
135 * Conditionally modify the value of a key if the current value in data storage
136 * matches the user's last known value.
138 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
139 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
140 * for different shareddatalayer error situations is not needed.
142 * @param ns Namespace under which this operation is targeted.
143 * @param key Key for which data modification will be executed.
144 * @param oldData Last known data.
145 * @param newData Data to be written.
147 * @return True for successful modification, false if the user's last known data did
148 * not match the current value in data storage.
150 * @throw BackendError if the backend data storage fails to process the request.
151 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
152 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
153 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
155 virtual bool setIf(const Namespace& ns,
158 const Data& newData) = 0;
161 * Conditionally set the value of a key. If key already exists, then it's value
162 * is not modified. Checking the key existence and potential set operation is done
163 * as a one atomic operation.
165 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
166 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
167 * for different shareddatalayer error situations is not needed.
169 * @param ns Namespace under which this operation is targeted.
171 * @param data Data to be written.
173 * @return True if key didn't exist yet and set operation was executed, false if
174 * key already existed and thus its value was left untouched.
176 * @throw BackendError if the backend data storage fails to process the request.
177 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
178 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
179 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
181 virtual bool setIfNotExists(const Namespace& ns,
183 const Data& data) = 0;
185 using Keys = std::set<Key>;
188 * Read data from shared data layer storage. Only those entries that are found will
191 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
192 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
193 * for different shareddatalayer error situations is not needed.
195 * @param ns Namespace under which this operation is targeted.
196 * @param keys Data to be read.
198 * @return Data from the storage.
200 * @throw BackendError if the backend data storage fails to process the request.
201 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
202 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
203 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
205 virtual DataMap get(const Namespace& ns,
206 const Keys& keys) = 0;
209 * Remove data from shared data layer storage. Existing keys are removed. Removing
210 * is done atomically, i.e. either all succeeds or all fails.
212 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
213 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
214 * for different shareddatalayer error situations is not needed.
216 * @param ns Namespace under which this operation is targeted.
217 * @param keys Data to be removed.
219 * @throw BackendError if the backend data storage fails to process the request.
220 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
221 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
222 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
224 virtual void remove(const Namespace& ns,
225 const Keys& keys) = 0;
228 * Conditionally remove data from shared data layer storage if the current data value
229 * matches the user's last known value.
231 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
232 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
233 * for different shareddatalayer error situations is not needed.
235 * @param ns Namespace under which this operation is targeted.
236 * @param key Data to be removed.
237 * @param data Last known value of data
239 * @return True if successful removal, false if the user's last known data did
240 * not match the current value in data storage.
242 * @throw BackendError if the backend data storage fails to process the request.
243 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
244 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
245 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
247 virtual bool removeIf(const Namespace& ns,
249 const Data& data) = 0;
252 * Find all keys matching search key prefix under the namespace. No prior knowledge about the keys in the given
253 * namespace exists, thus operation is not guaranteed to be atomic or isolated.
255 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
256 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
257 * for different shareddatalayer error situations is not needed.
259 * @param ns Namespace under which this operation is targeted.
260 * @param keyPrefix Only keys starting with given keyPrefix are returned. Passing empty string as
261 * keyPrefix will return all keys.
263 * @return Found keys.
265 * @throw BackendError if the backend data storage fails to process the request.
266 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
267 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
268 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
270 [[deprecated("Use listKeys() instead.")]]
271 virtual Keys findKeys(const Namespace& ns,
272 const std::string& keyPrefix) = 0;
275 * List all keys matching search glob-style pattern under the namespace.
277 * Supported glob-style patterns:
278 * h?llo matches hello, hallo and hxllo
279 * h*llo matches hllo and heeeello
280 * h[ae]llo matches hello and hallo, but not hillo
281 * h[^e]llo matches hallo, hbllo, ... but not hello
282 * h[a-b]llo matches hallo and hbllo
284 * The \ escapes character(s) in key search pattern and those will be treated as a normal
286 * h\[?llo\* matches h[ello* and h[allo*
288 * @param ns Namespace under which this operation is targeted.
289 * @param pattern Find keys matching a given glob-style pattern.
291 * @return Found keys.
293 * @throw BackendError if the backend data storage fails to process the request.
294 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
295 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
296 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
298 virtual Keys listKeys(const Namespace& ns,
299 const std::string& pattern) = 0;
302 * Remove all keys under the namespace. Found keys are removed atomically, i.e.
303 * either all succeeds or all fails.
305 * Exceptions thrown (excluding standard exceptions such as std::bad_alloc) are all derived from
306 * shareddatalayer::Exception base class. Client can catch only that exception if separate handling
307 * for different shareddatalayer error situations is not needed.
309 * @param ns Namespace under which this operation is targeted.
311 * @throw BackendError if the backend data storage fails to process the request.
312 * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
313 * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
314 * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
316 virtual void removeAll(const Namespace& ns) = 0;
319 * Set a timeout value for the synchronous SDL read, write and remove operations.
320 * By default synchronous read, write and remove operations do not have any timeout
321 * for the backend data storage readiness, operations are pending interminable to
322 * finish until backend is ready. With this API function default behaviour can be
323 * changed and when a timeout happens, an error exception is risen for the SDL
324 * operation in question. To avoid unnecessary timeout failure due to a temporal
325 * connection issue, it is recommended not to set too short timeout value.
326 * Reasonable timeout value is 5 seconds or bigger value. On a side note, timeout
327 * value 0 means interminable pending time.
329 * @param timeout Timeout value to set.
331 virtual void setOperationTimeout(const std::chrono::steady_clock::duration& timeout) = 0;
334 * Create a new instance of SyncStorage.
336 * @return New instance of SyncStorage.
338 * @throw EmptyNamespace if namespace string is an empty string.
339 * @throw InvalidNamespace if namespace contains illegal characters.
342 static std::unique_ptr<SyncStorage> create();
345 SyncStorage() = default;