1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "rd_single_ver_natural_store.h"
16
17 #include "rd_single_ver_natural_store_connection.h"
18 #include "rd_utils.h"
19 #include "sqlite_single_ver_storage_engine.h"
20
21 namespace DistributedDB {
22
RdSingleVerNaturalStore()23 RdSingleVerNaturalStore::RdSingleVerNaturalStore()
24 : storageEngine_(nullptr),
25 notificationEventsRegistered_(false)
26 {
27 LOGD("RdSingleVerNaturalStore Created");
28 }
29
~RdSingleVerNaturalStore()30 RdSingleVerNaturalStore::~RdSingleVerNaturalStore()
31 {
32 }
33
NewConnection(int & errCode)34 GenericKvDBConnection *RdSingleVerNaturalStore::NewConnection(int &errCode)
35 {
36 RdSingleVerNaturalStoreConnection *connection = new (std::nothrow) RdSingleVerNaturalStoreConnection(this);
37 if (connection == nullptr) {
38 errCode = -E_OUT_OF_MEMORY;
39 return nullptr;
40 }
41 errCode = E_OK;
42 return connection;
43 }
44
GetAndInitStorageEngine(const KvDBProperties & kvDBProp)45 int RdSingleVerNaturalStore::GetAndInitStorageEngine(const KvDBProperties &kvDBProp)
46 {
47 int errCode = E_OK;
48 {
49 std::unique_lock<std::shared_mutex> lock(engineMutex_);
50 storageEngine_ =
51 static_cast<RdSingleVerStorageEngine *>(StorageEngineManager::GetStorageEngine(kvDBProp, errCode));
52 if (storageEngine_ == nullptr) {
53 return errCode;
54 }
55 }
56
57 errCode = InitDatabaseContext(kvDBProp);
58 if (errCode != E_OK) {
59 LOGE("[RdSinStore][GetAndInitStorageEngine] Init database context fail! errCode = [%d]", errCode);
60 }
61 return errCode;
62 }
63
RegisterNotification()64 int RdSingleVerNaturalStore::RegisterNotification()
65 {
66 static const std::vector<int> events {
67 static_cast<int>(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT),
68 };
69 for (auto event = events.begin(); event != events.end(); ++event) {
70 int errCode = RegisterNotificationEventType(*event);
71 if (errCode == E_OK) {
72 continue;
73 }
74 LOGE("Register rd single version event %d failed:%d!", *event, errCode);
75 for (auto iter = events.begin(); iter != event; ++iter) {
76 UnRegisterNotificationEventType(*iter);
77 }
78 return errCode;
79 }
80 notificationEventsRegistered_ = true;
81 return E_OK;
82 }
83
ReleaseHandle(RdSingleVerStorageExecutor * & handle) const84 void RdSingleVerNaturalStore::ReleaseHandle(RdSingleVerStorageExecutor *&handle) const
85 {
86 if (handle == nullptr) {
87 return;
88 }
89 if (storageEngine_ != nullptr) {
90 StorageExecutor *databaseHandle = handle;
91 storageEngine_->Recycle(databaseHandle);
92 handle = nullptr;
93 }
94 engineMutex_.unlock_shared(); // unlock after handle used up
95 }
96
TransObserverTypeToRegisterFunctionType(int observerType,RegisterFuncType & type) const97 int RdSingleVerNaturalStore::TransObserverTypeToRegisterFunctionType(int observerType, RegisterFuncType &type) const
98 {
99 static constexpr TransPair transMap[] = {
100 { static_cast<int>(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT),
101 RegisterFuncType::OBSERVER_SINGLE_VERSION_NS_PUT_EVENT },
102 };
103 auto funcType = GetFuncType(observerType, transMap, sizeof(transMap) / sizeof(TransPair));
104 if (funcType == RegisterFuncType::REGISTER_FUNC_TYPE_MAX) {
105 return -E_NOT_SUPPORT;
106 }
107 type = funcType;
108 return E_OK;
109 }
110
Open(const KvDBProperties & kvDBProp)111 int RdSingleVerNaturalStore::Open(const KvDBProperties &kvDBProp)
112 {
113 // Currently, Design for the consistency of directory and file setting secOption
114 int errCode = ClearIncompleteDatabase(kvDBProp);
115 if (errCode != E_OK) {
116 LOGE("Clear incomplete database failed in single version:%d", errCode);
117 return errCode;
118 }
119 const std::string dataDir = kvDBProp.GetStringProp(KvDBProperties::DATA_DIR, "");
120 const std::string identifierDir = kvDBProp.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
121 bool isCreate = kvDBProp.GetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
122 errCode = DBCommon::CreateStoreDirectory(dataDir, identifierDir, DBConstant::SINGLE_SUB_DIR, isCreate);
123 if (errCode != E_OK) {
124 LOGE("Create single version natural store directory failed:%d", errCode);
125 return errCode;
126 }
127 LOGD("[RdSingleVerNaturalStore] Open RdSingleVerNaturalStore");
128 errCode = GetAndInitStorageEngine(kvDBProp);
129 if (errCode != E_OK) {
130 ReleaseResources();
131 return errCode;
132 }
133 errCode = RegisterNotification();
134 if (errCode != E_OK) {
135 LOGE("register notification failed:%d", errCode);
136 ReleaseResources();
137 return errCode;
138 }
139 MyProp() = kvDBProp;
140 OnKill([this]() { ReleaseResources(); });
141 return errCode;
142 }
143
ReleaseResources()144 void RdSingleVerNaturalStore::ReleaseResources()
145 {
146 if (notificationEventsRegistered_) {
147 UnRegisterNotificationEventType(
148 static_cast<EventType>(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT));
149 notificationEventsRegistered_ = false;
150 }
151 {
152 std::unique_lock<std::shared_mutex> lock(engineMutex_);
153 if (storageEngine_ != nullptr) {
154 (void)StorageEngineManager::ReleaseStorageEngine(storageEngine_);
155 storageEngine_ = nullptr;
156 }
157 }
158 }
159
160 // Invoked automatically when connection count is zero
Close()161 void RdSingleVerNaturalStore::Close()
162 {
163 ReleaseResources();
164 }
165
166 // Get interface type of this kvdb.
GetInterfaceType() const167 int RdSingleVerNaturalStore::GetInterfaceType() const
168 {
169 return -E_NOT_SUPPORT;
170 }
171
172 // Get the interface ref-count, in order to access asynchronously.
IncRefCount()173 void RdSingleVerNaturalStore::IncRefCount()
174 {
175 return;
176 }
177
178 // Drop the interface ref-count.
DecRefCount()179 void RdSingleVerNaturalStore::DecRefCount()
180 {
181 return;
182 }
183
184 // Get the identifier of this kvdb.
GetIdentifier() const185 std::vector<uint8_t> RdSingleVerNaturalStore::GetIdentifier() const
186 {
187 return {};
188 }
189
190 // Get interface for syncer.
GetSyncInterface()191 IKvDBSyncInterface *RdSingleVerNaturalStore::GetSyncInterface()
192 {
193 return nullptr;
194 }
195
GetMetaData(const Key & key,Value & value) const196 int RdSingleVerNaturalStore::GetMetaData(const Key &key, Value &value) const
197 {
198 return -E_NOT_SUPPORT;
199 }
200
PutMetaData(const Key & key,const Value & value,bool isInTransaction)201 int RdSingleVerNaturalStore::PutMetaData(const Key &key, const Value &value, bool isInTransaction)
202 {
203 return -E_NOT_SUPPORT;
204 }
205
206 // Delete multiple meta data records in a transaction.
DeleteMetaData(const std::vector<Key> & keys)207 int RdSingleVerNaturalStore::DeleteMetaData(const std::vector<Key> &keys)
208 {
209 return -E_NOT_SUPPORT;
210 }
211
212 // Delete multiple meta data records with key prefix in a transaction.
DeleteMetaDataByPrefixKey(const Key & keyPrefix) const213 int RdSingleVerNaturalStore::DeleteMetaDataByPrefixKey(const Key &keyPrefix) const
214 {
215 return -E_NOT_SUPPORT;
216 }
217
GetAllMetaKeys(std::vector<Key> & keys) const218 int RdSingleVerNaturalStore::GetAllMetaKeys(std::vector<Key> &keys) const
219 {
220 return -E_NOT_SUPPORT;
221 }
222
GetMaxTimestamp(Timestamp & stamp) const223 void RdSingleVerNaturalStore::GetMaxTimestamp(Timestamp &stamp) const
224 {
225 return;
226 }
227
SetMaxTimestamp(Timestamp timestamp)228 void RdSingleVerNaturalStore::SetMaxTimestamp(Timestamp timestamp)
229 {
230 return;
231 }
232
Rekey(const CipherPassword & passwd)233 int RdSingleVerNaturalStore::Rekey(const CipherPassword &passwd)
234 {
235 return -E_NOT_SUPPORT;
236 }
237
Export(const std::string & filePath,const CipherPassword & passwd)238 int RdSingleVerNaturalStore::Export(const std::string &filePath, const CipherPassword &passwd)
239 {
240 if (storageEngine_ == nullptr) {
241 return -E_INVALID_DB;
242 }
243
244 // MEMORY_MODE is false, not E_NOT_SUPPORT
245 if (MyProp().GetBoolProp(KvDBProperties::MEMORY_MODE, false)) {
246 return -E_NOT_SUPPORT;
247 }
248
249 // MEMORY_MODE is READ_ONLY_MODE is true, not E_NOT_SUPPORT
250 if (MyProp().GetBoolProp(KvDBProperties::READ_ONLY_MODE, true)) {
251 return -E_READ_ONLY;
252 }
253
254 int errCode = E_OK;
255 RdSingleVerStorageExecutor *handle = GetHandle(true, errCode);
256 if (handle == nullptr) {
257 return errCode;
258 }
259
260 // forbid migrate by hold write handle not release
261 if (storageEngine_->GetEngineState() != EngineState::MAINDB) {
262 errCode = (storageEngine_->GetEngineState() == EngineState::CACHEDB) ? -E_NOT_SUPPORT : -E_BUSY;
263 ReleaseHandle(handle);
264 return errCode;
265 }
266
267 errCode = TryToDisableConnection(OperatePerm::NORMAL_WRITE);
268 if (errCode != E_OK) {
269 ReleaseHandle(handle);
270 return errCode;
271 }
272
273 uint8_t *encryptedKey = const_cast<uint8_t*>(passwd.GetData());
274 uint32_t encryptedKeyLen = (uint32_t)passwd.GetSize();
275 errCode = handle->Backup(filePath, encryptedKey, encryptedKeyLen);
276 if (errCode != E_OK) {
277 LOGE("[RdSingleVerNaturalStore][Backup] can not backup the data %d", errCode);
278 }
279
280 ReEnableConnection(OperatePerm::NORMAL_WRITE);
281 ReleaseHandle(handle);
282 return errCode;
283 }
284
PreCheckRdImport(std::string & storePath)285 int RdSingleVerNaturalStore::PreCheckRdImport(std::string &storePath)
286 {
287 if (storageEngine_ == nullptr) {
288 LOGE("storageEngine_ is nullptr!");
289 return -E_INVALID_DB;
290 }
291
292 // MEMORY_MODE is false, not E_NOT_SUPPORT
293 if (MyProp().GetBoolProp(KvDBProperties::MEMORY_MODE, false)) {
294 LOGE("[RdSingleVerNaturalStore][Export] errCode is E_NOT_SUPPORT");
295 return -E_NOT_SUPPORT;
296 }
297
298 // MEMORY_MODE is READ_ONLY_MODE is true, not E_NOT_SUPPORT
299 if (MyProp().GetBoolProp(KvDBProperties::READ_ONLY_MODE, true)) {
300 LOGE("Not support export when cacheDB existed! state = [%d]", storageEngine_->GetEngineState());
301 return -E_READ_ONLY;
302 }
303
304 // get store path
305 OpenDbProperties optionTemp = storageEngine_->GetOption();
306 storePath = optionTemp.uri;
307 if (storePath.empty()) {
308 return -E_INVALID_ARGS;
309 }
310
311 return E_OK;
312 }
313
Import(const std::string & filePath,const CipherPassword & passwd)314 int RdSingleVerNaturalStore::Import(const std::string &filePath, const CipherPassword &passwd)
315 {
316 int errCode = E_OK;
317 std::string storePath;
318
319 errCode = PreCheckRdImport(storePath);
320 if (errCode != E_OK) {
321 LOGE("[RdSingleVerNaturalStore][PreCheckRdImport] is failed: %d", errCode);
322 return errCode;
323 }
324
325 uint8_t *decryptedKey = const_cast<uint8_t*>(passwd.GetData());
326 uint32_t decryptedKeyLen = (uint32_t)passwd.GetSize();
327
328 // try to disable
329 errCode = storageEngine_->TryToDisable(false, OperatePerm::IMPORT_MONOPOLIZE_PERM);
330 if (errCode != E_OK) {
331 LOGE("TryToDisable is not %d", errCode);
332 return errCode;
333 }
334
335 errCode = storageEngine_->TryToDisable(true, OperatePerm::IMPORT_MONOPOLIZE_PERM);
336 if (errCode != E_OK) {
337 LOGE("[Import] Failed to disable the database: %d", errCode);
338 AbortHandleAndWaitWriteHandle();
339 return errCode;
340 }
341
342 if (storageEngine_->GetEngineState() != EngineState::MAINDB) {
343 LOGE("Not support import when cacheDB existed! state = [%d]", storageEngine_->GetEngineState());
344 errCode = (storageEngine_->GetEngineState() == EngineState::CACHEDB) ? -E_NOT_SUPPORT : -E_BUSY;
345 AbortHandleAndWaitWriteHandle();
346 return errCode;
347 }
348
349 // close all grd handle
350 storageEngine_->CloseAllExecutor();
351
352 errCode = RdRestore(storePath.c_str(), filePath.c_str(), decryptedKey, decryptedKeyLen);
353 if (errCode != E_OK) {
354 AbortHandleAndWaitWriteHandle();
355 return errCode;
356 }
357
358 errCode = storageEngine_->InitAllReadWriteExecutor();
359 if (errCode != E_OK) {
360 LOGD("InitAllReadWriteExecutor is failed! errCode = [%d]", errCode);
361 return errCode;
362 }
363 storageEngine_->Enable(OperatePerm::IMPORT_MONOPOLIZE_PERM);
364 return errCode;
365 }
366
AbortHandleAndWaitWriteHandle() const367 void RdSingleVerNaturalStore::AbortHandleAndWaitWriteHandle() const
368 {
369 storageEngine_->Enable(OperatePerm::IMPORT_MONOPOLIZE_PERM);
370 storageEngine_->WaitWriteHandleIdle();
371 }
372
GetHandle(bool isWrite,int & errCode,OperatePerm perm) const373 RdSingleVerStorageExecutor *RdSingleVerNaturalStore::GetHandle(bool isWrite, int &errCode,
374 OperatePerm perm) const
375 {
376 engineMutex_.lock_shared();
377 if (storageEngine_ == nullptr) {
378 errCode = -E_INVALID_DB;
379 engineMutex_.unlock_shared(); // unlock when get handle failed.
380 return nullptr;
381 }
382 auto handle = storageEngine_->FindExecutor(isWrite, perm, errCode);
383 if (handle == nullptr) {
384 LOGD("Find null storage engine");
385 engineMutex_.unlock_shared(); // unlock when get handle failed.
386 }
387 return static_cast<RdSingleVerStorageExecutor *>(handle);
388 }
389
GetSchemaInfo() const390 SchemaObject RdSingleVerNaturalStore::GetSchemaInfo() const
391 {
392 return MyProp().GetSchema();
393 }
394
CheckCompatible(const std::string & schema,uint8_t type) const395 bool RdSingleVerNaturalStore::CheckCompatible(const std::string &schema, uint8_t type) const
396 {
397 return true;
398 }
399
GetCurrentTimestamp()400 Timestamp RdSingleVerNaturalStore::GetCurrentTimestamp()
401 {
402 return 0;
403 }
404
GetSchemaObject() const405 SchemaObject RdSingleVerNaturalStore::GetSchemaObject() const
406 {
407 return MyProp().GetSchema();
408 }
409
GetSchemaObjectConstRef() const410 const SchemaObject &RdSingleVerNaturalStore::GetSchemaObjectConstRef() const
411 {
412 return MyProp().GetSchemaConstRef();
413 }
414
GetDbProperties() const415 const KvDBProperties &RdSingleVerNaturalStore::GetDbProperties() const
416 {
417 return GetMyProperties();
418 }
419
GetKvDBSize(const KvDBProperties & properties,uint64_t & size) const420 int RdSingleVerNaturalStore::GetKvDBSize(const KvDBProperties &properties, uint64_t &size) const
421 {
422 return -E_NOT_SUPPORT;
423 }
424
GetDbPropertyForUpdate()425 KvDBProperties &RdSingleVerNaturalStore::GetDbPropertyForUpdate()
426 {
427 return MyProp();
428 }
429
InitDatabaseContext(const KvDBProperties & kvDBProp)430 int RdSingleVerNaturalStore::InitDatabaseContext(const KvDBProperties &kvDBProp)
431 {
432 OpenDbProperties option;
433 InitDataBaseOption(kvDBProp, option);
434
435 StorageEngineAttr poolSize = {1, 1, 1, 16}; // at most 1 write 16 read.
436
437 storageEngine_->SetNotifiedCallback(
438 [&](int eventType, KvDBCommitNotifyFilterAbleData *committedData) {
439 auto commitData = static_cast<SingleVerNaturalStoreCommitNotifyData *>(committedData);
440 this->CommitAndReleaseNotifyData(commitData, true, eventType);
441 }
442 );
443
444 std::string identifier = kvDBProp.GetStringProp(KvDBProperties::IDENTIFIER_DATA, "");
445 int errCode = storageEngine_->InitRdStorageEngine(poolSize, option, identifier);
446 if (errCode != E_OK) {
447 LOGE("Init the rd storage engine failed:%d", errCode);
448 }
449 return errCode;
450 }
451
RegisterLifeCycleCallback(const DatabaseLifeCycleNotifier & notifier)452 int RdSingleVerNaturalStore::RegisterLifeCycleCallback(const DatabaseLifeCycleNotifier ¬ifier)
453 {
454 return -E_NOT_SUPPORT;
455 }
456
SetAutoLifeCycleTime(uint32_t time)457 int RdSingleVerNaturalStore::SetAutoLifeCycleTime(uint32_t time)
458 {
459 return -E_NOT_SUPPORT;
460 }
461
IsDataMigrating() const462 bool RdSingleVerNaturalStore::IsDataMigrating() const
463 {
464 return false;
465 }
466
TriggerToMigrateData() const467 int RdSingleVerNaturalStore::TriggerToMigrateData() const
468 {
469 return -E_NOT_SUPPORT;
470 }
471
CheckReadDataControlled() const472 int RdSingleVerNaturalStore::CheckReadDataControlled() const
473 {
474 return E_OK;
475 }
476
IsCacheDBMode() const477 bool RdSingleVerNaturalStore::IsCacheDBMode() const
478 {
479 return false;
480 }
481
IncreaseCacheRecordVersion() const482 void RdSingleVerNaturalStore::IncreaseCacheRecordVersion() const
483 {
484 return;
485 }
486
GetCacheRecordVersion() const487 uint64_t RdSingleVerNaturalStore::GetCacheRecordVersion() const
488 {
489 return 0;
490 }
491
GetAndIncreaseCacheRecordVersion() const492 uint64_t RdSingleVerNaturalStore::GetAndIncreaseCacheRecordVersion() const
493 {
494 return 0;
495 }
496
CheckIntegrity() const497 int RdSingleVerNaturalStore::CheckIntegrity() const
498 {
499 return -E_NOT_SUPPORT;
500 }
501
GetCompressionAlgo(std::set<CompressAlgorithm> & algorithmSet) const502 int RdSingleVerNaturalStore::GetCompressionAlgo(std::set<CompressAlgorithm> &algorithmSet) const
503 {
504 return -E_NOT_SUPPORT;
505 }
506
SetSendDataInterceptor(const PushDataInterceptor & interceptor)507 void RdSingleVerNaturalStore::SetSendDataInterceptor(const PushDataInterceptor &interceptor)
508 {
509 return;
510 }
511
SetMaxLogSize(uint64_t limit)512 int RdSingleVerNaturalStore::SetMaxLogSize(uint64_t limit)
513 {
514 return -E_NOT_SUPPORT;
515 }
516
GetMaxLogSize() const517 uint64_t RdSingleVerNaturalStore::GetMaxLogSize() const
518 {
519 return 0;
520 }
521
Dump(int fd)522 void RdSingleVerNaturalStore::Dump(int fd)
523 {
524 return;
525 }
526
WakeUpSyncer()527 void RdSingleVerNaturalStore::WakeUpSyncer()
528 {
529 LOGD("Not support syncer yet");
530 return;
531 }
532
CommitNotify(int notifyEvent,KvDBCommitNotifyFilterAbleData * data)533 void RdSingleVerNaturalStore::CommitNotify(int notifyEvent, KvDBCommitNotifyFilterAbleData *data)
534 {
535 GenericKvDB::CommitNotify(notifyEvent, data);
536 }
537
InitDataBaseOption(const KvDBProperties & kvDBProp,OpenDbProperties & option)538 void RdSingleVerNaturalStore::InitDataBaseOption(const KvDBProperties &kvDBProp, OpenDbProperties &option)
539 {
540 option.uri = GetDatabasePath(kvDBProp);
541 option.subdir = GetSubDirPath(kvDBProp);
542 SecurityOption securityOpt;
543 if (RuntimeContext::GetInstance()->IsProcessSystemApiAdapterValid()) {
544 securityOpt.securityLabel = kvDBProp.GetSecLabel();
545 securityOpt.securityFlag = kvDBProp.GetSecFlag();
546 }
547 option.createIfNecessary = kvDBProp.GetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
548 option.createDirByStoreIdOnly = kvDBProp.GetBoolProp(KvDBProperties::CREATE_DIR_BY_STORE_ID_ONLY, false);
549 option.readOnly = kvDBProp.GetBoolProp(KvDBProperties::READ_ONLY_MODE, false);
550 option.isNeedIntegrityCheck = kvDBProp.GetBoolProp(KvDBProperties::CHECK_INTEGRITY, false);
551 option.isNeedRmCorruptedDb = kvDBProp.GetBoolProp(KvDBProperties::RM_CORRUPTED_DB, false);
552 bool isSharedMode = kvDBProp.GetBoolProp(KvDBProperties::SHARED_MODE, false);
553 option.isHashTable = (IndexType)kvDBProp.GetIntProp(KvDBProperties::INDEX_TYPE, BTREE) == HASH;
554 int pageSize = kvDBProp.GetIntProp(KvDBProperties::PAGE_SIZE, 32);
555 int cacheSize = kvDBProp.GetIntProp(KvDBProperties::CACHE_SIZE, 2048);
556
557 std::string config = "{";
558 config += InitRdConfig() + R"(, )";
559 config += option.isHashTable ?
560 R"("bufferPoolPolicy": "BUF_PRIORITY_NORMAL")" : R"("bufferPoolPolicy": "BUF_PRIORITY_INDEX")";
561 config += R"(, "pageSize":)" + std::to_string(pageSize) + R"(, )";
562 config += R"("bufferPoolSize":)" + std::to_string(cacheSize) + R"(, )";
563 config += R"("redoPubBufSize":)" + std::to_string(cacheSize) + R"(, )";
564 config += isSharedMode ? R"("sharedModeEnable": 1)" : R"("sharedModeEnable": 0)";
565 config += "}";
566 option.rdConfig = config;
567 }
568
SetReceiveDataInterceptor(const DataInterceptor & interceptor)569 void RdSingleVerNaturalStore::SetReceiveDataInterceptor(const DataInterceptor &interceptor)
570 {
571 }
572 } // namespace DistributedDB
573