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