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