Bug 1156063 - Intermittent application crashed [@ mozilla::dom::indexedDB::::ConnectionPool::Start] in various tests. r=janv, a=lizzard
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -4127,26 +4127,32 @@ private:
void
EnsureDatabaseActor();
nsresult
EnsureDatabaseActorIsAlive();
void
+ CleanupBackgroundThreadObjects(bool aInvalidate);
+
+ void
MetadataToSpec(DatabaseSpec& aSpec);
void
AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
#ifdef DEBUG
;
#else
{ }
#endif
+ virtual void
+ ActorDestroy(ActorDestroyReason aWhy) override;
+
virtual nsresult
QuotaManagerOpen() override;
virtual nsresult
DoDatabaseWork() override;
virtual nsresult
BeginVersionChange() override;
@@ -5177,17 +5183,17 @@ public:
}
static bool
IsShuttingDownOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
if (sInstance) {
- return sInstance->mShutdownRequested;
+ return sInstance->IsShuttingDown();
}
return QuotaManager::IsShuttingDown();
}
static bool
IsShuttingDownOnNonMainThread()
{
@@ -5258,23 +5264,21 @@ private:
UsageInfo* aUsageInfo,
bool aDatabaseFiles);
};
class QuotaClient::ShutdownTransactionThreadPoolRunnable final
: public nsRunnable
{
nsRefPtr<QuotaClient> mQuotaClient;
- bool mHasRequestedShutDown;
public:
explicit ShutdownTransactionThreadPoolRunnable(QuotaClient* aQuotaClient)
: mQuotaClient(aQuotaClient)
- , mHasRequestedShutDown(false)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aQuotaClient);
MOZ_ASSERT(QuotaClient::GetInstance() == aQuotaClient);
MOZ_ASSERT(aQuotaClient->mShutdownRequested);
}
NS_DECL_ISUPPORTS_INHERITED
@@ -9856,38 +9860,32 @@ WaitForTransactionsRunnable::Run()
NS_IMPL_ISUPPORTS_INHERITED0(QuotaClient::ShutdownTransactionThreadPoolRunnable,
nsRunnable)
NS_IMETHODIMP
QuotaClient::
ShutdownTransactionThreadPoolRunnable::Run()
{
if (NS_IsMainThread()) {
- MOZ_ASSERT(mHasRequestedShutDown);
MOZ_ASSERT(QuotaClient::GetInstance() == mQuotaClient);
MOZ_ASSERT(mQuotaClient->mShutdownRunnable == this);
mQuotaClient->mShutdownRunnable = nullptr;
mQuotaClient = nullptr;
return NS_OK;
}
AssertIsOnBackgroundThread();
- if (!mHasRequestedShutDown) {
- mHasRequestedShutDown = true;
-
- nsRefPtr<TransactionThreadPool> threadPool = gTransactionThreadPool.get();
- if (threadPool) {
- threadPool->Shutdown();
-
- gTransactionThreadPool = nullptr;
- }
-
+ nsRefPtr<TransactionThreadPool> threadPool = gTransactionThreadPool.get();
+ if (threadPool) {
+ threadPool->Shutdown();
+
+ gTransactionThreadPool = nullptr;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this)));
return NS_OK;
}
/*******************************************************************************
@@ -11209,16 +11207,28 @@ OpenDatabaseOp::OpenDatabaseOp(Factory*
// This is a little scary but it looks safe to call this off the main thread
// for now.
optionalContentParentId = mContentParent->ChildID();
} else {
optionalContentParentId = void_t();
}
}
+void
+OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
+{
+ AssertIsOnOwningThread();
+
+ FactoryOp::ActorDestroy(aWhy);
+
+ if (aWhy != Deletion) {
+ CleanupBackgroundThreadObjects(/* aInvalidate */ true);
+ }
+}
+
nsresult
OpenDatabaseOp::QuotaManagerOpen()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mState == State_OpenPending);
MOZ_ASSERT(!mOfflineStorage);
QuotaClient* quotaClient = QuotaClient::GetInstance();
@@ -11719,17 +11729,16 @@ OpenDatabaseOp::BeginVersionChange()
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State_BeginVersionChange);
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
MOZ_ASSERT(mMetadata->mCommonMetadata.version() <= mRequestedVersion);
MOZ_ASSERT(!mDatabase);
MOZ_ASSERT(!mVersionChangeTransaction);
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
- !OperationMayProceed() ||
IsActorDestroyed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
EnsureDatabaseActor();
if (mDatabase->IsInvalidated()) {
@@ -11837,17 +11846,18 @@ OpenDatabaseOp::DispatchToWorkThread()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State_WaitingForTransactionsToComplete);
MOZ_ASSERT(mVersionChangeTransaction);
MOZ_ASSERT(mVersionChangeTransaction->GetMode() ==
IDBTransaction::VERSION_CHANGE);
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
- if (IsActorDestroyed()) {
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+ IsActorDestroyed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
mState = State_DatabaseWorkVersionChange;
// Intentionally empty.
nsTArray<nsString> objectStoreNames;
@@ -11884,17 +11894,16 @@ OpenDatabaseOp::SendUpgradeNeeded()
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State_DatabaseWorkVersionChange);
MOZ_ASSERT(mVersionChangeTransaction);
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
MOZ_ASSERT_IF(!IsActorDestroyed(), mDatabase);
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
- !OperationMayProceed() ||
IsActorDestroyed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsRefPtr<VersionChangeTransaction> transaction;
mVersionChangeTransaction.swap(transaction);
@@ -11945,17 +11954,21 @@ OpenDatabaseOp::SendResults()
if (mVersionChangeTransaction) {
MOZ_ASSERT(NS_FAILED(mResultCode));
mVersionChangeTransaction->Abort(mResultCode, /* aForce */ true);
mVersionChangeTransaction = nullptr;
}
- if (!IsActorDestroyed()) {
+ if (IsActorDestroyed()) {
+ if (NS_SUCCEEDED(mResultCode)) {
+ mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+ } else {
FactoryRequestResponse response;
if (NS_SUCCEEDED(mResultCode)) {
// If we just successfully completed a versionchange operation then we
// need to update the version in our metadata.
mMetadata->mCommonMetadata.version() = mRequestedVersion;
nsresult rv = EnsureDatabaseActorIsAlive();
@@ -11980,24 +11993,17 @@ OpenDatabaseOp::SendResults()
#endif
response = ClampResultCode(mResultCode);
}
unused <<
PBackgroundIDBFactoryRequestParent::Send__delete__(this, response);
}
- if (NS_FAILED(mResultCode) && mOfflineStorage) {
- mOfflineStorage->CloseOnOwningThread();
- DatabaseOfflineStorage::UnregisterOnOwningThread(mOfflineStorage.forget());
- }
-
- // Make sure to release the database on this thread.
- nsRefPtr<Database> database;
- mDatabase.swap(database);
+ CleanupBackgroundThreadObjects(NS_FAILED(mResultCode));
FinishSendResults();
}
void
OpenDatabaseOp::EnsureDatabaseActor()
{
AssertIsOnOwningThread();
@@ -12070,16 +12076,37 @@ OpenDatabaseOp::EnsureDatabaseActorIsAli
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
return NS_OK;
}
void
+OpenDatabaseOp::CleanupBackgroundThreadObjects(bool aInvalidate)
+{
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(IsActorDestroyed());
+
+ if (mDatabase) {
+ MOZ_ASSERT(!mOfflineStorage);
+
+ if (aInvalidate) {
+ mDatabase->Invalidate();
+ }
+
+ // Make sure to release the database on this thread.
+ mDatabase = nullptr;
+ } else if (mOfflineStorage) {
+ mOfflineStorage->CloseOnOwningThread();
+ DatabaseOfflineStorage::UnregisterOnOwningThread(mOfflineStorage.forget());
+ }
+}
+
+void
OpenDatabaseOp::MetadataToSpec(DatabaseSpec& aSpec)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mMetadata);
class MOZ_STACK_CLASS Helper final
{
DatabaseSpec& mSpec;
@@ -12582,17 +12609,16 @@ DeleteDatabaseOp::DoDatabaseWork()
nsresult
DeleteDatabaseOp::BeginVersionChange()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State_BeginVersionChange);
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
- !OperationMayProceed() ||
IsActorDestroyed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
DatabaseActorInfo* info;
if (gLiveDatabaseHashtable->Get(mDatabaseId, &info)) {
MOZ_ASSERT(!info->mWaitingFactoryOp);
@@ -12622,17 +12648,16 @@ DeleteDatabaseOp::BeginVersionChange()
nsresult
DeleteDatabaseOp::DispatchToWorkThread()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State_WaitingForTransactionsToComplete);
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
- !OperationMayProceed() ||
IsActorDestroyed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
mState = State_DatabaseWorkVersionChange;
nsRefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);