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
16 #ifndef OMIT_MULTI_VER
17 #include "sqlite_multi_ver_data_storage.h"
18
19 #include <climits>
20 #include <string>
21 #include <vector>
22 #include <algorithm>
23
24 #include "db_constant.h"
25 #include "db_types.h"
26 #include "log_print.h"
27 #include "sqlite_utils.h"
28 #include "multi_ver_kv_entry.h"
29 #include "multi_ver_value_object.h"
30 #include "value_hash_calc.h"
31 #include "db_common.h"
32 #include "multi_ver_natural_store.h"
33 #include "platform_specific.h"
34
35 namespace DistributedDB {
36 namespace {
37 const std::string CREATE_TABLE_SQL =
38 "CREATE TABLE IF NOT EXISTS version_data(key BLOB, value BLOB, oper_flag INTEGER, version INTEGER, " \
39 "timestamp INTEGER, ori_timestamp INTEGER, hash_key BLOB, " \
40 "PRIMARY key(hash_key, version));";
41 const std::string CREATE_TABLE_VERSION_INDEX_SQL =
42 "CREATE INDEX IF NOT EXISTS version_index ON version_data (version);";
43 const std::string CREATE_TABLE_FLAG_INDEX_SQL =
44 "CREATE INDEX IF NOT EXISTS flag_index ON version_data (oper_flag);";
45
46 const std::size_t MAX_READ_CONNECT_NUM = 16;
47 }
48
SQLiteMultiVerDataStorage()49 SQLiteMultiVerDataStorage::SQLiteMultiVerDataStorage()
50 : writeTransaction_(nullptr),
51 writeTransactionUsed_(false)
52 {}
53
~SQLiteMultiVerDataStorage()54 SQLiteMultiVerDataStorage::~SQLiteMultiVerDataStorage()
55 {
56 writeTransaction_ = nullptr;
57 }
58
CheckVersion(const Property & property,bool & isDbExist) const59 int SQLiteMultiVerDataStorage::CheckVersion(const Property &property, bool &isDbExist) const
60 {
61 int dbVer = 0;
62 int errCode = GetVersion(property, dbVer, isDbExist);
63 if (errCode != E_OK) {
64 LOGE("[DataStorage][CheckVer] GetVersion failed, errCode=%d.", errCode);
65 return errCode;
66 }
67 if (!isDbExist) {
68 return E_OK;
69 }
70 LOGD("[DataStorage][CheckVer] DbVersion=%d, CurVersion=%d.", dbVer, MULTI_VER_DATA_STORAGE_VERSION_CURRENT);
71 if (dbVer > MULTI_VER_DATA_STORAGE_VERSION_CURRENT) {
72 LOGE("[DataStorage][CheckVer] Version Not Support!");
73 return -E_VERSION_NOT_SUPPORT;
74 }
75 return E_OK;
76 }
77
GetVersion(const Property & property,int & version,bool & isDbExisted) const78 int SQLiteMultiVerDataStorage::GetVersion(const Property &property, int &version, bool &isDbExisted) const
79 {
80 std::string uri = property.path + "/" + property.identifierName + "/" + DBConstant::MULTI_SUB_DIR + "/" +
81 DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
82 isDbExisted = OS::CheckPathExistence(uri);
83 if (isDbExisted) {
84 std::vector<std::string> tableVect;
85 OpenDbProperties option = {uri, property.isNeedCreate, false, tableVect, property.cipherType, property.passwd};
86 return SQLiteUtils::GetVersion(option, version);
87 }
88 return E_OK;
89 }
90
Open(const Property & property)91 int SQLiteMultiVerDataStorage::Open(const Property &property)
92 {
93 // only set the property para or create the database and the table?
94 // whether create the transactions.
95 property_ = property;
96 uri_ = property.path + "/" + property_.identifierName + "/" + DBConstant::MULTI_SUB_DIR + "/" +
97 DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
98 std::vector<std::string> tableVect;
99 tableVect.push_back(CREATE_TABLE_SQL);
100 tableVect.push_back(CREATE_TABLE_VERSION_INDEX_SQL);
101 tableVect.push_back(CREATE_TABLE_FLAG_INDEX_SQL);
102
103 OpenDbProperties option = {uri_, property.isNeedCreate, false, tableVect, property.cipherType, property.passwd};
104 sqlite3 *db = nullptr;
105 int errCode = SQLiteUtils::OpenDatabase(option, db);
106 if (errCode != E_OK) {
107 LOGE("Open the multi ver data store error:%d", errCode);
108 goto END;
109 }
110
111 // Version had been check before open and currently no upgrade to do
112 errCode = SQLiteUtils::SetUserVer(option, MULTI_VER_DATA_STORAGE_VERSION_CURRENT);
113 if (errCode != E_OK) {
114 LOGE("Init the version multi ver store error:%d", errCode);
115 }
116
117 END:
118 if (db != nullptr) {
119 (void)sqlite3_close_v2(db);
120 db = nullptr;
121 }
122
123 return errCode;
124 }
125
126 // start one write transaction
127 // do the transaction initialization and call the start transaction;
StartWrite(KvDataType dataType,IKvDBMultiVerTransaction * & transaction)128 int SQLiteMultiVerDataStorage::StartWrite(KvDataType dataType, IKvDBMultiVerTransaction *&transaction)
129 {
130 (void)dataType;
131 std::unique_lock<std::mutex> lock(transactionMutex_);
132 // if same thread. return nullptr.
133 if (std::this_thread::get_id() == writeHolderId_) {
134 transaction = nullptr;
135 return -E_BUSY;
136 }
137
138 if (writeTransaction_ != nullptr) {
139 writeCondition_.wait(lock, [&] {
140 return !writeTransactionUsed_;
141 });
142
143 writeTransactionUsed_ = true;
144 writeHolderId_ = std::this_thread::get_id();
145 transaction = writeTransaction_;
146 return E_OK;
147 }
148
149 transaction = new (std::nothrow) SQLiteMultiVerTransaction();
150 if (transaction == nullptr) {
151 LOGE("Failed to create the SQLite write transaction");
152 return -E_OUT_OF_MEMORY;
153 }
154
155 // initialize the transaction.
156 int errCode = static_cast<SQLiteMultiVerTransaction *>(transaction)->Initialize(uri_, false,
157 property_.cipherType, property_.passwd);
158 if (errCode != E_OK) {
159 LOGE("Init write transaction failed:%d", errCode);
160 delete transaction;
161 transaction = nullptr;
162 return errCode;
163 }
164
165 writeTransaction_ = static_cast<SQLiteMultiVerTransaction *>(transaction);
166 writeTransactionUsed_ = true;
167 writeHolderId_ = std::this_thread::get_id();
168 return E_OK;
169 }
170
171 // do the first step of commit record.
172 // commit the transaction, and avoid other operation reading the new data.
CommitWritePhaseOne(IKvDBMultiVerTransaction * transaction,const UpdateVerTimestamp & multiVerTimestamp)173 int SQLiteMultiVerDataStorage::CommitWritePhaseOne(IKvDBMultiVerTransaction *transaction,
174 const UpdateVerTimestamp &multiVerTimestamp)
175 {
176 if (transaction == nullptr) {
177 LOGE("Invalid transaction!");
178 return -E_INVALID_DB;
179 }
180 // Get versionInfo from transaction.
181 // Call the commit of the sqlite.
182 Version versionInfo = transaction->GetVersion();
183
184 if (multiVerTimestamp.isNeedUpdate) {
185 (void)transaction->UpdateTimestampByVersion(versionInfo, multiVerTimestamp.timestamp);
186 }
187
188 int errCode = transaction->CommitTransaction();
189 if (errCode != E_OK) {
190 auto sqliteTransaction = static_cast<SQLiteMultiVerTransaction *>(transaction);
191 if (transaction != nullptr) {
192 (void)sqliteTransaction->Reset(property_.cipherType, property_.passwd);
193 }
194 LOGE("SQLite commit the transaction failed:%d", errCode);
195 }
196 return errCode;
197 }
198
199 // when the commit history update failed, need delete the commit
RollbackWritePhaseOne(IKvDBMultiVerTransaction * transaction,const Version & versionInfo)200 int SQLiteMultiVerDataStorage::RollbackWritePhaseOne(IKvDBMultiVerTransaction *transaction,
201 const Version &versionInfo)
202 {
203 if (transaction == nullptr) {
204 LOGE("Invalid transaction!");
205 return -E_INVALID_DB;
206 }
207
208 SQLiteMultiVerTransaction *sqliteTransaction = static_cast<SQLiteMultiVerTransaction *>(transaction);
209 sqliteTransaction->StartTransaction();
210 int errCode = sqliteTransaction->ClearEntriesByVersion(versionInfo);
211 if (errCode == E_OK) {
212 sqliteTransaction->CommitTransaction();
213 } else {
214 sqliteTransaction->RollBackTransaction();
215 }
216
217 return errCode;
218 }
219
220 // Rollback the write transaction.
RollbackWrite(IKvDBMultiVerTransaction * transaction)221 int SQLiteMultiVerDataStorage::RollbackWrite(IKvDBMultiVerTransaction *transaction)
222 {
223 if (transaction == nullptr) {
224 LOGE("Invalid transaction!");
225 return -E_INVALID_DB;
226 }
227 // call the rollback of the sqlite.
228 int errCode = static_cast<SQLiteMultiVerTransaction *>(transaction)->RollBackTransaction();
229 if (errCode != E_OK) {
230 (void)static_cast<SQLiteMultiVerTransaction *>(transaction)->Reset(property_.cipherType, property_.passwd);
231 LOGE("SQLite rollback failed:%d", errCode);
232 }
233 return errCode;
234 }
235
236 // should update the flag indicated that other operating could read the new record.
CommitWritePhaseTwo(IKvDBMultiVerTransaction * transaction)237 void SQLiteMultiVerDataStorage::CommitWritePhaseTwo(IKvDBMultiVerTransaction *transaction)
238 {
239 // just change the head version?
240 (void)transaction;
241 }
242
243 // Get one start transaction.
StartRead(KvDataType dataType,const Version & versionInfo,int & errCode)244 IKvDBMultiVerTransaction *SQLiteMultiVerDataStorage::StartRead(KvDataType dataType,
245 const Version &versionInfo, int &errCode)
246 {
247 (void)dataType;
248 std::unique_lock<std::mutex> lock(transactionMutex_);
249 for (auto &iter : readTransactions_) {
250 if (iter.second) {
251 iter.second = false;
252 (iter.first)->SetVersion(versionInfo);
253 errCode = E_OK;
254 return iter.first;
255 }
256 }
257 // need wait.
258 if (readTransactions_.size() > MAX_READ_CONNECT_NUM) {
259 LOGE("Over the max transaction num");
260 errCode = -E_BUSY;
261 return nullptr;
262 }
263
264 IKvDBMultiVerTransaction *transaction = new (std::nothrow) SQLiteMultiVerTransaction;
265 if (transaction == nullptr) {
266 errCode = -E_OUT_OF_MEMORY;
267 return nullptr;
268 }
269 errCode = static_cast<SQLiteMultiVerTransaction *>(transaction)->Initialize(uri_,
270 true, property_.cipherType, property_.passwd);
271 if (errCode != E_OK) {
272 delete transaction;
273 transaction = nullptr;
274 return nullptr;
275 }
276
277 transaction->SetVersion(versionInfo);
278 readTransactions_.insert(std::make_pair(transaction, false));
279 return transaction;
280 }
281
282 // Release the transaction created.
ReleaseTransaction(IKvDBMultiVerTransaction * transaction)283 void SQLiteMultiVerDataStorage::ReleaseTransaction(IKvDBMultiVerTransaction *transaction)
284 {
285 // whether need manage the transaction.
286 std::unique_lock<std::mutex> lock(transactionMutex_);
287 if (transaction == nullptr) {
288 LOGE("Invalid transaction!");
289 return;
290 }
291
292 if (transaction == writeTransaction_) {
293 static_cast<SQLiteMultiVerTransaction *>(writeTransaction_)->ResetVersion();
294 writeTransactionUsed_ = false;
295 writeHolderId_ = std::thread::id();
296 writeCondition_.notify_all();
297 return;
298 }
299
300 auto iter = readTransactions_.find(transaction);
301 if (iter != readTransactions_.end()) {
302 static_cast<SQLiteMultiVerTransaction *>(iter->first)->ResetVersion();
303 iter->second = true;
304 }
305 return;
306 }
307
Close()308 void SQLiteMultiVerDataStorage::Close()
309 {
310 std::lock_guard<std::mutex> lock(transactionMutex_);
311 // close all the transaction?
312 for (auto iter = readTransactions_.begin(); iter != readTransactions_.end(); iter++) {
313 if (iter->first != nullptr) {
314 delete iter->first;
315 }
316 }
317 readTransactions_.clear();
318
319 if (writeTransaction_ != nullptr) {
320 delete writeTransaction_;
321 writeTransaction_ = nullptr;
322 }
323 }
324
RunRekeyLogic(CipherType type,const CipherPassword & passwd)325 int SQLiteMultiVerDataStorage::RunRekeyLogic(CipherType type, const CipherPassword &passwd)
326 {
327 (void)type;
328 // openDatabase to get the sqlite3 pointer
329 std::vector<std::string> tableVect;
330 tableVect.push_back(CREATE_TABLE_SQL);
331 sqlite3 *db = nullptr;
332 OpenDbProperties option = {uri_, property_.isNeedCreate, false, tableVect, property_.cipherType, property_.passwd};
333 int errCode = SQLiteUtils::OpenDatabase(option, db);
334 if (errCode != E_OK) {
335 LOGE("Open db error:%d", errCode);
336 return errCode;
337 }
338
339 // execute rekey
340 errCode = SQLiteUtils::Rekey(db, passwd);
341 if (errCode != E_OK) {
342 LOGE("multi ver data rekey failed:%d", errCode);
343 }
344 // close db
345 (void)sqlite3_close_v2(db);
346 db = nullptr;
347
348 return errCode;
349 }
350
RunExportLogic(CipherType type,const CipherPassword & passwd,const std::string & dbDir)351 int SQLiteMultiVerDataStorage::RunExportLogic(CipherType type, const CipherPassword &passwd, const std::string &dbDir)
352 {
353 // openDatabase to get the sqlite3 pointer
354 std::vector<std::string> tableVect;
355 sqlite3 *db = nullptr;
356 OpenDbProperties option = {uri_, true, false, tableVect, property_.cipherType, property_.passwd};
357 int errCode = SQLiteUtils::OpenDatabase(option, db);
358 if (errCode != E_OK) {
359 LOGE("Open db error:%d", errCode);
360 return errCode;
361 }
362
363 // execute export
364 std::string newDbName = dbDir + "/" + DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
365 errCode = SQLiteUtils::ExportDatabase(db, type, passwd, newDbName);
366 if (errCode != E_OK) {
367 LOGE("multi ver data export failed:%d", errCode);
368 }
369 // close db
370 (void)sqlite3_close_v2(db);
371 db = nullptr;
372
373 return errCode;
374 }
375
BackupCurrentDatabase(const Property & property,const std::string & dir)376 int SQLiteMultiVerDataStorage::BackupCurrentDatabase(const Property &property, const std::string &dir)
377 {
378 std::string currentDb = property.path + "/" + property.identifierName + "/" + DBConstant::MULTI_SUB_DIR + "/" +
379 DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
380 std::string dstDb = dir + "/" + DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
381 int errCode = DBCommon::CopyFile(currentDb, dstDb);
382 if (errCode != E_OK) {
383 LOGE("Copy the local current db error:%d", errCode);
384 }
385 return errCode;
386 }
387
ImportDatabase(const Property & property,const std::string & dir,const CipherPassword & passwd)388 int SQLiteMultiVerDataStorage::ImportDatabase(const Property &property, const std::string &dir,
389 const CipherPassword &passwd)
390 {
391 std::string currentDb = property.path + "/" + property.identifierName + "/" + DBConstant::MULTI_SUB_DIR + "/" +
392 DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
393 std::string srcDb = dir + "/" + DBConstant::MULTI_VER_DATA_STORE + DBConstant::DB_EXTENSION;
394 int errCode = SQLiteUtils::ExportDatabase(srcDb, property.cipherType, passwd, currentDb, property.passwd);
395 if (errCode != E_OK) {
396 LOGE("import the multi ver data db error:%d", errCode);
397 }
398 return E_OK;
399 }
400 } // namespace DistributedDB
401 #endif