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