void IDBDatabase::CloseInternal() { AssertIsOnOwningThread(); if (!mClosed) { mClosed = true; ExpireFileActors(/* aExpireAll */ true); if (mObserver) { mObserver->Revoke(); nsCOMPtr<nsIObserverService> obsSvc = GetObserverService(); if (obsSvc) { // These might not have been registered. obsSvc->RemoveObserver(mObserver, kCycleCollectionObserverTopic); obsSvc->RemoveObserver(mObserver, kMemoryPressureObserverTopic); MOZ_ALWAYS_TRUE(NS_SUCCEEDED( obsSvc->RemoveObserver(mObserver, kWindowObserverTopic))); } mObserver = nullptr; } if (mBackgroundActor && !mInvalidated) { mBackgroundActor->SendClose(); } } }
nsresult IDBDatabase::Transaction(JSContext* aCx, const StringOrStringSequence& aStoreNames, IDBTransactionMode aMode, IDBTransaction** aTransaction) { AssertIsOnOwningThread(); if (NS_WARN_IF((aMode == IDBTransactionMode::Readwriteflush || aMode == IDBTransactionMode::Cleanup) && !IndexedDatabaseManager::ExperimentalFeaturesEnabled())) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (QuotaManager::IsShuttingDown()) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (mClosed || RunningVersionChangeTransaction()) { return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } AutoTArray<nsString, 1> stackSequence; if (aStoreNames.IsString()) { stackSequence.AppendElement(aStoreNames.GetAsString()); } else { MOZ_ASSERT(aStoreNames.IsStringSequence()); if (aStoreNames.GetAsStringSequence().IsEmpty()) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } } const nsTArray<nsString>& storeNames = aStoreNames.IsString() ? stackSequence : static_cast<const nsTArray<nsString>&>(aStoreNames.GetAsStringSequence()); MOZ_ASSERT(!storeNames.IsEmpty()); const nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores(); const uint32_t nameCount = storeNames.Length(); nsTArray<nsString> sortedStoreNames; sortedStoreNames.SetCapacity(nameCount); // Check to make sure the object store names we collected actually exist. for (uint32_t nameIndex = 0; nameIndex < nameCount; nameIndex++) { const nsString& name = storeNames[nameIndex]; bool found = false; for (uint32_t objCount = objectStores.Length(), objIndex = 0; objIndex < objCount; objIndex++) { if (objectStores[objIndex].metadata().name() == name) { found = true; break; } } if (!found) { return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR; } sortedStoreNames.InsertElementSorted(name); } // Remove any duplicates. for (uint32_t nameIndex = nameCount - 1; nameIndex > 0; nameIndex--) { if (sortedStoreNames[nameIndex] == sortedStoreNames[nameIndex - 1]) { sortedStoreNames.RemoveElementAt(nameIndex); } } IDBTransaction::Mode mode; switch (aMode) { case IDBTransactionMode::Readonly: mode = IDBTransaction::READ_ONLY; break; case IDBTransactionMode::Readwrite: mode = IDBTransaction::READ_WRITE; break; case IDBTransactionMode::Readwriteflush: mode = IDBTransaction::READ_WRITE_FLUSH; break; case IDBTransactionMode::Cleanup: mode = IDBTransaction::CLEANUP; break; case IDBTransactionMode::Versionchange: return NS_ERROR_DOM_INVALID_ACCESS_ERR; default: MOZ_CRASH("Unknown mode!"); } RefPtr<IDBTransaction> transaction = IDBTransaction::Create(aCx, this, sortedStoreNames, mode); if (NS_WARN_IF(!transaction)) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } BackgroundTransactionChild* actor = new BackgroundTransactionChild(transaction); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " "database(%s).transaction(%s)", "IndexedDB %s: C T[%lld]: IDBDatabase.transaction()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(transaction)); MOZ_ALWAYS_TRUE( mBackgroundActor->SendPBackgroundIDBTransactionConstructor(actor, sortedStoreNames, mode)); transaction->SetBackgroundActor(actor); if (aMode == IDBTransactionMode::Cleanup) { ExpireFileActors(/* aExpireAll */ true); } transaction.forget(aTransaction); return NS_OK; }