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