1 /*
2 * Copyright (c) 2021 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 #define LOG_TAG "ShareBlock"
16 #include "share_block.h"
17
18 #include <unistd.h>
19
20 #include <algorithm>
21
22 #include "logger.h"
23 #include "shared_block_serializer_info.h"
24 #include "sqlite_errno.h"
25 #include "value_object.h"
26
27 namespace OHOS {
28 namespace NativeRdb {
29 using namespace OHOS::Rdb;
30
31 const int ERROR_STATUS = -1;
32 const unsigned int SLEEP_TIME = 1000;
33 // move to the highest 32 bits of 64 bits number
34 const int RETRY_TIME = 50;
35 const int PRINT_RETRY_TIMES = 10;
36
SeriAddRow(void * pCtx,int addedRows)37 int SeriAddRow(void *pCtx, int addedRows)
38 {
39 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
40 return serializer->AddRow(addedRows);
41 }
42
SeriReset(void * pCtx,int startPos)43 int SeriReset(void *pCtx, int startPos)
44 {
45 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
46 return serializer->Reset(startPos);
47 }
48
SeriFinish(void * pCtx,int addedRows,int totalRows)49 int SeriFinish(void *pCtx, int addedRows, int totalRows)
50 {
51 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
52 return serializer->Finish(addedRows, totalRows);
53 }
54
SeriPutString(void * pCtx,int addedRows,int column,const char * text,int size)55 int SeriPutString(void *pCtx, int addedRows, int column, const char *text, int size)
56 {
57 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
58 return serializer->PutString(addedRows, column, text, size);
59 }
60
SeriPutLong(void * pCtx,int addedRows,int column,sqlite3_int64 value)61 int SeriPutLong(void *pCtx, int addedRows, int column, sqlite3_int64 value)
62 {
63 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
64 return serializer->PutLong(addedRows, column, value);
65 }
66
SeriPutDouble(void * pCtx,int addedRows,int column,double value)67 int SeriPutDouble(void *pCtx, int addedRows, int column, double value)
68 {
69 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
70 return serializer->PutDouble(addedRows, column, value);
71 }
72
SeriPutBlob(void * pCtx,int addedRows,int column,const void * blob,int len)73 int SeriPutBlob(void *pCtx, int addedRows, int column, const void *blob, int len)
74 {
75 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
76 return serializer->PutBlob(addedRows, column, blob, len);
77 }
78
SeriPutNull(void * pCtx,int addedRows,int column)79 int SeriPutNull(void *pCtx, int addedRows, int column)
80 {
81 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
82 return serializer->PutNull(addedRows, column);
83 }
84
SeriPutOther(void * pCtx,int addedRows,int column)85 int SeriPutOther(void *pCtx, int addedRows, int column)
86 {
87 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
88 return serializer->PutOther(addedRows, column);
89 }
90
ClearSharedBlock(AppDataFwk::SharedBlock * sharedBlock)91 int ClearSharedBlock(AppDataFwk::SharedBlock *sharedBlock)
92 {
93 int status = sharedBlock->Clear();
94 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
95 return ERROR_STATUS;
96 }
97 return status;
98 }
99
SharedBlockSetColumnNum(AppDataFwk::SharedBlock * sharedBlock,int columnNum)100 int SharedBlockSetColumnNum(AppDataFwk::SharedBlock *sharedBlock, int columnNum)
101 {
102 int status = sharedBlock->SetColumnNum(columnNum);
103 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
104 return ERROR_STATUS;
105 }
106 return status;
107 }
108
FillSharedBlockOpt(SharedBlockInfo * info,sqlite3_stmt * stmt)109 int FillSharedBlockOpt(SharedBlockInfo *info, sqlite3_stmt *stmt)
110 {
111 SharedBlockSerializerInfo serializer(info->sharedBlock, stmt, info->columnNum, info->startPos);
112 Sqlite3SharedBlockMethods sqliteBlock =
113 (info->sharedBlock != nullptr)
114 ? Sqlite3SharedBlockMethods{ 1, &serializer, info->isCountAllRows, info->startPos, info->requiredPos,
115 SeriAddRow, SeriReset, SeriFinish, SeriPutString, SeriPutLong, SeriPutDouble, SeriPutBlob,
116 SeriPutNull, SeriPutOther }
117 : Sqlite3SharedBlockMethods{ 1, &serializer, true, 0, 0, DefAddRow, DefReset, DefFinish, DefPutString,
118 DefPutLong, DefPutDouble, DefPutBlob, DefPutNull, DefPutOther };
119
120 auto db = sqlite3_db_handle(stmt);
121 int cfgErr = sqlite3_db_config(db, SQLITE_DBCONFIG_SET_SHAREDBLOCK, stmt, &sqliteBlock);
122 if (cfgErr != SQLITE_OK) {
123 LOG_ERROR("set sqlite shared block methods error. err=%{public}d, errno=%{public}d", cfgErr, errno);
124 return SQLiteError::ErrNo(cfgErr);
125 }
126 int retryCount = 0;
127 int errCode = SQLITE_OK;
128 while (true) {
129 errCode = sqlite3_step(stmt);
130 if (errCode == SQLITE_LOCKED || errCode == SQLITE_BUSY) {
131 LOG_WARN("Database locked, retrying errCode=%{public}d, errno=%{public}d", errCode, errno);
132 if (retryCount <= RETRY_TIME) {
133 usleep(SLEEP_TIME);
134 retryCount++;
135 continue;
136 }
137 }
138 break;
139 }
140 info->totalRows = serializer.GetTotalRows();
141 info->startPos = serializer.GetStartPos();
142 info->addedRows = serializer.GetAddedRows();
143
144 if (errCode == SQLITE_DONE || errCode == SQLITE_ROW) {
145 errCode = SQLITE_OK;
146 }
147
148 cfgErr = sqlite3_db_config(db, SQLITE_DBCONFIG_SET_SHAREDBLOCK, stmt, nullptr);
149 if (cfgErr != SQLITE_OK || (errCode != SQLITE_OK) || retryCount > PRINT_RETRY_TIMES) {
150 LOG_ERROR("failed, cfgErr=%{public}d errCode=%{public}d retry=%{public}d", cfgErr, errCode, retryCount);
151 }
152 return SQLiteError::ErrNo(errCode);
153 }
154
FillSharedBlock(SharedBlockInfo * info,sqlite3_stmt * stmt)155 int FillSharedBlock(SharedBlockInfo *info, sqlite3_stmt *stmt)
156 {
157 int retryCount = 0;
158 info->totalRows = info->addedRows = 0;
159 bool isFull = false;
160 bool hasException = false;
161 auto fillRow = info->sharedBlock == nullptr ? DefFillRow : FillRow;
162 while (!hasException && (!isFull || info->isCountAllRows)) {
163 int err = sqlite3_step(stmt);
164 if (err == SQLITE_ROW) {
165 retryCount = 0;
166 info->totalRows += 1;
167 if (info->startPos >= info->totalRows || isFull) {
168 continue;
169 }
170 fillRow(info, stmt);
171 isFull = info->isFull;
172 hasException = info->hasException;
173 } else if (err == SQLITE_DONE) {
174 LOG_WARN("Processed all rows.");
175 break;
176 } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
177 LOG_WARN("Database locked, retrying");
178 if (retryCount > RETRY_TIME) {
179 LOG_ERROR("Bailing on database busy retry.");
180 hasException = true;
181 return E_DATABASE_BUSY;
182 } else {
183 usleep(SLEEP_TIME);
184 retryCount++;
185 }
186 } else {
187 hasException = true;
188 return SQLiteError::ErrNo(err);
189 }
190 }
191 return E_OK;
192 }
193
FillRow(SharedBlockInfo * info,sqlite3_stmt * stmt)194 void FillRow(SharedBlockInfo *info, sqlite3_stmt *stmt)
195 {
196 FillOneRowResult fillOneRowResult =
197 FillOneRow(info->sharedBlock, stmt, info->columnNum, info->startPos, info->addedRows);
198 if (fillOneRowResult == SHARED_BLOCK_IS_FULL && info->addedRows &&
199 info->startPos + info->addedRows <= info->requiredPos) {
200 info->sharedBlock->Clear();
201 info->sharedBlock->SetColumnNum(info->columnNum);
202 info->startPos += info->addedRows;
203 info->addedRows = 0;
204 fillOneRowResult = FillOneRow(info->sharedBlock, stmt, info->columnNum, info->startPos, info->addedRows);
205 }
206
207 if (fillOneRowResult == FILL_ONE_ROW_SUCESS) {
208 info->addedRows += 1;
209 } else if (fillOneRowResult == SHARED_BLOCK_IS_FULL) {
210 info->isFull = true;
211 } else {
212 info->hasException = true;
213 }
214 }
215
FillOneRow(AppDataFwk::SharedBlock * sharedBlock,sqlite3_stmt * statement,int numColumns,int startPos,int addedRows)216 FillOneRowResult FillOneRow(
217 AppDataFwk::SharedBlock *sharedBlock, sqlite3_stmt *statement, int numColumns, int startPos, int addedRows)
218 {
219 int status = sharedBlock->AllocRow();
220 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
221 LOG_ERROR("Failed allocating fieldDir at startPos %{public}d row %{public}d, error=%{public}d", startPos,
222 addedRows, status);
223 return SHARED_BLOCK_IS_FULL;
224 }
225
226 FillOneRowResult result = FILL_ONE_ROW_SUCESS;
227 for (int i = 0; i < numColumns; i++) {
228 int type = sqlite3_column_type(statement, i);
229 if (type == SQLITE_TEXT) {
230 // TEXT data
231 result = FillOneRowOfString(sharedBlock, statement, startPos, addedRows, i);
232 } else if (type == SQLITE_INTEGER) {
233 // INTEGER data
234 result = FillOneRowOfLong(sharedBlock, statement, startPos, addedRows, i);
235 } else if (type == SQLITE_FLOAT) {
236 // FLOAT data
237 result = FillOneRowOfFloat(sharedBlock, statement, startPos, addedRows, i);
238 } else if (type == SQLITE_BLOB) {
239 // BLOB data
240 result = FillOneRowOfBlob(sharedBlock, statement, startPos, addedRows, i);
241 } else if (type == SQLITE_NULL) {
242 // NULL field
243 result = FillOneRowOfNull(sharedBlock, statement, startPos, addedRows, i);
244 } else {
245 // Unknown data
246 LOG_ERROR("Unknown column type when filling database shared block.");
247 result = FILL_ONE_ROW_FAIL;
248 break;
249 }
250
251 if (result == SHARED_BLOCK_IS_FULL) {
252 break;
253 }
254 }
255
256 // Free the last row if if was not successfully copied.
257 if (result != FILL_ONE_ROW_SUCESS) {
258 sharedBlock->FreeLastRow();
259 }
260 return result;
261 }
262
FillOneRowOfString(AppDataFwk::SharedBlock * sharedBlock,sqlite3_stmt * statement,int startPos,int addedRows,int pos)263 FillOneRowResult FillOneRowOfString(
264 AppDataFwk::SharedBlock *sharedBlock, sqlite3_stmt *statement, int startPos, int addedRows, int pos)
265 {
266 const char *text = reinterpret_cast<const char *>(sqlite3_column_text(statement, pos));
267 if (text == nullptr) {
268 LOG_ERROR("Text is null.");
269 return SHARED_BLOCK_IS_FULL;
270 }
271
272 auto sizeIncludingNull = sqlite3_column_bytes(statement, pos) + 1;
273 int status = sharedBlock->PutString(addedRows, pos, text, sizeIncludingNull);
274 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
275 LOG_ERROR("Failed allocating %{public}d bytes for text at %{public}d,%{public}d, error=%{public}d",
276 sizeIncludingNull, startPos + addedRows, pos, status);
277 return SHARED_BLOCK_IS_FULL;
278 }
279
280 return FILL_ONE_ROW_SUCESS;
281 }
282
FillOneRowOfLong(AppDataFwk::SharedBlock * sharedBlock,sqlite3_stmt * statement,int startPos,int addedRows,int pos)283 FillOneRowResult FillOneRowOfLong(
284 AppDataFwk::SharedBlock *sharedBlock, sqlite3_stmt *statement, int startPos, int addedRows, int pos)
285 {
286 int64_t value = sqlite3_column_int64(statement, pos);
287 int status = sharedBlock->PutLong(addedRows, pos, value);
288 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
289 LOG_ERROR("Failed allocating space for a long in column %{public}d, error=%{public}d", pos, status);
290 return SHARED_BLOCK_IS_FULL;
291 }
292
293 return FILL_ONE_ROW_SUCESS;
294 }
295
FillOneRowOfFloat(AppDataFwk::SharedBlock * sharedBlock,sqlite3_stmt * statement,int startPos,int addedRows,int pos)296 FillOneRowResult FillOneRowOfFloat(
297 AppDataFwk::SharedBlock *sharedBlock, sqlite3_stmt *statement, int startPos, int addedRows, int pos)
298 {
299 double value = sqlite3_column_double(statement, pos);
300 int status = sharedBlock->PutDouble(addedRows, pos, value);
301 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
302 LOG_ERROR("Failed allocating space for a double in column %{public}d, error=%{public}d", pos, status);
303 return SHARED_BLOCK_IS_FULL;
304 }
305
306 return FILL_ONE_ROW_SUCESS;
307 }
308
FillOneRowOfBlob(AppDataFwk::SharedBlock * sharedBlock,sqlite3_stmt * statement,int startPos,int addedRows,int pos)309 FillOneRowResult FillOneRowOfBlob(
310 AppDataFwk::SharedBlock *sharedBlock, sqlite3_stmt *statement, int startPos, int addedRows, int pos)
311 {
312 auto action = &AppDataFwk::SharedBlock::PutBlob;
313 auto *declType = sqlite3_column_decltype(statement, pos);
314 if (declType != nullptr) {
315 std::string type(declType);
316 std::transform(type.begin(), type.end(), type.begin(), [](auto ch) { return std::toupper(ch); });
317 action = (type == ValueObject::DeclType<ValueObject::Asset>()) ? &AppDataFwk::SharedBlock::PutAsset
318 : (type == ValueObject::DeclType<ValueObject::Assets>()) ? &AppDataFwk::SharedBlock::PutAssets
319 : (type == ValueObject::DeclType<ValueObject::FloatVector>()) ? &AppDataFwk::SharedBlock::PutFloats
320 : (type == ValueObject::DeclType<ValueObject::BigInt>()) ? &AppDataFwk::SharedBlock::PutBigInt
321 : &AppDataFwk::SharedBlock::PutBlob;
322 }
323
324 const void *blob = sqlite3_column_blob(statement, pos);
325 auto size = sqlite3_column_bytes(statement, pos);
326 int status = (sharedBlock->*action)(addedRows, pos, blob, size);
327 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
328 LOG_ERROR("Failed allocating %{public}d bytes for blob at %{public}d,%{public}d, error=%{public}d", size,
329 startPos + addedRows, pos, status);
330 return SHARED_BLOCK_IS_FULL;
331 }
332
333 return FILL_ONE_ROW_SUCESS;
334 }
335
FillOneRowOfNull(AppDataFwk::SharedBlock * sharedBlock,sqlite3_stmt * statement,int startPos,int addedRows,int pos)336 FillOneRowResult FillOneRowOfNull(
337 AppDataFwk::SharedBlock *sharedBlock, sqlite3_stmt *statement, int startPos, int addedRows, int pos)
338 {
339 int status = sharedBlock->PutNull(addedRows, pos);
340 if (status != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
341 LOG_ERROR("Failed allocating space for a null in column %{public}d, error=%{public}d", pos, status);
342 return SHARED_BLOCK_IS_FULL;
343 }
344 return FILL_ONE_ROW_SUCESS;
345 }
346
ResetStatement(SharedBlockInfo * info,sqlite3_stmt * stmt)347 bool ResetStatement(SharedBlockInfo *info, sqlite3_stmt *stmt)
348 {
349 sqlite3_reset(stmt);
350 if (info->startPos > info->totalRows) {
351 LOG_ERROR("startPos %{public}d > actual rows %{public}d", info->startPos, info->totalRows);
352 }
353
354 if ((info->totalRows > 0 && info->addedRows == 0) && info->sharedBlock != nullptr) {
355 LOG_WARN("over 2MB[%{public}d, %{public}d]", info->totalRows, info->addedRows);
356 return false;
357 }
358 return true;
359 }
360
DefAddRow(void * pCtx,int addedRows)361 int DefAddRow(void *pCtx, int addedRows)
362 {
363 return SQLITE_FULL;
364 }
365
DefReset(void * pCtx,int startPos)366 int DefReset(void *pCtx, int startPos)
367 {
368 return SQLITE_OK;
369 }
370
DefFinish(void * pCtx,int addedRows,int totalRows)371 int DefFinish(void *pCtx, int addedRows, int totalRows)
372 {
373 auto *serializer = static_cast<SharedBlockSerializerInfo *>(pCtx);
374 return serializer->Finish(addedRows, totalRows);
375 }
376
DefPutString(void * pCtx,int addedRows,int column,const char * text,int size)377 int DefPutString(void *pCtx, int addedRows, int column, const char *text, int size)
378 {
379 return SQLITE_FULL;
380 }
381
DefPutLong(void * pCtx,int addedRows,int column,sqlite3_int64 value)382 int DefPutLong(void *pCtx, int addedRows, int column, sqlite3_int64 value)
383 {
384 return SQLITE_FULL;
385 }
386
DefPutDouble(void * pCtx,int addedRows,int column,double value)387 int DefPutDouble(void *pCtx, int addedRows, int column, double value)
388 {
389 return SQLITE_FULL;
390 }
391
DefPutBlob(void * pCtx,int addedRows,int column,const void * blob,int len)392 int DefPutBlob(void *pCtx, int addedRows, int column, const void *blob, int len)
393 {
394 return SQLITE_FULL;
395 }
396
DefPutNull(void * pCtx,int addedRows,int column)397 int DefPutNull(void *pCtx, int addedRows, int column)
398 {
399 return SQLITE_FULL;
400 }
401
DefPutOther(void * pCtx,int addedRows,int column)402 int DefPutOther(void *pCtx, int addedRows, int column)
403 {
404 return SQLITE_FULL;
405 }
406
DefFillRow(SharedBlockInfo * info,sqlite3_stmt * stmt)407 void DefFillRow(SharedBlockInfo *info, sqlite3_stmt *stmt)
408 {
409 info->isFull = true;
410 }
411 } // namespace NativeRdb
412 } // namespace OHOS