• 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_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