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:
Simon Giesecke 2019-11-05 14:40:35 +00:00
parent 9804c8f159
commit 59cd698867
6 changed files with 232 additions and 110 deletions

View File

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

View File

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

View File

@ -7611,7 +7611,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
@ -7674,8 +7676,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(); }
@ -15223,7 +15226,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);
@ -15245,10 +15249,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!");
@ -15302,8 +15308,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);
@ -15321,7 +15328,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
@ -15339,6 +15347,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);
@ -25776,10 +25791,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;
@ -25819,7 +25839,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.");
@ -26243,7 +26264,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);
@ -26289,7 +26311,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(

View File

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

View File

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

View File

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