mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1147942 - Don't warn when aborting finished IndexedDB transactions, r=janv.
This commit is contained in:
parent
0449f2b1ca
commit
d7fb6b8331
@ -896,70 +896,104 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
|
|||||||
|
|
||||||
class MOZ_STACK_CLASS Helper final
|
class MOZ_STACK_CLASS Helper final
|
||||||
{
|
{
|
||||||
|
typedef nsAutoTArray<nsRefPtr<IDBTransaction>, 20> StrongTransactionArray;
|
||||||
|
typedef nsAutoTArray<IDBTransaction*, 20> WeakTransactionArray;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void
|
static void
|
||||||
AbortTransactions(nsTHashtable<nsPtrHashKey<IDBTransaction>>& aTable,
|
AbortTransactions(IDBDatabase* aDatabase, const bool aShouldWarn)
|
||||||
nsTArray<nsRefPtr<IDBTransaction>>& aAbortedTransactions)
|
|
||||||
{
|
{
|
||||||
const uint32_t count = aTable.Count();
|
MOZ_ASSERT(aDatabase);
|
||||||
if (!count) {
|
aDatabase->AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
nsTHashtable<nsPtrHashKey<IDBTransaction>>& transactionTable =
|
||||||
|
aDatabase->mTransactions;
|
||||||
|
|
||||||
|
if (!transactionTable.Count()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoTArray<nsRefPtr<IDBTransaction>, 20> transactions;
|
StrongTransactionArray transactionsToAbort;
|
||||||
transactions.SetCapacity(count);
|
transactionsToAbort.SetCapacity(transactionTable.Count());
|
||||||
|
|
||||||
aTable.EnumerateEntries(Collect, &transactions);
|
transactionTable.EnumerateEntries(Collect, &transactionsToAbort);
|
||||||
|
MOZ_ASSERT(transactionsToAbort.Length() <= transactionTable.Count());
|
||||||
|
|
||||||
MOZ_ASSERT(transactions.Length() == count);
|
if (transactionsToAbort.IsEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t index = 0; index < count; index++) {
|
// We want to abort transactions as soon as possible so we iterate the
|
||||||
nsRefPtr<IDBTransaction> transaction = Move(transactions[index]);
|
// transactions once and abort them all first, collecting the transactions
|
||||||
|
// that need to have a warning issued along the way. Those that need a
|
||||||
|
// warning will be a subset of those that are aborted, so we don't need
|
||||||
|
// additional strong references here.
|
||||||
|
WeakTransactionArray transactionsThatNeedWarning;
|
||||||
|
|
||||||
|
for (nsRefPtr<IDBTransaction>& transaction : transactionsToAbort) {
|
||||||
MOZ_ASSERT(transaction);
|
MOZ_ASSERT(transaction);
|
||||||
|
MOZ_ASSERT(!transaction->IsDone());
|
||||||
|
|
||||||
|
if (aShouldWarn) {
|
||||||
|
switch (transaction->GetMode()) {
|
||||||
|
// We ignore transactions that could not have written any data.
|
||||||
|
case IDBTransaction::READ_ONLY:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// We warn for any transactions that could have written data.
|
||||||
|
case IDBTransaction::READ_WRITE:
|
||||||
|
case IDBTransaction::READ_WRITE_FLUSH:
|
||||||
|
case IDBTransaction::VERSION_CHANGE:
|
||||||
|
transactionsThatNeedWarning.AppendElement(transaction);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
MOZ_CRASH("Unknown mode!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||||
|
|
||||||
// We only care about warning for write transactions.
|
|
||||||
if (transaction->GetMode() != IDBTransaction::READ_ONLY) {
|
|
||||||
aAbortedTransactions.AppendElement(Move(transaction));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
static const char kWarningMessage[] =
|
||||||
static PLDHashOperator
|
"IndexedDBTransactionAbortNavigation";
|
||||||
Collect(nsPtrHashKey<IDBTransaction>* aTransaction, void* aClosure)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aTransaction);
|
|
||||||
aTransaction->GetKey()->AssertIsOnOwningThread();
|
|
||||||
MOZ_ASSERT(aClosure);
|
|
||||||
|
|
||||||
auto* array = static_cast<nsTArray<nsRefPtr<IDBTransaction>>*>(aClosure);
|
for (IDBTransaction* transaction : transactionsThatNeedWarning) {
|
||||||
array->AppendElement(aTransaction->GetKey());
|
|
||||||
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
nsAutoTArray<nsRefPtr<IDBTransaction>, 5> abortedTransactions;
|
|
||||||
Helper::AbortTransactions(mTransactions, abortedTransactions);
|
|
||||||
|
|
||||||
if (aShouldWarn && !abortedTransactions.IsEmpty()) {
|
|
||||||
static const char kWarningMessage[] = "IndexedDBTransactionAbortNavigation";
|
|
||||||
|
|
||||||
for (uint32_t count = abortedTransactions.Length(), index = 0;
|
|
||||||
index < count;
|
|
||||||
index++) {
|
|
||||||
nsRefPtr<IDBTransaction>& transaction = abortedTransactions[index];
|
|
||||||
MOZ_ASSERT(transaction);
|
MOZ_ASSERT(transaction);
|
||||||
|
|
||||||
nsString filename;
|
nsString filename;
|
||||||
uint32_t lineNo;
|
uint32_t lineNo;
|
||||||
transaction->GetCallerLocation(filename, &lineNo);
|
transaction->GetCallerLocation(filename, &lineNo);
|
||||||
|
|
||||||
LogWarning(kWarningMessage, filename, lineNo);
|
aDatabase->LogWarning(kWarningMessage, filename, lineNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static PLDHashOperator
|
||||||
|
Collect(nsPtrHashKey<IDBTransaction>* aTransactionKey, void* aClosure)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aTransactionKey);
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
|
||||||
|
IDBTransaction* transaction = aTransactionKey->GetKey();
|
||||||
|
MOZ_ASSERT(transaction);
|
||||||
|
|
||||||
|
transaction->AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
// Transactions that are already done can simply be ignored. Otherwise
|
||||||
|
// there is a race here and it's possible that the transaction has not
|
||||||
|
// been successfully committed yet so we will warn the user.
|
||||||
|
if (!transaction->IsDone()) {
|
||||||
|
auto* array = static_cast<StrongTransactionArray*>(aClosure);
|
||||||
|
array->AppendElement(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Helper::AbortTransactions(this, aShouldWarn);
|
||||||
}
|
}
|
||||||
|
|
||||||
PBackgroundIDBDatabaseFileChild*
|
PBackgroundIDBDatabaseFileChild*
|
||||||
|
@ -1437,7 +1437,7 @@ IDBObjectStore::Index(const nsAString& aName, ErrorResult &aRv)
|
|||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
if (mTransaction->IsFinished()) {
|
if (mTransaction->IsCommittingOrDone() || mDeletedSpec) {
|
||||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ IDBTransaction::SendCommit()
|
|||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(mAbortCode));
|
MOZ_ASSERT(NS_SUCCEEDED(mAbortCode));
|
||||||
MOZ_ASSERT(IsFinished());
|
MOZ_ASSERT(IsCommittingOrDone());
|
||||||
MOZ_ASSERT(!mSentCommitOrAbort);
|
MOZ_ASSERT(!mSentCommitOrAbort);
|
||||||
MOZ_ASSERT(!mPendingRequestCount);
|
MOZ_ASSERT(!mPendingRequestCount);
|
||||||
|
|
||||||
@ -481,7 +481,7 @@ IDBTransaction::SendAbort(nsresult aResultCode)
|
|||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_ASSERT(NS_FAILED(aResultCode));
|
MOZ_ASSERT(NS_FAILED(aResultCode));
|
||||||
MOZ_ASSERT(IsFinished());
|
MOZ_ASSERT(IsCommittingOrDone());
|
||||||
MOZ_ASSERT(!mSentCommitOrAbort);
|
MOZ_ASSERT(!mSentCommitOrAbort);
|
||||||
|
|
||||||
// Don't do this in the macro because we always need to increment the serial
|
// Don't do this in the macro because we always need to increment the serial
|
||||||
@ -640,14 +640,10 @@ IDBTransaction::AbortInternal(nsresult aAbortCode,
|
|||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_ASSERT(NS_FAILED(aAbortCode));
|
MOZ_ASSERT(NS_FAILED(aAbortCode));
|
||||||
|
MOZ_ASSERT(!IsCommittingOrDone());
|
||||||
|
|
||||||
nsRefPtr<DOMError> error = aError;
|
nsRefPtr<DOMError> error = aError;
|
||||||
|
|
||||||
if (IsFinished()) {
|
|
||||||
// Already finished, nothing to do here.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool isVersionChange = mMode == VERSION_CHANGE;
|
const bool isVersionChange = mMode == VERSION_CHANGE;
|
||||||
const bool isInvalidated = mDatabase->IsInvalidated();
|
const bool isInvalidated = mDatabase->IsInvalidated();
|
||||||
bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
|
bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
|
||||||
@ -740,6 +736,12 @@ IDBTransaction::Abort(IDBRequest* aRequest)
|
|||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_ASSERT(aRequest);
|
MOZ_ASSERT(aRequest);
|
||||||
|
|
||||||
|
if (IsCommittingOrDone()) {
|
||||||
|
// Already started (and maybe finished) the commit or abort so there is
|
||||||
|
// nothing to do here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorResult rv;
|
ErrorResult rv;
|
||||||
nsRefPtr<DOMError> error = aRequest->GetError(rv);
|
nsRefPtr<DOMError> error = aRequest->GetError(rv);
|
||||||
|
|
||||||
@ -751,6 +753,12 @@ IDBTransaction::Abort(nsresult aErrorCode)
|
|||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
if (IsCommittingOrDone()) {
|
||||||
|
// Already started (and maybe finished) the commit or abort so there is
|
||||||
|
// nothing to do here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsRefPtr<DOMError> error = new DOMError(GetOwner(), aErrorCode);
|
nsRefPtr<DOMError> error = new DOMError(GetOwner(), aErrorCode);
|
||||||
AbortInternal(aErrorCode, error.forget());
|
AbortInternal(aErrorCode, error.forget());
|
||||||
}
|
}
|
||||||
@ -760,7 +768,7 @@ IDBTransaction::Abort(ErrorResult& aRv)
|
|||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
if (IsFinished()) {
|
if (IsCommittingOrDone()) {
|
||||||
aRv = NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
aRv = NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -905,7 +913,7 @@ IDBTransaction::ObjectStore(const nsAString& aName, ErrorResult& aRv)
|
|||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
if (IsFinished()) {
|
if (IsCommittingOrDone()) {
|
||||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1029,12 +1037,13 @@ WorkerFeature::Notify(JSContext* aCx, Status aStatus)
|
|||||||
if (mTransaction && aStatus > Terminating) {
|
if (mTransaction && aStatus > Terminating) {
|
||||||
mTransaction->AssertIsOnOwningThread();
|
mTransaction->AssertIsOnOwningThread();
|
||||||
|
|
||||||
nsRefPtr<IDBTransaction> transaction = mTransaction;
|
nsRefPtr<IDBTransaction> transaction = Move(mTransaction);
|
||||||
mTransaction = nullptr;
|
|
||||||
|
|
||||||
|
if (!transaction->IsCommittingOrDone()) {
|
||||||
IDB_REPORT_INTERNAL_ERR();
|
IDB_REPORT_INTERNAL_ERR();
|
||||||
transaction->AbortInternal(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR, nullptr);
|
transaction->AbortInternal(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR, nullptr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -166,10 +166,19 @@ public:
|
|||||||
IsOpen() const;
|
IsOpen() const;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsFinished() const
|
IsCommittingOrDone() const
|
||||||
{
|
{
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
return mReadyState > LOADING;
|
|
||||||
|
return mReadyState == COMMITTING || mReadyState == DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsDone() const
|
||||||
|
{
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
return mReadyState == DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
Loading…
Reference in New Issue
Block a user