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:
Jan Varga 2018-11-29 21:49:31 +01:00
parent 150cf2ce62
commit 3177670987
12 changed files with 372 additions and 74 deletions

View File

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

View File

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

View File

@ -246,6 +246,9 @@ private:
// IPDL methods are only called by IPDL.
void
ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult
RecvMarkDirty() override;
};
} // namespace dom

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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