Add extra line about src files are part of RIC platform project
[ric-plt/sdl.git] / include / sdl / asyncstorage.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_ASYNCSTORAGE_HPP_
23 #define SHAREDDATALAYER_ASYNCSTORAGE_HPP_
24
25 #include <cstdint>
26 #include <functional>
27 #include <map>
28 #include <memory>
29 #include <set>
30 #include <string>
31 #include <system_error>
32 #include <utility>
33 #include <vector>
34 #include <sdl/errorqueries.hpp>
35 #include <sdl/publisherid.hpp>
36
37 namespace shareddatalayer
38 {
39     /**
40      * @brief Class providing asynchronous access to shared data layer storage.
41      *
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.
46      *
47      * AsyncStorage is primarily intended for event-loop based applications.
48      *
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.
52      *
53      * @see fd
54      * @see handleEvents
55      *
56      * @note The same instance of AsyncStorage must not be shared between multiple
57      *       threads without explicit application level locking.
58      *
59      * @see SyncStorage for synchronous interface.
60      */
61     class AsyncStorage
62     {
63     public:
64         AsyncStorage(const AsyncStorage&) = delete;
65
66         AsyncStorage& operator = (const AsyncStorage&) = delete;
67
68         AsyncStorage(AsyncStorage&&) = delete;
69
70         AsyncStorage& operator = (AsyncStorage&&) = delete;
71
72         virtual ~AsyncStorage() = default;
73
74         using Namespace = std::string;
75
76         /**
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.
80          *
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
83          * though.
84          */
85         static constexpr char SEPARATOR = ',';
86
87         /**
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>).
92          *
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>.
97          *
98          * @return The file descriptor to monitor in application's event loop.
99          *
100          * @see handleEvents
101          */
102         virtual int fd() const = 0;
103
104         /**
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.
108          *
109          * @see fd
110          */
111         virtual void handleEvents() = 0;
112
113         /**
114          * Ready acknowledgement to be called when shared data layer storage is ready to serve.
115          *
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.
120          */
121         using ReadyAck = std::function<void(const std::error_code& error)>;
122
123         /**
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.
128          *
129          * In a steady state, the callback is called almost immediately, varying based on runtime
130          * conditions.
131          *
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.
140          *
141          * @note Each instance/namespace should be waited on only *once*.
142          */
143         virtual void waitReadyAsync(const Namespace& ns,
144                                     const ReadyAck& readyAck) = 0;
145
146         using Key = std::string;
147
148         using Data = std::vector<uint8_t>;
149
150         using DataMap = std::map<Key, Data>;
151
152         /**
153          * Modify acknowledgement to be called when setAsync/removeAsync/removeAllAsync request has been
154          * handled.
155          *
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.
162          */
163         using ModifyAck = std::function<void(const std::error_code& error)>;
164
165         /**
166          * Write data to shared data layer storage. Writing is done atomically, i.e. either
167          * all succeeds or all fails.
168          *
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.
173          */
174         virtual void setAsync(const Namespace& ns,
175                               const DataMap& dataMap,
176                               const ModifyAck& modifyAck) = 0;
177
178         /**
179          * Modify acknowledgement to be called when setIfAsync/setIfNotExistsAsync/removeIfAsync request has been handled.
180          *
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.
189          */
190         using ModifyIfAck = std::function<void(const std::error_code& error, bool status)>;
191
192         /**
193          * Conditionally modify the value of a key if the current value in data storage
194          * matches the user's last known value.
195          *
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.
202          */
203         virtual void setIfAsync(const Namespace& ns,
204                                 const Key& key,
205                                 const Data& oldData,
206                                 const Data& newData,
207                                 const ModifyIfAck& modifyIfAck) = 0;
208
209         /**
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.
213          *
214          * @param ns Namespace under which this operation is targeted.
215          * @param key Key.
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.
219          */
220         virtual void setIfNotExistsAsync(const Namespace& ns,
221                                          const Key& key,
222                                          const Data& data,
223                                          const ModifyIfAck& modifyIfAck) = 0;
224
225         using Keys = std::set<Key>;
226
227         /**
228          * Read acknowledgement to be called when getAsync request has been handled.
229          *
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.
237          */
238         using GetAck = std::function<void(const std::error_code& error, const DataMap& dataMap)>;
239
240         /**
241          * Read data from shared data layer storage. Only those entries that are found will
242          * be returned.
243          *
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.
248          */
249         virtual void getAsync(const Namespace& ns,
250                               const Keys& keys,
251                               const GetAck& getAck) = 0;
252
253         /**
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.
256          *
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.
261          */
262         virtual void removeAsync(const Namespace& ns,
263                                  const Keys& keys,
264                                  const ModifyAck& modifyAck) = 0;
265
266         /**
267          * Conditionally remove data from shared data layer storage if the current data value
268          * matches the user's last known value.
269          *
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.
275          */
276         virtual void removeIfAsync(const Namespace& ns,
277                                    const Key& key,
278                                    const Data& data,
279                                    const ModifyIfAck& modifyIfAck) = 0;
280
281         /**
282          * Read acknowledgement to be called when findKeysAsync request has been handled.
283          *
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.
291          */
292         using FindKeysAck = std::function<void(const std::error_code& error, const Keys& keys)>;
293
294         /**
295          * Find all keys matching search pattern 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.
297          *
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.
303          */
304         virtual void findKeysAsync(const Namespace& ns,
305                                    const std::string& keyPrefix,
306                                    const FindKeysAck& findKeysAck) = 0;
307
308         /**
309          * Remove all keys under the namespace. Found keys are removed atomically, i.e.
310          * either all succeeds or all fails.
311          *
312          * @param ns Namespace under which this operation is targeted.
313          * @param modifyAck The acknowledgement to be called once the request has been handled.
314          *                  The given function is called in the context of handleEvents() function.
315          */
316         virtual void removeAllAsync(const Namespace& ns,
317                                     const ModifyAck& modifyAck) = 0;
318
319         /**
320          * Create a new instance of AsyncStorage.
321          *
322          * @return New instance of AsyncStorage.
323          */
324         static std::unique_ptr<AsyncStorage> create();
325
326     protected:
327         AsyncStorage() = default;
328     };
329 }
330
331 #endif