• 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 #define LOG_TAG "SqliteConnectionPool"
17 
18 #include "sqlite_connection_pool.h"
19 
20 #include "logger.h"
21 #include "rdb_errno.h"
22 #include "sqlite_global_config.h"
23 #include "sqlite_utils.h"
24 
25 #include <condition_variable>
26 #include <mutex>
27 #include <vector>
28 #include <sstream>
29 #include <iostream>
30 #include <iterator>
31 #include <base_transaction.h>
32 
33 namespace OHOS {
34 namespace NativeRdb {
Create(const RdbStoreConfig & storeConfig,int & errCode)35 SqliteConnectionPool *SqliteConnectionPool::Create(const RdbStoreConfig &storeConfig, int &errCode)
36 {
37     auto pool = new (std::nothrow) SqliteConnectionPool(storeConfig);
38     if (pool == nullptr) {
39         LOG_ERROR("SqliteConnectionPool::Create new failed, pool is nullptr");
40         return nullptr;
41     }
42     errCode = pool->Init();
43     if (errCode != E_OK) {
44         delete pool;
45         return nullptr;
46     }
47     return pool;
48 }
49 
SqliteConnectionPool(const RdbStoreConfig & storeConfig)50 SqliteConnectionPool::SqliteConnectionPool(const RdbStoreConfig &storeConfig)
51     : config(storeConfig), writeConnection(nullptr), writeConnectionUsed(true), readConnections(),
52       readConnectionCount(0), idleReadConnectionCount(0), transactionStack()
53 {
54 }
55 
Init()56 int SqliteConnectionPool::Init()
57 {
58     int errCode = E_OK;
59     writeConnection = SqliteConnection::Open(config, true, errCode);
60     if (writeConnection == nullptr) {
61         return errCode;
62     }
63 
64     InitReadConnectionCount();
65 
66     for (int i = 0; i < readConnectionCount; i++) {
67         SqliteConnection *connection = SqliteConnection::Open(config, false, errCode);
68         if (connection == nullptr) {
69             CloseAllConnections();
70             return errCode;
71         }
72         readConnections.push_back(connection);
73     }
74 
75     writeConnectionUsed = false;
76     idleReadConnectionCount = readConnectionCount;
77     return E_OK;
78 }
79 
~SqliteConnectionPool()80 SqliteConnectionPool::~SqliteConnectionPool()
81 {
82     CloseAllConnections();
83 }
84 
InitReadConnectionCount()85 void SqliteConnectionPool::InitReadConnectionCount()
86 {
87     if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
88         readConnectionCount = 0;
89     } else if (config.GetJournalMode() == "WAL") {
90         readConnectionCount = SqliteGlobalConfig::GetReadConnectionCount();
91     } else {
92         readConnectionCount = 0;
93     }
94 }
95 
CloseAllConnections()96 void SqliteConnectionPool::CloseAllConnections()
97 {
98     if (writeConnection != nullptr) {
99         delete writeConnection;
100     }
101     writeConnection = nullptr;
102     writeConnectionUsed = true;
103 
104     for (auto &item : readConnections) {
105         if (item != nullptr) {
106             delete item;
107             item = nullptr;
108         }
109     }
110     readConnections.clear();
111     idleReadConnectionCount = 0;
112 }
113 
AcquireConnection(bool isReadOnly)114 SqliteConnection *SqliteConnectionPool::AcquireConnection(bool isReadOnly)
115 {
116     if (isReadOnly && readConnectionCount != 0) {
117         LOG_DEBUG("AcquireReadConnection");
118         return AcquireReadConnection();
119     } else {
120         LOG_DEBUG("AcquireWriteConnection");
121         return AcquireWriteConnection();
122     }
123 }
ReleaseConnection(SqliteConnection * connection)124 void SqliteConnectionPool::ReleaseConnection(SqliteConnection *connection)
125 {
126     if (connection == writeConnection) {
127         ReleaseWriteConnection();
128     } else {
129         ReleaseReadConnection(connection);
130     }
131 }
132 
AcquireWriteConnection()133 SqliteConnection *SqliteConnectionPool::AcquireWriteConnection()
134 {
135     LOG_DEBUG("begin");
136     std::unique_lock<std::mutex> lock(writeMutex);
137     writeCondition.wait(lock, [&] { return !writeConnectionUsed; });
138     writeConnectionUsed = true;
139     LOG_DEBUG("end");
140     return writeConnection;
141 }
142 
ReleaseWriteConnection()143 void SqliteConnectionPool::ReleaseWriteConnection()
144 {
145     {
146         std::unique_lock<std::mutex> lock(writeMutex);
147         writeConnectionUsed = false;
148     }
149     writeCondition.notify_one();
150 }
151 
152 /**
153  * get last element from connectionPool
154  * @return
155  */
AcquireReadConnection()156 SqliteConnection *SqliteConnectionPool::AcquireReadConnection()
157 {
158     std::unique_lock<std::mutex> lock(readMutex);
159     readCondition.wait(lock, [&] { return idleReadConnectionCount > 0; });
160     SqliteConnection *connection = readConnections.back();
161     readConnections.pop_back();
162     idleReadConnectionCount--;
163     return connection;
164 }
165 
166 /**
167  * push connection back to last of connectionPool
168  * @param connection
169  */
ReleaseReadConnection(SqliteConnection * connection)170 void SqliteConnectionPool::ReleaseReadConnection(SqliteConnection *connection)
171 {
172     {
173         std::unique_lock<std::mutex> lock(readMutex);
174         readConnections.push_back(connection);
175         idleReadConnectionCount++;
176     }
177     readCondition.notify_one();
178 }
179 
IsOverLength(const std::vector<uint8_t> & newKey)180 bool SqliteConnectionPool::IsOverLength(const std::vector<uint8_t> &newKey)
181 {
182     if (newKey.empty()) {
183         return false;
184     }
185 
186     std::stringstream ss;
187     copy(newKey.begin(), newKey.end(), std::ostream_iterator<uint8_t>(ss, ""));
188     return ss.str().length() > LIMITATION;
189 }
190 
InnerReOpenReadConnections()191 int SqliteConnectionPool::InnerReOpenReadConnections()
192 {
193     int errCode = E_OK;
194     for (auto &item : readConnections) {
195         if (item != nullptr) {
196             delete item;
197             item = nullptr;
198         }
199     }
200     readConnections.clear();
201 
202     for (int i = 0; i < readConnectionCount; i++) {
203         SqliteConnection *connection = SqliteConnection::Open(config, false, errCode);
204         if (connection == nullptr) {
205             CloseAllConnections();
206             return errCode;
207         }
208         readConnections.push_back(connection);
209     }
210 
211     return errCode;
212 }
213 
214 
ReOpenAvailableReadConnections()215 int SqliteConnectionPool::ReOpenAvailableReadConnections()
216 {
217     std::unique_lock<std::mutex> lock(readMutex);
218     return InnerReOpenReadConnections();
219 }
220 
221 #ifdef RDB_SUPPORT_ICU
222 /**
223  * The database locale.
224  */
ConfigLocale(const std::string localeStr)225 int SqliteConnectionPool::ConfigLocale(const std::string localeStr)
226 {
227     std::unique_lock<std::mutex> lock(rdbMutex);
228     if (idleReadConnectionCount != readConnectionCount) {
229         return E_NO_ROW_IN_QUERY;
230     }
231 
232     for (int i = 0; i < idleReadConnectionCount; i++) {
233         SqliteConnection *connection = readConnections[i];
234         if (connection == nullptr) {
235             LOG_ERROR("Read Connection is null.");
236             return E_ERROR;
237         }
238         connection->ConfigLocale(localeStr);
239     }
240 
241     if (writeConnection == nullptr) {
242         LOG_ERROR("Write Connection is null.");
243         return E_ERROR;
244     } else {
245         writeConnection->ConfigLocale(localeStr);
246     }
247 
248     return E_OK;
249 }
250 #endif
251 
252 /**
253  * Rename the backed up database.
254  */
ChangeDbFileForRestore(const std::string newPath,const std::string backupPath,const std::vector<uint8_t> & newKey)255 int SqliteConnectionPool::ChangeDbFileForRestore(const std::string newPath, const std::string backupPath,
256     const std::vector<uint8_t> &newKey)
257 {
258     if (writeConnectionUsed == true || idleReadConnectionCount != readConnectionCount) {
259         LOG_ERROR("Connection pool is busy now!");
260         return E_ERROR;
261     }
262 
263     CloseAllConnections();
264 
265     std::string currentPath = config.GetPath();
266     bool ret = SqliteUtils::DeleteFile(currentPath);
267     if (ret == false) {
268         LOG_ERROR("DeleteFile error");
269     }
270     SqliteUtils::DeleteFile(currentPath + "-shm");
271     SqliteUtils::DeleteFile(currentPath + "-wal");
272     SqliteUtils::DeleteFile(currentPath + "-journal");
273 
274     if (currentPath != newPath) {
275         SqliteUtils::DeleteFile(newPath);
276         SqliteUtils::DeleteFile(newPath + "-shm");
277         SqliteUtils::DeleteFile(newPath + "-wal");
278         SqliteUtils::DeleteFile(newPath + "-journal");
279     }
280 
281     int retVal = SqliteUtils::RenameFile(backupPath, newPath);
282     if (retVal != E_OK) {
283         LOG_ERROR("RenameFile error");
284     }
285 
286     config.SetPath(newPath);
287     return Init();
288 }
289 
getTransactionStack()290 std::stack<BaseTransaction> &SqliteConnectionPool::getTransactionStack()
291 {
292     return transactionStack;
293 }
294 } // namespace NativeRdb
295 } // namespace OHOS
296