Changeset 209960 in webkit
- Timestamp:
- Dec 16, 2016 11:29:17 PM (7 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r209959 r209960 1 2016-12-16 Brady Eidson <beidson@apple.com> 2 3 IndexedDB: Refactor SQLiteIDBCursor to prepare for cursor prefetching. 4 https://bugs.webkit.org/show_bug.cgi?id=165978 5 6 Reviewed by Alex Christensen. 7 8 No new tests (Refactor, no behavior change). 9 10 In preparation for cursor prefetching, we need to shift the cursor off of keeping "the current record" 11 and onto keeping "a deque of fetched records", the first of which is "the current record". 12 13 This patch does just that, but with no behavior change; The deque only ever holds 0 or 1 records. 14 15 * Modules/indexeddb/server/SQLiteIDBCursor.cpp: 16 (WebCore::IDBServer::SQLiteIDBCursor::currentData): 17 (WebCore::IDBServer::SQLiteIDBCursor::objectStoreRecordsChanged): 18 (WebCore::IDBServer::SQLiteIDBCursor::resetAndRebindStatement): 19 (WebCore::IDBServer::SQLiteIDBCursor::prefetch): 20 (WebCore::IDBServer::SQLiteIDBCursor::advance): 21 (WebCore::IDBServer::SQLiteIDBCursor::fetch): 22 (WebCore::IDBServer::SQLiteIDBCursor::fetchNextRecord): 23 (WebCore::IDBServer::SQLiteIDBCursor::markAsErrored): 24 (WebCore::IDBServer::SQLiteIDBCursor::internalFetchNextRecord): 25 (WebCore::IDBServer::SQLiteIDBCursor::iterate): 26 (WebCore::IDBServer::SQLiteIDBCursor::currentKey): 27 (WebCore::IDBServer::SQLiteIDBCursor::currentPrimaryKey): 28 (WebCore::IDBServer::SQLiteIDBCursor::currentValue): 29 (WebCore::IDBServer::SQLiteIDBCursor::didComplete): 30 (WebCore::IDBServer::SQLiteIDBCursor::didError): 31 (WebCore::IDBServer::SQLiteIDBCursor::currentRecordRowID): 32 (WebCore::IDBServer::SQLiteIDBCursor::advanceUnique): Deleted. 33 (WebCore::IDBServer::SQLiteIDBCursor::advanceOnce): Deleted. 34 (WebCore::IDBServer::SQLiteIDBCursor::internalAdvanceOnce): Deleted. 35 36 * Modules/indexeddb/server/SQLiteIDBCursor.h: 37 (WebCore::IDBServer::SQLiteIDBCursor::SQLiteCursorRecord::isTerminalRecord): 38 (WebCore::IDBServer::SQLiteIDBCursor::currentRecordRowID): Deleted. 39 (WebCore::IDBServer::SQLiteIDBCursor::currentKey): Deleted. 40 (WebCore::IDBServer::SQLiteIDBCursor::currentPrimaryKey): Deleted. 41 (WebCore::IDBServer::SQLiteIDBCursor::currentValue): Deleted. 42 (WebCore::IDBServer::SQLiteIDBCursor::didComplete): Deleted. 43 (WebCore::IDBServer::SQLiteIDBCursor::didError): Deleted. 44 1 45 2016-12-16 Darin Adler <darin@apple.com> 2 46 -
trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp
r209942 r209960 102 102 void SQLiteIDBCursor::currentData(IDBGetResult& result) 103 103 { 104 if (m_currentRecord.completed) { 105 ASSERT(!m_currentRecord.errored); 104 ASSERT(!m_fetchedRecords.isEmpty()); 105 106 auto& currentRecord = m_fetchedRecords.first(); 107 if (currentRecord.completed) { 108 ASSERT(!currentRecord.errored); 106 109 result = { }; 107 110 return; 108 111 } 109 112 110 result = { m_currentRecord.record.key, m_currentRecord.record.primaryKey, m_currentRecord.record.value ? *m_currentRecord.record.value : IDBValue() };113 result = { currentRecord.record.key, currentRecord.record.primaryKey, currentRecord.record.value ? *currentRecord.record.value : IDBValue() }; 111 114 } 112 115 … … 207 210 void SQLiteIDBCursor::objectStoreRecordsChanged() 208 211 { 212 if (m_statementNeedsReset) 213 return; 214 209 215 // If ObjectStore or Index contents changed, we need to reset the statement and bind new parameters to it. 210 216 // This is to pick up any changes that might exist. 217 // We also need to throw away any fetched records as they may no longer be valid. 211 218 212 219 m_statementNeedsReset = true; 213 } 214 215 void SQLiteIDBCursor::resetAndRebindStatement() 216 { 217 ASSERT(!m_currentLowerKey.isNull()); 218 ASSERT(!m_currentUpperKey.isNull()); 219 ASSERT(m_transaction->sqliteTransaction()); 220 ASSERT(m_statement); 221 ASSERT(m_statementNeedsReset); 222 223 m_statementNeedsReset = false; 224 225 // If this cursor never fetched any records, we don't need to reset the statement. 226 if (m_currentRecord.record.key.isNull()) 227 return; 228 229 // Otherwise update the lower key or upper key used for the cursor range. 230 // This is so the cursor can pick up where we left off. 231 // We might also have to change the statement from closed to open so we don't refetch the current key a second time. 220 ASSERT(!m_fetchedRecords.isEmpty()); 221 232 222 if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) { 233 m_currentLowerKey = m_ currentRecord.record.key;223 m_currentLowerKey = m_fetchedRecords.first().record.key; 234 224 if (!m_keyRange.lowerOpen) { 235 225 m_keyRange.lowerOpen = true; … … 238 228 } 239 229 } else { 240 m_currentUpperKey = m_ currentRecord.record.key;230 m_currentUpperKey = m_fetchedRecords.first().record.key; 241 231 if (!m_keyRange.upperOpen) { 242 232 m_keyRange.upperOpen = true; … … 246 236 } 247 237 238 m_fetchedRecords.clear(); 239 } 240 241 void SQLiteIDBCursor::resetAndRebindStatement() 242 { 243 ASSERT(!m_currentLowerKey.isNull()); 244 ASSERT(!m_currentUpperKey.isNull()); 245 ASSERT(m_transaction->sqliteTransaction()); 246 ASSERT(m_statementNeedsReset); 247 248 m_statementNeedsReset = false; 249 248 250 if (!m_statement && !establishStatement()) { 249 251 LOG_ERROR("Unable to establish new statement for cursor iteration"); … … 290 292 } 291 293 294 void SQLiteIDBCursor::prefetch() 295 { 296 ASSERT(!m_fetchedRecords.isEmpty()); 297 if (m_fetchedRecords.last().errored || m_fetchedRecords.last().completed) 298 return; 299 300 m_currentKeyForUniqueness = m_fetchedRecords.last().record.key; 301 fetch(); 302 } 303 292 304 bool SQLiteIDBCursor::advance(uint64_t count) 293 305 { 294 bool isUnique = m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate || m_cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate;295 296 if ( m_currentRecord.completed) {306 ASSERT(count); 307 308 if (!m_fetchedRecords.isEmpty() && m_fetchedRecords.first().isTerminalRecord()) { 297 309 LOG_ERROR("Attempt to advance a completed cursor"); 298 310 return false; 299 311 } 300 312 313 if (!m_fetchedRecords.isEmpty()) 314 m_currentKeyForUniqueness = m_fetchedRecords.last().record.key; 315 316 // Drop already-fetched records up to `count` to see if we've already fetched the record we're looking for. 317 for (size_t i = 0; i < count && !m_fetchedRecords.isEmpty(); ++i) { 318 if (m_fetchedRecords.first().isTerminalRecord()) 319 break; 320 321 m_fetchedRecords.removeFirst(); 322 } 323 324 // If we still have any records left, the first record is our new current record. 325 if (!m_fetchedRecords.isEmpty()) 326 return !m_fetchedRecords.first().isTerminalRecord(); 327 328 ASSERT(m_fetchedRecords.isEmpty()); 329 301 330 for (uint64_t i = 0; i < count; ++i) { 302 if (!isUnique) { 303 if (!advanceOnce()) 304 return false; 305 } else { 306 if (!advanceUnique()) 307 return false; 308 } 309 310 if (m_currentRecord.completed) 331 if (!m_fetchedRecords.isEmpty()) { 332 ASSERT(m_fetchedRecords.size() == 1); 333 m_currentKeyForUniqueness = m_fetchedRecords.first().record.key; 334 m_fetchedRecords.removeFirst(); 335 } 336 337 if (!fetch()) 338 return false; 339 340 ASSERT(!m_fetchedRecords.isEmpty()); 341 ASSERT(!m_fetchedRecords.first().errored); 342 if (m_fetchedRecords.first().completed) 311 343 break; 312 344 } … … 315 347 } 316 348 317 bool SQLiteIDBCursor::advanceUnique() 318 { 319 IDBKeyData currentKey = m_currentRecord.record.key; 320 321 while (!m_currentRecord.completed) { 322 if (!advanceOnce()) 349 bool SQLiteIDBCursor::fetch() 350 { 351 ASSERT(m_fetchedRecords.isEmpty() || !m_fetchedRecords.last().isTerminalRecord()); 352 353 m_fetchedRecords.append({ }); 354 355 bool isUnique = m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate || m_cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate; 356 if (!isUnique) 357 return fetchNextRecord(m_fetchedRecords.last()); 358 359 while (!m_fetchedRecords.last().completed) { 360 if (!fetchNextRecord(m_fetchedRecords.last())) 323 361 return false; 324 362 325 363 // If the new current key is different from the old current key, we're done. 326 if ( currentKey.compare(m_currentRecord.record.key))364 if (m_currentKeyForUniqueness.compare(m_fetchedRecords.last().record.key)) 327 365 return true; 328 366 } … … 331 369 } 332 370 333 bool SQLiteIDBCursor:: advanceOnce()371 bool SQLiteIDBCursor::fetchNextRecord(SQLiteCursorRecord& record) 334 372 { 335 373 if (m_statementNeedsReset) 336 374 resetAndRebindStatement(); 337 375 338 AdvanceResult result;376 FetchResult result; 339 377 do { 340 result = internalAdvanceOnce(); 341 } while (result == AdvanceResult::ShouldAdvanceAgain); 342 343 return result == AdvanceResult::Success; 344 } 345 346 void SQLiteIDBCursor::markAsErrored() 347 { 348 m_currentRecord.completed = true; 349 m_currentRecord.errored = true; 350 m_currentRecord.rowID = 0; 351 } 352 353 SQLiteIDBCursor::AdvanceResult SQLiteIDBCursor::internalAdvanceOnce() 378 result = internalFetchNextRecord(record); 379 } while (result == FetchResult::ShouldFetchAgain); 380 381 return result == FetchResult::Success; 382 } 383 384 void SQLiteIDBCursor::markAsErrored(SQLiteCursorRecord& record) 385 { 386 record.record = { }; 387 record.completed = true; 388 record.errored = true; 389 record.rowID = 0; 390 } 391 392 SQLiteIDBCursor::FetchResult SQLiteIDBCursor::internalFetchNextRecord(SQLiteCursorRecord& record) 354 393 { 355 394 ASSERT(m_transaction->sqliteTransaction()); 356 395 ASSERT(m_statement); 357 ASSERT(!m_currentRecord.completed); 358 359 m_currentRecord.record.value = nullptr; 396 ASSERT(!m_fetchedRecords.isEmpty()); 397 ASSERT(!m_fetchedRecords.last().isTerminalRecord()); 398 399 record.record.value = nullptr; 360 400 361 401 int result = m_statement->step(); 362 402 if (result == SQLITE_DONE) { 363 403 // When a cursor reaches its end, that is indicated by having undefined keys/values 364 m_currentRecord = { }; 365 m_currentRecord.completed = true; 366 m_currentRecord.rowID = 0; 367 368 return AdvanceResult::Success; 404 record = { }; 405 record.completed = true; 406 407 return FetchResult::Success; 369 408 } 370 409 371 410 if (result != SQLITE_ROW) { 372 411 LOG_ERROR("Error advancing cursor - (%i) %s", result, m_transaction->sqliteTransaction()->database().lastErrorMsg()); 373 markAsErrored( );374 return AdvanceResult::Failure;375 } 376 377 m_currentRecord.rowID = m_statement->getColumnInt64(0);378 ASSERT( m_currentRecord.rowID);412 markAsErrored(record); 413 return FetchResult::Failure; 414 } 415 416 record.rowID = m_statement->getColumnInt64(0); 417 ASSERT(record.rowID); 379 418 380 419 Vector<uint8_t> keyData; 381 420 m_statement->getColumnBlobAsVector(1, keyData); 382 421 383 if (!deserializeIDBKeyData(keyData.data(), keyData.size(), m_currentRecord.record.key)) {422 if (!deserializeIDBKeyData(keyData.data(), keyData.size(), record.record.key)) { 384 423 LOG_ERROR("Unable to deserialize key data from database while advancing cursor"); 385 markAsErrored( );386 return AdvanceResult::Failure;424 markAsErrored(record); 425 return FetchResult::Failure; 387 426 } 388 427 … … 391 430 // The primaryKey of an ObjectStore cursor is the same as its key. 392 431 if (m_indexID == IDBIndexInfo::InvalidId) { 393 m_currentRecord.record.primaryKey = m_currentRecord.record.key;432 record.record.primaryKey = record.record.key; 394 433 395 434 Vector<String> blobURLs, blobFilePaths; 396 auto error = m_transaction->backingStore().getBlobRecordsForObjectStoreRecord( m_currentRecord.rowID, blobURLs, blobFilePaths);435 auto error = m_transaction->backingStore().getBlobRecordsForObjectStoreRecord(record.rowID, blobURLs, blobFilePaths); 397 436 if (!error.isNull()) { 398 437 LOG_ERROR("Unable to fetch blob records from database while advancing cursor"); 399 markAsErrored( );400 return AdvanceResult::Failure;438 markAsErrored(record); 439 return FetchResult::Failure; 401 440 } 402 441 403 442 if (m_cursorType == IndexedDB::CursorType::KeyAndValue) 404 m_currentRecord.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData), blobURLs, blobFilePaths);443 record.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData), blobURLs, blobFilePaths); 405 444 } else { 406 if (!deserializeIDBKeyData(keyData.data(), keyData.size(), m_currentRecord.record.primaryKey)) {445 if (!deserializeIDBKeyData(keyData.data(), keyData.size(), record.record.primaryKey)) { 407 446 LOG_ERROR("Unable to deserialize value data from database while advancing index cursor"); 408 markAsErrored( );409 return AdvanceResult::Failure;447 markAsErrored(record); 448 return FetchResult::Failure; 410 449 } 411 450 … … 416 455 || objectStoreStatement.bindInt64(2, m_objectStoreID) != SQLITE_OK) { 417 456 LOG_ERROR("Could not create index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg()); 418 markAsErrored( );419 return AdvanceResult::Failure;457 markAsErrored(record); 458 return FetchResult::Failure; 420 459 } 421 460 … … 424 463 if (result == SQLITE_ROW) { 425 464 objectStoreStatement.getColumnBlobAsVector(0, keyData); 426 m_currentRecord.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData));465 record.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData)); 427 466 } else if (result == SQLITE_DONE) { 428 467 // This indicates that the record we're trying to retrieve has been removed from the object store. 429 468 // Skip over it. 430 return AdvanceResult::ShouldAdvanceAgain;469 return FetchResult::ShouldFetchAgain; 431 470 } else { 432 471 LOG_ERROR("Could not step index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg()); 433 markAsErrored( );434 return AdvanceResult::Failure;435 436 } 437 } 438 439 return AdvanceResult::Success;472 markAsErrored(record); 473 return FetchResult::Failure; 474 475 } 476 } 477 478 return FetchResult::Success; 440 479 } 441 480 … … 446 485 447 486 bool result = advance(1); 487 ASSERT(!m_fetchedRecords.isEmpty()); 448 488 449 489 // Iterating with no key is equivalent to advancing 1 step. … … 451 491 return result; 452 492 453 while (!m_ currentRecord.completed) {493 while (!m_fetchedRecords.first().isTerminalRecord()) { 454 494 if (!result) 455 495 return false; … … 457 497 // 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. 458 498 if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) { 459 if (m_ currentRecord.record.key.compare(targetKey) >= 0)499 if (m_fetchedRecords.first().record.key.compare(targetKey) >= 0) 460 500 break; 461 } else if (m_ currentRecord.record.key.compare(targetKey) <= 0)501 } else if (m_fetchedRecords.first().record.key.compare(targetKey) <= 0) 462 502 break; 463 503 … … 466 506 467 507 if (targetPrimaryKey.isValid()) { 468 while (!m_ currentRecord.completed && !m_currentRecord.record.key.compare(targetKey)) {508 while (!m_fetchedRecords.first().isTerminalRecord() && !m_fetchedRecords.first().record.key.compare(targetKey)) { 469 509 if (!result) 470 510 return false; … … 472 512 // 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. 473 513 if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) { 474 if (m_ currentRecord.record.primaryKey.compare(targetPrimaryKey) >= 0)514 if (m_fetchedRecords.first().record.primaryKey.compare(targetPrimaryKey) >= 0) 475 515 break; 476 } else if (m_ currentRecord.record.primaryKey.compare(targetPrimaryKey) <= 0)516 } else if (m_fetchedRecords.first().record.primaryKey.compare(targetPrimaryKey) <= 0) 477 517 break; 478 518 … … 483 523 return result; 484 524 } 525 526 const IDBKeyData& SQLiteIDBCursor::currentKey() const 527 { 528 ASSERT(!m_fetchedRecords.isEmpty()); 529 return m_fetchedRecords.first().record.key; 530 } 531 532 const IDBKeyData& SQLiteIDBCursor::currentPrimaryKey() const 533 { 534 ASSERT(!m_fetchedRecords.isEmpty()); 535 return m_fetchedRecords.first().record.primaryKey; 536 } 537 538 IDBValue* SQLiteIDBCursor::currentValue() const 539 { 540 ASSERT(!m_fetchedRecords.isEmpty()); 541 return m_fetchedRecords.first().record.value.get(); 542 } 543 544 bool SQLiteIDBCursor::didComplete() const 545 { 546 ASSERT(!m_fetchedRecords.isEmpty()); 547 return m_fetchedRecords.first().completed; 548 } 549 550 bool SQLiteIDBCursor::didError() const 551 { 552 ASSERT(!m_fetchedRecords.isEmpty()); 553 return m_fetchedRecords.first().errored; 554 } 555 556 int64_t SQLiteIDBCursor::currentRecordRowID() const 557 { 558 ASSERT(!m_fetchedRecords.isEmpty()); 559 return m_fetchedRecords.first().rowID; 560 } 561 485 562 486 563 } // namespace IDBServer -
trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h
r209942 r209960 35 35 #include "IDBValue.h" 36 36 #include "SQLiteStatement.h" 37 #include <wtf/Deque.h> 37 38 #include <wtf/Noncopyable.h> 38 39 … … 61 62 62 63 int64_t objectStoreID() const { return m_objectStoreID; } 63 int64_t currentRecordRowID() const { return m_currentRecord.rowID; }64 int64_t currentRecordRowID() const; 64 65 65 const IDBKeyData& currentKey() const { return m_currentRecord.record.key; }66 const IDBKeyData& currentPrimaryKey() const { return m_currentRecord.record.primaryKey; }67 IDBValue* currentValue() const { return m_currentRecord.record.value.get(); }66 const IDBKeyData& currentKey() const; 67 const IDBKeyData& currentPrimaryKey() const; 68 IDBValue* currentValue() const; 68 69 69 70 bool advance(uint64_t count); 70 71 bool iterate(const IDBKeyData& targetKey, const IDBKeyData& targetPrimaryKey); 72 void prefetch(); 71 73 72 bool didComplete() const { return m_currentRecord.completed; }73 bool didError() const { return m_currentRecord.errored; }74 bool didComplete() const; 75 bool didError() const; 74 76 75 77 void objectStoreRecordsChanged(); … … 84 86 void resetAndRebindStatement(); 85 87 86 void markAsErrored(); 87 88 enum class AdvanceResult { 88 enum class FetchResult { 89 89 Success, 90 90 Failure, 91 Should AdvanceAgain91 ShouldFetchAgain 92 92 }; 93 93 94 AdvanceResult internalAdvanceOnce(); 95 bool advanceOnce(); 96 bool advanceUnique(); 94 bool fetch(); 95 96 struct SQLiteCursorRecord { 97 IDBCursorRecord record; 98 bool completed { false }; 99 bool errored { false }; 100 int64_t rowID { 0 }; 101 bool isTerminalRecord() const { return completed || errored; } 102 }; 103 bool fetchNextRecord(SQLiteCursorRecord&); 104 FetchResult internalFetchNextRecord(SQLiteCursorRecord&); 105 106 void markAsErrored(SQLiteCursorRecord&); 97 107 98 108 SQLiteIDBTransaction* m_transaction; … … 107 117 IDBKeyData m_currentUpperKey; 108 118 109 struct SQLiteCursorRecord { 110 IDBCursorRecord record; 111 bool completed { false }; 112 bool errored { false }; 113 int64_t rowID { 0 }; 114 }; 115 116 SQLiteCursorRecord m_currentRecord; 119 Deque<SQLiteCursorRecord> m_fetchedRecords; 120 IDBKeyData m_currentKeyForUniqueness; 117 121 118 122 std::unique_ptr<SQLiteStatement> m_statement; 119 bool m_statementNeedsReset { false };123 bool m_statementNeedsReset { true }; 120 124 int64_t m_boundID { 0 }; 121 125
Note: See TracChangeset
for help on using the changeset viewer.