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