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