зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
9bcd87cf24
Коммит
a48be584a9
|
@ -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, ¤tKey,
|
||||
¤tObjectStoreKey](const auto& currentCachedResponse) {
|
||||
DiscardCachedResponses([&advanceCount, ¤tKey,
|
||||
¤tObjectStoreKey](
|
||||
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',
|
||||
|
|
Загрузка…
Ссылка в новой задаче