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

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: change kDesiredNumberOfBuffers to unsigned 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
« no previous file with comments | « chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..e2acb94b72f41a97b5a90c2ee9dc0e6443915c82
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc
@@ -0,0 +1,146 @@
+// 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 size_t kDesiredNumberOfBuffers = 2; // So we are always one buffer ahead.
+const int kBufferSize = 1024*1024; // 1MB to minimize transaction costs.
+
+} // namespace
+
+ReadaheadFileStreamReader::ReadaheadFileStreamReader(FileStreamReader* source)
+ : source_(source),
+ source_error_(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_sink_buffer_.get());
+ DCHECK(pending_read_callback_.is_null());
+
+ ReadFromSourceIfNeeded();
+
+ scoped_refptr<net::DrainableIOBuffer> sink =
+ new net::DrainableIOBuffer(buf, buf_len);
+ int result = FinishReadFromCacheOrStoredError(sink);
+
+ // We are waiting for an source read to complete, so save the request.
+ if (result == net::ERR_IO_PENDING) {
+ DCHECK(!pending_sink_buffer_.get());
+ DCHECK(pending_read_callback_.is_null());
+ pending_sink_buffer_ = sink;
+ pending_read_callback_ = callback;
+ }
+
+ return result;
+}
+
+int64 ReadaheadFileStreamReader::GetLength(
+ const net::Int64CompletionCallback& callback) {
+ return source_->GetLength(callback);
+}
+
+int ReadaheadFileStreamReader::FinishReadFromCacheOrStoredError(
+ net::DrainableIOBuffer* sink) {
+ // If we don't have any ready cache, return the pending read code, or
+ // the stored error code.
+ if (buffers_.empty()) {
+ if (source_.get()) {
+ DCHECK(source_has_pending_read_);
+ return net::ERR_IO_PENDING;
+ } else {
+ return source_error_;
+ }
+ }
+
+ while (sink->BytesRemaining() > 0 && !buffers_.empty()) {
+ net::DrainableIOBuffer* source_buffer = buffers_.front().get();
+
+ DCHECK(source_buffer->BytesRemaining() > 0);
+
+ int copy_len = std::min(source_buffer->BytesRemaining(),
+ sink->BytesRemaining());
+ std::copy(source_buffer->data(), source_buffer->data() + copy_len,
+ sink->data());
+
+ source_buffer->DidConsume(copy_len);
+ sink->DidConsume(copy_len);
+
+ if (source_buffer->BytesRemaining() == 0) {
+ buffers_.pop();
+
+ // Get a new buffer to replace the one we just used up.
+ ReadFromSourceIfNeeded();
+ }
+ }
+
+ return sink->BytesConsumed();
+}
+
+void ReadaheadFileStreamReader::ReadFromSourceIfNeeded() {
+ if (!source_.get() || source_has_pending_read_ ||
+ buffers_.size() >= kDesiredNumberOfBuffers) {
+ return;
+ }
+
+ source_has_pending_read_ = true;
+
+ 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;
+
+ // Either store the data read from |source_|, or store the error code.
+ if (result > 0) {
+ scoped_refptr<net::DrainableIOBuffer> drainable_buffer(
+ new net::DrainableIOBuffer(buf, result));
+ buffers_.push(drainable_buffer);
+ ReadFromSourceIfNeeded();
+ } else {
+ source_.reset();
+ source_error_ = result;
+ }
+
+ // If there's a read request waiting for the source FileStreamReader to
+ // finish reading, fulfill that request now from the cache or stored error.
+ if (pending_sink_buffer_.get()) {
+ DCHECK(!pending_read_callback_.is_null());
+
+ // Free the pending callback before running it, as the callback often
+ // dispatches another read.
+ scoped_refptr<net::DrainableIOBuffer> sink = pending_sink_buffer_;
+ pending_sink_buffer_ = NULL;
+ net::CompletionCallback completion_callback = pending_read_callback_;
+ pending_read_callback_.Reset();
+
+ completion_callback.Run(FinishReadFromCacheOrStoredError(sink));
+ }
+}
« no previous file with comments | « chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698