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_manager.h"
17
18 #include <thread>
19
20 #include "auto_launch.h"
21 #include "db_common.h"
22 #include "db_dfx_adapter.h"
23 #include "db_errno.h"
24 #include "cloud/cloud_db_constant.h"
25 #include "cloud/cloud_storage_utils.h"
26 #include "kv_store_errno.h"
27 #include "log_print.h"
28 #include "param_check_utils.h"
29 #include "platform_specific.h"
30 #include "query_sync_object.h"
31 #include "relational_store_changed_data_impl.h"
32 #include "relational_store_delegate_impl.h"
33 #include "relational_store_instance.h"
34 #include "runtime_config.h"
35 #include "runtime_context.h"
36
37 namespace DistributedDB {
38 namespace {
39 const int GET_CONNECT_RETRY = 3;
40 const int RETRY_GET_CONN_INTER = 30;
41 }
42
RelationalStoreManager(const std::string & appId,const std::string & userId,int32_t instanceId)43 RelationalStoreManager::RelationalStoreManager(const std::string &appId, const std::string &userId, int32_t instanceId)
44 : appId_(appId),
45 userId_(userId),
46 instanceId_(instanceId)
47 {}
48
RelationalStoreManager(const std::string & appId,const std::string & userId,const std::string & subUser,int32_t instanceId)49 RelationalStoreManager::RelationalStoreManager(const std::string &appId, const std::string &userId,
50 const std::string &subUser, int32_t instanceId)
51 : appId_(appId),
52 userId_(userId),
53 subUser_(subUser),
54 instanceId_(instanceId)
55 {}
56
GetOneConnectionWithRetry(const RelationalDBProperties & properties,int & errCode)57 static RelationalStoreConnection *GetOneConnectionWithRetry(const RelationalDBProperties &properties, int &errCode)
58 {
59 for (int i = 0; i < GET_CONNECT_RETRY; i++) {
60 auto conn = RelationalStoreInstance::GetDatabaseConnection(properties, errCode);
61 if (conn != nullptr) {
62 return conn;
63 }
64 if (errCode == -E_STALE) {
65 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_GET_CONN_INTER));
66 } else {
67 return nullptr;
68 }
69 }
70 return nullptr;
71 }
72
PreCheckOpenStore(const std::string & path,const std::string & storeId,RelationalStoreDelegate * & delegate,std::string & canonicalDir)73 bool RelationalStoreManager::PreCheckOpenStore(const std::string &path, const std::string &storeId,
74 RelationalStoreDelegate *&delegate, std::string &canonicalDir)
75 {
76 if (delegate != nullptr) {
77 LOGE("[RelationalStoreMgr] Invalid delegate!");
78 return false;
79 }
80
81 if (!ParamCheckUtils::CheckDataDir(path, canonicalDir)) {
82 return false;
83 }
84
85 if (!ParamCheckUtils::CheckStoreParameter({userId_, appId_, storeId}, false, subUser_, true) || path.empty()) {
86 return false;
87 }
88
89 return true;
90 }
91
OpenStore(const std::string & path,const std::string & storeId,const RelationalStoreDelegate::Option & option,RelationalStoreDelegate * & delegate)92 DB_API DBStatus RelationalStoreManager::OpenStore(const std::string &path, const std::string &storeId,
93 const RelationalStoreDelegate::Option &option, RelationalStoreDelegate *&delegate)
94 {
95 std::string canonicalDir;
96 if (!PreCheckOpenStore(path, storeId, delegate, canonicalDir)) {
97 return INVALID_ARGS;
98 }
99
100 RelationalDBProperties properties;
101 properties.SetStringProp(RelationalDBProperties::DATA_DIR, canonicalDir);
102 properties.SetIdentifier(userId_, appId_, storeId, subUser_, instanceId_);
103 properties.SetBoolProp(RelationalDBProperties::SYNC_DUAL_TUPLE_MODE, option.syncDualTupleMode);
104 if (option.isEncryptedDb) {
105 if (!ParamCheckUtils::CheckEncryptedParameter(option.cipher, option.passwd) || option.iterateTimes == 0) {
106 return INVALID_ARGS;
107 }
108 properties.SetCipherArgs(option.cipher, option.passwd, option.iterateTimes);
109 }
110
111 int errCode = E_OK;
112 auto *conn = GetOneConnectionWithRetry(properties, errCode);
113 if (conn == nullptr) {
114 return TransferDBErrno(errCode);
115 }
116
117 delegate = new (std::nothrow) RelationalStoreDelegateImpl(conn, path);
118 if (delegate == nullptr) {
119 conn->Close();
120 return DB_ERROR;
121 }
122
123 if (option.observer == nullptr) {
124 return OK;
125 }
126 DBStatus status = delegate->RegisterObserver(option.observer);
127 if (status != OK) {
128 LOGE("register observer failed when open store: %d", status);
129 conn->Close();
130 }
131 return status;
132 }
133
CloseStore(RelationalStoreDelegate * store)134 DBStatus RelationalStoreManager::CloseStore(RelationalStoreDelegate *store)
135 {
136 if (store == nullptr) {
137 return INVALID_ARGS;
138 }
139
140 auto storeImpl = static_cast<RelationalStoreDelegateImpl *>(store);
141 DBStatus status = storeImpl->Close();
142 if (status == BUSY) {
143 LOGD("NbDelegateImpl is busy now.");
144 return BUSY;
145 }
146 storeImpl->SetReleaseFlag(true);
147 delete store;
148 store = nullptr;
149 return OK;
150 }
151
GetDistributedTableName(const std::string & device,const std::string & tableName)152 std::string RelationalStoreManager::GetDistributedTableName(const std::string &device, const std::string &tableName)
153 {
154 if ((!RuntimeContext::GetInstance()->ExistTranslateDevIdCallback() && device.empty()) || tableName.empty()) {
155 return {};
156 }
157 return DBCommon::GetDistributedTableName(device, tableName);
158 }
159
GetDistributedLogTableName(const std::string & tableName)160 DB_API std::string RelationalStoreManager::GetDistributedLogTableName(const std::string &tableName)
161 {
162 return DBCommon::GetLogTableName(tableName);
163 }
164
GetCollateTypeByName(const std::map<std::string,CollateType> & collateTypeMap,const std::string & name,CollateType & collateType)165 static int GetCollateTypeByName(const std::map<std::string, CollateType> &collateTypeMap,
166 const std::string &name, CollateType &collateType)
167 {
168 auto it = collateTypeMap.find(name);
169 if (it == collateTypeMap.end()) {
170 LOGW("collate map doesn't contain primary key we need");
171 collateType = CollateType::COLLATE_NONE;
172 return E_OK;
173 }
174 if (static_cast<uint32_t>(it->second) >= static_cast<uint32_t>(CollateType::COLLATE_BUTT)) {
175 LOGE("collate type is invalid");
176 return -E_INVALID_ARGS;
177 }
178 collateType = it->second;
179 return E_OK;
180 }
181
CalcPrimaryKeyHash(const std::map<std::string,Type> & primaryKey,const std::map<std::string,CollateType> & collateTypeMap)182 DB_API std::vector<uint8_t> RelationalStoreManager::CalcPrimaryKeyHash(const std::map<std::string, Type> &primaryKey,
183 const std::map<std::string, CollateType> &collateTypeMap)
184 {
185 std::vector<uint8_t> result;
186 if (primaryKey.empty()) {
187 LOGW("primaryKey is empty");
188 return result;
189 }
190 int errCode = E_OK;
191 CollateType collateType = CollateType::COLLATE_NONE;
192 if (primaryKey.size() == 1) {
193 auto iter = primaryKey.begin();
194 Field field = {iter->first, static_cast<int32_t>(iter->second.index()), true, false};
195 if (GetCollateTypeByName(collateTypeMap, iter->first, collateType) != E_OK) {
196 return result;
197 }
198 errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, collateType, result);
199 if (errCode != E_OK) {
200 // never happen
201 LOGE("calc hash fail when there is one primary key errCode = %d", errCode);
202 }
203 } else {
204 std::vector<uint8_t> tempRes;
205 std::map<std::string, Type> pkOrderByUpperName;
206 for (const auto &item : primaryKey) { // we sort by upper case name in log table when calculate hash
207 pkOrderByUpperName[DBCommon::ToUpperCase(item.first)] = item.second;
208 }
209
210 for (const auto &item : pkOrderByUpperName) {
211 std::vector<uint8_t> temp;
212 Field field = {DBCommon::ToLowerCase(item.first), static_cast<int32_t>(item.second.index()), true, false};
213 if (GetCollateTypeByName(collateTypeMap, DBCommon::ToLowerCase(item.first), collateType) != E_OK) {
214 return result;
215 }
216 errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, collateType, temp);
217 if (errCode != E_OK) {
218 // never happen
219 LOGE("calc hash fail when there is more than one primary key errCode = %d", errCode);
220 return result;
221 }
222 tempRes.insert(tempRes.end(), temp.begin(), temp.end());
223 }
224 errCode = DBCommon::CalcValueHash(tempRes, result);
225 if (errCode != E_OK) {
226 LOGE("calc hash fail when calc the composite primary key errCode = %d", errCode);
227 }
228 }
229 return result;
230 }
231
SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback & callback)232 void RelationalStoreManager::SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback &callback)
233 {
234 RuntimeContext::GetInstance()->SetAutoLaunchRequestCallback(callback, DBTypeInner::DB_RELATION);
235 }
236
GetRelationalStoreIdentifier(const std::string & userId,const std::string & appId,const std::string & storeId,bool syncDualTupleMode)237 std::string RelationalStoreManager::GetRelationalStoreIdentifier(const std::string &userId, const std::string &appId,
238 const std::string &storeId, bool syncDualTupleMode)
239 {
240 return RuntimeConfig::GetStoreIdentifier(userId, appId, storeId, syncDualTupleMode);
241 }
242
ParserQueryNodes(const Bytes & queryBytes,DBStatus & status)243 std::vector<QueryNode> RelationalStoreManager::ParserQueryNodes(const Bytes &queryBytes,
244 DBStatus &status)
245 {
246 std::vector<QueryNode> res;
247 status = TransferDBErrno(QuerySyncObject::ParserQueryNodes(queryBytes, res));
248 return res;
249 }
250 } // namespace DistributedDB
251 #endif
252