mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 04:15:43 +00:00
Bug 1379091 - Let block cache tell MediaCache its block use limit - r=cpearce
MozReview-Commit-ID: 5ZCD3NoeYEP --HG-- extra : rebase_source : 0fe76cfa6b15053dc5cf2b392c5d649e6888e6c6
This commit is contained in:
parent
98e6346e07
commit
fd79ed9c4e
@ -5,6 +5,8 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FileBlockCache.h"
|
||||
#include "MediaCache.h"
|
||||
#include "MediaPrefs.h"
|
||||
#include "mozilla/SharedThreadPool.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "prio.h"
|
||||
@ -121,6 +123,33 @@ FileBlockCache::Init()
|
||||
return rv;
|
||||
}
|
||||
|
||||
int32_t
|
||||
FileBlockCache::GetMaxBlocks() const
|
||||
{
|
||||
// We look up the cache size every time. This means dynamic changes
|
||||
// to the pref are applied.
|
||||
const uint32_t cacheSizeKb =
|
||||
std::min(MediaPrefs::MediaCacheSizeKb(), uint32_t(INT32_MAX) * 2);
|
||||
// Ensure we can divide BLOCK_SIZE by 1024.
|
||||
static_assert(MediaCacheStream::BLOCK_SIZE % 1024 == 0,
|
||||
"BLOCK_SIZE should be a multiple of 1024");
|
||||
// Ensure BLOCK_SIZE/1024 is at least 2.
|
||||
static_assert(MediaCacheStream::BLOCK_SIZE / 1024 >= 2,
|
||||
"BLOCK_SIZE / 1024 should be at least 2");
|
||||
// Ensure we can convert BLOCK_SIZE/1024 to a uint32_t without truncation.
|
||||
static_assert(MediaCacheStream::BLOCK_SIZE / 1024 <= int64_t(UINT32_MAX),
|
||||
"BLOCK_SIZE / 1024 should be at most UINT32_MAX");
|
||||
// Since BLOCK_SIZE is a strict multiple of 1024,
|
||||
// cacheSizeKb * 1024 / BLOCK_SIZE == cacheSizeKb / (BLOCK_SIZE / 1024),
|
||||
// but the latter formula avoids a potential overflow from `* 1024`.
|
||||
// And because BLOCK_SIZE/1024 is at least 2, the maximum cache size
|
||||
// INT32_MAX*2 will give a maxBlocks that can fit in an int32_t.
|
||||
constexpr uint32_t blockSizeKb =
|
||||
uint32_t(MediaCacheStream::BLOCK_SIZE / 1024);
|
||||
const int32_t maxBlocks = int32_t(cacheSizeKb / blockSizeKb);
|
||||
return std::max(maxBlocks, int32_t(1));
|
||||
}
|
||||
|
||||
FileBlockCache::FileBlockCache()
|
||||
: mFileMutex("MediaCache.Writer.IO.Mutex")
|
||||
, mFD(nullptr)
|
||||
|
@ -65,6 +65,10 @@ public:
|
||||
// If re-initializing, just discard pending writes if any.
|
||||
nsresult Init() override;
|
||||
|
||||
// Maximum number of blocks allowed in this block cache.
|
||||
// Calculated from "media.cache_size" pref.
|
||||
int32_t GetMaxBlocks() const override;
|
||||
|
||||
// Can be called on any thread. This defers to a non-main thread.
|
||||
nsresult WriteBlock(uint32_t aBlockIndex,
|
||||
Span<const uint8_t> aData1,
|
||||
|
@ -52,6 +52,10 @@ public:
|
||||
// If called again, re-initialize cache with minimal chance of failure.
|
||||
virtual nsresult Init() = 0;
|
||||
|
||||
// Maximum number of blocks expected in this block cache. (But allow overflow
|
||||
// to accomodate incoming traffic before MediaCache can handle it.)
|
||||
virtual int32_t GetMaxBlocks() const = 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,
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "FileBlockCache.h"
|
||||
#include "MediaBlockCacheBase.h"
|
||||
#include "MediaPrefs.h"
|
||||
#include "MediaResource.h"
|
||||
#include "MemoryBlockCache.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -737,31 +738,6 @@ MediaCache::ReadCacheFile(
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t GetMaxBlocks()
|
||||
{
|
||||
// We look up the cache size every time. This means dynamic changes
|
||||
// to the pref are applied.
|
||||
const uint32_t cacheSizeKb =
|
||||
std::min(MediaPrefs::MediaCacheSizeKb(), uint32_t(INT32_MAX) * 2);
|
||||
// Ensure we can divide BLOCK_SIZE by 1024.
|
||||
static_assert(MediaCache::BLOCK_SIZE % 1024 == 0,
|
||||
"BLOCK_SIZE should be a multiple of 1024");
|
||||
// Ensure BLOCK_SIZE/1024 is at least 2.
|
||||
static_assert(MediaCache::BLOCK_SIZE / 1024 >= 2,
|
||||
"BLOCK_SIZE / 1024 should be at least 2");
|
||||
// Ensure we can convert BLOCK_SIZE/1024 to a uint32_t without truncation.
|
||||
static_assert(MediaCache::BLOCK_SIZE / 1024 <= int64_t(UINT32_MAX),
|
||||
"BLOCK_SIZE / 1024 should be at most UINT32_MAX");
|
||||
// Since BLOCK_SIZE is a strict multiple of 1024,
|
||||
// cacheSizeKb * 1024 / BLOCK_SIZE == cacheSizeKb / (BLOCK_SIZE / 1024),
|
||||
// but the latter formula avoids a potential overflow from `* 1024`.
|
||||
// And because BLOCK_SIZE/1024 is at least 2, the maximum cache size
|
||||
// INT32_MAX*2 will give a maxBlocks that can fit in an int32_t.
|
||||
constexpr uint32_t blockSizeKb = uint32_t(MediaCache::BLOCK_SIZE / 1024);
|
||||
const int32_t maxBlocks = int32_t(cacheSizeKb / blockSizeKb);
|
||||
return std::max(maxBlocks, int32_t(1));
|
||||
}
|
||||
|
||||
// Allowed range is whatever can be accessed with an int32_t block index.
|
||||
static bool
|
||||
IsOffsetAllowed(int64_t aOffset)
|
||||
@ -818,8 +794,10 @@ MediaCache::FindBlockForIncomingData(TimeStamp aNow,
|
||||
// b) the data we're going to store in the free block is not higher
|
||||
// priority than the data already stored in the free block.
|
||||
// The latter can lead us to go over the cache limit a bit.
|
||||
if ((mIndex.Length() < uint32_t(GetMaxBlocks()) || blockIndex < 0 ||
|
||||
PredictNextUseForIncomingData(aStream) >= PredictNextUse(aNow, blockIndex))) {
|
||||
if ((mIndex.Length() < uint32_t(mBlockCache->GetMaxBlocks()) ||
|
||||
blockIndex < 0 ||
|
||||
PredictNextUseForIncomingData(aStream) >=
|
||||
PredictNextUse(aNow, blockIndex))) {
|
||||
blockIndex = mIndex.Length();
|
||||
if (!mIndex.AppendElement())
|
||||
return -1;
|
||||
@ -1163,7 +1141,7 @@ MediaCache::Update()
|
||||
mInUpdate = true;
|
||||
#endif
|
||||
|
||||
int32_t maxBlocks = GetMaxBlocks();
|
||||
int32_t maxBlocks = mBlockCache->GetMaxBlocks();
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
||||
int32_t freeBlockCount = mFreeBlocks.GetCount();
|
||||
|
@ -137,9 +137,23 @@ enum MemoryBlockCacheTelemetryErrors
|
||||
MoveBlockCannotGrow = 7,
|
||||
};
|
||||
|
||||
static int32_t
|
||||
CalculateMaxBlocks(int64_t aContentLength)
|
||||
{
|
||||
// Note: It doesn't matter if calculations overflow, Init() would later fail.
|
||||
// We want at least enough blocks to contain the original content length.
|
||||
const int32_t requiredBlocks =
|
||||
int32_t((aContentLength - 1) / MediaBlockCacheBase::BLOCK_SIZE + 1);
|
||||
// Allow at least 1s of ultra HD (25Mbps).
|
||||
const int32_t workableBlocks =
|
||||
25 * 1024 * 1024 / 8 / MediaBlockCacheBase::BLOCK_SIZE;
|
||||
return std::max(requiredBlocks, workableBlocks);
|
||||
}
|
||||
|
||||
MemoryBlockCache::MemoryBlockCache(int64_t aContentLength)
|
||||
// Buffer whole blocks.
|
||||
: mInitialContentLength((aContentLength >= 0) ? size_t(aContentLength) : 0)
|
||||
, mMaxBlocks(CalculateMaxBlocks(aContentLength))
|
||||
, mMutex("MemoryBlockCache")
|
||||
, mHasGrown(false)
|
||||
{
|
||||
|
@ -42,6 +42,10 @@ public:
|
||||
// If re-initializing, clear buffer.
|
||||
virtual nsresult Init() override;
|
||||
|
||||
// Maximum number of blocks allowed in this block cache.
|
||||
// Based on initial content length, and minimum usable block cache.
|
||||
int32_t GetMaxBlocks() const override { return mMaxBlocks; }
|
||||
|
||||
// Can be called on any thread.
|
||||
virtual nsresult WriteBlock(uint32_t aBlockIndex,
|
||||
Span<const uint8_t> aData1,
|
||||
@ -71,6 +75,9 @@ private:
|
||||
// Initial content length.
|
||||
const size_t mInitialContentLength;
|
||||
|
||||
// Maximum number of blocks that this MemoryBlockCache expects.
|
||||
const int32_t mMaxBlocks;
|
||||
|
||||
// Mutex which controls access to all members below.
|
||||
Mutex mMutex;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user