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_ASYNCSTORAGE_HPP_
23 #define SHAREDDATALAYER_ASYNCSTORAGE_HPP_
31 #include <system_error>
34 #include <sdl/errorqueries.hpp>
35 #include <sdl/publisherid.hpp>
37 namespace shareddatalayer
40 * @brief Class providing asynchronous access to shared data layer storage.
42 * AsyncStorage class provides asynchronous 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 * AsyncStorage is primarily intended for event-loop based applications.
49 * Asynchronous functions taking const reference parameters do not assume that the
50 * references are valid after the function returns. The underlying implementation will
51 * make copies of the given parameter when needed.
56 * @note The same instance of AsyncStorage must not be shared between multiple
57 * threads without explicit application level locking.
59 * @see SyncStorage for synchronous interface.
64 AsyncStorage(const AsyncStorage&) = delete;
66 AsyncStorage& operator = (const AsyncStorage&) = delete;
68 AsyncStorage(AsyncStorage&&) = delete;
70 AsyncStorage& operator = (AsyncStorage&&) = delete;
72 virtual ~AsyncStorage() = default;
74 using Namespace = std::string;
77 * Separator character is used by the API internally in namespace handling. Thus, separator
78 * character cannot be part of the namespace identifier string provided by the client.
79 * Also namespace identifier cannot be an empty string.
81 * API otherwise does not impose additional restrictions to the characters used in namespace
82 * identifiers. Excessive and unnecessary usage of special characters is strongly discouraged
85 static constexpr char SEPARATOR = ',';
88 * Get the file descriptor to monitor in application's event loop. The file descriptor
89 * can be monitored for example with <code>select(2)</code>, <code>poll(2)</code> or
90 * <code>epoll_wait(2)</code>. The event to be monitored is <i>input</i> event (like
91 * for example <code>POLLIN</code>).
93 * Whenever there is input event in the file descriptor, application must call
94 * handleEvents() function. Application must keep monitoring events until all desired
95 * acknowledgement functions have been invoked. Application must stop monitoring events
96 * before destroying <code>this</code>.
98 * @return The file descriptor to monitor in application's event loop.
102 virtual int fd() const = 0;
105 * Function to be called whenever there is an input event in the file descriptor
106 * returned by fd() function. Each call to handleEvents() may invoke zero or more
107 * acknowledgement functions.
111 virtual void handleEvents() = 0;
114 * Ready acknowledgement to be called when shared data layer storage is ready to serve.
116 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
117 * and <code>std::error_code::value()</code> are implementation specific. If ReadyAck
118 * is passed an error, client is advised to instantiate a new AsyncStorage and
119 * waitReadyAsync again.
121 using ReadyAck = std::function<void(const std::error_code& error)>;
124 * Wait for the service to become ready to serve. There typically is a waiting period
125 * when product cluster is brought up (commissioning, VNFC restart etc.). The function
126 * can be called and used to synchronize the application startup with the readiness of
127 * the underlying data storage.
129 * In a steady state, the callback is called almost immediately, varying based on runtime
132 * @param ns Namespace under which this operation is targeted. As it is possible to
133 * configure for each namespace whether DB backend is in use, it is neccasary
134 * to provide namespace for this call. If it is known that DB backend usage
135 * configuration is the same for all used namespaces, this call can be done only
136 * once for certain namespace. If the configuration can vary between namespaces,
137 * it is recommended to call this always when starting to use new namespace.
138 * @param readyAck The acknowledgement to be called once the request has been handled.
139 * The given function is called in the context of handleEvents() function.
141 * @note Each instance/namespace should be waited on only *once*.
143 virtual void waitReadyAsync(const Namespace& ns,
144 const ReadyAck& readyAck) = 0;
146 using Key = std::string;
148 using Data = std::vector<uint8_t>;
150 using DataMap = std::map<Key, Data>;
153 * Modify acknowledgement to be called when setAsync/removeAsync/removeAllAsync request has been
156 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
157 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
158 * to compare received error against <code>shareddatalayer::Error</code> constants when
159 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
160 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
161 * and provided to shareddatalayer developers if problem needs further investigation.
163 using ModifyAck = std::function<void(const std::error_code& error)>;
166 * Write data to shared data layer storage. Writing is done atomically, i.e. either
167 * all succeeds or all fails.
169 * @param ns Namespace under which this operation is targeted.
170 * @param dataMap Data to be written.
171 * @param modifyAck The acknowledgement to be called once the request has been handled.
172 * The given function is called in the context of handleEvents() function.
174 virtual void setAsync(const Namespace& ns,
175 const DataMap& dataMap,
176 const ModifyAck& modifyAck) = 0;
179 * Modify acknowledgement to be called when setIfAsync/setIfNotExistsAsync/removeIfAsync request has been handled.
181 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
182 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
183 * to compare received error against <code>shareddatalayer::Error</code> constants when
184 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
185 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
186 * and provided to shareddatalayer developers if problem needs further investigation.
187 * @param status Status of the modification. True for successful modification, false if modification
188 * was not done due to the given prerequisite.
190 using ModifyIfAck = std::function<void(const std::error_code& error, bool status)>;
193 * Conditionally modify the value of a key if the current value in data storage
194 * matches the user's last known value.
196 * @param ns Namespace under which this operation is targeted.
197 * @param key Key for which data modification will be executed.
198 * @param oldData Last known data.
199 * @param newData Data to be written.
200 * @param modifyIfAck The acknowledgement to be called once the request has been handled.
201 * The given function is called in the context of handleEvents() function.
203 virtual void setIfAsync(const Namespace& ns,
207 const ModifyIfAck& modifyIfAck) = 0;
210 * Conditionally set the value of a key. If key already exists, then it's value
211 * is not modified. Checking the key existence and potential set operation is done
212 * as a one atomic operation.
214 * @param ns Namespace under which this operation is targeted.
216 * @param data Data to be written.
217 * @param modifyIfAck The acknowledgement to be called once the request has been handled.
218 * The given function is called in the context of handleEvents() function.
220 virtual void setIfNotExistsAsync(const Namespace& ns,
223 const ModifyIfAck& modifyIfAck) = 0;
225 using Keys = std::set<Key>;
228 * Read acknowledgement to be called when getAsync request has been handled.
230 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
231 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
232 * to compare received error against <code>shareddatalayer::Error</code> constants when
233 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
234 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
235 * and provided to shareddatalayer developers if problem needs further investigation.
236 * @param dataMap Data from the storage. Empty container is returned in case of error.
238 using GetAck = std::function<void(const std::error_code& error, const DataMap& dataMap)>;
241 * Read data from shared data layer storage. Only those entries that are found will
244 * @param ns Namespace under which this operation is targeted.
245 * @param keys Data to be read.
246 * @param getAck The acknowledgement to be called once the request has been handled.
247 * The given function is called in the context of handleEvents() function.
249 virtual void getAsync(const Namespace& ns,
251 const GetAck& getAck) = 0;
254 * Remove data from shared data layer storage. Existing keys are removed. Removing
255 * is done atomically, i.e. either all succeeds or all fails.
257 * @param ns Namespace under which this operation is targeted.
258 * @param keys Data to be removed.
259 * @param modifyAck The acknowledgement to be called once the request has been handled.
260 * The given function is called in the context of handleEvents() function.
262 virtual void removeAsync(const Namespace& ns,
264 const ModifyAck& modifyAck) = 0;
267 * Conditionally remove data from shared data layer storage if the current data value
268 * matches the user's last known value.
270 * @param ns Namespace under which this operation is targeted.
271 * @param key Data to be removed
272 * @param data Last known value of data
273 * @param modifyIfAck The acknowledgement to be called once the request has been handled.
274 * The given function is called in the context of handleEvents() function.
276 virtual void removeIfAsync(const Namespace& ns,
279 const ModifyIfAck& modifyIfAck) = 0;
282 * Read acknowledgement to be called when findKeysAsync request has been handled.
284 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
285 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
286 * to compare received error against <code>shareddatalayer::Error</code> constants when
287 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
288 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
289 * and provided to shareddatalayer developers if problem needs further investigation.
290 * @param keys Found keys.
292 using FindKeysAck = std::function<void(const std::error_code& error, const Keys& keys)>;
295 * Find all keys matching search key prefix under the namespace. No prior knowledge about the keys in the given
296 * namespace exists, thus operation is not guaranteed to be atomic or isolated.
298 * @param ns Namespace under which this operation is targeted.
299 * @param keyPrefix Only keys starting with given keyPrefix are returned. Passing empty string as
300 * keyPrefix will return all keys.
301 * @param findKeysAck The acknowledgement to be called once the request has been handled.
302 * The given function is called in the context of handleEvents() function.
304 [[deprecated("Use listKeys() instead.")]]
305 virtual void findKeysAsync(const Namespace& ns,
306 const std::string& keyPrefix,
307 const FindKeysAck& findKeysAck) = 0;
310 * List all keys matching search glob-style pattern under the namespace.
312 * Supported glob-style patterns:
313 * h?llo matches hello, hallo and hxllo
314 * h*llo matches hllo and heeeello
315 * h[ae]llo matches hello and hallo, but not hillo
316 * h[^e]llo matches hallo, hbllo, ... but not hello
317 * h[a-b]llo matches hallo and hbllo
319 * The \ escapes character(s) in key search pattern and those will be treated as a normal
321 * h\[?llo\* matches h[ello* and h[allo*
323 * @param ns Namespace under which this operation is targeted.
324 * @param pattern Find keys matching a given glob-style pattern.
325 * @param findKeysAck The acknowledgement to be called once the request has been handled.
326 * The given function is called in the context of handleEvents() function.
328 virtual void listKeys(const Namespace& ns,
329 const std::string& pattern,
330 const FindKeysAck& findKeysAck) = 0;
333 * Remove all keys under the namespace. Found keys are removed atomically, i.e.
334 * either all succeeds or all fails.
336 * @param ns Namespace under which this operation is targeted.
337 * @param modifyAck The acknowledgement to be called once the request has been handled.
338 * The given function is called in the context of handleEvents() function.
340 virtual void removeAllAsync(const Namespace& ns,
341 const ModifyAck& modifyAck) = 0;
344 * Create a new instance of AsyncStorage.
346 * @return New instance of AsyncStorage.
348 static std::unique_ptr<AsyncStorage> create();
351 AsyncStorage() = default;