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 "multi_ver_natural_store_connection.h"
18 
19 #include <vector>
20 #include <cstdlib>
21 #include <ctime>
22 
23 #include "log_print.h"
24 #include "db_errno.h"
25 #include "db_constant.h"
26 #include "multi_ver_natural_store_snapshot.h"
27 #include "multi_ver_natural_store.h"
28 
29 namespace DistributedDB {
MultiVerNaturalStoreConnection(MultiVerNaturalStore * kvDB)30 MultiVerNaturalStoreConnection::MultiVerNaturalStoreConnection(MultiVerNaturalStore *kvDB)
31     : SyncAbleKvDBConnection(kvDB),
32       writeHandle_(nullptr)
33 {}
34 
~MultiVerNaturalStoreConnection()35 MultiVerNaturalStoreConnection::~MultiVerNaturalStoreConnection()
36 {
37     writeHandle_ = nullptr;
38 }
39 
40 // Get the value from the database
Get(const IOption & option,const Key & key,Value & value) const41 int MultiVerNaturalStoreConnection::Get(const IOption &option, const Key &key, Value &value) const
42 {
43     int errCode = CheckDataStatus(key, {}, false);
44     if (errCode != E_OK) {
45         return errCode;
46     }
47     {
48         // Only for the read in the write transaction
49         std::lock_guard<std::mutex> lock(writeMutex_);
50         if (writeHandle_ != nullptr) {
51             return writeHandle_->Get(key, value);
52         }
53     }
54 
55     auto handle = GetHandle(false, errCode);
56     if (handle == nullptr) {
57         return errCode;
58     }
59 
60     errCode = handle->InitCurrentReadVersion();
61     if (errCode == E_OK) {
62         errCode = handle->Get(key, value);
63     }
64 
65     GetDB<MultiVerNaturalStore>()->ReleaseHandle(handle);
66     return errCode;
67 }
68 
69 // Put the value to the database
Put(const IOption & option,const Key & key,const Value & value)70 int MultiVerNaturalStoreConnection::Put(const IOption &option, const Key &key, const Value &value)
71 {
72     bool isAuto = false;
73     int errCode = CheckDataStatus(key, value, false);
74     if (errCode != E_OK) {
75         return errCode;
76     }
77 
78     std::lock_guard<std::mutex> lock(writeMutex_);
79     errCode = StartTransactionInner(isAuto);
80     if (errCode != E_OK) {
81         LOGE("Start transaction failed:%d", errCode);
82         return errCode;
83     }
84 
85     errCode = writeHandle_->Put(key, value);
86     if (errCode != E_OK) {
87         LOGE("Put value err:%d", errCode);
88         if (isAuto) {
89             (void)(RollBackTransactionInner());
90         }
91         return errCode;
92     }
93 
94     if (isAuto) {
95         errCode = CommitTransactionInner();
96     }
97 
98     return errCode;
99 }
100 
101 // Delete the value from the database
Delete(const IOption & option,const Key & key)102 int MultiVerNaturalStoreConnection::Delete(const IOption &option, const Key &key)
103 {
104     int errCode = CheckDataStatus(key, {}, true);
105     if (errCode != E_OK) {
106         return errCode;
107     }
108     bool isAuto = false;
109     std::lock_guard<std::mutex> lock(writeMutex_);
110     errCode = StartTransactionInner(isAuto);
111     if (errCode != E_OK) {
112         LOGE("start transaction to delete failed:%d", errCode);
113         return errCode;
114     }
115 
116     errCode = writeHandle_->Delete(key);
117     if (errCode != E_OK) {
118         if (isAuto) {
119             int rollbackErrCode = RollBackTransactionInner();
120             LOGE("Connection Delete fail, rollback(state:%d) transaction!", rollbackErrCode);
121         }
122         return errCode;
123     }
124 
125     if (isAuto) {
126         errCode = CommitTransactionInner();
127     }
128     return errCode;
129 }
130 
131 // Clear all the data from the database
Clear(const IOption & option)132 int MultiVerNaturalStoreConnection::Clear(const IOption &option)
133 {
134     bool isAuto = false;
135     std::lock_guard<std::mutex> lock(writeMutex_);
136     int errCode = StartTransactionInner(isAuto);
137     if (errCode != E_OK) {
138         LOGE("start transaction to clear failed:%d", errCode);
139         return errCode;
140     }
141 
142     errCode = writeHandle_->Clear();
143     if (errCode != E_OK) {
144         if (isAuto) {
145             int rollbackErrCode = RollBackTransactionInner();
146             LOGD("Connection Clear, rollback(state:%d) transaction!", rollbackErrCode);
147         }
148         return errCode;
149     }
150 
151     if (isAuto) {
152         errCode = CommitTransactionInner();
153     }
154     return errCode;
155 }
156 
157 // Get all the data from the database
GetEntries(const IOption & option,const Key & keyPrefix,std::vector<Entry> & entries) const158 int MultiVerNaturalStoreConnection::GetEntries(const IOption &option,
159     const Key &keyPrefix, std::vector<Entry> &entries) const
160 {
161     {
162         std::lock_guard<std::mutex> lock(writeMutex_);
163         if (writeHandle_ != nullptr) {
164             return writeHandle_->GetEntries(keyPrefix, entries);
165         }
166     }
167 
168     int errCode = E_OK;
169     auto handle = GetHandle(false, errCode);
170     if (handle == nullptr) {
171         return errCode;
172     }
173     errCode = handle->GetEntries(keyPrefix, entries);
174     GetDB<MultiVerNaturalStore>()->ReleaseHandle(handle);
175     return errCode;
176 }
177 
178 // Put the batch values to the database.
PutBatch(const IOption & option,const std::vector<Entry> & entries)179 int MultiVerNaturalStoreConnection::PutBatch(const IOption &option, const std::vector<Entry> &entries)
180 {
181     bool isAuto = false;
182     if (entries.empty() || entries.size() > DBConstant::MAX_BATCH_SIZE) {
183         return -E_INVALID_ARGS;
184     }
185     for (const auto &item : entries) {
186         if (CheckDataStatus(item.key, item.value, false) != E_OK) {
187             return -E_INVALID_ARGS;
188         }
189     }
190 
191     std::lock_guard<std::mutex> lock(writeMutex_);
192 
193     // if the transaction is not started auto
194     int errCode = StartTransactionInner(isAuto);
195     if (errCode != E_OK) {
196         LOGE("start transaction failed:%d", errCode);
197         return errCode;
198     }
199 
200     for (const auto &item : entries) {
201         errCode = writeHandle_->Put(item.key, item.value);
202         if (errCode != E_OK) {
203             if (isAuto) {
204                 (void)(RollBackTransactionInner());
205             }
206             return errCode;
207         }
208     }
209 
210     if (isAuto) {
211         errCode = CommitTransactionInner();
212     }
213     return errCode;
214 }
215 
216 // Delete the batch values from the database.
DeleteBatch(const IOption & option,const std::vector<Key> & keys)217 int MultiVerNaturalStoreConnection::DeleteBatch(const IOption &option, const std::vector<Key> &keys)
218 {
219     if (keys.empty() || keys.size() > DBConstant::MAX_BATCH_SIZE) {
220         LOGE("[MultiVer]DeleteBatch size[%zu]!", keys.size());
221         return -E_INVALID_ARGS;
222     }
223     if (!CheckDeletedKeys(keys)) {
224         return -E_INVALID_ARGS;
225     }
226     bool isAuto = false;
227     std::lock_guard<std::mutex> lock(writeMutex_);
228     // if the transaction is not started auto
229     int errCode = StartTransactionInner(isAuto);
230     if (errCode != E_OK) {
231         LOGE("Start transaction failed:%d", errCode);
232         return errCode;
233     }
234 
235     // delete automatic
236     bool needCommit = false;
237     for (const auto &item : keys) {
238         errCode = writeHandle_->Delete(item);
239         if (errCode == E_OK) {
240             needCommit = true;
241         } else if (errCode != -E_NOT_FOUND) {
242             if (isAuto) {
243                 (void)(RollBackTransactionInner());
244             }
245             LOGE("Delete failed:%d", errCode);
246             return errCode;
247         }
248     }
249 
250     if (isAuto) {
251         if (needCommit) {
252             errCode = CommitTransactionInner();
253         } else {
254             (void)(RollBackTransactionInner());
255             errCode = -E_NOT_FOUND;
256         }
257     } else {
258         errCode = needCommit ? E_OK : -E_NOT_FOUND;
259     }
260     return errCode;
261 }
262 
GetSnapshot(IKvDBSnapshot * & snapshot) const263 int MultiVerNaturalStoreConnection::GetSnapshot(IKvDBSnapshot *&snapshot) const
264 {
265     if (kvDB_ == nullptr) {
266         return -E_INVALID_DB;
267     }
268     int errCode = E_OK;
269     auto handle = GetHandle(false, errCode);
270     if (handle == nullptr) {
271         LOGE("Get the handle for snapshot failed:%d", errCode);
272         return errCode;
273     }
274 
275     errCode = handle->InitCurrentReadVersion();
276     if (errCode != E_OK) {
277         LOGE("Init the handle version for snapshot failed:%d", errCode);
278         GetDB<MultiVerNaturalStore>()->ReleaseHandle(handle);
279         return errCode;
280     }
281 
282     snapshot = new (std::nothrow) MultiVerNaturalStoreSnapshot(handle);
283     if (snapshot == nullptr) {
284         GetDB<MultiVerNaturalStore>()->ReleaseHandle(handle);
285         return -E_OUT_OF_MEMORY;
286     }
287 
288     std::lock_guard<std::mutex> lock(snapshotMutex_);
289     snapshots_.insert(snapshot);
290     GetDB<MultiVerNaturalStore>()->AddVersionConstraintToList(handle->GetCurrentReadVersion());
291     return E_OK;
292 }
293 
294 // Release the created snapshot
ReleaseSnapshot(IKvDBSnapshot * & snapshot)295 void MultiVerNaturalStoreConnection::ReleaseSnapshot(IKvDBSnapshot *&snapshot)
296 {
297     if (snapshot == nullptr) {
298         return;
299     }
300 
301     std::lock_guard<std::mutex> lock(snapshotMutex_);
302     static_cast<MultiVerNaturalStoreSnapshot *>(snapshot)->Close();
303     snapshots_.erase(snapshot);
304     delete snapshot;
305     snapshot = nullptr;
306     return;
307 }
308 
309 // Start the transaction
StartTransaction()310 int MultiVerNaturalStoreConnection::StartTransaction()
311 {
312     // Get the state of the transaction.
313     std::lock_guard<std::mutex> lock(writeMutex_);
314     if (writeHandle_ != nullptr) {
315         LOGE("Transaction is already running");
316         return -E_TRANSACT_STATE;
317     }
318     bool isAuto = false;
319     return StartTransactionInner(isAuto);
320 }
321 
322 // Commit the transaction
Commit()323 int MultiVerNaturalStoreConnection::Commit()
324 {
325     std::lock_guard<std::mutex> lock(writeMutex_);
326     return CommitTransactionInner();
327 }
328 
329 // Roll back the transaction
RollBack()330 int MultiVerNaturalStoreConnection::RollBack()
331 {
332     std::lock_guard<std::mutex> lock(writeMutex_);
333     return RollBackTransactionInner();
334 }
335 
IsTransactionStarted() const336 bool MultiVerNaturalStoreConnection::IsTransactionStarted() const
337 {
338     std::lock_guard<std::mutex> lock(writeMutex_);
339     if (writeHandle_ != nullptr) {
340         return true;
341     }
342     return false;
343 }
344 
345 // Close and delete the connection.
PreClose()346 int MultiVerNaturalStoreConnection::PreClose()
347 {
348     std::lock_guard<std::mutex> snapshotLock(snapshotMutex_);
349     if (snapshots_.size() > 0) {
350         LOGE("the connection have unreleased snapshot, should not close.");
351         return -E_BUSY;
352     }
353 
354     std::lock_guard<std::mutex> writeLock(writeMutex_);
355     if (writeHandle_ != nullptr) {
356         LOGE("the connection have transaction, should not close.");
357         (void)(RollBackTransactionInner());
358     }
359     return E_OK;
360 }
361 
362 // Commit Transaction for local change data
CommitTransactionInner()363 int MultiVerNaturalStoreConnection::CommitTransactionInner()
364 {
365     if (kvDB_ == nullptr) {
366         return -E_INVALID_DB;
367     }
368     // Get the state of the transaction.
369     if (writeHandle_ == nullptr) {
370         LOGE("Transaction has not been started.");
371         return -E_TRANSACT_STATE;
372     }
373 
374     int errCode = writeHandle_->CommitTransaction();
375     GetDB<MultiVerNaturalStore>()->ReleaseHandle(writeHandle_);
376 
377     return errCode;
378 }
379 
380 // If the transaction is started automatically, should roll back automatically
RollBackTransactionInner()381 int MultiVerNaturalStoreConnection::RollBackTransactionInner()
382 {
383     if (kvDB_ == nullptr) {
384         return -E_INVALID_DB;
385     }
386     if (writeHandle_ == nullptr) {
387         return -E_TRANSACT_STATE;
388     }
389 
390     int errCode = writeHandle_->RollBackTransaction();
391     GetDB<MultiVerNaturalStore>()->ReleaseHandle(writeHandle_);
392 
393     return errCode;
394 }
395 
StartTransactionInner(bool & isAuto)396 int MultiVerNaturalStoreConnection::StartTransactionInner(bool &isAuto)
397 {
398     if (kvDB_ == nullptr) {
399         return -E_INVALID_DB;
400     }
401     isAuto = false;
402     if (writeHandle_ != nullptr) {
403         return E_OK;
404     }
405 
406     int errCode = E_OK;
407     auto handle = GetHandle(true, errCode);
408     if (handle == nullptr) {
409         LOGE("Get write handle for transaction failed:%d", errCode);
410         return errCode;
411     }
412     errCode = handle->StartTransaction();
413     if (errCode != E_OK) {
414         LOGE("Start transaction failed:%d", errCode);
415         GetDB<MultiVerNaturalStore>()->ReleaseHandle(handle);
416         return errCode;
417     }
418 
419     writeHandle_ = handle;
420     isAuto = true;
421 
422     return E_OK;
423 }
424 
TranslateObserverModeToEventTypes(unsigned mode,std::list<int> & eventTypes) const425 int MultiVerNaturalStoreConnection::TranslateObserverModeToEventTypes(unsigned mode,
426     std::list<int> &eventTypes) const
427 {
428     if (mode != NATURAL_STORE_COMMIT_EVENT) {
429         return -E_NOT_SUPPORT;
430     } else {
431         eventTypes.push_back(NATURAL_STORE_COMMIT_EVENT);
432         return E_OK;
433     }
434 }
435 
Rekey(const CipherPassword & passwd)436 int MultiVerNaturalStoreConnection::Rekey(const CipherPassword &passwd)
437 {
438     if (kvDB_ == nullptr) {
439         return -E_INVALID_DB;
440     }
441     std::lock_guard<std::mutex> lock(rekeyMutex_);
442     // Check the condition, have no more than one connection.
443     int errCode = kvDB_->TryToDisableConnection(OperatePerm::REKEY_MONOPOLIZE_PERM);
444     if (errCode != E_OK) {
445         return errCode;
446     }
447 
448     // Check the observer condition.
449     errCode = GenericKvDBConnection::PreCheckExclusiveStatus();
450     if (errCode != E_OK) {
451         kvDB_->ReEnableConnection(OperatePerm::REKEY_MONOPOLIZE_PERM);
452         return errCode;
453     }
454 
455     // No need the check other
456     errCode = kvDB_->Rekey(passwd);
457     GenericKvDBConnection::ResetExclusiveStatus();
458     kvDB_->ReEnableConnection(OperatePerm::REKEY_MONOPOLIZE_PERM);
459     return errCode;
460 }
461 
Export(const std::string & filePath,const CipherPassword & passwd)462 int MultiVerNaturalStoreConnection::Export(const std::string &filePath, const CipherPassword &passwd)
463 {
464     if (kvDB_ == nullptr) {
465         return -E_INVALID_DB;
466     }
467     return kvDB_->Export(filePath, passwd);
468 }
469 
Import(const std::string & filePath,const CipherPassword & passwd)470 int MultiVerNaturalStoreConnection::Import(const std::string &filePath, const CipherPassword &passwd)
471 {
472     if (kvDB_ == nullptr) {
473         return -E_INVALID_DB;
474     }
475     std::lock_guard<std::mutex> lock(importMutex_);
476     int errCode = kvDB_->TryToDisableConnection(OperatePerm::IMPORT_MONOPOLIZE_PERM);
477     if (errCode != E_OK) {
478         return errCode;
479     }
480 
481     // Check the observer condition.
482     errCode = GenericKvDBConnection::PreCheckExclusiveStatus();
483     if (errCode != E_OK) {
484         kvDB_->ReEnableConnection(OperatePerm::IMPORT_MONOPOLIZE_PERM);
485         return errCode;
486     }
487     errCode = kvDB_->Import(filePath, passwd);
488     GenericKvDBConnection::ResetExclusiveStatus();
489     kvDB_->ReEnableConnection(OperatePerm::IMPORT_MONOPOLIZE_PERM);
490     return errCode;
491 }
492 
CheckDeletedKeys(const std::vector<Key> & keys)493 bool MultiVerNaturalStoreConnection::CheckDeletedKeys(const std::vector<Key> &keys)
494 {
495     for (const auto &item : keys) {
496         if (item.empty() || item.size() > DBConstant::MAX_KEY_SIZE) {
497             return false;
498         }
499     }
500     return true;
501 }
502 
CheckDataStatus(const Key & key,const Value & value,bool isDeleted) const503 int MultiVerNaturalStoreConnection::CheckDataStatus(const Key &key, const Value &value, bool isDeleted) const
504 {
505     if (kvDB_ == nullptr) {
506         return -E_INVALID_DB;
507     }
508     return static_cast<MultiVerNaturalStore *>(kvDB_)->CheckDataStatus(key, value, isDeleted);
509 }
510 
GetHandle(bool isWrite,int & errCode) const511 MultiVerStorageExecutor *MultiVerNaturalStoreConnection::GetHandle(bool isWrite, int &errCode) const
512 {
513     MultiVerNaturalStore *multiVerNatureStore = GetDB<MultiVerNaturalStore>();
514     if (multiVerNatureStore == nullptr) {
515         errCode = -E_INVALID_DB;
516         return nullptr;
517     }
518 
519     return multiVerNatureStore->GetHandle(isWrite, errCode);
520 }
521 
522 DEFINE_OBJECT_TAG_FACILITIES(MultiVerNaturalStoreConnection)
523 } // namespace DistributedDB
524 #endif