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