зеркало из https://github.com/mozilla/gecko-dev.git
af2df0c8a7
Prior to this patch, the startupcache created its own mWriteThread off which it wrote to disk. It's initialized by MaybeSpawnWriteThread, which got called at shutdown, to do the shutdown write if there was any reason to do so, and from a timer that is re-initialized after every addition to the startup cache, to run 60s after the last change to the cache. It then joined that write thread on the main thread (in other words, blocks on that off-main-thread write completing from the main thread) when: - xpcom-shutdown fired - the startupcache itself gets destroyed - someone calls any of: * HasEntry * GetBuffer * PutBuffer * InvalidateCache This patch removes the separate write thread, and instead dispatches a task to the background task queue, indicating it can block. The task is started in the same circumstances where we previously used to write (timer from the last PutBuffer call, and shutdown if necessary). To ensure it cannot be trying to use the data it writes out (mTable) from the other thread while that data changes on the main thread, we use a mutex. The task locks the mutex before starting, and unlocks when finished. Enumerating the cases that we used to block on joining the thread: In terms of application shutdown, we expect the background task queue to either finish the write task, or fail to run it if it hasn't started it yet. In the FastStartup case, we check if a write was necessary; if so, we attempt to gain the lock without waiting. If we're successful, the write has not yet started, and we instead run the write on the main thread. Otherwise, we retry gaining the lock, blocking this time, thus guaranteeing the off-the-main-thread write completes. The task keeps a reference to the startupcache object, so it cannot be destroyed while the task is pending. Because the write does not modify `mTable`, and neither does `HasEntry`, we do not need to do anything there. In the `GetBuffer` case, we do not modify the table unless we have to read the entry off disk (memmapped into `mCacheData`). This can only happen if `mCacheData.initialized()` returns true, and we specifically call `mCacheData.reset()` before firing off the write task to avoid this. `mCacheData` is only re-initialized if someone calls `LoadArchive()`, which can only happen from `Init()` (which is guaranteed not to run again because this is a singleton), or `InvalidateCache()`, where we lock the mutex (see below). So this is safe - but we assert on the lock to try and avoid people breaking this chain of assumptions in the future. When `PutBuffer` is called, we try to lock the mutex - but if locking fails (ie the background thread is writing), we simply fail to store the entry in the startupcache. In practice, this should be rare - it'd happen if new calls to PutBuffer happen while writing during shutdown (when really, we don't care) or when it's been 60 seconds since the last PutBuffer so we started writing the startupcache. When InvalidateCache is called, we lock the mutex - we shouldn't try to write while invalidating, or invalidate while writing. This may be slow, but in practice nothing should call `InvalidateCache` except developer restarts or the `-purgecaches` commandline flag, so it shouldn't matter a great deal. Differential Revision: https://phabricator.services.mozilla.com/D70413 --HG-- extra : moz-landing-system : lando |
||
---|---|---|
.. | ||
test | ||
StartupCache.cpp | ||
StartupCache.h | ||
StartupCacheInfo.cpp | ||
StartupCacheInfo.h | ||
StartupCacheUtils.cpp | ||
StartupCacheUtils.h | ||
components.conf | ||
moz.build | ||
nsIStartupCacheInfo.idl |