Bug 1371882 - MediaCache uses MemoryBlockCache when content length is known - r=cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Fri, 09 Jun 2017 18:56:34 +1200
changeset 595162 e117063a8b99f6ca7cde6655569c70d51f98eea6
parent 595161 4b7e2d0829a8286be5f6d30841961db7882b488e
child 595163 eed65eafbabe59ca7c02f2c2c43ddd8ff349e99b
push id64265
push usergsquelart@mozilla.com
push dateFri, 16 Jun 2017 03:37:56 +0000
reviewerscpearce
bugs1371882
milestone56.0a1
Bug 1371882 - MediaCache uses MemoryBlockCache when content length is known - r=cpearce MozReview-Commit-ID: 35A4Vc95NtB
dom/media/MediaCache.cpp
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -10,16 +10,17 @@
 #include "prio.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "MediaResource.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "FileBlockCache.h"
 #include "MediaBlockCacheBase.h"
+#include "MemoryBlockCache.h"
 #include "nsIObserverService.h"
 #include "nsISeekableStream.h"
 #include "nsIPrincipal.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include <algorithm>
@@ -252,18 +253,19 @@ public:
     }
   private:
     MediaCache* mMediaCache;
     int64_t  mResourceID;
     uint32_t mNext;
   };
 
 protected:
-  MediaCache()
-    : mNextResourceID(1)
+  explicit MediaCache(int64_t aContentLength)
+    : mContentLength(aContentLength)
+    , mNextResourceID(1)
     , mReentrantMonitor("MediaCache.mReentrantMonitor")
     , mUpdateQueued(false)
     , mShutdownInsteadOfUpdating(false)
 #ifdef DEBUG
     , mInUpdate(false)
 #endif
   {
     MOZ_COUNT_CTOR(MediaCache);
@@ -275,28 +277,32 @@ protected:
     MediaCacheFlusher::UnregisterMediaCache(this);
     NS_ASSERTION(mStreams.IsEmpty(), "Stream(s) still open!");
     Truncate();
     NS_ASSERTION(mIndex.Length() == 0, "Blocks leaked?");
     if (mBlockCache) {
       mBlockCache->Close();
       mBlockCache = nullptr;
     }
-    LOG("MediaCache::~MediaCache(this=%p) MEDIACACHE_WATERMARK_KB=%u",
-        this,
-        unsigned(mIndexWatermark * MediaCache::BLOCK_SIZE / 1024));
-    Telemetry::Accumulate(
-      Telemetry::HistogramID::MEDIACACHE_WATERMARK_KB,
-      uint32_t(mIndexWatermark * MediaCache::BLOCK_SIZE / 1024));
-    LOG("MediaCache::~MediaCache(this=%p) MEDIACACHE_BLOCKOWNERS_WATERMARK=%u",
+    if (mContentLength <= 0) {
+      // Only gather "MEDIACACHE" telemetry for the file-based cache.
+      LOG("MediaCache::~MediaCache(this=%p) MEDIACACHE_WATERMARK_KB=%u",
+          this,
+          unsigned(mIndexWatermark * MediaCache::BLOCK_SIZE / 1024));
+      Telemetry::Accumulate(
+        Telemetry::HistogramID::MEDIACACHE_WATERMARK_KB,
+        uint32_t(mIndexWatermark * MediaCache::BLOCK_SIZE / 1024));
+      LOG(
+        "MediaCache::~MediaCache(this=%p) MEDIACACHE_BLOCKOWNERS_WATERMARK=%u",
         this,
         unsigned(mBlockOwnersWatermark));
-    Telemetry::Accumulate(
-      Telemetry::HistogramID::MEDIACACHE_BLOCKOWNERS_WATERMARK,
-      mBlockOwnersWatermark);
+      Telemetry::Accumulate(
+        Telemetry::HistogramID::MEDIACACHE_BLOCKOWNERS_WATERMARK,
+        mBlockOwnersWatermark);
+    }
 
     MOZ_COUNT_DTOR(MediaCache);
   }
 
   // Main thread only. Creates the backing cache file. If this fails,
   // then the cache is still in a semi-valid state; mFD will be null,
   // so all I/O on the cache file will fail.
   nsresult Init();
@@ -393,16 +399,21 @@ protected:
   // Shutdown this MediaCache, and reset gMediaCache if we are the global one.
   // If there is no queued update, destroy the MediaCache immediately.
   // Otherwise when the update is processed, it will destroy the MediaCache.
   void ShutdownAndDestroyThis();
 
   // There is at most one file-backed media cache.
   static MediaCache* gMediaCache;
 
+  // Expected content length if known initially from the HTTP Content-Length
+  // header (this is a memory-backed MediaCache), otherwise -1 (file-backed
+  // MediaCache).
+  const int64_t mContentLength;
+
   // This member is main-thread only. It's used to allocate unique
   // resource IDs to streams.
   int64_t                       mNextResourceID;
 
   // The monitor protects all the data members here. Also, off-main-thread
   // readers that need to block will Wait() on this monitor. When new
   // data becomes available in the cache, we NotifyAll() on this monitor.
   ReentrantMonitor         mReentrantMonitor;
@@ -660,17 +671,23 @@ MediaCacheStream::BlockList::NotifyBlock
 }
 
 nsresult
 MediaCache::Init()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   NS_ASSERTION(!mBlockCache, "Block cache already open?");
 
-  mBlockCache = new FileBlockCache();
+  if (mContentLength <= 0) {
+    // The global MediaCache uses a file-backed storage for its resource blocks.
+    mBlockCache = new FileBlockCache();
+  } else {
+    // Non-global MediaCaches keep the whole resource in memory.
+    mBlockCache = new MemoryBlockCache(mContentLength);
+  }
   nsresult rv = mBlockCache->Init();
   NS_ENSURE_SUCCESS(rv,rv);
 
   return NS_OK;
 }
 
 void
 MediaCache::Flush()
@@ -742,31 +759,31 @@ MediaCache::ShutdownAndDestroyThis()
 /* static */ MediaCache*
 MediaCache::GetMediaCache(int64_t aContentLength)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   if (aContentLength > 0 &&
       aContentLength <=
         int64_t(MediaPrefs::MediaMemoryCacheMaxSize()) * 1024) {
     // Small-enough resource, use a new memory-backed MediaCache.
-    MediaCache* mc = new MediaCache();
+    MediaCache* mc = new MediaCache(aContentLength);
     nsresult rv = mc->Init();
     if (NS_SUCCEEDED(rv)) {
       return mc;
     }
     // Memory-backed MediaCache initialization failed, clean up and try for a
     // file-backed MediaCache below.
     delete mc;
   }
 
   if (gMediaCache) {
     return gMediaCache;
   }
 
-  gMediaCache = new MediaCache();
+  gMediaCache = new MediaCache(-1);
   nsresult rv = gMediaCache->Init();
   if (NS_FAILED(rv)) {
     delete gMediaCache;
     gMediaCache = nullptr;
   }
 
   return gMediaCache;
 }