Bug 1594814 - move FileBlockCache over to a background thread; r=pehrsons

Sharing a common thread(pool) is better than spinning up a private thread.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nathan Froyd 2019-12-16 07:52:41 +00:00
parent 2808b0a1c5
commit 3422b5f22b
2 changed files with 29 additions and 41 deletions

View File

@ -31,7 +31,7 @@ static void CloseFD(PRFileDesc* aFD) {
}
void FileBlockCache::SetCacheFile(PRFileDesc* aFD) {
LOG("SetFD(aFD=%p) mThread=%p", aFD, mThread.get());
LOG("SetFD(aFD=%p) mBackgroundET=%p", aFD, mBackgroundET.get());
if (!aFD) {
// Failed to get a temporary file. Shutdown.
@ -44,7 +44,7 @@ void FileBlockCache::SetCacheFile(PRFileDesc* aFD) {
}
{
MutexAutoLock lock(mDataMutex);
if (mThread) {
if (mBackgroundET) {
// Still open, complete the initialization.
mInitialized = true;
if (mIsWriteScheduled) {
@ -53,7 +53,7 @@ void FileBlockCache::SetCacheFile(PRFileDesc* aFD) {
nsCOMPtr<nsIRunnable> event = mozilla::NewRunnableMethod(
"FileBlockCache::SetCacheFile -> PerformBlockIOs", this,
&FileBlockCache::PerformBlockIOs);
mThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
mBackgroundET->Dispatch(event.forget(), NS_DISPATCH_EVENT_MAY_BLOCK);
}
return;
}
@ -70,17 +70,16 @@ void FileBlockCache::SetCacheFile(PRFileDesc* aFD) {
nsresult FileBlockCache::Init() {
LOG("Init()");
MutexAutoLock mon(mDataMutex);
MOZ_ASSERT(!mThread);
nsresult rv =
NS_NewNamedThread("FileBlockCache", getter_AddRefs(mThread), nullptr,
nsIThreadManager::kThreadPoolStackSize);
MOZ_ASSERT(!mBackgroundET);
nsresult rv = NS_CreateBackgroundTaskQueue("FileBlockCache",
getter_AddRefs(mBackgroundET));
if (NS_FAILED(rv)) {
return rv;
}
if (XRE_IsParentProcess()) {
RefPtr<FileBlockCache> self = this;
rv = mThread->Dispatch(
rv = mBackgroundET->Dispatch(
NS_NewRunnableFunction("FileBlockCache::Init",
[self] {
PRFileDesc* fd = nullptr;
@ -92,7 +91,7 @@ nsresult FileBlockCache::Init() {
self->Close();
}
}),
NS_DISPATCH_NORMAL);
NS_DISPATCH_EVENT_MAY_BLOCK);
} else {
// We must request a temporary file descriptor from the parent process.
RefPtr<FileBlockCache> self = this;
@ -110,12 +109,12 @@ nsresult FileBlockCache::Init() {
void FileBlockCache::Flush() {
LOG("Flush()");
MutexAutoLock mon(mDataMutex);
MOZ_ASSERT(mThread);
MOZ_ASSERT(mBackgroundET);
// Dispatch a task so we won't clear the arrays while PerformBlockIOs() is
// dropping the data lock and cause InvalidArrayIndex.
RefPtr<FileBlockCache> self = this;
mThread->Dispatch(NS_NewRunnableFunction("FileBlockCache::Flush", [self]() {
mBackgroundET->Dispatch(NS_NewRunnableFunction("FileBlockCache::Flush", [self]() {
MutexAutoLock mon(self->mDataMutex);
// Just discard pending changes, assume MediaCache won't read from
// blocks it hasn't written to.
@ -159,13 +158,13 @@ FileBlockCache::~FileBlockCache() { Close(); }
void FileBlockCache::Close() {
LOG("Close()");
nsCOMPtr<nsIThread> thread;
nsCOMPtr<nsISerialEventTarget> thread;
{
MutexAutoLock mon(mDataMutex);
if (!mThread) {
if (!mBackgroundET) {
return;
}
thread.swap(mThread);
thread.swap(mBackgroundET);
}
PRFileDesc* fd;
@ -176,8 +175,8 @@ void FileBlockCache::Close() {
}
// Let the thread close the FD, and then trigger its own shutdown.
// Note that mThread is now empty, so no other task will be posted there.
// Also mThread and mFD are empty and therefore can be reused immediately.
// Note that mBackgroundET is now empty, so no other task will be posted there.
// Also mBackgroundET and mFD are empty and therefore can be reused immediately.
nsresult rv = thread->Dispatch(
NS_NewRunnableFunction(
"FileBlockCache::Close",
@ -185,19 +184,9 @@ void FileBlockCache::Close() {
if (fd) {
CloseFD(fd);
}
// We must shut down the thread in another
// runnable. This is called
// while we're shutting down the media cache, and
// nsIThread::Shutdown()
// can cause events to run before it completes,
// which could end up
// opening more streams, while the media cache is
// shutting down and
// releasing memory etc!
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(thread);
SystemGroup::Dispatch(TaskCategory::Other, event.forget());
// No need to shutdown background task queues.
}),
NS_DISPATCH_NORMAL);
NS_DISPATCH_EVENT_MAY_BLOCK);
NS_ENSURE_SUCCESS_VOID(rv);
}
@ -212,7 +201,7 @@ nsresult FileBlockCache::WriteBlock(uint32_t aBlockIndex,
Span<const uint8_t> aData2) {
MutexAutoLock mon(mDataMutex);
if (!mThread) {
if (!mBackgroundET) {
return NS_ERROR_FAILURE;
}
@ -241,7 +230,7 @@ nsresult FileBlockCache::WriteBlock(uint32_t aBlockIndex,
void FileBlockCache::EnsureWriteScheduled() {
mDataMutex.AssertCurrentThreadOwns();
MOZ_ASSERT(mThread);
MOZ_ASSERT(mBackgroundET);
if (mIsWriteScheduled || mIsReading) {
return;
@ -255,7 +244,7 @@ void FileBlockCache::EnsureWriteScheduled() {
nsCOMPtr<nsIRunnable> event = mozilla::NewRunnableMethod(
"FileBlockCache::EnsureWriteScheduled -> PerformBlockIOs", this,
&FileBlockCache::PerformBlockIOs);
mThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
mBackgroundET->Dispatch(event.forget(), NS_DISPATCH_EVENT_MAY_BLOCK);
}
nsresult FileBlockCache::Seek(int64_t aOffset) {
@ -326,14 +315,14 @@ nsresult FileBlockCache::MoveBlockInFile(int32_t aSourceBlockIndex,
}
void FileBlockCache::PerformBlockIOs() {
MOZ_ASSERT(mThread->IsOnCurrentThread());
MOZ_ASSERT(mBackgroundET->IsOnCurrentThread());
MutexAutoLock mon(mDataMutex);
NS_ASSERTION(mIsWriteScheduled, "Should report write running or scheduled.");
LOG("Run() mFD=%p mThread=%p", mFD, mThread.get());
LOG("Run() mFD=%p mBackgroundET=%p", mFD, mBackgroundET.get());
while (!mChangeIndexList.empty()) {
if (!mThread) {
if (!mBackgroundET) {
// We've been closed, abort, discarding unwritten changes.
mIsWriteScheduled = false;
return;
@ -391,7 +380,7 @@ nsresult FileBlockCache::Read(int64_t aOffset, uint8_t* aData, int32_t aLength,
int32_t* aBytes) {
MutexAutoLock mon(mDataMutex);
if (!mThread || (aOffset / BLOCK_SIZE) > INT32_MAX) {
if (!mBackgroundET || (aOffset / BLOCK_SIZE) > INT32_MAX) {
return NS_ERROR_FAILURE;
}
@ -462,7 +451,7 @@ nsresult FileBlockCache::MoveBlock(int32_t aSourceBlockIndex,
int32_t aDestBlockIndex) {
MutexAutoLock mon(mDataMutex);
if (!mThread) {
if (!mBackgroundET) {
return NS_ERROR_FAILURE;
}

View File

@ -171,14 +171,13 @@ class FileBlockCache : public MediaBlockCacheBase {
// cached in memory waiting to be written, or this block is the target of a
// block move.
nsTArray<RefPtr<BlockChange> > mBlockChanges;
// Thread upon which block writes and block moves are performed. This is
// created upon open, and shutdown (asynchronously) upon close (on the
// main thread).
nsCOMPtr<nsIThread> mThread;
// Event target upon which block writes and block moves are performed. This is
// created upon open, and dropped on close.
nsCOMPtr<nsISerialEventTarget> mBackgroundET;
// Queue of pending block indexes that need to be written or moved.
std::deque<int32_t> mChangeIndexList;
// True if we've dispatched an event to commit all pending block changes
// to file on mThread.
// to file on mBackgroundET.
bool mIsWriteScheduled;
// True when a read is happening. Pending writes may be postponed, to give
// higher priority to reads (which may be blocking the caller).