| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <utility> | 5 #include <utility> |
| 6 | 6 |
| 7 #include "media/blink/multibuffer.h" | 7 #include "media/blink/multibuffer.h" |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/location.h" |
| 10 | 11 |
| 11 namespace media { | 12 namespace media { |
| 12 | 13 |
| 14 // Prune 80 blocks per 30 seconds. |
| 15 // This means a full cache will go away in ~5 minutes. |
| 16 enum { |
| 17 kBlockPruneInterval = 30, |
| 18 kBlocksPrunedPerInterval = 80, |
| 19 }; |
| 20 |
| 13 // Returns the block ID closest to (but less or equal than) |pos| from |index|. | 21 // Returns the block ID closest to (but less or equal than) |pos| from |index|. |
| 14 template <class T> | 22 template <class T> |
| 15 static MultiBuffer::BlockId ClosestPreviousEntry( | 23 static MultiBuffer::BlockId ClosestPreviousEntry( |
| 16 const std::map<MultiBuffer::BlockId, T>& index, | 24 const std::map<MultiBuffer::BlockId, T>& index, |
| 17 MultiBuffer::BlockId pos) { | 25 MultiBuffer::BlockId pos) { |
| 18 auto i = index.upper_bound(pos); | 26 auto i = index.upper_bound(pos); |
| 19 DCHECK(i == index.end() || i->first > pos); | 27 DCHECK(i == index.end() || i->first > pos); |
| 20 if (i == index.begin()) { | 28 if (i == index.begin()) { |
| 21 return std::numeric_limits<MultiBufferBlockId>::min(); | 29 return std::numeric_limits<MultiBufferBlockId>::min(); |
| 22 } | 30 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 35 if (i == index.end()) { | 43 if (i == index.end()) { |
| 36 return std::numeric_limits<MultiBufferBlockId>::max(); | 44 return std::numeric_limits<MultiBufferBlockId>::max(); |
| 37 } | 45 } |
| 38 DCHECK_GE(i->first, pos); | 46 DCHECK_GE(i->first, pos); |
| 39 return i->first; | 47 return i->first; |
| 40 } | 48 } |
| 41 | 49 |
| 42 // | 50 // |
| 43 // MultiBuffer::GlobalLRU | 51 // MultiBuffer::GlobalLRU |
| 44 // | 52 // |
| 45 MultiBuffer::GlobalLRU::GlobalLRU() : max_size_(0), data_size_(0) {} | 53 MultiBuffer::GlobalLRU::GlobalLRU( |
| 54 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
| 55 : max_size_(0), |
| 56 data_size_(0), |
| 57 background_pruning_pending_(false), |
| 58 task_runner_(task_runner) {} |
| 46 | 59 |
| 47 MultiBuffer::GlobalLRU::~GlobalLRU() { | 60 MultiBuffer::GlobalLRU::~GlobalLRU() { |
| 48 // By the time we're freed, all blocks should have been removed, | 61 // By the time we're freed, all blocks should have been removed, |
| 49 // and our sums should be zero. | 62 // and our sums should be zero. |
| 50 DCHECK(lru_.Empty()); | 63 DCHECK(lru_.Empty()); |
| 51 DCHECK_EQ(max_size_, 0); | 64 DCHECK_EQ(max_size_, 0); |
| 52 DCHECK_EQ(data_size_, 0); | 65 DCHECK_EQ(data_size_, 0); |
| 53 } | 66 } |
| 54 | 67 |
| 55 void MultiBuffer::GlobalLRU::Use(MultiBuffer* multibuffer, | 68 void MultiBuffer::GlobalLRU::Use(MultiBuffer* multibuffer, |
| 56 MultiBufferBlockId block_id) { | 69 MultiBufferBlockId block_id) { |
| 57 GlobalBlockId id(multibuffer, block_id); | 70 GlobalBlockId id(multibuffer, block_id); |
| 58 lru_.Use(id); | 71 lru_.Use(id); |
| 72 SchedulePrune(); |
| 59 } | 73 } |
| 60 | 74 |
| 61 void MultiBuffer::GlobalLRU::Insert(MultiBuffer* multibuffer, | 75 void MultiBuffer::GlobalLRU::Insert(MultiBuffer* multibuffer, |
| 62 MultiBufferBlockId block_id) { | 76 MultiBufferBlockId block_id) { |
| 63 GlobalBlockId id(multibuffer, block_id); | 77 GlobalBlockId id(multibuffer, block_id); |
| 64 lru_.Insert(id); | 78 lru_.Insert(id); |
| 79 SchedulePrune(); |
| 65 } | 80 } |
| 66 | 81 |
| 67 void MultiBuffer::GlobalLRU::Remove(MultiBuffer* multibuffer, | 82 void MultiBuffer::GlobalLRU::Remove(MultiBuffer* multibuffer, |
| 68 MultiBufferBlockId block_id) { | 83 MultiBufferBlockId block_id) { |
| 69 GlobalBlockId id(multibuffer, block_id); | 84 GlobalBlockId id(multibuffer, block_id); |
| 70 lru_.Remove(id); | 85 lru_.Remove(id); |
| 71 } | 86 } |
| 72 | 87 |
| 73 bool MultiBuffer::GlobalLRU::Contains(MultiBuffer* multibuffer, | 88 bool MultiBuffer::GlobalLRU::Contains(MultiBuffer* multibuffer, |
| 74 MultiBufferBlockId block_id) { | 89 MultiBufferBlockId block_id) { |
| 75 GlobalBlockId id(multibuffer, block_id); | 90 GlobalBlockId id(multibuffer, block_id); |
| 76 return lru_.Contains(id); | 91 return lru_.Contains(id); |
| 77 } | 92 } |
| 78 | 93 |
| 79 void MultiBuffer::GlobalLRU::IncrementDataSize(int64_t blocks) { | 94 void MultiBuffer::GlobalLRU::IncrementDataSize(int64_t blocks) { |
| 80 data_size_ += blocks; | 95 data_size_ += blocks; |
| 81 DCHECK_GE(data_size_, 0); | 96 DCHECK_GE(data_size_, 0); |
| 97 SchedulePrune(); |
| 82 } | 98 } |
| 83 | 99 |
| 84 void MultiBuffer::GlobalLRU::IncrementMaxSize(int64_t blocks) { | 100 void MultiBuffer::GlobalLRU::IncrementMaxSize(int64_t blocks) { |
| 85 max_size_ += blocks; | 101 max_size_ += blocks; |
| 86 DCHECK_GE(max_size_, 0); | 102 DCHECK_GE(max_size_, 0); |
| 103 SchedulePrune(); |
| 104 } |
| 105 |
| 106 bool MultiBuffer::GlobalLRU::Pruneable() const { |
| 107 return data_size_ > max_size_ && !lru_.Empty(); |
| 108 } |
| 109 |
| 110 void MultiBuffer::GlobalLRU::SchedulePrune() { |
| 111 if (Pruneable() && !background_pruning_pending_) { |
| 112 task_runner_->PostDelayedTask( |
| 113 FROM_HERE, base::Bind(&MultiBuffer::GlobalLRU::PruneTask, this), |
| 114 base::TimeDelta::FromSeconds(kBlockPruneInterval)); |
| 115 background_pruning_pending_ = true; |
| 116 } |
| 117 } |
| 118 |
| 119 void MultiBuffer::GlobalLRU::PruneTask() { |
| 120 background_pruning_pending_ = false; |
| 121 Prune(kBlocksPrunedPerInterval); |
| 122 SchedulePrune(); |
| 87 } | 123 } |
| 88 | 124 |
| 89 void MultiBuffer::GlobalLRU::Prune(int64_t max_to_free) { | 125 void MultiBuffer::GlobalLRU::Prune(int64_t max_to_free) { |
| 90 // We group the blocks by multibuffer so that we can free as many blocks as | 126 // We group the blocks by multibuffer so that we can free as many blocks as |
| 91 // possible in one call. This reduces the number of callbacks to clients | 127 // possible in one call. This reduces the number of callbacks to clients |
| 92 // when their available ranges change. | 128 // when their available ranges change. |
| 93 std::map<MultiBuffer*, std::vector<MultiBufferBlockId>> to_free; | 129 std::map<MultiBuffer*, std::vector<MultiBufferBlockId>> to_free; |
| 94 int64_t freed = 0; | 130 int64_t freed = 0; |
| 95 while (data_size_ - freed > max_size_ && !lru_.Empty() && | 131 while (data_size_ - freed > max_size_ && !lru_.Empty() && |
| 96 freed < max_to_free) { | 132 freed < max_to_free) { |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 } | 512 } |
| 477 | 513 |
| 478 void MultiBuffer::IncrementMaxSize(int32_t size) { | 514 void MultiBuffer::IncrementMaxSize(int32_t size) { |
| 479 max_size_ += size; | 515 max_size_ += size; |
| 480 lru_->IncrementMaxSize(size); | 516 lru_->IncrementMaxSize(size); |
| 481 DCHECK_GE(max_size_, 0); | 517 DCHECK_GE(max_size_, 0); |
| 482 // Pruning only happens when blocks are added. | 518 // Pruning only happens when blocks are added. |
| 483 } | 519 } |
| 484 | 520 |
| 485 } // namespace media | 521 } // namespace media |
| OLD | NEW |