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.
17 #ifndef SHAREDDATALAYER_ASYNCSTORAGE_HPP_
18 #define SHAREDDATALAYER_ASYNCSTORAGE_HPP_
26 #include <system_error>
29 #include <sdl/errorqueries.hpp>
30 #include <sdl/publisherid.hpp>
32 namespace shareddatalayer
35 * @brief Class providing asynchronous access to shared data layer storage.
37 * AsyncStorage class provides asynchronous access to all namespaces in
38 * shared data layer storage. Data can be saved, read and removed based on keys known
39 * to clients. Keys are unique within a namespace, namespace identifier is passed as
40 * a parameter to all operations.
42 * AsyncStorage is primarily intended for event-loop based applications.
44 * Asynchronous functions taking const reference parameters do not assume that the
45 * references are valid after the function returns. The underlying implementation will
46 * make copies of the given parameter when needed.
51 * @note The same instance of AsyncStorage must not be shared between multiple
52 * threads without explicit application level locking.
54 * @see SyncStorage for synchronous interface.
59 AsyncStorage(const AsyncStorage&) = delete;
61 AsyncStorage& operator = (const AsyncStorage&) = delete;
63 AsyncStorage(AsyncStorage&&) = delete;
65 AsyncStorage& operator = (AsyncStorage&&) = delete;
67 virtual ~AsyncStorage() = default;
69 using Namespace = std::string;
72 * Separator character is used by the API internally in namespace handling. Thus, separator
73 * character cannot be part of the namespace identifier string provided by the client.
74 * Also namespace identifier cannot be an empty string.
76 * API otherwise does not impose additional restrictions to the characters used in namespace
77 * identifiers. Excessive and unnecessary usage of special characters is strongly discouraged
80 static constexpr char SEPARATOR = ',';
83 * Get the file descriptor to monitor in application's event loop. The file descriptor
84 * can be monitored for example with <code>select(2)</code>, <code>poll(2)</code> or
85 * <code>epoll_wait(2)</code>. The event to be monitored is <i>input</i> event (like
86 * for example <code>POLLIN</code>).
88 * Whenever there is input event in the file descriptor, application must call
89 * handleEvents() function. Application must keep monitoring events until all desired
90 * acknowledgement functions have been invoked. Application must stop monitoring events
91 * before destroying <code>this</code>.
93 * @return The file descriptor to monitor in application's event loop.
97 virtual int fd() const = 0;
100 * Function to be called whenever there is an input event in the file descriptor
101 * returned by fd() function. Each call to handleEvents() may invoke zero or more
102 * acknowledgement functions.
106 virtual void handleEvents() = 0;
109 * Ready acknowledgement to be called when shared data layer storage is ready to serve.
111 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
112 * and <code>std::error_code::value()</code> are implementation specific. If ReadyAck
113 * is passed an error, client is advised to instantiate a new AsyncStorage and
114 * waitReadyAsync again.
116 using ReadyAck = std::function<void(const std::error_code& error)>;
119 * Wait for the service to become ready to serve. There typically is a waiting period
120 * when product cluster is brought up (commissioning, VNFC restart etc.). The function
121 * can be called and used to synchronize the application startup with the readiness of
122 * the underlying data storage.
124 * In a steady state, the callback is called almost immediately, varying based on runtime
127 * @param ns Namespace under which this operation is targeted. As it is possible to
128 * configure for each namespace whether DB backend is in use, it is neccasary
129 * to provide namespace for this call. If it is known that DB backend usage
130 * configuration is the same for all used namespaces, this call can be done only
131 * once for certain namespace. If the configuration can vary between namespaces,
132 * it is recommended to call this always when starting to use new namespace.
133 * @param readyAck The acknowledgement to be called once the request has been handled.
134 * The given function is called in the context of handleEvents() function.
136 * @note Each instance/namespace should be waited on only *once*.
138 virtual void waitReadyAsync(const Namespace& ns,
139 const ReadyAck& readyAck) = 0;
141 using Key = std::string;
143 using Data = std::vector<uint8_t>;
145 using DataMap = std::map<Key, Data>;
148 * Modify acknowledgement to be called when setAsync/removeAsync/removeAllAsync request has been
151 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
152 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
153 * to compare received error against <code>shareddatalayer::Error</code> constants when
154 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
155 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
156 * and provided to shareddatalayer developers if problem needs further investigation.
158 using ModifyAck = std::function<void(const std::error_code& error)>;
161 * Write data to shared data layer storage. Writing is done atomically, i.e. either
162 * all succeeds or all fails.
164 * @param ns Namespace under which this operation is targeted.
165 * @param dataMap Data to be written.
166 * @param modifyAck The acknowledgement to be called once the request has been handled.
167 * The given function is called in the context of handleEvents() function.
169 virtual void setAsync(const Namespace& ns,
170 const DataMap& dataMap,
171 const ModifyAck& modifyAck) = 0;
174 * Modify acknowledgement to be called when setIfAsync/setIfNotExistsAsync/removeIfAsync request has been handled.
176 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
177 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
178 * to compare received error against <code>shareddatalayer::Error</code> constants when
179 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
180 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
181 * and provided to shareddatalayer developers if problem needs further investigation.
182 * @param status Status of the modification. True for successful modification, false if modification
183 * was not done due to the given prerequisite.
185 using ModifyIfAck = std::function<void(const std::error_code& error, bool status)>;
188 * Conditionally modify the value of a key if the current value in data storage
189 * matches the user's last known value.
191 * @param ns Namespace under which this operation is targeted.
192 * @param key Key for which data modification will be executed.
193 * @param oldData Last known data.
194 * @param newData Data to be written.
195 * @param modifyIfAck The acknowledgement to be called once the request has been handled.
196 * The given function is called in the context of handleEvents() function.
198 virtual void setIfAsync(const Namespace& ns,
202 const ModifyIfAck& modifyIfAck) = 0;
205 * Conditionally set the value of a key. If key already exists, then it's value
206 * is not modified. Checking the key existence and potential set operation is done
207 * as a one atomic operation.
209 * @param ns Namespace under which this operation is targeted.
211 * @param data Data to be written.
212 * @param modifyIfAck The acknowledgement to be called once the request has been handled.
213 * The given function is called in the context of handleEvents() function.
215 virtual void setIfNotExistsAsync(const Namespace& ns,
218 const ModifyIfAck& modifyIfAck) = 0;
220 using Keys = std::set<Key>;
223 * Read acknowledgement to be called when getAsync request has been handled.
225 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
226 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
227 * to compare received error against <code>shareddatalayer::Error</code> constants when
228 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
229 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
230 * and provided to shareddatalayer developers if problem needs further investigation.
231 * @param dataMap Data from the storage. Empty container is returned in case of error.
233 using GetAck = std::function<void(const std::error_code& error, const DataMap& dataMap)>;
236 * Read data from shared data layer storage. Only those entries that are found will
239 * @param ns Namespace under which this operation is targeted.
240 * @param keys Data to be read.
241 * @param getAck The acknowledgement to be called once the request has been handled.
242 * The given function is called in the context of handleEvents() function.
244 virtual void getAsync(const Namespace& ns,
246 const GetAck& getAck) = 0;
249 * Remove data from shared data layer storage. Existing keys are removed. Removing
250 * is done atomically, i.e. either all succeeds or all fails.
252 * @param ns Namespace under which this operation is targeted.
253 * @param keys Data to be removed.
254 * @param modifyAck The acknowledgement to be called once the request has been handled.
255 * The given function is called in the context of handleEvents() function.
257 virtual void removeAsync(const Namespace& ns,
259 const ModifyAck& modifyAck) = 0;
262 * Conditionally remove data from shared data layer storage if the current data value
263 * matches the user's last known value.
265 * @param ns Namespace under which this operation is targeted.
266 * @param key Data to be removed
267 * @param data Last known value of data
268 * @param modifyIfAck The acknowledgement to be called once the request has been handled.
269 * The given function is called in the context of handleEvents() function.
271 virtual void removeIfAsync(const Namespace& ns,
274 const ModifyIfAck& modifyIfAck) = 0;
277 * Read acknowledgement to be called when findKeysAsync request has been handled.
279 * @param error Error code describing the status of the request. The <code>std::error_code::category()</code>
280 * and <code>std::error_code::value()</code> are implementation specific. Client is advised
281 * to compare received error against <code>shareddatalayer::Error</code> constants when
282 * doing error handling. See documentation: sdl/errorqueries.hpp for further information.
283 * Received <code>std::error_code</code> and <code>std::error_code::message()</code> can be stored
284 * and provided to shareddatalayer developers if problem needs further investigation.
285 * @param keys Found keys.
287 using FindKeysAck = std::function<void(const std::error_code& error, const Keys& keys)>;
290 * Find all keys matching search pattern under the namespace. No prior knowledge about the keys in the given
291 * namespace exists, thus operation is not guaranteed to be atomic or isolated.
293 * @param ns Namespace under which this operation is targeted.
294 * @param keyPrefix Only keys starting with given keyPrefix are returned. Passing empty string as
295 * keyPrefix will return all keys.
296 * @param findKeysAck The acknowledgement to be called once the request has been handled.
297 * The given function is called in the context of handleEvents() function.
299 virtual void findKeysAsync(const Namespace& ns,
300 const std::string& keyPrefix,
301 const FindKeysAck& findKeysAck) = 0;
304 * Remove all keys under the namespace. Found keys are removed atomically, i.e.
305 * either all succeeds or all fails.
307 * @param ns Namespace under which this operation is targeted.
308 * @param modifyAck The acknowledgement to be called once the request has been handled.
309 * The given function is called in the context of handleEvents() function.
311 virtual void removeAllAsync(const Namespace& ns,
312 const ModifyAck& modifyAck) = 0;
315 * Create a new instance of AsyncStorage.
317 * @return New instance of AsyncStorage.
319 static std::unique_ptr<AsyncStorage> create();
322 AsyncStorage() = default;