Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Unified Diff: media/blink/multibuffer.h

Issue 1165903002: Multi reader/writer cache/buffer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: lru unit tests Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/blink/multibuffer.h
diff --git a/media/blink/multibuffer.h b/media/blink/multibuffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..fbce55497ac2817bca170e66af1329d0cae3e543
--- /dev/null
+++ b/media/blink/multibuffer.h
@@ -0,0 +1,222 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BLINK_MULTIBUFFER_H_
+#define MEDIA_BLINK_MULTIBUFFER_H_
+
+#include <stdint.h>
+
+#include <map>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "media/base/data_buffer.h"
+#include "media/blink/lru.h"
+#include "media/blink/rangemap.h"
+#include "media/blink/waiter_index.h"
+
+namespace media {
+
+const int kMaxFreesPerAdd = 10;
+const int kMaxWaitForWriterOffset = 5;
+
+// MultiBuffers are multi-reader multi-writer cache/buffers with
+// prefetching and pinning. Data is stored internally in ref-counted
+// blocks of identical size. |block_size_shift| is log2 of the block
+// size.
+class MultiBuffer {
liberato (no reviews please) 2015/06/09 15:00:54 the name "MultiBuffer" is a little confusing. may
hubbe 2015/06/09 21:23:48 It's meant to replace multiple preloading buffers.
+ public:
+ explicit MultiBuffer(int32_t block_size_shift);
+ virtual ~MultiBuffer();
+
+ typedef std::map<int32_t, scoped_refptr<DataBuffer> > DataMap;
+
+ // Adds a writer. This writer becomes responsible
+ // for writing data at |pos| and forwards.
+ // Takes ownership of |writer|.
+ void AddWriter(int32_t pos, Waiter* writer);
liberato (no reviews please) 2015/06/09 15:00:53 are all the positions in byte offsets or block off
hubbe 2015/06/09 21:23:48 Yes. (the new typedef makes that clear)
+
+ // Remove a writer.
+ // Caller takes ownership of |writer|.
+ void RemoveWriter(int32_t pos, Waiter* writer);
+
+ // Wait for block |pos| to become available.
+ // Starts new Writers as needed.
+ void WaitFor(int32_t pos, Waiter* reader);
+
+ // Let the buffer that we're going to want to read
+ // block |pos|, but we're ok with the current level
+ // of buffering, so no worries.
+ void DeferredWaitFor(int32_t pos, Waiter* reader);
liberato (no reviews please) 2015/06/09 15:00:53 why do we need WaitFor vs DeferredWaitFor? should
hubbe 2015/06/09 21:23:48 This class doesn't know about any preload specs.
+
+ // Stop waiting for block |pos|.
+ // Often followed by a call to WaitFor(pos + 1, ...);
+ void StopWaitFor(int32_t pos, Waiter* reader);
+
+ // Returns true if block |pos| is available in the cache.
+ bool Contains(int32_t pos) const;
+
+ // Returns true if some reader is currently waiting for
+ // block |pos|.
+ bool WantNow(int32_t pos) const;
+
+ // Returns true if some reader is will want block |pos| soon.
+ bool WantSoon(int32_t pos) const;
+
+ // Add a data block to the cache, notifying readers as
+ // needed and prune old blocks if cache is too big.
+ void AddData(int32_t pos, scoped_refptr<DataBuffer> data);
+
+ // Change the pin count for a range of data blocks.
+ // Note that blocks do not have to be present in the
+ // cache to be pinned.
+ // Examples:
+ // Pin block 3, 4 & 5: PinRange(3, 6, 1);
+ // Unpin block 4 & 5: PinRange(4, 6, -1);
+ void PinRange(int32_t from, int32_t to, int32_t howmuch);
+
+ // Increment max cache size by |size|.
+ void IncrementMaxSize(int32_t size);
+
+ // Accessors.
+ const DataMap& map() const { return data_; }
+ int32_t block_size_shift() const { return block_size_shift_; }
+
+ protected:
+ // Start a new writer at |pos|.
+ // Should call AddWriter().
+ virtual void StartWriter(int32_t pos) = 0;
liberato (no reviews please) 2015/06/09 15:00:53 MultiBuffer::StartWriter => new Writer => MultiBuf
hubbe 2015/06/09 21:23:48 I could break out the cache itself into something
+
+ private:
+ // Free elements from cache if needed and possible.
+ void Prune();
+
+ // Current number of blocks.
+ int32_t size_;
+
+ // Max number of blocks.
+ int32_t max_size_;
+
+ // log2 of block size.
+ int32_t block_size_shift_;
+
+ // Stores the actual data.
+ DataMap data_;
+
+ // Keeps track of readers waiting for data.
+ WaiterIndex reader_index_;
+
+ // Keeps track of readers that will want data soon.
+ WaiterIndex deferred_reader_index_;
+
+ // Keeps track of what writers are waiting.
+ WaiterIndex writer_index_;
+
+ // The LRU should contain all blocks which are not pinned.
+ LRU<int32_t> lru_;
+
+ // Keeps track of what blocks are pinned. If block p is pinned,
+ // then pinned_[p] > 0. Pinned blocks cannot be freed and are
+ // not present in |lru_|.
+ RangeMap<int32_t, int32_t> pinned_;
+};
+
+// Typically, calling MultiBuffer::StartWriter() will
+// instantiate a subclass of this class. Writers are
+// responsible for writing data into the cache.
+// Writers are owned by the MultiBuffer.
+class MultiBufferWriter : public Waiter {
liberato (no reviews please) 2015/06/09 15:00:54 this might be better off in another .h
hubbe 2015/06/09 21:23:48 They really are meant to be used as a set. Origina
+ MultiBufferWriter(MultiBuffer* multibuffer, int32_t pos);
+
+ ~MultiBufferWriter() override;
+
+ // Waiter implementation.
+ void Continue() override;
+
+ protected:
+ virtual void SetDeferred(bool deferred) = 0;
+
+ // Write |data| to |pos_| in the cache and update |pos_|.
+ void Write(scoped_refptr<DataBuffer> data);
+
+ int32_t pos_;
+ MultiBuffer* multibuffer_;
+};
+
+// Wrapper for MultiBuffer that offers a simple byte-reading
+// interface with prefetch.
+class MultiBufferReader : public Waiter {
+ public:
+ MultiBufferReader(MultiBuffer* multibuffer,
+ int64_t start,
+ int64_t end,
+ int64_t preload,
+ int64_t max_buffer_forward,
+ int64_t max_buffer_backward);
+
+ ~MultiBufferReader() override;
+
+ // Returns number of bytes available for reading.
+ // If the actual number of bytes available is greater
+ // than |preload|, then it might return a number between
+ // |preload| and and the actual number.
+ int64_t Available() const;
+
+ // Seek to a different position.
+ void Seek(int64_t pos);
+
+ // Tries to read |len| bytes and advance position.
+ // Returns true if successful.
+ bool TryRead(unsigned char *data, int64_t len);
+
+ // Wait until |len| bytes are available for reading.
+ void Wait(int64_t len, base::Closure cb);
+
+ // Waiter implementation.
+ void Continue() override;
+
+ private:
+ // Returns the block for a particular byte position.
+ int32_t block(int64_t byte_pos) const;
+
+ // Returns the block for a particular byte position, rounding up.
+ int32_t block_ciel(int64_t byte_pos) const;
+
+ // Check if wait operation can complete now.
+ void CheckWait();
+
+ // Increment preload position if data has been added to the buffer.
+ void IncrementPreloadPos();
+
+ // We're not interested in reading past this position.
+ const int64_t end_;
+
+ // Defer reading once we have this much data.
+ const int64_t preload_;
+
+ // Pin this much data in the cache from the current position.
+ const int64_t max_buffer_forward_;
+ const int64_t max_buffer_backward_;
+
+ // Current position in bytes.
+ int64_t pos_;
+
+ // [block(pos_)..preload_pos_) are known to be in the cache.
+ // preload_pos_ is only allowed to point to a filled
+ // cache position if it is equal to end_ or pos_+preload_.
+ // This is a pointer to a slot in the cache, so the unit is
+ // blocks.
+ int32_t preload_pos_;
+
+ // When Available() > current_wait_size_ we call cb_.
+ int64_t current_wait_size_;
+ base::Closure cb_;
+
+ // The multibuffer we're wrapping, not owned.
+ MultiBuffer* multibuffer_;
+};
+
+} // namespace media
+
+#endif // MEDIA_BLINK_MULTIBUFFER_H_

Powered by Google App Engine
This is Rietveld 408576698