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 14:21:18 +00:00
Родитель 9bcd87cf24
Коммит a48be584a9
16 изменённых файлов: 1117 добавлений и 911 удалений

Просмотреть файл

@ -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,
template <IDBCursorType CursorType>
BackgroundCursorChild<CursorType>::BackgroundCursorChild(IDBRequest* aRequest,
SourceType* aSource,
Direction aDirection)
: mRequest(aRequest),
mTransaction(aRequest->GetTransaction()),
mObjectStore(nullptr),
mIndex(aIndex),
: 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,6 +3306,7 @@ void BackgroundCursorChild::SendContinueInternal(
}
case CursorRequestParams::TContinuePrimaryKeyParams: {
if constexpr (!CursorTypeTraits<CursorType>::IsObjectStoreCursor) {
const auto& key = params.get_ContinuePrimaryKeyParams().key();
const auto& primaryKey =
params.get_ContinuePrimaryKeyParams().primaryKey();
@ -3347,19 +3315,20 @@ void BackgroundCursorChild::SendContinueInternal(
}
// Discard cache entries before the target key.
DiscardCachedResponses(
[&key, &primaryKey, isLocaleAware = mCursor->IsLocaleAware(),
DiscardCachedResponses([&key, &primaryKey,
isLocaleAware = mCursor->IsLocaleAware(),
keyCompareOperator = GetKeyOperator(mDirection),
transactionSerialNumber = mTransaction->LoggingSerialNumber(),
requestSerialNumber = mRequest->LoggingSerialNumber()](
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 =
isLocaleAware ? currentCachedResponse.mLocaleAwareKey
: currentCachedResponse.mKey;
currentCachedResponse.GetSortKey(isLocaleAware);
const auto& cachedSortPrimaryKey =
currentCachedResponse.mObjectStoreKey;
@ -3388,6 +3357,9 @@ void BackgroundCursorChild::SendContinueInternal(
return discard;
});
} else {
MOZ_CRASH("Shouldn't get here");
}
break;
}
@ -3396,13 +3368,13 @@ 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) {
DiscardCachedResponses([&advanceCount, &currentKey,
&currentObjectStoreKey](
const auto& currentCachedResponse) {
const bool res = advanceCount > 1;
if (res) {
--advanceCount;
@ -3410,7 +3382,11 @@ void BackgroundCursorChild::SendContinueInternal(
// 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;
});
@ -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:
if constexpr (CursorType == IDBCursorType::ObjectStore) {
HandleResponse(aResponse.get_ArrayOfObjectStoreCursorResponse());
} else {
MOZ_CRASH("Response type mismatch");
}
break;
case CursorResponse::TArrayOfObjectStoreKeyCursorResponse:
if constexpr (CursorType == IDBCursorType::ObjectStoreKey) {
HandleResponse(aResponse.get_ArrayOfObjectStoreKeyCursorResponse());
} else {
MOZ_CRASH("Response type mismatch");
}
break;
case CursorResponse::TArrayOfIndexCursorResponse:
if constexpr (CursorType == IDBCursorType::Index) {
HandleResponse(aResponse.get_ArrayOfIndexCursorResponse());
} else {
MOZ_CRASH("Response type mismatch");
}
break;
case CursorResponse::TArrayOfIndexKeyCursorResponse:
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;
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -27,18 +27,13 @@ namespace dom {
using namespace indexedDB;
IDBCursor::IDBCursor(Type aType, BackgroundCursorChild* aBackgroundActor,
Key aKey)
IDBCursor::IDBCursor(BackgroundCursorChildBase* const aBackgroundActor)
: mBackgroundActor(aBackgroundActor),
mRequest(aBackgroundActor->GetRequest()),
mSourceObjectStore(aBackgroundActor->GetObjectStore()),
mSourceIndex(aBackgroundActor->GetIndex()),
mTransaction(mRequest->GetTransaction()),
mCachedKey(JS::UndefinedValue()),
mCachedPrimaryKey(JS::UndefinedValue()),
mCachedValue(JS::UndefinedValue()),
mKey(std::move(aKey)),
mType(aType),
mDirection(aBackgroundActor->GetDirection()),
mHaveCachedKey(false),
mHaveCachedPrimaryKey(false),
@ -49,20 +44,13 @@ IDBCursor::IDBCursor(Type aType, BackgroundCursorChild* aBackgroundActor,
MOZ_ASSERT(aBackgroundActor);
aBackgroundActor->AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
MOZ_ASSERT_IF(aType == Type::ObjectStore || aType == Type::ObjectStoreKey,
mSourceObjectStore);
MOZ_ASSERT_IF(aType == Type::Index || aType == Type::IndexKey, mSourceIndex);
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(!aKey.IsUnset());
mTransaction->RegisterCursor(this);
}
bool IDBCursor::IsLocaleAware() const {
return mSourceIndex && !mSourceIndex->Locale().IsEmpty();
}
IDBCursor::~IDBCursor() {
template <IDBCursor::Type CursorType>
IDBTypedCursor<CursorType>::~IDBTypedCursor() {
AssertIsOnOwningThread();
mTransaction->UnregisterCursor(this);
@ -70,102 +58,60 @@ IDBCursor::~IDBCursor() {
DropJSObjects();
if (mBackgroundActor) {
mBackgroundActor->SendDeleteMeInternal();
(*mBackgroundActor)->SendDeleteMeInternal();
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
}
}
// static
RefPtr<IDBCursor> IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
Key aKey,
RefPtr<IDBObjectStoreCursor> IDBCursor::Create(
BackgroundCursorChild<Type::ObjectStore>* const aBackgroundActor, Key aKey,
StructuredCloneReadInfo&& aCloneInfo) {
MOZ_ASSERT(aBackgroundActor);
aBackgroundActor->AssertIsOnOwningThread();
MOZ_ASSERT(aBackgroundActor->GetObjectStore());
MOZ_ASSERT(!aBackgroundActor->GetIndex());
MOZ_ASSERT(!aKey.IsUnset());
RefPtr<IDBCursor> cursor =
new IDBCursor(Type::ObjectStore, aBackgroundActor, std::move(aKey));
cursor->mCloneInfo = std::move(aCloneInfo);
return cursor;
return MakeRefPtr<IDBObjectStoreCursor>(aBackgroundActor, std::move(aKey),
std::move(aCloneInfo));
}
// static
RefPtr<IDBCursor> IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
RefPtr<IDBObjectStoreKeyCursor> IDBCursor::Create(
BackgroundCursorChild<Type::ObjectStoreKey>* const aBackgroundActor,
Key aKey) {
MOZ_ASSERT(aBackgroundActor);
aBackgroundActor->AssertIsOnOwningThread();
MOZ_ASSERT(aBackgroundActor->GetObjectStore());
MOZ_ASSERT(!aBackgroundActor->GetIndex());
MOZ_ASSERT(!aKey.IsUnset());
RefPtr<IDBCursor> cursor =
new IDBCursor(Type::ObjectStoreKey, aBackgroundActor, std::move(aKey));
return cursor;
return MakeRefPtr<IDBObjectStoreKeyCursor>(aBackgroundActor, std::move(aKey));
}
// static
RefPtr<IDBCursor> IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
Key aKey, Key aSortKey, Key aPrimaryKey,
StructuredCloneReadInfo&& aCloneInfo) {
RefPtr<IDBIndexCursor> IDBCursor::Create(
BackgroundCursorChild<Type::Index>* const aBackgroundActor, Key aKey,
Key aSortKey, Key aPrimaryKey, StructuredCloneReadInfo&& aCloneInfo) {
MOZ_ASSERT(aBackgroundActor);
aBackgroundActor->AssertIsOnOwningThread();
MOZ_ASSERT(aBackgroundActor->GetIndex());
MOZ_ASSERT(!aBackgroundActor->GetObjectStore());
MOZ_ASSERT(!aKey.IsUnset());
MOZ_ASSERT(!aPrimaryKey.IsUnset());
RefPtr<IDBCursor> cursor =
new IDBCursor(Type::Index, aBackgroundActor, std::move(aKey));
cursor->mSortKey = std::move(aSortKey);
cursor->mPrimaryKey = std::move(aPrimaryKey);
cursor->mCloneInfo = std::move(aCloneInfo);
return cursor;
return MakeRefPtr<IDBIndexCursor>(aBackgroundActor, std::move(aKey),
std::move(aSortKey), std::move(aPrimaryKey),
std::move(aCloneInfo));
}
// static
RefPtr<IDBCursor> IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
Key aKey, Key aSortKey, Key aPrimaryKey) {
RefPtr<IDBIndexKeyCursor> IDBCursor::Create(
BackgroundCursorChild<Type::IndexKey>* const aBackgroundActor, Key aKey,
Key aSortKey, Key aPrimaryKey) {
MOZ_ASSERT(aBackgroundActor);
aBackgroundActor->AssertIsOnOwningThread();
MOZ_ASSERT(aBackgroundActor->GetIndex());
MOZ_ASSERT(!aBackgroundActor->GetObjectStore());
MOZ_ASSERT(!aKey.IsUnset());
MOZ_ASSERT(!aPrimaryKey.IsUnset());
RefPtr<IDBCursor> cursor =
new IDBCursor(Type::IndexKey, aBackgroundActor, std::move(aKey));
cursor->mSortKey = std::move(aSortKey);
cursor->mPrimaryKey = std::move(aPrimaryKey);
return cursor;
}
// static
auto IDBCursor::ConvertDirection(IDBCursorDirection aDirection) -> Direction {
switch (aDirection) {
case mozilla::dom::IDBCursorDirection::Next:
return Direction::Next;
case mozilla::dom::IDBCursorDirection::Nextunique:
return Direction::NextUnique;
case mozilla::dom::IDBCursorDirection::Prev:
return Direction::Prev;
case mozilla::dom::IDBCursorDirection::Prevunique:
return Direction::PrevUnique;
default:
MOZ_CRASH("Unknown direction!");
}
return MakeRefPtr<IDBIndexKeyCursor>(aBackgroundActor, std::move(aKey),
std::move(aSortKey),
std::move(aPrimaryKey));
}
#ifdef DEBUG
@ -177,7 +123,8 @@ void IDBCursor::AssertIsOnOwningThread() const {
#endif // DEBUG
void IDBCursor::DropJSObjects() {
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::DropJSObjects() {
AssertIsOnOwningThread();
Reset();
@ -191,36 +138,35 @@ void IDBCursor::DropJSObjects() {
mozilla::DropJSObjects(this);
}
bool IDBCursor::IsSourceDeleted() const {
template <IDBCursor::Type CursorType>
bool IDBTypedCursor<CursorType>::IsSourceDeleted() const {
AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(mTransaction->CanAcceptRequests());
IDBObjectStore* sourceObjectStore;
if (mType == Type::Index || mType == Type::IndexKey) {
MOZ_ASSERT(mSourceIndex);
if (mSourceIndex->IsDeleted()) {
return true;
}
sourceObjectStore = mSourceIndex->ObjectStore();
MOZ_ASSERT(sourceObjectStore);
const auto* const sourceObjectStore = [this]() -> const IDBObjectStore* {
if constexpr (IsObjectStoreCursor) {
return mSource;
} else {
MOZ_ASSERT(mSourceObjectStore);
sourceObjectStore = mSourceObjectStore;
if (GetSourceRef().IsDeleted()) {
return nullptr;
}
return sourceObjectStore->IsDeleted();
const auto* const res = GetSourceRef().ObjectStore();
MOZ_ASSERT(res);
return res;
}
}();
return !sourceObjectStore || sourceObjectStore->IsDeleted();
}
void IDBCursor::Reset() {
void IDBCursor::ResetBase() {
AssertIsOnOwningThread();
mCachedKey.setUndefined();
mCachedPrimaryKey.setUndefined();
mCachedValue.setUndefined();
IDBObjectStore::ClearCloneReadInfo(mCloneInfo);
mHaveCachedKey = false;
mHaveCachedPrimaryKey = false;
@ -229,6 +175,17 @@ void IDBCursor::Reset() {
mContinueCalled = false;
}
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::Reset() {
AssertIsOnOwningThread();
if constexpr (!IsKeyOnlyCursor) {
IDBObjectStore::ClearCloneReadInfo(mData.mCloneInfo);
}
ResetBase();
}
nsIGlobalObject* IDBCursor::GetParentObject() const {
AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
@ -243,13 +200,13 @@ IDBCursorDirection IDBCursor::GetDirection() const {
case Direction::Next:
return IDBCursorDirection::Next;
case Direction::NextUnique:
case Direction::Nextunique:
return IDBCursorDirection::Nextunique;
case Direction::Prev:
return IDBCursorDirection::Prev;
case Direction::PrevUnique:
case Direction::Prevunique:
return IDBCursorDirection::Prevunique;
default:
@ -257,33 +214,24 @@ IDBCursorDirection IDBCursor::GetDirection() const {
}
}
IDBCursor::Type IDBCursor::GetType() const { return mType; }
void IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const {
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::GetSource(
OwningIDBObjectStoreOrIDBIndex& aSource) const {
AssertIsOnOwningThread();
switch (mType) {
case Type::ObjectStore:
case Type::ObjectStoreKey:
MOZ_ASSERT(mSourceObjectStore);
aSource.SetAsIDBObjectStore() = mSourceObjectStore;
return;
case Type::Index:
case Type::IndexKey:
MOZ_ASSERT(mSourceIndex);
aSource.SetAsIDBIndex() = mSourceIndex;
return;
default:
MOZ_ASSERT_UNREACHABLE("Bad type!");
if constexpr (IsObjectStoreCursor) {
aSource.SetAsIDBObjectStore() = mSource;
} else {
aSource.SetAsIDBIndex() = mSource;
}
}
void IDBCursor::GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::GetKey(JSContext* const aCx,
JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) {
AssertIsOnOwningThread();
MOZ_ASSERT(!mKey.IsUnset() || !mHaveValue);
MOZ_ASSERT(!mData.mKey.IsUnset() || !mHaveValue);
if (!mHaveValue) {
aResult.setUndefined();
@ -296,7 +244,7 @@ void IDBCursor::GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
mRooted = true;
}
aRv = mKey.ToJSVal(aCx, mCachedKey);
aRv = mData.mKey.ToJSVal(aCx, mCachedKey);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -307,8 +255,9 @@ void IDBCursor::GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
aResult.set(mCachedKey);
}
void IDBCursor::GetPrimaryKey(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult,
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::GetPrimaryKey(
JSContext* const aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) {
AssertIsOnOwningThread();
@ -323,10 +272,7 @@ void IDBCursor::GetPrimaryKey(JSContext* aCx,
mRooted = true;
}
const Key& key =
(mType == Type::ObjectStore || mType == Type::ObjectStoreKey)
? mKey
: mPrimaryKey;
const Key& key = mData.GetObjectStoreKey();
MOZ_ASSERT(!key.IsUnset());
@ -341,11 +287,13 @@ void IDBCursor::GetPrimaryKey(JSContext* aCx,
aResult.set(mCachedPrimaryKey);
}
void IDBCursor::GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::GetValue(JSContext* const aCx,
JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) {
AssertIsOnOwningThread();
MOZ_ASSERT(mType == Type::ObjectStore || mType == Type::Index);
if constexpr (!IsKeyOnlyCursor) {
if (!mHaveValue) {
aResult.setUndefined();
return;
@ -358,21 +306,27 @@ void IDBCursor::GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
}
JS::Rooted<JS::Value> val(aCx);
if (NS_WARN_IF(!IDBObjectStore::DeserializeValue(aCx, mCloneInfo, &val))) {
if (NS_WARN_IF(
!IDBObjectStore::DeserializeValue(aCx, mData.mCloneInfo, &val))) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
IDBObjectStore::ClearCloneReadInfo(mCloneInfo);
IDBObjectStore::ClearCloneReadInfo(mData.mCloneInfo);
mCachedValue = val;
mHaveCachedValue = true;
}
aResult.set(mCachedValue);
} else {
MOZ_CRASH("This shouldn't be callable on a key-only cursor.");
}
}
void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::Continue(JSContext* const aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv) {
AssertIsOnOwningThread();
@ -395,9 +349,11 @@ void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
return;
}
if constexpr (!IsObjectStoreCursor) {
if (IsLocaleAware() && !key.IsUnset()) {
Key tmp;
result = key.ToLocaleAwareKey(tmp, mSourceIndex->Locale(), aRv);
result = key.ToLocaleAwareKey(tmp, GetSourceRef().Locale(), aRv);
if (!result.Is(Ok, aRv)) {
if (result.Is(Invalid, aRv)) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
@ -406,13 +362,14 @@ void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
}
key = tmp;
}
}
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
const Key& sortKey = mData.GetSortKey(IsLocaleAware());
if (!key.IsUnset()) {
switch (mDirection) {
case Direction::Next:
case Direction::NextUnique:
case Direction::Nextunique:
if (key <= sortKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
@ -420,7 +377,7 @@ void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
break;
case Direction::Prev:
case Direction::PrevUnique:
case Direction::Prevunique:
if (key >= sortKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
@ -435,13 +392,13 @@ void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
mRequest->SetLoggingSerialNumber(requestSerialNumber);
if (mType == Type::ObjectStore || mType == Type::ObjectStoreKey) {
if constexpr (IsObjectStoreCursor) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).continue(%s)",
"IDBCursor.continue()", mTransaction->LoggingSerialNumber(),
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceObjectStore),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSource),
IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(key));
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
@ -450,20 +407,20 @@ void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
"IDBCursor.continue()", mTransaction->LoggingSerialNumber(),
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(GetSourceRef().ObjectStore()),
IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(key));
}
mBackgroundActor->SendContinueInternal(ContinueParams(key), mKey,
mPrimaryKey);
GetTypedBackgroundActorRef().SendContinueInternal(ContinueParams(key), mData);
mContinueCalled = true;
}
void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
JS::Handle<JS::Value> aPrimaryKey,
ErrorResult& aRv) {
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::ContinuePrimaryKey(
JSContext* const aCx, JS::Handle<JS::Value> aKey,
JS::Handle<JS::Value> aPrimaryKey, ErrorResult& aRv) {
AssertIsOnOwningThread();
if (!mTransaction->CanAcceptRequests()) {
@ -476,12 +433,13 @@ void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
return;
}
if ((mType != Type::Index && mType != Type::IndexKey) ||
if (IsObjectStoreCursor ||
(mDirection != Direction::Next && mDirection != Direction::Prev)) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
}
if constexpr (!IsObjectStoreCursor) {
if (!mHaveValue || mContinueCalled) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return;
@ -498,7 +456,7 @@ void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
if (IsLocaleAware() && !key.IsUnset()) {
Key tmp;
result = key.ToLocaleAwareKey(tmp, mSourceIndex->Locale(), aRv);
result = key.ToLocaleAwareKey(tmp, GetSourceRef().Locale(), aRv);
if (!result.Is(Ok, aRv)) {
if (result.Is(Invalid, aRv)) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
@ -527,18 +485,20 @@ void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
return;
}
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
const Key& sortKey = mData.GetSortKey(IsLocaleAware());
switch (mDirection) {
case Direction::Next:
if (key < sortKey || (key == sortKey && primaryKey <= mPrimaryKey)) {
if (key < sortKey ||
(key == sortKey && primaryKey <= mData.mObjectStoreKey)) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
}
break;
case Direction::Prev:
if (key > sortKey || (key == sortKey && primaryKey >= mPrimaryKey)) {
if (key > sortKey ||
(key == sortKey && primaryKey >= mData.mObjectStoreKey)) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
}
@ -557,17 +517,20 @@ void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
"IDBCursor.continuePrimaryKey()", mTransaction->LoggingSerialNumber(),
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(&GetSourceObjectStoreRef()),
IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(key), IDB_LOG_STRINGIFY(primaryKey));
mBackgroundActor->SendContinueInternal(
ContinuePrimaryKeyParams(key, primaryKey), mKey, mPrimaryKey);
GetTypedBackgroundActorRef().SendContinueInternal(
ContinuePrimaryKeyParams(key, primaryKey), mData);
mContinueCalled = true;
}
}
void IDBCursor::Advance(uint32_t aCount, ErrorResult& aRv) {
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::Advance(const uint32_t aCount,
ErrorResult& aRv) {
AssertIsOnOwningThread();
if (!aCount) {
@ -588,13 +551,13 @@ void IDBCursor::Advance(uint32_t aCount, ErrorResult& aRv) {
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
mRequest->SetLoggingSerialNumber(requestSerialNumber);
if (mType == Type::ObjectStore || mType == Type::ObjectStoreKey) {
if constexpr (IsObjectStoreCursor) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).advance(%ld)",
"IDBCursor.advance()", mTransaction->LoggingSerialNumber(),
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceObjectStore),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSource),
IDB_LOG_STRINGIFY(mDirection), aCount);
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
@ -603,19 +566,19 @@ void IDBCursor::Advance(uint32_t aCount, ErrorResult& aRv) {
"IDBCursor.advance()", mTransaction->LoggingSerialNumber(),
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), aCount);
IDB_LOG_STRINGIFY(GetSourceRef().ObjectStore()),
IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection), aCount);
}
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), mKey,
mPrimaryKey);
GetTypedBackgroundActorRef().SendContinueInternal(AdvanceParams(aCount),
mData);
mContinueCalled = true;
}
RefPtr<IDBRequest> IDBCursor::Update(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv) {
template <IDBCursor::Type CursorType>
RefPtr<IDBRequest> IDBTypedCursor<CursorType>::Update(
JSContext* const aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) {
AssertIsOnOwningThread();
if (!mTransaction->CanAcceptRequests()) {
@ -629,41 +592,34 @@ RefPtr<IDBRequest> IDBCursor::Update(JSContext* aCx,
}
if (mTransaction->GetMode() == IDBTransaction::Mode::Cleanup ||
IsSourceDeleted() || !mHaveValue || mType == Type::ObjectStoreKey ||
mType == Type::IndexKey || mContinueCalled) {
IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return nullptr;
}
MOZ_ASSERT(mType == Type::ObjectStore || mType == Type::Index);
MOZ_ASSERT(!mKey.IsUnset());
MOZ_ASSERT_IF(mType == Type::Index, !mPrimaryKey.IsUnset());
if constexpr (!IsKeyOnlyCursor) {
MOZ_ASSERT(!mData.mKey.IsUnset());
if constexpr (!IsObjectStoreCursor) {
MOZ_ASSERT(!mData.mObjectStoreKey.IsUnset());
}
mTransaction->InvalidateCursorCaches();
IDBObjectStore* objectStore;
if (mType == Type::ObjectStore) {
objectStore = mSourceObjectStore;
} else {
objectStore = mSourceIndex->ObjectStore();
}
MOZ_ASSERT(objectStore);
IDBObjectStore::ValueWrapper valueWrapper(aCx, aValue);
const Key& primaryKey = (mType == Type::ObjectStore) ? mKey : mPrimaryKey;
const Key& primaryKey = mData.GetObjectStoreKey();
RefPtr<IDBRequest> request;
if (objectStore->HasValidKeyPath()) {
IDBObjectStore& objectStore = GetSourceObjectStoreRef();
if (objectStore.HasValidKeyPath()) {
if (!valueWrapper.Clone(aCx)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return nullptr;
}
// Make sure the object given has the correct keyPath value set on it.
const KeyPath& keyPath = objectStore->GetKeyPath();
const KeyPath& keyPath = objectStore.GetKeyPath();
Key key;
aRv = keyPath.ExtractKey(aCx, valueWrapper.Value(), key);
@ -676,7 +632,7 @@ RefPtr<IDBRequest> IDBCursor::Update(JSContext* aCx,
return nullptr;
}
request = objectStore->AddOrPut(aCx, valueWrapper,
request = objectStore.AddOrPut(aCx, valueWrapper,
/* aKey */ JS::UndefinedHandleValue,
/* aOverwrite */ true,
/* aFromCursor */ true, aRv);
@ -690,7 +646,7 @@ RefPtr<IDBRequest> IDBCursor::Update(JSContext* aCx,
return nullptr;
}
request = objectStore->AddOrPut(aCx, valueWrapper, keyVal,
request = objectStore.AddOrPut(aCx, valueWrapper, keyVal,
/* aOverwrite */ true,
/* aFromCursor */ true, aRv);
if (aRv.Failed()) {
@ -700,16 +656,16 @@ RefPtr<IDBRequest> IDBCursor::Update(JSContext* aCx,
request->SetSource(this);
if (mType == Type::ObjectStore) {
if (IsObjectStoreCursor) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).update(%s)",
"IDBCursor.update()", mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(&objectStore),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
IDB_LOG_STRINGIFY(&objectStore, primaryKey));
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s)."
@ -717,15 +673,22 @@ RefPtr<IDBRequest> IDBCursor::Update(JSContext* aCx,
"IDBCursor.update()", mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(&objectStore),
IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(&objectStore, primaryKey));
}
return request;
} else {
// XXX: Just to work around a bug in gcc, which otherwise claims 'control
// reaches end of non-void function', which is not true.
return nullptr;
}
}
RefPtr<IDBRequest> IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv) {
template <IDBCursor::Type CursorType>
RefPtr<IDBRequest> IDBTypedCursor<CursorType>::Delete(JSContext* const aCx,
ErrorResult& aRv) {
AssertIsOnOwningThread();
if (!mTransaction->CanAcceptRequests()) {
@ -738,24 +701,17 @@ RefPtr<IDBRequest> IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv) {
return nullptr;
}
if (IsSourceDeleted() || !mHaveValue || mType == Type::ObjectStoreKey ||
mType == Type::IndexKey || mContinueCalled) {
if (IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return nullptr;
}
MOZ_ASSERT(mType == Type::ObjectStore || mType == Type::Index);
MOZ_ASSERT(!mKey.IsUnset());
if constexpr (!IsKeyOnlyCursor) {
MOZ_ASSERT(!mData.mKey.IsUnset());
mTransaction->InvalidateCursorCaches();
IDBObjectStore* const objectStore = mType == Type::ObjectStore
? mSourceObjectStore.get()
: mSourceIndex->ObjectStore();
MOZ_ASSERT(objectStore);
const Key& primaryKey = (mType == Type::ObjectStore) ? mKey : mPrimaryKey;
const Key& primaryKey = mData.GetObjectStoreKey();
JS::Rooted<JS::Value> key(aCx);
aRv = primaryKey.ToJSVal(aCx, &key);
@ -763,24 +719,25 @@ RefPtr<IDBRequest> IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv) {
return nullptr;
}
auto& objectStore = GetSourceObjectStoreRef();
RefPtr<IDBRequest> request =
objectStore->DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
objectStore.DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
if (aRv.Failed()) {
return nullptr;
}
request->SetSource(this);
if (mType == Type::ObjectStore) {
if (IsObjectStoreCursor) {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).delete(%s)",
"IDBCursor.delete()", mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(&objectStore),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
IDB_LOG_STRINGIFY(&objectStore, primaryKey));
} else {
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
"database(%s).transaction(%s).objectStore(%s)."
@ -788,71 +745,37 @@ RefPtr<IDBRequest> IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv) {
"IDBCursor.delete()", mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(&objectStore),
IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(&objectStore, primaryKey));
}
return request;
} else {
// XXX: Just to work around a bug in gcc, which otherwise claims 'control
// reaches end of non-void function', which is not true.
return nullptr;
}
}
void IDBCursor::Reset(Key&& aKey, StructuredCloneReadInfo&& aValue) {
AssertIsOnOwningThread();
MOZ_ASSERT(mType == Type::ObjectStore);
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::Reset(CursorData<CursorType>&& aCursorData) {
this->AssertIsOnOwningThread();
Reset();
mKey = std::move(aKey);
mCloneInfo = std::move(aValue);
mData = std::move(aCursorData);
mHaveValue = !mKey.IsUnset();
mHaveValue = !mData.mKey.IsUnset();
}
void IDBCursor::Reset(Key&& aKey) {
AssertIsOnOwningThread();
MOZ_ASSERT(mType == Type::ObjectStoreKey);
Reset();
mKey = std::move(aKey);
mHaveValue = !mKey.IsUnset();
}
void IDBCursor::Reset(Key&& aKey, Key&& aSortKey, Key&& aPrimaryKey,
StructuredCloneReadInfo&& aValue) {
AssertIsOnOwningThread();
MOZ_ASSERT(mType == Type::Index);
Reset();
mKey = std::move(aKey);
mSortKey = std::move(aSortKey);
mPrimaryKey = std::move(aPrimaryKey);
mCloneInfo = std::move(aValue);
mHaveValue = !mKey.IsUnset();
}
void IDBCursor::Reset(Key&& aKey, Key&& aSortKey, Key&& aPrimaryKey) {
AssertIsOnOwningThread();
MOZ_ASSERT(mType == Type::IndexKey);
Reset();
mKey = std::move(aKey);
mSortKey = std::move(aSortKey);
mPrimaryKey = std::move(aPrimaryKey);
mHaveValue = !mKey.IsUnset();
}
void IDBCursor::InvalidateCachedResponses() {
template <IDBCursor::Type CursorType>
void IDBTypedCursor<CursorType>::InvalidateCachedResponses() {
AssertIsOnOwningThread();
// TODO: In what case would mBackgroundActor be nullptr?
// TODO: Can mBackgroundActor actually be empty at this point?
if (mBackgroundActor) {
mBackgroundActor->InvalidateCachedResponses();
GetTypedBackgroundActorRef().InvalidateCachedResponses();
}
}
@ -868,8 +791,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceObjectStore)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceIndex)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
@ -885,26 +806,59 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
// Don't unlink mRequest, mSourceObjectStore, or mSourceIndex!
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->DropJSObjects();
// Unlinking is done in the subclasses.
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
JSObject* IDBCursor::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
// Don't unlink mRequest or mSource in
// NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED!
#define NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(_subclassName) \
NS_IMPL_CYCLE_COLLECTION_CLASS(_subclassName) \
\
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_subclassName, IDBCursor) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
\
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_subclassName, IDBCursor) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
tmp->DropJSObjects(); \
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
\
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_subclassName) \
NS_INTERFACE_MAP_END_INHERITING(IDBCursor) \
\
NS_IMPL_ADDREF_INHERITED(_subclassName, IDBCursor) \
NS_IMPL_RELEASE_INHERITED(_subclassName, IDBCursor)
NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreCursor)
NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreKeyCursor)
NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexCursor)
NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexKeyCursor)
template <IDBCursor::Type CursorType>
JSObject* IDBTypedCursor<CursorType>::WrapObject(
JSContext* const aCx, JS::Handle<JSObject*> aGivenProto) {
AssertIsOnOwningThread();
switch (mType) {
case Type::ObjectStore:
case Type::Index:
return IDBCursorWithValue_Binding::Wrap(aCx, this, aGivenProto);
return IsKeyOnlyCursor
? IDBCursor_Binding::Wrap(aCx, this, aGivenProto)
: IDBCursorWithValue_Binding::Wrap(aCx, this, aGivenProto);
}
case Type::ObjectStoreKey:
case Type::IndexKey:
return IDBCursor_Binding::Wrap(aCx, this, aGivenProto);
template <IDBCursor::Type CursorType>
template <typename... DataArgs>
IDBTypedCursor<CursorType>::IDBTypedCursor(
indexedDB::BackgroundCursorChild<CursorType>* const aBackgroundActor,
DataArgs&&... aDataArgs)
: IDBCursor{aBackgroundActor},
mData{std::forward<DataArgs>(aDataArgs)...},
mSource(aBackgroundActor->GetSource()) {}
default:
MOZ_CRASH("Bad type!");
template <IDBCursor::Type CursorType>
bool IDBTypedCursor<CursorType>::IsLocaleAware() const {
if constexpr (IsObjectStoreCursor) {
return false;
} else {
return !GetSourceRef().Locale().IsEmpty();
}
}

Просмотреть файл

@ -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);
MOZ_MUST_USE RefPtr<IDBRequest> Update(JSContext* aCx,
virtual MOZ_MUST_USE RefPtr<IDBRequest> Update(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv);
ErrorResult& aRv) = 0;
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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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',