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

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

Powered by Google App Engine
This is Rietveld 408576698