Part 9: Bug 1700623 - Notify main thread about storage updates periodically. r=asuth

This is used to update session store storage contents continuously.

Depends on D111435

Differential Revision: https://phabricator.services.mozilla.com/D114586
This commit is contained in:
Andreas Farre 2021-05-26 07:14:07 +00:00
parent 046cb66bae
commit 3dd66dc912
7 changed files with 138 additions and 12 deletions

View File

@ -299,6 +299,8 @@ class CanonicalBrowsingContext final : public BrowsingContext {
void UpdateSessionStoreSessionStorage(const std::function<void()>& aDone);
static void UpdateSessionStoreForStorage(uint64_t aBrowsingContextId);
// Called when a BrowserParent for this BrowsingContext has been fully
// destroyed (i.e. `ActorDestroy` was called).
void BrowserParentDestroyed(BrowserParent* aBrowserParent,

View File

@ -53,6 +53,8 @@ void RecvPropagateBackgroundSessionStorageManager(
if (sManagers) {
if (RefPtr<BackgroundSessionStorageManager> mgr =
sManagers->Get(aCurrentTopContextId)) {
mgr->MaybeDispatchSessionStoreUpdate();
mgr->SetCurrentBrowsingContextId(aTargetTopContextId);
// Because of bfcache, we may re-register aTargetTopContextId in
// CanonicalBrowsingContext::ReplacedBy.
// XXXBFCache do we want to tweak this behavior and ensure this is
@ -66,14 +68,19 @@ bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
if (sManagers) {
sManagers->Remove(aTopContextId);
RefPtr<BackgroundSessionStorageManager> mgr;
sManagers->Remove(aTopContextId, getter_AddRefs(mgr));
if (mgr) {
mgr->CancelSessionStoreUpdate();
}
}
return true;
}
bool RecvGetSessionStorageData(
uint64_t aTopContextId, uint32_t aSizeLimit,
uint64_t aTopContextId, uint32_t aSizeLimit, bool aCancelSessionStoreTimer,
::mozilla::ipc::PBackgroundParent::GetSessionStorageManagerDataResolver&&
aResolver) {
nsTArray<mozilla::dom::SSCacheCopy> data;
@ -89,6 +96,8 @@ bool RecvGetSessionStorageData(
return true;
}
if (aCancelSessionStoreTimer) {
manager->CancelSessionStoreUpdate();
}
manager->GetData(aSizeLimit, data);
@ -660,12 +669,17 @@ BackgroundSessionStorageManager* BackgroundSessionStorageManager::GetOrCreate(
}
return sManagers
->LookupOrInsertWith(aTopContextId,
[] { return new BackgroundSessionStorageManager(); })
->LookupOrInsertWith(
aTopContextId,
[aTopContextId] {
return new BackgroundSessionStorageManager(aTopContextId);
})
.get();
}
BackgroundSessionStorageManager::BackgroundSessionStorageManager() {
BackgroundSessionStorageManager::BackgroundSessionStorageManager(
uint64_t aBrowsingContextId)
: mCurrentBrowsingContextId(aBrowsingContextId) {
MOZ_ASSERT(XRE_IsParentProcess());
::mozilla::ipc::AssertIsOnBackgroundThread();
}
@ -694,7 +708,8 @@ void BackgroundSessionStorageManager::CopyDataToContentProcess(
/* static */
RefPtr<BackgroundSessionStorageManager::DataPromise>
BackgroundSessionStorageManager::GetData(BrowsingContext* aContext,
uint32_t aSizeLimit) {
uint32_t aSizeLimit,
bool aClearSessionStoreTimer) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aContext->IsTop());
@ -754,11 +769,70 @@ void BackgroundSessionStorageManager::UpdateData(
GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
MOZ_ASSERT(originRecord);
MaybeScheduleSessionStoreUpdate();
originRecord->mCache->DeserializeWriteInfos(
SessionStorageCache::eDefaultSetType, aDefaultWriteInfos);
originRecord->mCache->DeserializeWriteInfos(
SessionStorageCache::eSessionSetType, aSessionWriteInfos);
}
void BackgroundSessionStorageManager::SetCurrentBrowsingContextId(
uint64_t aBrowsingContextId) {
MOZ_DIAGNOSTIC_ASSERT(aBrowsingContextId != mCurrentBrowsingContextId);
mCurrentBrowsingContextId = aBrowsingContextId;
}
void BackgroundSessionStorageManager::MaybeScheduleSessionStoreUpdate() {
if (mSessionStoreCallbackTimer) {
return;
}
if (StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
DispatchSessionStoreUpdate();
return;
}
auto result = NS_NewTimerWithFuncCallback(
[](nsITimer*, void* aClosure) {
auto* mgr = static_cast<BackgroundSessionStorageManager*>(aClosure);
mgr->DispatchSessionStoreUpdate();
},
this, StaticPrefs::browser_sessionstore_interval(),
nsITimer::TYPE_ONE_SHOT,
"BackgroundSessionStorageManager::DispatchSessionStoreUpdate");
if (result.isErr()) {
return;
}
mSessionStoreCallbackTimer = result.unwrap();
}
void BackgroundSessionStorageManager::MaybeDispatchSessionStoreUpdate() {
if (mSessionStoreCallbackTimer) {
BackgroundSessionStorageManager::DispatchSessionStoreUpdate();
}
}
void BackgroundSessionStorageManager::DispatchSessionStoreUpdate() {
::mozilla::ipc::AssertIsOnBackgroundThread();
NS_DispatchToMainThread(NS_NewRunnableFunction(
"CanonicalBrowsingContext::UpdateSessionStore",
[targetBrowsingContextId = mCurrentBrowsingContextId]() {
CanonicalBrowsingContext::UpdateSessionStoreForStorage(
targetBrowsingContextId);
}));
CancelSessionStoreUpdate();
}
void BackgroundSessionStorageManager::CancelSessionStoreUpdate() {
if (mSessionStoreCallbackTimer) {
mSessionStoreCallbackTimer->Cancel();
mSessionStoreCallbackTimer = nullptr;
}
}
} // namespace dom
} // namespace mozilla

View File

@ -19,6 +19,7 @@
#include "mozilla/ipc/PBackgroundParent.h"
class nsIPrincipal;
class nsITimer;
namespace mozilla {
class OriginAttributesPattern;
@ -31,7 +32,7 @@ void RecvPropagateBackgroundSessionStorageManager(uint64_t aCurrentTopContextId,
bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId);
bool RecvGetSessionStorageData(
uint64_t aTopContextId, uint32_t aSizeLimit,
uint64_t aTopContextId, uint32_t aSizeLimit, bool aCancelSessionStoreTimer,
::mozilla::ipc::PBackgroundParent::GetSessionStorageManagerDataResolver&&
aResolver);
@ -182,7 +183,8 @@ class BackgroundSessionStorageManager final : public SessionStorageManagerBase {
using DataPromise =
::mozilla::ipc::PBackgroundChild::GetSessionStorageManagerDataPromise;
static RefPtr<DataPromise> GetData(BrowsingContext* aContext,
uint32_t aSizeLimit);
uint32_t aSizeLimit,
bool aClearSessionStoreTimer = false);
void GetData(uint32_t aSizeLimit, nsTArray<SSCacheCopy>& aCacheCopyList);
@ -195,11 +197,56 @@ class BackgroundSessionStorageManager final : public SessionStorageManagerBase {
const nsTArray<SSWriteInfo>& aDefaultWriteInfos,
const nsTArray<SSWriteInfo>& aSessionWriteInfos);
void SetCurrentBrowsingContextId(uint64_t aBrowsingContextId);
void MaybeDispatchSessionStoreUpdate();
void CancelSessionStoreUpdate();
private:
// Only be called by GetOrCreate() on the parent process.
explicit BackgroundSessionStorageManager();
explicit BackgroundSessionStorageManager(uint64_t aBrowsingContextId);
~BackgroundSessionStorageManager();
// Sets a timer for notifying main thread that the cache has been
// updated. May do nothing if we're coalescing notifications.
void MaybeScheduleSessionStoreUpdate();
void DispatchSessionStoreUpdate();
// The most current browsing context using this manager
uint64_t mCurrentBrowsingContextId;
// Callback for notifying main thread of calls to `UpdateData`.
//
// A timer that is held whenever this manager has dirty state that
// has not yet been reflected to the main thread. The timer is used
// to delay notifying the main thread to ask for changes, thereby
// coalescing/throttling changes. (Note that SessionStorage, like
// LocalStorage, treats attempts to set a value to its current value
// as a no-op.)
//
// The timer is initialized with a fixed delay as soon as the state
// becomes dirty; additional mutations to our state will not reset
// the timer because then we might never flush to the main
// thread. The timer is cleared only when a new set of data is sent
// to the main thread and therefore this manager no longer has any
// dirty state. This means that there is a period of time after the
// nsITimer fires where this value is non-null but there is no
// scheduled timer while we wait for the main thread to request the
// new state. Callers of GetData can also optionally cancel the
// current timer to reduce the amounts of notifications.
//
// When this manager is moved to a new top-level browsing context id
// via a PropagateBackgroundSessionStorageManager message, the
// behavior of the timer doesn't change because the main thread knows
// about the renaming and is initiating it (and any in-flight
// GetSessionStorageManagerData requests will be unaffected because
// they use async-returns so the response is inherently matched up via
// the issued promise).
nsCOMPtr<nsITimer> mSessionStoreCallbackTimer;
};
} // namespace dom

View File

@ -1142,6 +1142,7 @@ BackgroundParentImpl::RecvRemoveBackgroundSessionStorageManager(
mozilla::ipc::IPCResult BackgroundParentImpl::RecvGetSessionStorageManagerData(
const uint64_t& aTopContextId, const uint32_t& aSizeLimit,
const bool& aCancelSessionStoreTimer,
GetSessionStorageManagerDataResolver&& aResolver) {
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
@ -1151,6 +1152,7 @@ mozilla::ipc::IPCResult BackgroundParentImpl::RecvGetSessionStorageManagerData(
}
if (!mozilla::dom::RecvGetSessionStorageData(aTopContextId, aSizeLimit,
aCancelSessionStoreTimer,
std::move(aResolver))) {
return IPC_FAIL(this, "Couldn't get session storage data");
}

View File

@ -320,6 +320,7 @@ class BackgroundParentImpl : public PBackgroundParent,
mozilla::ipc::IPCResult RecvGetSessionStorageManagerData(
const uint64_t& aTopContextId, const uint32_t& aSizeLimit,
const bool& aCancelSessionStoreTimer,
GetSessionStorageManagerDataResolver&& aResolver) override;
already_AddRefed<PFileSystemRequestParent> AllocPFileSystemRequestParent(

View File

@ -211,7 +211,7 @@ parent:
async RemoveBackgroundSessionStorageManager(uint64_t topContextId);
async GetSessionStorageManagerData(
uint64_t aTopContextId, uint32_t aSizeLimit)
uint64_t aTopContextId, uint32_t aSizeLimit, bool aCancelSessionStoreTimer)
returns(SSCacheCopy[] aCacheCopy);
async PFileSystemRequest(FileSystemParams params);

View File

@ -1241,7 +1241,7 @@
# Minimal interval between two save operations in milliseconds (while the user is active).
- name: browser.sessionstore.interval
type: uint32_t
type: RelaxedAtomicUint32
value: 15000
mirror: always
@ -1249,7 +1249,7 @@
# browser tabs that were not caused by a flush from the parent.
# This is a testing flag and should not be used by end-users.
- name: browser.sessionstore.debug.no_auto_updates
type: bool
type: RelaxedAtomicBool
value: false
mirror: always