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