• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "medialibrary_rdb_transaction.h"
17 
18 #include "media_log.h"
19 
20 namespace OHOS::Media {
21 using namespace std;
22 
23 constexpr int32_t E_HAS_DB_ERROR = -222;
24 constexpr int32_t E_OK = 0;
25 
26 constexpr int RDB_TRANSACTION_WAIT_MS = 1000;
27 std::mutex TransactionOperations::transactionMutex_;
28 std::condition_variable TransactionOperations::transactionCV_;
29 std::atomic<bool> TransactionOperations::isInTransaction_(false);
30 constexpr int32_t MAX_TRY_TIMES = 30;
31 constexpr int32_t TRANSACTION_WAIT_INTERVAL = 50; // in milliseconds.
32 
TransactionOperations(const shared_ptr<OHOS::NativeRdb::RdbStore> & rdbStore)33 TransactionOperations::TransactionOperations(
34     const shared_ptr<OHOS::NativeRdb::RdbStore> &rdbStore) : rdbStore_(rdbStore) {}
35 
~TransactionOperations()36 TransactionOperations::~TransactionOperations()
37 {
38     if (isStart && !isFinish) {
39         TransactionRollback();
40     }
41 }
42 
Start()43 int32_t TransactionOperations::Start()
44 {
45     if (isStart || isFinish) {
46         return 0;
47     }
48     int32_t errCode = BeginTransaction();
49     if (errCode == 0) {
50         isStart = true;
51     }
52     return errCode;
53 }
54 
Finish()55 void TransactionOperations::Finish()
56 {
57     if (!isStart) {
58         return;
59     }
60     if (!isFinish) {
61         int32_t ret = TransactionCommit();
62         if (ret == 0) {
63             isFinish = true;
64         }
65     }
66 }
67 
BeginTransaction()68 int32_t TransactionOperations::BeginTransaction()
69 {
70     if (rdbStore_ == nullptr) {
71         MEDIA_ERR_LOG("Pointer rdbStore_ is nullptr. Maybe it didn't init successfully.");
72         return E_HAS_DB_ERROR;
73     }
74     MEDIA_INFO_LOG("Start transaction");
75 
76     unique_lock<mutex> cvLock(transactionMutex_);
77     if (isInTransaction_.load()) {
78         transactionCV_.wait_for(cvLock, chrono::milliseconds(RDB_TRANSACTION_WAIT_MS),
79             [this] () { return !(isInTransaction_.load()); });
80     }
81 
82     int curTryTime = 0;
83     while (curTryTime < MAX_TRY_TIMES) {
84         if (rdbStore_->IsInTransaction()) {
85             this_thread::sleep_for(chrono::milliseconds(TRANSACTION_WAIT_INTERVAL));
86             if (isInTransaction_.load() || rdbStore_->IsInTransaction()) {
87                 curTryTime++;
88                 MEDIA_INFO_LOG("RdbStore is in transaction, try %{public}d times...", curTryTime);
89                 continue;
90             }
91         }
92 
93         int32_t errCode = rdbStore_->BeginTransaction();
94         if (errCode == SQLITE3_DATABASE_LOCKER) {
95             curTryTime++;
96             MEDIA_ERR_LOG("Sqlite database file is locked! try %{public}d times...", curTryTime);
97             continue;
98         } else if (errCode != NativeRdb::E_OK) {
99             MEDIA_ERR_LOG("Start Transaction failed, errCode=%{public}d", errCode);
100             isInTransaction_.store(false);
101             transactionCV_.notify_one();
102             return E_HAS_DB_ERROR;
103         } else {
104             isInTransaction_.store(true);
105             return E_OK;
106         }
107     }
108 
109     MEDIA_ERR_LOG("RdbStore is still in transaction after try %{public}d times, abort.", MAX_TRY_TIMES);
110     return E_HAS_DB_ERROR;
111 }
112 
TransactionCommit()113 int32_t TransactionOperations::TransactionCommit()
114 {
115     if (rdbStore_ == nullptr) {
116         return E_HAS_DB_ERROR;
117     }
118     MEDIA_INFO_LOG("Try commit transaction");
119 
120     if (!(isInTransaction_.load()) || !(rdbStore_->IsInTransaction())) {
121         MEDIA_ERR_LOG("no transaction now");
122         return E_HAS_DB_ERROR;
123     }
124 
125     int32_t errCode = rdbStore_->Commit();
126     isInTransaction_.store(false);
127     transactionCV_.notify_all();
128     if (errCode != NativeRdb::E_OK) {
129         MEDIA_ERR_LOG("commit failed, errCode=%{public}d", errCode);
130         return E_HAS_DB_ERROR;
131     }
132 
133     return E_OK;
134 }
135 
TransactionRollback()136 int32_t TransactionOperations::TransactionRollback()
137 {
138     if (rdbStore_ == nullptr) {
139         return E_HAS_DB_ERROR;
140     }
141     MEDIA_INFO_LOG("Try rollback transaction");
142 
143     if (!(isInTransaction_.load()) || !(rdbStore_->IsInTransaction())) {
144         MEDIA_ERR_LOG("no transaction now");
145         return E_HAS_DB_ERROR;
146     }
147 
148     int32_t errCode = rdbStore_->RollBack();
149     isInTransaction_.store(false);
150     transactionCV_.notify_all();
151     if (errCode != NativeRdb::E_OK) {
152         MEDIA_ERR_LOG("rollback failed, errCode=%{public}d", errCode);
153         return E_HAS_DB_ERROR;
154     }
155 
156     return E_OK;
157 }
158 } // namespace OHOS::Media
159