зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1168606 - Support preloading also for index cursors. r=ttung,asuth
Depends on D43252 Differential Revision: https://phabricator.services.mozilla.com/D43461 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
1db45a09bf
Коммит
69cd8f61cb
|
@ -3215,6 +3215,18 @@ 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)} {}
|
||||
|
||||
// Does not need to be threadsafe since this only runs on one thread, but
|
||||
// inheriting from CancelableRunnable is easy.
|
||||
class BackgroundCursorChild::DelayedActionRunnable final
|
||||
|
@ -3285,7 +3297,8 @@ BackgroundCursorChild::~BackgroundCursorChild() {
|
|||
}
|
||||
|
||||
void BackgroundCursorChild::SendContinueInternal(
|
||||
const CursorRequestParams& aParams, const Key& aCurrentKey) {
|
||||
const CursorRequestParams& aParams, const Key& aCurrentKey,
|
||||
const Key& aCurrentObjectStoreKey) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mRequest);
|
||||
MOZ_ASSERT(mTransaction);
|
||||
|
@ -3303,6 +3316,7 @@ void BackgroundCursorChild::SendContinueInternal(
|
|||
|
||||
CursorRequestParams params = aParams;
|
||||
Key currentKey = aCurrentKey;
|
||||
Key currentObjectStoreKey = aCurrentObjectStoreKey;
|
||||
|
||||
switch (params.type()) {
|
||||
case CursorRequestParams::TContinueParams: {
|
||||
|
@ -3314,20 +3328,30 @@ void BackgroundCursorChild::SendContinueInternal(
|
|||
// Invalidate cache entries.
|
||||
size_t discardedCount = 0;
|
||||
while (!mCachedResponses.empty()) {
|
||||
// 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 =
|
||||
mCursor->IsLocaleAware() ? mCachedResponses.front().mLocaleAwareKey
|
||||
: mCachedResponses.front().mKey;
|
||||
const auto& keyOperator = GetKeyOperator(mDirection);
|
||||
if ((mCachedResponses.front().mKey.*keyOperator)(key)) {
|
||||
if ((cachedSortKey.*keyOperator)(key)) {
|
||||
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
|
||||
"PRELOAD: Continue to key %s, keeping cached key %s and further",
|
||||
"PRELOAD: Continue to key %s, keeping cached key %s/%s and "
|
||||
"further",
|
||||
"Continue/keep", mTransaction->LoggingSerialNumber(),
|
||||
mRequest->LoggingSerialNumber(), key.GetBuffer().get(),
|
||||
mCachedResponses.front().mKey.GetBuffer().get());
|
||||
mCachedResponses.front().mKey.GetBuffer().get(),
|
||||
mCachedResponses.front().mObjectStoreKey.GetBuffer().get());
|
||||
break;
|
||||
}
|
||||
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
|
||||
"PRELOAD: Continue to key %s, discarding cached key %s",
|
||||
"PRELOAD: Continue to key %s, discarding cached key %s/%s",
|
||||
"Continue/discard", mTransaction->LoggingSerialNumber(),
|
||||
mRequest->LoggingSerialNumber(), key.GetBuffer().get(),
|
||||
mCachedResponses.front().mKey.GetBuffer().get());
|
||||
mCachedResponses.front().mKey.GetBuffer().get(),
|
||||
mCachedResponses.front().mObjectStoreKey.GetBuffer().get());
|
||||
mCachedResponses.pop_front();
|
||||
++discardedCount;
|
||||
}
|
||||
|
@ -3360,6 +3384,7 @@ void BackgroundCursorChild::SendContinueInternal(
|
|||
// TODO: We only need to update currentKey on the last entry, the others
|
||||
// are overwritten in the next iteration anyway.
|
||||
currentKey = mCachedResponses.front().mKey;
|
||||
currentObjectStoreKey = mCachedResponses.front().mObjectStoreKey;
|
||||
mCachedResponses.pop_front();
|
||||
++discardedCount;
|
||||
}
|
||||
|
@ -3397,8 +3422,8 @@ void BackgroundCursorChild::SendContinueInternal(
|
|||
// mCachedResponses falls under some threshold? Or does the response
|
||||
// handling model disallow this?
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(
|
||||
PBackgroundIDBCursorChild::SendContinue(params, currentKey));
|
||||
MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(
|
||||
params, currentKey, currentObjectStoreKey));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3408,12 +3433,27 @@ void BackgroundCursorChild::CompleteContinueRequestFromCache() {
|
|||
MOZ_ASSERT(mCursor);
|
||||
MOZ_ASSERT(mStrongCursor);
|
||||
MOZ_ASSERT(!mDelayedResponses.empty());
|
||||
// TODO: Also support the other types.
|
||||
MOZ_ASSERT(mCursor->GetType() == IDBCursor::Type_ObjectStore ||
|
||||
mCursor->GetType() == IDBCursor::Type_Index);
|
||||
|
||||
RefPtr<IDBCursor> cursor;
|
||||
mStrongCursor.swap(cursor);
|
||||
|
||||
auto& item = mDelayedResponses.front();
|
||||
mCursor->Reset(std::move(item.mKey), std::move(item.mCloneInfo));
|
||||
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;
|
||||
default:
|
||||
// TODO: Also support the other types.
|
||||
MOZ_CRASH("Should never get here.");
|
||||
}
|
||||
mDelayedResponses.pop_front();
|
||||
|
||||
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
|
||||
|
@ -3499,14 +3539,15 @@ void BackgroundCursorChild::HandleResponse(const void_t& aResponse) {
|
|||
}
|
||||
}
|
||||
|
||||
void BackgroundCursorChild::HandleResponse(
|
||||
const nsTArray<ObjectStoreCursorResponse>& aResponses) {
|
||||
template <typename T, typename Func>
|
||||
void BackgroundCursorChild::HandleMultipleCursorResponses(
|
||||
const nsTArray<T>& aResponses, const Func& aHandleRecord) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mRequest);
|
||||
MOZ_ASSERT(mTransaction);
|
||||
MOZ_ASSERT(mObjectStore);
|
||||
MOZ_ASSERT(!mStrongRequest);
|
||||
MOZ_ASSERT(!mStrongCursor);
|
||||
MOZ_ASSERT(aResponses.Length() > 0);
|
||||
|
||||
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
|
||||
"PRELOAD: Received %zu cursor responses", "Received",
|
||||
|
@ -3515,45 +3556,78 @@ void BackgroundCursorChild::HandleResponse(
|
|||
MOZ_ASSERT_IF(aResponses.Length() > 1, mCachedResponses.empty());
|
||||
|
||||
// XXX Fix this somehow...
|
||||
auto& responses =
|
||||
const_cast<nsTArray<ObjectStoreCursorResponse>&>(aResponses);
|
||||
auto& responses = const_cast<nsTArray<T>&>(aResponses);
|
||||
|
||||
for (ObjectStoreCursorResponse& response : responses) {
|
||||
StructuredCloneReadInfo cloneReadInfo(std::move(response.cloneInfo()));
|
||||
cloneReadInfo.mDatabase = mTransaction->Database();
|
||||
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());
|
||||
|
||||
// TODO: This uses response.cloneInfo() after it was apparently moved above,
|
||||
// which would be invalid. However, it was not really moved, since
|
||||
// StructuredCloneReadInfo::StructuredCloneReadInfo(SerializedStructuredCloneReadInfo&&)
|
||||
// does not touch 'files' at all. This is, however, confusing.
|
||||
// Can't this be done in the constructor of StructuredCloneReadInfo as well?
|
||||
// Note: this will be fixed in a subsequent patch for bug 1168606.
|
||||
DeserializeStructuredCloneFiles(
|
||||
mTransaction->Database(), response.cloneInfo().files(),
|
||||
/* aForPreprocess */ false, cloneReadInfo.mFiles);
|
||||
|
||||
RefPtr<IDBCursor> newCursor;
|
||||
|
||||
if (mCursor) {
|
||||
if (mCursor->IsContinueCalled()) {
|
||||
mCursor->Reset(std::move(response.key()), std::move(cloneReadInfo));
|
||||
} else {
|
||||
CachedResponse cachedResponse;
|
||||
cachedResponse.mKey = std::move(response.key());
|
||||
cachedResponse.mCloneInfo = std::move(cloneReadInfo);
|
||||
mCachedResponses.emplace_back(std::move(cachedResponse));
|
||||
}
|
||||
} else {
|
||||
newCursor = IDBCursor::Create(this, std::move(response.key()),
|
||||
std::move(cloneReadInfo));
|
||||
mCursor = newCursor;
|
||||
}
|
||||
aHandleRecord(response);
|
||||
}
|
||||
|
||||
ResultHelper helper(mRequest, mTransaction, mCursor);
|
||||
DispatchSuccessEvent(&helper);
|
||||
}
|
||||
|
||||
// Note: the parameter type is an rvalue reference, since passing it by value
|
||||
// yields a 'Type must not be used as parameter' error
|
||||
StructuredCloneReadInfo BackgroundCursorChild::PrepareCloneReadInfo(
|
||||
SerializedStructuredCloneReadInfo&& aCloneInfo) const {
|
||||
StructuredCloneReadInfo cloneReadInfo(
|
||||
std::forward<SerializedStructuredCloneReadInfo>(aCloneInfo));
|
||||
cloneReadInfo.mDatabase = mTransaction->Database();
|
||||
|
||||
// TODO: This uses response.cloneInfo() after it was apparently moved
|
||||
// above, which would be invalid. However, it was not really moved,
|
||||
// since
|
||||
// StructuredCloneReadInfo::StructuredCloneReadInfo(SerializedStructuredCloneReadInfo&&)
|
||||
// does not touch 'files' at all. This is, however, confusing.
|
||||
// Can't this be done in the constructor of StructuredCloneReadInfo as
|
||||
// well?
|
||||
// Note: this will be fixed in a subsequent patch for bug 1168606.
|
||||
DeserializeStructuredCloneFiles(mTransaction->Database(), aCloneInfo.files(),
|
||||
/* aForPreprocess */ false,
|
||||
cloneReadInfo.mFiles);
|
||||
|
||||
return cloneReadInfo;
|
||||
}
|
||||
|
||||
void BackgroundCursorChild::HandleResponse(
|
||||
const nsTArray<ObjectStoreCursorResponse>& aResponses) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mObjectStore);
|
||||
|
||||
HandleMultipleCursorResponses(
|
||||
aResponses, [this](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.
|
||||
auto cloneReadInfo =
|
||||
PrepareCloneReadInfo(std::move(response.cloneInfo()));
|
||||
|
||||
// TODO: the structure of the rest of this function is the same for all
|
||||
// cursor responses, and it can be unified with a template function,
|
||||
// only the arguments to IDBCursor::Reset, IDBCursor::Create and the
|
||||
// fields for the cached response differ.
|
||||
RefPtr<IDBCursor> newCursor;
|
||||
|
||||
if (mCursor) {
|
||||
if (mCursor->IsContinueCalled()) {
|
||||
mCursor->Reset(std::move(response.key()), std::move(cloneReadInfo));
|
||||
} else {
|
||||
mCachedResponses.emplace_back(std::move(response.key()),
|
||||
std::move(cloneReadInfo));
|
||||
}
|
||||
} else {
|
||||
newCursor = IDBCursor::Create(this, std::move(response.key()),
|
||||
std::move(cloneReadInfo));
|
||||
mCursor = newCursor;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BackgroundCursorChild::HandleResponse(
|
||||
const ObjectStoreKeyCursorResponse& aResponse) {
|
||||
AssertIsOnOwningThread();
|
||||
|
@ -3580,42 +3654,37 @@ void BackgroundCursorChild::HandleResponse(
|
|||
}
|
||||
|
||||
void BackgroundCursorChild::HandleResponse(
|
||||
const IndexCursorResponse& aResponse) {
|
||||
const nsTArray<IndexCursorResponse>& aResponses) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mRequest);
|
||||
MOZ_ASSERT(mTransaction);
|
||||
MOZ_ASSERT(mIndex);
|
||||
MOZ_ASSERT(!mStrongRequest);
|
||||
MOZ_ASSERT(!mStrongCursor);
|
||||
|
||||
// XXX Fix this somehow...
|
||||
auto& response = const_cast<IndexCursorResponse&>(aResponse);
|
||||
HandleMultipleCursorResponses(aResponses, [this](
|
||||
IndexCursorResponse& response) {
|
||||
auto cloneReadInfo = PrepareCloneReadInfo(std::move(response.cloneInfo()));
|
||||
|
||||
StructuredCloneReadInfo cloneReadInfo(std::move(response.cloneInfo()));
|
||||
cloneReadInfo.mDatabase = mTransaction->Database();
|
||||
RefPtr<IDBCursor> newCursor;
|
||||
|
||||
DeserializeStructuredCloneFiles(
|
||||
mTransaction->Database(), aResponse.cloneInfo().files(),
|
||||
/* aForPreprocess */ false, cloneReadInfo.mFiles);
|
||||
|
||||
RefPtr<IDBCursor> newCursor;
|
||||
|
||||
if (mCursor) {
|
||||
mCursor->Reset(std::move(response.key()), std::move(response.sortKey()),
|
||||
std::move(response.objectKey()), std::move(cloneReadInfo));
|
||||
} else {
|
||||
// TODO: This looks particularly dangerous to me. Why do we need to have an
|
||||
// extra newCursor of type RefPtr? Why can't we directly assign to mCursor?
|
||||
// Why is mCursor not a RefPtr? (A similar construct exists in the other
|
||||
// HandleResponse overloads).
|
||||
newCursor = IDBCursor::Create(
|
||||
this, std::move(response.key()), std::move(response.sortKey()),
|
||||
std::move(response.objectKey()), std::move(cloneReadInfo));
|
||||
mCursor = newCursor;
|
||||
}
|
||||
|
||||
ResultHelper helper(mRequest, mTransaction, mCursor);
|
||||
DispatchSuccessEvent(&helper);
|
||||
if (mCursor) {
|
||||
if (mCursor->IsContinueCalled()) {
|
||||
mCursor->Reset(std::move(response.key()), std::move(response.sortKey()),
|
||||
std::move(response.objectKey()),
|
||||
std::move(cloneReadInfo));
|
||||
} else {
|
||||
mCachedResponses.emplace_back(
|
||||
std::move(response.key()), std::move(response.sortKey()),
|
||||
std::move(response.objectKey()), std::move(cloneReadInfo));
|
||||
}
|
||||
} else {
|
||||
// TODO: This looks particularly dangerous to me. Why do we need to
|
||||
// have an extra newCursor of type RefPtr? Why can't we directly
|
||||
// assign to mCursor? Why is mCursor not a RefPtr? (A similar
|
||||
// construct exists in the other HandleResponse overloads).
|
||||
newCursor = IDBCursor::Create(
|
||||
this, std::move(response.key()), std::move(response.sortKey()),
|
||||
std::move(response.objectKey()), std::move(cloneReadInfo));
|
||||
mCursor = newCursor;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BackgroundCursorChild::HandleResponse(
|
||||
|
@ -3709,8 +3778,8 @@ mozilla::ipc::IPCResult BackgroundCursorChild::RecvResponse(
|
|||
HandleResponse(aResponse.get_ObjectStoreKeyCursorResponse());
|
||||
break;
|
||||
|
||||
case CursorResponse::TIndexCursorResponse:
|
||||
HandleResponse(aResponse.get_IndexCursorResponse());
|
||||
case CursorResponse::TArrayOfIndexCursorResponse:
|
||||
HandleResponse(aResponse.get_ArrayOfIndexCursorResponse());
|
||||
break;
|
||||
|
||||
case CursorResponse::TIndexKeyCursorResponse:
|
||||
|
|
|
@ -618,6 +618,9 @@ class BackgroundRequestChild final : public BackgroundRequestChildBase,
|
|||
const PreprocessParams& aParams) override;
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
@ -625,7 +628,11 @@ class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
|
|||
class DelayedActionRunnable;
|
||||
|
||||
struct CachedResponse {
|
||||
CachedResponse() = default;
|
||||
CachedResponse() = delete;
|
||||
|
||||
CachedResponse(Key aKey, StructuredCloneReadInfo&& aCloneInfo);
|
||||
CachedResponse(Key aKey, Key aLocaleAwareKey, Key aObjectStoreKey,
|
||||
StructuredCloneReadInfo&& aCloneInfo);
|
||||
|
||||
CachedResponse(CachedResponse&& aOther) = default;
|
||||
CachedResponse& operator=(CachedResponse&& aOther) = default;
|
||||
|
@ -633,7 +640,8 @@ class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
|
|||
CachedResponse& operator=(const CachedResponse& aOther) = delete;
|
||||
|
||||
Key mKey;
|
||||
Key mObjectKey; // TODO: This is not used anywhere right now
|
||||
Key mLocaleAwareKey;
|
||||
Key mObjectStoreKey;
|
||||
StructuredCloneReadInfo mCloneInfo;
|
||||
};
|
||||
|
||||
|
@ -665,7 +673,8 @@ class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
|
|||
}
|
||||
|
||||
void SendContinueInternal(const CursorRequestParams& aParams,
|
||||
const Key& aCurrentKey);
|
||||
const Key& aCurrentKey,
|
||||
const Key& aCurrentObjectStoreKey);
|
||||
|
||||
void SendDeleteMeInternal();
|
||||
|
||||
|
@ -706,11 +715,18 @@ class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
|
|||
|
||||
void HandleResponse(const void_t& aResponse);
|
||||
|
||||
void HandleResponse(const nsTArray<ObjectStoreCursorResponse>& aResponse);
|
||||
void HandleResponse(const nsTArray<ObjectStoreCursorResponse>& aResponses);
|
||||
|
||||
void HandleResponse(const ObjectStoreKeyCursorResponse& aResponse);
|
||||
|
||||
void HandleResponse(const IndexCursorResponse& aResponse);
|
||||
void HandleResponse(const nsTArray<IndexCursorResponse>& aResponses);
|
||||
|
||||
StructuredCloneReadInfo PrepareCloneReadInfo(
|
||||
SerializedStructuredCloneReadInfo&& aCloneInfo) const;
|
||||
|
||||
template <typename T, typename Func>
|
||||
void HandleMultipleCursorResponses(const nsTArray<T>& aResponses,
|
||||
const Func& aHandleRecord);
|
||||
|
||||
void HandleResponse(const IndexKeyCursorResponse& aResponse);
|
||||
|
||||
|
@ -722,8 +738,8 @@ class BackgroundCursorChild final : public PBackgroundIDBCursorChild {
|
|||
|
||||
public:
|
||||
// Force callers to use SendContinueInternal.
|
||||
bool SendContinue(const CursorRequestParams& aParams,
|
||||
const Key& aCurrentKey) = delete;
|
||||
bool SendContinue(const CursorRequestParams& aParams, const Key& aCurrentKey,
|
||||
const Key& aCurrentObjectStoreKey) = delete;
|
||||
|
||||
bool SendDeleteMe() = delete;
|
||||
};
|
||||
|
|
|
@ -7613,7 +7613,9 @@ class Cursor final : public PBackgroundIDBCursorParent {
|
|||
nsCString mContinueQuery;
|
||||
nsCString mContinueToQuery;
|
||||
nsCString mContinuePrimaryKeyQuery;
|
||||
const nsCString mLocale;
|
||||
const nsCString
|
||||
mLocale; ///< The locale if the cursor is locale-aware, otherwise empty.
|
||||
///< Note that only index-based cursors can be locale-aware.
|
||||
|
||||
// TODO: Probably, it is still necessary to change more related identifiers
|
||||
// (e.g. local variables) and literals, to be in line with the new member
|
||||
|
@ -7676,8 +7678,9 @@ class Cursor final : public PBackgroundIDBCursorParent {
|
|||
|
||||
mozilla::ipc::IPCResult RecvDeleteMe() override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvContinue(const CursorRequestParams& aParams,
|
||||
const Key& key) override;
|
||||
mozilla::ipc::IPCResult RecvContinue(
|
||||
const CursorRequestParams& aParams, const Key& aCurrentKey,
|
||||
const Key& aCurrentObjectStoreKey) override;
|
||||
|
||||
bool IsLocaleAware() const { return !mLocale.IsEmpty(); }
|
||||
|
||||
|
@ -15225,7 +15228,8 @@ void Cursor::SendResponseInternal(
|
|||
if (!files.IsEmpty()) {
|
||||
MOZ_ASSERT(aResponse.type() ==
|
||||
CursorResponse::TArrayOfObjectStoreCursorResponse ||
|
||||
aResponse.type() == CursorResponse::TIndexCursorResponse);
|
||||
aResponse.type() ==
|
||||
CursorResponse::TArrayOfIndexCursorResponse);
|
||||
MOZ_ASSERT(mDatabase);
|
||||
MOZ_ASSERT(mBackgroundParent);
|
||||
|
||||
|
@ -15247,10 +15251,12 @@ void Cursor::SendResponseInternal(
|
|||
break;
|
||||
}
|
||||
|
||||
case CursorResponse::TIndexCursorResponse:
|
||||
MOZ_ASSERT(i == 0);
|
||||
serializedInfo = &aResponse.get_IndexCursorResponse().cloneInfo();
|
||||
case CursorResponse::TArrayOfIndexCursorResponse: {
|
||||
auto& responses = aResponse.get_ArrayOfIndexCursorResponse();
|
||||
MOZ_ASSERT(i < responses.Length());
|
||||
serializedInfo = &responses[i].cloneInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Should never get here!");
|
||||
|
@ -15304,8 +15310,9 @@ mozilla::ipc::IPCResult Cursor::RecvDeleteMe() {
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult Cursor::RecvContinue(const CursorRequestParams& aParams,
|
||||
const Key& aCurrentKey) {
|
||||
mozilla::ipc::IPCResult Cursor::RecvContinue(
|
||||
const CursorRequestParams& aParams, const Key& aCurrentKey,
|
||||
const Key& aCurrentObjectStoreKey) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
|
||||
MOZ_ASSERT(!mActorDestroyed);
|
||||
|
@ -15323,7 +15330,8 @@ mozilla::ipc::IPCResult Cursor::RecvContinue(const CursorRequestParams& aParams,
|
|||
#endif
|
||||
;
|
||||
|
||||
// At the time of writing, the child always passes its current position.
|
||||
// At the time of writing, the child always passes its current position and
|
||||
// object store position.
|
||||
//
|
||||
// TODO: Probably, aCurrentKey is always set, unless ActorsChild is changed to
|
||||
// pass it only when necessary, e.g. only pass if some cached responses were
|
||||
|
@ -15341,6 +15349,13 @@ mozilla::ipc::IPCResult Cursor::RecvContinue(const CursorRequestParams& aParams,
|
|||
mPosition = aCurrentKey;
|
||||
}
|
||||
|
||||
if (!aCurrentObjectStoreKey.IsUnset()) {
|
||||
MOZ_ASSERT(mType == OpenCursorParams::TIndexOpenCursorParams ||
|
||||
mType == OpenCursorParams::TIndexOpenKeyCursorParams);
|
||||
|
||||
mObjectStorePosition = aCurrentObjectStoreKey;
|
||||
}
|
||||
|
||||
if (!trustParams && !VerifyRequestParams(aParams)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
|
@ -25788,10 +25803,15 @@ nsresult Cursor::CursorOpBase::PopulateResponseFromStatement(
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aInitializeResponse);
|
||||
mResponse = IndexCursorResponse();
|
||||
if (aInitializeResponse) {
|
||||
mResponse = nsTArray<IndexCursorResponse>();
|
||||
} else {
|
||||
MOZ_ASSERT(mResponse.type() ==
|
||||
CursorResponse::TArrayOfIndexCursorResponse);
|
||||
}
|
||||
|
||||
auto& response = mResponse.get_IndexCursorResponse();
|
||||
auto& responses = mResponse.get_ArrayOfIndexCursorResponse();
|
||||
auto& response = *responses.AppendElement();
|
||||
response.cloneInfo().data().data = std::move(cloneInfo.mData);
|
||||
response.key() = mCursor->mPosition;
|
||||
response.sortKey() = mCursor->mLocaleAwarePosition;
|
||||
|
@ -25831,7 +25851,8 @@ nsresult Cursor::CursorOpBase::PopulateExtraResponses(
|
|||
const nsCString& aOperation) {
|
||||
AssertIsOnConnectionThread();
|
||||
|
||||
if (mCursor->mType != OpenCursorParams::TObjectStoreOpenCursorParams) {
|
||||
if (mCursor->mType != OpenCursorParams::TObjectStoreOpenCursorParams &&
|
||||
mCursor->mType != OpenCursorParams::TIndexOpenCursorParams) {
|
||||
IDB_WARNING(
|
||||
"PRELOAD: Not yet implemented. Extra results were queried, but are "
|
||||
"discarded for now.");
|
||||
|
@ -26255,7 +26276,8 @@ nsresult Cursor::OpenOp::DoIndexDatabaseWork(DatabaseConnection* aConnection) {
|
|||
// Note: Changing the number or order of SELECT columns in the query will
|
||||
// require changes to CursorOpBase::PopulateResponseFromStatement.
|
||||
const nsCString firstQuery = queryStart + keyRangeClause + directionClause +
|
||||
kOpenLimit + NS_LITERAL_CSTRING("1");
|
||||
kOpenLimit +
|
||||
ToAutoCString(1 + mCursor->mMaxExtraCount);
|
||||
|
||||
DatabaseConnection::CachedStatement stmt;
|
||||
nsresult rv = aConnection->GetCachedStatement(firstQuery, &stmt);
|
||||
|
@ -26301,7 +26323,12 @@ nsresult Cursor::OpenOp::DoIndexDatabaseWork(DatabaseConnection* aConnection) {
|
|||
NS_LITERAL_CSTRING("index_table."),
|
||||
std::move(queryStart));
|
||||
|
||||
return NS_OK;
|
||||
// The degree to which extra responses on OpenOp can actually be used depends
|
||||
// on the parameters of subsequent ContinueOp operations, see also comment in
|
||||
// ContinueOp::DoDatabaseWork.
|
||||
|
||||
return PopulateExtraResponses(stmt, mCursor->mMaxExtraCount,
|
||||
NS_LITERAL_CSTRING("OpenOp"));
|
||||
}
|
||||
|
||||
nsresult Cursor::OpenOp::DoIndexKeyDatabaseWork(
|
||||
|
|
|
@ -258,6 +258,8 @@ IDBCursorDirection IDBCursor::GetDirection() const {
|
|||
}
|
||||
}
|
||||
|
||||
IDBCursor::Type IDBCursor::GetType() const { return mType; }
|
||||
|
||||
void IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
|
@ -453,7 +455,8 @@ void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
|
|||
IDB_LOG_STRINGIFY(key));
|
||||
}
|
||||
|
||||
mBackgroundActor->SendContinueInternal(ContinueParams(key), mKey);
|
||||
mBackgroundActor->SendContinueInternal(ContinueParams(key), mKey,
|
||||
mPrimaryKey);
|
||||
|
||||
mContinueCalled = true;
|
||||
}
|
||||
|
@ -559,7 +562,7 @@ void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
|
|||
IDB_LOG_STRINGIFY(key), IDB_LOG_STRINGIFY(primaryKey));
|
||||
|
||||
mBackgroundActor->SendContinueInternal(
|
||||
ContinuePrimaryKeyParams(key, primaryKey), mKey);
|
||||
ContinuePrimaryKeyParams(key, primaryKey), mKey, mPrimaryKey);
|
||||
|
||||
mContinueCalled = true;
|
||||
}
|
||||
|
@ -604,7 +607,8 @@ void IDBCursor::Advance(uint32_t aCount, ErrorResult& aRv) {
|
|||
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), aCount);
|
||||
}
|
||||
|
||||
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), mKey);
|
||||
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), mKey,
|
||||
mPrimaryKey);
|
||||
|
||||
mContinueCalled = true;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ namespace indexedDB {
|
|||
class BackgroundCursorChild;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
public:
|
||||
typedef indexedDB::Key Key;
|
||||
|
@ -48,7 +51,6 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
|
|||
DIRECTION_INVALID
|
||||
};
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
Type_ObjectStore,
|
||||
Type_ObjectStoreKey,
|
||||
|
@ -56,6 +58,7 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
|
|||
Type_IndexKey,
|
||||
};
|
||||
|
||||
private:
|
||||
indexedDB::BackgroundCursorChild* mBackgroundActor;
|
||||
|
||||
// TODO: mRequest, mSourceObjectStore and mSourceIndex could be made const if
|
||||
|
@ -74,8 +77,8 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
|
|||
JS::Heap<JS::Value> mCachedValue;
|
||||
|
||||
Key mKey;
|
||||
Key mSortKey;
|
||||
Key mPrimaryKey;
|
||||
Key mSortKey; ///< AKA locale aware key/position elsewhere
|
||||
Key mPrimaryKey; ///< AKA object store key/position elsewhere
|
||||
StructuredCloneReadInfo mCloneInfo;
|
||||
|
||||
const Type mType;
|
||||
|
@ -120,6 +123,8 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
|
|||
|
||||
IDBCursorDirection GetDirection() const;
|
||||
|
||||
Type GetType() const;
|
||||
|
||||
bool IsContinueCalled() const { return mContinueCalled; }
|
||||
|
||||
void GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
||||
|
@ -163,6 +168,9 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
|
|||
|
||||
void InvalidateCachedResponses();
|
||||
|
||||
// Checks if this is a locale aware cursor (ie. the index's sortKey is unset)
|
||||
bool IsLocaleAware() const;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBCursor)
|
||||
|
||||
|
@ -176,9 +184,6 @@ class IDBCursor final : public nsISupports, public nsWrapperCache {
|
|||
|
||||
~IDBCursor();
|
||||
|
||||
// Checks if this is a locale aware cursor (ie. the index's sortKey is unset)
|
||||
bool IsLocaleAware() const;
|
||||
|
||||
void DropJSObjects();
|
||||
|
||||
bool IsSourceDeleted() const;
|
||||
|
|
|
@ -80,7 +80,7 @@ union CursorResponse
|
|||
nsresult;
|
||||
ObjectStoreCursorResponse[];
|
||||
ObjectStoreKeyCursorResponse;
|
||||
IndexCursorResponse;
|
||||
IndexCursorResponse[];
|
||||
IndexKeyCursorResponse;
|
||||
};
|
||||
|
||||
|
@ -91,7 +91,8 @@ protocol PBackgroundIDBCursor
|
|||
parent:
|
||||
async DeleteMe();
|
||||
|
||||
async Continue(CursorRequestParams params, Key currentKey);
|
||||
async Continue(CursorRequestParams params, Key currentKey,
|
||||
Key currentObjectStoreKey);
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
|
Загрузка…
Ссылка в новой задаче