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.SetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, static_cast<int>(option.tableMode));
103 properties.SetIdentifier(userId_, appId_, storeId, subUser_, instanceId_);
104 properties.SetBoolProp(RelationalDBProperties::SYNC_DUAL_TUPLE_MODE, option.syncDualTupleMode);
105 if (option.isEncryptedDb) {
106 if (!ParamCheckUtils::CheckEncryptedParameter(option.cipher, option.passwd) || option.iterateTimes == 0) {
107 return INVALID_ARGS;
108 }
109 properties.SetCipherArgs(option.cipher, option.passwd, option.iterateTimes);
110 }
111
112 int errCode = E_OK;
113 auto *conn = GetOneConnectionWithRetry(properties, errCode);
114 if (conn == nullptr) {
115 return TransferDBErrno(errCode);
116 }
117
118 delegate = new (std::nothrow) RelationalStoreDelegateImpl(conn, path);
119 if (delegate == nullptr) {
120 conn->Close();
121 return DB_ERROR;
122 }
123
124 if (option.observer == nullptr) {
125 return OK;
126 }
127 DBStatus status = delegate->RegisterObserver(option.observer);
128 if (status != OK) {
129 LOGE("register observer failed when open store: %d", status);
130 conn->Close();
131 }
132 return status;
133 }
134
CloseStore(RelationalStoreDelegate * store)135 DBStatus RelationalStoreManager::CloseStore(RelationalStoreDelegate *store)
136 {
137 if (store == nullptr) {
138 return INVALID_ARGS;
139 }
140
141 auto storeImpl = static_cast<RelationalStoreDelegateImpl *>(store);
142 DBStatus status = storeImpl->Close();
143 if (status == BUSY) {
144 LOGD("NbDelegateImpl is busy now.");
145 return BUSY;
146 }
147 storeImpl->SetReleaseFlag(true);
148 delete store;
149 store = nullptr;
150 return OK;
151 }
152
GetDistributedTableName(const std::string & device,const std::string & tableName)153 std::string RelationalStoreManager::GetDistributedTableName(const std::string &device, const std::string &tableName)
154 {
155 if ((!RuntimeContext::GetInstance()->ExistTranslateDevIdCallback() && device.empty()) || tableName.empty()) {
156 return {};
157 }
158 return DBCommon::GetDistributedTableName(device, tableName);
159 }
160
GetDistributedLogTableName(const std::string & tableName)161 DB_API std::string RelationalStoreManager::GetDistributedLogTableName(const std::string &tableName)
162 {
163 return DBCommon::GetLogTableName(tableName);
164 }
165
GetCollateTypeByName(const std::map<std::string,CollateType> & collateTypeMap,const std::string & name,CollateType & collateType)166 static int GetCollateTypeByName(const std::map<std::string, CollateType> &collateTypeMap,
167 const std::string &name, CollateType &collateType)
168 {
169 auto it = collateTypeMap.find(name);
170 if (it == collateTypeMap.end()) {
171 LOGW("collate map doesn't contain primary key we need");
172 collateType = CollateType::COLLATE_NONE;
173 return E_OK;
174 }
175 if (static_cast<uint32_t>(it->second) >= static_cast<uint32_t>(CollateType::COLLATE_BUTT)) {
176 LOGE("collate type is invalid");
177 return -E_INVALID_ARGS;
178 }
179 collateType = it->second;
180 return E_OK;
181 }
182
CalcPrimaryKeyHash(const std::map<std::string,Type> & primaryKey,const std::map<std::string,CollateType> & collateTypeMap)183 DB_API std::vector<uint8_t> RelationalStoreManager::CalcPrimaryKeyHash(const std::map<std::string, Type> &primaryKey,
184 const std::map<std::string, CollateType> &collateTypeMap)
185 {
186 std::vector<uint8_t> result;
187 if (primaryKey.empty()) {
188 LOGW("primaryKey is empty");
189 return result;
190 }
191 int errCode = E_OK;
192 CollateType collateType = CollateType::COLLATE_NONE;
193 if (primaryKey.size() == 1) {
194 auto iter = primaryKey.begin();
195 Field field = {iter->first, static_cast<int32_t>(iter->second.index()), true, false};
196 if (GetCollateTypeByName(collateTypeMap, iter->first, collateType) != E_OK) {
197 return result;
198 }
199 errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, collateType, result);
200 if (errCode != E_OK) {
201 // never happen
202 LOGE("calc hash fail when there is one primary key errCode = %d", errCode);
203 }
204 } else {
205 std::vector<uint8_t> tempRes;
206 std::map<std::string, Type> pkOrderByUpperName;
207 for (const auto &item : primaryKey) { // we sort by upper case name in log table when calculate hash
208 pkOrderByUpperName[DBCommon::ToUpperCase(item.first)] = item.second;
209 }
210
211 for (const auto &item : pkOrderByUpperName) {
212 std::vector<uint8_t> temp;
213 Field field = {DBCommon::ToLowerCase(item.first), static_cast<int32_t>(item.second.index()), true, false};
214 if (GetCollateTypeByName(collateTypeMap, DBCommon::ToLowerCase(item.first), collateType) != E_OK) {
215 return result;
216 }
217 errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, collateType, temp);
218 if (errCode != E_OK) {
219 // never happen
220 LOGE("calc hash fail when there is more than one primary key errCode = %d", errCode);
221 return result;
222 }
223 tempRes.insert(tempRes.end(), temp.begin(), temp.end());
224 }
225 errCode = DBCommon::CalcValueHash(tempRes, result);
226 if (errCode != E_OK) {
227 LOGE("calc hash fail when calc the composite primary key errCode = %d", errCode);
228 }
229 }
230 return result;
231 }
232
SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback & callback)233 void RelationalStoreManager::SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback &callback)
234 {
235 RuntimeContext::GetInstance()->SetAutoLaunchRequestCallback(callback, DBTypeInner::DB_RELATION);
236 }
237
GetRelationalStoreIdentifier(const std::string & userId,const std::string & appId,const std::string & storeId,bool syncDualTupleMode)238 std::string RelationalStoreManager::GetRelationalStoreIdentifier(const std::string &userId, const std::string &appId,
239 const std::string &storeId, bool syncDualTupleMode)
240 {
241 return RelationalStoreManager::GetRelationalStoreIdentifier(userId, "", appId, storeId, syncDualTupleMode);
242 }
243
GetRelationalStoreIdentifier(const std::string & userId,const std::string & subUserId,const std::string & appId,const std::string & storeId,bool syncDualTupleMode)244 std::string RelationalStoreManager::GetRelationalStoreIdentifier(const std::string &userId,
245 const std::string &subUserId, const std::string &appId, const std::string &storeId, bool syncDualTupleMode)
246 {
247 StoreInfo info;
248 info.storeId = storeId;
249 info.appId = appId;
250 info.userId = userId;
251 return DBCommon::GetStoreIdentifier(info, subUserId, syncDualTupleMode, true);
252 }
253
ParserQueryNodes(const Bytes & queryBytes,DBStatus & status)254 std::vector<QueryNode> RelationalStoreManager::ParserQueryNodes(const Bytes &queryBytes,
255 DBStatus &status)
256 {
257 std::vector<QueryNode> res;
258 status = TransferDBErrno(QuerySyncObject::ParserQueryNodes(queryBytes, res));
259 return res;
260 }
261 } // namespace DistributedDB
262 #endif
263