mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-17 14:25:49 +00:00
Bug 1598164 - Implement transaction inactive state according to spec. r=dom-workers-and-storage-reviewers,ytausky
Differential Revision: https://phabricator.services.mozilla.com/D55142 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
39bf196ebf
commit
b727e2abc1
@ -153,6 +153,12 @@ class MOZ_STACK_CLASS AutoSetCurrentTransaction final {
|
||||
ThreadLocal* mThreadLocal;
|
||||
|
||||
public:
|
||||
AutoSetCurrentTransaction(const AutoSetCurrentTransaction&) = delete;
|
||||
AutoSetCurrentTransaction(AutoSetCurrentTransaction&&) = delete;
|
||||
AutoSetCurrentTransaction& operator=(const AutoSetCurrentTransaction&) =
|
||||
delete;
|
||||
AutoSetCurrentTransaction& operator=(AutoSetCurrentTransaction&&) = delete;
|
||||
|
||||
explicit AutoSetCurrentTransaction(IDBTransaction* aTransaction)
|
||||
: mTransaction(aTransaction),
|
||||
mPreviousTransaction(nullptr),
|
||||
@ -629,6 +635,8 @@ StructuredCloneReadInfo DeserializeStructuredCloneReadInfo(
|
||||
aDatabase, aSerialized.hasPreprocessInfo()};
|
||||
}
|
||||
|
||||
// TODO: Remove duplication between DispatchErrorEvent and DispatchSucessEvent.
|
||||
|
||||
void DispatchErrorEvent(IDBRequest* aRequest, nsresult aErrorCode,
|
||||
IDBTransaction* aTransaction = nullptr,
|
||||
Event* aEvent = nullptr) {
|
||||
@ -659,6 +667,10 @@ void DispatchErrorEvent(IDBRequest* aRequest, nsresult aErrorCode,
|
||||
asct.emplace(aTransaction);
|
||||
}
|
||||
|
||||
if (transaction && transaction->IsInactive()) {
|
||||
transaction->TransitionToActive();
|
||||
}
|
||||
|
||||
if (transaction) {
|
||||
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
|
||||
"Firing %s event with error 0x%x", "%s (0x%x)",
|
||||
@ -678,22 +690,25 @@ void DispatchErrorEvent(IDBRequest* aRequest, nsresult aErrorCode,
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!transaction || transaction->CanAcceptRequests() ||
|
||||
MOZ_ASSERT(!transaction || transaction->IsActive() ||
|
||||
transaction->IsAborted());
|
||||
|
||||
// Do not abort the transaction here if this request is failed due to the
|
||||
// abortion of its transaction to ensure that the correct error cause of
|
||||
// the abort event be set in IDBTransaction::FireCompleteOrAbortEvents()
|
||||
// later.
|
||||
if (transaction && transaction->CanAcceptRequests() &&
|
||||
aErrorCode != NS_ERROR_DOM_INDEXEDDB_ABORT_ERR) {
|
||||
WidgetEvent* const internalEvent = aEvent->WidgetEventPtr();
|
||||
MOZ_ASSERT(internalEvent);
|
||||
if (transaction && transaction->IsActive()) {
|
||||
transaction->TransitionToInactive();
|
||||
|
||||
if (internalEvent->mFlags.mExceptionWasRaised) {
|
||||
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
||||
} else if (doDefault) {
|
||||
transaction->Abort(request);
|
||||
// Do not abort the transaction here if this request is failed due to the
|
||||
// abortion of its transaction to ensure that the correct error cause of
|
||||
// the abort event be set in IDBTransaction::FireCompleteOrAbortEvents()
|
||||
// later.
|
||||
if (aErrorCode != NS_ERROR_DOM_INDEXEDDB_ABORT_ERR) {
|
||||
WidgetEvent* const internalEvent = aEvent->WidgetEventPtr();
|
||||
MOZ_ASSERT(internalEvent);
|
||||
|
||||
if (internalEvent->mFlags.mExceptionWasRaised) {
|
||||
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
||||
} else if (doDefault) {
|
||||
transaction->Abort(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -728,7 +743,10 @@ void DispatchSuccessEvent(ResultHelper* aResultHelper,
|
||||
request->SetResultCallback(aResultHelper);
|
||||
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT_IF(transaction, transaction->CanAcceptRequests());
|
||||
|
||||
if (transaction && transaction->IsInactive()) {
|
||||
transaction->TransitionToActive();
|
||||
}
|
||||
|
||||
if (transaction) {
|
||||
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
|
||||
@ -742,7 +760,7 @@ void DispatchSuccessEvent(ResultHelper* aResultHelper,
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(transaction,
|
||||
transaction->CanAcceptRequests() && !transaction->IsAborted());
|
||||
transaction->IsActive() && !transaction->IsAborted());
|
||||
|
||||
IgnoredErrorResult rv;
|
||||
request->DispatchEvent(*aEvent, rv);
|
||||
@ -753,7 +771,9 @@ void DispatchSuccessEvent(ResultHelper* aResultHelper,
|
||||
WidgetEvent* const internalEvent = aEvent->WidgetEventPtr();
|
||||
MOZ_ASSERT(internalEvent);
|
||||
|
||||
if (transaction && transaction->CanAcceptRequests()) {
|
||||
if (transaction && transaction->IsActive()) {
|
||||
transaction->TransitionToInactive();
|
||||
|
||||
if (internalEvent->mFlags.mExceptionWasRaised) {
|
||||
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
||||
} else {
|
||||
|
@ -1514,7 +1514,8 @@ already_AddRefed<IDBRequest> IDBObjectStore::AddOrPut(
|
||||
nsTArray<IndexUpdateInfo> updateInfo;
|
||||
|
||||
{
|
||||
const auto autoStateRestore = mTransaction->TemporarilyProceedToInactive();
|
||||
const auto autoStateRestore =
|
||||
mTransaction->TemporarilyTransitionToInactive();
|
||||
GetAddInfo(aCx, aValueWrapper, aKey, cloneWriteInfo, key, updateInfo, aRv);
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ void IDBTransaction::OnNewRequest() {
|
||||
void IDBTransaction::OnRequestFinished(
|
||||
const bool aRequestCompletedSuccessfully) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mReadyState == ReadyState::Active ||
|
||||
MOZ_ASSERT(mReadyState == ReadyState::Inactive ||
|
||||
mReadyState == ReadyState::Finished);
|
||||
MOZ_ASSERT_IF(mReadyState == ReadyState::Finished, !NS_SUCCEEDED(mAbortCode));
|
||||
MOZ_ASSERT(mPendingRequestCount);
|
||||
@ -351,7 +351,7 @@ void IDBTransaction::OnRequestFinished(
|
||||
--mPendingRequestCount;
|
||||
|
||||
if (!mPendingRequestCount) {
|
||||
if (mReadyState == ReadyState::Active) {
|
||||
if (mReadyState == ReadyState::Inactive) {
|
||||
mReadyState = ReadyState::Committing;
|
||||
}
|
||||
|
||||
@ -446,6 +446,18 @@ bool IDBTransaction::CanAcceptRequests() const {
|
||||
(!mStarted || mCreating || GetCurrent() == this);
|
||||
}
|
||||
|
||||
IDBTransaction::AutoRestoreState<IDBTransaction::ReadyState::Inactive,
|
||||
IDBTransaction::ReadyState::Active>
|
||||
IDBTransaction::TemporarilyTransitionToActive() {
|
||||
return AutoRestoreState<ReadyState::Inactive, ReadyState::Active>{*this};
|
||||
}
|
||||
|
||||
IDBTransaction::AutoRestoreState<IDBTransaction::ReadyState::Active,
|
||||
IDBTransaction::ReadyState::Inactive>
|
||||
IDBTransaction::TemporarilyTransitionToInactive() {
|
||||
return AutoRestoreState<ReadyState::Active, ReadyState::Inactive>{*this};
|
||||
}
|
||||
|
||||
void IDBTransaction::GetCallerLocation(nsAString& aFilename,
|
||||
uint32_t* const aLineNo,
|
||||
uint32_t* const aColumn) const {
|
||||
@ -584,7 +596,7 @@ void IDBTransaction::AbortInternal(const nsresult aAbortCode,
|
||||
MOZ_ASSERT(!IsCommittingOrFinished());
|
||||
|
||||
const bool isVersionChange = mMode == Mode::VersionChange;
|
||||
const bool needToSendAbort = mReadyState == ReadyState::Active && !mStarted;
|
||||
const bool needToSendAbort = mReadyState == ReadyState::Inactive && !mStarted;
|
||||
|
||||
mAbortCode = aAbortCode;
|
||||
mReadyState = ReadyState::Finished;
|
||||
@ -682,6 +694,7 @@ void IDBTransaction::Abort(const nsresult aErrorCode) {
|
||||
AbortInternal(aErrorCode, DOMException::Create(aErrorCode));
|
||||
}
|
||||
|
||||
// Specified by https://w3c.github.io/IndexedDB/#dom-idbtransaction-abort.
|
||||
void IDBTransaction::Abort(ErrorResult& aRv) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
@ -690,6 +703,8 @@ void IDBTransaction::Abort(ErrorResult& aRv) {
|
||||
return;
|
||||
}
|
||||
|
||||
mReadyState = ReadyState::Inactive;
|
||||
|
||||
AbortInternal(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, nullptr);
|
||||
|
||||
mAbortedByScript.Flip();
|
||||
@ -944,8 +959,12 @@ IDBTransaction::Run() {
|
||||
// We're back at the event loop, no longer newborn.
|
||||
mCreating = false;
|
||||
|
||||
MOZ_ASSERT_IF(mReadyState == ReadyState::Finished, IsAborted());
|
||||
|
||||
// Maybe commit if there were no requests generated.
|
||||
if (mReadyState == ReadyState::Active && !mStarted) {
|
||||
if (!mStarted && mReadyState != ReadyState::Finished) {
|
||||
MOZ_ASSERT(mReadyState == ReadyState::Inactive ||
|
||||
mReadyState == ReadyState::Active);
|
||||
mReadyState = ReadyState::Finished;
|
||||
|
||||
SendCommit();
|
||||
|
@ -174,6 +174,18 @@ class IDBTransaction final : public DOMEventTargetHelper, public nsIRunnable {
|
||||
mReadyState == ReadyState::Finished;
|
||||
}
|
||||
|
||||
bool IsActive() const {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mReadyState == ReadyState::Active;
|
||||
}
|
||||
|
||||
bool IsInactive() const {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mReadyState == ReadyState::Inactive;
|
||||
}
|
||||
|
||||
bool IsFinished() const {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
@ -191,32 +203,47 @@ class IDBTransaction final : public DOMEventTargetHelper, public nsIRunnable {
|
||||
return NS_FAILED(mAbortCode);
|
||||
}
|
||||
|
||||
auto TemporarilyProceedToInactive() {
|
||||
AssertIsOnOwningThread();
|
||||
template <ReadyState OriginalState, ReadyState TemporaryState>
|
||||
class AutoRestoreState {
|
||||
public:
|
||||
explicit AutoRestoreState(IDBTransaction& aOwner) : mOwner { aOwner }
|
||||
#ifdef DEBUG
|
||||
, mSavedPendingRequestCount { mOwner.mPendingRequestCount }
|
||||
#endif
|
||||
{
|
||||
mOwner.AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mOwner.mReadyState == OriginalState);
|
||||
mOwner.mReadyState = TemporaryState;
|
||||
}
|
||||
|
||||
~AutoRestoreState() {
|
||||
mOwner.AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mOwner.mReadyState == TemporaryState);
|
||||
MOZ_ASSERT(mOwner.mPendingRequestCount == mSavedPendingRequestCount);
|
||||
|
||||
mOwner.mReadyState = OriginalState;
|
||||
}
|
||||
|
||||
private:
|
||||
IDBTransaction& mOwner;
|
||||
#ifdef DEBUG
|
||||
const uint32_t mSavedPendingRequestCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
AutoRestoreState<ReadyState::Inactive, ReadyState::Active>
|
||||
TemporarilyTransitionToActive();
|
||||
AutoRestoreState<ReadyState::Active, ReadyState::Inactive>
|
||||
TemporarilyTransitionToInactive();
|
||||
|
||||
void TransitionToActive() {
|
||||
MOZ_ASSERT(mReadyState == ReadyState::Inactive);
|
||||
mReadyState = ReadyState::Active;
|
||||
}
|
||||
|
||||
void TransitionToInactive() {
|
||||
MOZ_ASSERT(mReadyState == ReadyState::Active);
|
||||
mReadyState = ReadyState::Inactive;
|
||||
|
||||
struct AutoRestoreState {
|
||||
IDBTransaction& mOwner;
|
||||
#ifdef DEBUG
|
||||
uint32_t mSavedPendingRequestCount;
|
||||
#endif
|
||||
|
||||
~AutoRestoreState() {
|
||||
mOwner.AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mOwner.mReadyState == ReadyState::Inactive);
|
||||
MOZ_ASSERT(mOwner.mPendingRequestCount == mSavedPendingRequestCount);
|
||||
|
||||
mOwner.mReadyState = ReadyState::Active;
|
||||
}
|
||||
};
|
||||
|
||||
return AutoRestoreState{*this
|
||||
#ifdef DEBUG
|
||||
,
|
||||
mPendingRequestCount
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
nsresult AbortCode() const {
|
||||
|
Loading…
x
Reference in New Issue
Block a user