Bug 1371882 - MediaBlockCacheBase::Init may be called again to re-initialize cache - r?cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Thu, 15 Jun 2017 15:55:39 +1200
changeset 595166 80cd4f7e6c13c04eec2e6ef7e1fb394c7701d2cb
parent 595165 507ffe036c060afb18bba30c3afa0884ee06a99e
child 595167 38054b35434d5f77a17fe4273ef626228486e117
push id64265
push usergsquelart@mozilla.com
push dateFri, 16 Jun 2017 03:37:56 +0000
reviewerscpearce
bugs1371882
milestone56.0a1
Bug 1371882 - MediaBlockCacheBase::Init may be called again to re-initialize cache - r?cpearce This will be useful to let the MediaCache flush its block cache without having to restart from scratch (and risk failing). MozReview-Commit-ID: At3mxH9jb9m
dom/media/FileBlockCache.cpp
dom/media/FileBlockCache.h
dom/media/MediaBlockCacheBase.h
dom/media/MemoryBlockCache.cpp
dom/media/MemoryBlockCache.h
--- a/dom/media/FileBlockCache.cpp
+++ b/dom/media/FileBlockCache.cpp
@@ -68,19 +68,28 @@ FileBlockCache::SetCacheFile(PRFileDesc*
     CloseFD(mFD);
     mFD = nullptr;
   }
 }
 
 nsresult
 FileBlockCache::Init()
 {
+  MutexAutoLock mon(mDataMutex);
+  if (mThread) {
+    LOG("Init() again");
+    // Just discard pending changes, assume MediaCache won't read from
+    // blocks it hasn't written to.
+    mChangeIndexList.clear();
+    mBlockChanges.Clear();
+    return NS_OK;
+  }
+
   LOG("Init()");
 
-  MutexAutoLock mon(mDataMutex);
   nsresult rv = NS_NewNamedThread("FileBlockCache",
                                   getter_AddRefs(mThread),
                                   nullptr,
                                   SharedThreadPool::kStackSize);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -299,17 +308,16 @@ nsresult FileBlockCache::MoveBlockInFile
   return WriteBlockToFile(aDestBlockIndex, buf);
 }
 
 void
 FileBlockCache::PerformBlockIOs()
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
   MutexAutoLock mon(mDataMutex);
-  NS_ASSERTION(!mChangeIndexList.empty(), "Only dispatch when there's work to do");
   NS_ASSERTION(mIsWriteScheduled, "Should report write running or scheduled.");
 
   LOG("Run() mFD=%p mThread=%p", mFD, mThread.get());
 
   while (!mChangeIndexList.empty()) {
     if (!mThread) {
       // We've been closed, abort, discarding unwritten changes.
       mIsWriteScheduled = false;
--- a/dom/media/FileBlockCache.h
+++ b/dom/media/FileBlockCache.h
@@ -56,16 +56,18 @@ class FileBlockCache : public MediaBlock
 {
 public:
   FileBlockCache();
 
 protected:
   virtual ~FileBlockCache();
 
 public:
+  // Launch thread and open temporary file.
+  // If re-initializing, just discard pending writes if any.
   nsresult Init() override;
 
   // Can be called on any thread. This defers to a non-main thread.
   nsresult WriteBlock(uint32_t aBlockIndex,
                       Span<const uint8_t> aData1,
                       Span<const uint8_t> aData2) override;
 
   // Synchronously reads data from file. May read from file or memory
--- a/dom/media/MediaBlockCacheBase.h
+++ b/dom/media/MediaBlockCacheBase.h
@@ -43,16 +43,18 @@ public:
       static_cast<decltype(MediaCacheStream::BLOCK_SIZE)>(INT32_MAX),
     "MediaCacheStream::BLOCK_SIZE should fit in 31 bits");
   static const int32_t BLOCK_SIZE = MediaCacheStream::BLOCK_SIZE;
 
 protected:
   virtual ~MediaBlockCacheBase() {}
 
 public:
+  // Initialize this cache.
+  // If called again, re-initialize cache with minimal chance of failure.
   virtual nsresult Init() = 0;
 
   // Can be called on any thread. This defers to a non-main thread.
   virtual nsresult WriteBlock(uint32_t aBlockIndex,
                               Span<const uint8_t> aData1,
                               Span<const uint8_t> aData2) = 0;
 
   // Synchronously reads data from file. May read from file or memory
--- a/dom/media/MemoryBlockCache.cpp
+++ b/dom/media/MemoryBlockCache.cpp
@@ -66,24 +66,31 @@ MemoryBlockCache::EnsureBufferCanContain
   }
   mHasGrown = false;
   return true;
 }
 
 nsresult
 MemoryBlockCache::Init()
 {
-  LOG("@%p Init()", this);
   MutexAutoLock lock(mMutex);
-  // Attempt to pre-allocate buffer for expected content length.
-  if (!EnsureBufferCanContain(mInitialContentLength)) {
-    LOG("@%p Init() MEMORYBLOCKCACHE_ERRORS='InitAllocation'", this);
-    Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS,
-                          InitAllocation);
-    return NS_ERROR_FAILURE;
+  if (mBuffer.IsEmpty()) {
+    LOG("@%p Init()", this);
+    // Attempt to pre-allocate buffer for expected content length.
+    if (!EnsureBufferCanContain(mInitialContentLength)) {
+      LOG("@%p Init() MEMORYBLOCKCACHE_ERRORS='InitAllocation'", this);
+      Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS,
+                            InitAllocation);
+      return NS_ERROR_FAILURE;
+    }
+  } else {
+    LOG("@%p Init() again", this);
+    // Re-initialization - Just erase data.
+    MOZ_ASSERT(mBuffer.Length() >= mInitialContentLength);
+    memset(mBuffer.Elements(), 0, mBuffer.Length());
   }
   // Ignore initial growth.
   mHasGrown = false;
   return NS_OK;
 }
 
 nsresult
 MemoryBlockCache::WriteBlock(uint32_t aBlockIndex,
--- a/dom/media/MemoryBlockCache.h
+++ b/dom/media/MemoryBlockCache.h
@@ -34,16 +34,17 @@ class MemoryBlockCache : public MediaBlo
 public:
   explicit MemoryBlockCache(int64_t aContentLength);
 
 protected:
   virtual ~MemoryBlockCache();
 
 public:
   // Allocate initial buffer.
+  // If re-initializing, clear buffer.
   virtual nsresult Init() override;
 
   // Can be called on any thread.
   virtual nsresult WriteBlock(uint32_t aBlockIndex,
                               Span<const uint8_t> aData1,
                               Span<const uint8_t> aData2) override;
 
   // Synchronously reads data from buffer.