Skip to content

Commit

Permalink
Part 9: Bug 1700623 - Notify main thread about storage updates period…
Browse files Browse the repository at this point in the history
…ically. r=asuth

This is used to update session store storage contents continuously.

Depends on D111435

Differential Revision: https://phabricator.services.mozilla.com/D114586
  • Loading branch information
farre committed May 20, 2021
1 parent ea3916b commit a0d376b
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 12 deletions.
2 changes: 2 additions & 0 deletions docshell/base/CanonicalBrowsingContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
86 changes: 80 additions & 6 deletions dom/storage/SessionStorageManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -89,6 +96,8 @@ bool RecvGetSessionStorageData(
return true;
}

if (aCancelSessionStoreTimer) {
manager->CancelSessionStoreUpdate();
}

manager->GetData(aSizeLimit, data);
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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
53 changes: 50 additions & 3 deletions dom/storage/SessionStorageManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "mozilla/ipc/PBackgroundParent.h"

class nsIPrincipal;
class nsITimer;

namespace mozilla {
class OriginAttributesPattern;
Expand All @@ -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);

Expand Down Expand Up @@ -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);

Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions ipc/glue/BackgroundParentImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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");
}
Expand Down
1 change: 1 addition & 0 deletions ipc/glue/BackgroundParentImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion ipc/glue/PBackground.ipdl
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions modules/libpref/init/StaticPrefList.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1231,15 +1231,15 @@

# 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

# Causes SessionStore to ignore non-final update messages from
# 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

Expand Down

0 comments on commit a0d376b

Please sign in to comment.