mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1286798 - Part 42: Implement snapshot reusing; r=asuth
This improves performance by keeping snapshots around for some time if there are no changes done by other processes. If a snapshot is not destroyed immediately after getting into the stable state then there's a chance that it won't have to be synchronously created again when a new opeartion is requested.
This commit is contained in:
parent
150cf2ce62
commit
3177670987
@ -60,6 +60,9 @@ add_task(async function testLocalStorage() {
|
||||
await browser.browsingData.remove({}, {localStorage: true});
|
||||
await sendMessageToTabs(tabs, "checkLocalStorageCleared");
|
||||
|
||||
// Cleanup (checkLocalStorageCleared creates empty LS databases).
|
||||
await browser.browsingData.removeLocalStorage({});
|
||||
|
||||
browser.tabs.remove(tabs.map(tab => tab.id));
|
||||
|
||||
browser.test.notifyPass("done");
|
||||
|
@ -318,5 +318,19 @@ LSSnapshotChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
LSSnapshotChild::RecvMarkDirty()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!mSnapshot) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mSnapshot->MarkDirty();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -246,6 +246,9 @@ private:
|
||||
// IPDL methods are only called by IPDL.
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvMarkDirty() override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -1550,7 +1550,7 @@ public:
|
||||
void
|
||||
BeginUpdateBatch(int64_t aSnapshotInitialUsage);
|
||||
|
||||
void
|
||||
int64_t
|
||||
EndUpdateBatch(int64_t aSnapshotPeakUsage);
|
||||
|
||||
int64_t
|
||||
@ -1581,6 +1581,9 @@ private:
|
||||
const nsAString& aOldValue,
|
||||
bool aAffectsOrder);
|
||||
|
||||
void
|
||||
MarkSnapshotsDirty();
|
||||
|
||||
void
|
||||
NotifyObservers(Database* aDatabase,
|
||||
const nsString& aDocumentURI,
|
||||
@ -1824,7 +1827,7 @@ class Snapshot final
|
||||
nsTArray<nsString> mKeys;
|
||||
nsString mDocumentURI;
|
||||
uint32_t mTotalLength;
|
||||
int64_t mInitialUsage;
|
||||
int64_t mUsage;
|
||||
int64_t mPeakUsage;
|
||||
bool mSavedKeys;
|
||||
bool mActorDestroyed;
|
||||
@ -1832,6 +1835,7 @@ class Snapshot final
|
||||
bool mLoadedReceived;
|
||||
bool mLoadedAllItems;
|
||||
bool mLoadKeysReceived;
|
||||
bool mSentMarkDirty;
|
||||
|
||||
public:
|
||||
// Created in AllocPBackgroundLSSnapshotParent.
|
||||
@ -1851,12 +1855,12 @@ public:
|
||||
MOZ_ASSERT_IF(aLoadState == LSSnapshot::LoadState::AllOrderedItems,
|
||||
aLoadedItems.Count() == 0);
|
||||
MOZ_ASSERT(mTotalLength == 0);
|
||||
MOZ_ASSERT(mInitialUsage == -1);
|
||||
MOZ_ASSERT(mUsage == -1);
|
||||
MOZ_ASSERT(mPeakUsage == -1);
|
||||
|
||||
mLoadedItems.SwapElements(aLoadedItems);
|
||||
mTotalLength = aTotalLength;
|
||||
mInitialUsage = aInitialUsage;
|
||||
mUsage = aInitialUsage;
|
||||
mPeakUsage = aPeakUsage;
|
||||
if (aLoadState == LSSnapshot::LoadState::AllOrderedKeys) {
|
||||
mLoadKeysReceived = true;
|
||||
@ -1872,12 +1876,18 @@ public:
|
||||
const nsAString& aOldValue,
|
||||
bool aAffectsOrder);
|
||||
|
||||
void
|
||||
MarkDirty();
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Snapshot)
|
||||
|
||||
private:
|
||||
// Reference counted.
|
||||
~Snapshot();
|
||||
|
||||
void
|
||||
Finish();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
@ -1886,7 +1896,10 @@ private:
|
||||
RecvDeleteMe() override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvFinish(const LSSnapshotFinishInfo& aFinishInfo) override;
|
||||
RecvCheckpoint(nsTArray<LSWriteInfo>&& aWriteInfos) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvFinish() override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvLoaded() override;
|
||||
@ -4272,15 +4285,18 @@ Datastore::PrivateBrowsingClear()
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mPrivateBrowsingId);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(!mInUpdateBatch);
|
||||
|
||||
if (mValues.Count()) {
|
||||
DebugOnly<bool> ok = UpdateUsage(-mUsage);
|
||||
MOZ_ASSERT(ok);
|
||||
MarkSnapshotsDirty();
|
||||
|
||||
mValues.Clear();
|
||||
|
||||
mOrderedItems.Clear();
|
||||
|
||||
DebugOnly<bool> ok = UpdateUsage(-mSizeOfItems);
|
||||
MOZ_ASSERT(ok);
|
||||
|
||||
mSizeOfKeys = 0;
|
||||
mSizeOfItems = 0;
|
||||
}
|
||||
@ -4306,33 +4322,35 @@ Datastore::BeginUpdateBatch(int64_t aSnapshotInitialUsage)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
int64_t
|
||||
Datastore::EndUpdateBatch(int64_t aSnapshotPeakUsage)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aSnapshotPeakUsage >= 0);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(mInUpdateBatch);
|
||||
|
||||
mWriteOptimizer.ApplyWrites(mOrderedItems);
|
||||
|
||||
int64_t delta = mUpdateBatchUsage - aSnapshotPeakUsage;
|
||||
if (aSnapshotPeakUsage >= 0) {
|
||||
int64_t delta = mUpdateBatchUsage - aSnapshotPeakUsage;
|
||||
|
||||
if (mActiveDatabases.Count()) {
|
||||
// We can't apply deltas while other databases are still active.
|
||||
// The final delta must be zero or negative, but individual deltas can be
|
||||
// positive. A positive delta can't be applied asynchronously since there's
|
||||
// no way to fire the quota exceeded error event.
|
||||
if (mActiveDatabases.Count()) {
|
||||
// We can't apply deltas while other databases are still active.
|
||||
// The final delta must be zero or negative, but individual deltas can
|
||||
// be positive. A positive delta can't be applied asynchronously since
|
||||
// there's no way to fire the quota exceeded error event.
|
||||
|
||||
mPendingUsageDeltas.AppendElement(delta);
|
||||
} else {
|
||||
MOZ_ASSERT(delta <= 0);
|
||||
if (delta != 0) {
|
||||
DebugOnly<bool> ok = UpdateUsage(delta);
|
||||
MOZ_ASSERT(ok);
|
||||
mPendingUsageDeltas.AppendElement(delta);
|
||||
} else {
|
||||
MOZ_ASSERT(delta <= 0);
|
||||
if (delta != 0) {
|
||||
DebugOnly<bool> ok = UpdateUsage(delta);
|
||||
MOZ_ASSERT(ok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t result = mUpdateBatchUsage;
|
||||
mUpdateBatchUsage = -1;
|
||||
|
||||
if (IsPersistent()) {
|
||||
@ -4342,6 +4360,8 @@ Datastore::EndUpdateBatch(int64_t aSnapshotPeakUsage)
|
||||
#ifdef DEBUG
|
||||
mInUpdateBatch = false;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t
|
||||
@ -4480,6 +4500,21 @@ Datastore::NotifySnapshots(Database* aDatabase,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Datastore::MarkSnapshotsDirty()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
for (auto iter = mDatabases.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
Database* database = iter.Get()->GetKey();
|
||||
|
||||
Snapshot* snapshot = database->GetSnapshot();
|
||||
if (snapshot) {
|
||||
snapshot->MarkDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Datastore::NotifyObservers(Database* aDatabase,
|
||||
const nsString& aDocumentURI,
|
||||
@ -4799,7 +4834,7 @@ Snapshot::Snapshot(Database* aDatabase,
|
||||
, mDatastore(aDatabase->GetDatastore())
|
||||
, mDocumentURI(aDocumentURI)
|
||||
, mTotalLength(0)
|
||||
, mInitialUsage(-1)
|
||||
, mUsage(-1)
|
||||
, mPeakUsage(-1)
|
||||
, mSavedKeys(false)
|
||||
, mActorDestroyed(false)
|
||||
@ -4807,6 +4842,7 @@ Snapshot::Snapshot(Database* aDatabase,
|
||||
, mLoadedReceived(false)
|
||||
, mLoadedAllItems(false)
|
||||
, mLoadKeysReceived(false)
|
||||
, mSentMarkDirty(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aDatabase);
|
||||
@ -4825,6 +4861,8 @@ Snapshot::SaveItem(const nsAString& aKey,
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
MarkDirty();
|
||||
|
||||
if (mLoadedAllItems) {
|
||||
return;
|
||||
}
|
||||
@ -4842,6 +4880,34 @@ Snapshot::SaveItem(const nsAString& aKey,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Snapshot::MarkDirty()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (!mSentMarkDirty) {
|
||||
Unused << SendMarkDirty();
|
||||
mSentMarkDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Snapshot::Finish()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mDatabase);
|
||||
MOZ_ASSERT(mDatastore);
|
||||
MOZ_ASSERT(!mFinishReceived);
|
||||
|
||||
mDatastore->BeginUpdateBatch(mUsage);
|
||||
|
||||
mDatastore->EndUpdateBatch(mPeakUsage);
|
||||
|
||||
mDatabase->UnregisterSnapshot(this);
|
||||
|
||||
mFinishReceived = true;
|
||||
}
|
||||
|
||||
void
|
||||
Snapshot::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
@ -4851,11 +4917,7 @@ Snapshot::ActorDestroy(ActorDestroyReason aWhy)
|
||||
mActorDestroyed = true;
|
||||
|
||||
if (!mFinishReceived) {
|
||||
mDatabase->UnregisterSnapshot(this);
|
||||
|
||||
mDatastore->BeginUpdateBatch(mInitialUsage);
|
||||
|
||||
mDatastore->EndUpdateBatch(mPeakUsage);
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4873,26 +4935,21 @@ Snapshot::RecvDeleteMe()
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
Snapshot::RecvFinish(const LSSnapshotFinishInfo& aFinishInfo)
|
||||
Snapshot::RecvCheckpoint(nsTArray<LSWriteInfo>&& aWriteInfos)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mInitialUsage >= 0);
|
||||
MOZ_ASSERT(mPeakUsage >= mInitialUsage);
|
||||
MOZ_ASSERT(mUsage >= 0);
|
||||
MOZ_ASSERT(mPeakUsage >= mUsage);
|
||||
|
||||
if (NS_WARN_IF(mFinishReceived)) {
|
||||
if (NS_WARN_IF(aWriteInfos.IsEmpty())) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
mFinishReceived = true;
|
||||
mDatastore->BeginUpdateBatch(mUsage);
|
||||
|
||||
mDatabase->UnregisterSnapshot(this);
|
||||
|
||||
mDatastore->BeginUpdateBatch(mInitialUsage);
|
||||
|
||||
const nsTArray<LSWriteInfo>& writeInfos = aFinishInfo.writeInfos();
|
||||
for (uint32_t index = 0; index < writeInfos.Length(); index++) {
|
||||
const LSWriteInfo& writeInfo = writeInfos[index];
|
||||
for (uint32_t index = 0; index < aWriteInfos.Length(); index++) {
|
||||
const LSWriteInfo& writeInfo = aWriteInfos[index];
|
||||
switch (writeInfo.type()) {
|
||||
case LSWriteInfo::TLSSetItemInfo: {
|
||||
const LSSetItemInfo& info = writeInfo.get_LSSetItemInfo();
|
||||
@ -4928,7 +4985,22 @@ Snapshot::RecvFinish(const LSSnapshotFinishInfo& aFinishInfo)
|
||||
}
|
||||
}
|
||||
|
||||
mDatastore->EndUpdateBatch(mPeakUsage);
|
||||
mUsage = mDatastore->EndUpdateBatch(-1);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
Snapshot::RecvFinish()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (NS_WARN_IF(mFinishReceived)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
Finish();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -74,7 +74,9 @@ LSDatabase::RequestAllowToClose()
|
||||
|
||||
mRequestedAllowToClose = true;
|
||||
|
||||
if (!mSnapshot) {
|
||||
if (mSnapshot) {
|
||||
mSnapshot->MarkDirty();
|
||||
} else {
|
||||
AllowToClose();
|
||||
}
|
||||
}
|
||||
@ -285,7 +287,7 @@ LSDatabase::EndExplicitSnapshot(LSObject* aObject)
|
||||
|
||||
MOZ_ASSERT(mSnapshot->Explicit());
|
||||
|
||||
nsresult rv = mSnapshot->Finish();
|
||||
nsresult rv = mSnapshot->End();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -11,6 +11,12 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kSnapshotTimeoutMs = 20000;
|
||||
|
||||
} // namespace
|
||||
|
||||
LSSnapshot::LSSnapshot(LSDatabase* aDatabase)
|
||||
: mDatabase(aDatabase)
|
||||
, mActor(nullptr)
|
||||
@ -20,6 +26,9 @@ LSSnapshot::LSSnapshot(LSDatabase* aDatabase)
|
||||
, mPeakUsage(0)
|
||||
, mLoadState(LoadState::Initial)
|
||||
, mExplicit(false)
|
||||
, mHasPendingStableStateCallback(false)
|
||||
, mHasPendingTimerCallback(false)
|
||||
, mDirty(false)
|
||||
#ifdef DEBUG
|
||||
, mInitialized(false)
|
||||
, mSentFinish(false)
|
||||
@ -32,6 +41,8 @@ LSSnapshot::~LSSnapshot()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mDatabase);
|
||||
MOZ_ASSERT(!mHasPendingStableStateCallback);
|
||||
MOZ_ASSERT(!mHasPendingTimerCallback);
|
||||
MOZ_ASSERT_IF(mInitialized, mSentFinish);
|
||||
|
||||
if (mActor) {
|
||||
@ -55,17 +66,13 @@ LSSnapshot::Init(const LSSnapshotInitInfo& aInitInfo,
|
||||
bool aExplicit)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mSelfRef);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(mLoadState == LoadState::Initial);
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
if (aExplicit) {
|
||||
mSelfRef = this;
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> runnable = this;
|
||||
nsContentUtils::RunInStableState(runnable.forget());
|
||||
}
|
||||
mSelfRef = this;
|
||||
|
||||
LoadState loadState = aInitInfo.loadState();
|
||||
|
||||
@ -102,6 +109,13 @@ LSSnapshot::Init(const LSSnapshotInitInfo& aInitInfo,
|
||||
mInitialized = true;
|
||||
#endif
|
||||
|
||||
if (!mExplicit) {
|
||||
mTimer = NS_NewTimer();
|
||||
MOZ_ASSERT(mTimer);
|
||||
|
||||
ScheduleStableStateCallback();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -113,6 +127,8 @@ LSSnapshot::GetLength(uint32_t* aResult)
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
if (mLoadState == LoadState::Partial) {
|
||||
*aResult = mLength;
|
||||
} else {
|
||||
@ -131,6 +147,8 @@ LSSnapshot::GetKey(uint32_t aIndex,
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
nsresult rv = EnsureAllKeys();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@ -157,6 +175,8 @@ LSSnapshot::GetItem(const nsAString& aKey,
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
nsString result;
|
||||
nsresult rv = GetItemInternal(aKey, Optional<nsString>(), result);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -175,6 +195,8 @@ LSSnapshot::GetKeys(nsTArray<nsString>& aKeys)
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
nsresult rv = EnsureAllKeys();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@ -197,6 +219,8 @@ LSSnapshot::SetItem(const nsAString& aKey,
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
nsString oldValue;
|
||||
nsresult rv =
|
||||
GetItemInternal(aKey, Optional<nsString>(nsString(aValue)), oldValue);
|
||||
@ -254,6 +278,8 @@ LSSnapshot::RemoveItem(const nsAString& aKey,
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
nsString oldValue;
|
||||
nsresult rv =
|
||||
GetItemInternal(aKey, Optional<nsString>(VoidString()), oldValue);
|
||||
@ -298,6 +324,8 @@ LSSnapshot::Clear(LSNotifyInfo& aNotifyInfo)
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
uint32_t length;
|
||||
if (mLoadState == LoadState::Partial) {
|
||||
length = mLength;
|
||||
@ -334,38 +362,89 @@ LSSnapshot::Clear(LSNotifyInfo& aNotifyInfo)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LSSnapshot::Finish()
|
||||
void
|
||||
LSSnapshot::MarkDirty()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mDatabase);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MOZ_ALWAYS_TRUE(mActor->SendFinish(mWriteInfos));
|
||||
|
||||
#ifdef DEBUG
|
||||
mSentFinish = true;
|
||||
#endif
|
||||
|
||||
if (mExplicit) {
|
||||
if (NS_WARN_IF(!mActor->SendPing())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDatabase->NoteFinishedSnapshot(this);
|
||||
mDirty = true;
|
||||
|
||||
if (mExplicit) {
|
||||
mSelfRef = nullptr;
|
||||
if (!mExplicit && !mHasPendingStableStateCallback) {
|
||||
CancelTimer();
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(Checkpoint());
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(Finish());
|
||||
} else {
|
||||
MOZ_ASSERT(!mSelfRef);
|
||||
MOZ_ASSERT(!mHasPendingTimerCallback);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
LSSnapshot::End()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(mExplicit);
|
||||
MOZ_ASSERT(!mHasPendingStableStateCallback);
|
||||
MOZ_ASSERT(!mHasPendingTimerCallback);
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
nsresult rv = Checkpoint();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<LSSnapshot> kungFuDeathGrip = this;
|
||||
|
||||
rv = Finish();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mActor->SendPing())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LSSnapshot::ScheduleStableStateCallback()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mTimer);
|
||||
MOZ_ASSERT(!mExplicit);
|
||||
MOZ_ASSERT(!mHasPendingStableStateCallback);
|
||||
|
||||
CancelTimer();
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = this;
|
||||
nsContentUtils::RunInStableState(runnable.forget());
|
||||
|
||||
mHasPendingStableStateCallback = true;
|
||||
}
|
||||
|
||||
void
|
||||
LSSnapshot::MaybeScheduleStableStateCallback()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!mExplicit && !mHasPendingStableStateCallback) {
|
||||
ScheduleStableStateCallback();
|
||||
} else {
|
||||
MOZ_ASSERT(!mHasPendingTimerCallback);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
LSSnapshot::GetItemInternal(const nsAString& aKey,
|
||||
const Optional<nsString>& aValue,
|
||||
@ -599,6 +678,77 @@ LSSnapshot::UpdateUsage(int64_t aDelta)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LSSnapshot::Checkpoint()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
if (!mWriteInfos.IsEmpty()) {
|
||||
MOZ_ALWAYS_TRUE(mActor->SendCheckpoint(mWriteInfos));
|
||||
|
||||
mWriteInfos.Clear();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LSSnapshot::Finish()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mDatabase);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(!mSentFinish);
|
||||
|
||||
MOZ_ALWAYS_TRUE(mActor->SendFinish());
|
||||
|
||||
mDatabase->NoteFinishedSnapshot(this);
|
||||
|
||||
#ifdef DEBUG
|
||||
mSentFinish = true;
|
||||
#endif
|
||||
|
||||
// Clear the self reference added in Init method.
|
||||
MOZ_ASSERT(mSelfRef);
|
||||
mSelfRef = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LSSnapshot::CancelTimer()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mTimer);
|
||||
|
||||
if (mHasPendingTimerCallback) {
|
||||
MOZ_ALWAYS_SUCCEEDS(mTimer->Cancel());
|
||||
mHasPendingTimerCallback = false;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
LSSnapshot::TimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aTimer);
|
||||
|
||||
auto* self = static_cast<LSSnapshot*>(aClosure);
|
||||
MOZ_ASSERT(self);
|
||||
MOZ_ASSERT(self->mTimer);
|
||||
MOZ_ASSERT(SameCOMIdentity(self->mTimer, aTimer));
|
||||
MOZ_ASSERT(!self->mHasPendingStableStateCallback);
|
||||
MOZ_ASSERT(self->mHasPendingTimerCallback);
|
||||
|
||||
self->mHasPendingTimerCallback = false;
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(self->Finish());
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(LSSnapshot, nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -606,8 +756,27 @@ LSSnapshot::Run()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mExplicit);
|
||||
MOZ_ASSERT(mHasPendingStableStateCallback);
|
||||
MOZ_ASSERT(!mHasPendingTimerCallback);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(Finish());
|
||||
mHasPendingStableStateCallback = false;
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(Checkpoint());
|
||||
|
||||
if (mDirty || !Preferences::GetBool("dom.storage.snapshot_reusing")) {
|
||||
MOZ_ALWAYS_SUCCEEDS(Finish());
|
||||
} else if (!mExplicit) {
|
||||
MOZ_ASSERT(mTimer);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mTimer->InitWithNamedFuncCallback(TimerCallback,
|
||||
this,
|
||||
kSnapshotTimeoutMs,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"LSSnapshot::TimerCallback"));
|
||||
|
||||
mHasPendingTimerCallback = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ private:
|
||||
|
||||
RefPtr<LSDatabase> mDatabase;
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
LSSnapshotChild* mActor;
|
||||
|
||||
nsTHashtable<nsStringHashKey> mLoadedItems;
|
||||
@ -50,6 +52,9 @@ private:
|
||||
LoadState mLoadState;
|
||||
|
||||
bool mExplicit;
|
||||
bool mHasPendingStableStateCallback;
|
||||
bool mHasPendingTimerCallback;
|
||||
bool mDirty;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mInitialized;
|
||||
@ -113,12 +118,21 @@ public:
|
||||
nsresult
|
||||
Clear(LSNotifyInfo& aNotifyInfo);
|
||||
|
||||
void
|
||||
MarkDirty();
|
||||
|
||||
nsresult
|
||||
Finish();
|
||||
End();
|
||||
|
||||
private:
|
||||
~LSSnapshot();
|
||||
|
||||
void
|
||||
ScheduleStableStateCallback();
|
||||
|
||||
void
|
||||
MaybeScheduleStableStateCallback();
|
||||
|
||||
nsresult
|
||||
GetItemInternal(const nsAString& aKey,
|
||||
const Optional<nsString>& aValue,
|
||||
@ -130,6 +144,18 @@ private:
|
||||
nsresult
|
||||
UpdateUsage(int64_t aDelta);
|
||||
|
||||
nsresult
|
||||
Checkpoint();
|
||||
|
||||
nsresult
|
||||
Finish();
|
||||
|
||||
void
|
||||
CancelTimer();
|
||||
|
||||
static void
|
||||
TimerCallback(nsITimer* aTimer, void* aClosure);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
@ -32,11 +32,6 @@ union LSWriteInfo
|
||||
LSClearInfo;
|
||||
};
|
||||
|
||||
struct LSSnapshotFinishInfo
|
||||
{
|
||||
LSWriteInfo[] writeInfos;
|
||||
};
|
||||
|
||||
sync protocol PBackgroundLSSnapshot
|
||||
{
|
||||
manager PBackgroundLSDatabase;
|
||||
@ -44,7 +39,9 @@ sync protocol PBackgroundLSSnapshot
|
||||
parent:
|
||||
async DeleteMe();
|
||||
|
||||
async Finish(LSSnapshotFinishInfo finishInfo);
|
||||
async Checkpoint(LSWriteInfo[] writeInfos);
|
||||
|
||||
async Finish();
|
||||
|
||||
async Loaded();
|
||||
|
||||
@ -63,6 +60,8 @@ parent:
|
||||
sync Ping();
|
||||
|
||||
child:
|
||||
async MarkDirty();
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
|
@ -19,9 +19,10 @@ function* testSteps()
|
||||
return "http://example" + index + ".com";
|
||||
}
|
||||
|
||||
info("Setting pref");
|
||||
info("Setting prefs");
|
||||
|
||||
Services.prefs.setBoolPref("dom.storage.next_gen", true);
|
||||
Services.prefs.setBoolPref("dom.storage.snapshot_reusing", false);
|
||||
|
||||
info("Setting limits");
|
||||
|
||||
|
@ -26,6 +26,10 @@ function* testSteps()
|
||||
data.value = repeatChar(data.sizeKB * 1024 - data.key.length, ".");
|
||||
data.urlCount = groupLimitKB / data.sizeKB;
|
||||
|
||||
info("Setting pref");
|
||||
|
||||
Services.prefs.setBoolPref("dom.storage.snapshot_reusing", false);
|
||||
|
||||
info("Setting limits");
|
||||
|
||||
setGlobalLimit(globalLimitKB);
|
||||
|
@ -38,6 +38,10 @@ function* testSteps()
|
||||
-1, // full prefill
|
||||
];
|
||||
|
||||
info("Setting pref");
|
||||
|
||||
Services.prefs.setBoolPref("dom.storage.snapshot_reusing", false);
|
||||
|
||||
for (let prefillValue of prefillValues) {
|
||||
info("Setting prefill value");
|
||||
|
||||
|
@ -1293,6 +1293,7 @@ pref("dom.storage.next_gen", false);
|
||||
#endif
|
||||
pref("dom.storage.default_quota", 5120);
|
||||
pref("dom.storage.snapshot_prefill", 16384);
|
||||
pref("dom.storage.snapshot_reusing", true);
|
||||
pref("dom.storage.testing", false);
|
||||
|
||||
pref("dom.send_after_paint_to_content", false);
|
||||
|
Loading…
Reference in New Issue
Block a user