IndexedDB 2.0: Prefetch cursor records in the server.
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / SQLiteIDBCursor.cpp
1 /*
2  * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "SQLiteIDBCursor.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBCursorInfo.h"
32 #include "IDBGetResult.h"
33 #include "IDBSerialization.h"
34 #include "Logging.h"
35 #include "SQLiteIDBBackingStore.h"
36 #include "SQLiteIDBTransaction.h"
37 #include "SQLiteStatement.h"
38 #include "SQLiteTransaction.h"
39 #include <sqlite3.h>
40 #include <wtf/text/StringBuilder.h>
41
42 namespace WebCore {
43 namespace IDBServer {
44
45 static const size_t prefetchLimit = 8;
46
47 std::unique_ptr<SQLiteIDBCursor> SQLiteIDBCursor::maybeCreate(SQLiteIDBTransaction& transaction, const IDBCursorInfo& info)
48 {
49     auto cursor = std::make_unique<SQLiteIDBCursor>(transaction, info);
50
51     if (!cursor->establishStatement())
52         return nullptr;
53
54     if (!cursor->advance(1))
55         return nullptr;
56
57     return cursor;
58 }
59
60 std::unique_ptr<SQLiteIDBCursor> SQLiteIDBCursor::maybeCreateBackingStoreCursor(SQLiteIDBTransaction& transaction, const uint64_t objectStoreID, const uint64_t indexID, const IDBKeyRangeData& range)
61 {
62     auto cursor = std::make_unique<SQLiteIDBCursor>(transaction, objectStoreID, indexID, range);
63
64     if (!cursor->establishStatement())
65         return nullptr;
66
67     if (!cursor->advance(1))
68         return nullptr;
69
70     return cursor;
71 }
72
73 SQLiteIDBCursor::SQLiteIDBCursor(SQLiteIDBTransaction& transaction, const IDBCursorInfo& info)
74     : m_transaction(&transaction)
75     , m_cursorIdentifier(info.identifier())
76     , m_objectStoreID(info.objectStoreIdentifier())
77     , m_indexID(info.cursorSource() == IndexedDB::CursorSource::Index ? info.sourceIdentifier() : IDBIndexInfo::InvalidId)
78     , m_cursorDirection(info.cursorDirection())
79     , m_cursorType(info.cursorType())
80     , m_keyRange(info.range())
81 {
82     ASSERT(m_objectStoreID);
83 }
84
85 SQLiteIDBCursor::SQLiteIDBCursor(SQLiteIDBTransaction& transaction, const uint64_t objectStoreID, const uint64_t indexID, const IDBKeyRangeData& range)
86     : m_transaction(&transaction)
87     , m_cursorIdentifier(transaction.transactionIdentifier())
88     , m_objectStoreID(objectStoreID)
89     , m_indexID(indexID ? indexID : IDBIndexInfo::InvalidId)
90     , m_cursorDirection(IndexedDB::CursorDirection::Next)
91     , m_cursorType(IndexedDB::CursorType::KeyAndValue)
92     , m_keyRange(range)
93     , m_backingStoreCursor(true)
94 {
95     ASSERT(m_objectStoreID);
96 }
97
98 SQLiteIDBCursor::~SQLiteIDBCursor()
99 {
100     if (m_backingStoreCursor)
101         m_transaction->closeCursor(*this);
102 }
103
104 void SQLiteIDBCursor::currentData(IDBGetResult& result)
105 {
106     ASSERT(!m_fetchedRecords.isEmpty());
107
108     auto& currentRecord = m_fetchedRecords.first();
109     if (currentRecord.completed) {
110         ASSERT(!currentRecord.errored);
111         result = { };
112         return;
113     }
114
115     result = { currentRecord.record.key, currentRecord.record.primaryKey, currentRecord.record.value ? *currentRecord.record.value : IDBValue() };
116 }
117
118 static String buildIndexStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)
119 {
120     StringBuilder builder;
121
122     builder.appendLiteral("SELECT rowid, key, value FROM IndexRecords WHERE indexID = ? AND objectStoreID = ? AND key ");
123     if (!keyRange.lowerKey.isNull() && !keyRange.lowerOpen)
124         builder.appendLiteral(">=");
125     else
126         builder.append('>');
127
128     builder.appendLiteral(" CAST(? AS TEXT) AND key ");
129     if (!keyRange.upperKey.isNull() && !keyRange.upperOpen)
130         builder.appendLiteral("<=");
131     else
132         builder.append('<');
133
134     builder.appendLiteral(" CAST(? AS TEXT) ORDER BY key");
135     if (cursorDirection == IndexedDB::CursorDirection::Prev || cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate)
136         builder.appendLiteral(" DESC");
137
138     builder.appendLiteral(", value");
139     if (cursorDirection == IndexedDB::CursorDirection::Prev)
140         builder.appendLiteral(" DESC");
141
142     builder.append(';');
143
144     return builder.toString();
145 }
146
147 static String buildObjectStoreStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)
148 {
149     StringBuilder builder;
150
151     builder.appendLiteral("SELECT rowid, key, value FROM Records WHERE objectStoreID = ? AND key ");
152
153     if (!keyRange.lowerKey.isNull() && !keyRange.lowerOpen)
154         builder.appendLiteral(">=");
155     else
156         builder.append('>');
157
158     builder.appendLiteral(" CAST(? AS TEXT) AND key ");
159
160     if (!keyRange.upperKey.isNull() && !keyRange.upperOpen)
161         builder.appendLiteral("<=");
162     else
163         builder.append('<');
164
165     builder.appendLiteral(" CAST(? AS TEXT) ORDER BY key");
166
167     if (cursorDirection == IndexedDB::CursorDirection::Prev || cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate)
168         builder.appendLiteral(" DESC");
169
170     builder.append(';');
171
172     return builder.toString();
173 }
174
175 bool SQLiteIDBCursor::establishStatement()
176 {
177     ASSERT(!m_statement);
178     String sql;
179
180     if (m_indexID != IDBIndexInfo::InvalidId) {
181         sql = buildIndexStatement(m_keyRange, m_cursorDirection);
182         m_boundID = m_indexID;
183     } else {
184         sql = buildObjectStoreStatement(m_keyRange, m_cursorDirection);
185         m_boundID = m_objectStoreID;
186     }
187
188     m_currentLowerKey = m_keyRange.lowerKey.isNull() ? IDBKeyData::minimum() : m_keyRange.lowerKey;
189     m_currentUpperKey = m_keyRange.upperKey.isNull() ? IDBKeyData::maximum() : m_keyRange.upperKey;
190
191     return createSQLiteStatement(sql);
192 }
193
194 bool SQLiteIDBCursor::createSQLiteStatement(const String& sql)
195 {
196     LOG(IndexedDB, "Creating cursor with SQL query: \"%s\"", sql.utf8().data());
197
198     ASSERT(!m_currentLowerKey.isNull());
199     ASSERT(!m_currentUpperKey.isNull());
200     ASSERT(m_transaction->sqliteTransaction());
201
202     m_statement = std::make_unique<SQLiteStatement>(m_transaction->sqliteTransaction()->database(), sql);
203
204     if (m_statement->prepare() != SQLITE_OK) {
205         LOG_ERROR("Could not create cursor statement (prepare/id) - '%s'", m_transaction->sqliteTransaction()->database().lastErrorMsg());
206         return false;
207     }
208
209     return bindArguments();
210 }
211
212 void SQLiteIDBCursor::objectStoreRecordsChanged()
213 {
214     if (m_statementNeedsReset)
215         return;
216
217     // If ObjectStore or Index contents changed, we need to reset the statement and bind new parameters to it.
218     // This is to pick up any changes that might exist.
219     // We also need to throw away any fetched records as they may no longer be valid.
220
221     m_statementNeedsReset = true;
222     ASSERT(!m_fetchedRecords.isEmpty());
223
224     if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
225         m_currentLowerKey = m_fetchedRecords.first().record.key;
226         if (!m_keyRange.lowerOpen) {
227             m_keyRange.lowerOpen = true;
228             m_keyRange.lowerKey = m_currentLowerKey;
229             m_statement = nullptr;
230         }
231     } else {
232         m_currentUpperKey = m_fetchedRecords.first().record.key;
233         if (!m_keyRange.upperOpen) {
234             m_keyRange.upperOpen = true;
235             m_keyRange.upperKey = m_currentUpperKey;
236             m_statement = nullptr;
237         }
238     }
239
240     m_currentKeyForUniqueness = m_fetchedRecords.first().record.key;
241
242     m_fetchedRecords.clear();
243 }
244
245 void SQLiteIDBCursor::resetAndRebindStatement()
246 {
247     ASSERT(!m_currentLowerKey.isNull());
248     ASSERT(!m_currentUpperKey.isNull());
249     ASSERT(m_transaction->sqliteTransaction());
250     ASSERT(m_statementNeedsReset);
251
252     m_statementNeedsReset = false;
253
254     if (!m_statement && !establishStatement()) {
255         LOG_ERROR("Unable to establish new statement for cursor iteration");
256         return;
257     }
258
259     if (m_statement->reset() != SQLITE_OK) {
260         LOG_ERROR("Could not reset cursor statement to respond to object store changes");
261         return;
262     }
263
264     bindArguments();
265 }
266
267 bool SQLiteIDBCursor::bindArguments()
268 {
269     LOG(IndexedDB, "Cursor is binding lower key '%s' and upper key '%s'", m_currentLowerKey.loggingString().utf8().data(), m_currentUpperKey.loggingString().utf8().data());
270
271     int currentBindArgument = 1;
272
273     if (m_statement->bindInt64(currentBindArgument++, m_boundID) != SQLITE_OK) {
274         LOG_ERROR("Could not bind id argument (bound ID)");
275         return false;
276     }
277
278     if (m_indexID != IDBIndexInfo::InvalidId && m_statement->bindInt64(currentBindArgument++, m_objectStoreID) != SQLITE_OK) {
279         LOG_ERROR("Could not bind object store id argument for an index cursor");
280         return false;
281     }
282
283     RefPtr<SharedBuffer> buffer = serializeIDBKeyData(m_currentLowerKey);
284     if (m_statement->bindBlob(currentBindArgument++, buffer->data(), buffer->size()) != SQLITE_OK) {
285         LOG_ERROR("Could not create cursor statement (lower key)");
286         return false;
287     }
288
289     buffer = serializeIDBKeyData(m_currentUpperKey);
290     if (m_statement->bindBlob(currentBindArgument++, buffer->data(), buffer->size()) != SQLITE_OK) {
291         LOG_ERROR("Could not create cursor statement (upper key)");
292         return false;
293     }
294
295     return true;
296 }
297
298 bool SQLiteIDBCursor::prefetch()
299 {
300     LOG(IndexedDB, "SQLiteIDBCursor::prefetch() - Cursor already has %zu fetched records", m_fetchedRecords.size());
301
302     if (m_fetchedRecords.isEmpty() || m_fetchedRecords.size() >= prefetchLimit || m_fetchedRecords.last().isTerminalRecord())
303         return false;
304
305     m_currentKeyForUniqueness = m_fetchedRecords.last().record.key;
306     fetch();
307
308     return m_fetchedRecords.size() < prefetchLimit;
309 }
310
311 bool SQLiteIDBCursor::advance(uint64_t count)
312 {
313     LOG(IndexedDB, "SQLiteIDBCursor::advance() - Count %" PRIu64 ", %zu fetched records", count, m_fetchedRecords.size());
314     ASSERT(count);
315
316     if (!m_fetchedRecords.isEmpty() && m_fetchedRecords.first().isTerminalRecord()) {
317         LOG_ERROR("Attempt to advance a completed cursor");
318         return false;
319     }
320
321     if (!m_fetchedRecords.isEmpty())
322         m_currentKeyForUniqueness = m_fetchedRecords.last().record.key;
323
324     // Drop already-fetched records up to `count` to see if we've already fetched the record we're looking for.
325     bool hadCurrentRecord = !m_fetchedRecords.isEmpty();
326     for (; count && !m_fetchedRecords.isEmpty(); --count) {
327         if (m_fetchedRecords.first().isTerminalRecord())
328             break;
329
330         m_fetchedRecords.removeFirst();
331     }
332
333     // If we still have any records left, the first record is our new current record.
334     if (!m_fetchedRecords.isEmpty())
335         return true;
336
337     ASSERT(m_fetchedRecords.isEmpty());
338
339     // If we started out with a current record, we burnt a count on removing it.
340     // Replace that count now.
341     if (hadCurrentRecord)
342         ++count;
343
344     for (; count; --count) {
345         if (!m_fetchedRecords.isEmpty()) {
346             ASSERT(m_fetchedRecords.size() == 1);
347             m_currentKeyForUniqueness = m_fetchedRecords.first().record.key;
348             m_fetchedRecords.removeFirst();
349         }
350
351         if (!fetch())
352             return false;
353
354         ASSERT(!m_fetchedRecords.isEmpty());
355         ASSERT(!m_fetchedRecords.first().errored);
356         if (m_fetchedRecords.first().completed)
357             break;
358     }
359
360     return true;
361 }
362
363 bool SQLiteIDBCursor::fetch()
364 {
365     ASSERT(m_fetchedRecords.isEmpty() || !m_fetchedRecords.last().isTerminalRecord());
366
367     m_fetchedRecords.append({ });
368
369     bool isUnique = m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate || m_cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate;
370     if (!isUnique)
371         return fetchNextRecord(m_fetchedRecords.last());
372
373     while (!m_fetchedRecords.last().completed) {
374         if (!fetchNextRecord(m_fetchedRecords.last()))
375             return false;
376
377         // If the new current key is different from the old current key, we're done.
378         if (m_currentKeyForUniqueness.compare(m_fetchedRecords.last().record.key))
379             return true;
380     }
381
382     return false;
383 }
384
385 bool SQLiteIDBCursor::fetchNextRecord(SQLiteCursorRecord& record)
386 {
387     if (m_statementNeedsReset)
388         resetAndRebindStatement();
389
390     FetchResult result;
391     do {
392         result = internalFetchNextRecord(record);
393     } while (result == FetchResult::ShouldFetchAgain);
394
395     return result == FetchResult::Success;
396 }
397
398 void SQLiteIDBCursor::markAsErrored(SQLiteCursorRecord& record)
399 {
400     record.record = { };
401     record.completed = true;
402     record.errored = true;
403     record.rowID = 0;
404 }
405
406 SQLiteIDBCursor::FetchResult SQLiteIDBCursor::internalFetchNextRecord(SQLiteCursorRecord& record)
407 {
408     ASSERT(m_transaction->sqliteTransaction());
409     ASSERT(m_statement);
410     ASSERT(!m_fetchedRecords.isEmpty());
411     ASSERT(!m_fetchedRecords.last().isTerminalRecord());
412
413     record.record.value = nullptr;
414
415     int result = m_statement->step();
416     if (result == SQLITE_DONE) {
417         // When a cursor reaches its end, that is indicated by having undefined keys/values
418         record = { };
419         record.completed = true;
420
421         return FetchResult::Success;
422     }
423
424     if (result != SQLITE_ROW) {
425         LOG_ERROR("Error advancing cursor - (%i) %s", result, m_transaction->sqliteTransaction()->database().lastErrorMsg());
426         markAsErrored(record);
427         return FetchResult::Failure;
428     }
429
430     record.rowID = m_statement->getColumnInt64(0);
431     ASSERT(record.rowID);
432
433     Vector<uint8_t> keyData;
434     m_statement->getColumnBlobAsVector(1, keyData);
435
436     if (!deserializeIDBKeyData(keyData.data(), keyData.size(), record.record.key)) {
437         LOG_ERROR("Unable to deserialize key data from database while advancing cursor");
438         markAsErrored(record);
439         return FetchResult::Failure;
440     }
441
442     m_statement->getColumnBlobAsVector(2, keyData);
443
444     // The primaryKey of an ObjectStore cursor is the same as its key.
445     if (m_indexID == IDBIndexInfo::InvalidId) {
446         record.record.primaryKey = record.record.key;
447
448         Vector<String> blobURLs, blobFilePaths;
449         auto error = m_transaction->backingStore().getBlobRecordsForObjectStoreRecord(record.rowID, blobURLs, blobFilePaths);
450         if (!error.isNull()) {
451             LOG_ERROR("Unable to fetch blob records from database while advancing cursor");
452             markAsErrored(record);
453             return FetchResult::Failure;
454         }
455
456         if (m_cursorType == IndexedDB::CursorType::KeyAndValue)
457             record.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData), blobURLs, blobFilePaths);
458     } else {
459         if (!deserializeIDBKeyData(keyData.data(), keyData.size(), record.record.primaryKey)) {
460             LOG_ERROR("Unable to deserialize value data from database while advancing index cursor");
461             markAsErrored(record);
462             return FetchResult::Failure;
463         }
464
465         SQLiteStatement objectStoreStatement(m_statement->database(), "SELECT value FROM Records WHERE key = CAST(? AS TEXT) and objectStoreID = ?;");
466
467         if (objectStoreStatement.prepare() != SQLITE_OK
468             || objectStoreStatement.bindBlob(1, keyData.data(), keyData.size()) != SQLITE_OK
469             || objectStoreStatement.bindInt64(2, m_objectStoreID) != SQLITE_OK) {
470             LOG_ERROR("Could not create index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg());
471             markAsErrored(record);
472             return FetchResult::Failure;
473         }
474
475         int result = objectStoreStatement.step();
476
477         if (result == SQLITE_ROW) {
478             objectStoreStatement.getColumnBlobAsVector(0, keyData);
479             record.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData));
480         } else if (result == SQLITE_DONE) {
481             // This indicates that the record we're trying to retrieve has been removed from the object store.
482             // Skip over it.
483             return FetchResult::ShouldFetchAgain;
484         } else {
485             LOG_ERROR("Could not step index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg());
486             markAsErrored(record);
487             return FetchResult::Failure;
488
489         }
490     }
491
492     return FetchResult::Success;
493 }
494
495 bool SQLiteIDBCursor::iterate(const IDBKeyData& targetKey, const IDBKeyData& targetPrimaryKey)
496 {
497     ASSERT(m_transaction->sqliteTransaction());
498     ASSERT(m_statement);
499
500     bool result = advance(1);
501     ASSERT(!m_fetchedRecords.isEmpty());
502
503     // Iterating with no key is equivalent to advancing 1 step.
504     if (targetKey.isNull() || !result)
505         return result;
506
507     while (!m_fetchedRecords.first().isTerminalRecord()) {
508         if (!result)
509             return false;
510
511         // Search for the next key >= the target if the cursor is a Next cursor, or the next key <= if the cursor is a Previous cursor.
512         if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
513             if (m_fetchedRecords.first().record.key.compare(targetKey) >= 0)
514                 break;
515         } else if (m_fetchedRecords.first().record.key.compare(targetKey) <= 0)
516             break;
517
518         result = advance(1);
519     }
520
521     if (targetPrimaryKey.isValid()) {
522         while (!m_fetchedRecords.first().isTerminalRecord() && !m_fetchedRecords.first().record.key.compare(targetKey)) {
523             if (!result)
524                 return false;
525
526             // Search for the next primary key >= the primary target if the cursor is a Next cursor, or the next key <= if the cursor is a Previous cursor.
527             if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
528                 if (m_fetchedRecords.first().record.primaryKey.compare(targetPrimaryKey) >= 0)
529                     break;
530             } else if (m_fetchedRecords.first().record.primaryKey.compare(targetPrimaryKey) <= 0)
531                 break;
532
533             result = advance(1);
534         }
535     }
536
537     return result;
538 }
539
540 const IDBKeyData& SQLiteIDBCursor::currentKey() const
541 {
542     ASSERT(!m_fetchedRecords.isEmpty());
543     return m_fetchedRecords.first().record.key;
544 }
545
546 const IDBKeyData& SQLiteIDBCursor::currentPrimaryKey() const
547 {
548     ASSERT(!m_fetchedRecords.isEmpty());
549     return m_fetchedRecords.first().record.primaryKey;
550 }
551
552 IDBValue* SQLiteIDBCursor::currentValue() const
553 {
554     ASSERT(!m_fetchedRecords.isEmpty());
555     return m_fetchedRecords.first().record.value.get();
556 }
557
558 bool SQLiteIDBCursor::didComplete() const
559 {
560     ASSERT(!m_fetchedRecords.isEmpty());
561     return m_fetchedRecords.first().completed;
562 }
563
564 bool SQLiteIDBCursor::didError() const
565 {
566     ASSERT(!m_fetchedRecords.isEmpty());
567     return m_fetchedRecords.first().errored;
568 }
569
570 int64_t SQLiteIDBCursor::currentRecordRowID() const
571 {
572     ASSERT(!m_fetchedRecords.isEmpty());
573     return m_fetchedRecords.first().rowID;
574 }
575
576
577 } // namespace IDBServer
578 } // namespace WebCore
579
580 #endif // ENABLE(INDEXED_DATABASE)