blob: 19f0e547d8e8e329c5889d63c1ee0f9d549b7b92 [file] [log] [blame]
Rolf Badorekef2bf512019-08-20 11:17:15 +03001/*
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
Timo Tietavainena0745d22019-11-28 09:55:22 +020017/*
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
20*/
21
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +030022#include <chrono>
Rolf Badorekef2bf512019-08-20 11:17:15 +030023#include <sstream>
Rolf Badorekef2bf512019-08-20 11:17:15 +030024#include <sdl/asyncstorage.hpp>
25#include <sdl/backenderror.hpp>
26#include <sdl/errorqueries.hpp>
27#include <sdl/invalidnamespace.hpp>
28#include <sdl/notconnected.hpp>
29#include <sdl/operationinterrupted.hpp>
30#include <sdl/rejectedbybackend.hpp>
31#include <sdl/rejectedbysdl.hpp>
32#include "private/redis/asyncredisstorage.hpp"
33#include "private/syncstorageimpl.hpp"
34#include "private/system.hpp"
35
36using namespace shareddatalayer;
37
38namespace
39{
40 void throwExceptionForErrorCode[[ noreturn ]](const std::error_code& ec)
41 {
42 if (ec == shareddatalayer::Error::BACKEND_FAILURE)
43 throw BackendError(ec.message());
44 else if (ec == shareddatalayer::Error::NOT_CONNECTED)
45 throw NotConnected(ec.message());
46 else if (ec == shareddatalayer::Error::OPERATION_INTERRUPTED)
47 throw OperationInterrupted(ec.message());
48 else if (ec == shareddatalayer::Error::REJECTED_BY_BACKEND)
49 throw RejectedByBackend(ec.message());
50 else if (ec == AsyncRedisStorage::ErrorCode::INVALID_NAMESPACE)
51 throw InvalidNamespace(ec.message());
52 else if (ec == shareddatalayer::Error::REJECTED_BY_SDL)
53 throw RejectedBySdl(ec.message());
54
55 std::ostringstream os;
56 os << "No corresponding SDL exception found for error code: " << ec.category().name() << " " << ec.value();
57 throw std::range_error(os.str());
58 }
59}
60
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +030061/* TODO: This synchronous API implementation could probably be refactored to be boost::asio based
62 * instead of current (bit error prone) poll based implementation.
63 */
64
Rolf Badorekef2bf512019-08-20 11:17:15 +030065SyncStorageImpl::SyncStorageImpl(std::unique_ptr<AsyncStorage> asyncStorage):
66 SyncStorageImpl(std::move(asyncStorage), System::getSystem())
67{
68}
69
70SyncStorageImpl::SyncStorageImpl(std::unique_ptr<AsyncStorage> pAsyncStorage,
71 System& system):
72 asyncStorage(std::move(pAsyncStorage)),
73 system(system),
Rolf Badorekef2bf512019-08-20 11:17:15 +030074 localStatus(false),
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +030075 synced(false),
76 isReady(false),
77 events{ asyncStorage->fd(), POLLIN, 0 },
78 operationTimeout(std::chrono::steady_clock::duration::zero())
Rolf Badorekef2bf512019-08-20 11:17:15 +030079{
80}
81
Timo Tietavainend565df62021-08-11 07:33:30 +030082void SyncStorageImpl::waitReadyAck(const std::error_code& error)
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +030083{
84 isReady = true;
Timo Tietavainend565df62021-08-11 07:33:30 +030085 localError = error;
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +030086}
87
Rolf Badorekef2bf512019-08-20 11:17:15 +030088void SyncStorageImpl::modifyAck(const std::error_code& error)
89{
90 synced = true;
91 localError = error;
92}
93
94void SyncStorageImpl::modifyIfAck(const std::error_code& error, bool status)
95{
96 synced = true;
97 localError = error;
98 localStatus = status;
99}
100
101void SyncStorageImpl::getAck(const std::error_code& error, const DataMap& dataMap)
102{
103 synced = true;
104 localError = error;
105 localMap = dataMap;
106}
107
108void SyncStorageImpl::findKeysAck(const std::error_code& error, const Keys& keys)
109{
110 synced = true;
111 localError = error;
112 localKeys = keys;
113}
114
115void SyncStorageImpl::verifyBackendResponse()
116{
117 if(localError)
118 throwExceptionForErrorCode(localError);
119}
120
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300121void SyncStorageImpl::waitForOperationCallback()
Rolf Badorekef2bf512019-08-20 11:17:15 +0300122{
Rolf Badorekef2bf512019-08-20 11:17:15 +0300123 while(!synced)
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300124 pollAndHandleEvents(NO_TIMEOUT);
125}
126
127void SyncStorageImpl::pollAndHandleEvents(int timeout_ms)
128{
129 if (system.poll(&events, 1, timeout_ms) > 0 && (events.revents & POLLIN))
130 asyncStorage->handleEvents();
131}
132
Timo Tietavainend565df62021-08-11 07:33:30 +0300133void SyncStorageImpl::waitForReadinessCheckCallback(const std::chrono::steady_clock::duration& timeout)
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300134{
Timo Tietavainend565df62021-08-11 07:33:30 +0300135 if (timeout == std::chrono::steady_clock::duration::zero())
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300136 {
137 while (!isReady)
138 pollAndHandleEvents(NO_TIMEOUT);
139 }
140 else
141 {
Timo Tietavainend565df62021-08-11 07:33:30 +0300142 auto timeout_ms(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count());
143 auto pollTimeout_ms(timeout_ms / 10);
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300144 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
Timo Tietavainend565df62021-08-11 07:33:30 +0300145 while(!isReady && (std::chrono::steady_clock::now() - start < std::chrono::milliseconds(timeout_ms)))
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300146 pollAndHandleEvents(pollTimeout_ms);
147 }
Rolf Badorekef2bf512019-08-20 11:17:15 +0300148}
149
150void SyncStorageImpl::waitSdlToBeReady(const Namespace& ns)
151{
Timo Tietavainend565df62021-08-11 07:33:30 +0300152 waitSdlToBeReady(ns, operationTimeout);
153}
154
155void SyncStorageImpl::waitSdlToBeReady(const Namespace& ns, const std::chrono::steady_clock::duration& timeout)
156{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300157 isReady = false;
Rolf Badorekef2bf512019-08-20 11:17:15 +0300158 asyncStorage->waitReadyAsync(ns,
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300159 std::bind(&shareddatalayer::SyncStorageImpl::waitReadyAck,
Rolf Badorekef2bf512019-08-20 11:17:15 +0300160 this,
Timo Tietavainend565df62021-08-11 07:33:30 +0300161 std::placeholders::_1));
162 waitForReadinessCheckCallback(timeout);
163}
164
165void SyncStorageImpl::waitReady(const Namespace& ns, const std::chrono::steady_clock::duration& timeout)
166{
167 waitSdlToBeReady(ns, timeout);
168 if(!isReady)
169 throw RejectedBySdl("Timeout, SDL service not ready for the '" + ns + "' namespace");
170 verifyBackendResponse();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300171}
172
173void SyncStorageImpl::set(const Namespace& ns, const DataMap& dataMap)
174{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300175 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300176 waitSdlToBeReady(ns);
177 synced = false;
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300178
Rolf Badorekef2bf512019-08-20 11:17:15 +0300179 asyncStorage->setAsync(ns,
180 dataMap,
181 std::bind(&shareddatalayer::SyncStorageImpl::modifyAck,
182 this,
183 std::placeholders::_1));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300184 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300185 verifyBackendResponse();
186}
187
188bool SyncStorageImpl::setIf(const Namespace& ns, const Key& key, const Data& oldData, const Data& newData)
189{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300190 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300191 waitSdlToBeReady(ns);
192 synced = false;
193 asyncStorage->setIfAsync(ns,
194 key,
195 oldData,
196 newData,
197 std::bind(&shareddatalayer::SyncStorageImpl::modifyIfAck,
198 this,
199 std::placeholders::_1,
200 std::placeholders::_2));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300201 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300202 verifyBackendResponse();
203 return localStatus;
204}
205
206bool SyncStorageImpl::setIfNotExists(const Namespace& ns, const Key& key, const Data& data)
207{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300208 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300209 waitSdlToBeReady(ns);
210 synced = false;
211 asyncStorage->setIfNotExistsAsync(ns,
212 key,
213 data,
214 std::bind(&shareddatalayer::SyncStorageImpl::modifyIfAck,
215 this,
216 std::placeholders::_1,
217 std::placeholders::_2));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300218 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300219 verifyBackendResponse();
220 return localStatus;
221}
222
223SyncStorageImpl::DataMap SyncStorageImpl::get(const Namespace& ns, const Keys& keys)
224{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300225 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300226 waitSdlToBeReady(ns);
227 synced = false;
228 asyncStorage->getAsync(ns,
229 keys,
230 std::bind(&shareddatalayer::SyncStorageImpl::getAck,
231 this,
232 std::placeholders::_1,
233 std::placeholders::_2));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300234 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300235 verifyBackendResponse();
236 return localMap;
237}
238
239void SyncStorageImpl::remove(const Namespace& ns, const Keys& keys)
240{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300241 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300242 waitSdlToBeReady(ns);
243 synced = false;
244 asyncStorage->removeAsync(ns,
245 keys,
246 std::bind(&shareddatalayer::SyncStorageImpl::modifyAck,
247 this,
248 std::placeholders::_1));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300249 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300250 verifyBackendResponse();
251}
252
253bool SyncStorageImpl::removeIf(const Namespace& ns, const Key& key, const Data& data)
254{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300255 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300256 waitSdlToBeReady(ns);
257 synced = false;
258 asyncStorage->removeIfAsync(ns,
259 key,
260 data,
261 std::bind(&shareddatalayer::SyncStorageImpl::modifyIfAck,
262 this,
263 std::placeholders::_1,
264 std::placeholders::_2));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300265 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300266 verifyBackendResponse();
267 return localStatus;
268}
269
270SyncStorageImpl::Keys SyncStorageImpl::findKeys(const Namespace& ns, const std::string& keyPrefix)
271{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300272 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300273 waitSdlToBeReady(ns);
274 synced = false;
275 asyncStorage->findKeysAsync(ns,
276 keyPrefix,
277 std::bind(&shareddatalayer::SyncStorageImpl::findKeysAck,
278 this,
279 std::placeholders::_1,
280 std::placeholders::_2));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300281 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300282 verifyBackendResponse();
283 return localKeys;
284}
285
Petri Ovaska63869e12021-09-17 11:54:21 +0300286SyncStorageImpl::Keys SyncStorageImpl::listKeys(const Namespace& ns, const std::string& pattern)
287{
288 handlePendingEvents();
289 waitSdlToBeReady(ns);
290 synced = false;
291 asyncStorage->listKeys(ns,
292 pattern,
293 std::bind(&shareddatalayer::SyncStorageImpl::findKeysAck,
294 this,
295 std::placeholders::_1,
296 std::placeholders::_2));
297 waitForOperationCallback();
298 verifyBackendResponse();
299 return localKeys;
300}
301
Rolf Badorekef2bf512019-08-20 11:17:15 +0300302void SyncStorageImpl::removeAll(const Namespace& ns)
303{
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300304 handlePendingEvents();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300305 waitSdlToBeReady(ns);
306 synced = false;
307 asyncStorage->removeAllAsync(ns,
308 std::bind(&shareddatalayer::SyncStorageImpl::modifyAck,
309 this,
310 std::placeholders::_1));
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300311 waitForOperationCallback();
Rolf Badorekef2bf512019-08-20 11:17:15 +0300312 verifyBackendResponse();
313}
Timo Tietavainenfaf9fc72021-08-05 11:46:07 +0300314
315void SyncStorageImpl::handlePendingEvents()
316{
317 int pollRetVal = system.poll(&events, 1, 0);
318
319 while (pollRetVal > 0 && events.revents & POLLIN)
320 {
321 asyncStorage->handleEvents();
322 pollRetVal = system.poll(&events, 1, 0);
323 }
324}
325
326void SyncStorageImpl::setOperationTimeout(const std::chrono::steady_clock::duration& timeout)
327{
328 operationTimeout = timeout;
329}