forked from mirrors/gecko-dev
Bug 1754448 - Add basic testing for snapshot re-using; r=dom-storage-reviewers,webidl,asuth,jari,ipc-reviewers,mccr8
Differential Revision: https://phabricator.services.mozilla.com/D138405
This commit is contained in:
parent
3bf75dd4f0
commit
01ad68bec6
18 changed files with 437 additions and 13 deletions
|
|
@ -1580,10 +1580,10 @@ class Datastore final
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// Mutation Methods
|
// Mutation Methods
|
||||||
//
|
//
|
||||||
// These are only called during Snapshot::RecvAsyncCheckpoint
|
// These are only called during Snapshot::Checkpoint
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by Snapshot::RecvAsyncCheckpoint to set a key/value pair as part of an
|
* Used by Snapshot::Checkpoint to set a key/value pair as part of an
|
||||||
* explicit batch.
|
* explicit batch.
|
||||||
*/
|
*/
|
||||||
void SetItem(Database* aDatabase, const nsString& aKey,
|
void SetItem(Database* aDatabase, const nsString& aKey,
|
||||||
|
|
@ -2023,6 +2023,11 @@ class Snapshot final : public PBackgroundLSSnapshotParent {
|
||||||
// Reference counted.
|
// Reference counted.
|
||||||
~Snapshot();
|
~Snapshot();
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult Checkpoint(nsTArray<LSWriteInfo>&& aWriteInfos);
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult CheckpointAndNotify(
|
||||||
|
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos);
|
||||||
|
|
||||||
void Finish();
|
void Finish();
|
||||||
|
|
||||||
// IPDL methods are only called by IPDL.
|
// IPDL methods are only called by IPDL.
|
||||||
|
|
@ -2036,6 +2041,12 @@ class Snapshot final : public PBackgroundLSSnapshotParent {
|
||||||
mozilla::ipc::IPCResult RecvAsyncCheckpointAndNotify(
|
mozilla::ipc::IPCResult RecvAsyncCheckpointAndNotify(
|
||||||
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos) override;
|
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos) override;
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult RecvSyncCheckpoint(
|
||||||
|
nsTArray<LSWriteInfo>&& aWriteInfos) override;
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult RecvSyncCheckpointAndNotify(
|
||||||
|
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos) override;
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvAsyncFinish() override;
|
mozilla::ipc::IPCResult RecvAsyncFinish() override;
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvSyncFinish() override;
|
mozilla::ipc::IPCResult RecvSyncFinish() override;
|
||||||
|
|
@ -2456,6 +2467,19 @@ class PreloadedOp : public LSSimpleRequestBase {
|
||||||
void GetResponse(LSSimpleRequestResponse& aResponse) override;
|
void GetResponse(LSSimpleRequestResponse& aResponse) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GetStateOp : public LSSimpleRequestBase {
|
||||||
|
nsCString mOrigin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GetStateOp(const LSSimpleRequestParams& aParams,
|
||||||
|
const Maybe<ContentParentId>& aContentParentId);
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsresult Start() override;
|
||||||
|
|
||||||
|
void GetResponse(LSSimpleRequestResponse& aResponse) override;
|
||||||
|
};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Other class declarations
|
* Other class declarations
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
@ -3468,6 +3492,14 @@ PBackgroundLSSimpleRequestParent* AllocPBackgroundLSSimpleRequestParent(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case LSSimpleRequestParams::TLSSimpleRequestGetStateParams: {
|
||||||
|
RefPtr<GetStateOp> getStateOp = new GetStateOp(aParams, contentParentId);
|
||||||
|
|
||||||
|
actor = std::move(getStateOp);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("Should never get here!");
|
MOZ_CRASH("Should never get here!");
|
||||||
}
|
}
|
||||||
|
|
@ -5696,7 +5728,7 @@ mozilla::ipc::IPCResult Snapshot::RecvDeleteMe() {
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult Snapshot::RecvAsyncCheckpoint(
|
mozilla::ipc::IPCResult Snapshot::Checkpoint(
|
||||||
nsTArray<LSWriteInfo>&& aWriteInfos) {
|
nsTArray<LSWriteInfo>&& aWriteInfos) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
// Don't assert `mUsage >= 0`, it can be negative when multiple snapshots are
|
// Don't assert `mUsage >= 0`, it can be negative when multiple snapshots are
|
||||||
|
|
@ -5749,7 +5781,7 @@ mozilla::ipc::IPCResult Snapshot::RecvAsyncCheckpoint(
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult Snapshot::RecvAsyncCheckpointAndNotify(
|
mozilla::ipc::IPCResult Snapshot::CheckpointAndNotify(
|
||||||
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos) {
|
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos) {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
// Don't assert `mUsage >= 0`, it can be negative when multiple snapshots are
|
// Don't assert `mUsage >= 0`, it can be negative when multiple snapshots are
|
||||||
|
|
@ -5816,6 +5848,26 @@ mozilla::ipc::IPCResult Snapshot::RecvAsyncCheckpointAndNotify(
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult Snapshot::RecvAsyncCheckpoint(
|
||||||
|
nsTArray<LSWriteInfo>&& aWriteInfos) {
|
||||||
|
return Checkpoint(std::move(aWriteInfos));
|
||||||
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult Snapshot::RecvAsyncCheckpointAndNotify(
|
||||||
|
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos) {
|
||||||
|
return CheckpointAndNotify(std::move(aWriteAndNotifyInfos));
|
||||||
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult Snapshot::RecvSyncCheckpoint(
|
||||||
|
nsTArray<LSWriteInfo>&& aWriteInfos) {
|
||||||
|
return Checkpoint(std::move(aWriteInfos));
|
||||||
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult Snapshot::RecvSyncCheckpointAndNotify(
|
||||||
|
nsTArray<LSWriteAndNotifyInfo>&& aWriteAndNotifyInfos) {
|
||||||
|
return CheckpointAndNotify(std::move(aWriteAndNotifyInfos));
|
||||||
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult Snapshot::RecvAsyncFinish() {
|
mozilla::ipc::IPCResult Snapshot::RecvAsyncFinish() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
|
|
@ -7889,6 +7941,18 @@ bool LSSimpleRequestBase::VerifyRequestParams() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case LSSimpleRequestParams::TLSSimpleRequestGetStateParams: {
|
||||||
|
const LSSimpleRequestGetStateParams& params =
|
||||||
|
mParams.get_LSSimpleRequestGetStateParams();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!VerifyPrincipalInfo(
|
||||||
|
params.principalInfo(), params.storagePrincipalInfo(), false))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("Should never get here!");
|
MOZ_CRASH("Should never get here!");
|
||||||
}
|
}
|
||||||
|
|
@ -8043,6 +8107,60 @@ void PreloadedOp::GetResponse(LSSimpleRequestResponse& aResponse) {
|
||||||
aResponse = preloadedResponse;
|
aResponse = preloadedResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* GetStateOp
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
GetStateOp::GetStateOp(const LSSimpleRequestParams& aParams,
|
||||||
|
const Maybe<ContentParentId>& aContentParentId)
|
||||||
|
: LSSimpleRequestBase(aParams, aContentParentId) {
|
||||||
|
MOZ_ASSERT(aParams.type() ==
|
||||||
|
LSSimpleRequestParams::TLSSimpleRequestGetStateParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult GetStateOp::Start() {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
MOZ_ASSERT(mState == State::StartingRequest);
|
||||||
|
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
|
||||||
|
MOZ_ASSERT(MayProceed());
|
||||||
|
|
||||||
|
const LSSimpleRequestGetStateParams& params =
|
||||||
|
mParams.get_LSSimpleRequestGetStateParams();
|
||||||
|
|
||||||
|
const PrincipalInfo& storagePrincipalInfo = params.storagePrincipalInfo();
|
||||||
|
|
||||||
|
MOZ_ASSERT(
|
||||||
|
storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo ||
|
||||||
|
storagePrincipalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
|
||||||
|
mOrigin = storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo
|
||||||
|
? nsCString{QuotaManager::GetOriginForChrome()}
|
||||||
|
: QuotaManager::GetOriginFromValidatedPrincipalInfo(
|
||||||
|
storagePrincipalInfo);
|
||||||
|
|
||||||
|
mState = State::SendingResults;
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetStateOp::GetResponse(LSSimpleRequestResponse& aResponse) {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
MOZ_ASSERT(mState == State::SendingResults);
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
|
||||||
|
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
|
||||||
|
MOZ_ASSERT(MayProceed());
|
||||||
|
|
||||||
|
LSSimpleRequestGetStateResponse getStateResponse;
|
||||||
|
|
||||||
|
if (RefPtr<Datastore> datastore = GetDatastore(mOrigin)) {
|
||||||
|
if (!datastore->IsClosed()) {
|
||||||
|
getStateResponse.itemInfos() = datastore->GetOrderedItems().Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aResponse = getStateResponse;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* ArchivedOriginScope
|
* ArchivedOriginScope
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,21 @@ nsresult LSDatabase::BeginExplicitSnapshot(LSObject* aObject) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult LSDatabase::CheckpointExplicitSnapshot() {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
MOZ_ASSERT(!mAllowedToClose);
|
||||||
|
MOZ_ASSERT(mSnapshot);
|
||||||
|
MOZ_ASSERT(mSnapshot->Explicit());
|
||||||
|
|
||||||
|
nsresult rv = mSnapshot->ExplicitCheckpoint();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult LSDatabase::EndExplicitSnapshot() {
|
nsresult LSDatabase::EndExplicitSnapshot() {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
|
|
@ -307,7 +322,7 @@ nsresult LSDatabase::EndExplicitSnapshot() {
|
||||||
MOZ_ASSERT(mSnapshot);
|
MOZ_ASSERT(mSnapshot);
|
||||||
MOZ_ASSERT(mSnapshot->Explicit());
|
MOZ_ASSERT(mSnapshot->Explicit());
|
||||||
|
|
||||||
nsresult rv = mSnapshot->End();
|
nsresult rv = mSnapshot->ExplicitEnd();
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,8 @@ class LSDatabase final {
|
||||||
|
|
||||||
nsresult BeginExplicitSnapshot(LSObject* aObject);
|
nsresult BeginExplicitSnapshot(LSObject* aObject);
|
||||||
|
|
||||||
|
nsresult CheckpointExplicitSnapshot();
|
||||||
|
|
||||||
nsresult EndExplicitSnapshot();
|
nsresult EndExplicitSnapshot();
|
||||||
|
|
||||||
bool HasSnapshot() const;
|
bool HasSnapshot() const;
|
||||||
|
|
|
||||||
|
|
@ -835,6 +835,29 @@ void LSObject::BeginExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
mInExplicitSnapshot = true;
|
mInExplicitSnapshot = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LSObject::CheckpointExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
|
ErrorResult& aError) {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
if (!CanUseStorage(aSubjectPrincipal)) {
|
||||||
|
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mInExplicitSnapshot) {
|
||||||
|
aError.Throw(NS_ERROR_NOT_INITIALIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssertExplicitSnapshotInvariants(*this);
|
||||||
|
|
||||||
|
nsresult rv = mDatabase->CheckpointExplicitSnapshot();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
aError.Throw(rv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LSObject::EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
void LSObject::EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
ErrorResult& aError) {
|
ErrorResult& aError) {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,9 @@ class LSObject final : public Storage {
|
||||||
void BeginExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
void BeginExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
ErrorResult& aError) override;
|
ErrorResult& aError) override;
|
||||||
|
|
||||||
|
void CheckpointExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
|
ErrorResult& aError) override;
|
||||||
|
|
||||||
void EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
void EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
ErrorResult& aError) override;
|
ErrorResult& aError) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -567,7 +567,24 @@ void LSSnapshot::MarkDirty() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult LSSnapshot::End() {
|
nsresult LSSnapshot::ExplicitCheckpoint() {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
MOZ_ASSERT(mExplicit);
|
||||||
|
MOZ_ASSERT(!mHasPendingStableStateCallback);
|
||||||
|
MOZ_ASSERT(!mHasPendingIdleTimerCallback);
|
||||||
|
MOZ_ASSERT(mInitialized);
|
||||||
|
MOZ_ASSERT(!mSentFinish);
|
||||||
|
|
||||||
|
nsresult rv = Checkpoint(/* aSync */ true);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult LSSnapshot::ExplicitEnd() {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
MOZ_ASSERT(mExplicit);
|
MOZ_ASSERT(mExplicit);
|
||||||
|
|
@ -920,7 +937,7 @@ nsresult LSSnapshot::UpdateUsage(int64_t aDelta) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult LSSnapshot::Checkpoint() {
|
nsresult LSSnapshot::Checkpoint(bool aSync) {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
MOZ_ASSERT(mInitialized);
|
MOZ_ASSERT(mInitialized);
|
||||||
|
|
@ -930,8 +947,13 @@ nsresult LSSnapshot::Checkpoint() {
|
||||||
MOZ_ASSERT(mWriteAndNotifyInfos);
|
MOZ_ASSERT(mWriteAndNotifyInfos);
|
||||||
|
|
||||||
if (!mWriteAndNotifyInfos->IsEmpty()) {
|
if (!mWriteAndNotifyInfos->IsEmpty()) {
|
||||||
MOZ_ALWAYS_TRUE(
|
if (aSync) {
|
||||||
mActor->SendAsyncCheckpointAndNotify(*mWriteAndNotifyInfos));
|
MOZ_ALWAYS_TRUE(
|
||||||
|
mActor->SendSyncCheckpointAndNotify(*mWriteAndNotifyInfos));
|
||||||
|
} else {
|
||||||
|
MOZ_ALWAYS_TRUE(
|
||||||
|
mActor->SendAsyncCheckpointAndNotify(*mWriteAndNotifyInfos));
|
||||||
|
}
|
||||||
|
|
||||||
mWriteAndNotifyInfos->Clear();
|
mWriteAndNotifyInfos->Clear();
|
||||||
}
|
}
|
||||||
|
|
@ -944,7 +966,11 @@ nsresult LSSnapshot::Checkpoint() {
|
||||||
|
|
||||||
MOZ_ASSERT(!writeInfos.IsEmpty());
|
MOZ_ASSERT(!writeInfos.IsEmpty());
|
||||||
|
|
||||||
MOZ_ALWAYS_TRUE(mActor->SendAsyncCheckpoint(writeInfos));
|
if (aSync) {
|
||||||
|
MOZ_ALWAYS_TRUE(mActor->SendSyncCheckpoint(writeInfos));
|
||||||
|
} else {
|
||||||
|
MOZ_ALWAYS_TRUE(mActor->SendAsyncCheckpoint(writeInfos));
|
||||||
|
}
|
||||||
|
|
||||||
mWriteOptimizer->Reset();
|
mWriteOptimizer->Reset();
|
||||||
}
|
}
|
||||||
|
|
@ -1035,7 +1061,7 @@ LSSnapshot::Run() {
|
||||||
if (mDirty || mHasOtherProcessDatabases ||
|
if (mDirty || mHasOtherProcessDatabases ||
|
||||||
!Preferences::GetBool("dom.storage.snapshot_reusing")) {
|
!Preferences::GetBool("dom.storage.snapshot_reusing")) {
|
||||||
MOZ_ALWAYS_SUCCEEDS(Finish());
|
MOZ_ALWAYS_SUCCEEDS(Finish());
|
||||||
} else if (!mExplicit) {
|
} else {
|
||||||
MOZ_ASSERT(mIdleTimer);
|
MOZ_ASSERT(mIdleTimer);
|
||||||
|
|
||||||
MOZ_ALWAYS_SUCCEEDS(mIdleTimer->InitWithNamedFuncCallback(
|
MOZ_ALWAYS_SUCCEEDS(mIdleTimer->InitWithNamedFuncCallback(
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,9 @@ class LSSnapshot final : public nsIRunnable {
|
||||||
|
|
||||||
void MarkDirty();
|
void MarkDirty();
|
||||||
|
|
||||||
nsresult End();
|
nsresult ExplicitCheckpoint();
|
||||||
|
|
||||||
|
nsresult ExplicitEnd();
|
||||||
|
|
||||||
int64_t GetUsage() const;
|
int64_t GetUsage() const;
|
||||||
|
|
||||||
|
|
@ -175,7 +177,7 @@ class LSSnapshot final : public nsIRunnable {
|
||||||
|
|
||||||
nsresult UpdateUsage(int64_t aDelta);
|
nsresult UpdateUsage(int64_t aDelta);
|
||||||
|
|
||||||
nsresult Checkpoint();
|
nsresult Checkpoint(bool aSync = false);
|
||||||
|
|
||||||
nsresult Finish(bool aSync = false);
|
nsresult Finish(bool aSync = false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,8 @@ class SimpleRequestResolver final : public LSSimpleRequestChildCallback {
|
||||||
|
|
||||||
void HandleResponse(bool aResponse);
|
void HandleResponse(bool aResponse);
|
||||||
|
|
||||||
|
void HandleResponse(const nsTArray<LSItemInfo>& aResponse);
|
||||||
|
|
||||||
// LSRequestChildCallback
|
// LSRequestChildCallback
|
||||||
void OnResponse(const LSSimpleRequestResponse& aResponse) override;
|
void OnResponse(const LSSimpleRequestResponse& aResponse) override;
|
||||||
};
|
};
|
||||||
|
|
@ -385,6 +387,37 @@ LocalStorageManager2::IsPreloaded(nsIPrincipal* aPrincipal, JSContext* aContext,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
LocalStorageManager2::GetState(nsIPrincipal* aPrincipal, JSContext* aContext,
|
||||||
|
Promise** _retval) {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aPrincipal);
|
||||||
|
MOZ_ASSERT(_retval);
|
||||||
|
|
||||||
|
RefPtr<Promise> promise;
|
||||||
|
nsresult rv = CreatePromise(aContext, getter_AddRefs(promise));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSSimpleRequestGetStateParams params;
|
||||||
|
|
||||||
|
rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.storagePrincipalInfo() = params.principalInfo();
|
||||||
|
|
||||||
|
rv = StartSimpleRequest(promise, params);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
promise.forget(_retval);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
LSRequestChild* LocalStorageManager2::StartRequest(
|
LSRequestChild* LocalStorageManager2::StartRequest(
|
||||||
const LSRequestParams& aParams, LSRequestChildCallback* aCallback) {
|
const LSRequestParams& aParams, LSRequestChildCallback* aCallback) {
|
||||||
AssertIsOnDOMFileThread();
|
AssertIsOnDOMFileThread();
|
||||||
|
|
@ -565,6 +598,42 @@ void SimpleRequestResolver::HandleResponse(bool aResponse) {
|
||||||
mPromise->MaybeResolve(aResponse);
|
mPromise->MaybeResolve(aResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static bool ToJSValue(JSContext* aCx,
|
||||||
|
const nsTArray<LSItemInfo>& aArgument,
|
||||||
|
JS::MutableHandle<JS::Value> aValue) {
|
||||||
|
JS::RootedObject obj(aCx, JS_NewPlainObject(aCx));
|
||||||
|
if (!obj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < aArgument.Length(); ++i) {
|
||||||
|
const LSItemInfo& itemInfo = aArgument[i];
|
||||||
|
|
||||||
|
const nsString& key = itemInfo.key();
|
||||||
|
|
||||||
|
JS::RootedValue value(aCx);
|
||||||
|
if (!ToJSValue(aCx, itemInfo.value().AsString(), &value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!JS_DefineUCProperty(aCx, obj, key.BeginReading(), key.Length(), value,
|
||||||
|
JSPROP_ENUMERATE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aValue.setObject(*obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleRequestResolver::HandleResponse(
|
||||||
|
const nsTArray<LSItemInfo>& aResponse) {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(mPromise);
|
||||||
|
|
||||||
|
mPromise->MaybeResolve(aResponse);
|
||||||
|
}
|
||||||
|
|
||||||
void SimpleRequestResolver::OnResponse(
|
void SimpleRequestResolver::OnResponse(
|
||||||
const LSSimpleRequestResponse& aResponse) {
|
const LSSimpleRequestResponse& aResponse) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
@ -579,6 +648,11 @@ void SimpleRequestResolver::OnResponse(
|
||||||
aResponse.get_LSSimpleRequestPreloadedResponse().preloaded());
|
aResponse.get_LSSimpleRequestPreloadedResponse().preloaded());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LSSimpleRequestResponse::TLSSimpleRequestGetStateResponse:
|
||||||
|
HandleResponse(
|
||||||
|
aResponse.get_LSSimpleRequestGetStateResponse().itemInfos());
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("Unknown response type!");
|
MOZ_CRASH("Unknown response type!");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,16 @@ struct LSSimpleRequestPreloadedParams
|
||||||
PrincipalInfo storagePrincipalInfo;
|
PrincipalInfo storagePrincipalInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LSSimpleRequestGetStateParams
|
||||||
|
{
|
||||||
|
PrincipalInfo principalInfo;
|
||||||
|
PrincipalInfo storagePrincipalInfo;
|
||||||
|
};
|
||||||
|
|
||||||
union LSSimpleRequestParams
|
union LSSimpleRequestParams
|
||||||
{
|
{
|
||||||
LSSimpleRequestPreloadedParams;
|
LSSimpleRequestPreloadedParams;
|
||||||
|
LSSimpleRequestGetStateParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
include protocol PBackground;
|
include protocol PBackground;
|
||||||
|
|
||||||
|
include PBackgroundLSSharedTypes;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
|
@ -16,6 +18,11 @@ struct LSSimpleRequestPreloadedResponse
|
||||||
bool preloaded;
|
bool preloaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LSSimpleRequestGetStateResponse
|
||||||
|
{
|
||||||
|
LSItemInfo[] itemInfos;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discriminated union which can contain an error code (`nsresult`) or
|
* Discriminated union which can contain an error code (`nsresult`) or
|
||||||
* particular simple request response.
|
* particular simple request response.
|
||||||
|
|
@ -24,6 +31,7 @@ union LSSimpleRequestResponse
|
||||||
{
|
{
|
||||||
nsresult;
|
nsresult;
|
||||||
LSSimpleRequestPreloadedResponse;
|
LSSimpleRequestPreloadedResponse;
|
||||||
|
LSSimpleRequestGetStateResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,14 @@ parent:
|
||||||
|
|
||||||
async AsyncCheckpointAndNotify(LSWriteAndNotifyInfo[] writeAndNotifyInfos);
|
async AsyncCheckpointAndNotify(LSWriteAndNotifyInfo[] writeAndNotifyInfos);
|
||||||
|
|
||||||
|
// A synchronous checkpoint. This should only be used by the snapshotting code
|
||||||
|
// to checkpoint an explicit snapshot.
|
||||||
|
sync SyncCheckpoint(LSWriteInfo[] writeInfos);
|
||||||
|
|
||||||
|
// A synchronous checkpoint and notify. This should only be used by the
|
||||||
|
// snapshotting code to checkpoint and notify an explicit snapshot.
|
||||||
|
sync SyncCheckpointAndNotify(LSWriteAndNotifyInfo[] writeAndNotifyInfos);
|
||||||
|
|
||||||
async AsyncFinish();
|
async AsyncFinish();
|
||||||
|
|
||||||
// A synchronous finish. This should only be used by the snapshotting code to
|
// A synchronous finish. This should only be used by the snapshotting code to
|
||||||
|
|
|
||||||
|
|
@ -32,4 +32,7 @@ interface nsILocalStorageManager : nsISupports
|
||||||
|
|
||||||
[implicit_jscontext]
|
[implicit_jscontext]
|
||||||
Promise isPreloaded(in nsIPrincipal aPrincipal);
|
Promise isPreloaded(in nsIPrincipal aPrincipal);
|
||||||
|
|
||||||
|
[implicit_jscontext]
|
||||||
|
Promise getState(in nsIPrincipal aPrincipal);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -318,6 +318,16 @@ LocalStorageManager::IsPreloaded(nsIPrincipal* aPrincipal, JSContext* aContext,
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
LocalStorageManager::GetState(nsIPrincipal* aPrincipal, JSContext* aContext,
|
||||||
|
Promise** _retval) {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aPrincipal);
|
||||||
|
MOZ_ASSERT(_retval);
|
||||||
|
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
void LocalStorageManager::ClearCaches(uint32_t aUnloadFlags,
|
void LocalStorageManager::ClearCaches(uint32_t aUnloadFlags,
|
||||||
const OriginAttributesPattern& aPattern,
|
const OriginAttributesPattern& aPattern,
|
||||||
const nsACString& aOriginScope) {
|
const nsACString& aOriginScope) {
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,9 @@ class Storage : public nsISupports, public nsWrapperCache {
|
||||||
virtual void BeginExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
virtual void BeginExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
ErrorResult& aRv) {}
|
ErrorResult& aRv) {}
|
||||||
|
|
||||||
|
virtual void CheckpointExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
|
ErrorResult& aRv) {}
|
||||||
|
|
||||||
virtual void EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
virtual void EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
|
||||||
ErrorResult& aRv) {}
|
ErrorResult& aRv) {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,12 @@ async function beginExplicitSnapshot(knownTab) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function checkpointExplicitSnapshot(knownTab) {
|
||||||
|
await SpecialPowers.spawn(knownTab.tab.linkedBrowser, [], function() {
|
||||||
|
return content.wrappedJSObject.checkpointExplicitSnapshot();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function endExplicitSnapshot(knownTab) {
|
async function endExplicitSnapshot(knownTab) {
|
||||||
await SpecialPowers.spawn(knownTab.tab.linkedBrowser, [], function() {
|
await SpecialPowers.spawn(knownTab.tab.linkedBrowser, [], function() {
|
||||||
return content.wrappedJSObject.endExplicitSnapshot();
|
return content.wrappedJSObject.endExplicitSnapshot();
|
||||||
|
|
@ -99,6 +105,24 @@ async function verifySnapshotUsage(knownTab, expectedSnapshotUsage) {
|
||||||
is(snapshotUsage, expectedSnapshotUsage, "Correct snapshot usage");
|
is(snapshotUsage, expectedSnapshotUsage, "Correct snapshot usage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function verifyParentState(expectedState) {
|
||||||
|
let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
|
||||||
|
HELPER_PAGE_ORIGIN
|
||||||
|
);
|
||||||
|
|
||||||
|
let actualState = await Services.domStorageManager.getState(principal);
|
||||||
|
|
||||||
|
for (let [expectedKey, expectedValue] of Object.entries(expectedState)) {
|
||||||
|
ok(actualState.hasOwnProperty(expectedKey), "key present: " + expectedKey);
|
||||||
|
is(actualState[expectedKey], expectedValue, "value correct");
|
||||||
|
}
|
||||||
|
for (let actualKey of Object.keys(actualState)) {
|
||||||
|
if (!expectedState.hasOwnProperty(actualKey)) {
|
||||||
|
ok(false, "actual state has key it shouldn't have: " + actualKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We spin up a ton of child processes.
|
// We spin up a ton of child processes.
|
||||||
requestLongerTimeout(4);
|
requestLongerTimeout(4);
|
||||||
|
|
||||||
|
|
@ -648,3 +672,84 @@ add_task(async function() {
|
||||||
|
|
||||||
clearOriginStorageEnsuringNoPreload(HELPER_PAGE_ORIGIN);
|
clearOriginStorageEnsuringNoPreload(HELPER_PAGE_ORIGIN);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that datastore in the parent is correctly updated after a checkpoint.
|
||||||
|
*/
|
||||||
|
add_task(async function() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
// Force multiple web and webIsolated content processes so that the
|
||||||
|
// multi-e10s logic works correctly.
|
||||||
|
["dom.ipc.processCount", 4],
|
||||||
|
["dom.ipc.processCount.webIsolated", 2],
|
||||||
|
// Enable LocalStorage's testing API so we can explicitly create
|
||||||
|
// snapshots when needed.
|
||||||
|
["dom.storage.testing", true],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure that there is no localstorage data by forcing the origin to be
|
||||||
|
// cleared prior to the start of our test.
|
||||||
|
await clearOriginStorageEnsuringNoPreload(HELPER_PAGE_ORIGIN);
|
||||||
|
|
||||||
|
// Open tabs. Don't configure any of them yet.
|
||||||
|
const knownTabs = new KnownTabs();
|
||||||
|
const writerTab1 = await openTestTab(
|
||||||
|
HELPER_PAGE_URL,
|
||||||
|
"writer1",
|
||||||
|
knownTabs,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
await verifyParentState({});
|
||||||
|
|
||||||
|
// Apply the initial mutation using an explicit snapshot. The explicit
|
||||||
|
// snapshot here ensures that the parent process have received the changes.
|
||||||
|
await beginExplicitSnapshot(writerTab1);
|
||||||
|
await verifyParentState({});
|
||||||
|
await applyMutations(writerTab1, [["key", "something"]]);
|
||||||
|
await verifyParentState({});
|
||||||
|
await endExplicitSnapshot(writerTab1);
|
||||||
|
|
||||||
|
await verifyParentState({ key: "something" });
|
||||||
|
|
||||||
|
// Begin an explicit snapshot in writerTab1, apply the first mutation in
|
||||||
|
// writerTab1 and checkpoint the explicit snapshot.
|
||||||
|
await beginExplicitSnapshot(writerTab1);
|
||||||
|
await verifyParentState({ key: "something" });
|
||||||
|
await applyMutations(writerTab1, [["key", "somethingBigger"]]);
|
||||||
|
await verifyParentState({ key: "something" });
|
||||||
|
await checkpointExplicitSnapshot(writerTab1);
|
||||||
|
|
||||||
|
await verifyParentState({ key: "somethingBigger" });
|
||||||
|
|
||||||
|
// Apply the second mutation in writerTab1 and checkpoint the explicit
|
||||||
|
// snapshot.
|
||||||
|
await applyMutations(writerTab1, [["key", null]]);
|
||||||
|
await verifyParentState({ key: "somethingBigger" });
|
||||||
|
await checkpointExplicitSnapshot(writerTab1);
|
||||||
|
|
||||||
|
await verifyParentState({});
|
||||||
|
|
||||||
|
// Apply the third mutation in writerTab1 and end the explicit snapshot.
|
||||||
|
await applyMutations(writerTab1, [["otherKey", "something"]]);
|
||||||
|
await verifyParentState({});
|
||||||
|
await endExplicitSnapshot(writerTab1);
|
||||||
|
|
||||||
|
await verifyParentState({ otherKey: "something" });
|
||||||
|
|
||||||
|
// Verify the final state, it should match the state after the third mutation
|
||||||
|
// has been applied and "commited". An explicit snapshot is used.
|
||||||
|
await beginExplicitSnapshot(writerTab1);
|
||||||
|
await verifyParentState({ otherKey: "something" });
|
||||||
|
await verifyState(writerTab1, { otherKey: "something" });
|
||||||
|
await endExplicitSnapshot(writerTab1);
|
||||||
|
|
||||||
|
await verifyParentState({ otherKey: "something" });
|
||||||
|
|
||||||
|
// Clean up.
|
||||||
|
await cleanupTabs(knownTabs);
|
||||||
|
|
||||||
|
clearOriginStorageEnsuringNoPreload(HELPER_PAGE_ORIGIN);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@ function beginExplicitSnapshot() {
|
||||||
localStorage.beginExplicitSnapshot();
|
localStorage.beginExplicitSnapshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkpointExplicitSnapshot() {
|
||||||
|
localStorage.checkpointExplicitSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
function endExplicitSnapshot() {
|
function endExplicitSnapshot() {
|
||||||
localStorage.endExplicitSnapshot();
|
localStorage.endExplicitSnapshot();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,15 @@ partial interface Storage {
|
||||||
[Throws, NeedsSubjectPrincipal, Pref="dom.storage.testing"]
|
[Throws, NeedsSubjectPrincipal, Pref="dom.storage.testing"]
|
||||||
void beginExplicitSnapshot();
|
void beginExplicitSnapshot();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checkpoints the explicitly begun snapshot. This is only useful for testing
|
||||||
|
* of snapshot re-using when multiple checkpoints are involved. There's no
|
||||||
|
* need to call this before `endExplicitSnapshot` because it checkpoints the
|
||||||
|
* snapshot before it's ended.
|
||||||
|
*/
|
||||||
|
[Throws, NeedsSubjectPrincipal, Pref="dom.storage.testing"]
|
||||||
|
void checkpointExplicitSnapshot();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ends the explicitly begun snapshot and retains the underlying database.
|
* Ends the explicitly begun snapshot and retains the underlying database.
|
||||||
* Compare with `close` which also drops the reference to the database.
|
* Compare with `close` which also drops the reference to the database.
|
||||||
|
|
|
||||||
|
|
@ -854,6 +854,10 @@ description = legacy sync IPC - please add detailed description
|
||||||
description = legacy sync IPC - please add detailed description
|
description = legacy sync IPC - please add detailed description
|
||||||
[PBackgroundLSDatabase::PBackgroundLSSnapshot]
|
[PBackgroundLSDatabase::PBackgroundLSSnapshot]
|
||||||
description = See corresponding comment in PBackgroundLSDatabase.ipdl
|
description = See corresponding comment in PBackgroundLSDatabase.ipdl
|
||||||
|
[PBackgroundLSSnapshot::SyncCheckpoint]
|
||||||
|
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
|
||||||
|
[PBackgroundLSSnapshot::SyncCheckpointAndNotify]
|
||||||
|
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
|
||||||
[PBackgroundLSSnapshot::SyncFinish]
|
[PBackgroundLSSnapshot::SyncFinish]
|
||||||
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
|
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
|
||||||
[PBackgroundLSSnapshot::LoadValueAndMoreItems]
|
[PBackgroundLSSnapshot::LoadValueAndMoreItems]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue