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

Side by Side 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: this patchset allows memory reuse Created 6 years, 9 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h"
6
7 #include <algorithm>
8
9 #include "base/message_loop/message_loop.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13
14 using webkit_blob::FileStreamReader;
15
16 namespace {
17
18 const int kDesiredNumberOfBuffers = 2; // So we are always one buffer ahead.
19 const int kBufferSize = 1024*1024; // 1MB to minimize transaction costs.
20
21 } // namespace
22
23 ReadaheadFileStreamReader::ReadaheadFileStreamReader(FileStreamReader* source)
24 : source_(source),
25 source_error_(0),
26 current_offset_(0),
27 source_has_pending_read_(false),
28 weak_factory_(this) {
29 }
30
31 ReadaheadFileStreamReader::~ReadaheadFileStreamReader() {}
32
33 int ReadaheadFileStreamReader::Read(
34 net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) {
35 DCHECK(!pending_sink_buffer_.get());
36 DCHECK(pending_read_callback_.is_null());
37
38 ReadFromSourceIfNeeded(scoped_refptr<net::DrainableIOBuffer>());
39
40 int result = FinishReadFromCacheOrStoredError(buf, buf_len);
41
42 // We are waiting for an source read to complete, so save the request.
43 if (result == net::ERR_IO_PENDING) {
44 DCHECK(!pending_sink_buffer_.get());
45 DCHECK(pending_read_callback_.is_null());
46 pending_sink_buffer_ = new net::DrainableIOBuffer(buf, buf_len);
47 pending_read_callback_ = callback;
48 }
49
50 return result;
51 }
52
53 int64 ReadaheadFileStreamReader::GetLength(
54 const net::Int64CompletionCallback& callback) {
55 return source_->GetLength(callback);
56 }
57
58 int ReadaheadFileStreamReader::FinishReadFromCacheOrStoredError(
59 net::IOBuffer* buf, int buf_len) {
60 // If we don't have any ready cache, return the pending read code, or
61 // the stored error code.
62 if (buffers_.empty()) {
63 if (source_.get()) {
64 DCHECK(source_has_pending_read_);
65 return net::ERR_IO_PENDING;
66 } else {
67 return source_error_;
68 }
69 }
70
71 scoped_refptr<net::DrainableIOBuffer> sink(
72 new net::DrainableIOBuffer(buf, buf_len));
73
74 while (sink->BytesRemaining() > 0 && !buffers_.empty()) {
75 scoped_refptr<net::DrainableIOBuffer> source_buffer = buffers_.front();
76
77 DCHECK(source_buffer->BytesRemaining() > 0);
78
79 int copy_len = std::min(source_buffer->BytesRemaining(),
80 sink->BytesRemaining());
81 std::copy(source_buffer->data(), source_buffer->data() + copy_len,
82 sink->data());
83
84 source_buffer->DidConsume(copy_len);
85 sink->DidConsume(copy_len);
86
87 if (source_buffer->BytesRemaining() == 0) {
88 buffers_.pop();
89
90 // Get a new buffer to replace the one we just used up.
91 ReadFromSourceIfNeeded(source_buffer);
92 }
93 }
94
95 return sink->BytesConsumed();
96 }
97
98 void ReadaheadFileStreamReader::ReadFromSourceIfNeeded(
99 scoped_refptr<net::DrainableIOBuffer> reuse) {
100 if (!source_.get() || source_has_pending_read_ ||
101 buffers_.size() >= kDesiredNumberOfBuffers) {
102 return;
103 }
104
105 source_has_pending_read_ = true;
106
107 scoped_refptr<net::DrainableIOBuffer> buf;
108 if (reuse.get()) {
109 reuse->SetOffset(0);
110 reuse->SetSize(kBufferSize);
111 buf = reuse;
112 } else {
113 buf = new net::DrainableIOBuffer(
114 new net::IOBuffer(kBufferSize), kBufferSize);
115 }
116
117 int result = source_->Read(
118 buf,
119 kBufferSize,
120 base::Bind(&ReadaheadFileStreamReader::OnFinishReadFromSource,
121 weak_factory_.GetWeakPtr(), buf));
122
123 if (result != net::ERR_IO_PENDING) {
124 OnFinishReadFromSource(buf, result);
125 }
126 }
127
128 void ReadaheadFileStreamReader::OnFinishReadFromSource(
129 net::DrainableIOBuffer* buf, int result) {
130 DCHECK(result != net::ERR_IO_PENDING);
131 DCHECK(source_has_pending_read_);
132 source_has_pending_read_ = false;
133
134 // Either store the data read from |source_|, or store the error code.
135 if (result > 0) {
136 buf->SetSize(result);
137 buffers_.push(make_scoped_refptr(buf));
138 } else {
139 source_.reset();
140 source_error_ = result;
141 }
142
143 // If there's a read request waiting for the source FileStreamReader to
144 // finish reading, fulfill that request now from the cache or stored error.
145 if (pending_sink_buffer_.get()) {
146 DCHECK(!pending_read_callback_.is_null());
147
148 int result = FinishReadFromCacheOrStoredError(
149 pending_sink_buffer_, pending_sink_buffer_->BytesRemaining());
150 DCHECK_NE(net::ERR_IO_PENDING, result);
vandebo (ex-Chrome) 2014/03/04 21:55:12 What happens if you exhaust the current buffer and
tommycli 2014/03/04 23:03:44 Done.
151
152 // Free the pending callback before running it, as the callback often
153 // dispatches another read.
154 pending_sink_buffer_ = NULL;
155 net::CompletionCallback completion_callback = pending_read_callback_;
156 pending_read_callback_.Reset();
157 completion_callback.Run(result);
158 }
159 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698