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