Bug 1365538 - Postpone FileBlockCache writes while reading - r?cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Wed, 17 May 2017 17:10:57 +1200
changeset 580045 e47d66e07d7a57545968b414f0f5351b09eab566
parent 580044 29b072418fc4e9262eb2d427d87ce02e8d5bbf8c
child 629175 d450a7cd43e3561d7102d3047cb19f516e8d72ce
push id59434
push usergsquelart@mozilla.com
push dateThu, 18 May 2017 04:40:14 +0000
reviewerscpearce
bugs1365538
milestone55.0a1
Bug 1365538 - Postpone FileBlockCache writes while reading - r?cpearce While inside FileBlock::Read, the mIsReading flag is set, which in turn prevents starting the writer task, or makes it exit as soon as possible. This should help multi-block reads (while data is being received) by giving them priority, so that that blocking call can return faster. At the end of Read, the writer task is re-dispatched if needed. MozReview-Commit-ID: J32tHGFRMNU
dom/media/FileBlockCache.cpp
dom/media/FileBlockCache.h
--- a/dom/media/FileBlockCache.cpp
+++ b/dom/media/FileBlockCache.cpp
@@ -91,16 +91,17 @@ FileBlockCache::Init()
 }
 
 FileBlockCache::FileBlockCache()
   : mFileMutex("MediaCache.Writer.IO.Mutex"),
     mFD(nullptr),
     mFDCurrentPos(0),
     mDataMutex("MediaCache.Writer.Data.Mutex"),
     mIsWriteScheduled(false),
+    mIsReading(false),
     mIsOpen(false)
 {
 }
 
 FileBlockCache::~FileBlockCache()
 {
   NS_ASSERTION(!mIsOpen, "Should Close() FileBlockCache before destroying");
 }
@@ -190,17 +191,17 @@ FileBlockCache::WriteBlock(uint32_t aBlo
   return NS_OK;
 }
 
 void FileBlockCache::EnsureWriteScheduled()
 {
   mDataMutex.AssertCurrentThreadOwns();
   MOZ_ASSERT(mIsOpen);
 
-  if (mIsWriteScheduled) {
+  if (mIsWriteScheduled || mIsReading) {
     return;
   }
   mIsWriteScheduled = true;
   if (!mInitialized) {
     // We're still waiting on a file descriptor. When it arrives,
     // the write will be scheduled.
     return;
   }
@@ -294,16 +295,22 @@ nsresult FileBlockCache::Run()
 
   while (!mChangeIndexList.empty()) {
     if (!mIsOpen) {
       // We've been closed, abort, discarding unwritten changes.
       mIsWriteScheduled = false;
       return NS_ERROR_FAILURE;
     }
 
+    if (mIsReading) {
+      // We're trying to read; postpone all writes. (Reader will resume writes.)
+      mIsWriteScheduled = false;
+      return NS_OK;
+    }
+
     // Process each pending change. We pop the index out of the change
     // list, but leave the BlockChange in mBlockChanges until the change
     // is written to file. This is so that any read which happens while
     // we drop mDataMutex to write will refer to the data's source in
     // memory, rather than the not-yet up to date data written to file.
     // This also ensures we will insert a new index into mChangeIndexList
     // when this happens.
 
@@ -343,16 +350,25 @@ nsresult FileBlockCache::Read(int64_t aO
                               int32_t aLength,
                               int32_t* aBytes)
 {
   MutexAutoLock mon(mDataMutex);
 
   if (!mIsOpen || (aOffset / BLOCK_SIZE) > INT32_MAX)
     return NS_ERROR_FAILURE;
 
+  mIsReading = true;
+  auto exitRead = MakeScopeExit([&] {
+    mIsReading = false;
+    if (!mChangeIndexList.empty()) {
+      // mReading has stopped or prevented pending writes, resume them.
+      EnsureWriteScheduled();
+    }
+  });
+
   int32_t bytesToRead = aLength;
   int64_t offset = aOffset;
   uint8_t* dst = aData;
   while (bytesToRead > 0) {
     int32_t blockIndex = static_cast<int32_t>(offset / BLOCK_SIZE);
     int32_t start = offset % BLOCK_SIZE;
     int32_t amount = std::min(BLOCK_SIZE - start, bytesToRead);
 
--- a/dom/media/FileBlockCache.h
+++ b/dom/media/FileBlockCache.h
@@ -184,16 +184,19 @@ private:
   // created upon open, and shutdown (asynchronously) upon close (on the
   // main thread).
   nsCOMPtr<nsIThread> mThread;
   // 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.
   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).
+  bool mIsReading;
   // True if the writer is ready to enqueue writes.
   bool mIsOpen;
   // True if we've got a temporary file descriptor. Note: we don't use mFD
   // directly as that's synchronized via mFileMutex and we need to make
   // decisions about whether we can write while holding mDataMutex.
   bool mInitialized = false;
 };