• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef RELATIONAL_STORE
16 #include "relational_store_instance.h"
17 
18 #include "db_common.h"
19 #include "db_dfx_adapter.h"
20 #include "db_errno.h"
21 #include "sqlite_relational_store.h"
22 #include "log_print.h"
23 
24 namespace DistributedDB {
25 RelationalStoreInstance *RelationalStoreInstance::instance_ = nullptr;
26 std::mutex RelationalStoreInstance::instanceLock_;
27 
28 static std::mutex storeLock_;
29 static std::map<std::string, IRelationalStore *> dbs_;
30 
RelationalStoreInstance()31 RelationalStoreInstance::RelationalStoreInstance()
32 {}
33 
GetInstance()34 RelationalStoreInstance *RelationalStoreInstance::GetInstance()
35 {
36     std::lock_guard<std::mutex> lockGuard(instanceLock_);
37     if (instance_ == nullptr) {
38         instance_ = new (std::nothrow) RelationalStoreInstance();
39         if (instance_ == nullptr) {
40             LOGE("failed to new RelationalStoreManager!");
41             return nullptr;
42         }
43     }
44     return instance_;
45 }
46 
ReleaseDataBaseConnection(RelationalStoreConnection * connection)47 int RelationalStoreInstance::ReleaseDataBaseConnection(RelationalStoreConnection *connection)
48 {
49     if (connection == nullptr) {
50         return -E_INVALID_DB;
51     }
52     auto manager = RelationalStoreInstance::GetInstance();
53     if (manager == nullptr) {
54         return -E_OUT_OF_MEMORY;
55     }
56     std::string identifier = connection->GetIdentifier();
57     manager->EnterDBOpenCloseProcess(identifier);
58     int errCode = connection->Close();
59     manager->ExitDBOpenCloseProcess(identifier);
60 
61     if (errCode != E_OK) {
62         LOGE("Release db connection failed. %d", errCode);
63     }
64     return errCode;
65 }
66 
GetFromCache(const RelationalDBProperties & properties,int & errCode)67 static IRelationalStore *GetFromCache(const RelationalDBProperties &properties, int &errCode)
68 {
69     errCode = E_OK;
70     std::string identifier = properties.GetStringProp(RelationalDBProperties::DATA_DIR, "");
71     std::lock_guard<std::mutex> lockGuard(storeLock_);
72     auto iter = dbs_.find(identifier);
73     if (iter == dbs_.end()) {
74         errCode = -E_NOT_FOUND;
75         return nullptr;
76     }
77 
78     auto *db = iter->second;
79     if (db == nullptr) {
80         LOGE("Store cache is nullptr, there may be a logic error");
81         errCode = -E_INTERNAL_ERROR;
82         return nullptr;
83     }
84     RefObject::IncObjRef(db);
85     return db;
86 }
87 
88 // Save to IKvDB to the global map
RemoveKvDBFromCache(const RelationalDBProperties & properties)89 void RelationalStoreInstance::RemoveKvDBFromCache(const RelationalDBProperties &properties)
90 {
91     std::string identifier = properties.GetStringProp(RelationalDBProperties::DATA_DIR, "");
92     std::lock_guard<std::mutex> lockGuard(storeLock_);
93     dbs_.erase(identifier);
94 }
95 
SaveRelationalDBToCache(IRelationalStore * store,const RelationalDBProperties & properties)96 void RelationalStoreInstance::SaveRelationalDBToCache(IRelationalStore *store, const RelationalDBProperties &properties)
97 {
98     std::string identifier = properties.GetStringProp(RelationalDBProperties::DATA_DIR, "");
99     std::lock_guard<std::mutex> lockGuard(storeLock_);
100     if (dbs_.count(identifier) == 0) {
101         dbs_.insert(std::pair<std::string, IRelationalStore *>(identifier, store));
102     }
103 }
104 
OpenDatabase(const RelationalDBProperties & properties,int & errCode)105 IRelationalStore *RelationalStoreInstance::OpenDatabase(const RelationalDBProperties &properties, int &errCode)
106 {
107     auto db = new (std::nothrow) SQLiteRelationalStore();
108     if (db == nullptr) {
109         errCode = -E_OUT_OF_MEMORY;
110         LOGE("Failed to get relational store! err:%d", errCode);
111         return nullptr;
112     }
113 
114     db->OnClose([this, properties]() {
115         LOGI("Remove from the cache");
116         this->RemoveKvDBFromCache(properties);
117     });
118 
119     errCode = db->Open(properties);
120     if (errCode != E_OK) {
121         LOGE("Failed to open db! err:%d", errCode);
122         RefObject::KillAndDecObjRef(db);
123         return nullptr;
124     }
125     db->WakeUpSyncer();
126 
127     SaveRelationalDBToCache(db, properties);
128     return db;
129 }
130 
GetDataBase(const RelationalDBProperties & properties,int & errCode,bool isNeedIfOpened)131 IRelationalStore *RelationalStoreInstance::GetDataBase(const RelationalDBProperties &properties, int &errCode,
132     bool isNeedIfOpened)
133 {
134     auto *db = GetFromCache(properties, errCode);
135 
136     if (db != nullptr && !isNeedIfOpened) {
137         RefObject::DecObjRef(db);
138         errCode = -E_ALREADY_OPENED;
139         LOGI("Database has already been opened.");
140         return nullptr;
141     } else if (db != nullptr) {
142         LOGD("Get db from cache.");
143         return db;
144     }
145 
146     // file lock
147     RelationalStoreInstance *manager = RelationalStoreInstance::GetInstance();
148     if (manager == nullptr) {
149         errCode = -E_OUT_OF_MEMORY;
150         return nullptr;
151     }
152 
153     db = manager->OpenDatabase(properties, errCode);
154     if (errCode != E_OK) {
155         LOGE("Create database failed, errCode = [%d]", errCode);
156     }
157     return db;
158 }
159 
160 namespace {
CheckCompatibility(const RelationalDBProperties & prop,const RelationalDBProperties & existedProp)161 int CheckCompatibility(const RelationalDBProperties &prop, const RelationalDBProperties &existedProp)
162 {
163     std::string canonicalDir = prop.GetStringProp(DBProperties::DATA_DIR, "");
164     if (canonicalDir.empty() || canonicalDir != existedProp.GetStringProp(DBProperties::DATA_DIR, "")) {
165         LOGE("Failed to check store path, the input path does not match with cached store.");
166         return -E_INVALID_ARGS;
167     }
168     if (prop.GetDistributedTableMode() != existedProp.GetDistributedTableMode()) {
169         LOGE("Failed to check table mode.");
170         return -E_INVALID_ARGS;
171     }
172 
173     if (prop.IsEncrypted() != existedProp.IsEncrypted()) {
174         LOGE("Failed to check cipher args.");
175         return -E_INVALID_PASSWD_OR_CORRUPTED_DB;
176     }
177     if (prop.IsEncrypted() &&
178         (prop.GetPasswd() != existedProp.GetPasswd() || prop.GetIterTimes() != existedProp.GetIterTimes() ||
179          !DBCommon::IsSameCipher(prop.GetCipherType(), existedProp.GetCipherType()))) {
180         LOGE("Failed to check cipher args.");
181         return -E_INVALID_PASSWD_OR_CORRUPTED_DB;
182     }
183 
184     if (prop.GetBoolProp(DBProperties::SYNC_DUAL_TUPLE_MODE, false) !=
185         existedProp.GetBoolProp(DBProperties::SYNC_DUAL_TUPLE_MODE, false)) {
186         LOGE("Failed to check dual tuple sync mode for rdb.");
187         return -E_MODE_MISMATCH;
188     }
189     bool compressOnSyncUser = prop.GetBoolProp(DBProperties::COMPRESS_ON_SYNC, false);
190     bool compressOnSyncGet = existedProp.GetBoolProp(DBProperties::COMPRESS_ON_SYNC, false);
191     if (compressOnSyncUser != compressOnSyncGet) {
192         LOGE("Failed to check compress option, the input %d not match with cached %d.", compressOnSyncUser,
193              compressOnSyncGet);
194         return -E_INVALID_ARGS;
195     }
196     if (compressOnSyncUser) {
197         int compressRateUser = prop.GetIntProp(DBProperties::COMPRESSION_RATE, 0);
198         int compressRateGet = existedProp.GetIntProp(DBProperties::COMPRESSION_RATE, 0);
199         if (compressRateUser != compressRateGet) {
200             LOGE("Failed to check compress rate, the input %d not match with cached %d.", compressRateUser,
201                 compressRateGet);
202             return -E_INVALID_ARGS;
203         }
204     }
205     return E_OK;
206 }
207 }
208 
GetDatabaseConnection(const RelationalDBProperties & properties,int & errCode,bool isNeedIfOpened)209 RelationalStoreConnection *RelationalStoreInstance::GetDatabaseConnection(const RelationalDBProperties &properties,
210     int &errCode, bool isNeedIfOpened)
211 {
212     std::string identifier = properties.GetStringProp(DBProperties::IDENTIFIER_DATA, "");
213     LOGD("Begin to get [%s] database connection.", STR_MASK(DBCommon::TransferStringToHex(identifier)));
214     RelationalStoreInstance *manager = RelationalStoreInstance::GetInstance();
215     if (manager == nullptr) {
216         errCode = -E_OUT_OF_MEMORY;
217         return nullptr;
218     }
219     manager->EnterDBOpenCloseProcess(properties.GetStringProp(DBProperties::IDENTIFIER_DATA, ""));
220     RelationalStoreConnection *connection = nullptr;
221     IRelationalStore *db = GetDataBase(properties, errCode, isNeedIfOpened);
222     if (db == nullptr) {
223         DBDfxAdapter::ReportBehavior(
224             {__func__, Scene::OPEN_CONN, State::BEGIN, Stage::GET_DB, StageResult::FAIL, errCode});
225         LOGE("Failed to open the db:%d", errCode);
226         goto END;
227     }
228 
229     errCode = CheckCompatibility(properties, db->GetProperties());
230     if (errCode != E_OK) {
231         DBDfxAdapter::ReportBehavior(
232             {__func__, Scene::OPEN_CONN, State::BEGIN, Stage::CHECK_OPT, StageResult::FAIL, errCode});
233         goto END;
234     }
235 
236     connection = db->GetDBConnection(errCode);
237     if (connection == nullptr) { // not kill db, Other operations like import may be used concurrently
238         DBDfxAdapter::ReportBehavior(
239             {__func__, Scene::OPEN_CONN, State::BEGIN, Stage::GET_DB_CONN, StageResult::FAIL, errCode});
240         LOGE("Failed to get the db connect for delegate:%d", errCode);
241     }
242 
243 END:
244     RefObject::DecObjRef(db); // restore the reference increased by the cache.
245     manager->ExitDBOpenCloseProcess(properties.GetStringProp(DBProperties::IDENTIFIER_DATA, ""));
246     return connection;
247 }
248 
EnterDBOpenCloseProcess(const std::string & identifier)249 void RelationalStoreInstance::EnterDBOpenCloseProcess(const std::string &identifier)
250 {
251     std::unique_lock<std::mutex> lock(relationalDBOpenMutex_);
252     relationalDBOpenCondition_.wait(lock, [this, &identifier]() {
253         return this->relationalDBOpenSet_.count(identifier) == 0;
254     });
255     (void)relationalDBOpenSet_.insert(identifier);
256 }
257 
ExitDBOpenCloseProcess(const std::string & identifier)258 void RelationalStoreInstance::ExitDBOpenCloseProcess(const std::string &identifier)
259 {
260     std::unique_lock<std::mutex> lock(relationalDBOpenMutex_);
261     (void)relationalDBOpenSet_.erase(identifier);
262     relationalDBOpenCondition_.notify_all();
263 }
264 
Dump(int fd)265 void RelationalStoreInstance::Dump(int fd)
266 {
267     std::lock_guard<std::mutex> autoLock(storeLock_);
268     for (const auto &entry : dbs_) {
269         RefObject::IncObjRef(entry.second);
270         entry.second->Dump(fd);
271         RefObject::DecObjRef(entry.second);
272     }
273 }
274 } // namespace DistributedDB
275 #endif