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

Unified Diff: chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc

Issue 178473022: MTP Streaming: Readahead Buffer (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 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: chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc
diff --git a/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc b/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a10d53bf2f3d387b64c23784c59025faf02a08ef
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc
@@ -0,0 +1,162 @@
+// Copyright 2014 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.
+
+#include "chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h"
+
+#include <algorithm>
+
+#include "base/message_loop/message_loop.h"
+#include "base/numerics/safe_conversions.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+using webkit_blob::FileStreamReader;
+
+namespace {
+
+const int kDesiredNumberOfBuffers = 2; // So we are always one buffer ahead.
+const int kBufferSize = 1024*1024; // 1MB to minimize transaction costs.
+
+} // namespace
+
+// Represents an outstanding read request, waiting for the buffer to be filled
+// from the source FileStreamReader.
+struct ReadaheadFileStreamReader::Request {
vandebo (ex-Chrome) 2014/03/04 18:51:32 You only have one of these... There's no need to
tommycli 2014/03/04 21:14:58 Done.
+ Request(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback)
+ : buf(buf),
+ buf_len(buf_len),
+ callback(callback) {
+ }
+
+ ~Request() {}
+
+ scoped_refptr<net::IOBuffer> buf;
+ const int buf_len;
vandebo (ex-Chrome) 2014/03/04 18:51:32 Instead of storing the IOBuffer and length and wra
tommycli 2014/03/04 21:14:58 Done.
+ const net::CompletionCallback callback;
+};
+
+ReadaheadFileStreamReader::ReadaheadFileStreamReader(FileStreamReader* source)
+ : source_(source),
+ source_error_(0),
+ current_offset_(0),
+ source_has_pending_read_(false),
+ weak_factory_(this) {
+}
+
+ReadaheadFileStreamReader::~ReadaheadFileStreamReader() {}
+
+int ReadaheadFileStreamReader::Read(
+ net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) {
+ DCHECK(!pending_read_.get());
+
+ // Dispatch a request to fill up our buffers if needed.
+ if (source_.get() && !source_has_pending_read_ &&
vandebo (ex-Chrome) 2014/03/04 18:51:32 push these conditionals down into ReadFromSource(I
tommycli 2014/03/04 21:14:58 Done.
+ buffers_.size() < kDesiredNumberOfBuffers) {
+ ReadFromSource();
+ }
+
+ // Consume from our existing buffers and return immediately if possible.
vandebo (ex-Chrome) 2014/03/04 18:51:32 Maybe push lines 60-66 into ConsumeFromBuffer and
tommycli 2014/03/04 21:14:58 Done.
+ if (!buffers_.empty())
+ return ConsumeFromBuffer(buf, buf_len);
+
+ // Pass through the stored source error or EOF if existent.
+ if (!source_.get())
+ return source_error_;
+
+ // We are waiting for an source read to complete, so save the request.
+ DCHECK(!pending_read_.get());
+ pending_read_.reset(new Request(buf, buf_len, callback));
+ return net::ERR_IO_PENDING;
+}
+
+int64 ReadaheadFileStreamReader::GetLength(
+ const net::Int64CompletionCallback& callback) {
+ return source_->GetLength(callback);
+}
+
+int ReadaheadFileStreamReader::ConsumeFromBuffer(net::IOBuffer* buf,
+ int buf_len) {
+ DCHECK(!buffers_.empty());
+
+ // |buf| continues to exist after |sink| goes out of scope.
vandebo (ex-Chrome) 2014/03/04 18:51:32 This comment doesn't seem necessary, since sink li
tommycli 2014/03/04 21:14:58 Done.
+ scoped_refptr<net::DrainableIOBuffer> sink(
+ new net::DrainableIOBuffer(buf, buf_len));
+
+ while (sink->BytesRemaining() > 0 && !buffers_.empty()) {
+ net::DrainableIOBuffer* head_buffer = buffers_.front().get();
vandebo (ex-Chrome) 2014/03/04 18:51:32 If you're calling the destination sink, might as w
tommycli 2014/03/04 21:14:58 Done.
+
+ DCHECK(head_buffer->BytesRemaining() > 0);
+
+ int copy_len = std::min(head_buffer->BytesRemaining(),
+ sink->BytesRemaining());
+ std::copy(head_buffer->data(), head_buffer->data() + copy_len,
+ sink->data());
+
+ head_buffer->DidConsume(copy_len);
+ sink->DidConsume(copy_len);
+
+ if (head_buffer->BytesRemaining() == 0) {
+ buffers_.pop();
vandebo (ex-Chrome) 2014/03/04 18:51:32 This is unfortunate - we're going to free a meg of
tommycli 2014/03/04 21:14:58 Last patchset adds something to reuse the just-exh
+
+ // Get a new buffer to replace the one we just used up.
+ if (!source_has_pending_read_ && source_.get())
+ ReadFromSource();
+ }
+ }
+
+ return sink->BytesConsumed();
+}
+
+void ReadaheadFileStreamReader::ReadFromSource() {
+ DCHECK(!source_has_pending_read_);
+ source_has_pending_read_ = true;
+
+ // We don't create the DrainableIOBuffer wrapper until the callback, when
+ // we know the size of the content written to the buffer.
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufferSize));
+ int result = source_->Read(
+ buf,
+ kBufferSize,
+ base::Bind(&ReadaheadFileStreamReader::OnFinishReadFromSource,
+ weak_factory_.GetWeakPtr(), buf));
+
+ if (result != net::ERR_IO_PENDING) {
+ OnFinishReadFromSource(buf, result);
+ }
+}
+
+void ReadaheadFileStreamReader::OnFinishReadFromSource(net::IOBuffer* buf,
+ int result) {
+ DCHECK(result != net::ERR_IO_PENDING);
+ DCHECK(source_has_pending_read_);
+ source_has_pending_read_ = false;
+
+ if (result <= 0) {
+ source_.reset();
+ source_error_ = result;
+
+ // If there's a read waiting on this source-read, finish it with the error.
+ if (pending_read_.get()) {
vandebo (ex-Chrome) 2014/03/04 18:51:32 If you push lines 65 and 66 into ComsumeFromBuffer
tommycli 2014/03/04 21:14:58 Done.
+ pending_read_->callback.Run(result);
+ pending_read_.reset();
+ }
+
+ return;
+ }
+
+ scoped_refptr<net::DrainableIOBuffer> drainable_buffer(
+ new net::DrainableIOBuffer(buf, result));
+ buffers_.push(drainable_buffer);
+
+ // If there's a read request waiting for the source FileStreamReader to
+ // finish reading, fulfill that request now.
+ if (pending_read_.get()) {
+ // Free up pending read immediately, as the read completion callback often
+ // dispatches another read.
+ scoped_ptr<Request> request(pending_read_.Pass());
+
+ request->callback.Run(ConsumeFromBuffer(request->buf, request->buf_len));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698