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