Bug 1600906 - Convert IDBCursor and BackgroundCursorChild to templates to increase type safety and reduce state. r=dom-workers-and-storage-reviewers,ytausky

This also simplifies delegating calls that are dependent on the cursor type.

Also reduce dependency on IDBCursor.h by moving enums and type traits to IDBCursorType.h

Differential Revision: https://phabricator.services.mozilla.com/D57993

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Simon Giesecke 2020-01-10 15:23:52 +00:00
parent a4a201dde8
commit a5e45033f2
16 changed files with 1117 additions and 911 deletions

View File

@ -1276,19 +1276,48 @@ void DispatchFileHandleSuccessEvent(FileHandleResultHelper* aResultHelper) {
MOZ_ASSERT(fileHandle->IsOpen() || fileHandle->IsAborted());
}
auto GetKeyOperator(const IDBCursor::Direction aDirection) {
auto GetKeyOperator(const IDBCursorDirection aDirection) {
switch (aDirection) {
case IDBCursor::Direction::Next:
case IDBCursor::Direction::NextUnique:
case IDBCursorDirection::Next:
case IDBCursorDirection::Nextunique:
return &Key::operator>=;
case IDBCursor::Direction::Prev:
case IDBCursor::Direction::PrevUnique:
case IDBCursorDirection::Prev:
case IDBCursorDirection::Prevunique:
return &Key::operator<=;
default:
MOZ_CRASH("Should never get here.");
}
}
// Does not need to be threadsafe since this only runs on one thread, but
// inheriting from CancelableRunnable is easy.
template <typename T>
class DelayedActionRunnable final : public CancelableRunnable {
using ActionFunc = void (T::*)();
T* mActor;
RefPtr<IDBRequest> mRequest;
ActionFunc mActionFunc;
public:
explicit DelayedActionRunnable(T* aActor, ActionFunc aActionFunc)
: CancelableRunnable("indexedDB::DelayedActionRunnable"),
mActor(aActor),
mRequest(aActor->GetRequest()),
mActionFunc(aActionFunc) {
MOZ_ASSERT(aActor);
aActor->AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
MOZ_ASSERT(mActionFunc);
}
private:
~DelayedActionRunnable() = default;
NS_DECL_NSIRUNNABLE
nsresult Cancel() override;
};
} // namespace
/*******************************************************************************
@ -2338,7 +2367,7 @@ bool BackgroundTransactionChild::DeallocPBackgroundIDBCursorChild(
PBackgroundIDBCursorChild* aActor) {
MOZ_ASSERT(aActor);
delete static_cast<BackgroundCursorChild*>(aActor);
delete aActor;
return true;
}
@ -2456,7 +2485,7 @@ bool BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBCursorChild(
PBackgroundIDBCursorChild* aActor) {
MOZ_ASSERT(aActor);
delete static_cast<BackgroundCursorChild*>(aActor);
delete aActor;
return true;
}
@ -3178,102 +3207,37 @@ BackgroundRequestChild::PreprocessHelper::OnFileMetadataReady(
* BackgroundCursorChild
******************************************************************************/
BackgroundCursorChild::CachedResponse::CachedResponse(
Key aKey, StructuredCloneReadInfo&& aCloneInfo)
: mKey{std::move(aKey)}, mCloneInfo{std::move(aCloneInfo)} {}
BackgroundCursorChild::CachedResponse::CachedResponse(
Key aKey, Key aLocaleAwareKey, Key aObjectStoreKey,
StructuredCloneReadInfo&& aCloneInfo)
: mKey{std::move(aKey)},
mLocaleAwareKey{std::move(aLocaleAwareKey)},
mObjectStoreKey{std::move(aObjectStoreKey)},
mCloneInfo{std::move(aCloneInfo)} {}
BackgroundCursorChild::CachedResponse::CachedResponse(Key aKey)
: mKey{std::move(aKey)} {}
BackgroundCursorChild::CachedResponse::CachedResponse(Key aKey,
Key aLocaleAwareKey,
Key aObjectStoreKey)
: mKey{std::move(aKey)},
mLocaleAwareKey{std::move(aLocaleAwareKey)},
mObjectStoreKey{std::move(aObjectStoreKey)} {}
// Does not need to be threadsafe since this only runs on one thread, but
// inheriting from CancelableRunnable is easy.
class BackgroundCursorChild::DelayedActionRunnable final
: public CancelableRunnable {
using ActionFunc = void (BackgroundCursorChild::*)();
BackgroundCursorChild* mActor;
RefPtr<IDBRequest> mRequest;
ActionFunc mActionFunc;
public:
explicit DelayedActionRunnable(BackgroundCursorChild* aActor,
ActionFunc aActionFunc)
: CancelableRunnable(
"indexedDB::BackgroundCursorChild::DelayedActionRunnable"),
mActor(aActor),
mRequest(aActor->mRequest),
mActionFunc(aActionFunc) {
MOZ_ASSERT(aActor);
aActor->AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
MOZ_ASSERT(mActionFunc);
}
private:
~DelayedActionRunnable() = default;
NS_DECL_NSIRUNNABLE
nsresult Cancel() override;
};
BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
IDBObjectStore* aObjectStore,
Direction aDirection)
BackgroundCursorChildBase::BackgroundCursorChildBase(IDBRequest* const aRequest,
const Direction aDirection)
: mRequest(aRequest),
mTransaction(aRequest->GetTransaction()),
mObjectStore(aObjectStore),
mIndex(nullptr),
mCursor(nullptr),
mStrongRequest(aRequest),
mDirection(aDirection),
mInFlightResponseInvalidationNeeded(false) {
MOZ_ASSERT(aObjectStore);
aObjectStore->AssertIsOnOwningThread();
mDirection(aDirection) {
MOZ_ASSERT(mTransaction);
MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild);
}
BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
IDBIndex* aIndex,
Direction aDirection)
: mRequest(aRequest),
mTransaction(aRequest->GetTransaction()),
mObjectStore(nullptr),
mIndex(aIndex),
template <IDBCursorType CursorType>
BackgroundCursorChild<CursorType>::BackgroundCursorChild(IDBRequest* aRequest,
SourceType* aSource,
Direction aDirection)
: BackgroundCursorChildBase(aRequest, aDirection),
mSource(aSource),
mCursor(nullptr),
mStrongRequest(aRequest),
mDirection(aDirection),
mInFlightResponseInvalidationNeeded(false) {
MOZ_ASSERT(aIndex);
aIndex->AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
aSource->AssertIsOnOwningThread();
MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild);
MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild<CursorType>);
}
BackgroundCursorChild::~BackgroundCursorChild() {
MOZ_COUNT_DTOR(indexedDB::BackgroundCursorChild);
template <IDBCursorType CursorType>
BackgroundCursorChild<CursorType>::~BackgroundCursorChild() {
MOZ_COUNT_DTOR(indexedDB::BackgroundCursorChild<CursorType>);
}
void BackgroundCursorChild::SendContinueInternal(
const CursorRequestParams& aParams, const Key& aCurrentKey,
const Key& aCurrentObjectStoreKey) {
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::SendContinueInternal(
const CursorRequestParams& aParams,
const CursorData<CursorType>& aCurrentData) {
AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
MOZ_ASSERT(mTransaction);
@ -3284,14 +3248,18 @@ void BackgroundCursorChild::SendContinueInternal(
// Make sure all our DOM objects stay alive.
mStrongCursor = mCursor;
MOZ_ASSERT(mRequest->ReadyState() == IDBRequestReadyState::Done);
mRequest->Reset();
MOZ_ASSERT(GetRequest()->ReadyState() == IDBRequestReadyState::Done);
GetRequest()->Reset();
mTransaction->OnNewRequest();
CursorRequestParams params = aParams;
Key currentKey = aCurrentKey;
Key currentObjectStoreKey = aCurrentObjectStoreKey;
Key currentKey = aCurrentData.mKey;
Key currentObjectStoreKey;
// TODO: This is still not nice.
if constexpr (!CursorTypeTraits<CursorType>::IsObjectStoreCursor) {
currentObjectStoreKey = aCurrentData.mObjectStoreKey;
}
switch (params.type()) {
case CursorRequestParams::TContinueParams: {
@ -3305,15 +3273,14 @@ void BackgroundCursorChild::SendContinueInternal(
[&key, isLocaleAware = mCursor->IsLocaleAware(),
keyOperator = GetKeyOperator(mDirection),
transactionSerialNumber = mTransaction->LoggingSerialNumber(),
requestSerialNumber = mRequest->LoggingSerialNumber()](
requestSerialNumber = GetRequest()->LoggingSerialNumber()](
const auto& currentCachedResponse) {
// This duplicates the logic from the parent. We could avoid this
// duplication if we invalidated the cached records always for any
// continue-with-key operation, but would lose the benefits of
// preloading then.
const auto& cachedSortKey =
isLocaleAware ? currentCachedResponse.mLocaleAwareKey
: currentCachedResponse.mKey;
currentCachedResponse.GetSortKey(isLocaleAware);
const bool discard = !(cachedSortKey.*keyOperator)(key);
if (discard) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
@ -3321,7 +3288,7 @@ void BackgroundCursorChild::SendContinueInternal(
"Continue, discarding", transactionSerialNumber,
requestSerialNumber, key.GetBuffer().get(),
cachedSortKey.GetBuffer().get(),
currentCachedResponse.mObjectStoreKey.GetBuffer().get());
currentCachedResponse.GetObjectStoreKeyForLogging());
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Continue to key %s, keeping cached key %s/%s and "
@ -3329,7 +3296,7 @@ void BackgroundCursorChild::SendContinueInternal(
"Continue, keeping", transactionSerialNumber,
requestSerialNumber, key.GetBuffer().get(),
cachedSortKey.GetBuffer().get(),
currentCachedResponse.mObjectStoreKey.GetBuffer().get());
currentCachedResponse.GetObjectStoreKeyForLogging());
}
return discard;
@ -3339,56 +3306,61 @@ void BackgroundCursorChild::SendContinueInternal(
}
case CursorRequestParams::TContinuePrimaryKeyParams: {
const auto& key = params.get_ContinuePrimaryKeyParams().key();
const auto& primaryKey =
params.get_ContinuePrimaryKeyParams().primaryKey();
if (key.IsUnset() || primaryKey.IsUnset()) {
break;
if constexpr (!CursorTypeTraits<CursorType>::IsObjectStoreCursor) {
const auto& key = params.get_ContinuePrimaryKeyParams().key();
const auto& primaryKey =
params.get_ContinuePrimaryKeyParams().primaryKey();
if (key.IsUnset() || primaryKey.IsUnset()) {
break;
}
// Discard cache entries before the target key.
DiscardCachedResponses([&key, &primaryKey,
isLocaleAware = mCursor->IsLocaleAware(),
keyCompareOperator = GetKeyOperator(mDirection),
transactionSerialNumber =
mTransaction->LoggingSerialNumber(),
requestSerialNumber =
GetRequest()->LoggingSerialNumber()](
const auto& currentCachedResponse) {
// This duplicates the logic from the parent. We could avoid this
// duplication if we invalidated the cached records always for any
// continue-with-key operation, but would lose the benefits of
// preloading then.
const auto& cachedSortKey =
currentCachedResponse.GetSortKey(isLocaleAware);
const auto& cachedSortPrimaryKey =
currentCachedResponse.mObjectStoreKey;
const bool discard =
(cachedSortKey == key &&
!(cachedSortPrimaryKey.*keyCompareOperator)(primaryKey)) ||
!(cachedSortKey.*keyCompareOperator)(key);
if (discard) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Continue to key %s with primary key %s, discarding "
"cached key %s with cached primary key %s",
"Continue, discarding", transactionSerialNumber,
requestSerialNumber, key.GetBuffer().get(),
primaryKey.GetBuffer().get(), cachedSortKey.GetBuffer().get(),
cachedSortPrimaryKey.GetBuffer().get());
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Continue to key %s with primary key %s, keeping "
"cached key %s with cached primary key %s and further",
"Continue, keeping", transactionSerialNumber,
requestSerialNumber, key.GetBuffer().get(),
primaryKey.GetBuffer().get(), cachedSortKey.GetBuffer().get(),
cachedSortPrimaryKey.GetBuffer().get());
}
return discard;
});
} else {
MOZ_CRASH("Shouldn't get here");
}
// Discard cache entries before the target key.
DiscardCachedResponses(
[&key, &primaryKey, isLocaleAware = mCursor->IsLocaleAware(),
keyCompareOperator = GetKeyOperator(mDirection),
transactionSerialNumber = mTransaction->LoggingSerialNumber(),
requestSerialNumber = mRequest->LoggingSerialNumber()](
const auto& currentCachedResponse) {
// This duplicates the logic from the parent. We could avoid this
// duplication if we invalidated the cached records always for any
// continue-with-key operation, but would lose the benefits of
// preloading then.
const auto& cachedSortKey =
isLocaleAware ? currentCachedResponse.mLocaleAwareKey
: currentCachedResponse.mKey;
const auto& cachedSortPrimaryKey =
currentCachedResponse.mObjectStoreKey;
const bool discard =
(cachedSortKey == key &&
!(cachedSortPrimaryKey.*keyCompareOperator)(primaryKey)) ||
!(cachedSortKey.*keyCompareOperator)(key);
if (discard) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Continue to key %s with primary key %s, discarding "
"cached key %s with cached primary key %s",
"Continue, discarding", transactionSerialNumber,
requestSerialNumber, key.GetBuffer().get(),
primaryKey.GetBuffer().get(), cachedSortKey.GetBuffer().get(),
cachedSortPrimaryKey.GetBuffer().get());
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Continue to key %s with primary key %s, keeping "
"cached key %s with cached primary key %s and further",
"Continue, keeping", transactionSerialNumber,
requestSerialNumber, key.GetBuffer().get(),
primaryKey.GetBuffer().get(), cachedSortKey.GetBuffer().get(),
cachedSortPrimaryKey.GetBuffer().get());
}
return discard;
});
break;
}
@ -3396,24 +3368,28 @@ void BackgroundCursorChild::SendContinueInternal(
uint32_t& advanceCount = params.get_AdvanceParams().count();
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Advancing %" PRIu32 " records", "Advancing",
mTransaction->LoggingSerialNumber(), mRequest->LoggingSerialNumber(),
advanceCount);
mTransaction->LoggingSerialNumber(),
GetRequest()->LoggingSerialNumber(), advanceCount);
// Discard cache entries.
DiscardCachedResponses(
[&advanceCount, &currentKey,
&currentObjectStoreKey](const auto& currentCachedResponse) {
const bool res = advanceCount > 1;
if (res) {
--advanceCount;
DiscardCachedResponses([&advanceCount, &currentKey,
&currentObjectStoreKey](
const auto& currentCachedResponse) {
const bool res = advanceCount > 1;
if (res) {
--advanceCount;
// TODO: We only need to update currentKey on the last entry, the
// others are overwritten in the next iteration anyway.
currentKey = currentCachedResponse.mKey;
currentObjectStoreKey = currentCachedResponse.mObjectStoreKey;
}
return res;
});
// TODO: We only need to update currentKey on the last entry, the
// others are overwritten in the next iteration anyway.
currentKey = currentCachedResponse.mKey;
if constexpr (!CursorTypeTraits<CursorType>::IsObjectStoreCursor) {
currentObjectStoreKey = currentCachedResponse.mObjectStoreKey;
} else {
Unused << currentObjectStoreKey;
}
}
return res;
});
break;
}
@ -3433,8 +3409,8 @@ void BackgroundCursorChild::SendContinueInternal(
// This is accompanied by invalidating cached entries at proper locations to
// make it correct. To avoid this, further changes are necessary, see Bug
// 1580499.
MOZ_ALWAYS_SUCCEEDS(
NS_DispatchToCurrentThread(MakeAndAddRef<DelayedActionRunnable>(
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(
MakeAndAddRef<DelayedActionRunnable<BackgroundCursorChild<CursorType>>>(
this, &BackgroundCursorChild::CompleteContinueRequestFromCache)));
// TODO: Could we preload further entries in the background when the size of
@ -3446,58 +3422,44 @@ void BackgroundCursorChild::SendContinueInternal(
}
}
void BackgroundCursorChild::CompleteContinueRequestFromCache() {
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::CompleteContinueRequestFromCache() {
AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(mCursor);
MOZ_ASSERT(mStrongCursor);
MOZ_ASSERT(!mDelayedResponses.empty());
MOZ_ASSERT(mCursor->GetType() == CursorType);
const RefPtr<IDBCursor> cursor = std::move(mStrongCursor);
auto& item = mDelayedResponses.front();
switch (mCursor->GetType()) {
case IDBCursor::Type::ObjectStore:
mCursor->Reset(std::move(item.mKey), std::move(item.mCloneInfo));
break;
case IDBCursor::Type::Index:
mCursor->Reset(std::move(item.mKey), std::move(item.mLocaleAwareKey),
std::move(item.mObjectStoreKey),
std::move(item.mCloneInfo));
break;
case IDBCursor::Type::ObjectStoreKey:
mCursor->Reset(std::move(item.mKey));
break;
case IDBCursor::Type::IndexKey:
mCursor->Reset(std::move(item.mKey), std::move(item.mLocaleAwareKey),
std::move(item.mObjectStoreKey));
break;
default:
MOZ_CRASH("Should never get here.");
}
mCursor->Reset(std::move(mDelayedResponses.front()));
mDelayedResponses.pop_front();
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Consumed 1 cached response, %zu cached responses remaining",
"Consumed cached response", mTransaction->LoggingSerialNumber(),
mRequest->LoggingSerialNumber(),
GetRequest()->LoggingSerialNumber(),
mDelayedResponses.size() + mCachedResponses.size());
ResultHelper helper(mRequest, mTransaction, cursor);
ResultHelper helper(GetRequest(), mTransaction, cursor);
DispatchSuccessEvent(&helper);
mTransaction->OnRequestFinished(/* aRequestCompletedSuccessfully */ true);
}
void BackgroundCursorChild::SendDeleteMeInternal() {
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::SendDeleteMeInternal() {
AssertIsOnOwningThread();
MOZ_ASSERT(!mStrongRequest);
MOZ_ASSERT(!mStrongCursor);
mRequest = nullptr;
mRequest.reset();
mTransaction = nullptr;
mObjectStore = nullptr;
mIndex = nullptr;
// TODO: The things until here could be pulled up to
// BackgroundCursorChildBase.
mSource.reset();
if (mCursor) {
mCursor->ClearBackgroundActor();
@ -3507,7 +3469,8 @@ void BackgroundCursorChild::SendDeleteMeInternal() {
}
}
void BackgroundCursorChild::InvalidateCachedResponses() {
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::InvalidateCachedResponses() {
AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(mRequest);
@ -3520,7 +3483,7 @@ void BackgroundCursorChild::InvalidateCachedResponses() {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Invalidating all %zu cached responses", "Invalidating",
mTransaction->LoggingSerialNumber(), mRequest->LoggingSerialNumber(),
mTransaction->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
mCachedResponses.size());
mCachedResponses.clear();
@ -3533,14 +3496,16 @@ void BackgroundCursorChild::InvalidateCachedResponses() {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Setting flag to invalidate in-flight responses",
"Set flag to invalidate in-flight responses",
mTransaction->LoggingSerialNumber(), mRequest->LoggingSerialNumber());
mTransaction->LoggingSerialNumber(),
GetRequest()->LoggingSerialNumber());
mInFlightResponseInvalidationNeeded = true;
}
}
template <IDBCursorType CursorType>
template <typename Condition>
void BackgroundCursorChild::DiscardCachedResponses(
void BackgroundCursorChild<CursorType>::DiscardCachedResponses(
const Condition& aConditionFunc) {
size_t discardedCount = 0;
while (!mCachedResponses.empty() &&
@ -3550,11 +3515,11 @@ void BackgroundCursorChild::DiscardCachedResponses(
}
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Discarded %zu cached responses, %zu remaining", "Discarded",
mTransaction->LoggingSerialNumber(), mRequest->LoggingSerialNumber(),
mTransaction->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
discardedCount, mCachedResponses.size());
}
void BackgroundCursorChild::HandleResponse(nsresult aResponse) {
void BackgroundCursorChildBase::HandleResponse(nsresult aResponse) {
AssertIsOnOwningThread();
MOZ_ASSERT(NS_FAILED(aResponse));
MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
@ -3563,10 +3528,12 @@ void BackgroundCursorChild::HandleResponse(nsresult aResponse) {
MOZ_ASSERT(!mStrongRequest);
MOZ_ASSERT(!mStrongCursor);
DispatchErrorEvent(mRequest, aResponse, mTransaction);
DispatchErrorEvent(GetRequest(), aResponse, mTransaction);
}
void BackgroundCursorChild::HandleResponse(const void_t& aResponse) {
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::HandleResponse(
const void_t& aResponse) {
AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
MOZ_ASSERT(mTransaction);
@ -3577,23 +3544,25 @@ void BackgroundCursorChild::HandleResponse(const void_t& aResponse) {
mCursor->Reset();
}
ResultHelper helper(mRequest, mTransaction, &JS::NullHandleValue);
ResultHelper helper(GetRequest(), mTransaction, &JS::NullHandleValue);
DispatchSuccessEvent(&helper);
if (!mCursor) {
MOZ_ALWAYS_SUCCEEDS(this->GetActorEventTarget()->Dispatch(
MakeAndAddRef<DelayedActionRunnable>(
MakeAndAddRef<DelayedActionRunnable<BackgroundCursorChild<CursorType>>>(
this, &BackgroundCursorChild::SendDeleteMeInternal),
NS_DISPATCH_NORMAL));
}
}
template <IDBCursorType CursorType>
template <typename... Args>
RefPtr<IDBCursor> BackgroundCursorChild::HandleIndividualCursorResponse(
RefPtr<IDBCursor>
BackgroundCursorChild<CursorType>::HandleIndividualCursorResponse(
const bool aUseAsCurrentResult, Args&&... aArgs) {
if (mCursor) {
if (aUseAsCurrentResult) {
mCursor->Reset(std::forward<Args>(aArgs)...);
mCursor->Reset(CursorData<CursorType>{std::forward<Args>(aArgs)...});
} else {
mCachedResponses.emplace_back(std::forward<Args>(aArgs)...);
}
@ -3602,15 +3571,16 @@ RefPtr<IDBCursor> BackgroundCursorChild::HandleIndividualCursorResponse(
MOZ_ASSERT(aUseAsCurrentResult);
// TODO: This still looks quite dangerous to me. Why is mCursor not a RefPtr?
RefPtr<IDBCursor> newCursor =
IDBCursor::Create(this, std::forward<Args>(aArgs)...);
// TODO: This still looks quite dangerous to me. Why is mCursor not a
// RefPtr?
auto newCursor = IDBCursor::Create(this, std::forward<Args>(aArgs)...);
mCursor = newCursor;
return newCursor;
}
template <IDBCursorType CursorType>
template <typename T, typename Func>
void BackgroundCursorChild::HandleMultipleCursorResponses(
void BackgroundCursorChild<CursorType>::HandleMultipleCursorResponses(
const nsTArray<T>& aResponses, const Func& aHandleRecord) {
AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
@ -3621,7 +3591,7 @@ void BackgroundCursorChild::HandleMultipleCursorResponses(
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Received %zu cursor responses", "Received",
mTransaction->LoggingSerialNumber(), mRequest->LoggingSerialNumber(),
mTransaction->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
aResponses.Length());
MOZ_ASSERT_IF(aResponses.Length() > 1, mCachedResponses.empty());
@ -3636,14 +3606,14 @@ void BackgroundCursorChild::HandleMultipleCursorResponses(
for (auto& response : responses) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"PRELOAD: Processing response for key %s", "Processing",
mTransaction->LoggingSerialNumber(), mRequest->LoggingSerialNumber(),
response.key().GetBuffer().get());
mTransaction->LoggingSerialNumber(),
GetRequest()->LoggingSerialNumber(), response.key().GetBuffer().get());
// TODO: At the moment, we only send a cursor request to the parent if
// requested by the user code. Therefore, the first result is always used as
// the current result, and the potential extra results are cached. If we
// extended this towards preloading in the background, all results might
// need to be cached.
// requested by the user code. Therefore, the first result is always used
// as the current result, and the potential extra results are cached. If
// we extended this towards preloading in the background, all results
// might need to be cached.
auto maybeNewCursor =
aHandleRecord(/* aUseAsCurrentResult */ isFirst, response);
if (maybeNewCursor) {
@ -3657,29 +3627,29 @@ void BackgroundCursorChild::HandleMultipleCursorResponses(
"PRELOAD: Discarding remaining responses since "
"mInFlightResponseInvalidationNeeded is set",
"Discarding responses", mTransaction->LoggingSerialNumber(),
mRequest->LoggingSerialNumber());
GetRequest()->LoggingSerialNumber());
mInFlightResponseInvalidationNeeded = false;
break;
}
}
ResultHelper helper(mRequest, mTransaction, mCursor);
ResultHelper helper(GetRequest(), mTransaction, mCursor);
DispatchSuccessEvent(&helper);
}
void BackgroundCursorChild::HandleResponse(
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::HandleResponse(
const nsTArray<ObjectStoreCursorResponse>& aResponses) {
AssertIsOnOwningThread();
MOZ_ASSERT(mObjectStore);
MOZ_ASSERT(mTransaction);
HandleMultipleCursorResponses(
aResponses, [this](const bool useAsCurrentResult,
ObjectStoreCursorResponse& response) {
// TODO: Maybe move the deserialization of the clone-read-info into the
// cursor, so that it is only done for records actually accessed, which
// might not be the case for all cached records.
// TODO: Maybe move the deserialization of the clone-read-info into
// the cursor, so that it is only done for records actually accessed,
// which might not be the case for all cached records.
return HandleIndividualCursorResponse(
useAsCurrentResult, std::move(response.key()),
DeserializeStructuredCloneReadInfo(std::move(response.cloneInfo()),
@ -3687,10 +3657,10 @@ void BackgroundCursorChild::HandleResponse(
});
}
void BackgroundCursorChild::HandleResponse(
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::HandleResponse(
const nsTArray<ObjectStoreKeyCursorResponse>& aResponses) {
AssertIsOnOwningThread();
MOZ_ASSERT(mObjectStore);
HandleMultipleCursorResponses(
aResponses, [this](const bool useAsCurrentResult,
@ -3700,10 +3670,10 @@ void BackgroundCursorChild::HandleResponse(
});
}
void BackgroundCursorChild::HandleResponse(
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::HandleResponse(
const nsTArray<IndexCursorResponse>& aResponses) {
AssertIsOnOwningThread();
MOZ_ASSERT(mIndex);
MOZ_ASSERT(mTransaction);
HandleMultipleCursorResponses(
@ -3717,10 +3687,11 @@ void BackgroundCursorChild::HandleResponse(
});
}
void BackgroundCursorChild::HandleResponse(
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::HandleResponse(
const nsTArray<IndexKeyCursorResponse>& aResponses) {
AssertIsOnOwningThread();
MOZ_ASSERT(mIndex);
static_assert(!CursorTypeTraits<CursorType>::IsObjectStoreCursor);
HandleMultipleCursorResponses(
aResponses,
@ -3731,7 +3702,8 @@ void BackgroundCursorChild::HandleResponse(
});
}
void BackgroundCursorChild::ActorDestroy(ActorDestroyReason aWhy) {
template <IDBCursorType CursorType>
void BackgroundCursorChild<CursorType>::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnOwningThread();
MOZ_ASSERT_IF(aWhy == Deletion, !mStrongRequest);
MOZ_ASSERT_IF(aWhy == Deletion, !mStrongCursor);
@ -3751,14 +3723,14 @@ void BackgroundCursorChild::ActorDestroy(ActorDestroyReason aWhy) {
}
#ifdef DEBUG
mRequest = nullptr;
mRequest.maybeReset();
mTransaction = nullptr;
mObjectStore = nullptr;
mIndex = nullptr;
mSource.maybeReset();
#endif
}
mozilla::ipc::IPCResult BackgroundCursorChild::RecvResponse(
template <IDBCursorType CursorType>
mozilla::ipc::IPCResult BackgroundCursorChild<CursorType>::RecvResponse(
const CursorResponse& aResponse) {
AssertIsOnOwningThread();
MOZ_ASSERT(aResponse.type() != CursorResponse::T__None);
@ -3786,19 +3758,35 @@ mozilla::ipc::IPCResult BackgroundCursorChild::RecvResponse(
break;
case CursorResponse::TArrayOfObjectStoreCursorResponse:
HandleResponse(aResponse.get_ArrayOfObjectStoreCursorResponse());
if constexpr (CursorType == IDBCursorType::ObjectStore) {
HandleResponse(aResponse.get_ArrayOfObjectStoreCursorResponse());
} else {
MOZ_CRASH("Response type mismatch");
}
break;
case CursorResponse::TArrayOfObjectStoreKeyCursorResponse:
HandleResponse(aResponse.get_ArrayOfObjectStoreKeyCursorResponse());
if constexpr (CursorType == IDBCursorType::ObjectStoreKey) {
HandleResponse(aResponse.get_ArrayOfObjectStoreKeyCursorResponse());
} else {
MOZ_CRASH("Response type mismatch");
}
break;
case CursorResponse::TArrayOfIndexCursorResponse:
HandleResponse(aResponse.get_ArrayOfIndexCursorResponse());
if constexpr (CursorType == IDBCursorType::Index) {
HandleResponse(aResponse.get_ArrayOfIndexCursorResponse());
} else {
MOZ_CRASH("Response type mismatch");
}
break;
case CursorResponse::TArrayOfIndexKeyCursorResponse:
HandleResponse(aResponse.get_ArrayOfIndexKeyCursorResponse());
if constexpr (CursorType == IDBCursorType::IndexKey) {
HandleResponse(aResponse.get_ArrayOfIndexKeyCursorResponse());
} else {
MOZ_CRASH("Response type mismatch");
}
break;
default:
@ -3810,8 +3798,8 @@ mozilla::ipc::IPCResult BackgroundCursorChild::RecvResponse(
return IPC_OK();
}
NS_IMETHODIMP
BackgroundCursorChild::DelayedActionRunnable::Run() {
template <typename T>
NS_IMETHODIMP DelayedActionRunnable<T>::Run() {
MOZ_ASSERT(mActor);
mActor->AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
@ -3825,7 +3813,8 @@ BackgroundCursorChild::DelayedActionRunnable::Run() {
return NS_OK;
}
nsresult BackgroundCursorChild::DelayedActionRunnable::Cancel() {
template <typename T>
nsresult DelayedActionRunnable<T>::Cancel() {
if (NS_WARN_IF(!mActor)) {
return NS_ERROR_UNEXPECTED;
}
@ -3880,8 +3869,9 @@ void BackgroundFileHandleChild::NoteActorDestroyed() {
mFileHandle->ClearBackgroundActor();
// Normally this would be DEBUG-only but NoteActorDestroyed is also called
// from SendDeleteMeInternal. In that case we're going to receive an actual
// ActorDestroy call later and we don't want to touch a dead object.
// from SendDeleteMeInternal. In that case we're going to receive an
// actual ActorDestroy call later and we don't want to touch a dead
// object.
mTemporaryStrongFileHandle = nullptr;
mFileHandle = nullptr;
}

View File

@ -7,6 +7,7 @@
#ifndef mozilla_dom_indexeddb_actorschild_h__
#define mozilla_dom_indexeddb_actorschild_h__
#include "IDBCursorType.h"
#include "IDBTransaction.h"
#include "js/RootingAPI.h"
#include "mozilla/Attributes.h"
@ -634,90 +635,32 @@ struct CloneInfo {
UniquePtr<JSStructuredCloneData> mCloneData;
};
// TODO: Consider defining different subclasses for the different cursor types,
// possibly using the CRTP, which would remove the need for various case
// distinctions.
class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
friend class BackgroundTransactionChild;
friend class BackgroundVersionChangeTransactionChild;
class DelayedActionRunnable;
struct CachedResponse {
CachedResponse() = delete;
CachedResponse(Key aKey, StructuredCloneReadInfo&& aCloneInfo);
CachedResponse(Key aKey, Key aLocaleAwareKey, Key aObjectStoreKey,
StructuredCloneReadInfo&& aCloneInfo);
explicit CachedResponse(Key aKey);
CachedResponse(Key aKey, Key aLocaleAwareKey, Key aObjectStoreKey);
CachedResponse(CachedResponse&& aOther) = default;
CachedResponse& operator=(CachedResponse&& aOther) = default;
CachedResponse(const CachedResponse& aOther) = delete;
CachedResponse& operator=(const CachedResponse& aOther) = delete;
Key mKey;
Key mLocaleAwareKey;
Key mObjectStoreKey;
StructuredCloneReadInfo mCloneInfo;
};
IDBRequest* mRequest;
class BackgroundCursorChildBase : public PBackgroundIDBCursorChild {
private:
NS_DECL_OWNINGTHREAD
protected:
InitializedOnceMustBeTrue<IDBRequest* const> mRequest;
IDBTransaction* mTransaction;
IDBObjectStore* mObjectStore;
IDBIndex* mIndex;
IDBCursor* mCursor;
// These are only set while a request is in progress.
RefPtr<IDBRequest> mStrongRequest;
RefPtr<IDBCursor> mStrongCursor;
Direction mDirection;
const Direction mDirection;
NS_DECL_OWNINGTHREAD
BackgroundCursorChildBase(IDBRequest* aRequest, Direction aDirection);
std::deque<CachedResponse> mCachedResponses, mDelayedResponses;
bool mInFlightResponseInvalidationNeeded;
void HandleResponse(nsresult aResponse);
public:
BackgroundCursorChild(IDBRequest* aRequest, IDBObjectStore* aObjectStore,
Direction aDirection);
BackgroundCursorChild(IDBRequest* aRequest, IDBIndex* aIndex,
Direction aDirection);
void AssertIsOnOwningThread() const {
NS_ASSERT_OWNINGTHREAD(BackgroundCursorChild);
NS_ASSERT_OWNINGTHREAD(BackgroundCursorChildBase);
}
void SendContinueInternal(const CursorRequestParams& aParams,
const Key& aCurrentKey,
const Key& aCurrentObjectStoreKey);
void SendDeleteMeInternal();
void InvalidateCachedResponses();
template <typename Condition>
void DiscardCachedResponses(const Condition& aConditionFunc);
IDBRequest* GetRequest() const {
AssertIsOnOwningThread();
return mRequest;
}
IDBObjectStore* GetObjectStore() const {
AssertIsOnOwningThread();
return mObjectStore;
}
IDBIndex* GetIndex() const {
AssertIsOnOwningThread();
return mIndex;
return *mRequest;
}
Direction GetDirection() const {
@ -726,6 +669,44 @@ class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
return mDirection;
}
virtual void SendDeleteMeInternal() = 0;
};
template <IDBCursorType CursorType>
class BackgroundCursorChild final : public BackgroundCursorChildBase {
public:
using SourceType = CursorSourceType<CursorType>;
private:
friend class BackgroundTransactionChild;
friend class BackgroundVersionChangeTransactionChild;
InitializedOnceMustBeTrue<SourceType* const> mSource;
IDBCursorImpl<CursorType>* mCursor;
std::deque<CursorData<CursorType>> mCachedResponses, mDelayedResponses;
bool mInFlightResponseInvalidationNeeded;
public:
BackgroundCursorChild(IDBRequest* aRequest, SourceType* aSource,
Direction aDirection);
void SendContinueInternal(const CursorRequestParams& aParams,
const CursorData<CursorType>& aCurrentData);
void InvalidateCachedResponses();
template <typename Condition>
void DiscardCachedResponses(const Condition& aConditionFunc);
SourceType* GetSource() const {
AssertIsOnOwningThread();
return *mSource;
}
void SendDeleteMeInternal() final;
private:
// Only destroyed by BackgroundTransactionChild or
// BackgroundVersionChangeTransactionChild.
@ -733,7 +714,7 @@ class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
void CompleteContinueRequestFromCache();
void HandleResponse(nsresult aResponse);
using BackgroundCursorChildBase::HandleResponse;
void HandleResponse(const void_t& aResponse);

View File

@ -12,6 +12,7 @@
#include <utility>
#include "FileInfo.h"
#include "FileManager.h"
#include "IDBCursorType.h"
#include "IDBObjectStore.h"
#include "IDBTransaction.h"
#include "IndexedDatabase.h"
@ -9395,24 +9396,24 @@ nsAutoCString MakeColumnPairSelectionList(
: EmptyCString());
}
constexpr bool IsIncreasingOrder(const IDBCursor::Direction aDirection) {
MOZ_ASSERT(aDirection == IDBCursor::Direction::Next ||
aDirection == IDBCursor::Direction::NextUnique ||
aDirection == IDBCursor::Direction::Prev ||
aDirection == IDBCursor::Direction::PrevUnique);
constexpr bool IsIncreasingOrder(const IDBCursorDirection aDirection) {
MOZ_ASSERT(aDirection == IDBCursorDirection::Next ||
aDirection == IDBCursorDirection::Nextunique ||
aDirection == IDBCursorDirection::Prev ||
aDirection == IDBCursorDirection::Prevunique);
return aDirection == IDBCursor::Direction::Next ||
aDirection == IDBCursor::Direction::NextUnique;
return aDirection == IDBCursorDirection::Next ||
aDirection == IDBCursorDirection::Nextunique;
}
constexpr bool IsUnique(const IDBCursor::Direction aDirection) {
MOZ_ASSERT(aDirection == IDBCursor::Direction::Next ||
aDirection == IDBCursor::Direction::NextUnique ||
aDirection == IDBCursor::Direction::Prev ||
aDirection == IDBCursor::Direction::PrevUnique);
constexpr bool IsUnique(const IDBCursorDirection aDirection) {
MOZ_ASSERT(aDirection == IDBCursorDirection::Next ||
aDirection == IDBCursorDirection::Nextunique ||
aDirection == IDBCursorDirection::Prev ||
aDirection == IDBCursorDirection::Prevunique);
return aDirection == IDBCursor::Direction::NextUnique ||
aDirection == IDBCursor::Direction::PrevUnique;
return aDirection == IDBCursorDirection::Nextunique ||
aDirection == IDBCursorDirection::Prevunique;
}
constexpr bool IsKeyCursor(const Cursor::Type aType) {
@ -9422,7 +9423,7 @@ constexpr bool IsKeyCursor(const Cursor::Type aType) {
// TODO: In principle, this could be constexpr, if operator+(nsLiteralCString,
// nsLiteralCString) were constexpr and returned a literal type.
nsAutoCString MakeDirectionClause(const IDBCursor::Direction aDirection) {
nsAutoCString MakeDirectionClause(const IDBCursorDirection aDirection) {
return NS_LITERAL_CSTRING(" ORDER BY ") + kColumnNameKey +
(IsIncreasingOrder(aDirection) ? NS_LITERAL_CSTRING(" ASC")
: NS_LITERAL_CSTRING(" DESC"));
@ -15395,16 +15396,16 @@ bool Cursor::VerifyRequestParams(const CursorRequestParams& aParams,
const Key& key = aParams.get_ContinueParams().key();
if (!key.IsUnset()) {
switch (mDirection) {
case IDBCursor::Direction::Next:
case IDBCursor::Direction::NextUnique:
case IDBCursorDirection::Next:
case IDBCursorDirection::Nextunique:
if (NS_WARN_IF(key <= sortKey)) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
case IDBCursor::Direction::Prev:
case IDBCursor::Direction::PrevUnique:
case IDBCursorDirection::Prev:
case IDBCursorDirection::Prevunique:
if (NS_WARN_IF(key >= sortKey)) {
ASSERT_UNLESS_FUZZING();
return false;
@ -15425,7 +15426,7 @@ bool Cursor::VerifyRequestParams(const CursorRequestParams& aParams,
MOZ_ASSERT(!key.IsUnset());
MOZ_ASSERT(!primaryKey.IsUnset());
switch (mDirection) {
case IDBCursor::Direction::Next:
case IDBCursorDirection::Next:
if (NS_WARN_IF(key < sortKey ||
(key == sortKey &&
primaryKey <= aPosition.mObjectStorePosition))) {
@ -15434,7 +15435,7 @@ bool Cursor::VerifyRequestParams(const CursorRequestParams& aParams,
}
break;
case IDBCursor::Direction::Prev:
case IDBCursorDirection::Prev:
if (NS_WARN_IF(key > sortKey ||
(key == sortKey &&
primaryKey >= aPosition.mObjectStorePosition))) {
@ -26221,8 +26222,8 @@ void Cursor::OpenOp::PrepareIndexKeyConditionClause(
kStmtParamNameCurrentKey);
switch (mCursor->mDirection) {
case IDBCursor::Direction::Next:
case IDBCursor::Direction::Prev:
case IDBCursorDirection::Next:
case IDBCursorDirection::Prev:
continueQuery =
aQueryStart + NS_LITERAL_CSTRING(" AND ") +
GetSortKeyClause(isIncreasingOrder
@ -26261,8 +26262,8 @@ void Cursor::OpenOp::PrepareIndexKeyConditionClause(
NS_LITERAL_CSTRING(")");
break;
case IDBCursor::Direction::NextUnique:
case IDBCursor::Direction::PrevUnique:
case IDBCursorDirection::Nextunique:
case IDBCursorDirection::Prevunique:
continueQuery =
aQueryStart + NS_LITERAL_CSTRING(" AND ") +
GetSortKeyClause(isIncreasingOrder ? ComparisonOperator::GreaterThan
@ -26477,16 +26478,16 @@ nsresult Cursor::OpenOp::DoIndexDatabaseWork(DatabaseConnection* aConnection) {
NS_LITERAL_CSTRING(" ORDER BY ") + kColumnNameAliasSortKey;
switch (mCursor->mDirection) {
case IDBCursor::Direction::Next:
case IDBCursor::Direction::NextUnique:
case IDBCursorDirection::Next:
case IDBCursorDirection::Nextunique:
directionClause.AppendLiteral(" ASC, index_table.object_data_key ASC");
break;
case IDBCursor::Direction::Prev:
case IDBCursorDirection::Prev:
directionClause.AppendLiteral(" DESC, index_table.object_data_key DESC");
break;
case IDBCursor::Direction::PrevUnique:
case IDBCursorDirection::Prevunique:
directionClause.AppendLiteral(" DESC, index_table.object_data_key ASC");
break;
@ -26572,16 +26573,16 @@ nsresult Cursor::OpenOp::DoIndexKeyDatabaseWork(
NS_LITERAL_CSTRING(" ORDER BY ") + kColumnNameAliasSortKey;
switch (mCursor->mDirection) {
case IDBCursor::Direction::Next:
case IDBCursor::Direction::NextUnique:
case IDBCursorDirection::Next:
case IDBCursorDirection::Nextunique:
directionClause.AppendLiteral(" ASC, object_data_key ASC");
break;
case IDBCursor::Direction::Prev:
case IDBCursorDirection::Prev:
directionClause.AppendLiteral(" DESC, object_data_key DESC");
break;
case IDBCursor::Direction::PrevUnique:
case IDBCursorDirection::Prevunique:
directionClause.AppendLiteral(" DESC, object_data_key ASC");
break;
@ -26693,8 +26694,8 @@ nsresult Cursor::ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection) {
mCursor->mType == OpenCursorParams::TIndexOpenCursorParams ||
mCursor->mType == OpenCursorParams::TIndexOpenKeyCursorParams;
MOZ_ASSERT_IF(isIndex && (mCursor->mDirection == IDBCursor::Direction::Next ||
mCursor->mDirection == IDBCursor::Direction::Prev),
MOZ_ASSERT_IF(isIndex && (mCursor->mDirection == IDBCursorDirection::Next ||
mCursor->mDirection == IDBCursorDirection::Prev),
!mCursor->mContinueQueries->mContinuePrimaryKeyQuery.IsEmpty());
MOZ_ASSERT_IF(isIndex, mCursor->mIndexId);
MOZ_ASSERT_IF(isIndex, !mCurrentPosition.mObjectStorePosition.IsUnset());
@ -26736,8 +26737,8 @@ nsresult Cursor::ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection) {
MOZ_ASSERT(!mParams.get_ContinuePrimaryKeyParams().key().IsUnset());
MOZ_ASSERT(
!mParams.get_ContinuePrimaryKeyParams().primaryKey().IsUnset());
MOZ_ASSERT(mCursor->mDirection == IDBCursor::Direction::Next ||
mCursor->mDirection == IDBCursor::Direction::Prev);
MOZ_ASSERT(mCursor->mDirection == IDBCursorDirection::Next ||
mCursor->mDirection == IDBCursorDirection::Prev);
hasContinueKey = true;
hasContinuePrimaryKey = true;
explicitContinueKey = mParams.get_ContinuePrimaryKeyParams().key();
@ -26814,8 +26815,8 @@ nsresult Cursor::ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection) {
// Bind object store position if duplicates are allowed and we're not
// continuing to a specific key.
if (isIndex && !hasContinueKey &&
(mCursor->mDirection == IDBCursor::Direction::Next ||
mCursor->mDirection == IDBCursor::Direction::Prev)) {
(mCursor->mDirection == IDBCursorDirection::Next ||
mCursor->mDirection == IDBCursorDirection::Prev)) {
rv = mCurrentPosition.mObjectStorePosition.BindToStatement(
&*stmt, kStmtParamNameObjectStorePosition);
if (NS_WARN_IF(NS_FAILED(rv))) {

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,9 @@
#ifndef mozilla_dom_idbcursor_h__
#define mozilla_dom_idbcursor_h__
#include "IDBCursorType.h"
#include "IndexedDatabase.h"
#include "InitializedOnce.h"
#include "js/RootingAPI.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/IDBCursorBinding.h"
@ -30,59 +32,42 @@ class IDBObjectStore;
class IDBRequest;
class OwningIDBObjectStoreOrIDBIndex;
namespace indexedDB {
class BackgroundCursorChild;
}
class IDBObjectStoreCursor;
class IDBObjectStoreKeyCursor;
class IDBIndexCursor;
class IDBIndexKeyCursor;
// TODO: Consider defining different subclasses for the different cursor types,
// possibly using the CRTP, which would remove the need for various case
// distinctions.
class IDBCursor final : public nsISupports, public nsWrapperCache {
namespace indexedDB {
class BackgroundCursorChildBase;
template <IDBCursorType CursorType>
class BackgroundCursorChild;
} // namespace indexedDB
class IDBCursor : public nsISupports, public nsWrapperCache {
public:
using Key = indexedDB::Key;
using StructuredCloneReadInfo = indexedDB::StructuredCloneReadInfo;
enum struct Direction {
Next = 0,
NextUnique,
Prev,
PrevUnique,
using Direction = IDBCursorDirection;
using Type = IDBCursorType;
// Only needed for IPC serialization helper, should never be used in code.
Invalid
};
protected:
InitializedOnceMustBeTrue<indexedDB::BackgroundCursorChildBase* const>
mBackgroundActor;
enum struct Type {
ObjectStore,
ObjectStoreKey,
Index,
IndexKey,
};
private:
indexedDB::BackgroundCursorChild* mBackgroundActor;
// TODO: mRequest, mSourceObjectStore and mSourceIndex could be made const if
// Bug 1575173 is resolved. They are initialized in the constructor and never
// modified/cleared.
// TODO: mRequest could be made const if Bug 1575173 is resolved. It is
// initialized in the constructor and never modified/cleared.
RefPtr<IDBRequest> mRequest;
RefPtr<IDBObjectStore> mSourceObjectStore;
RefPtr<IDBIndex> mSourceIndex;
// mSourceObjectStore or mSourceIndex will hold this alive.
// Sub-classes' mSource will hold this alive.
const CheckedUnsafePtr<IDBTransaction> mTransaction;
protected:
// These are cycle-collected!
JS::Heap<JS::Value> mCachedKey;
JS::Heap<JS::Value> mCachedPrimaryKey;
JS::Heap<JS::Value> mCachedValue;
Key mKey;
Key mSortKey; ///< AKA locale aware key/position elsewhere
Key mPrimaryKey; ///< AKA object store key/position elsewhere
StructuredCloneReadInfo mCloneInfo;
const Type mType;
const Direction mDirection;
bool mHaveCachedKey : 1;
@ -93,22 +78,21 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
bool mHaveValue : 1;
public:
static MOZ_MUST_USE RefPtr<IDBCursor> Create(
indexedDB::BackgroundCursorChild* aBackgroundActor, Key aKey,
StructuredCloneReadInfo&& aCloneInfo);
static MOZ_MUST_USE RefPtr<IDBObjectStoreCursor> Create(
indexedDB::BackgroundCursorChild<Type::ObjectStore>* aBackgroundActor,
Key aKey, StructuredCloneReadInfo&& aCloneInfo);
static MOZ_MUST_USE RefPtr<IDBCursor> Create(
indexedDB::BackgroundCursorChild* aBackgroundActor, Key aKey);
static MOZ_MUST_USE RefPtr<IDBObjectStoreKeyCursor> Create(
indexedDB::BackgroundCursorChild<Type::ObjectStoreKey>* aBackgroundActor,
Key aKey);
static MOZ_MUST_USE RefPtr<IDBCursor> Create(
indexedDB::BackgroundCursorChild* aBackgroundActor, Key aKey,
static MOZ_MUST_USE RefPtr<IDBIndexCursor> Create(
indexedDB::BackgroundCursorChild<Type::Index>* aBackgroundActor, Key aKey,
Key aSortKey, Key aPrimaryKey, StructuredCloneReadInfo&& aCloneInfo);
static MOZ_MUST_USE RefPtr<IDBCursor> Create(
indexedDB::BackgroundCursorChild* aBackgroundActor, Key aKey,
Key aSortKey, Key aPrimaryKey);
static Direction ConvertDirection(IDBCursorDirection aDirection);
static MOZ_MUST_USE RefPtr<IDBIndexKeyCursor> Create(
indexedDB::BackgroundCursorChild<Type::IndexKey>* aBackgroundActor,
Key aKey, Key aSortKey, Key aPrimaryKey);
void AssertIsOnOwningThread() const
#ifdef DEBUG
@ -120,74 +104,183 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
nsIGlobalObject* GetParentObject() const;
void GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const;
// XXX: The virtual methods that are used by the DOM binding could be removed
// on the base class, if we provided a non-polymorphic wrapper instead, which
// uses a custom dispatch to the actual implementation type. Don't know if
// this is worth it.
virtual void GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const = 0;
IDBCursorDirection GetDirection() const;
Type GetType() const;
virtual void GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) = 0;
void GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv);
virtual void GetPrimaryKey(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) = 0;
void GetPrimaryKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv);
// XXX: We could move this to a sub-class, since this is only present on
// IDBCursorWithValue.
virtual void GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) = 0;
void GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv);
virtual void Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
ErrorResult& aRv) = 0;
void Continue(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
virtual void ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
JS::Handle<JS::Value> aPrimaryKey,
ErrorResult& aRv) = 0;
void ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
JS::Handle<JS::Value> aPrimaryKey, ErrorResult& aRv);
virtual void Advance(uint32_t aCount, ErrorResult& aRv) = 0;
void Advance(uint32_t aCount, ErrorResult& aRv);
virtual MOZ_MUST_USE RefPtr<IDBRequest> Update(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv) = 0;
MOZ_MUST_USE RefPtr<IDBRequest> Update(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv);
MOZ_MUST_USE RefPtr<IDBRequest> Delete(JSContext* aCx, ErrorResult& aRv);
void Reset();
void Reset(Key&& aKey, StructuredCloneReadInfo&& aValue);
void Reset(Key&& aKey);
void Reset(Key&& aKey, Key&& aSortKey, Key&& aPrimaryKey,
StructuredCloneReadInfo&& aValue);
void Reset(Key&& aKey, Key&& aSortKey, Key&& aPrimaryKey);
virtual MOZ_MUST_USE RefPtr<IDBRequest> Delete(JSContext* aCx,
ErrorResult& aRv) = 0;
void ClearBackgroundActor() {
AssertIsOnOwningThread();
mBackgroundActor = nullptr;
mBackgroundActor.reset();
}
void InvalidateCachedResponses();
// Checks if this is a locale aware cursor (ie. the index's sortKey is unset)
bool IsLocaleAware() const;
virtual void InvalidateCachedResponses() = 0;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBCursor)
protected:
IDBCursor(indexedDB::BackgroundCursorChildBase* aBackgroundActor);
// TODO: Check if we can remove virtual by changing cycle collection.
virtual ~IDBCursor() = default;
void ResetBase();
};
template <IDBCursor::Type CursorType>
class IDBTypedCursor : public IDBCursor {
public:
template <typename... DataArgs>
explicit IDBTypedCursor(
indexedDB::BackgroundCursorChild<CursorType>* aBackgroundActor,
DataArgs&&... aDataArgs);
static constexpr Type GetType() { return CursorType; }
// Checks if this is a locale aware cursor (ie. the index's sortKey is unset)
bool IsLocaleAware() const;
void GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const final;
void GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) final;
void GetPrimaryKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) final;
void GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) final;
void Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
ErrorResult& aRv) final;
void ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
JS::Handle<JS::Value> aPrimaryKey,
ErrorResult& aRv) final;
void Advance(uint32_t aCount, ErrorResult& aRv) final;
MOZ_MUST_USE RefPtr<IDBRequest> Update(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv) final;
MOZ_MUST_USE RefPtr<IDBRequest> Delete(JSContext* aCx,
ErrorResult& aRv) final;
// nsWrapperCache
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
void InvalidateCachedResponses() final;
void Reset();
void Reset(CursorData<CursorType>&& aCursorData);
private:
IDBCursor(Type aType, indexedDB::BackgroundCursorChild* aBackgroundActor,
Key aKey);
static constexpr bool IsObjectStoreCursor =
CursorTypeTraits<CursorType>::IsObjectStoreCursor;
static constexpr bool IsKeyOnlyCursor =
CursorTypeTraits<CursorType>::IsKeyOnlyCursor;
~IDBCursor();
CursorSourceType<CursorType>& GetSourceRef() const {
MOZ_ASSERT(mSource);
return *mSource;
}
IDBObjectStore& GetSourceObjectStoreRef() const {
if constexpr (IsObjectStoreCursor) {
return GetSourceRef();
} else {
MOZ_ASSERT(!GetSourceRef().IsDeleted());
auto res = GetSourceRef().ObjectStore();
MOZ_ASSERT(res);
return *res;
}
}
indexedDB::BackgroundCursorChild<CursorType>& GetTypedBackgroundActorRef()
const {
// We can safely downcast to BackgroundCursorChild<CursorType>*, since we
// initialized that in the constructor from that type. We just want to avoid
// having a second typed field.
return *static_cast<indexedDB::BackgroundCursorChild<CursorType>*>(
*mBackgroundActor);
}
bool IsSourceDeleted() const;
protected:
virtual ~IDBTypedCursor() override;
void DropJSObjects();
bool IsSourceDeleted() const;
CursorData<CursorType> mData;
// TODO: mSource could be made const if Bug 1575173 is resolved. It is
// initialized in the constructor and never modified/cleared.
RefPtr<CursorSourceType<CursorType>> mSource;
};
// The subclasses defined by this macro are only needed to be able to use the
// cycle collector macros, which do not support templates. If spelled out, the
// cycle collection could be implemented directly on IDBTypedCursor, and these
// classes were not needed.
#define CONCRETE_IDBCURSOR_SUBCLASS(_subclassName, _cursorType) \
class _subclassName final : public IDBTypedCursor<_cursorType> { \
public: \
NS_DECL_ISUPPORTS_INHERITED \
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(_subclassName, IDBCursor) \
\
using IDBTypedCursor<_cursorType>::IDBTypedCursor; \
\
private: \
~_subclassName() final = default; \
};
CONCRETE_IDBCURSOR_SUBCLASS(IDBObjectStoreCursor, IDBCursor::Type::ObjectStore)
CONCRETE_IDBCURSOR_SUBCLASS(IDBObjectStoreKeyCursor,
IDBCursor::Type::ObjectStoreKey)
CONCRETE_IDBCURSOR_SUBCLASS(IDBIndexCursor, IDBCursor::Type::Index)
CONCRETE_IDBCURSOR_SUBCLASS(IDBIndexKeyCursor, IDBCursor::Type::IndexKey)
template <IDBCursor::Type CursorType>
using IDBCursorImpl = typename CursorTypeTraits<CursorType>::Type;
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IDBCursorType.h"
namespace mozilla {
namespace dom {
CommonCursorDataBase::CommonCursorDataBase(Key aKey) : mKey{std::move(aKey)} {}
IndexCursorDataBase::IndexCursorDataBase(Key aKey, Key aLocaleAwareKey,
Key aObjectStoreKey)
: CommonCursorDataBase{std::move(aKey)},
mLocaleAwareKey{std::move(aLocaleAwareKey)},
mObjectStoreKey{std::move(aObjectStoreKey)} {}
ValueCursorDataBase::ValueCursorDataBase(StructuredCloneReadInfo&& aCloneInfo)
: mCloneInfo{std::move(aCloneInfo)} {}
CursorData<IDBCursorType::ObjectStore>::CursorData(
Key aKey, StructuredCloneReadInfo&& aCloneInfo)
: ObjectStoreCursorDataBase{std::move(aKey)},
ValueCursorDataBase{std::move(aCloneInfo)} {}
CursorData<IDBCursorType::Index>::CursorData(
Key aKey, Key aLocaleAwareKey, Key aObjectStoreKey,
StructuredCloneReadInfo&& aCloneInfo)
: IndexCursorDataBase{std::move(aKey), std::move(aLocaleAwareKey),
std::move(aObjectStoreKey)},
ValueCursorDataBase{std::move(aCloneInfo)} {}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,138 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_idbcursortype_h__
#define mozilla_dom_idbcursortype_h__
#include "IndexedDatabase.h"
#include "mozilla/dom/indexedDB/Key.h"
namespace mozilla {
namespace dom {
enum struct IDBCursorType {
ObjectStore,
ObjectStoreKey,
Index,
IndexKey,
};
template <IDBCursorType CursorType>
struct CursorTypeTraits;
class IDBIndex;
class IDBObjectStore;
class IDBIndexCursor;
class IDBIndexKeyCursor;
class IDBObjectStoreCursor;
class IDBObjectStoreKeyCursor;
template <>
struct CursorTypeTraits<IDBCursorType::Index> {
using Type = IDBIndexCursor;
static constexpr bool IsObjectStoreCursor = false;
static constexpr bool IsKeyOnlyCursor = false;
};
template <>
struct CursorTypeTraits<IDBCursorType::IndexKey> {
using Type = IDBIndexKeyCursor;
static constexpr bool IsObjectStoreCursor = false;
static constexpr bool IsKeyOnlyCursor = true;
};
template <>
struct CursorTypeTraits<IDBCursorType::ObjectStore> {
using Type = IDBObjectStoreCursor;
static constexpr bool IsObjectStoreCursor = true;
static constexpr bool IsKeyOnlyCursor = false;
};
template <>
struct CursorTypeTraits<IDBCursorType::ObjectStoreKey> {
using Type = IDBObjectStoreKeyCursor;
static constexpr bool IsObjectStoreCursor = true;
static constexpr bool IsKeyOnlyCursor = true;
};
template <IDBCursorType CursorType>
using CursorSourceType =
std::conditional_t<CursorTypeTraits<CursorType>::IsObjectStoreCursor,
IDBObjectStore, IDBIndex>;
using Key = indexedDB::Key;
using StructuredCloneReadInfo = indexedDB::StructuredCloneReadInfo;
struct CommonCursorDataBase {
CommonCursorDataBase() = delete;
explicit CommonCursorDataBase(Key aKey);
Key mKey;
};
template <IDBCursorType CursorType>
struct CursorData;
struct ObjectStoreCursorDataBase : CommonCursorDataBase {
using CommonCursorDataBase::CommonCursorDataBase;
const Key& GetSortKey(const bool aIsLocaleAware) const {
MOZ_ASSERT(!aIsLocaleAware);
return GetObjectStoreKey();
}
const Key& GetObjectStoreKey() const { return mKey; }
static constexpr const char* GetObjectStoreKeyForLogging() { return "NA"; }
};
struct IndexCursorDataBase : CommonCursorDataBase {
IndexCursorDataBase(Key aKey, Key aLocaleAwareKey, Key aObjectStoreKey);
const Key& GetSortKey(const bool aIsLocaleAware) const {
return aIsLocaleAware ? mLocaleAwareKey : mKey;
}
const Key& GetObjectStoreKey() const { return mObjectStoreKey; }
const char* GetObjectStoreKeyForLogging() const {
return GetObjectStoreKey().GetBuffer().get();
}
Key mLocaleAwareKey;
Key mObjectStoreKey;
};
struct ValueCursorDataBase {
explicit ValueCursorDataBase(StructuredCloneReadInfo&& aCloneInfo);
StructuredCloneReadInfo mCloneInfo;
};
template <>
struct CursorData<IDBCursorType::ObjectStoreKey> : ObjectStoreCursorDataBase {
using ObjectStoreCursorDataBase::ObjectStoreCursorDataBase;
};
template <>
struct CursorData<IDBCursorType::ObjectStore> : ObjectStoreCursorDataBase,
ValueCursorDataBase {
CursorData(Key aKey, StructuredCloneReadInfo&& aCloneInfo);
};
template <>
struct CursorData<IDBCursorType::IndexKey> : IndexCursorDataBase {
using IndexCursorDataBase::IndexCursorDataBase;
};
template <>
struct CursorData<IDBCursorType::Index> : IndexCursorDataBase,
ValueCursorDataBase {
CursorData(Key aKey, Key aLocaleAwareKey, Key aObjectStoreKey,
StructuredCloneReadInfo&& aCloneInfo);
};
} // namespace dom
} // namespace mozilla
#endif

View File

@ -7,7 +7,7 @@
#include "IDBIndex.h"
#include "FileInfo.h"
#include "IDBCursor.h"
#include "IDBCursorType.h"
#include "IDBEvents.h"
#include "IDBKeyRange.h"
#include "IDBObjectStore.h"
@ -489,11 +489,8 @@ RefPtr<IDBRequest> IDBIndex::OpenCursorInternal(bool aKeysOnly, JSContext* aCx,
optionalKeyRange.emplace(std::move(serializedKeyRange));
}
const IDBCursor::Direction direction =
IDBCursor::ConvertDirection(aDirection);
const CommonIndexOpenCursorParams commonIndexParams = {
{objectStoreId, std::move(optionalKeyRange), direction}, indexId};
{objectStoreId, std::move(optionalKeyRange), aDirection}, indexId};
const auto params =
aKeysOnly ? OpenCursorParams{IndexOpenKeyCursorParams{commonIndexParams}}
@ -511,7 +508,7 @@ RefPtr<IDBRequest> IDBIndex::OpenCursorInternal(bool aKeysOnly, JSContext* aCx,
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(direction));
IDB_LOG_STRINGIFY(aDirection));
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s).index(%s)."
@ -521,11 +518,15 @@ RefPtr<IDBRequest> IDBIndex::OpenCursorInternal(bool aKeysOnly, JSContext* aCx,
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(direction));
IDB_LOG_STRINGIFY(aDirection));
}
BackgroundCursorChild* const actor =
new BackgroundCursorChild(request, this, direction);
BackgroundCursorChildBase* const actor =
aKeysOnly ? static_cast<BackgroundCursorChildBase*>(
new BackgroundCursorChild<IDBCursorType::IndexKey>(
request, this, aDirection))
: new BackgroundCursorChild<IDBCursorType::Index>(request, this,
aDirection);
// TODO: This is necessary to preserve request ordering only. Proper
// sequencing of requests should be done in a more sophisticated manner that

View File

@ -7,7 +7,7 @@
#include "IDBObjectStore.h"
#include "FileInfo.h"
#include "IDBCursor.h"
#include "IDBCursorType.h"
#include "IDBDatabase.h"
#include "IDBEvents.h"
#include "IDBFactory.h"
@ -2376,11 +2376,8 @@ RefPtr<IDBRequest> IDBObjectStore::OpenCursorInternal(
optionalKeyRange.emplace(std::move(serializedKeyRange));
}
const IDBCursor::Direction direction =
IDBCursor::ConvertDirection(aDirection);
const CommonOpenCursorParams commonParams = {
objectStoreId, std::move(optionalKeyRange), direction};
objectStoreId, std::move(optionalKeyRange), aDirection};
// TODO: It would be great if the IPDL generator created a constructor
// accepting a CommonOpenCursorParams by value or rvalue reference.
@ -2399,7 +2396,7 @@ RefPtr<IDBRequest> IDBObjectStore::OpenCursorInternal(
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(direction));
IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(aDirection));
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s)."
@ -2408,11 +2405,15 @@ RefPtr<IDBRequest> IDBObjectStore::OpenCursorInternal(
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(direction));
IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(aDirection));
}
BackgroundCursorChild* const actor =
new BackgroundCursorChild(request, this, direction);
BackgroundCursorChildBase* const actor =
aKeysOnly ? static_cast<BackgroundCursorChildBase*>(
new BackgroundCursorChild<IDBCursorType::ObjectStoreKey>(
request, this, aDirection))
: new BackgroundCursorChild<IDBCursorType::ObjectStore>(
request, this, aDirection);
// TODO: This is necessary to preserve request ordering only. Proper
// sequencing of requests should be done in a more sophisticated manner that

View File

@ -7,6 +7,7 @@
#ifndef mozilla_dom_idbobjectstore_h__
#define mozilla_dom_idbobjectstore_h__
#include "IDBCursor.h"
#include "js/RootingAPI.h"
#include "mozilla/dom/IDBCursorBinding.h"
#include "mozilla/dom/IDBIndexBinding.h"
@ -27,7 +28,6 @@ class ErrorResult;
namespace dom {
class DOMStringList;
class IDBCursor;
class IDBRequest;
class IDBTransaction;
class StringOrStringSequence;
@ -50,7 +50,9 @@ class IDBObjectStore final : public nsISupports, public nsWrapperCache {
typedef indexedDB::StructuredCloneReadInfo StructuredCloneReadInfo;
// For AddOrPut() and DeleteInternal().
friend class IDBCursor;
// TODO Consider removing this, and making the functions public?
template <IDBCursor::Type>
friend class IDBTypedCursor;
static const JSClass sDummyPropJSClass;

View File

@ -299,8 +299,9 @@ BackgroundRequestChild* IDBTransaction::StartRequest(
return actor;
}
void IDBTransaction::OpenCursor(BackgroundCursorChild* const aBackgroundActor,
const OpenCursorParams& aParams) {
void IDBTransaction::OpenCursor(
PBackgroundIDBCursorChild* const aBackgroundActor,
const OpenCursorParams& aParams) {
AssertIsOnOwningThread();
MOZ_ASSERT(aBackgroundActor);
MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);

View File

@ -34,7 +34,7 @@ class IDBRequest;
class StrongWorkerRef;
namespace indexedDB {
class BackgroundCursorChild;
class PBackgroundIDBCursorChild;
class BackgroundRequestChild;
class BackgroundTransactionChild;
class BackgroundVersionChangeTransactionChild;
@ -48,7 +48,6 @@ class IDBTransaction final
: public DOMEventTargetHelper,
public nsIRunnable,
public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>> {
friend class indexedDB::BackgroundCursorChild;
friend class indexedDB::BackgroundRequestChild;
public:
@ -163,7 +162,7 @@ class IDBTransaction final
indexedDB::BackgroundRequestChild* StartRequest(
IDBRequest* aRequest, const indexedDB::RequestParams& aParams);
void OpenCursor(indexedDB::BackgroundCursorChild* aBackgroundActor,
void OpenCursor(indexedDB::PBackgroundIDBCursorChild* aBackgroundActor,
const indexedDB::OpenCursorParams& aParams);
void RefreshSpec(bool aMayDelete);
@ -366,10 +365,13 @@ class IDBTransaction final
void MaybeNoteInactiveTransaction();
// TODO consider making private again, or move to the right place
public:
void OnNewRequest();
void OnRequestFinished(bool aRequestCompletedSuccessfully);
private:
template <typename Func>
auto DoWithTransactionChild(const Func& aFunc) const;

View File

@ -85,6 +85,10 @@ class InitializedOnce final {
void reset() {
MOZ_ASSERT(mMaybe.isSome());
maybeReset();
}
void maybeReset() {
mMaybe.reset();
#ifdef DEBUG
mWasReset = true;

View File

@ -12,7 +12,7 @@
#include "BackgroundChildImpl.h"
#include "GeckoProfiler.h"
#include "IDBCursor.h"
#include "IDBCursorType.h"
#include "IDBDatabase.h"
#include "IDBIndex.h"
#include "IDBKeyRange.h"
@ -189,18 +189,18 @@ class MOZ_STACK_CLASS LoggingString final : public nsAutoCString {
}
}
explicit LoggingString(const IDBCursor::Direction aDirection) {
explicit LoggingString(const IDBCursorDirection aDirection) {
switch (aDirection) {
case IDBCursor::Direction::Next:
case IDBCursorDirection::Next:
AssignLiteral("\"next\"");
break;
case IDBCursor::Direction::NextUnique:
case IDBCursorDirection::Nextunique:
AssignLiteral("\"nextunique\"");
break;
case IDBCursor::Direction::Prev:
case IDBCursorDirection::Prev:
AssignLiteral("\"prev\"");
break;
case IDBCursor::Direction::PrevUnique:
case IDBCursorDirection::Prevunique:
AssignLiteral("\"prevunique\"");
break;
default:

View File

@ -73,7 +73,7 @@ struct ParamTraits<mozilla::dom::IDBCursor::Direction>
: public ContiguousEnumSerializer<
mozilla::dom::IDBCursor::Direction,
mozilla::dom::IDBCursor::Direction::Next,
mozilla::dom::IDBCursor::Direction::Invalid> {};
mozilla::dom::IDBCursor::Direction::EndGuard_> {};
template <>
struct ParamTraits<mozilla::dom::IDBTransaction::Mode>

View File

@ -26,6 +26,7 @@ TEST_DIRS += ['test/gtest']
EXPORTS.mozilla.dom += [
'FlippedOnce.h',
'IDBCursor.h',
'IDBCursorType.h',
'IDBDatabase.h',
'IDBEvents.h',
'IDBFactory.h',
@ -39,6 +40,7 @@ EXPORTS.mozilla.dom += [
'IDBTransaction.h',
'IndexedDatabase.h',
'IndexedDatabaseManager.h',
'InitializedOnce.h',
]
EXPORTS.mozilla.dom.indexedDB += [
@ -56,6 +58,7 @@ UNIFIED_SOURCES += [
'FileInfo.cpp',
'FileSnapshot.cpp',
'IDBCursor.cpp',
'IDBCursorType.cpp',
'IDBDatabase.cpp',
'IDBEvents.cpp',
'IDBFactory.cpp',