1 /*
2  * Copyright (c) 2021 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 
16 #include "kvdb_manager.h"
17 #include "log_print.h"
18 #include "db_common.h"
19 #include "db_dfx_adapter.h"
20 #include "runtime_context.h"
21 #include "schema_object.h"
22 #include "default_factory.h"
23 #include "generic_kvdb.h"
24 #include "db_constant.h"
25 #include "res_finalizer.h"
26 
27 namespace DistributedDB {
28 const std::string KvDBManager::PROCESS_LABEL_CONNECTOR = "-";
29 std::atomic<KvDBManager *> KvDBManager::instance_{nullptr};
30 std::mutex KvDBManager::kvDBLock_;
31 std::mutex KvDBManager::instanceLock_;
32 std::map<std::string, OS::FileHandle *> KvDBManager::locks_;
33 std::mutex KvDBManager::fileHandleMutex_;
34 
35 namespace {
36     DefaultFactory g_defaultFactory;
37 
38     static const KvDBType g_dbTypeArr[] = {
39 #ifndef OMIT_MULTI_VER
40         LOCAL_KVDB_SQLITE,
41 #endif // OMIT_MULTI_VER
42         SINGER_VER_KVDB_SQLITE,
43 #ifndef OMIT_MULTI_VER
44         MULTI_VER_KVDB_SQLITE,
45 #endif // OMIT_MULTI_VER
46         SINGLE_VER_KVDB_RD
47     };
48 
CreateDataBaseInstance(const KvDBProperties & property,IKvDB * & kvDB)49     int CreateDataBaseInstance(const KvDBProperties &property, IKvDB *&kvDB)
50     {
51         IKvDBFactory *factory = IKvDBFactory::GetCurrent();
52         if (factory == nullptr) {
53             return -E_OUT_OF_MEMORY;
54         }
55         int errCode = E_OK;
56         int databaseType = property.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE_SQLITE);
57         if (databaseType == KvDBProperties::LOCAL_TYPE_SQLITE) {
58 #ifndef OMIT_MULTI_VER
59             kvDB = factory->CreateKvDb(LOCAL_KVDB_SQLITE, errCode);
60             if (kvDB != nullptr) {
61                 kvDB->EnableAutonomicUpgrade();
62             }
63 #else
64             return -E_NOT_SUPPORT;
65 #endif // OMIT_MULTI_VER
66         } else if (databaseType == KvDBProperties::SINGLE_VER_TYPE_SQLITE) {
67             kvDB = factory->CreateKvDb(SINGER_VER_KVDB_SQLITE, errCode);
68         } else if (databaseType == KvDBProperties::SINGLE_VER_TYPE_RD_KERNAL) {
69             kvDB = factory->CreateKvDb(SINGLE_VER_KVDB_RD, errCode);
70         } else {
71 #ifndef OMIT_MULTI_VER
72             kvDB = factory->CreateKvDb(MULTI_VER_KVDB_SQLITE, errCode);
73 #else
74             return -E_NOT_SUPPORT;
75 #endif // OMIT_MULTI_VER
76         }
77         return errCode;
78     }
79 
CreateRemoveStateFlagFile(const KvDBProperties & properties)80     int CreateRemoveStateFlagFile(const KvDBProperties &properties)
81     {
82         std::string dataDir = properties.GetStringProp(KvDBProperties::DATA_DIR, "");
83         std::string identifier = properties.GetStringProp(KvDBProperties::IDENTIFIER_DATA, "");
84         std::string identifierName = DBCommon::TransferStringToHex(identifier);
85         std::string storeDir = dataDir + "/" + identifierName + DBConstant::DELETE_KVSTORE_REMOVING;
86         if (OS::CheckPathExistence(storeDir)) {
87             return E_OK;
88         }
89         // create the pre flag file.
90         int errCode = OS::CreateFileByFileName(storeDir);
91         if (errCode != E_OK) {
92             LOGE("Create remove state flag file failed:%d.", errCode);
93         }
94         return errCode;
95     }
96 }
97 
CheckRemoveStateAndRetry(const KvDBProperties & property)98 int KvDBManager::CheckRemoveStateAndRetry(const KvDBProperties &property)
99 {
100     std::string dataDir = property.GetStringProp(KvDBProperties::DATA_DIR, "");
101     std::string identifier = property.GetStringProp(KvDBProperties::IDENTIFIER_DATA, "");
102     std::string identifierName = DBCommon::TransferStringToHex(identifier);
103     std::string storeDir = dataDir + "/" + identifierName + DBConstant::DELETE_KVSTORE_REMOVING;
104 
105     if (OS::CheckPathExistence(storeDir)) {
106         KvDBManager::ExecuteRemoveDatabase(property);
107     }
108     // Re-detection deleted had been finish
109     if (OS::CheckPathExistence(storeDir)) {
110         LOGD("Deletekvstore unfinished, can not create new same identifier kvstore!");
111         return -E_REMOVE_FILE;
112     }
113     return E_OK;
114 }
115 
ExecuteRemoveDatabase(const KvDBProperties & properties)116 int KvDBManager::ExecuteRemoveDatabase(const KvDBProperties &properties)
117 {
118     int errCode = CheckDatabaseFileStatus(properties);
119     if (errCode != E_OK) {
120         return errCode;
121     }
122     IKvDBFactory *factory = IKvDBFactory::GetCurrent();
123     if (factory == nullptr) {
124         return -E_INVALID_DB;
125     }
126 
127     errCode = CreateRemoveStateFlagFile(properties);
128     if (errCode != E_OK) {
129         LOGE("create ctrl file failed:%d.", errCode);
130         return errCode;
131     }
132 
133     errCode = -E_NOT_FOUND;
134     for (KvDBType kvDbType : g_dbTypeArr) {
135         int innerErrCode = E_OK;
136         IKvDB *kvdb = factory->CreateKvDb(kvDbType, innerErrCode);
137         if (innerErrCode != E_OK) {
138             return innerErrCode;
139         }
140         innerErrCode = kvdb->RemoveKvDB(properties);
141         RefObject::DecObjRef(kvdb);
142         if (innerErrCode != -E_NOT_FOUND) {
143             if (innerErrCode != E_OK) {
144                 return innerErrCode;
145             }
146             errCode = E_OK;
147         }
148     }
149 
150     if (errCode == -E_NOT_FOUND) {
151         LOGE("DataBase file Not exist! return NOT_FOUND.");
152     }
153 
154     RemoveDBDirectory(properties);
155     return errCode;
156 }
157 
RemoveDBDirectory(const KvDBProperties & properties)158 void KvDBManager::RemoveDBDirectory(const KvDBProperties &properties)
159 {
160     std::string dataDir = properties.GetStringProp(KvDBProperties::DATA_DIR, "");
161     std::string identifier = properties.GetStringProp(KvDBProperties::IDENTIFIER_DATA, "");
162     std::string identifierName = DBCommon::TransferStringToHex(identifier);
163     std::string storeDir = dataDir + "/" + identifierName;
164     std::string removingFlag = dataDir + "/" + identifierName + DBConstant::DELETE_KVSTORE_REMOVING;
165     (void)OS::RemoveDBDirectory(storeDir);
166 
167     std::string storeId = properties.GetStringProp(KvDBProperties::STORE_ID, "");
168     identifier = DBCommon::TransferHashString(storeId);
169     identifierName = DBCommon::TransferStringToHex(identifier);
170     storeDir = dataDir + "/" + identifierName;
171     (void)OS::RemoveDBDirectory(storeDir);
172 
173     (void)OS::RemoveFile(removingFlag);
174 }
175 
176 // Used to open a kvdb with the given property
OpenDatabase(const KvDBProperties & property,int & errCode)177 IKvDB *KvDBManager::OpenDatabase(const KvDBProperties &property, int &errCode)
178 {
179     KvDBManager *manager = GetInstance();
180     if (manager == nullptr) {
181         errCode = -E_OUT_OF_MEMORY;
182         return nullptr;
183     }
184     return manager->GetDataBase(property, errCode, true);
185 }
186 
EnterDBOpenCloseProcess(const std::string & identifier)187 void KvDBManager::EnterDBOpenCloseProcess(const std::string &identifier)
188 {
189     std::unique_lock<std::mutex> lock(kvDBOpenMutex_);
190     kvDBOpenCondition_.wait(lock, [this, &identifier]() {
191         return this->kvDBOpenSet_.count(identifier) == 0;
192     });
193     (void)kvDBOpenSet_.insert(identifier);
194 }
195 
ExitDBOpenCloseProcess(const std::string & identifier)196 void KvDBManager::ExitDBOpenCloseProcess(const std::string &identifier)
197 {
198     std::unique_lock<std::mutex> lock(kvDBOpenMutex_);
199     (void)kvDBOpenSet_.erase(identifier);
200     kvDBOpenCondition_.notify_all();
201 }
202 
203 // one time 100ms
204 // In order to prevent long-term blocking of the process, a retry method is used
205 // The dimensions of the lock by appid-userid-storeid
TryLockDB(const KvDBProperties & kvDBProp,int retryTimes)206 int KvDBManager::TryLockDB(const KvDBProperties &kvDBProp, int retryTimes)
207 {
208     std::string dataDir = kvDBProp.GetStringProp(KvDBProperties::DATA_DIR, "");
209     bool isMemoryDb = kvDBProp.GetBoolProp(KvDBProperties::MEMORY_MODE, false);
210     std::string id = KvDBManager::GenerateKvDBIdentifier(kvDBProp);
211     if (dataDir.back() != '/') {
212         dataDir += "/";
213     }
214 
215     if (isMemoryDb) {
216         LOGI("MemoryDb not need lock!");
217         return E_OK;
218     }
219 
220     {
221         std::lock_guard<std::mutex> autoLock(fileHandleMutex_);
222         if (locks_.count(id) != 0) {
223             LOGI("db has been locked!");
224             return E_OK;
225         }
226     }
227 
228     std::string hexHashId = DBCommon::TransferStringToHex((id));
229     OS::FileHandle *handle = nullptr;
230     int errCode = OS::OpenFile(dataDir + hexHashId + DBConstant::DB_LOCK_POSTFIX, handle);
231     if (errCode != E_OK) {
232         LOGE("Open lock file fail errCode = [%d], errno:%d", errCode, errno);
233         return errCode;
234     }
235 
236     while (retryTimes-- > 0) {
237         errCode = OS::FileLock(handle, false); // not block process
238         if (errCode == E_OK) {
239             LOGI("[%s]locked!", STR_MASK(DBCommon::TransferStringToHex(KvDBManager::GenerateKvDBIdentifier(kvDBProp))));
240             std::lock_guard<std::mutex> autoLock(fileHandleMutex_);
241             locks_[id] = handle;
242             return errCode;
243         } else if (errCode == -E_BUSY) {
244             LOGD("DB already held by process lock!");
245             std::this_thread::sleep_for(std::chrono::milliseconds(100)); // wait for 100ms
246             continue;
247         } else {
248             LOGE("Try lock db failed, errCode = [%d] errno:%d", errCode, errno);
249             OS::CloseFile(handle);
250             return errCode;
251         }
252     }
253     OS::CloseFile(handle);
254     return -E_BUSY;
255 }
256 
UnlockDB(const KvDBProperties & kvDBProp)257 int KvDBManager::UnlockDB(const KvDBProperties &kvDBProp)
258 {
259     bool isMemoryDb = kvDBProp.GetBoolProp(KvDBProperties::MEMORY_MODE, false);
260     if (isMemoryDb) {
261         return E_OK;
262     }
263     std::string identifierDir = KvDBManager::GenerateKvDBIdentifier(kvDBProp);
264     OS::FileHandle *handle = nullptr;
265     {
266         std::lock_guard<std::mutex> autoLock(fileHandleMutex_);
267         if (locks_.count(identifierDir) == 0) {
268             return E_OK;
269         }
270         handle = locks_[identifierDir];
271     }
272     int errCode = OS::FileUnlock(handle);
273     if (errCode != E_OK) {
274         LOGE("DB unlocked! errCode = [%d]", errCode);
275         return errCode;
276     }
277     errCode = OS::CloseFile(handle);
278     if (errCode != E_OK) {
279         LOGE("DB closed! errCode = [%d]", errCode);
280         return errCode;
281     }
282     std::lock_guard<std::mutex> autoLock(fileHandleMutex_);
283     locks_.erase(identifierDir);
284     return E_OK;
285 }
286 
CheckOpenDBOptionWithCached(const KvDBProperties & properties,IKvDB * kvDB)287 bool KvDBManager::CheckOpenDBOptionWithCached(const KvDBProperties &properties, IKvDB *kvDB)
288 {
289     bool isMemoryDb = properties.GetBoolProp(KvDBProperties::MEMORY_MODE, false);
290     std::string canonicalDir = properties.GetStringProp(KvDBProperties::DATA_DIR, "");
291     if (!isMemoryDb && (canonicalDir.empty() || canonicalDir != kvDB->GetStorePath())) {
292         LOGE("Failed to check store path, the input path does not match with cached store.");
293         return false;
294     }
295 
296     bool compressOnSyncUser = properties.GetBoolProp(KvDBProperties::COMPRESS_ON_SYNC, false);
297     bool compressOnSyncGet = kvDB->GetMyProperties().GetBoolProp(KvDBProperties::COMPRESS_ON_SYNC, false);
298     if (compressOnSyncUser != compressOnSyncGet) {
299         LOGE("Failed to check compress option, the input %d not match with cached %d.", compressOnSyncUser,
300             compressOnSyncGet);
301         return false;
302     }
303     if (compressOnSyncUser) {
304         int compressRateUser = properties.GetIntProp(KvDBProperties::COMPRESSION_RATE, 0);
305         int compressRateGet = kvDB->GetMyProperties().GetIntProp(KvDBProperties::COMPRESSION_RATE, 0);
306         if (compressRateUser != compressRateGet) {
307             LOGE("Failed to check compress rate, the input %d not match with cached %d.", compressRateUser,
308                 compressRateGet);
309             return false;
310         }
311     }
312     return true;
313 }
314 
315 // Used to open a kvdb with the given property
GetDatabaseConnection(const KvDBProperties & properties,int & errCode,bool isNeedIfOpened)316 IKvDBConnection *KvDBManager::GetDatabaseConnection(const KvDBProperties &properties, int &errCode,
317     bool isNeedIfOpened)
318 {
319     auto manager = GetInstance();
320     if (manager == nullptr) {
321         errCode = -E_OUT_OF_MEMORY;
322         return nullptr;
323     }
324     IKvDBConnection *connection = nullptr;
325     std::string identifier = properties.GetStringProp(KvDBProperties::IDENTIFIER_DATA, "");
326     LOGD("Begin to get [%s] database connection.", STR_MASK(DBCommon::TransferStringToHex(identifier)));
327     manager->EnterDBOpenCloseProcess(identifier);
328 
329     IKvDB *kvDB = manager->GetDataBase(properties, errCode, isNeedIfOpened);
330     if (kvDB == nullptr) {
331         if (isNeedIfOpened) {
332             DBDfxAdapter::ReportBehavior(
333                 {__func__, Scene::OPEN_CONN, State::END, Stage::GET_DB, StageResult::FAIL, errCode});
334             LOGE("Failed to open the db:%d", errCode);
335         }
336     } else {
337         if (!CheckOpenDBOptionWithCached(properties, kvDB)) {
338             LOGE("Failed to check open db option");
339             errCode = -E_INVALID_ARGS;
340             DBDfxAdapter::ReportBehavior(
341                 {__func__, Scene::OPEN_CONN, State::END, Stage::CHECK_OPT, StageResult::FAIL, errCode});
342         } else {
343             connection = kvDB->GetDBConnection(errCode);
344             if (connection == nullptr) { // not kill kvdb, Other operations like import may be used concurrently
345                 DBDfxAdapter::ReportBehavior(
346                     {__func__, Scene::OPEN_CONN, State::END, Stage::GET_DB_CONN, StageResult::FAIL, errCode});
347                 LOGE("Failed to get the db connect for delegate:%d", errCode);
348             }
349         }
350         RefObject::DecObjRef(kvDB); // restore the reference increased by the cache.
351         kvDB = nullptr;
352     }
353 
354     manager->ExitDBOpenCloseProcess(identifier);
355     if (errCode == -E_INVALID_PASSWD_OR_CORRUPTED_DB) {
356         std::string appId = properties.GetStringProp(KvDBProperties::APP_ID, "");
357         std::string userId = properties.GetStringProp(KvDBProperties::USER_ID, "");
358         std::string storeId = properties.GetStringProp(KvDBProperties::STORE_ID, "");
359         manager->DataBaseCorruptNotify(appId, userId, storeId);
360         LOGE("Database [%s] is corrupted or authentication failed:%d",
361             STR_MASK(DBCommon::TransferStringToHex(identifier)), errCode);
362     }
363 
364     return connection;
365 }
366 
ReleaseDatabaseConnection(IKvDBConnection * connection)367 int KvDBManager::ReleaseDatabaseConnection(IKvDBConnection *connection)
368 {
369     if (connection == nullptr) {
370         return -E_INVALID_DB;
371     }
372 
373     std::string identifier = connection->GetIdentifier();
374     auto manager = GetInstance();
375     if (manager == nullptr) {
376         return -E_OUT_OF_MEMORY;
377     }
378     manager->EnterDBOpenCloseProcess(identifier);
379     int errCode = connection->Close();
380     manager->ExitDBOpenCloseProcess(identifier);
381 
382     if (errCode != E_OK) {
383         LOGE("[KvDBManager] Release db connection:%d", errCode);
384     }
385     LOGI("[Connection] db[%s] conn Close", STR_MASK(DBCommon::TransferStringToHex(identifier)));
386     return errCode;
387 }
388 
CreateDataBase(const KvDBProperties & property,int & errCode)389 IKvDB *KvDBManager::CreateDataBase(const KvDBProperties &property, int &errCode)
390 {
391     IKvDB *kvDB = OpenNewDatabase(property, errCode);
392     int databaseType = property.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE_SQLITE);
393     if (kvDB == nullptr) {
394         LOGE("Failed to open the new database.");
395         bool isReadOnly = property.GetBoolProp(KvDBProperties::READ_ONLY_MODE, false);
396         if (errCode == -E_INVALID_PASSWD_OR_CORRUPTED_DB &&
397             databaseType == KvDBProperties::SINGLE_VER_TYPE_RD_KERNAL && isReadOnly) {
398             LOGI("readOnly process can not remove database");
399             return kvDB;
400         }
401         if (errCode == -E_INVALID_PASSWD_OR_CORRUPTED_DB &&
402             property.GetBoolProp(KvDBProperties::RM_CORRUPTED_DB, false)) {
403             LOGI("Remove the corrupted database while open");
404             ExecuteRemoveDatabase(property);
405             kvDB = OpenNewDatabase(property, errCode);
406             if (kvDB != nullptr) {
407                 kvDB->MarkRebuild();
408             }
409         }
410         return kvDB;
411     }
412     bool rebuild = false;
413     if (property.GetBoolProp(KvDBProperties::CHECK_INTEGRITY, false) &&
414         databaseType != KvDBProperties::SINGLE_VER_TYPE_RD_KERNAL) {
415         int integrityStatus = kvDB->CheckIntegrity();
416         if (integrityStatus == -E_INVALID_PASSWD_OR_CORRUPTED_DB) {
417             RemoveKvDBFromCache(kvDB);
418             RefObject::KillAndDecObjRef(kvDB);
419             kvDB = nullptr;
420             errCode = -E_INVALID_PASSWD_OR_CORRUPTED_DB;
421             if (property.GetBoolProp(KvDBProperties::RM_CORRUPTED_DB, false)) {
422                 LOGI("Remove the corrupted database for the integrity check");
423                 ExecuteRemoveDatabase(property);
424                 kvDB = OpenNewDatabase(property, errCode);
425                 rebuild = true;
426             }
427         }
428     }
429     if (kvDB != nullptr && rebuild) {
430         kvDB->MarkRebuild();
431     }
432     return kvDB;
433 }
434 
GetDataBase(const KvDBProperties & property,int & errCode,bool isNeedIfOpened)435 IKvDB *KvDBManager::GetDataBase(const KvDBProperties &property, int &errCode, bool isNeedIfOpened)
436 {
437     bool isMemoryDb = property.GetBoolProp(KvDBProperties::MEMORY_MODE, false);
438     bool isCreateNecessary = property.GetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
439     IKvDB *kvDB = FindAndGetKvDBFromCache(property, errCode);
440     if (kvDB != nullptr) {
441         if (!isNeedIfOpened) {
442             LOGI("[KvDBManager] Database has already been opened.");
443             RefObject::DecObjRef(kvDB);
444             errCode = -E_ALREADY_OPENED;
445             kvDB = nullptr;
446         }
447         return kvDB;
448     }
449     if (isMemoryDb && !isCreateNecessary) {
450         LOGI("IsCreateNecessary is false, Not need create database");
451         return nullptr;
452     }
453     if (errCode != -E_NOT_FOUND) {
454         return nullptr;
455     }
456 
457     // Taking into account the compatibility of version delivery,
458     // temporarily use isNeedIntegrityCheck this field to avoid multi-process concurrency
459     bool isNeedIntegrityCheck = property.GetBoolProp(KvDBProperties::CHECK_INTEGRITY, false);
460     int databaseType = property.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE_SQLITE);
461     if (isNeedIntegrityCheck || databaseType == KvDBProperties::SINGLE_VER_TYPE_RD_KERNAL) {
462         LOGI("db need lock, need check integrity is [%d]", isNeedIntegrityCheck);
463         errCode = KvDBManager::TryLockDB(property, 10);  // default 10 times retry
464         if (errCode != E_OK) {
465             return nullptr;
466         }
467     }
468 
469     ResFinalizer unlock([&errCode, &property, &kvDB]() {
470         int err = KvDBManager::UnlockDB(property);
471         if (err != E_OK) {
472             LOGE("GetDataBase unlock failed! err [%d] errCode [%d]", err, errCode);
473             errCode = err;
474             RefObject::KillAndDecObjRef(kvDB);
475             kvDB = nullptr;
476         }
477     });
478 
479     kvDB = CreateDataBase(property, errCode);
480     if (errCode != E_OK) {
481         LOGE("Create database failed, errCode = [%d]", errCode);
482     }
483     return kvDB;
484 }
485 
IsOpenMemoryDb(const KvDBProperties & properties,const std::map<std::string,IKvDB * > & cache) const486 bool KvDBManager::IsOpenMemoryDb(const KvDBProperties &properties, const std::map<std::string, IKvDB *> &cache) const
487 {
488     std::string identifier = GenerateKvDBIdentifier(properties);
489     auto iter = cache.find(identifier);
490     if (iter != cache.end()) {
491         IKvDB *kvDB = iter->second;
492         if (kvDB != nullptr && kvDB->GetMyProperties().GetBoolProp(KvDBProperties::MEMORY_MODE, false)) {
493             return true;
494         }
495     }
496     return false;
497 }
498 
499 // used to get kvdb size with the given property.
CalculateKvStoreSize(const KvDBProperties & properties,uint64_t & size)500 int KvDBManager::CalculateKvStoreSize(const KvDBProperties &properties, uint64_t &size)
501 {
502     KvDBManager *manager = GetInstance();
503     if (manager == nullptr) {
504         LOGE("Failed to get KvDBManager instance!");
505         return -E_OUT_OF_MEMORY;
506     }
507 
508     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
509     if (manager->IsOpenMemoryDb(properties, manager->singleVerNaturalStores_)) {
510         size = 0;
511         return E_OK;
512     }
513 
514     IKvDBFactory *factory = IKvDBFactory::GetCurrent();
515     if (factory == nullptr) {
516         return -E_INVALID_DB;
517     }
518 
519     uint64_t totalSize = 0;
520     for (KvDBType kvDbType : g_dbTypeArr) {
521         if (kvDbType == SINGLE_VER_KVDB_RD) {
522             continue;
523         }
524         int innerErrCode = E_OK;
525         IKvDB *kvDB = factory->CreateKvDb(kvDbType, innerErrCode);
526         if (innerErrCode != E_OK) {
527             return innerErrCode;
528         }
529         uint64_t dbSize = 0;
530         innerErrCode = kvDB->GetKvDBSize(properties, dbSize);
531         RefObject::DecObjRef(kvDB);
532         if (innerErrCode != E_OK && innerErrCode != -E_NOT_FOUND) {
533             return innerErrCode;
534         }
535         LOGD("DB type [%u], size[%" PRIu64 "]", static_cast<unsigned>(kvDbType), dbSize);
536         totalSize = totalSize + dbSize;
537     }
538     // This represent Db file size(Unit is byte), It is small than max size(max uint64_t represent 2^64B)
539     if (totalSize != 0ULL) {
540         size = totalSize;
541         return E_OK;
542     }
543     return -E_NOT_FOUND;
544 }
545 
GetKvDBFromCacheByIdentify(const std::string & identifier,const std::map<std::string,IKvDB * > & cache) const546 IKvDB *KvDBManager::GetKvDBFromCacheByIdentify(const std::string &identifier,
547     const std::map<std::string, IKvDB *> &cache) const
548 {
549     auto iter = cache.find(identifier);
550     if (iter != cache.end()) {
551         IKvDB *kvDB = iter->second;
552         if (kvDB == nullptr) {
553             LOGE("Kvstore cache is nullptr, there may be a logic error");
554             return nullptr;
555         }
556         return kvDB;
557     }
558     return nullptr;
559 }
560 
CheckDatabaseFileStatus(const KvDBProperties & properties)561 int KvDBManager::CheckDatabaseFileStatus(const KvDBProperties &properties)
562 {
563     KvDBManager *manager = GetInstance();
564     if (manager == nullptr) {
565         LOGE("Failed to get KvDBManager instance!");
566         return -E_OUT_OF_MEMORY;
567     }
568 
569     std::string identifier = GenerateKvDBIdentifier(properties);
570     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
571     IKvDB *kvDB = manager->GetKvDBFromCacheByIdentify(identifier, manager->localKvDBs_);
572     if (kvDB != nullptr) {
573         LOGE("The local KvDB is busy!");
574         return -E_BUSY;
575     }
576 
577     kvDB = manager->GetKvDBFromCacheByIdentify(identifier, manager->multiVerNaturalStores_);
578     if (kvDB != nullptr) {
579         LOGE("The multi ver natural store is busy!");
580         return -E_BUSY;
581     }
582 
583     kvDB = manager->GetKvDBFromCacheByIdentify(identifier, manager->singleVerNaturalStores_);
584     if (kvDB != nullptr) {
585         LOGE("The single version natural store is busy!");
586         return -E_BUSY;
587     }
588     return E_OK;
589 }
590 
OpenNewDatabase(const KvDBProperties & property,int & errCode)591 IKvDB *KvDBManager::OpenNewDatabase(const KvDBProperties &property, int &errCode)
592 {
593     errCode = CheckRemoveStateAndRetry(property);
594     if (errCode != E_OK) {
595         LOGE("Failed to open IKvDB! Because delete kvstore unfinished err:%d", errCode);
596         return nullptr;
597     }
598 
599     IKvDB *kvDB = nullptr;
600     errCode = CreateDataBaseInstance(property, kvDB);
601     if (errCode != E_OK) {
602         LOGE("Failed to get IKvDB! err:%d", errCode);
603         return nullptr;
604     }
605 
606     errCode = kvDB->Open(property);
607     if (errCode != E_OK) {
608         LOGE("Failed to open IKvDB! err:%d", errCode);
609         RefObject::KillAndDecObjRef(kvDB);
610         kvDB = nullptr;
611         return nullptr;
612     }
613     auto identifier = DBCommon::TransferStringToHex(property.GetStringProp(KvDBProperties::IDENTIFIER_DATA, ""));
614     auto dbDir = property.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
615     LOGI("Database identifier:%.6s, dir:%.6s", identifier.c_str(), dbDir.c_str());
616     // Register the callback function when the database is closed, triggered when kvdb free
617     kvDB->OnClose([kvDB, this]() {
618         this->RemoveKvDBFromCache(kvDB);
619     });
620 
621     IKvDB *kvDBTmp = SaveKvDBToCache(kvDB);
622     if (kvDBTmp != kvDB) {
623         RefObject::KillAndDecObjRef(kvDB);
624         kvDB = nullptr;
625         return kvDBTmp;
626     }
627     return kvDB;
628 }
629 
630 // used to delete a kvdb with the given property.
631 // return BUSY if in use
RemoveDatabase(const KvDBProperties & properties)632 int KvDBManager::RemoveDatabase(const KvDBProperties &properties)
633 {
634     KvDBManager *manager = GetInstance();
635     if (manager == nullptr) {
636         LOGE("Failed to get kvdb manager while removing the db!");
637         return -E_OUT_OF_MEMORY;
638     }
639     std::string identifier = GenerateKvDBIdentifier(properties);
640     manager->EnterDBOpenCloseProcess(identifier);
641 
642     LOGI("KvDBManager::RemoveDatabase begin try lock the database!");
643     std::string lockFile = properties.GetStringProp(KvDBProperties::DATA_DIR, "") + "/" +
644         DBCommon::TransferStringToHex(identifier) + DBConstant::DB_LOCK_POSTFIX;
645     int errCode = E_OK;
646     if (OS::CheckPathExistence(lockFile)) {
647         errCode = KvDBManager::TryLockDB(properties, 10); // default 10 times retry
648         if (errCode != E_OK) {
649             manager->ExitDBOpenCloseProcess(identifier);
650             return errCode;
651         }
652     }
653 
654     errCode = ExecuteRemoveDatabase(properties);
655     if (errCode != E_OK) {
656         LOGE("[KvDBManager] Remove database failed:%d", errCode);
657     }
658     int err = KvDBManager::UnlockDB(properties); // unlock and delete lock file before delete dir
659     if (err != E_OK) {
660         LOGE("[KvDBManager][RemoveDatabase] UnlockDB failed:%d, errno:%d", err, errno);
661         errCode = err;
662     }
663 
664     manager->ExitDBOpenCloseProcess(identifier);
665     return errCode;
666 }
667 
GenerateKvDBIdentifier(const KvDBProperties & property)668 std::string KvDBManager::GenerateKvDBIdentifier(const KvDBProperties &property)
669 {
670     return property.GetStringProp(KvDBProperties::IDENTIFIER_DATA, "");
671 }
672 
GetInstance()673 KvDBManager *KvDBManager::GetInstance()
674 {
675     // For Double-Checked Locking, we need check instance_ twice
676     if (instance_ == nullptr) {
677         std::lock_guard<std::mutex> lockGuard(instanceLock_);
678         if (instance_ == nullptr) {
679             instance_ = new (std::nothrow) KvDBManager();
680             if (instance_ == nullptr) {
681                 LOGE("failed to new KvDBManager!");
682                 return nullptr;
683             }
684         }
685     }
686     if (IKvDBFactory::GetCurrent() == nullptr) {
687         IKvDBFactory::Register(&g_defaultFactory);
688     }
689     return instance_;
690 }
691 
692 // Save to IKvDB to the global map
SaveKvDBToCache(IKvDB * kvDB)693 IKvDB *KvDBManager::SaveKvDBToCache(IKvDB *kvDB)
694 {
695     if (kvDB == nullptr) {
696         return nullptr;
697     }
698 
699     {
700         KvDBProperties properties = kvDB->GetMyProperties();
701         std::string identifier = GenerateKvDBIdentifier(properties);
702         int databaseType = properties.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE_SQLITE);
703         std::lock_guard<std::mutex> lockGuard(kvDBLock_);
704         int errCode = E_OK;
705         if (databaseType == KvDBProperties::LOCAL_TYPE_SQLITE) {
706             IKvDB *kvDBTmp = FindKvDBFromCache(properties, localKvDBs_, true, errCode);
707             if (kvDBTmp != nullptr) {
708                 kvDBTmp->IncObjRef(kvDBTmp);
709                 return kvDBTmp;
710             }
711             localKvDBs_.insert(std::pair<std::string, IKvDB *>(identifier, kvDB));
712         } else if (databaseType == KvDBProperties::MULTI_VER_TYPE_SQLITE) {
713             IKvDB *kvDBTmp = FindKvDBFromCache(properties, multiVerNaturalStores_, true, errCode);
714             if (kvDBTmp != nullptr) {
715                 kvDBTmp->IncObjRef(kvDBTmp);
716                 return kvDBTmp;
717             }
718             kvDB->WakeUpSyncer();
719             multiVerNaturalStores_.insert(std::pair<std::string, IKvDB *>(identifier, kvDB));
720         } else {
721             IKvDB *kvDBTmp = FindKvDBFromCache(properties, singleVerNaturalStores_, true, errCode);
722             if (kvDBTmp != nullptr) {
723                 kvDBTmp->IncObjRef(kvDBTmp);
724                 return kvDBTmp;
725             }
726             kvDB->WakeUpSyncer();
727             singleVerNaturalStores_.insert(std::pair<std::string, IKvDB *>(identifier, kvDB));
728         }
729     }
730     kvDB->SetCorruptHandler([kvDB, this]() {
731         std::string appId = kvDB->GetMyProperties().GetStringProp(KvDBProperties::APP_ID, "");
732         std::string userId = kvDB->GetMyProperties().GetStringProp(KvDBProperties::USER_ID, "");
733         std::string storeId = kvDB->GetMyProperties().GetStringProp(KvDBProperties::STORE_ID, "");
734         this->DataBaseCorruptNotifyAsync(appId, userId, storeId);
735     });
736     return kvDB;
737 }
738 
739 // Save to IKvDB to the global map
RemoveKvDBFromCache(const IKvDB * kvDB)740 void KvDBManager::RemoveKvDBFromCache(const IKvDB *kvDB)
741 {
742     const KvDBProperties &properties = kvDB->GetMyProperties();
743     std::string identifier = GenerateKvDBIdentifier(properties);
744     int databaseType = properties.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE_SQLITE);
745     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
746     if (databaseType == KvDBProperties::LOCAL_TYPE_SQLITE) {
747         localKvDBs_.erase(identifier);
748     } else if (databaseType == KvDBProperties::MULTI_VER_TYPE_SQLITE) {
749         multiVerNaturalStores_.erase(identifier);
750     } else {
751         singleVerNaturalStores_.erase(identifier);
752     }
753 }
754 
755 // Get IKvDB from the global map
FindAndGetKvDBFromCache(const KvDBProperties & properties,int & errCode) const756 IKvDB *KvDBManager::FindAndGetKvDBFromCache(const KvDBProperties &properties, int &errCode) const
757 {
758     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
759 
760     IKvDB *kvDB = FindKvDBFromCache(properties, localKvDBs_, true, errCode);
761     if (kvDB != nullptr) {
762         kvDB->IncObjRef(kvDB);
763         return kvDB;
764     }
765     if (errCode != -E_NOT_FOUND) {
766         return nullptr;
767     }
768 
769     kvDB = FindKvDBFromCache(properties, multiVerNaturalStores_, true, errCode);
770     if (kvDB != nullptr) {
771         kvDB->IncObjRef(kvDB);
772         return kvDB;
773     }
774     if (errCode != -E_NOT_FOUND) {
775         return nullptr;
776     }
777 
778     kvDB = FindKvDBFromCache(properties, singleVerNaturalStores_, true, errCode);
779     if (kvDB != nullptr) {
780         kvDB->IncObjRef(kvDB);
781         return kvDB;
782     }
783     return nullptr;
784 }
785 
FindKvDBFromCache(const KvDBProperties & properties,const std::map<std::string,IKvDB * > & cache,bool isNeedCheckPasswd,int & errCode) const786 IKvDB *KvDBManager::FindKvDBFromCache(const KvDBProperties &properties, const std::map<std::string, IKvDB *> &cache,
787     bool isNeedCheckPasswd, int &errCode) const
788 {
789     errCode = E_OK;
790     std::string identifier = GenerateKvDBIdentifier(properties);
791     auto iter = cache.find(identifier);
792     if (iter != cache.end()) {
793         IKvDB *kvDB = iter->second;
794         if (kvDB == nullptr) {
795             LOGE("KVSTORE cache is nullptr, there may be a logic error");
796             errCode = -E_INTERNAL_ERROR;
797             return nullptr;
798         }
799         int newType = properties.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE_SQLITE);
800         int oldType = kvDB->GetMyProperties().GetIntProp(KvDBProperties::DATABASE_TYPE,
801             KvDBProperties::LOCAL_TYPE_SQLITE);
802         if (oldType == newType) {
803             errCode = CheckKvDBProperties(kvDB, properties, isNeedCheckPasswd);
804             if (errCode != E_OK) {
805                 return nullptr;
806             }
807             return kvDB;
808         } else {
809             errCode = -E_INVALID_ARGS;
810             LOGE("Database [%s] type not matched, type [%d] vs [%d]",
811                 STR_MASK(DBCommon::TransferStringToHex(identifier)), newType, oldType);
812             return nullptr;
813         }
814     }
815 
816     errCode = -E_NOT_FOUND;
817     return nullptr;
818 }
819 
SetProcessLabel(const std::string & appId,const std::string & userId)820 int KvDBManager::SetProcessLabel(const std::string &appId, const std::string &userId)
821 {
822     std::string label = appId + PROCESS_LABEL_CONNECTOR + userId;
823     RuntimeContext::GetInstance()->SetProcessLabel(label);
824     return E_OK;
825 }
826 
RestoreSyncableKvStore()827 void KvDBManager::RestoreSyncableKvStore()
828 {
829     KvDBManager *manager = GetInstance();
830     if (manager == nullptr) {
831         return;
832     }
833 
834     manager->RestoreSyncerOfAllKvStore();
835 }
836 
SetDatabaseCorruptionHandler(const KvStoreCorruptionHandler & handler)837 void KvDBManager::SetDatabaseCorruptionHandler(const KvStoreCorruptionHandler &handler)
838 {
839     KvDBManager *manager = GetInstance();
840     if (manager == nullptr) {
841         return;
842     }
843 
844     manager->SetAllDatabaseCorruptionHander(handler);
845 }
846 
SetAllDatabaseCorruptionHander(const KvStoreCorruptionHandler & handler)847 void KvDBManager::SetAllDatabaseCorruptionHander(const KvStoreCorruptionHandler &handler)
848 {
849     {
850         std::lock_guard<std::mutex> lock(corruptMutex_);
851         corruptHandler_ = handler;
852     }
853     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
854     SetCorruptHandlerForDatabases(singleVerNaturalStores_);
855     SetCorruptHandlerForDatabases(localKvDBs_);
856     SetCorruptHandlerForDatabases(multiVerNaturalStores_);
857 }
858 
DataBaseCorruptNotify(const std::string & appId,const std::string & userId,const std::string & storeId)859 void KvDBManager::DataBaseCorruptNotify(const std::string &appId, const std::string &userId, const std::string &storeId)
860 {
861     KvStoreCorruptionHandler corruptHandler = nullptr;
862     {
863         std::lock_guard<std::mutex> lock(corruptMutex_);
864         corruptHandler = corruptHandler_;
865     }
866 
867     if (corruptHandler != nullptr) {
868         corruptHandler(appId, userId, storeId);
869     }
870 }
871 
DataBaseCorruptNotifyAsync(const std::string & appId,const std::string & userId,const std::string & storeId)872 void KvDBManager::DataBaseCorruptNotifyAsync(const std::string &appId, const std::string &userId,
873     const std::string &storeId)
874 {
875     int errCode = RuntimeContext::GetInstance()->ScheduleTask(
876         [this, appId, userId, storeId] { DataBaseCorruptNotify(appId, userId, storeId); });
877     if (errCode != E_OK) {
878         LOGE("[KvDBManager][CorruptNotify] ScheduleTask failed, errCode = %d.", errCode);
879         return;
880     }
881 }
882 
SetCorruptHandlerForDatabases(const std::map<std::string,IKvDB * > & dbMaps)883 void KvDBManager::SetCorruptHandlerForDatabases(const std::map<std::string, IKvDB *> &dbMaps)
884 {
885     for (const auto &item : dbMaps) {
886         if (item.second == nullptr) {
887             continue;
888         }
889 
890         item.second->SetCorruptHandler([item, this]() {
891             std::string appId = item.second->GetMyProperties().GetStringProp(KvDBProperties::APP_ID, "");
892             std::string userId = item.second->GetMyProperties().GetStringProp(KvDBProperties::USER_ID, "");
893             std::string storeId = item.second->GetMyProperties().GetStringProp(KvDBProperties::STORE_ID, "");
894             this->DataBaseCorruptNotifyAsync(appId, userId, storeId);
895         });
896     }
897 }
898 
RestoreSyncerOfAllKvStore()899 void KvDBManager::RestoreSyncerOfAllKvStore()
900 {
901     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
902     for (auto &item : singleVerNaturalStores_) {
903         if (item.second != nullptr) {
904             item.second->WakeUpSyncer();
905         }
906     }
907 
908     for (auto &item : multiVerNaturalStores_) {
909         if (item.second != nullptr) {
910             item.second->WakeUpSyncer();
911         }
912     }
913 }
914 
CompareSchemaObject(const SchemaObject & newSchema,const SchemaObject & oldSchema)915 bool KvDBManager::CompareSchemaObject(const SchemaObject &newSchema, const SchemaObject &oldSchema)
916 {
917     if (!newSchema.IsSchemaValid() && !oldSchema.IsSchemaValid()) { // LCOV_EXCL_BR_LINE
918         return true;
919     }
920     if (!newSchema.IsSchemaValid() || !oldSchema.IsSchemaValid()) { // LCOV_EXCL_BR_LINE
921         return false;
922     }
923     return (oldSchema.CompareAgainstSchemaObject(newSchema) == -E_SCHEMA_EQUAL_EXACTLY);
924 }
925 
CheckSchema(const IKvDB * kvDB,const KvDBProperties & properties)926 int KvDBManager::CheckSchema(const IKvDB *kvDB, const KvDBProperties &properties)
927 {
928     if (kvDB == nullptr) {
929         LOGE("input kvdb is nullptr");
930         return -E_INVALID_ARGS;
931     }
932     SchemaObject inputSchema = properties.GetSchema();
933     SchemaObject cacheSchema = kvDB->GetMyProperties().GetSchema();
934     bool isFirstOpenReadOnly =
935         kvDB->GetMyProperties().GetBoolProp(KvDBProperties::FIRST_OPEN_IS_READ_ONLY, false);
936     if (isFirstOpenReadOnly) {
937         if (inputSchema.IsSchemaValid()) {
938             LOGE("schema not matched");
939             return -E_SCHEMA_MISMATCH;
940         } else {
941             return E_OK;
942         }
943     }
944     if (!CompareSchemaObject(inputSchema, cacheSchema)) {
945         LOGE("schema not matched");
946         return -E_SCHEMA_MISMATCH;
947     }
948     return E_OK;
949 }
950 
951 namespace {
CheckSecOptions(const KvDBProperties & input,const KvDBProperties & existed)952     bool CheckSecOptions(const KvDBProperties &input, const KvDBProperties &existed)
953     {
954         // If any has NO_SET, skip the check and using the existed option.
955         if (input.GetIntProp(KvDBProperties::SECURITY_LABEL, 0) != 0 &&
956             existed.GetIntProp(KvDBProperties::SECURITY_LABEL, 0) != 0) {
957             if (existed.GetIntProp(KvDBProperties::SECURITY_LABEL, 0) !=
958                 input.GetIntProp(KvDBProperties::SECURITY_LABEL, 0)) {
959                 LOGE("Security label mismatch: existed[%d] vs input[%d]",
960                     existed.GetIntProp(KvDBProperties::SECURITY_LABEL, 0),
961                     input.GetIntProp(KvDBProperties::SECURITY_LABEL, 0));
962                 return false;
963             }
964             if (existed.GetIntProp(KvDBProperties::SECURITY_FLAG, 0) !=
965                 input.GetIntProp(KvDBProperties::SECURITY_FLAG, 0)) {
966                 LOGE("Security flag mismatch: existed[%d] vs input[%d]",
967                     existed.GetIntProp(KvDBProperties::SECURITY_FLAG, 0),
968                     input.GetIntProp(KvDBProperties::SECURITY_FLAG, 0));
969                 return false;
970             }
971         }
972         return true;
973     }
974 }
975 
CheckKvDBProperties(const IKvDB * kvDB,const KvDBProperties & properties,bool isNeedCheckPasswd) const976 int KvDBManager::CheckKvDBProperties(const IKvDB *kvDB, const KvDBProperties &properties,
977     bool isNeedCheckPasswd) const
978 {
979     // if get from cache is not memoryDb, do not support open or create memory DB
980     bool isMemoryDb = properties.GetBoolProp(KvDBProperties::MEMORY_MODE, false);
981     if (isMemoryDb != kvDB->GetMyProperties().GetBoolProp(KvDBProperties::MEMORY_MODE, false)) { // LCOV_EXCL_BR_LINE
982         LOGE("Already open same id physical DB, so do not support open or create memory DB");
983         return -E_INVALID_ARGS;
984     }
985 
986     if (kvDB->GetMyProperties().GetBoolProp(KvDBProperties::CREATE_DIR_BY_STORE_ID_ONLY, false) !=
987         properties.GetBoolProp(KvDBProperties::CREATE_DIR_BY_STORE_ID_ONLY, false)) { // LCOV_EXCL_BR_LINE
988         LOGE("Different ways to create dir.");
989         return -E_INVALID_ARGS;
990     }
991 
992     if (kvDB->GetMyProperties().GetIntProp(KvDBProperties::CONFLICT_RESOLVE_POLICY, 0) !=
993         properties.GetIntProp(KvDBProperties::CONFLICT_RESOLVE_POLICY, 0)) { // LCOV_EXCL_BR_LINE
994         LOGE("Different conflict resolve policy.");
995         return -E_INVALID_ARGS;
996     }
997 
998     if (kvDB->GetMyProperties().GetBoolProp(KvDBProperties::SYNC_DUAL_TUPLE_MODE, false) !=
999         properties.GetBoolProp(KvDBProperties::SYNC_DUAL_TUPLE_MODE, false)) { // LCOV_EXCL_BR_LINE
1000             LOGE("Different dual tuple sync mode");
1001             return -E_MODE_MISMATCH;
1002     }
1003 
1004     if (kvDB->GetMyProperties().GetBoolProp(KvDBProperties::LOCAL_ONLY, false) !=
1005         properties.GetBoolProp(KvDBProperties::LOCAL_ONLY, false)) { // LCOV_EXCL_BR_LINE
1006         LOGE("Different local only mode");
1007         return -E_INVALID_ARGS;
1008     }
1009 
1010     if (!CheckSecOptions(properties, kvDB->GetMyProperties())) { // LCOV_EXCL_BR_LINE
1011         return -E_INVALID_ARGS;
1012     }
1013 
1014     CipherType cacheType;
1015     CipherType inputType;
1016     CipherPassword cachePasswd;
1017     CipherPassword inputPasswd;
1018     kvDB->GetMyProperties().GetPassword(cacheType, cachePasswd);
1019     properties.GetPassword(inputType, inputPasswd);
1020     if (isNeedCheckPasswd && (cachePasswd != inputPasswd ||
1021         !DBCommon::IsSameCipher(cacheType, inputType))) { // LCOV_EXCL_BR_LINE
1022         LOGE("Identification not matched");
1023         return -E_INVALID_PASSWD_OR_CORRUPTED_DB;
1024     }
1025 
1026     return CheckSchema(kvDB, properties);
1027 }
1028 
1029 // Attention. After call FindKvDB and kvdb is not null, you need to call DecObjRef.
FindKvDB(const std::string & identifier) const1030 IKvDB* KvDBManager::FindKvDB(const std::string &identifier) const
1031 {
1032     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
1033     auto kvdb = singleVerNaturalStores_.find(identifier);
1034     if (kvdb != singleVerNaturalStores_.end()) {
1035         // Increase ref counter here.
1036         RefObject::IncObjRef(kvdb->second);
1037         return kvdb->second;
1038     }
1039     return nullptr;
1040 }
1041 
Dump(int fd)1042 void KvDBManager::Dump(int fd)
1043 {
1044     std::lock_guard<std::mutex> lockGuard(kvDBLock_);
1045     for (const auto &entry : singleVerNaturalStores_) {
1046         RefObject::IncObjRef(entry.second);
1047         entry.second->Dump(fd);
1048         RefObject::DecObjRef(entry.second);
1049     }
1050 }
1051 } // namespace DistributedDB
1052