• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_connection_pool.h"
17 
18 #include <base_transaction.h>
19 
20 #include <condition_variable>
21 #include <iostream>
22 #include <iterator>
23 #include <mutex>
24 #include <sstream>
25 #include <vector>
26 
27 #include "logger.h"
28 #include "rdb_errno.h"
29 #include "sqlite_global_config.h"
30 #include "sqlite_utils.h"
31 
32 namespace OHOS {
33 namespace NativeRdb {
34 using namespace OHOS::Rdb;
35 
36 constexpr std::chrono::seconds TRANSACTION_TIMEOUT(2);
37 
Create(const RdbStoreConfig & storeConfig,int & errCode)38 SqliteConnectionPool *SqliteConnectionPool::Create(const RdbStoreConfig &storeConfig, int &errCode)
39 {
40     auto pool = new (std::nothrow) SqliteConnectionPool(storeConfig);
41     if (pool == nullptr) {
42         LOG_ERROR("SqliteConnectionPool::Create new failed, pool is nullptr");
43         return nullptr;
44     }
45     errCode = pool->Init();
46     if (errCode != E_OK) {
47         delete pool;
48         return nullptr;
49     }
50     return pool;
51 }
52 
SqliteConnectionPool(const RdbStoreConfig & storeConfig)53 SqliteConnectionPool::SqliteConnectionPool(const RdbStoreConfig &storeConfig)
54     : config_(storeConfig), writeConnection_(nullptr), writeConnectionUsed_(true), readConnections_(),
55       readConnectionCount_(0), idleReadConnectionCount_(0), transactionStack_(), transactionUsed_(false)
56 {
57 }
58 
Init()59 int SqliteConnectionPool::Init()
60 {
61     int errCode = E_OK;
62     writeConnection_ = SqliteConnection::Open(config_, true, errCode);
63     if (writeConnection_ == nullptr) {
64         return errCode;
65     }
66 
67     InitReadConnectionCount();
68 
69     // max read connect count is 64
70     if (readConnectionCount_ > 64) {
71         return E_ARGS_READ_CON_OVERLOAD;
72     }
73     for (int i = 0; i < readConnectionCount_; i++) {
74         auto connection = SqliteConnection::Open(config_, false, errCode);
75         if (connection == nullptr) {
76             CloseAllConnections();
77             return errCode;
78         }
79         readConnections_.push_back(connection);
80     }
81 
82     writeConnectionUsed_ = false;
83     idleReadConnectionCount_ = readConnectionCount_;
84     writeTimeout_ = std::chrono::seconds(config_.GetWriteTime());
85     readTimeout_ = std::chrono::seconds(config_.GetReadTime());
86     return E_OK;
87 }
88 
~SqliteConnectionPool()89 SqliteConnectionPool::~SqliteConnectionPool()
90 {
91     CloseAllConnections();
92 }
93 
InitReadConnectionCount()94 void SqliteConnectionPool::InitReadConnectionCount()
95 {
96     if (config_.GetStorageMode() == StorageMode::MODE_MEMORY) {
97         readConnectionCount_ = 0;
98     } else if (config_.GetJournalMode() == "WAL") {
99         readConnectionCount_ = config_.GetReadConSize();
100     } else {
101         readConnectionCount_ = 0;
102     }
103 }
104 
CloseAllConnections()105 void SqliteConnectionPool::CloseAllConnections()
106 {
107     writeConnection_ = nullptr;
108     writeConnectionUsed_ = true;
109 
110     for (auto &item : readConnections_) {
111         item = nullptr;
112     }
113     readConnections_.clear();
114     idleReadConnectionCount_ = 0;
115 }
116 
AcquireConnection(bool isReadOnly)117 std::shared_ptr<SqliteConnection> SqliteConnectionPool::AcquireConnection(bool isReadOnly)
118 {
119     if (isReadOnly && readConnectionCount_ != 0) {
120         return AcquireReadConnection();
121     } else {
122         return AcquireWriteConnection();
123     }
124 }
125 
ReleaseConnection(std::shared_ptr<SqliteConnection> connection)126 void SqliteConnectionPool::ReleaseConnection(std::shared_ptr<SqliteConnection> connection)
127 {
128     if (connection == nullptr) {
129         return;
130     }
131     connection->DesFinalize();
132     if (connection == writeConnection_) {
133         ReleaseWriteConnection();
134         connection->TryCheckPoint();
135     } else {
136         ReleaseReadConnection(connection);
137     }
138 }
139 
AcquireWriteConnection()140 std::shared_ptr<SqliteConnection> SqliteConnectionPool::AcquireWriteConnection()
141 {
142     std::unique_lock<std::mutex> lock(writeMutex_);
143     if (writeCondition_.wait_for(lock, writeTimeout_, [this] {
144             return !writeConnectionUsed_;
145         })) {
146         writeConnectionUsed_ = true;
147         return writeConnection_;
148     }
149     LOG_WARN("writeConnection_ is %{public}d",  writeConnectionUsed_);
150     return nullptr;
151 }
152 
AcquireTransaction()153 int SqliteConnectionPool::AcquireTransaction()
154 {
155     std::unique_lock<std::mutex> lock(transMutex_);
156     if (transCondition_.wait_for(lock, TRANSACTION_TIMEOUT, [this] {
157             return !transactionUsed_;
158         })) {
159         transactionUsed_ = true;
160         return E_OK;
161     }
162     LOG_WARN("transactionUsed_ is %{public}d", transactionUsed_);
163     return E_TRANSACTION_IN_EXECUTE;
164 }
165 
ReleaseTransaction()166 void SqliteConnectionPool::ReleaseTransaction()
167 {
168     {
169         std::unique_lock<std::mutex> lock(transMutex_);
170         transactionUsed_ = false;
171     }
172     transCondition_.notify_one();
173 }
174 
ReleaseWriteConnection()175 void SqliteConnectionPool::ReleaseWriteConnection()
176 {
177     {
178         std::unique_lock<std::mutex> lock(writeMutex_);
179         writeConnectionUsed_ = false;
180     }
181     writeCondition_.notify_one();
182 }
183 
184 /**
185  * get last element from connectionPool
186  * @return
187  */
AcquireReadConnection()188 std::shared_ptr<SqliteConnection> SqliteConnectionPool::AcquireReadConnection()
189 {
190     std::unique_lock<std::mutex> lock(readMutex_);
191     if (readCondition_.wait_for(lock, readTimeout_, [this] {
192             return idleReadConnectionCount_ > 0;
193         })) {
194         auto connection = readConnections_.back();
195         readConnections_.pop_back();
196         idleReadConnectionCount_--;
197         return connection;
198     }
199     LOG_WARN("readConnectionCount_ is %{public}d, idleReadConnectionCount_ is %{public}d", readConnectionCount_,
200         idleReadConnectionCount_);
201     return nullptr;
202 }
203 
204 /**
205  * push connection back to last of connectionPool
206  * @param connection
207  */
ReleaseReadConnection(std::shared_ptr<SqliteConnection> connection)208 void SqliteConnectionPool::ReleaseReadConnection(std::shared_ptr<SqliteConnection> connection)
209 {
210     {
211         std::unique_lock<std::mutex> lock(readMutex_);
212         readConnections_.push_back(connection);
213         idleReadConnectionCount_++;
214     }
215     readCondition_.notify_one();
216 }
217 
InnerReOpenReadConnections()218 int SqliteConnectionPool::InnerReOpenReadConnections()
219 {
220     int errCode = E_OK;
221     for (auto &item : readConnections_) {
222         item = nullptr;
223     }
224     readConnections_.clear();
225 
226     for (int i = 0; i < readConnectionCount_; i++) {
227         auto connection = SqliteConnection::Open(config_, false, errCode);
228         if (connection == nullptr) {
229             CloseAllConnections();
230             return errCode;
231         }
232         readConnections_.push_back(connection);
233     }
234 
235     return errCode;
236 }
237 
ReOpenAvailableReadConnections()238 int SqliteConnectionPool::ReOpenAvailableReadConnections()
239 {
240     std::unique_lock<std::mutex> lock(readMutex_);
241     return InnerReOpenReadConnections();
242 }
243 
244 #ifdef RDB_SUPPORT_ICU
245 /**
246  * The database locale.
247  */
ConfigLocale(const std::string localeStr)248 int SqliteConnectionPool::ConfigLocale(const std::string localeStr)
249 {
250     std::unique_lock<std::mutex> lock(rdbMutex_);
251     if (idleReadConnectionCount_ != readConnectionCount_) {
252         return E_NO_ROW_IN_QUERY;
253     }
254 
255     for (int i = 0; i < idleReadConnectionCount_; i++) {
256         auto connection = readConnections_[i];
257         if (connection == nullptr) {
258             LOG_ERROR("Read Connection is null.");
259             return E_ERROR;
260         }
261         connection->ConfigLocale(localeStr);
262     }
263 
264     if (writeConnection_ == nullptr) {
265         LOG_ERROR("Write Connection is null.");
266         return E_ERROR;
267     } else {
268         writeConnection_->ConfigLocale(localeStr);
269     }
270 
271     return E_OK;
272 }
273 #endif
274 
275 /**
276  * Rename the backed up database.
277  */
ChangeDbFileForRestore(const std::string newPath,const std::string backupPath,const std::vector<uint8_t> & newKey)278 int SqliteConnectionPool::ChangeDbFileForRestore(const std::string newPath, const std::string backupPath,
279     const std::vector<uint8_t> &newKey)
280 {
281     if (writeConnectionUsed_ == true || idleReadConnectionCount_ != readConnectionCount_) {
282         LOG_ERROR("Connection pool is busy now!");
283         return E_ERROR;
284     }
285 
286     LOG_ERROR("restore.");
287     CloseAllConnections();
288 
289     std::string currentPath = config_.GetPath();
290     bool ret = SqliteUtils::DeleteFile(currentPath);
291     if (ret == false) {
292         LOG_ERROR("DeleteFile error");
293     }
294     SqliteUtils::DeleteFile(currentPath + "-shm");
295     SqliteUtils::DeleteFile(currentPath + "-wal");
296     SqliteUtils::DeleteFile(currentPath + "-journal");
297 
298     if (currentPath != newPath) {
299         SqliteUtils::DeleteFile(newPath);
300         SqliteUtils::DeleteFile(newPath + "-shm");
301         SqliteUtils::DeleteFile(newPath + "-wal");
302         SqliteUtils::DeleteFile(newPath + "-journal");
303     }
304 
305     int retVal = SqliteUtils::RenameFile(backupPath, newPath);
306     if (retVal != E_OK) {
307         LOG_ERROR("RenameFile error");
308         return retVal;
309     }
310 
311     return Init();
312 }
313 
GetTransactionStack()314 std::stack<BaseTransaction> &SqliteConnectionPool::GetTransactionStack()
315 {
316     return transactionStack_;
317 }
318 
GetTransactionStackMutex()319 std::mutex &SqliteConnectionPool::GetTransactionStackMutex()
320 {
321     return transactionStackMutex_;
322 }
323 } // namespace NativeRdb
324 } // namespace OHOS
325