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:
Simon Giesecke 2019-12-04 12:59:09 +00:00
parent 39bf196ebf
commit b727e2abc1
4 changed files with 112 additions and 45 deletions

View File

@ -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 {

View File

@ -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);
}

View File

@ -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();

View File

@ -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 {