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 "sqlite_single_ver_result_set.h"
17 #include <algorithm>
18 #include "log_print.h"
19 #include "db_errno.h"
20 #include "sqlite_single_ver_forward_cursor.h"
21 #include "sqlite_single_ver_natural_store.h"
22 #include "sqlite_single_ver_storage_executor.h"
23 
24 namespace DistributedDB {
25 namespace {
26     const int64_t MEM_WINDOW_SIZE = 0xFFFFFFFF; // 4G for max
27     const double MEM_WINDOW_SCALE = 0.5; // set default window size to 2G
28     const double DEFAULT_WINDOW_SCALE = 1; // For non-mem db
29     const int64_t WINDOW_SIZE_MB_UNIT = 1024 * 1024; // 1024 is scale
30 }
31 
SQLiteSingleVerResultSet(SQLiteSingleVerNaturalStore * kvDB,const Key & keyPrefix,const Option & option)32 SQLiteSingleVerResultSet::SQLiteSingleVerResultSet(SQLiteSingleVerNaturalStore *kvDB, const Key &keyPrefix,
33     const Option& option) : option_(option), type_(ResultSetType::KEYPREFIX), keyPrefix_(keyPrefix), kvDB_(kvDB) {}
34 
SQLiteSingleVerResultSet(SQLiteSingleVerNaturalStore * kvDB,const QueryObject & queryObj,const Option & option)35 SQLiteSingleVerResultSet::SQLiteSingleVerResultSet(SQLiteSingleVerNaturalStore *kvDB, const QueryObject &queryObj,
36     const Option& option) : option_(option), type_(ResultSetType::QUERY), queryObj_(queryObj), kvDB_(kvDB) {}
37 
~SQLiteSingleVerResultSet()38 SQLiteSingleVerResultSet::~SQLiteSingleVerResultSet()
39 {
40     isOpen_ = false;
41     count_ = 0;
42     position_ = INIT_POSITION;
43     kvDB_ = nullptr;
44     window_ = nullptr;
45     rawCursor_ = nullptr;
46     handle_ = nullptr;
47     cacheStartPosition_ = INIT_POSITION;
48 }
49 
50 // The user get KvStoreResultSet after Open function called, so no need mutex during open procedure
Open(bool isMemDb)51 int SQLiteSingleVerResultSet::Open(bool isMemDb)
52 {
53     if (isOpen_) {
54         return E_OK;
55     }
56     if (kvDB_ == nullptr) { // Unlikely
57         return -E_INVALID_ARGS;
58     }
59     if (option_.cacheMode == ResultSetCacheMode::CACHE_FULL_ENTRY) {
60         return OpenForCacheFullEntryMode(isMemDb);
61     } else {
62         return OpenForCacheEntryIdMode();
63     }
64 }
65 
OpenForCacheFullEntryMode(bool isMemDb)66 int SQLiteSingleVerResultSet::OpenForCacheFullEntryMode(bool isMemDb)
67 {
68     if (type_ == ResultSetType::KEYPREFIX) {
69         rawCursor_ = new (std::nothrow) SQLiteSingleVerForwardCursor(kvDB_, keyPrefix_);
70     } else {
71         rawCursor_ = new (std::nothrow) SQLiteSingleVerForwardCursor(kvDB_, queryObj_);
72     }
73     if (rawCursor_ == nullptr) {
74         LOGE("[SqlSinResSet][OpenForEntry] OOM When Create ForwardCursor.");
75         return E_OUT_OF_MEMORY;
76     }
77     window_ = new (std::nothrow) ResultEntriesWindow();
78     if (window_ == nullptr) {
79         LOGE("[SqlSinResSet][OpenForEntry] OOM When Create EntryWindow.");
80         delete rawCursor_;
81         rawCursor_ = nullptr;
82         return -E_OUT_OF_MEMORY;
83     }
84     // cacheMaxSize is within [1,16]
85     int64_t windowSize = isMemDb ? MEM_WINDOW_SIZE : (option_.cacheMaxSize * WINDOW_SIZE_MB_UNIT);
86     double scale = isMemDb ? MEM_WINDOW_SCALE : DEFAULT_WINDOW_SCALE;
87     int errCode = window_->Init(rawCursor_, windowSize, scale);
88     if (errCode != E_OK) {
89         LOGE("[SqlSinResSet][OpenForEntry] EntryWindow Init Fail, ErrCode=%d.", errCode);
90         delete window_;
91         window_ = nullptr;
92         delete rawCursor_;
93         rawCursor_ = nullptr;
94         return errCode;
95     }
96     count_ = window_->GetTotalCount();
97     isOpen_ = true;
98     LOGD("[SqlSinResSet][OpenForEntry] Type=%d, CacheMaxSize=%d(MB), Count=%d, IsMem=%d.", static_cast<int>(type_),
99         option_.cacheMaxSize, count_, isMemDb);
100     return E_OK;
101 }
102 
OpenForCacheEntryIdMode()103 int SQLiteSingleVerResultSet::OpenForCacheEntryIdMode()
104 {
105     int errCode = E_OK;
106     handle_ = kvDB_->GetHandle(false, errCode);
107     if (handle_ == nullptr) {
108         LOGE("[SqlSinResSet][OpenForRowId] Get handle fail, errCode=%d.", errCode);
109         return errCode;
110     }
111     // cacheMaxSize is within [1,16], rowId is of type int64_t
112     uint32_t cacheLimit = option_.cacheMaxSize * (WINDOW_SIZE_MB_UNIT / sizeof(int64_t));
113     if (type_ == ResultSetType::KEYPREFIX) {
114         errCode = handle_->OpenResultSetForCacheRowIdMode(keyPrefix_, cachedRowIds_, cacheLimit, count_);
115     } else {
116         errCode = handle_->OpenResultSetForCacheRowIdMode(queryObj_, cachedRowIds_, cacheLimit, count_);
117     }
118     if (errCode != E_OK) {
119         LOGE("[SqlSinResSet][OpenForRowId] Open ResultSet fail, errCode=%d.", errCode);
120         kvDB_->ReleaseHandle(handle_);
121         cachedRowIds_.clear();
122         return errCode;
123     }
124     // If no result, then nothing is cached, so the cacheStartPosition_ is still INIT_POSITION
125     if (count_ != 0) {
126         cacheStartPosition_ = 0;
127     }
128     isOpen_ = true;
129     LOGD("[SqlSinResSet][OpenForRowId] Type=%d, CacheMaxSize=%d(MB), Count=%d, Cached=%zu.", static_cast<int>(type_),
130         option_.cacheMaxSize, count_, cachedRowIds_.size());
131     return E_OK;
132 }
133 
GetCount() const134 int SQLiteSingleVerResultSet::GetCount() const
135 {
136     // count_ never changed after ResultSet opened
137     return count_;
138 }
139 
GetPosition() const140 int SQLiteSingleVerResultSet::GetPosition() const
141 {
142     std::lock_guard<std::mutex> lockGuard(mutex_);
143     return position_;
144 }
145 
Move(int offset) const146 int SQLiteSingleVerResultSet::Move(int offset) const
147 {
148     int64_t position = GetPosition();
149     int64_t aimPos = position + offset;
150     if (aimPos > INT_MAX) {
151         return MoveTo(INT_MAX);
152     }
153     if (aimPos < INIT_POSITION) {
154         return MoveTo(INIT_POSITION);
155     }
156     return MoveTo(aimPos);
157 }
158 
MoveTo(int position) const159 int SQLiteSingleVerResultSet::MoveTo(int position) const
160 {
161     std::lock_guard<std::mutex> lockGuard(mutex_);
162     if (!isOpen_) {
163         return -E_RESULT_SET_STATUS_INVALID;
164     }
165     if (count_ == 0) {
166         position_ = (position >= 0) ? 0 : INIT_POSITION;
167         LOGW("[SqlSinResSet][MoveTo] Empty ResultSet.");
168         return -E_RESULT_SET_EMPTY;
169     }
170     if (position < 0) {
171         position_ = INIT_POSITION;
172         LOGW("[SqlSinResSet][MoveTo] Target Position=%d invalid.", position);
173         return -E_INVALID_ARGS;
174     }
175     if (position >= count_) {
176         position_ = count_;
177         LOGW("[SqlSinResSet][MoveTo] Target Position=%d Exceed Count=%d.", position, count_);
178         return -E_INVALID_ARGS;
179     }
180     if (position_ == position) {
181         return E_OK;
182     }
183     if (option_.cacheMode == ResultSetCacheMode::CACHE_FULL_ENTRY) {
184         return MoveToForCacheFullEntryMode(position);
185     } else {
186         return MoveToForCacheEntryIdMode(position);
187     }
188 }
189 
MoveToFirst()190 int SQLiteSingleVerResultSet::MoveToFirst()
191 {
192     return MoveTo(0);
193 }
194 
MoveToLast()195 int SQLiteSingleVerResultSet::MoveToLast()
196 {
197     return MoveTo(GetCount() - 1);
198 }
199 
IsFirst() const200 bool SQLiteSingleVerResultSet::IsFirst() const
201 {
202     int position = GetPosition();
203     if (GetCount() == 0) {
204         return false;
205     }
206     if (position == 0) {
207         return true;
208     }
209     return false;
210 }
211 
IsLast() const212 bool SQLiteSingleVerResultSet::IsLast() const
213 {
214     int position = GetPosition();
215     int count = GetCount();
216     if (count == 0) {
217         return false;
218     }
219     if (position == (count - 1)) {
220         return true;
221     }
222     return false;
223 }
224 
IsBeforeFirst() const225 bool SQLiteSingleVerResultSet::IsBeforeFirst() const
226 {
227     int position = GetPosition();
228 
229     if (GetCount() == 0) {
230         return true;
231     }
232     if (position <= INIT_POSITION) {
233         return true;
234     }
235     return false;
236 }
237 
IsAfterLast() const238 bool SQLiteSingleVerResultSet::IsAfterLast() const
239 {
240     int position = GetPosition();
241     int count = GetCount();
242     if (count == 0) {
243         return true;
244     }
245     if (position >= count) {
246         return true;
247     }
248     return false;
249 }
250 
MoveToForCacheFullEntryMode(int position) const251 int SQLiteSingleVerResultSet::MoveToForCacheFullEntryMode(int position) const
252 {
253     if (window_->MoveToPosition(position)) {
254         position_ = position;
255         return E_OK;
256     }
257     position_ = INIT_POSITION;
258     LOGE("[SqlSinResSet][MoveForEntry] Move to position=%d fail.", position);
259     return -E_UNEXPECTED_DATA;
260 }
261 
MoveToForCacheEntryIdMode(int position) const262 int SQLiteSingleVerResultSet::MoveToForCacheEntryIdMode(int position) const
263 {
264     // The parameter position now is in [0, count_) with this resultSet not empty
265     // cacheEndPosition is just after cachedRowIds_, the cached range is [cacheStartPosition_, cacheEndPosition)
266     int cacheEndPosition = cacheStartPosition_ + cachedRowIds_.size();
267     if (position >= cacheStartPosition_ && position < cacheEndPosition) {
268         // Already in the cachedRowId range, Just move position
269         position_ = position;
270         return E_OK;
271     }
272     // Not in the cachedRowId range, but valid position, we should reload the cachedRowIds to contain this position
273     int newCacheStartPos = position;
274     // cacheMaxSize is within [1,16], rowId is of type int64_t
275     uint32_t cacheLimit = option_.cacheMaxSize * (WINDOW_SIZE_MB_UNIT / sizeof(int64_t));
276     if (position > cacheStartPosition_) {
277         // Move Forward
278         int newCacheEndPos = newCacheStartPos + cacheLimit;
279         if (newCacheEndPos > count_) {
280             // Since startPos in [0, count_), So the right in (0, cacheLimit), So position still in range
281             newCacheStartPos -= (newCacheEndPos - count_);
282         }
283     } else {
284         // Move Backward
285         newCacheStartPos -= (cacheLimit - 1); // Attention, subtract by 1 to ensure position still in range
286     }
287     newCacheStartPos = std::max(newCacheStartPos, 0); // Adjust to at least 0 if less then 0
288     // Clear rowId cache to accept new rowIds
289     cachedRowIds_.clear();
290     int errCode;
291     if (type_ == ResultSetType::KEYPREFIX) {
292         errCode = handle_->ReloadResultSetForCacheRowIdMode(keyPrefix_, cachedRowIds_, cacheLimit, newCacheStartPos);
293     } else {
294         errCode = handle_->ReloadResultSetForCacheRowIdMode(queryObj_, cachedRowIds_, cacheLimit, newCacheStartPos);
295     }
296     if (errCode != E_OK) {
297         LOGE("[SqlSinResSet][MoveForRowid] Move to position=%d, Reload fail, errCode=%d.", position, errCode);
298         // What else shall we do if error happened ?
299         cachedRowIds_.clear();
300         cacheStartPosition_ = INIT_POSITION;
301         position_ = INIT_POSITION; // Reset Position As MoveForEntry Do
302         return -E_UNEXPECTED_DATA;
303     }
304     LOGD("[SqlSinResSet][MoveForRowid] Reload: position=%d, cacheStartPos=%d, cached=%zu, count=%d.",
305         position, newCacheStartPos, cachedRowIds_.size(), count_);
306     // Everything OK
307     position_ = position;
308     cacheStartPosition_ = newCacheStartPos;
309     return E_OK;
310 }
311 
GetEntry(Entry & entry) const312 int SQLiteSingleVerResultSet::GetEntry(Entry &entry) const
313 {
314     std::lock_guard<std::mutex> lockGuard(mutex_);
315     if (!isOpen_ || count_ == 0) {
316         return -E_NO_SUCH_ENTRY;
317     }
318     if (position_ > INIT_POSITION && position_ < count_) {
319         // If position_ in the valid range, it can be guaranteed that everything is ok without errors
320         if (option_.cacheMode == ResultSetCacheMode::CACHE_FULL_ENTRY) {
321             return window_->GetEntry(entry);
322         } else {
323             // It can be guaranteed position_ in the range [cacheStartPosition_, cacheEndPosition)
324             // For CodeDex false alarm, we still do the check which is not necessary
325             int cacheIndex = position_ - cacheStartPosition_;
326             if (cacheIndex < 0 || cacheIndex >= static_cast<int>(cachedRowIds_.size())) { // Not Possible
327                 LOGE("[SqlSinResSet][GetEntry] Internal Error: Position=%d, CacheStartPos=%d, cached=%zu.", position_,
328                     cacheStartPosition_, cachedRowIds_.size());
329                 return -E_INTERNAL_ERROR;
330             }
331             int errCode = handle_->GetEntryByRowId(cachedRowIds_[cacheIndex], entry);
332             if (errCode != E_OK) {
333                 LOGE("[SqlSinResSet][GetEntry] GetEntryByRowId fail, errCode=%d.", errCode);
334                 return errCode;
335             }
336             return E_OK;
337         }
338     }
339     return -E_NO_SUCH_ENTRY;
340 }
341 
Close()342 int SQLiteSingleVerResultSet::Close()
343 {
344     std::lock_guard<std::mutex> lockGuard(mutex_);
345     if (!isOpen_) {
346         return E_OK;
347     }
348     if (option_.cacheMode == ResultSetCacheMode::CACHE_FULL_ENTRY) {
349         CloseForCacheFullEntryMode();
350     } else {
351         CloseForCacheEntryIdMode();
352     }
353     isOpen_ = false;
354     count_ = 0;
355     position_ = INIT_POSITION;
356     LOGD("[SqlSinResSet][Close] Done, Type=%d, Mode=%d.", static_cast<int>(type_), static_cast<int>(option_.cacheMode));
357     return E_OK;
358 }
359 
CloseForCacheFullEntryMode()360 void SQLiteSingleVerResultSet::CloseForCacheFullEntryMode()
361 {
362     // Attention! Must Delete EntryWindow First(will call ForwardCursor::Close), then delete ForwardCursor.
363     // ForwardCursor::Close will call Executor::CloseResultSet(Reset the statement and rollback transaction)
364     delete window_; // It is defined behavior to delete even a nullptr
365     window_ = nullptr;
366     // Attention! Delete ForwardCursor Later.
367     delete rawCursor_; // It is defined behavior to delete even a nullptr
368     rawCursor_ = nullptr;
369 }
370 
CloseForCacheEntryIdMode()371 void SQLiteSingleVerResultSet::CloseForCacheEntryIdMode()
372 {
373     cacheStartPosition_ = INIT_POSITION;
374     cachedRowIds_.clear();
375     // In Fact : handle_ and kvDB_ is guaranteed to be not nullptr
376     if (handle_ != nullptr) {
377         handle_->CloseResultSet();
378         kvDB_->ReleaseHandle(handle_);
379     }
380 }
381 } // namespace DistributedDB
382