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 "sqlite_single_relational_storage_engine.h"
17
18 #include "db_common.h"
19 #include "db_errno.h"
20 #include "res_finalizer.h"
21 #include "sqlite_single_ver_relational_storage_executor.h"
22
23
24 namespace DistributedDB {
25 namespace {
26 constexpr const char *RELATIONAL_SCHEMA_KEY = "relational_schema";
27 }
28
SQLiteSingleRelationalStorageEngine()29 SQLiteSingleRelationalStorageEngine::SQLiteSingleRelationalStorageEngine() {};
30
~SQLiteSingleRelationalStorageEngine()31 SQLiteSingleRelationalStorageEngine::~SQLiteSingleRelationalStorageEngine() {};
32
NewSQLiteStorageExecutor(sqlite3 * dbHandle,bool isWrite,bool isMemDb)33 StorageExecutor *SQLiteSingleRelationalStorageEngine::NewSQLiteStorageExecutor(sqlite3 *dbHandle, bool isWrite,
34 bool isMemDb)
35 {
36 return new (std::nothrow) SQLiteSingleVerRelationalStorageExecutor(dbHandle, isWrite);
37 }
38
Upgrade(sqlite3 * db)39 int SQLiteSingleRelationalStorageEngine::Upgrade(sqlite3 *db)
40 {
41 return SQLiteUtils::CreateRelationalMetaTable(db);
42 }
43
RegisterFunction(sqlite3 * db) const44 int SQLiteSingleRelationalStorageEngine::RegisterFunction(sqlite3 *db) const
45 {
46 int errCode = SQLiteUtils::RegisterCalcHash(db);
47 if (errCode != E_OK) {
48 LOGE("[engine] register calculate hash failed!");
49 return errCode;
50 }
51
52 errCode = SQLiteUtils::RegisterGetSysTime(db);
53 if (errCode != E_OK) {
54 LOGE("[engine] register get sys time failed!");
55 }
56 return E_OK;
57 }
58
CreateNewExecutor(bool isWrite,StorageExecutor * & handle)59 int SQLiteSingleRelationalStorageEngine::CreateNewExecutor(bool isWrite, StorageExecutor *&handle)
60 {
61 sqlite3 *db = nullptr;
62 int errCode = SQLiteUtils::OpenDatabase(option_, db, false);
63 if (errCode != E_OK) {
64 return errCode;
65 }
66 do {
67 errCode = SQLiteUtils::SetPersistWalMode(db);
68 if (errCode != E_OK) {
69 break;
70 }
71
72 errCode = Upgrade(db); // cerate meta_data table.
73 if (errCode != E_OK) {
74 break;
75 }
76
77 errCode = RegisterFunction(db);
78 if (errCode != E_OK) {
79 break;
80 }
81
82 handle = NewSQLiteStorageExecutor(db, isWrite, false);
83 if (handle == nullptr) {
84 LOGE("[Relational] New SQLiteStorageExecutor[%d] for the pool failed.", isWrite);
85 errCode = -E_OUT_OF_MEMORY;
86 break;
87 }
88 return E_OK;
89 } while (false);
90
91 (void)sqlite3_close_v2(db);
92 db = nullptr;
93 return errCode;
94 }
95
ReleaseExecutor(SQLiteSingleVerRelationalStorageExecutor * & handle)96 int SQLiteSingleRelationalStorageEngine::ReleaseExecutor(SQLiteSingleVerRelationalStorageExecutor *&handle)
97 {
98 if (handle == nullptr) {
99 return E_OK;
100 }
101 StorageExecutor *databaseHandle = handle;
102 Recycle(databaseHandle);
103 handle = nullptr;
104 return E_OK;
105 }
106
SetSchema(const RelationalSchemaObject & schema)107 void SQLiteSingleRelationalStorageEngine::SetSchema(const RelationalSchemaObject &schema)
108 {
109 std::lock_guard lock(schemaMutex_);
110 schema_ = schema;
111 }
112
GetSchemaRef() const113 const RelationalSchemaObject &SQLiteSingleRelationalStorageEngine::GetSchemaRef() const
114 {
115 std::lock_guard lock(schemaMutex_);
116 return schema_;
117 }
118
119 namespace {
SaveSchemaToMetaTable(SQLiteSingleVerRelationalStorageExecutor * handle,const RelationalSchemaObject & schema)120 int SaveSchemaToMetaTable(SQLiteSingleVerRelationalStorageExecutor *handle, const RelationalSchemaObject &schema)
121 {
122 const Key schemaKey(RELATIONAL_SCHEMA_KEY, RELATIONAL_SCHEMA_KEY + strlen(RELATIONAL_SCHEMA_KEY));
123 Value schemaVal;
124 DBCommon::StringToVector(schema.ToSchemaString(), schemaVal);
125 int errCode = handle->PutKvData(schemaKey, schemaVal); // save schema to meta_data
126 if (errCode != E_OK) {
127 LOGE("Save schema to meta table failed. %d", errCode);
128 }
129 return errCode;
130 }
131 }
132
CreateDistributedTable(const std::string & tableName,bool & schemaChanged)133 int SQLiteSingleRelationalStorageEngine::CreateDistributedTable(const std::string &tableName, bool &schemaChanged)
134 {
135 std::lock_guard lock(schemaMutex_);
136 RelationalSchemaObject tmpSchema = schema_;
137 bool isUpgrade = false;
138 if (tmpSchema.GetTable(tableName).GetTableName() == tableName) {
139 LOGW("distributed table was already created.");
140 isUpgrade = true;
141 int errCode = UpgradeDistributedTable(tableName);
142 if (errCode != E_OK) {
143 LOGE("Upgrade distributed table failed. %d", errCode);
144 return errCode;
145 }
146 }
147
148 if (tmpSchema.GetTables().size() >= DBConstant::MAX_DISTRIBUTED_TABLE_COUNT) {
149 LOGE("The number of distributed tables is exceeds limit.");
150 return -E_MAX_LIMITS;
151 }
152
153 LOGD("Create distributed table.");
154 int errCode = E_OK;
155 auto *handle = static_cast<SQLiteSingleVerRelationalStorageExecutor *>(FindExecutor(true, OperatePerm::NORMAL_PERM,
156 errCode));
157 if (handle == nullptr) {
158 return errCode;
159 }
160 ResFinalizer finalizer([&handle, this] { this->ReleaseExecutor(handle); });
161
162 errCode = handle->StartTransaction(TransactType::IMMEDIATE);
163 if (errCode != E_OK) {
164 return errCode;
165 }
166
167 TableInfo table;
168 errCode = handle->CreateDistributedTable(tableName, table, isUpgrade);
169 if (errCode != E_OK) {
170 LOGE("create distributed table failed. %d", errCode);
171 (void)handle->Rollback();
172 return errCode;
173 }
174
175 tmpSchema.AddRelationalTable(table);
176 errCode = SaveSchemaToMetaTable(handle, tmpSchema);
177 if (errCode != E_OK) {
178 LOGE("Save schema to meta table for create distributed table failed. %d", errCode);
179 (void)handle->Rollback();
180 return errCode;
181 }
182
183 errCode = handle->Commit();
184 if (errCode == E_OK) {
185 schema_ = tmpSchema;
186 schemaChanged = true;
187 }
188 return errCode;
189 }
190
UpgradeDistributedTable(const std::string & tableName)191 int SQLiteSingleRelationalStorageEngine::UpgradeDistributedTable(const std::string &tableName)
192 {
193 LOGD("Upgrade distributed table.");
194 RelationalSchemaObject tmpSchema = schema_;
195 int errCode = E_OK;
196 auto *handle = static_cast<SQLiteSingleVerRelationalStorageExecutor *>(FindExecutor(true, OperatePerm::NORMAL_PERM,
197 errCode));
198 if (handle == nullptr) {
199 return errCode;
200 }
201
202 errCode = handle->StartTransaction(TransactType::IMMEDIATE);
203 if (errCode != E_OK) {
204 ReleaseExecutor(handle);
205 return errCode;
206 }
207
208 TableInfo newTable;
209 errCode = handle->UpgradeDistributedTable(tmpSchema.GetTable(tableName), newTable);
210 if (errCode != E_OK) {
211 LOGE("Upgrade distributed table failed. %d", errCode);
212 (void)handle->Rollback();
213 ReleaseExecutor(handle);
214 return errCode;
215 }
216
217 tmpSchema.AddRelationalTable(newTable);
218 errCode = SaveSchemaToMetaTable(handle, tmpSchema);
219 if (errCode != E_OK) {
220 LOGE("Save schema to meta table for upgrade distributed table failed. %d", errCode);
221 (void)handle->Rollback();
222 ReleaseExecutor(handle);
223 return errCode;
224 }
225
226 errCode = handle->Commit();
227 if (errCode == E_OK) {
228 schema_ = tmpSchema;
229 }
230 ReleaseExecutor(handle);
231 return errCode;
232 }
233
CleanDistributedDeviceTable(std::vector<std::string> & missingTables)234 int SQLiteSingleRelationalStorageEngine::CleanDistributedDeviceTable(std::vector<std::string> &missingTables)
235 {
236 int errCode = E_OK;
237 auto handle = static_cast<SQLiteSingleVerRelationalStorageExecutor *>(FindExecutor(true, OperatePerm::NORMAL_PERM,
238 errCode));
239 if (handle == nullptr) {
240 return errCode;
241 }
242
243 std::lock_guard lock(schemaMutex_);
244 errCode = handle->StartTransaction(TransactType::IMMEDIATE);
245 if (errCode != E_OK) {
246 ReleaseExecutor(handle);
247 return errCode;
248 }
249
250 errCode = handle->CheckAndCleanDistributedTable(schema_.GetTableNames(), missingTables);
251 if (errCode == E_OK) {
252 errCode = handle->Commit();
253 if (errCode == E_OK) {
254 // Remove non-existent tables from the schema
255 for (const auto &tableName : missingTables) {
256 schema_.RemoveRelationalTable(tableName);
257 }
258 SaveSchemaToMetaTable(handle, schema_); // save schema to meta_data
259 }
260 } else {
261 LOGE("Check distributed table failed. %d", errCode);
262 (void)handle->Rollback();
263 }
264
265 ReleaseExecutor(handle);
266 return errCode;
267 }
268 }
269 #endif