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