• 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 WAIT_CONNECT_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         SqliteConnection *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     return E_OK;
85 }
86 
~SqliteConnectionPool()87 SqliteConnectionPool::~SqliteConnectionPool()
88 {
89     CloseAllConnections();
90 }
91 
InitReadConnectionCount()92 void SqliteConnectionPool::InitReadConnectionCount()
93 {
94     if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
95         readConnectionCount = 0;
96     } else if (config.GetJournalMode() == "WAL") {
97         readConnectionCount = config.GetReadConSize();
98     } else {
99         readConnectionCount = 0;
100     }
101 }
102 
CloseAllConnections()103 void SqliteConnectionPool::CloseAllConnections()
104 {
105     if (writeConnection != nullptr) {
106         delete writeConnection;
107     }
108     writeConnection = nullptr;
109     writeConnectionUsed = true;
110 
111     for (auto &item : readConnections) {
112         if (item != nullptr) {
113             delete item;
114             item = nullptr;
115         }
116     }
117     readConnections.clear();
118     idleReadConnectionCount = 0;
119 }
120 
AcquireConnection(bool isReadOnly)121 SqliteConnection *SqliteConnectionPool::AcquireConnection(bool isReadOnly)
122 {
123     if (isReadOnly && readConnectionCount != 0) {
124         return AcquireReadConnection();
125     } else {
126         return AcquireWriteConnection();
127     }
128 }
ReleaseConnection(SqliteConnection * connection)129 void SqliteConnectionPool::ReleaseConnection(SqliteConnection *connection)
130 {
131     if (connection == nullptr) {
132         return;
133     }
134     connection->DesFinalize();
135     if (connection == writeConnection) {
136         ReleaseWriteConnection();
137     } else {
138         ReleaseReadConnection(connection);
139     }
140 }
141 
AcquireWriteConnection()142 SqliteConnection *SqliteConnectionPool::AcquireWriteConnection()
143 {
144     std::unique_lock<std::mutex> lock(writeMutex);
145     if (writeCondition.wait_for(lock, WAIT_CONNECT_TIMEOUT, [this] { return !writeConnectionUsed; })) {
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, WAIT_CONNECT_TIMEOUT, [this] { return !transactionUsed; })) {
157         transactionUsed = true;
158         return E_OK;
159     }
160     LOG_WARN("transactionUsed is %{public}d", transactionUsed);
161     return E_TRANSACTION_IN_EXECUTE;
162 }
163 
ReleaseTransaction()164 void SqliteConnectionPool::ReleaseTransaction()
165 {
166     {
167         std::unique_lock<std::mutex> lock(transMutex);
168         transactionUsed = false;
169     }
170     transCondition.notify_one();
171 }
172 
ReleaseWriteConnection()173 void SqliteConnectionPool::ReleaseWriteConnection()
174 {
175     {
176         std::unique_lock<std::mutex> lock(writeMutex);
177         writeConnectionUsed = false;
178     }
179     writeCondition.notify_one();
180 }
181 
182 /**
183  * get last element from connectionPool
184  * @return
185  */
AcquireReadConnection()186 SqliteConnection *SqliteConnectionPool::AcquireReadConnection()
187 {
188     std::unique_lock<std::mutex> lock(readMutex);
189     if (readCondition.wait_for(lock, WAIT_CONNECT_TIMEOUT, [this] { return idleReadConnectionCount > 0; })) {
190         SqliteConnection *connection = readConnections.back();
191         readConnections.pop_back();
192         idleReadConnectionCount--;
193         return connection;
194     }
195     LOG_WARN("readConnectionCount is %{public}d, idleReadConnectionCount is %{public}d", readConnectionCount,
196         idleReadConnectionCount);
197     return nullptr;
198 }
199 
200 /**
201  * push connection back to last of connectionPool
202  * @param connection
203  */
ReleaseReadConnection(SqliteConnection * connection)204 void SqliteConnectionPool::ReleaseReadConnection(SqliteConnection *connection)
205 {
206     {
207         std::unique_lock<std::mutex> lock(readMutex);
208         readConnections.push_back(connection);
209         idleReadConnectionCount++;
210     }
211     readCondition.notify_one();
212 }
213 
IsOverLength(const std::vector<uint8_t> & newKey)214 bool SqliteConnectionPool::IsOverLength(const std::vector<uint8_t> &newKey)
215 {
216     if (newKey.empty()) {
217         return false;
218     }
219 
220     std::stringstream ss;
221     copy(newKey.begin(), newKey.end(), std::ostream_iterator<uint8_t>(ss, ""));
222     return ss.str().length() > LIMITATION;
223 }
224 
InnerReOpenReadConnections()225 int SqliteConnectionPool::InnerReOpenReadConnections()
226 {
227     int errCode = E_OK;
228     for (auto &item : readConnections) {
229         if (item != nullptr) {
230             delete item;
231             item = nullptr;
232         }
233     }
234     readConnections.clear();
235 
236     for (int i = 0; i < readConnectionCount; i++) {
237         SqliteConnection *connection = SqliteConnection::Open(config, false, errCode);
238         if (connection == nullptr) {
239             CloseAllConnections();
240             return errCode;
241         }
242         readConnections.push_back(connection);
243     }
244 
245     return errCode;
246 }
247 
248 
ReOpenAvailableReadConnections()249 int SqliteConnectionPool::ReOpenAvailableReadConnections()
250 {
251     std::unique_lock<std::mutex> lock(readMutex);
252     return InnerReOpenReadConnections();
253 }
254 
255 #ifdef RDB_SUPPORT_ICU
256 /**
257  * The database locale.
258  */
ConfigLocale(const std::string localeStr)259 int SqliteConnectionPool::ConfigLocale(const std::string localeStr)
260 {
261     std::unique_lock<std::mutex> lock(rdbMutex);
262     if (idleReadConnectionCount != readConnectionCount) {
263         return E_NO_ROW_IN_QUERY;
264     }
265 
266     for (int i = 0; i < idleReadConnectionCount; i++) {
267         SqliteConnection *connection = readConnections[i];
268         if (connection == nullptr) {
269             LOG_ERROR("Read Connection is null.");
270             return E_ERROR;
271         }
272         connection->ConfigLocale(localeStr);
273     }
274 
275     if (writeConnection == nullptr) {
276         LOG_ERROR("Write Connection is null.");
277         return E_ERROR;
278     } else {
279         writeConnection->ConfigLocale(localeStr);
280     }
281 
282     return E_OK;
283 }
284 #endif
285 
286 /**
287  * Rename the backed up database.
288  */
ChangeDbFileForRestore(const std::string newPath,const std::string backupPath,const std::vector<uint8_t> & newKey)289 int SqliteConnectionPool::ChangeDbFileForRestore(const std::string newPath, const std::string backupPath,
290     const std::vector<uint8_t> &newKey)
291 {
292     if (writeConnectionUsed == true || idleReadConnectionCount != readConnectionCount) {
293         LOG_ERROR("Connection pool is busy now!");
294         return E_ERROR;
295     }
296 
297     LOG_ERROR("restore.");
298     CloseAllConnections();
299 
300     std::string currentPath = config.GetPath();
301     bool ret = SqliteUtils::DeleteFile(currentPath);
302     if (ret == false) {
303         LOG_ERROR("DeleteFile error");
304     }
305     SqliteUtils::DeleteFile(currentPath + "-shm");
306     SqliteUtils::DeleteFile(currentPath + "-wal");
307     SqliteUtils::DeleteFile(currentPath + "-journal");
308 
309     if (currentPath != newPath) {
310         SqliteUtils::DeleteFile(newPath);
311         SqliteUtils::DeleteFile(newPath + "-shm");
312         SqliteUtils::DeleteFile(newPath + "-wal");
313         SqliteUtils::DeleteFile(newPath + "-journal");
314     }
315 
316     int retVal = SqliteUtils::RenameFile(backupPath, newPath);
317     if (retVal != E_OK) {
318         LOG_ERROR("RenameFile error");
319         return retVal;
320     }
321 
322     return Init();
323 }
324 
getTransactionStack()325 std::stack<BaseTransaction> &SqliteConnectionPool::getTransactionStack()
326 {
327     return transactionStack;
328 }
329 } // namespace NativeRdb
330 } // namespace OHOS
331