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