1/* 2 * Copyright (C) 2013 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 "UniqueIDBDatabase.h" 28 29#if ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS) 30 31#include "AsyncRequest.h" 32#include "AsyncTask.h" 33#include "DataReference.h" 34#include "DatabaseProcess.h" 35#include "DatabaseProcessIDBConnection.h" 36#include "Logging.h" 37#include "UniqueIDBDatabaseBackingStoreSQLite.h" 38#include "WebCrossThreadCopier.h" 39#include <WebCore/FileSystem.h> 40#include <WebCore/IDBDatabaseMetadata.h> 41#include <WebCore/IDBGetResult.h> 42#include <WebCore/IDBKeyData.h> 43#include <WebCore/IDBKeyRangeData.h> 44#include <wtf/MainThread.h> 45#include <wtf/text/WTFString.h> 46 47using namespace WebCore; 48 49namespace WebKit { 50 51String UniqueIDBDatabase::calculateAbsoluteDatabaseFilename(const String& absoluteDatabaseDirectory) 52{ 53 return pathByAppendingComponent(absoluteDatabaseDirectory, "IndexedDB.sqlite3"); 54} 55 56UniqueIDBDatabase::UniqueIDBDatabase(const UniqueIDBDatabaseIdentifier& identifier) 57 : m_identifier(identifier) 58 , m_acceptingNewRequests(true) 59 , m_didGetMetadataFromBackingStore(false) 60{ 61 m_inMemory = !canShareDatabases(identifier.openingOrigin(), identifier.mainFrameOrigin()); 62 if (m_inMemory) 63 return; 64 65 // ********* 66 // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>) 67 // ********* 68 69 // Each unique Indexed Database exists in a directory named for the database, which exists in a directory representing its opening origin. 70 m_databaseRelativeDirectory = pathByAppendingComponent(databaseFilenameIdentifier(identifier.openingOrigin()), filenameForDatabaseName()); 71 72 DatabaseProcess::shared().ensureIndexedDatabaseRelativePathExists(m_databaseRelativeDirectory); 73} 74 75UniqueIDBDatabase::~UniqueIDBDatabase() 76{ 77 ASSERT(!m_acceptingNewRequests); 78 ASSERT(m_pendingMetadataRequests.isEmpty()); 79} 80 81String UniqueIDBDatabase::filenameForDatabaseName() const 82{ 83 ASSERT(!m_identifier.databaseName().isNull()); 84 85 if (m_identifier.databaseName().isEmpty()) 86 return "%00"; 87 88 String filename = encodeForFileName(m_identifier.databaseName()); 89 filename.replace('.', "%2E"); 90 91 return filename; 92} 93 94String UniqueIDBDatabase::databaseFilenameIdentifier(const SecurityOriginData& originData) const 95{ 96 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(originData.protocol, originData.host, originData.port); 97 return securityOrigin->databaseIdentifier(); 98} 99 100bool UniqueIDBDatabase::canShareDatabases(const SecurityOriginData& openingOrigin, const SecurityOriginData& mainFrameOrigin) const 101{ 102 // For now, an origin's database access is predicated on equality with the other origin. 103 // We might need to make this more nuanced later. 104 return openingOrigin == mainFrameOrigin; 105} 106 107void UniqueIDBDatabase::registerConnection(DatabaseProcessIDBConnection& connection) 108{ 109 ASSERT(!m_connections.contains(&connection)); 110 m_connections.add(&connection); 111} 112 113void UniqueIDBDatabase::unregisterConnection(DatabaseProcessIDBConnection& connection) 114{ 115 ASSERT(m_connections.contains(&connection)); 116 resetAllTransactions(connection); 117 m_connections.remove(&connection); 118 119 if (m_connections.isEmpty() && m_pendingTransactionRollbacks.isEmpty()) { 120 shutdown(UniqueIDBDatabaseShutdownType::NormalShutdown); 121 DatabaseProcess::shared().removeUniqueIDBDatabase(*this); 122 } 123} 124 125void UniqueIDBDatabase::shutdown(UniqueIDBDatabaseShutdownType type) 126{ 127 ASSERT(RunLoop::isMain()); 128 129 if (!m_acceptingNewRequests) 130 return; 131 132 m_acceptingNewRequests = false; 133 134 // Balanced by an adoptRef in ::didShutdownBackingStore() 135 ref(); 136 137 { 138 MutexLocker locker(m_databaseTaskMutex); 139 m_databaseTasks.clear(); 140 } 141 142 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::shutdownBackingStore, type, absoluteDatabaseDirectory()), DatabaseTaskType::Shutdown); 143} 144 145void UniqueIDBDatabase::shutdownBackingStore(UniqueIDBDatabaseShutdownType type, const String& databaseDirectory) 146{ 147 ASSERT(!RunLoop::isMain()); 148 149 m_backingStore.clear(); 150 151 if (type == UniqueIDBDatabaseShutdownType::DeleteShutdown) { 152 String dbFilename = UniqueIDBDatabase::calculateAbsoluteDatabaseFilename(databaseDirectory); 153 LOG(IDB, "UniqueIDBDatabase::shutdownBackingStore deleting file '%s' on disk", dbFilename.utf8().data()); 154 deleteFile(dbFilename); 155 deleteEmptyDirectory(databaseDirectory); 156 } 157 158 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didShutdownBackingStore, type), DatabaseTaskType::Shutdown); 159} 160 161void UniqueIDBDatabase::didShutdownBackingStore(UniqueIDBDatabaseShutdownType type) 162{ 163 ASSERT(RunLoop::isMain()); 164 165 // Balanced by a ref in ::shutdown() 166 RefPtr<UniqueIDBDatabase> protector(adoptRef(this)); 167 168 // Empty out remaining main thread tasks. 169 while (performNextMainThreadTaskWithoutAdoptRef()) { 170 } 171 172 // No more requests will be handled, so abort all outstanding requests. 173 for (const auto& it : m_pendingMetadataRequests) 174 it->requestAborted(); 175 for (const auto& it : m_pendingTransactionRequests) 176 it.value->requestAborted(); 177 for (const auto& it : m_pendingDatabaseTasks) 178 it.value->requestAborted(); 179 180 m_pendingMetadataRequests.clear(); 181 m_pendingTransactionRequests.clear(); 182 m_pendingDatabaseTasks.clear(); 183 184 if (m_pendingShutdownTask) 185 m_pendingShutdownTask->completeRequest(type); 186 187 m_pendingShutdownTask = nullptr; 188} 189 190void UniqueIDBDatabase::deleteDatabase(std::function<void(bool)> successCallback) 191{ 192 ASSERT(RunLoop::isMain()); 193 194 if (!m_acceptingNewRequests) { 195 // Someone else has already shutdown this database, so we can't request a delete. 196 callOnMainThread([successCallback]() { 197 successCallback(false); 198 }); 199 return; 200 } 201 202 RefPtr<UniqueIDBDatabase> protector(this); 203 m_pendingShutdownTask = AsyncRequestImpl<UniqueIDBDatabaseShutdownType>::create([this, protector, successCallback](UniqueIDBDatabaseShutdownType type) { 204 // If the shutdown just completed was a Delete shutdown then we succeeded. 205 // If not report failure instead of trying again. 206 successCallback(type == UniqueIDBDatabaseShutdownType::DeleteShutdown); 207 }, [this, protector, successCallback]() { 208 successCallback(false); 209 }); 210 211 shutdown(UniqueIDBDatabaseShutdownType::DeleteShutdown); 212} 213 214void UniqueIDBDatabase::getOrEstablishIDBDatabaseMetadata(std::function<void(bool, const IDBDatabaseMetadata&)> completionCallback) 215{ 216 ASSERT(RunLoop::isMain()); 217 218 if (!m_acceptingNewRequests) { 219 completionCallback(false, IDBDatabaseMetadata()); 220 return; 221 } 222 223 // If we've already retrieved metadata from the backing store, return it now. 224 if (m_didGetMetadataFromBackingStore) { 225 if (m_metadata) 226 completionCallback(true, *m_metadata); 227 else 228 completionCallback(false, IDBDatabaseMetadata()); 229 230 return; 231 } 232 233 // If this is the first unanswered metadata request, then later we need to 234 // post a task to open the backing store and get metadata. 235 bool shouldOpenBackingStore = m_pendingMetadataRequests.isEmpty(); 236 237 // Then remember this metadata request to be answered later. 238 RefPtr<AsyncRequest> request = AsyncRequestImpl<>::create([completionCallback, this]() { 239 completionCallback(!!m_metadata, m_metadata ? *m_metadata : IDBDatabaseMetadata()); 240 }, [completionCallback]() { 241 // The boolean flag to the completion callback represents whether the 242 // attempt to get/establish metadata succeeded or failed. 243 // Since we're aborting the attempt, it failed, so we always pass in false. 244 completionCallback(false, IDBDatabaseMetadata()); 245 }); 246 247 m_pendingMetadataRequests.append(request.release()); 248 249 if (shouldOpenBackingStore) 250 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreAndReadMetadata, m_identifier, absoluteDatabaseDirectory())); 251} 252 253void UniqueIDBDatabase::openBackingStoreAndReadMetadata(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory) 254{ 255 ASSERT(!RunLoop::isMain()); 256 ASSERT(!m_backingStore); 257 258 if (m_inMemory) { 259 LOG_ERROR("Support for in-memory databases not yet implemented"); 260 return; 261 } 262 263 m_backingStore = UniqueIDBDatabaseBackingStoreSQLite::create(identifier, databaseDirectory); 264 std::unique_ptr<IDBDatabaseMetadata> metadata = m_backingStore->getOrEstablishMetadata(); 265 266 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata, metadata ? *metadata : IDBDatabaseMetadata(), !!metadata)); 267} 268 269void UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata(const IDBDatabaseMetadata& metadata, bool success) 270{ 271 ASSERT(RunLoop::isMain()); 272 ASSERT(!m_metadata); 273 274 m_didGetMetadataFromBackingStore = true; 275 276 if (success) 277 m_metadata = std::make_unique<IDBDatabaseMetadata>(metadata); 278 279 while (!m_pendingMetadataRequests.isEmpty()) { 280 RefPtr<AsyncRequest> request = m_pendingMetadataRequests.takeFirst(); 281 request->completeRequest(); 282 } 283} 284 285void UniqueIDBDatabase::openTransaction(const IDBIdentifier& transactionIdentifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode, std::function<void(bool)> successCallback) 286{ 287 postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreTransaction, transactionIdentifier, objectStoreIDs, mode), successCallback); 288} 289 290void UniqueIDBDatabase::beginTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback) 291{ 292 postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::beginBackingStoreTransaction, transactionIdentifier), successCallback); 293} 294 295void UniqueIDBDatabase::commitTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback) 296{ 297 postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::commitBackingStoreTransaction, transactionIdentifier), successCallback); 298} 299 300void UniqueIDBDatabase::resetTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback) 301{ 302 postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::resetBackingStoreTransaction, transactionIdentifier), successCallback); 303} 304 305void UniqueIDBDatabase::rollbackTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback) 306{ 307 postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::rollbackBackingStoreTransaction, transactionIdentifier), successCallback); 308} 309 310void UniqueIDBDatabase::postTransactionOperation(const IDBIdentifier& transactionIdentifier, std::unique_ptr<AsyncTask> task, std::function<void(bool)> successCallback) 311{ 312 ASSERT(RunLoop::isMain()); 313 314 if (!m_acceptingNewRequests) { 315 successCallback(false); 316 return; 317 } 318 319 if (m_pendingTransactionRequests.contains(transactionIdentifier)) { 320 LOG_ERROR("Attempting to queue an operation for a transaction that already has an operation pending. Each transaction should only have one operation pending at a time."); 321 successCallback(false); 322 return; 323 } 324 325 postDatabaseTask(WTF::move(task)); 326 327 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([successCallback](bool success) { 328 successCallback(success); 329 }, [successCallback]() { 330 successCallback(false); 331 }); 332 333 m_pendingTransactionRequests.add(transactionIdentifier, request.release()); 334} 335 336void UniqueIDBDatabase::didCompleteTransactionOperation(const IDBIdentifier& transactionIdentifier, bool success) 337{ 338 ASSERT(RunLoop::isMain()); 339 340 RefPtr<AsyncRequest> request = m_pendingTransactionRequests.take(transactionIdentifier); 341 342 if (request) 343 request->completeRequest(success); 344 345 if (m_pendingTransactionRollbacks.contains(transactionIdentifier)) 346 finalizeRollback(transactionIdentifier); 347} 348 349void UniqueIDBDatabase::changeDatabaseVersion(const IDBIdentifier& transactionIdentifier, uint64_t newVersion, std::function<void(bool)> successCallback) 350{ 351 ASSERT(RunLoop::isMain()); 352 353 if (!m_acceptingNewRequests) { 354 successCallback(false); 355 return; 356 } 357 358 uint64_t oldVersion = m_metadata->version; 359 m_metadata->version = newVersion; 360 361 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, oldVersion, successCallback](bool success) { 362 if (!success) 363 m_metadata->version = oldVersion; 364 successCallback(success); 365 }, [this, oldVersion, successCallback]() { 366 m_metadata->version = oldVersion; 367 successCallback(false); 368 }); 369 370 uint64_t requestID = request->requestID(); 371 m_pendingDatabaseTasks.add(requestID, request.release()); 372 373 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::changeDatabaseVersionInBackingStore, requestID, transactionIdentifier, newVersion)); 374} 375 376void UniqueIDBDatabase::didChangeDatabaseVersion(uint64_t requestID, bool success) 377{ 378 didCompleteBoolRequest(requestID, success); 379} 380 381void UniqueIDBDatabase::didCreateObjectStore(uint64_t requestID, bool success) 382{ 383 didCompleteBoolRequest(requestID, success); 384} 385 386void UniqueIDBDatabase::didDeleteObjectStore(uint64_t requestID, bool success) 387{ 388 didCompleteBoolRequest(requestID, success); 389} 390 391void UniqueIDBDatabase::didClearObjectStore(uint64_t requestID, bool success) 392{ 393 didCompleteBoolRequest(requestID, success); 394} 395 396void UniqueIDBDatabase::didCreateIndex(uint64_t requestID, bool success) 397{ 398 didCompleteBoolRequest(requestID, success); 399} 400 401void UniqueIDBDatabase::didDeleteIndex(uint64_t requestID, bool success) 402{ 403 didCompleteBoolRequest(requestID, success); 404} 405 406void UniqueIDBDatabase::didCompleteBoolRequest(uint64_t requestID, bool success) 407{ 408 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 409 ASSERT(request); 410 411 request->completeRequest(success); 412} 413 414void UniqueIDBDatabase::createObjectStore(const IDBIdentifier& transactionIdentifier, const IDBObjectStoreMetadata& metadata, std::function<void(bool)> successCallback) 415{ 416 ASSERT(RunLoop::isMain()); 417 418 if (!m_acceptingNewRequests) { 419 successCallback(false); 420 return; 421 } 422 423 ASSERT(!m_metadata->objectStores.contains(metadata.id)); 424 m_metadata->objectStores.set(metadata.id, metadata); 425 int64_t addedObjectStoreID = metadata.id; 426 427 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, addedObjectStoreID, successCallback](bool success) { 428 if (!success) 429 m_metadata->objectStores.remove(addedObjectStoreID); 430 successCallback(success); 431 }, [this, addedObjectStoreID, successCallback]() { 432 m_metadata->objectStores.remove(addedObjectStoreID); 433 successCallback(false); 434 }); 435 436 uint64_t requestID = request->requestID(); 437 m_pendingDatabaseTasks.add(requestID, request.release()); 438 439 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createObjectStoreInBackingStore, requestID, transactionIdentifier, metadata)); 440} 441 442void UniqueIDBDatabase::deleteObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, std::function<void(bool)> successCallback) 443{ 444 ASSERT(RunLoop::isMain()); 445 446 if (!m_acceptingNewRequests) { 447 successCallback(false); 448 return; 449 } 450 451 ASSERT(m_metadata->objectStores.contains(objectStoreID)); 452 IDBObjectStoreMetadata metadata = m_metadata->objectStores.take(objectStoreID); 453 454 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, metadata, successCallback](bool success) { 455 if (!success) 456 m_metadata->objectStores.set(metadata.id, metadata); 457 successCallback(success); 458 }, [this, metadata, successCallback]() { 459 m_metadata->objectStores.set(metadata.id, metadata); 460 successCallback(false); 461 }); 462 463 uint64_t requestID = request->requestID(); 464 m_pendingDatabaseTasks.add(requestID, request.release()); 465 466 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteObjectStoreInBackingStore, requestID, transactionIdentifier, objectStoreID)); 467} 468 469void UniqueIDBDatabase::clearObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, std::function<void(bool)> successCallback) 470{ 471 ASSERT(RunLoop::isMain()); 472 473 if (!m_acceptingNewRequests) { 474 successCallback(false); 475 return; 476 } 477 478 ASSERT(m_metadata->objectStores.contains(objectStoreID)); 479 480 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, successCallback](bool success) { 481 successCallback(success); 482 }, [this, successCallback]() { 483 successCallback(false); 484 }); 485 486 uint64_t requestID = request->requestID(); 487 m_pendingDatabaseTasks.add(requestID, request.release()); 488 489 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::clearObjectStoreInBackingStore, requestID, transactionIdentifier, objectStoreID)); 490} 491 492void UniqueIDBDatabase::createIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBIndexMetadata& metadata, std::function<void(bool)> successCallback) 493{ 494 ASSERT(RunLoop::isMain()); 495 496 if (!m_acceptingNewRequests) { 497 successCallback(false); 498 return; 499 } 500 501 ASSERT(m_metadata->objectStores.contains(objectStoreID)); 502 ASSERT(!m_metadata->objectStores.get(objectStoreID).indexes.contains(metadata.id)); 503 m_metadata->objectStores.get(objectStoreID).indexes.set(metadata.id, metadata); 504 int64_t addedIndexID = metadata.id; 505 506 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, addedIndexID, successCallback](bool success) { 507 if (!success) { 508 auto objectStoreFind = m_metadata->objectStores.find(objectStoreID); 509 if (objectStoreFind != m_metadata->objectStores.end()) 510 objectStoreFind->value.indexes.remove(addedIndexID); 511 } 512 successCallback(success); 513 }, [this, objectStoreID, addedIndexID, successCallback]() { 514 auto objectStoreFind = m_metadata->objectStores.find(objectStoreID); 515 if (objectStoreFind != m_metadata->objectStores.end()) 516 objectStoreFind->value.indexes.remove(addedIndexID); 517 successCallback(false); 518 }); 519 520 uint64_t requestID = request->requestID(); 521 m_pendingDatabaseTasks.add(requestID, request.release()); 522 523 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createIndexInBackingStore, requestID, transactionIdentifier, objectStoreID, metadata)); 524} 525 526void UniqueIDBDatabase::deleteIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, std::function<void(bool)> successCallback) 527{ 528 ASSERT(RunLoop::isMain()); 529 530 if (!m_acceptingNewRequests) { 531 successCallback(false); 532 return; 533 } 534 535 ASSERT(m_metadata->objectStores.contains(objectStoreID)); 536 ASSERT(m_metadata->objectStores.get(objectStoreID).indexes.contains(indexID)); 537 538 IDBIndexMetadata metadata = m_metadata->objectStores.get(objectStoreID).indexes.take(indexID); 539 540 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, metadata, successCallback](bool success) { 541 if (!success) { 542 auto objectStoreFind = m_metadata->objectStores.find(objectStoreID); 543 if (objectStoreFind != m_metadata->objectStores.end()) 544 objectStoreFind->value.indexes.set(metadata.id, metadata); 545 } 546 successCallback(success); 547 }, [this, objectStoreID, metadata, successCallback]() { 548 auto objectStoreFind = m_metadata->objectStores.find(objectStoreID); 549 if (objectStoreFind != m_metadata->objectStores.end()) 550 objectStoreFind->value.indexes.set(metadata.id, metadata); 551 successCallback(false); 552 }); 553 554 uint64_t requestID = request->requestID(); 555 m_pendingDatabaseTasks.add(requestID, request.release()); 556 557 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteIndexInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID)); 558} 559 560void UniqueIDBDatabase::putRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyData& keyData, const IPC::DataReference& value, int64_t putMode, const Vector<int64_t>& indexIDs, const Vector<Vector<IDBKeyData>>& indexKeys, std::function<void(const IDBKeyData&, uint32_t, const String&)> callback) 561{ 562 ASSERT(RunLoop::isMain()); 563 564 if (!m_acceptingNewRequests) { 565 callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database because it has shut down"); 566 return; 567 } 568 569 ASSERT(m_metadata->objectStores.contains(objectStoreID)); 570 571 RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, uint32_t, const String&>::create([this, callback](const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage) { 572 callback(keyData, errorCode, errorMessage); 573 }, [this, callback]() { 574 callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database"); 575 }); 576 577 uint64_t requestID = request->requestID(); 578 m_pendingDatabaseTasks.add(requestID, request.release()); 579 580 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::putRecordInBackingStore, requestID, transactionIdentifier, m_metadata->objectStores.get(objectStoreID), keyData, value.vector(), putMode, indexIDs, indexKeys)); 581} 582 583void UniqueIDBDatabase::getRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, IndexedDB::CursorType cursorType, std::function<void(const IDBGetResult&, uint32_t, const String&)> callback) 584{ 585 ASSERT(RunLoop::isMain()); 586 587 if (!m_acceptingNewRequests) { 588 callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database because it has shut down"); 589 return; 590 } 591 592 ASSERT(m_metadata->objectStores.contains(objectStoreID)); 593 594 RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBGetResult&, uint32_t, const String&>::create([this, callback](const IDBGetResult& result, uint32_t errorCode, const String& errorMessage) { 595 callback(result, errorCode, errorMessage); 596 }, [this, callback]() { 597 callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database"); 598 }); 599 600 uint64_t requestID = request->requestID(); 601 m_pendingDatabaseTasks.add(requestID, request.release()); 602 603 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::getRecordFromBackingStore, requestID, transactionIdentifier, m_metadata->objectStores.get(objectStoreID), indexID, keyRangeData, cursorType)); 604} 605 606void UniqueIDBDatabase::openCursor(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, IndexedDB::CursorDirection cursorDirection, IndexedDB::CursorType cursorType, IDBDatabaseBackend::TaskType taskType, const IDBKeyRangeData& keyRangeData, std::function<void(int64_t, const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback) 607{ 608 ASSERT(RunLoop::isMain()); 609 610 if (!m_acceptingNewRequests) { 611 callback(0, nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to open cursor in database because it has shut down"); 612 return; 613 } 614 615 ASSERT(m_metadata->objectStores.contains(objectStoreID)); 616 617 RefPtr<AsyncRequest> request = AsyncRequestImpl<int64_t, const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](int64_t cursorID, const IDBKeyData& key, const IDBKeyData& primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) { 618 callback(cursorID, key, primaryKey, value, errorCode, errorMessage); 619 }, [this, callback]() { 620 callback(0, nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to get record from database"); 621 }); 622 623 uint64_t requestID = request->requestID(); 624 m_pendingDatabaseTasks.add(requestID, request.release()); 625 626 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openCursorInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID, cursorDirection, cursorType, taskType, keyRangeData)); 627} 628 629void UniqueIDBDatabase::cursorAdvance(const IDBIdentifier& cursorIdentifier, uint64_t count, std::function<void(const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback) 630{ 631 ASSERT(RunLoop::isMain()); 632 633 if (!m_acceptingNewRequests) { 634 callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to advance cursor in database because it has shut down"); 635 return; 636 } 637 638 RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](const IDBKeyData& key, const IDBKeyData& primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) { 639 callback(key, primaryKey, value, errorCode, errorMessage); 640 }, [this, callback]() { 641 callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to advance cursor in database"); 642 }); 643 644 uint64_t requestID = request->requestID(); 645 m_pendingDatabaseTasks.add(requestID, request.release()); 646 647 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::advanceCursorInBackingStore, requestID, cursorIdentifier, count)); 648} 649 650void UniqueIDBDatabase::cursorIterate(const IDBIdentifier& cursorIdentifier, const IDBKeyData& key, std::function<void(const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback) 651{ 652 ASSERT(RunLoop::isMain()); 653 654 if (!m_acceptingNewRequests) { 655 callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to iterate cursor in database because it has shut down"); 656 return; 657 } 658 659 RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](const IDBKeyData& key, const IDBKeyData& primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) { 660 callback(key, primaryKey, value, errorCode, errorMessage); 661 }, [this, callback]() { 662 callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to iterate cursor in database"); 663 }); 664 665 uint64_t requestID = request->requestID(); 666 m_pendingDatabaseTasks.add(requestID, request.release()); 667 668 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::iterateCursorInBackingStore, requestID, cursorIdentifier, key)); 669} 670 671void UniqueIDBDatabase::count(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, std::function<void(int64_t, uint32_t, const String&)> callback) 672{ 673 ASSERT(RunLoop::isMain()); 674 675 if (!m_acceptingNewRequests) { 676 callback(0, INVALID_STATE_ERR, "Unable to get count from database because it has shut down"); 677 return; 678 } 679 680 RefPtr<AsyncRequest> request = AsyncRequestImpl<int64_t, uint32_t, const String&>::create([this, callback](int64_t count, uint32_t errorCode, const String& errorMessage) { 681 callback(count, errorCode, errorMessage); 682 }, [this, callback]() { 683 callback(0, INVALID_STATE_ERR, "Unable to get count from database"); 684 }); 685 686 uint64_t requestID = request->requestID(); 687 m_pendingDatabaseTasks.add(requestID, request.release()); 688 689 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::countInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID, keyRangeData)); 690} 691 692void UniqueIDBDatabase::deleteRange(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyRangeData& keyRangeData, std::function<void(uint32_t, const String&)> callback) 693{ 694 ASSERT(RunLoop::isMain()); 695 696 if (!m_acceptingNewRequests) { 697 callback(INVALID_STATE_ERR, "Unable to deleteRange from database because it has shut down"); 698 return; 699 } 700 701 RefPtr<AsyncRequest> request = AsyncRequestImpl<uint32_t, const String&>::create([callback](uint32_t errorCode, const String& errorMessage) { 702 callback(errorCode, errorMessage); 703 }, [callback]() { 704 callback(INVALID_STATE_ERR, "Unable to deleteRange from database"); 705 }); 706 707 uint64_t requestID = request->requestID(); 708 m_pendingDatabaseTasks.add(requestID, request.release()); 709 710 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteRangeInBackingStore, requestID, transactionIdentifier, objectStoreID, keyRangeData)); 711} 712 713void UniqueIDBDatabase::openBackingStoreTransaction(const IDBIdentifier& transactionIdentifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode) 714{ 715 ASSERT(!RunLoop::isMain()); 716 ASSERT(m_backingStore); 717 718 bool success = m_backingStore->establishTransaction(transactionIdentifier, objectStoreIDs, mode); 719 720 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didEstablishTransaction, transactionIdentifier, success)); 721 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success)); 722} 723 724void UniqueIDBDatabase::beginBackingStoreTransaction(const IDBIdentifier& transactionIdentifier) 725{ 726 ASSERT(!RunLoop::isMain()); 727 ASSERT(m_backingStore); 728 729 bool success = m_backingStore->beginTransaction(transactionIdentifier); 730 731 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success)); 732} 733 734void UniqueIDBDatabase::commitBackingStoreTransaction(const IDBIdentifier& transactionIdentifier) 735{ 736 ASSERT(!RunLoop::isMain()); 737 ASSERT(m_backingStore); 738 739 bool success = m_backingStore->commitTransaction(transactionIdentifier); 740 741 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success)); 742} 743 744void UniqueIDBDatabase::resetBackingStoreTransaction(const IDBIdentifier& transactionIdentifier) 745{ 746 ASSERT(!RunLoop::isMain()); 747 ASSERT(m_backingStore); 748 749 bool success = m_backingStore->resetTransaction(transactionIdentifier); 750 751 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didResetTransaction, transactionIdentifier, success)); 752 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success)); 753} 754 755void UniqueIDBDatabase::rollbackBackingStoreTransaction(const IDBIdentifier& transactionIdentifier) 756{ 757 ASSERT(!RunLoop::isMain()); 758 ASSERT(m_backingStore); 759 760 bool success = m_backingStore->rollbackTransaction(transactionIdentifier); 761 762 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success)); 763} 764 765void UniqueIDBDatabase::changeDatabaseVersionInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, uint64_t newVersion) 766{ 767 ASSERT(!RunLoop::isMain()); 768 ASSERT(m_backingStore); 769 770 bool success = m_backingStore->changeDatabaseVersion(transactionIdentifier, newVersion); 771 772 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didChangeDatabaseVersion, requestID, success)); 773} 774 775void UniqueIDBDatabase::createObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, const IDBObjectStoreMetadata& metadata) 776{ 777 ASSERT(!RunLoop::isMain()); 778 ASSERT(m_backingStore); 779 780 bool success = m_backingStore->createObjectStore(transactionIdentifier, metadata); 781 782 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateObjectStore, requestID, success)); 783} 784 785void UniqueIDBDatabase::deleteObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID) 786{ 787 ASSERT(!RunLoop::isMain()); 788 ASSERT(m_backingStore); 789 790 bool success = m_backingStore->deleteObjectStore(transactionIdentifier, objectStoreID); 791 792 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteObjectStore, requestID, success)); 793} 794 795void UniqueIDBDatabase::clearObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID) 796{ 797 ASSERT(!RunLoop::isMain()); 798 ASSERT(m_backingStore); 799 800 bool success = m_backingStore->clearObjectStore(transactionIdentifier, objectStoreID); 801 802 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didClearObjectStore, requestID, success)); 803} 804 805void UniqueIDBDatabase::createIndexInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBIndexMetadata& metadata) 806{ 807 ASSERT(!RunLoop::isMain()); 808 ASSERT(m_backingStore); 809 810 bool success = m_backingStore->createIndex(transactionIdentifier, objectStoreID, metadata); 811 812 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateIndex, requestID, success)); 813} 814 815void UniqueIDBDatabase::deleteIndexInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID) 816{ 817 ASSERT(!RunLoop::isMain()); 818 ASSERT(m_backingStore); 819 820 bool success = m_backingStore->deleteIndex(transactionIdentifier, objectStoreID, indexID); 821 822 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteIndex, requestID, success)); 823} 824 825void UniqueIDBDatabase::putRecordInBackingStore(uint64_t requestID, const IDBIdentifier& transaction, const IDBObjectStoreMetadata& objectStoreMetadata, const IDBKeyData& inputKeyData, const Vector<uint8_t>& value, int64_t putMode, const Vector<int64_t>& indexIDs, const Vector<Vector<IDBKeyData>>& indexKeys) 826{ 827 ASSERT(!RunLoop::isMain()); 828 ASSERT(m_backingStore); 829 830 bool keyWasGenerated = false; 831 IDBKeyData key; 832 int64_t keyNumber = 0; 833 834 if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && inputKeyData.isNull) { 835 if (!m_backingStore->generateKeyNumber(transaction, objectStoreMetadata.id, keyNumber)) { 836 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence"))); 837 return; 838 } 839 key.setNumberValue(keyNumber); 840 keyWasGenerated = true; 841 } else 842 key = inputKeyData; 843 844 if (putMode == IDBDatabaseBackend::AddOnly) { 845 bool keyExists; 846 if (!m_backingStore->keyExistsInObjectStore(transaction, objectStoreMetadata.id, key, keyExists)) { 847 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence"))); 848 return; 849 } 850 if (keyExists) { 851 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store"))); 852 return; 853 } 854 } 855 856 // The spec says that even if we're about to overwrite the record, perform the steps to delete it first. 857 // This is important because formally deleting it from from the object store also removes it from the appropriate indexes. 858 if (!m_backingStore->deleteRecord(transaction, objectStoreMetadata.id, key)) { 859 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Replacing an existing key in backing store, unable to delete previous record."))); 860 return; 861 } 862 863 if (!m_backingStore->putRecord(transaction, objectStoreMetadata.id, key, value.data(), value.size())) { 864 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error putting a record"))); 865 return; 866 } 867 868 ASSERT(indexIDs.size() == indexKeys.size()); 869 for (size_t i = 0; i < indexIDs.size(); ++i) { 870 for (size_t j = 0; j < indexKeys[i].size(); ++j) { 871 if (!m_backingStore->putIndexRecord(transaction, objectStoreMetadata.id, indexIDs[i], key, indexKeys[i][j])) { 872 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error writing index key"))); 873 return; 874 } 875 } 876 } 877 878 m_backingStore->notifyCursorsOfChanges(transaction, objectStoreMetadata.id); 879 880 if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && key.type == IDBKey::NumberType) { 881 if (!m_backingStore->updateKeyGeneratorNumber(transaction, objectStoreMetadata.id, keyNumber, keyWasGenerated)) { 882 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error updating key generator"))); 883 return; 884 } 885 } 886 887 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, key, 0, String(StringImpl::empty()))); 888} 889 890void UniqueIDBDatabase::didPutRecordInBackingStore(uint64_t requestID, const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage) 891{ 892 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 893 ASSERT(request); 894 895 request->completeRequest(keyData, errorCode, errorMessage); 896} 897 898void UniqueIDBDatabase::getRecordFromBackingStore(uint64_t requestID, const IDBIdentifier& transaction, const IDBObjectStoreMetadata& objectStoreMetadata, int64_t indexID, const IDBKeyRangeData& keyRangeData, IndexedDB::CursorType cursorType) 899{ 900 ASSERT(!RunLoop::isMain()); 901 ASSERT(m_backingStore); 902 903 RefPtr<IDBKeyRange> keyRange = keyRangeData.maybeCreateIDBKeyRange(); 904 ASSERT(keyRange); 905 if (!keyRange) { 906 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Invalid IDBKeyRange requested from backing store"))); 907 return; 908 } 909 910 if (indexID == IDBIndexMetadata::InvalidId) { 911 // IDBObjectStore get record 912 RefPtr<SharedBuffer> result; 913 914 if (keyRange->isOnlyKey()) { 915 if (!m_backingStore->getKeyRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange->lower(), result)) 916 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key record from object store in backing store"))); 917 else { 918 IDBGetResult getResult = result ? IDBGetResult(result.release(), keyRange->lower(), objectStoreMetadata.keyPath) : IDBGetResult(); 919 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, getResult, 0, String(StringImpl::empty()))); 920 } 921 922 return; 923 } 924 925 RefPtr<IDBKey> resultKey; 926 927 if (!m_backingStore->getKeyRangeRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange, result, resultKey)) 928 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key range record from object store in backing store"))); 929 else { 930 IDBGetResult getResult = result ? IDBGetResult(result.release(), resultKey.release(), objectStoreMetadata.keyPath) : IDBGetResult(); 931 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, getResult, 0, String(StringImpl::empty()))); 932 } 933 934 return; 935 } 936 937 // IDBIndex get record 938 939 IDBGetResult result; 940 if (!m_backingStore->getIndexRecord(transaction, objectStoreMetadata.id, indexID, keyRangeData, cursorType, result)) { 941 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get index record from backing store"))); 942 return; 943 } 944 945 // We must return a key path to know how to inject the result key into the result value object. 946 result.keyPath = objectStoreMetadata.keyPath; 947 948 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, result, 0, String(StringImpl::empty()))); 949} 950 951void UniqueIDBDatabase::didGetRecordFromBackingStore(uint64_t requestID, const IDBGetResult& result, uint32_t errorCode, const String& errorMessage) 952{ 953 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 954 ASSERT(request); 955 956 request->completeRequest(result, errorCode, errorMessage); 957} 958 959void UniqueIDBDatabase::openCursorInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, IndexedDB::CursorDirection cursorDirection, IndexedDB::CursorType cursorType, IDBDatabaseBackend::TaskType taskType, const IDBKeyRangeData& keyRange) 960{ 961 ASSERT(!RunLoop::isMain()); 962 ASSERT(m_backingStore); 963 964 int64_t cursorID = 0; 965 IDBKeyData key; 966 IDBKeyData primaryKey; 967 Vector<uint8_t> valueBuffer; 968 int32_t errorCode = 0; 969 String errorMessage; 970 bool success = m_backingStore->openCursor(transactionIdentifier, objectStoreID, indexID, cursorDirection, cursorType, taskType, keyRange, cursorID, key, primaryKey, valueBuffer); 971 972 if (!success) { 973 errorCode = IDBDatabaseException::UnknownError; 974 errorMessage = ASCIILiteral("Unknown error opening cursor in backing store"); 975 } 976 977 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenCursorInBackingStore, requestID, cursorID, key, primaryKey, valueBuffer, errorCode, errorMessage)); 978} 979 980void UniqueIDBDatabase::didOpenCursorInBackingStore(uint64_t requestID, int64_t cursorID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<uint8_t>& valueBuffer, uint32_t errorCode, const String& errorMessage) 981{ 982 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 983 ASSERT(request); 984 985 request->completeRequest(cursorID, key, primaryKey, SharedBuffer::create(valueBuffer.data(), valueBuffer.size()), errorCode, errorMessage); 986} 987 988void UniqueIDBDatabase::advanceCursorInBackingStore(uint64_t requestID, const IDBIdentifier& cursorIdentifier, uint64_t count) 989{ 990 IDBKeyData key; 991 IDBKeyData primaryKey; 992 Vector<uint8_t> valueBuffer; 993 int32_t errorCode = 0; 994 String errorMessage; 995 bool success = m_backingStore->advanceCursor(cursorIdentifier, count, key, primaryKey, valueBuffer); 996 997 if (!success) { 998 errorCode = IDBDatabaseException::UnknownError; 999 errorMessage = ASCIILiteral("Unknown error advancing cursor in backing store"); 1000 } 1001 1002 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didAdvanceCursorInBackingStore, requestID, key, primaryKey, valueBuffer, errorCode, errorMessage)); 1003} 1004 1005void UniqueIDBDatabase::didAdvanceCursorInBackingStore(uint64_t requestID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<uint8_t>& valueBuffer, uint32_t errorCode, const String& errorMessage) 1006{ 1007 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 1008 ASSERT(request); 1009 1010 request->completeRequest(key, primaryKey, SharedBuffer::create(valueBuffer.data(), valueBuffer.size()), errorCode, errorMessage); 1011} 1012 1013void UniqueIDBDatabase::iterateCursorInBackingStore(uint64_t requestID, const IDBIdentifier& cursorIdentifier, const IDBKeyData& iterateKey) 1014{ 1015 IDBKeyData key; 1016 IDBKeyData primaryKey; 1017 Vector<uint8_t> valueBuffer; 1018 int32_t errorCode = 0; 1019 String errorMessage; 1020 bool success = m_backingStore->iterateCursor(cursorIdentifier, iterateKey, key, primaryKey, valueBuffer); 1021 1022 if (!success) { 1023 errorCode = IDBDatabaseException::UnknownError; 1024 errorMessage = ASCIILiteral("Unknown error iterating cursor in backing store"); 1025 } 1026 1027 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didIterateCursorInBackingStore, requestID, key, primaryKey, valueBuffer, errorCode, errorMessage)); 1028} 1029 1030void UniqueIDBDatabase::didIterateCursorInBackingStore(uint64_t requestID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<uint8_t>& valueBuffer, uint32_t errorCode, const String& errorMessage) 1031{ 1032 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 1033 ASSERT(request); 1034 1035 request->completeRequest(key, primaryKey, SharedBuffer::create(valueBuffer.data(), valueBuffer.size()), errorCode, errorMessage); 1036} 1037 1038void UniqueIDBDatabase::countInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData) 1039{ 1040 int64_t count; 1041 1042 if (!m_backingStore->count(transactionIdentifier, objectStoreID, indexID, keyRangeData, count)) { 1043 LOG_ERROR("Failed to get count from backing store."); 1044 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCountInBackingStore, requestID, 0, IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get count from backing store"))); 1045 } 1046 1047 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCountInBackingStore, requestID, count, 0, String(StringImpl::empty()))); 1048} 1049 1050void UniqueIDBDatabase::didCountInBackingStore(uint64_t requestID, int64_t count, uint32_t errorCode, const String& errorMessage) 1051{ 1052 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 1053 ASSERT(request); 1054 1055 request->completeRequest(count, errorCode, errorMessage); 1056} 1057 1058void UniqueIDBDatabase::deleteRangeInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyRangeData& keyRangeData) 1059{ 1060 if (!m_backingStore->deleteRange(transactionIdentifier, objectStoreID, keyRangeData)) { 1061 LOG_ERROR("Failed to delete range from backing store."); 1062 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteRangeInBackingStore, requestID, IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get count from backing store"))); 1063 } 1064 1065 m_backingStore->notifyCursorsOfChanges(transactionIdentifier, objectStoreID); 1066 1067 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteRangeInBackingStore, requestID, 0, String(StringImpl::empty()))); 1068} 1069 1070void UniqueIDBDatabase::didDeleteRangeInBackingStore(uint64_t requestID, uint32_t errorCode, const String& errorMessage) 1071{ 1072 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID); 1073 ASSERT(request); 1074 1075 request->completeRequest(errorCode, errorMessage); 1076} 1077 1078void UniqueIDBDatabase::didEstablishTransaction(const IDBIdentifier& transactionIdentifier, bool success) 1079{ 1080 ASSERT(RunLoop::isMain()); 1081 if (!success) 1082 return; 1083 1084 auto transactions = m_establishedTransactions.add(&transactionIdentifier.connection(), HashSet<IDBIdentifier>()); 1085 transactions.iterator->value.add(transactionIdentifier); 1086} 1087 1088void UniqueIDBDatabase::didResetTransaction(const IDBIdentifier& transactionIdentifier, bool success) 1089{ 1090 ASSERT(RunLoop::isMain()); 1091 if (!success) 1092 return; 1093 1094 auto transactions = m_establishedTransactions.find(&transactionIdentifier.connection()); 1095 if (transactions != m_establishedTransactions.end()) 1096 transactions.get()->value.remove(transactionIdentifier); 1097} 1098 1099void UniqueIDBDatabase::resetAllTransactions(const DatabaseProcessIDBConnection& connection) 1100{ 1101 ASSERT(RunLoop::isMain()); 1102 auto transactions = m_establishedTransactions.find(&connection); 1103 if (transactions == m_establishedTransactions.end() || !m_acceptingNewRequests) 1104 return; 1105 1106 for (auto& transactionIdentifier : transactions.get()->value) { 1107 m_pendingTransactionRollbacks.add(transactionIdentifier); 1108 if (!m_pendingTransactionRequests.contains(transactionIdentifier)) 1109 finalizeRollback(transactionIdentifier); 1110 } 1111} 1112 1113void UniqueIDBDatabase::finalizeRollback(const WebKit::IDBIdentifier& transactionId) 1114{ 1115 ASSERT(RunLoop::isMain()); 1116 ASSERT(m_pendingTransactionRollbacks.contains(transactionId)); 1117 ASSERT(!m_pendingTransactionRequests.contains(transactionId)); 1118 rollbackTransaction(transactionId, [this, transactionId](bool) { 1119 ASSERT(RunLoop::isMain()); 1120 if (m_pendingTransactionRequests.contains(transactionId)) 1121 return; 1122 1123 ASSERT(m_pendingTransactionRollbacks.contains(transactionId)); 1124 m_pendingTransactionRollbacks.remove(transactionId); 1125 resetTransaction(transactionId, [this, transactionId](bool) { 1126 if (m_acceptingNewRequests && m_connections.isEmpty() && m_pendingTransactionRollbacks.isEmpty()) { 1127 shutdown(UniqueIDBDatabaseShutdownType::NormalShutdown); 1128 DatabaseProcess::shared().removeUniqueIDBDatabase(*this); 1129 } 1130 }); 1131 }); 1132} 1133 1134String UniqueIDBDatabase::absoluteDatabaseDirectory() const 1135{ 1136 ASSERT(RunLoop::isMain()); 1137 return DatabaseProcess::shared().absoluteIndexedDatabasePathFromDatabaseRelativePath(m_databaseRelativeDirectory); 1138} 1139 1140void UniqueIDBDatabase::postMainThreadTask(std::unique_ptr<AsyncTask> task, DatabaseTaskType taskType) 1141{ 1142 ASSERT(!RunLoop::isMain()); 1143 1144 if (!m_acceptingNewRequests && taskType == DatabaseTaskType::Normal) 1145 return; 1146 1147 MutexLocker locker(m_mainThreadTaskMutex); 1148 1149 m_mainThreadTasks.append(WTF::move(task)); 1150 1151 // Balanced by an adoptRef() in ::performNextMainThreadTask 1152 ref(); 1153 RunLoop::main().dispatch(bind(&UniqueIDBDatabase::performNextMainThreadTask, this)); 1154} 1155 1156void UniqueIDBDatabase::performNextMainThreadTask() 1157{ 1158 ASSERT(RunLoop::isMain()); 1159 1160 // Balanced by a ref() in ::postMainThreadTask 1161 RefPtr<UniqueIDBDatabase> protector(adoptRef(this)); 1162 1163 performNextMainThreadTaskWithoutAdoptRef(); 1164} 1165 1166bool UniqueIDBDatabase::performNextMainThreadTaskWithoutAdoptRef() 1167{ 1168 bool moreTasks; 1169 1170 std::unique_ptr<AsyncTask> task; 1171 { 1172 MutexLocker locker(m_mainThreadTaskMutex); 1173 1174 // This database might be shutting down, in which case the task queue might be empty. 1175 if (m_mainThreadTasks.isEmpty()) 1176 return false; 1177 1178 task = m_mainThreadTasks.takeFirst(); 1179 moreTasks = !m_mainThreadTasks.isEmpty(); 1180 } 1181 1182 task->performTask(); 1183 1184 return moreTasks; 1185} 1186 1187void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<AsyncTask> task, DatabaseTaskType taskType) 1188{ 1189 ASSERT(RunLoop::isMain()); 1190 1191 if (!m_acceptingNewRequests && taskType == DatabaseTaskType::Normal) 1192 return; 1193 1194 MutexLocker locker(m_databaseTaskMutex); 1195 1196 m_databaseTasks.append(WTF::move(task)); 1197 1198 DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::performNextDatabaseTask, this)); 1199} 1200 1201void UniqueIDBDatabase::performNextDatabaseTask() 1202{ 1203 ASSERT(!RunLoop::isMain()); 1204 1205 // It is possible that this database might be shutting down on the main thread. 1206 // In this case, immediately after releasing m_databaseTaskMutex, this database might get deleted. 1207 // We take a ref() to make sure the database is still live while this last task is performed. 1208 RefPtr<UniqueIDBDatabase> protector(this); 1209 1210 std::unique_ptr<AsyncTask> task; 1211 { 1212 MutexLocker locker(m_databaseTaskMutex); 1213 1214 // This database might be shutting down on the main thread, in which case the task queue might be empty. 1215 if (m_databaseTasks.isEmpty()) 1216 return; 1217 1218 task = m_databaseTasks.takeFirst(); 1219 } 1220 1221 task->performTask(); 1222} 1223 1224} // namespace WebKit 1225 1226#endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS) 1227