• 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 "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