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 "cloud/cloud_db_constant.h"
22 #include "cloud/cloud_storage_utils.h"
23 #include "relational_store_instance.h"
24 #include "db_common.h"
25 #include "db_dfx_adapter.h"
26 #include "db_errno.h"
27 #include "kv_store_errno.h"
28 #include "log_print.h"
29 #include "param_check_utils.h"
30 #include "platform_specific.h"
31 #include "relational_store_changed_data_impl.h"
32 #include "relational_store_delegate_impl.h"
33 #include "runtime_config.h"
34 #include "runtime_context.h"
35
36 namespace DistributedDB {
37 namespace {
38 const int GET_CONNECT_RETRY = 3;
39 const int RETRY_GET_CONN_INTER = 30;
40 }
41
RelationalStoreManager(const std::string & appId,const std::string & userId,int32_t instanceId)42 RelationalStoreManager::RelationalStoreManager(const std::string &appId, const std::string &userId, int32_t instanceId)
43 : appId_(appId),
44 userId_(userId),
45 instanceId_(instanceId)
46 {}
47
GetOneConnectionWithRetry(const RelationalDBProperties & properties,int & errCode)48 static RelationalStoreConnection *GetOneConnectionWithRetry(const RelationalDBProperties &properties, int &errCode)
49 {
50 for (int i = 0; i < GET_CONNECT_RETRY; i++) {
51 auto conn = RelationalStoreInstance::GetDatabaseConnection(properties, errCode);
52 if (conn != nullptr) {
53 return conn;
54 }
55 if (errCode == -E_STALE) {
56 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_GET_CONN_INTER));
57 } else {
58 return nullptr;
59 }
60 }
61 return nullptr;
62 }
63
PreCheckOpenStore(const std::string & path,const std::string & storeId,RelationalStoreDelegate * & delegate,std::string & canonicalDir)64 bool RelationalStoreManager::PreCheckOpenStore(const std::string &path, const std::string &storeId,
65 RelationalStoreDelegate *&delegate, std::string &canonicalDir)
66 {
67 if (delegate != nullptr) {
68 LOGE("[RelationalStoreMgr] Invalid delegate!");
69 return false;
70 }
71
72 if (!ParamCheckUtils::CheckDataDir(path, canonicalDir)) {
73 return false;
74 }
75
76 if (!ParamCheckUtils::CheckStoreParameter(storeId, appId_, userId_) || path.empty()) {
77 return false;
78 }
79
80 return true;
81 }
82
OpenStore(const std::string & path,const std::string & storeId,const RelationalStoreDelegate::Option & option,RelationalStoreDelegate * & delegate)83 DB_API DBStatus RelationalStoreManager::OpenStore(const std::string &path, const std::string &storeId,
84 const RelationalStoreDelegate::Option &option, RelationalStoreDelegate *&delegate)
85 {
86 std::string canonicalDir;
87 if (!PreCheckOpenStore(path, storeId, delegate, canonicalDir)) {
88 return INVALID_ARGS;
89 }
90
91 RelationalDBProperties properties;
92 properties.SetStringProp(RelationalDBProperties::DATA_DIR, canonicalDir);
93 properties.SetIdentifier(userId_, appId_, storeId, instanceId_);
94 properties.SetBoolProp(RelationalDBProperties::SYNC_DUAL_TUPLE_MODE, option.syncDualTupleMode);
95 if (option.isEncryptedDb) {
96 if (!ParamCheckUtils::CheckEncryptedParameter(option.cipher, option.passwd) || option.iterateTimes == 0) {
97 return INVALID_ARGS;
98 }
99 properties.SetCipherArgs(option.cipher, option.passwd, option.iterateTimes);
100 }
101
102 int errCode = E_OK;
103 auto *conn = GetOneConnectionWithRetry(properties, errCode);
104 if (errCode == -E_INVALID_PASSWD_OR_CORRUPTED_DB) {
105 DBDfxAdapter::ReportFault( { DBDfxAdapter::EVENT_OPEN_DATABASE_FAILED, userId_, appId_, storeId, errCode } );
106 }
107 if (conn == nullptr) {
108 return TransferDBErrno(errCode);
109 }
110
111 delegate = new (std::nothrow) RelationalStoreDelegateImpl(conn, path);
112 if (delegate == nullptr) {
113 conn->Close();
114 return DB_ERROR;
115 }
116 return option.observer != nullptr ? delegate->RegisterObserver(option.observer) : OK;
117 }
118
CloseStore(RelationalStoreDelegate * store)119 DBStatus RelationalStoreManager::CloseStore(RelationalStoreDelegate *store)
120 {
121 if (store == nullptr) {
122 return INVALID_ARGS;
123 }
124
125 auto storeImpl = static_cast<RelationalStoreDelegateImpl *>(store);
126 DBStatus status = storeImpl->Close();
127 if (status == BUSY) {
128 LOGD("NbDelegateImpl is busy now.");
129 return BUSY;
130 }
131 storeImpl->SetReleaseFlag(true);
132 delete store;
133 store = nullptr;
134 return OK;
135 }
136
GetDistributedTableName(const std::string & device,const std::string & tableName)137 std::string RelationalStoreManager::GetDistributedTableName(const std::string &device, const std::string &tableName)
138 {
139 if ((!RuntimeContext::GetInstance()->ExistTranslateDevIdCallback() && device.empty()) || tableName.empty()) {
140 return {};
141 }
142 return DBCommon::GetDistributedTableName(device, tableName);
143 }
144
GetDistributedLogTableName(const std::string & tableName)145 DB_API std::string RelationalStoreManager::GetDistributedLogTableName(const std::string &tableName)
146 {
147 return DBCommon::GetLogTableName(tableName);
148 }
149
CalcPrimaryKeyHash(const std::map<std::string,Type> primaryKey)150 DB_API std::vector<uint8_t> RelationalStoreManager::CalcPrimaryKeyHash(const std::map<std::string, Type> primaryKey)
151 {
152 std::vector<uint8_t> result;
153 if (primaryKey.empty()) {
154 LOGW("primaryKey is empty");
155 return result;
156 }
157 int errCode = E_OK;
158 if (primaryKey.size() == 1) {
159 auto iter = primaryKey.begin();
160 Field field = {iter->first, static_cast<int32_t>(iter->second.index()), true, false};
161 errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, result);
162 if (errCode != E_OK) {
163 // never happen
164 LOGE("calc hash fail when there is one primary key errCode = %d", errCode);
165 }
166 } else {
167 std::vector<uint8_t> tempRes;
168 for (const auto &item : primaryKey) {
169 std::vector<uint8_t> temp;
170 Field field = {item.first, static_cast<int32_t>(item.second.index()), true, false};
171 errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, temp);
172 if (errCode != E_OK) {
173 // never happen
174 LOGE("calc hash fail when there is more than one primary key errCode = %d", errCode);
175 return result;
176 }
177 tempRes.insert(tempRes.end(), temp.begin(), temp.end());
178 }
179 errCode = DBCommon::CalcValueHash(tempRes, result);
180 if (errCode != E_OK) {
181 LOGE("calc hash fail when calc the composite primary key errCode = %d", errCode);
182 }
183 }
184 return result;
185 }
186
SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback & callback)187 void RelationalStoreManager::SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback &callback)
188 {
189 RuntimeContext::GetInstance()->SetAutoLaunchRequestCallback(callback, DBTypeInner::DB_RELATION);
190 }
191
GetRelationalStoreIdentifier(const std::string & userId,const std::string & appId,const std::string & storeId,bool syncDualTupleMode)192 std::string RelationalStoreManager::GetRelationalStoreIdentifier(const std::string &userId, const std::string &appId,
193 const std::string &storeId, bool syncDualTupleMode)
194 {
195 return RuntimeConfig::GetStoreIdentifier(userId, appId, storeId, syncDualTupleMode);
196 }
197 } // namespace DistributedDB
198 #endif