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

Side by Side Diff: content/browser/download/download_file_impl.cc

Issue 10392111: Use ByteStream in downloads system to decouple source and sink. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added some histogram statistics. Created 8 years, 7 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/browser/download/download_file_impl.h" 5 #include "content/browser/download/download_file_impl.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h"
9 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/message_loop_proxy.h"
12 #include "base/time.h"
13 #include "content/browser/download/byte_stream.h"
10 #include "content/browser/download/download_create_info.h" 14 #include "content/browser/download/download_create_info.h"
15 #include "content/browser/download/download_interrupt_reasons_impl.h"
16 #include "content/browser/download/download_net_log_parameters.h"
11 #include "content/browser/power_save_blocker.h" 17 #include "content/browser/power_save_blocker.h"
12 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/download_manager.h" 19 #include "content/public/browser/download_manager.h"
20 #include "content/browser/download/download_stats.h"
21 #include "net/base/io_buffer.h"
14 22
15 using content::BrowserThread; 23 using content::BrowserThread;
16 using content::DownloadId; 24 using content::DownloadId;
17 using content::DownloadManager; 25 using content::DownloadManager;
18 26
19 const int kUpdatePeriodMs = 500; 27 const int kUpdatePeriodMs = 500;
20 28
21 DownloadFileImpl::DownloadFileImpl( 29 DownloadFileImpl::DownloadFileImpl(
22 const DownloadCreateInfo* info, 30 const DownloadCreateInfo* info,
31 scoped_ptr<content::ByteStreamOutput> pipe,
23 DownloadRequestHandleInterface* request_handle, 32 DownloadRequestHandleInterface* request_handle,
24 DownloadManager* download_manager, 33 DownloadManager* download_manager,
25 bool calculate_hash, 34 bool calculate_hash,
26 scoped_ptr<PowerSaveBlocker> power_save_blocker, 35 scoped_ptr<PowerSaveBlocker> power_save_blocker,
27 const net::BoundNetLog& bound_net_log) 36 const net::BoundNetLog& bound_net_log)
28 : file_(info->save_info.file_path, 37 : file_(info->save_info.file_path,
29 info->url(), 38 info->url(),
30 info->referrer_url, 39 info->referrer_url,
31 info->received_bytes, 40 info->received_bytes,
32 calculate_hash, 41 calculate_hash,
33 info->save_info.hash_state, 42 info->save_info.hash_state,
34 info->save_info.file_stream, 43 info->save_info.file_stream,
35 bound_net_log), 44 bound_net_log),
45 input_pipe_(pipe.Pass()),
36 id_(info->download_id), 46 id_(info->download_id),
37 request_handle_(request_handle), 47 request_handle_(request_handle),
38 download_manager_(download_manager), 48 download_manager_(download_manager),
49 bytes_seen_(0),
50 bound_net_log_(bound_net_log),
51 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
39 power_save_blocker_(power_save_blocker.Pass()) { 52 power_save_blocker_(power_save_blocker.Pass()) {
40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
41 } 54 }
42 55
43 DownloadFileImpl::~DownloadFileImpl() { 56 DownloadFileImpl::~DownloadFileImpl() {
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
58 // Prevent any future callbacks from reaching us.
59 if (input_pipe_.get())
60 input_pipe_->RegisterCallback(base::Closure());
45 } 61 }
46 62
47 // BaseFile delegated functions. 63 // BaseFile delegated functions.
48 net::Error DownloadFileImpl::Initialize() { 64 net::Error DownloadFileImpl::Initialize() {
49 update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>()); 65 update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
50 return file_.Initialize(); 66 net::Error result = file_.Initialize();
67 if (result != net::OK)
68 return result;
69
70 input_pipe_->RegisterCallback(
71 // Unretained is safe because the callback is nulled in the
72 // destructor.
73 base::Bind(&DownloadFileImpl::PipeActive, base::Unretained(this)));
74
75 download_start_ = base::TimeTicks::Now();
76 // Initial pull from the straw.
77 PipeActive();
78
79 return result;
51 } 80 }
52 81
53 net::Error DownloadFileImpl::AppendDataToFile(const char* data, 82 net::Error DownloadFileImpl::AppendDataToFile(const char* data,
54 size_t data_len) { 83 size_t data_len) {
55 if (!update_timer_->IsRunning()) { 84 if (!update_timer_->IsRunning()) {
56 update_timer_->Start(FROM_HERE, 85 update_timer_->Start(FROM_HERE,
57 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), 86 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
58 this, &DownloadFileImpl::SendUpdate); 87 this, &DownloadFileImpl::SendUpdate);
59 } 88 }
60 return file_.AppendDataToFile(data, data_len); 89 return file_.AppendDataToFile(data, data_len);
61 } 90 }
62 91
63 net::Error DownloadFileImpl::Rename(const FilePath& full_path) { 92 net::Error DownloadFileImpl::Rename(const FilePath& full_path) {
64 return file_.Rename(full_path); 93 return file_.Rename(full_path);
65 } 94 }
66 95
67 void DownloadFileImpl::Detach() { 96 void DownloadFileImpl::Detach() {
68 file_.Detach(); 97 file_.Detach();
69 } 98 }
70 99
71 void DownloadFileImpl::Cancel() { 100 void DownloadFileImpl::Cancel() {
72 file_.Cancel(); 101 file_.Cancel();
73 } 102 }
74 103
75 void DownloadFileImpl::Finish() {
76 file_.Finish();
77 update_timer_.reset();
78 }
79
80 void DownloadFileImpl::AnnotateWithSourceInformation() { 104 void DownloadFileImpl::AnnotateWithSourceInformation() {
81 file_.AnnotateWithSourceInformation(); 105 file_.AnnotateWithSourceInformation();
82 } 106 }
83 107
84 FilePath DownloadFileImpl::FullPath() const { 108 FilePath DownloadFileImpl::FullPath() const {
85 return file_.full_path(); 109 return file_.full_path();
86 } 110 }
87 111
88 bool DownloadFileImpl::InProgress() const { 112 bool DownloadFileImpl::InProgress() const {
89 return file_.in_progress(); 113 return file_.in_progress();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 return base::StringPrintf("{" 152 return base::StringPrintf("{"
129 " id_ = " "%d" 153 " id_ = " "%d"
130 " request_handle = %s" 154 " request_handle = %s"
131 " Base File = %s" 155 " Base File = %s"
132 " }", 156 " }",
133 id_.local(), 157 id_.local(),
134 request_handle_->DebugString().c_str(), 158 request_handle_->DebugString().c_str(),
135 file_.DebugString().c_str()); 159 file_.DebugString().c_str());
136 } 160 }
137 161
162 void DownloadFileImpl::PipeActive() {
163 base::TimeTicks start(base::TimeTicks::Now());
164 base::TimeTicks now;
165 scoped_refptr<net::IOBuffer> incoming_data;
166 size_t length = 0;
167 size_t total_length = 0;
168 size_t num_buffers = 0;
169 content::ByteStreamOutput::StreamState state(
170 content::ByteStreamOutput::STREAM_EMPTY);
171 content::DownloadInterruptReason reason =
172 content::DOWNLOAD_INTERRUPT_REASON_NONE;
173 base::TimeDelta delta(base::TimeDelta::FromMilliseconds(1000));
174
175 // Take care of any file local activity required.
176 do {
177 state = input_pipe_->Read(&incoming_data, &length);
178
179 net::Error result = net::OK;
180 switch (state) {
181 case content::ByteStreamOutput::STREAM_EMPTY:
182 break;
183 case content::ByteStreamOutput::STREAM_HAS_DATA:
184 {
185 ++num_buffers;
186 base::TimeTicks write_start(base::TimeTicks::Now());
187 result = AppendDataToFile(incoming_data.get()->data(), length);
188 disk_writes_time_ += (base::TimeTicks::Now() - write_start);
189 total_length += length;
190 reason = content::ConvertNetErrorToInterruptReason(
191 result, content::DOWNLOAD_INTERRUPT_FROM_DISK);
192 }
193 break;
194 case content::ByteStreamOutput::STREAM_COMPLETE:
195 {
196 reason = input_pipe_->GetStatus();
197 SendUpdate();
198 base::TimeTicks close_start(base::TimeTicks::Now());
199 file_.Finish();
200 base::TimeTicks now(base::TimeTicks::Now());
201 disk_writes_time_ += (now - close_start);
202 download_stats::RecordFileBandwidth(
203 bytes_seen_, disk_writes_time_, now - download_start_);
204 update_timer_.reset();
205 }
206 break;
207 default:
208 NOTREACHED();
209 break;
210 }
211 now = base::TimeTicks::Now();
212 } while (state == content::ByteStreamOutput::STREAM_HAS_DATA &&
213 reason == content::DOWNLOAD_INTERRUPT_REASON_NONE &&
214 now - start <= delta);
215
216 // If we're stopping to yield the thread, post a task so we come back.
217 if (state == content::ByteStreamOutput::STREAM_HAS_DATA &&
218 now - start > delta) {
219 BrowserThread::PostTask(
220 BrowserThread::FILE, FROM_HERE,
221 base::Bind(&DownloadFileImpl::PipeActive, weak_factory_.GetWeakPtr()));
222 }
223
224 if (total_length)
225 download_stats::RecordFileThreadReceiveBuffers(total_length);
226 bytes_seen_ += total_length;
227
228 download_stats::RecordContiguousWriteTime(now - start);
229
230 // Take care of communication with our controller.
231 if (reason != content::DOWNLOAD_INTERRUPT_REASON_NONE) {
232 // Error case for both upstream source and file write.
233 // Shut down processing and signal an error to our controller.
234 // Our controller will clean us up.
235 input_pipe_->RegisterCallback(base::Closure());
236 weak_factory_.InvalidateWeakPtrs();
237 if (download_manager_.get()) {
238 BrowserThread::PostTask(
239 BrowserThread::UI, FROM_HERE,
240 base::Bind(&DownloadManager::OnDownloadInterrupted,
241 download_manager_, id_.local(),
242 BytesSoFar(), GetHashState(), reason));
243 }
244 } else if (state == content::ByteStreamOutput::STREAM_COMPLETE) {
245 // Signal successful completion and shut down processing.
246 input_pipe_->RegisterCallback(base::Closure());
247 weak_factory_.InvalidateWeakPtrs();
248 if (download_manager_.get()) {
249 std::string hash;
250 if (!GetHash(&hash) || file_.IsEmptyHash(hash))
251 hash.clear();
252 BrowserThread::PostTask(
253 BrowserThread::UI, FROM_HERE,
254 base::Bind(&DownloadManager::OnResponseCompleted,
255 download_manager_, id_.local(),
256 BytesSoFar(), hash));
257 }
258 }
259 if (bound_net_log_.IsLoggingAllEvents()) {
260 bound_net_log_.AddEvent(
261 net::NetLog::TYPE_DOWNLOAD_PIPE_DRAINED,
262 make_scoped_refptr(new download_net_logs::FilePipeDrainedParameters(
263 total_length, num_buffers)));
264 }
265 }
266
138 void DownloadFileImpl::SendUpdate() { 267 void DownloadFileImpl::SendUpdate() {
139 if (download_manager_.get()) { 268 if (download_manager_.get()) {
140 BrowserThread::PostTask( 269 BrowserThread::PostTask(
141 BrowserThread::UI, FROM_HERE, 270 BrowserThread::UI, FROM_HERE,
142 base::Bind(&DownloadManager::UpdateDownload, 271 base::Bind(&DownloadManager::UpdateDownload,
143 download_manager_, id_.local(), 272 download_manager_, id_.local(),
144 BytesSoFar(), CurrentSpeed(), GetHashState())); 273 BytesSoFar(), CurrentSpeed(), GetHashState()));
145 } 274 }
146 } 275 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698