Bug 1607505 - Start writing StartupCache earlier in shutdown r=froydnj a=reland CLOSED TREE

The initial thought for getting the StartupCache out of the shutdown
path was to simply not write it during shutdown, as it should write
60 seconds after startup, and the theory was that if the user shut
down within the first 60 seconds of use, they were likely updating or
something and it shouldn't matter. However, considering how many of
our users only ever open one tab, I think it's rather likely that
users are starting up firefox to go to a web site, then closing it
when done with that website, and then maybe opening up a new instance
in order to go to a different website. Accordingly it still makes
sense to continue writing it. However, we may as well leverage a
background thread for this and get it kicked off earlier during
shutdown, so we don't sit there blocking in the destructor late
during shutdown.

Differential Revision: https://phabricator.services.mozilla.com/D62294

--HG--
extra : source : 7b7b147b6955cee07e0c115993446bfbd59cf7e2
extra : histedit_source : 6990122d6b1ac4939b0e4b0a5e452183fb981e19
This commit is contained in:
Doug Thayer 2020-02-12 19:02:12 +00:00
parent becd55c159
commit f564eb1f40
3 changed files with 44 additions and 29 deletions

View File

@ -147,26 +147,7 @@ StartupCache::StartupCache()
mPrefetchThread(nullptr) {}
StartupCache::~StartupCache() {
if (mTimer) {
mTimer->Cancel();
}
// Generally, the in-memory table should be empty here,
// but an early shutdown means either mTimer didn't run
// or the write thread is still running.
WaitOnWriteThread();
WaitOnPrefetchThread();
// If we shutdown quickly timer wont have fired. Instead of writing
// it on the main thread and block the shutdown we simply wont update
// the startup cache. Always do this if the file doesn't exist since
// we use it part of the package step.
if (!mCacheData.initialized() || ShouldCompactCache()) {
mDirty = true;
auto result = WriteToDisk();
Unused << NS_WARN_IF(result.isErr());
}
UnregisterWeakMemoryReporter(this);
}
@ -613,6 +594,25 @@ void StartupCache::InvalidateCache(bool memoryOnly) {
}
}
void StartupCache::MaybeInitShutdownWrite() {
if (mTimer) {
mTimer->Cancel();
}
gShutdownInitiated = true;
MaybeSpawnWriteThread();
// If we shutdown quickly timer wont have fired. Instead of writing
// it on the main thread and block the shutdown we simply wont update
// the startup cache. Always do this if the file doesn't exist since
// we use it part of the package step.
if (!mCacheData.initialized() || ShouldCompactCache()) {
mDirty = true;
auto result = WriteToDisk();
Unused << NS_WARN_IF(result.isErr());
}
}
void StartupCache::IgnoreDiskCache() {
gIgnoreDiskCache = true;
if (gStartupCache) gStartupCache->InvalidateCache();
@ -690,22 +690,28 @@ void StartupCache::WriteTimeout(nsITimer* aTimer, void* aClosure) {
* if the StartupCache object is valid.
*/
StartupCache* startupCacheObj = static_cast<StartupCache*>(aClosure);
if (startupCacheObj->mWrittenOnce) {
startupCacheObj->MaybeSpawnWriteThread();
}
/*
* See StartupCache::WriteTimeout above - this is just the non-static body.
*/
void StartupCache::MaybeSpawnWriteThread() {
if (mWrittenOnce || mWriteThread) {
return;
}
if (startupCacheObj->mCacheData.initialized() &&
!startupCacheObj->ShouldCompactCache()) {
if (mCacheData.initialized() && !ShouldCompactCache()) {
return;
}
startupCacheObj->WaitOnPrefetchThread();
startupCacheObj->mStartupWriteInitiated = false;
startupCacheObj->mDirty = true;
startupCacheObj->mCacheData.reset();
startupCacheObj->mWriteThread = PR_CreateThread(
PR_USER_THREAD, StartupCache::ThreadedWrite, startupCacheObj,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 512 * 1024);
WaitOnPrefetchThread();
mStartupWriteInitiated = false;
mDirty = true;
mCacheData.reset();
mWriteThread = PR_CreateThread(PR_USER_THREAD, StartupCache::ThreadedWrite,
this, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 512 * 1024);
}
// We don't want to refcount StartupCache, so we'll just
@ -720,6 +726,7 @@ nsresult StartupCacheListener::Observe(nsISupports* subject, const char* topic,
if (strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
// Do not leave the thread running past xpcom shutdown
sc->WaitOnWriteThread();
sc->WaitOnPrefetchThread();
StartupCache::gShutdownInitiated = true;
} else if (strcmp(topic, "startupcache-invalidate") == 0) {
sc->InvalidateCache(data && nsCRT::strcmp(data, u"memoryOnly") == 0);

View File

@ -163,6 +163,10 @@ class StartupCache : public nsIMemoryReporter {
// Removes the cache file.
void InvalidateCache(bool memoryOnly = false);
// For use during shutdown - this will write the startupcache's data
// to disk if the timer hasn't already gone off.
void MaybeInitShutdownWrite();
// Signal that data should not be loaded from the cache file
static void IgnoreDiskCache();
@ -203,6 +207,7 @@ class StartupCache : public nsIMemoryReporter {
void WaitOnWriteThread();
void WaitOnPrefetchThread();
void StartPrefetchMemoryThread();
void MaybeSpawnWriteThread();
static nsresult InitSingleton();
static void WriteTimeout(nsITimer* aTimer, void* aClosure);

View File

@ -16,6 +16,7 @@
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/PoisonIOInterposer.h"
#include "mozilla/Printf.h"
#include "mozilla/scache/StartupCache.h"
#include "mozilla/StartupTimeline.h"
#include "mozilla/StaticPrefs_toolkit.h"
#include "mozilla/LateWriteChecks.h"
@ -125,6 +126,8 @@ void AppShutdown::Init(AppShutdownMode aMode) {
int32_t lateWriteChecksPref =
StaticPrefs::toolkit_shutdown_lateWriteChecksStage();
sLateWriteChecksPhase = GetShutdownPhaseFromPrefValue(lateWriteChecksPref);
scache::StartupCache::GetSingleton()->MaybeInitShutdownWrite();
}
void AppShutdown::MaybeFastShutdown(ShutdownPhase aPhase) {