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_local_kvdb_connection.h"
18
19 #include <cstring>
20
21 #include "log_print.h"
22 #include "db_constant.h"
23 #include "sqlite_utils.h"
24 #include "sqlite_local_kvdb.h"
25 #include "sqlite_local_kvdb_snapshot.h"
26 #include "kvdb_commit_notify_filterable_data.h"
27 #include "sqlite_local_storage_executor.h"
28
29 namespace DistributedDB {
SQLiteLocalKvDBConnection(SQLiteLocalKvDB * kvDB)30 SQLiteLocalKvDBConnection::SQLiteLocalKvDBConnection(SQLiteLocalKvDB *kvDB)
31 : GenericKvDBConnection(kvDB),
32 writeHandle_(nullptr)
33 {}
34
~SQLiteLocalKvDBConnection()35 SQLiteLocalKvDBConnection::~SQLiteLocalKvDBConnection()
36 {}
37
Get(const IOption & option,const Key & key,Value & value) const38 int SQLiteLocalKvDBConnection::Get(const IOption &option, const Key &key, Value &value) const
39 {
40 if (kvDB_ == nullptr) {
41 return -E_INVALID_DB;
42 }
43 if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE) {
44 return -E_INVALID_ARGS;
45 }
46 {
47 std::lock_guard<std::mutex> lock(transactionMutex_);
48 if (writeHandle_ != nullptr) {
49 return writeHandle_->Get(key, value);
50 }
51 }
52 int errCode = E_OK;
53 SQLiteLocalStorageExecutor *handle = GetDB<SQLiteLocalKvDB>()->GetHandle(false, errCode);
54 if (handle == nullptr) {
55 return errCode;
56 }
57
58 errCode = handle->Get(key, value);
59 GetDB<SQLiteLocalKvDB>()->ReleaseHandle(handle);
60 return errCode;
61 }
62
Put(const IOption & option,const Key & key,const Value & value)63 int SQLiteLocalKvDBConnection::Put(const IOption &option, const Key &key, const Value &value)
64 {
65 int errCode = CheckDataStatus(key, value, false);
66 if (errCode != E_OK) {
67 return errCode;
68 }
69 std::lock_guard<std::mutex> lock(transactionMutex_);
70 bool isAuto = false;
71 errCode = StartTransactionInner(isAuto);
72 if (errCode != E_OK) {
73 LOGE("StartTransaction failed when Put error:%d", errCode);
74 return errCode;
75 }
76
77 errCode = writeHandle_->Put(key, value);
78 if (errCode != E_OK) {
79 if (isAuto) {
80 int errCodeRollBack = RollBackInner();
81 LOGI("Put failed,need rollback! errCode:[%d]", errCodeRollBack);
82 }
83 return errCode;
84 }
85 if (isAuto) {
86 errCode = CommitInner();
87 if (errCode != E_OK) {
88 LOGE("CommitTransaction failed when Put error:%d", errCode);
89 return errCode;
90 }
91 }
92
93 return errCode;
94 }
95
Delete(const IOption & option,const Key & key)96 int SQLiteLocalKvDBConnection::Delete(const IOption &option, const Key &key)
97 {
98 int errCode = CheckDataStatus(key, {}, true);
99 if (errCode != E_OK) {
100 return errCode;
101 }
102 std::lock_guard<std::mutex> lock(transactionMutex_);
103 bool isAuto = false;
104 errCode = StartTransactionInner(isAuto);
105 if (errCode != E_OK) {
106 LOGE("StartTransaction failed when Delete error:%d", errCode);
107 return errCode;
108 }
109
110 errCode = writeHandle_->Delete(key);
111 if (errCode != E_OK) {
112 if (isAuto) {
113 int errCodeRollBack = RollBackInner();
114 LOGI("Delete failed, need rollback! errcode:[%d]", errCodeRollBack);
115 }
116 return errCode;
117 }
118
119 if (isAuto) {
120 errCode = CommitInner();
121 if (errCode != E_OK) {
122 LOGE("CommitInner failed while delete:%d", errCode);
123 return errCode;
124 }
125 }
126 return E_OK;
127 }
128
Clear(const IOption & option)129 int SQLiteLocalKvDBConnection::Clear(const IOption &option)
130 {
131 std::lock_guard<std::mutex> lock(transactionMutex_);
132 bool isAuto = false;
133 int errCode = StartTransactionInner(isAuto);
134 if (errCode != E_OK) {
135 LOGE("StartTransaction failed when Clear error:%d", errCode);
136 return errCode;
137 }
138
139 errCode = writeHandle_->Clear();
140 if (errCode != E_OK) {
141 if (isAuto) {
142 int errCodeRollBack = RollBackInner();
143 LOGI("Clear failed, need rollback! RollBack result is [%d]", errCodeRollBack);
144 }
145 return errCode;
146 }
147
148 if (isAuto) {
149 errCode = CommitInner();
150 if (errCode != E_OK) {
151 LOGE("CommitInner failed when Clear error:%d", errCode);
152 return errCode;
153 }
154 }
155
156 return E_OK;
157 }
158
GetEntries(const IOption & option,const Key & keyPrefix,std::vector<Entry> & entries) const159 int SQLiteLocalKvDBConnection::GetEntries(const IOption &option, const Key &keyPrefix,
160 std::vector<Entry> &entries) const
161 {
162 if (kvDB_ == nullptr) {
163 return -E_INVALID_DB;
164 }
165 if (keyPrefix.size() > DBConstant::MAX_KEY_SIZE) {
166 return -E_INVALID_ARGS;
167 }
168 {
169 std::lock_guard<std::mutex> lock(transactionMutex_);
170 if (writeHandle_ != nullptr) {
171 return writeHandle_->GetEntries(keyPrefix, entries);
172 }
173 }
174 int errCode = E_OK;
175 SQLiteLocalStorageExecutor *handle = GetDB<SQLiteLocalKvDB>()->GetHandle(false, errCode);
176 if (handle == nullptr) {
177 return errCode;
178 }
179 errCode = handle->GetEntries(keyPrefix, entries);
180 GetDB<SQLiteLocalKvDB>()->ReleaseHandle(handle);
181 return errCode;
182 }
183
PutBatch(const IOption & option,const std::vector<Entry> & entries)184 int SQLiteLocalKvDBConnection::PutBatch(const IOption &option, const std::vector<Entry> &entries)
185 {
186 if (entries.empty() || entries.size() > DBConstant::MAX_BATCH_SIZE) {
187 return -E_INVALID_ARGS;
188 }
189 for (const auto &item : entries) {
190 if (CheckDataStatus(item.key, item.value, false) != E_OK) {
191 return -E_INVALID_ARGS;
192 }
193 }
194
195 bool isAuto = false;
196 std::lock_guard<std::mutex> lock(transactionMutex_);
197 int errCode = StartTransactionInner(isAuto);
198 if (errCode != E_OK) {
199 LOGE("StartTransaction failed when PutBatch error:%d", errCode);
200 return errCode;
201 }
202
203 for (const auto &entry : entries) {
204 // first argument is key and second argument is value.
205 errCode = writeHandle_->Put(entry.key, entry.value);
206 if (errCode != E_OK) {
207 if (isAuto) {
208 int errCodeRollBack = RollBackInner();
209 LOGI("PutBatch failed,need rollback! RollBack result is %d", errCodeRollBack);
210 }
211 return errCode;
212 }
213 }
214
215 if (isAuto) {
216 errCode = CommitInner();
217 if (errCode != E_OK) {
218 LOGE("CommitTransaction failed when PutBatch error:%d", errCode);
219 return errCode;
220 }
221 }
222
223 return E_OK;
224 }
225
DeleteBatch(const IOption & option,const std::vector<Key> & keys)226 int SQLiteLocalKvDBConnection::DeleteBatch(const IOption &option, const std::vector<Key> &keys)
227 {
228 if (keys.empty() || keys.size() > DBConstant::MAX_BATCH_SIZE) {
229 LOGE("[Local]DeleteBatch size[%zu]!", keys.size());
230 return -E_INVALID_ARGS;
231 }
232 for (const auto &item : keys) {
233 if (item.empty() || item.size() > DBConstant::MAX_KEY_SIZE) {
234 return -E_INVALID_ARGS;
235 }
236 }
237
238 bool isAuto = false;
239 std::lock_guard<std::mutex> lock(transactionMutex_);
240 int errCode = StartTransactionInner(isAuto);
241 if (errCode != E_OK) {
242 LOGE("StartTransaction failed when DeleteBatch error:%d", errCode);
243 return errCode;
244 }
245
246 errCode = writeHandle_->DeleteBatch(keys);
247
248 if (isAuto) {
249 if (errCode == E_OK) {
250 errCode = CommitInner();
251 if (errCode != E_OK) {
252 LOGE("CommitTransaction failed when DeleteBatch error:%d", errCode);
253 return errCode;
254 }
255 } else {
256 int errCodeRollBack = RollBackInner();
257 LOGI("DeleteBatchm need rollback! RollBack result is [%d]", errCodeRollBack);
258 return errCode;
259 }
260 }
261
262 return errCode;
263 }
264
265 // when GetSnapshot successfully, you must delete snapshot by ReleaseSnapshot
GetSnapshot(IKvDBSnapshot * & snapshot) const266 int SQLiteLocalKvDBConnection::GetSnapshot(IKvDBSnapshot *&snapshot) const
267 {
268 if (kvDB_ == nullptr) {
269 snapshot = nullptr;
270 return -E_INVALID_DB;
271 }
272
273 int errCode = E_OK;
274 IKvDBConnection *newConnect = kvDB_->GetDBConnection(errCode);
275 if (errCode != E_OK) {
276 LOGE("failed to get the new connection");
277 return errCode;
278 }
279
280 SQLiteLocalKvDBSnapshot *dbSnapshot = new (std::nothrow) SQLiteLocalKvDBSnapshot(newConnect);
281 if (dbSnapshot == nullptr) {
282 newConnect->Close();
283 delete newConnect;
284 return -E_OUT_OF_MEMORY;
285 }
286
287 snapshot = dbSnapshot;
288 {
289 std::lock_guard<std::mutex> lock(snapshotMutex_);
290 snapshots_.insert(dbSnapshot);
291 }
292
293 return E_OK;
294 }
295
ReleaseSnapshot(IKvDBSnapshot * & snapshot)296 void SQLiteLocalKvDBConnection::ReleaseSnapshot(IKvDBSnapshot *&snapshot)
297 {
298 if (snapshot != nullptr && kvDB_ != nullptr) {
299 std::lock_guard<std::mutex> lock(snapshotMutex_);
300 SQLiteLocalKvDBSnapshot *sqliteSnapshot = static_cast<SQLiteLocalKvDBSnapshot *>(snapshot);
301 sqliteSnapshot->Close();
302 snapshots_.erase(snapshot);
303 delete snapshot;
304 snapshot = nullptr;
305 }
306 }
307
StartTransaction()308 int SQLiteLocalKvDBConnection::StartTransaction()
309 {
310 std::lock_guard<std::mutex> lock(transactionMutex_);
311 if (writeHandle_ != nullptr) {
312 return -E_TRANSACT_STATE;
313 }
314 bool isAuto = false;
315 return StartTransactionInner(isAuto);
316 }
317
Commit()318 int SQLiteLocalKvDBConnection::Commit()
319 {
320 std::lock_guard<std::mutex> lock(transactionMutex_);
321 return CommitInner();
322 }
323
RollBack()324 int SQLiteLocalKvDBConnection::RollBack()
325 {
326 std::lock_guard<std::mutex> lock(transactionMutex_);
327 return RollBackInner();
328 }
329
IsTransactionStarted() const330 bool SQLiteLocalKvDBConnection::IsTransactionStarted() const
331 {
332 std::lock_guard<std::mutex> lock(transactionMutex_);
333 if (writeHandle_ != nullptr) {
334 return true;
335 }
336 return false;
337 }
338
PreClose()339 int SQLiteLocalKvDBConnection::PreClose()
340 {
341 {
342 std::lock_guard<std::mutex> snapshotLock(snapshotMutex_);
343 if (snapshots_.size() != 0) {
344 LOGE("Close failed, the connection have unreleased snapshot.");
345 return -E_BUSY;
346 }
347 }
348 std::lock_guard<std::mutex> transactionLock(transactionMutex_);
349 if (writeHandle_ != nullptr) {
350 writeHandle_->RollBack();
351 GetDB<SQLiteLocalKvDB>()->ReleaseHandle(writeHandle_);
352 }
353 return E_OK;
354 }
355
TranslateObserverModeToEventTypes(unsigned mode,std::list<int> & eventTypes) const356 int SQLiteLocalKvDBConnection::TranslateObserverModeToEventTypes(unsigned mode,
357 std::list<int> &eventTypes) const
358 {
359 return E_OK;
360 }
361
StartTransactionInner(bool & isAuto)362 int SQLiteLocalKvDBConnection::StartTransactionInner(bool &isAuto)
363 {
364 // if the transaction has been started, writeHandle wouldn't be nullptr.
365 if (writeHandle_ != nullptr) {
366 return E_OK;
367 }
368
369 if (kvDB_ == nullptr) {
370 LOGE("local database is null");
371 return -E_INVALID_DB;
372 }
373
374 int errCode = E_OK;
375 SQLiteLocalStorageExecutor *handle = GetDB<SQLiteLocalKvDB>()->GetHandle(true, errCode);
376 if (handle == nullptr) {
377 return errCode;
378 }
379
380 errCode = handle->StartTransaction();
381 if (errCode != E_OK) {
382 GetDB<SQLiteLocalKvDB>()->ReleaseHandle(handle);
383 return errCode;
384 }
385 writeHandle_ = handle;
386 // only the transaction has not been started before, set the flag to true.
387 // the manual operation would ignore the flag.
388 isAuto = true;
389 return E_OK;
390 }
391
CommitInner()392 int SQLiteLocalKvDBConnection::CommitInner()
393 {
394 if (writeHandle_ == nullptr) {
395 LOGE("local database is null or the transaction has not been started");
396 return -E_INVALID_DB;
397 }
398
399 int errCode = writeHandle_->Commit();
400 if (kvDB_ == nullptr) {
401 return -E_INVALID_DB;
402 }
403 GetDB<SQLiteLocalKvDB>()->ReleaseHandle(writeHandle_);
404 return errCode;
405 }
406
RollBackInner()407 int SQLiteLocalKvDBConnection::RollBackInner()
408 {
409 if (writeHandle_ == nullptr) {
410 LOGE("Invalid handle for rollback or the transaction has not been started.");
411 return -E_INVALID_DB;
412 }
413
414 int errCode = writeHandle_->RollBack();
415 if (kvDB_ == nullptr) {
416 return -E_INVALID_DB;
417 }
418 GetDB<SQLiteLocalKvDB>()->ReleaseHandle(writeHandle_);
419 return errCode;
420 }
421
Rekey(const CipherPassword & passwd)422 int SQLiteLocalKvDBConnection::Rekey(const CipherPassword &passwd)
423 {
424 if (kvDB_ == nullptr) {
425 return -E_INVALID_DB;
426 }
427 std::lock_guard<std::mutex> lock(transactionMutex_);
428 // return BUSY if in transaction
429 if (writeHandle_ != nullptr) {
430 LOGE("Transaction exists for rekey failed");
431 return -E_BUSY;
432 }
433 // Check the connection number.
434 int errCode = kvDB_->TryToDisableConnection(OperatePerm::REKEY_MONOPOLIZE_PERM);
435 if (errCode != E_OK) {
436 return errCode;
437 }
438
439 // Check the observer.
440 errCode = GenericKvDBConnection::PreCheckExclusiveStatus();
441 if (errCode != E_OK) {
442 kvDB_->ReEnableConnection(OperatePerm::REKEY_MONOPOLIZE_PERM);
443 return errCode;
444 }
445 // If only have one connection, just have the transactionMutex_;
446 // It means there would not be another operation on this connection.
447 errCode = kvDB_->Rekey(passwd);
448
449 GenericKvDBConnection::ResetExclusiveStatus();
450 kvDB_->ReEnableConnection(OperatePerm::REKEY_MONOPOLIZE_PERM);
451 return errCode;
452 }
453
Export(const std::string & filePath,const CipherPassword & passwd)454 int SQLiteLocalKvDBConnection::Export(const std::string &filePath, const CipherPassword &passwd)
455 {
456 if (kvDB_ == nullptr) {
457 return -E_INVALID_DB;
458 }
459 return kvDB_->Export(filePath, passwd);
460 }
461
Import(const std::string & filePath,const CipherPassword & passwd)462 int SQLiteLocalKvDBConnection::Import(const std::string &filePath, const CipherPassword &passwd)
463 {
464 if (kvDB_ == nullptr) {
465 return -E_INVALID_DB;
466 }
467 {
468 std::lock_guard<std::mutex> lock(transactionMutex_);
469 // return BUSY if in transaction
470 if (writeHandle_ != nullptr) {
471 LOGE("Transaction exists for rekey failed");
472 return -E_BUSY;
473 }
474 }
475 std::lock_guard<std::mutex> importLock(importMutex_);
476 int errCode = kvDB_->TryToDisableConnection(OperatePerm::IMPORT_MONOPOLIZE_PERM);
477 if (errCode != E_OK) {
478 return errCode;
479 }
480
481 errCode = GenericKvDBConnection::PreCheckExclusiveStatus();
482 if (errCode != E_OK) {
483 kvDB_->ReEnableConnection(OperatePerm::IMPORT_MONOPOLIZE_PERM);
484 return errCode;
485 }
486 errCode = kvDB_->Import(filePath, passwd);
487 GenericKvDBConnection::ResetExclusiveStatus();
488 kvDB_->ReEnableConnection(OperatePerm::IMPORT_MONOPOLIZE_PERM);
489 return errCode;
490 }
491
CheckDataStatus(const Key & key,const Value & value,bool isDeleted) const492 int SQLiteLocalKvDBConnection::CheckDataStatus(const Key &key, const Value &value, bool isDeleted) const
493 {
494 if (kvDB_ == nullptr) {
495 return -E_INVALID_DB;
496 }
497 return static_cast<SQLiteLocalKvDB *>(kvDB_)->CheckDataStatus(key, value, isDeleted);
498 }
499 } // namespace DistributedDB
500 #endif // OMIT_MULTI_VER
501