OLD | NEW |
---|---|
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 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
15 #include "base/values.h" | 15 #include "base/values.h" |
16 #include "content/browser/byte_stream.h" | 16 #include "content/browser/byte_stream.h" |
17 #include "content/browser/download/download_create_info.h" | 17 #include "content/browser/download/download_create_info.h" |
18 #include "content/browser/download/download_destination_observer.h" | 18 #include "content/browser/download/download_destination_observer.h" |
19 #include "content/browser/download/download_interrupt_reasons_impl.h" | 19 #include "content/browser/download/download_interrupt_reasons_impl.h" |
20 #include "content/browser/download/download_net_log_parameters.h" | 20 #include "content/browser/download/download_net_log_parameters.h" |
21 #include "content/browser/download/download_stats.h" | 21 #include "content/browser/download/download_stats.h" |
22 #include "content/browser/download/download_task_runner.h" | |
gab
2017/06/22 16:03:59
rm (see below)
Sigurður Ásgeirsson
2017/06/22 18:47:28
Done.
| |
22 #include "content/browser/download/parallel_download_utils.h" | 23 #include "content/browser/download/parallel_download_utils.h" |
23 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
24 #include "crypto/secure_hash.h" | 25 #include "crypto/secure_hash.h" |
25 #include "crypto/sha2.h" | 26 #include "crypto/sha2.h" |
26 #include "net/base/io_buffer.h" | 27 #include "net/base/io_buffer.h" |
27 #include "net/log/net_log.h" | 28 #include "net/log/net_log.h" |
28 #include "net/log/net_log_event_type.h" | 29 #include "net/log/net_log_event_type.h" |
29 #include "net/log/net_log_source.h" | 30 #include "net/log/net_log_source.h" |
30 #include "net/log/net_log_source_type.h" | 31 #include "net/log/net_log_source_type.h" |
31 | 32 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
113 weak_factory_(this) { | 114 weak_factory_(this) { |
114 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( | 115 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( |
115 save_info_->offset, save_info_->length, std::move(stream_reader)); | 116 save_info_->offset, save_info_->length, std::move(stream_reader)); |
116 | 117 |
117 download_item_net_log.AddEvent( | 118 download_item_net_log.AddEvent( |
118 net::NetLogEventType::DOWNLOAD_FILE_CREATED, | 119 net::NetLogEventType::DOWNLOAD_FILE_CREATED, |
119 net_log_.source().ToEventParametersCallback()); | 120 net_log_.source().ToEventParametersCallback()); |
120 net_log_.BeginEvent( | 121 net_log_.BeginEvent( |
121 net::NetLogEventType::DOWNLOAD_FILE_ACTIVE, | 122 net::NetLogEventType::DOWNLOAD_FILE_ACTIVE, |
122 download_item_net_log.source().ToEventParametersCallback()); | 123 download_item_net_log.source().ToEventParametersCallback()); |
124 | |
125 DETACH_FROM_SEQUENCE(sequence_checker_); | |
123 } | 126 } |
124 | 127 |
125 DownloadFileImpl::~DownloadFileImpl() { | 128 DownloadFileImpl::~DownloadFileImpl() { |
126 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 129 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
130 | |
127 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ACTIVE); | 131 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ACTIVE); |
128 } | 132 } |
129 | 133 |
130 void DownloadFileImpl::Initialize( | 134 void DownloadFileImpl::Initialize( |
131 const InitializeCallback& initialize_callback, | 135 const InitializeCallback& initialize_callback, |
132 const CancelRequestCallback& cancel_request_callback, | 136 const CancelRequestCallback& cancel_request_callback, |
133 const DownloadItem::ReceivedSlices& received_slices, | 137 const DownloadItem::ReceivedSlices& received_slices, |
134 bool is_parallelizable) { | 138 bool is_parallelizable) { |
135 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 139 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
136 | 140 |
137 update_timer_.reset(new base::RepeatingTimer()); | 141 update_timer_.reset(new base::RepeatingTimer()); |
138 int64_t bytes_so_far = 0; | 142 int64_t bytes_so_far = 0; |
139 cancel_request_callback_ = cancel_request_callback; | 143 cancel_request_callback_ = cancel_request_callback; |
140 received_slices_ = received_slices; | 144 received_slices_ = received_slices; |
141 if (IsSparseFile()) { | 145 if (IsSparseFile()) { |
142 for (const auto& received_slice : received_slices_) { | 146 for (const auto& received_slice : received_slices_) { |
143 bytes_so_far += received_slice.received_bytes; | 147 bytes_so_far += received_slice.received_bytes; |
144 } | 148 } |
145 } else { | 149 } else { |
(...skipping 23 matching lines...) Expand all Loading... | |
169 | 173 |
170 // Initial pull from the straw from all source streams. | 174 // Initial pull from the straw from all source streams. |
171 for (auto& source_stream : source_streams_) | 175 for (auto& source_stream : source_streams_) |
172 RegisterAndActivateStream(source_stream.second.get()); | 176 RegisterAndActivateStream(source_stream.second.get()); |
173 } | 177 } |
174 | 178 |
175 void DownloadFileImpl::AddByteStream( | 179 void DownloadFileImpl::AddByteStream( |
176 std::unique_ptr<ByteStreamReader> stream_reader, | 180 std::unique_ptr<ByteStreamReader> stream_reader, |
177 int64_t offset, | 181 int64_t offset, |
178 int64_t length) { | 182 int64_t length) { |
179 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 183 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
180 | 184 |
181 source_streams_[offset] = | 185 source_streams_[offset] = |
182 base::MakeUnique<SourceStream>(offset, length, std::move(stream_reader)); | 186 base::MakeUnique<SourceStream>(offset, length, std::move(stream_reader)); |
183 | 187 |
184 // There are writers at different offsets now, create the received slices | 188 // There are writers at different offsets now, create the received slices |
185 // vector if necessary. | 189 // vector if necessary. |
186 if (received_slices_.empty() && TotalBytesReceived() > 0) { | 190 if (received_slices_.empty() && TotalBytesReceived() > 0) { |
187 size_t index = AddOrMergeReceivedSliceIntoSortedArray( | 191 size_t index = AddOrMergeReceivedSliceIntoSortedArray( |
188 DownloadItem::ReceivedSlice(0, TotalBytesReceived()), received_slices_); | 192 DownloadItem::ReceivedSlice(0, TotalBytesReceived()), received_slices_); |
189 DCHECK_EQ(index, 0u); | 193 DCHECK_EQ(index, 0u); |
190 } | 194 } |
191 // If the file is initialized, start to write data, or wait until file opened. | 195 // If the file is initialized, start to write data, or wait until file opened. |
192 if (file_.in_progress()) | 196 if (file_.in_progress()) |
193 RegisterAndActivateStream(source_streams_[offset].get()); | 197 RegisterAndActivateStream(source_streams_[offset].get()); |
194 } | 198 } |
195 | 199 |
196 DownloadInterruptReason DownloadFileImpl::WriteDataToFile(int64_t offset, | 200 DownloadInterruptReason DownloadFileImpl::WriteDataToFile(int64_t offset, |
197 const char* data, | 201 const char* data, |
198 size_t data_len) { | 202 size_t data_len) { |
199 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 203 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
204 | |
200 WillWriteToDisk(data_len); | 205 WillWriteToDisk(data_len); |
201 return file_.WriteDataToFile(offset, data, data_len); | 206 return file_.WriteDataToFile(offset, data, data_len); |
202 } | 207 } |
203 | 208 |
204 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, | 209 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, |
205 size_t bytes_available_to_write, | 210 size_t bytes_available_to_write, |
206 size_t* bytes_to_write) { | 211 size_t* bytes_to_write) { |
207 if (source_stream->length() == kNoBytesToWrite) { | 212 if (source_stream->length() == kNoBytesToWrite) { |
208 *bytes_to_write = 0; | 213 *bytes_to_write = 0; |
209 return true; | 214 return true; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
267 return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) * | 272 return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) * |
268 (1 << attempt_number); | 273 (1 << attempt_number); |
269 } | 274 } |
270 | 275 |
271 bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) { | 276 bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) { |
272 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR; | 277 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR; |
273 } | 278 } |
274 | 279 |
275 void DownloadFileImpl::RenameWithRetryInternal( | 280 void DownloadFileImpl::RenameWithRetryInternal( |
276 std::unique_ptr<RenameParameters> parameters) { | 281 std::unique_ptr<RenameParameters> parameters) { |
277 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 282 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
278 | 283 |
279 base::FilePath new_path = parameters->new_path; | 284 base::FilePath new_path = parameters->new_path; |
280 | 285 |
281 if ((parameters->option & UNIQUIFY) && new_path != file_.full_path()) { | 286 if ((parameters->option & UNIQUIFY) && new_path != file_.full_path()) { |
282 int uniquifier = | 287 int uniquifier = |
283 base::GetUniquePathNumber(new_path, base::FilePath::StringType()); | 288 base::GetUniquePathNumber(new_path, base::FilePath::StringType()); |
284 if (uniquifier > 0) | 289 if (uniquifier > 0) |
285 new_path = new_path.InsertBeforeExtensionASCII( | 290 new_path = new_path.InsertBeforeExtensionASCII( |
286 base::StringPrintf(" (%d)", uniquifier)); | 291 base::StringPrintf(" (%d)", uniquifier)); |
287 } | 292 } |
288 | 293 |
289 DownloadInterruptReason reason = file_.Rename(new_path); | 294 DownloadInterruptReason reason = file_.Rename(new_path); |
290 | 295 |
291 // Attempt to retry the rename if possible. If the rename failed and the | 296 // Attempt to retry the rename if possible. If the rename failed and the |
292 // subsequent open also failed, then in_progress() would be false. We don't | 297 // subsequent open also failed, then in_progress() would be false. We don't |
293 // try to retry renames if the in_progress() was false to begin with since we | 298 // try to retry renames if the in_progress() was false to begin with since we |
294 // have less assurance that the file at file_.full_path() was the one we were | 299 // have less assurance that the file at file_.full_path() was the one we were |
295 // working with. | 300 // working with. |
296 if (ShouldRetryFailedRename(reason) && file_.in_progress() && | 301 if (ShouldRetryFailedRename(reason) && file_.in_progress() && |
297 parameters->retries_left > 0) { | 302 parameters->retries_left > 0) { |
298 int attempt_number = kMaxRenameRetries - parameters->retries_left; | 303 int attempt_number = kMaxRenameRetries - parameters->retries_left; |
299 --parameters->retries_left; | 304 --parameters->retries_left; |
300 if (parameters->time_of_first_failure.is_null()) | 305 if (parameters->time_of_first_failure.is_null()) |
301 parameters->time_of_first_failure = base::TimeTicks::Now(); | 306 parameters->time_of_first_failure = base::TimeTicks::Now(); |
302 BrowserThread::PostDelayedTask( | 307 GetDownloadTaskRunner()->PostDelayedTask( |
303 BrowserThread::FILE, | |
304 FROM_HERE, | 308 FROM_HERE, |
305 base::Bind(&DownloadFileImpl::RenameWithRetryInternal, | 309 base::Bind(&DownloadFileImpl::RenameWithRetryInternal, |
306 weak_factory_.GetWeakPtr(), | 310 weak_factory_.GetWeakPtr(), |
307 base::Passed(std::move(parameters))), | 311 base::Passed(std::move(parameters))), |
308 GetRetryDelayForFailedRename(attempt_number)); | 312 GetRetryDelayForFailedRename(attempt_number)); |
309 return; | 313 return; |
310 } | 314 } |
311 | 315 |
312 if (!parameters->time_of_first_failure.is_null()) | 316 if (!parameters->time_of_first_failure.is_null()) |
313 RecordDownloadFileRenameResultAfterRetry( | 317 RecordDownloadFileRenameResultAfterRetry( |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
461 break; | 465 break; |
462 } | 466 } |
463 now = base::TimeTicks::Now(); | 467 now = base::TimeTicks::Now(); |
464 } while (state == ByteStreamReader::STREAM_HAS_DATA && | 468 } while (state == ByteStreamReader::STREAM_HAS_DATA && |
465 reason == DOWNLOAD_INTERRUPT_REASON_NONE && now - start <= delta && | 469 reason == DOWNLOAD_INTERRUPT_REASON_NONE && now - start <= delta && |
466 !should_terminate); | 470 !should_terminate); |
467 | 471 |
468 // If we're stopping to yield the thread, post a task so we come back. | 472 // If we're stopping to yield the thread, post a task so we come back. |
469 if (state == ByteStreamReader::STREAM_HAS_DATA && now - start > delta && | 473 if (state == ByteStreamReader::STREAM_HAS_DATA && now - start > delta && |
470 !should_terminate) { | 474 !should_terminate) { |
471 BrowserThread::PostTask( | 475 GetDownloadTaskRunner()->PostTask( |
gab
2017/06/22 16:03:59
Use SequencedTaskRunnerHandle::Get() here instead
Sigurður Ásgeirsson
2017/06/22 18:47:28
Nice, this also cuts down on the sequence hopping
| |
472 BrowserThread::FILE, FROM_HERE, | 476 FROM_HERE, base::Bind(&DownloadFileImpl::StreamActive, |
473 base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr(), | 477 weak_factory_.GetWeakPtr(), source_stream)); |
474 source_stream)); | |
475 } | 478 } |
476 | 479 |
477 if (total_incoming_data_size) | 480 if (total_incoming_data_size) |
478 RecordFileThreadReceiveBuffers(num_buffers); | 481 RecordFileThreadReceiveBuffers(num_buffers); |
479 | 482 |
480 RecordContiguousWriteTime(now - start); | 483 RecordContiguousWriteTime(now - start); |
481 | 484 |
482 // Take care of communication with our observer. | 485 // Take care of communication with our observer. |
483 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { | 486 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
484 HandleStreamError(source_stream, reason); | 487 HandleStreamError(source_stream, reason); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
519 } | 522 } |
520 } | 523 } |
521 if (net_log_.IsCapturing()) { | 524 if (net_log_.IsCapturing()) { |
522 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_STREAM_DRAINED, | 525 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_STREAM_DRAINED, |
523 base::Bind(&FileStreamDrainedNetLogCallback, | 526 base::Bind(&FileStreamDrainedNetLogCallback, |
524 total_incoming_data_size, num_buffers)); | 527 total_incoming_data_size, num_buffers)); |
525 } | 528 } |
526 } | 529 } |
527 | 530 |
528 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { | 531 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { |
529 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 532 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
533 | |
530 ByteStreamReader* stream_reader = source_stream->stream_reader(); | 534 ByteStreamReader* stream_reader = source_stream->stream_reader(); |
531 if (stream_reader) { | 535 if (stream_reader) { |
532 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, | 536 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, |
533 weak_factory_.GetWeakPtr(), | 537 weak_factory_.GetWeakPtr(), |
534 source_stream)); | 538 source_stream)); |
535 // Truncate |source_stream|'s length if necessary. | 539 // Truncate |source_stream|'s length if necessary. |
536 for (const auto& received_slice : received_slices_) { | 540 for (const auto& received_slice : received_slices_) { |
537 source_stream->TruncateLengthWithWrittenDataBlock( | 541 source_stream->TruncateLengthWithWrittenDataBlock( |
538 received_slice.offset, received_slice.received_bytes); | 542 received_slice.offset, received_slice.received_bytes); |
539 } | 543 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
609 if (slices_to_download.size() > 1) { | 613 if (slices_to_download.size() > 1) { |
610 // If there are 1 or more holes in the file, download is not finished. | 614 // If there are 1 or more holes in the file, download is not finished. |
611 // Some streams might not have been added to |source_streams_| yet. | 615 // Some streams might not have been added to |source_streams_| yet. |
612 return false; | 616 return false; |
613 } | 617 } |
614 return TotalBytesReceived() == potential_file_length_; | 618 return TotalBytesReceived() == potential_file_length_; |
615 } | 619 } |
616 | 620 |
617 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, | 621 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
618 DownloadInterruptReason reason) { | 622 DownloadInterruptReason reason) { |
619 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 623 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
624 | |
620 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 625 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
621 source_stream->set_finished(true); | 626 source_stream->set_finished(true); |
622 num_active_streams_--; | 627 num_active_streams_--; |
623 | 628 |
624 bool can_recover_from_error = (source_stream->length() == kNoBytesToWrite); | 629 bool can_recover_from_error = (source_stream->length() == kNoBytesToWrite); |
625 | 630 |
626 if (IsSparseFile() && !can_recover_from_error) { | 631 if (IsSparseFile() && !can_recover_from_error) { |
627 // If a neighboring stream request is available, check if it can help | 632 // If a neighboring stream request is available, check if it can help |
628 // download all the data left by |source stream| or has already done so. We | 633 // download all the data left by |source stream| or has already done so. We |
629 // want to avoid the situation that a server always fail additional requests | 634 // want to avoid the situation that a server always fail additional requests |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
726 const base::FilePath& new_path, | 731 const base::FilePath& new_path, |
727 const RenameCompletionCallback& completion_callback) | 732 const RenameCompletionCallback& completion_callback) |
728 : option(option), | 733 : option(option), |
729 new_path(new_path), | 734 new_path(new_path), |
730 retries_left(kMaxRenameRetries), | 735 retries_left(kMaxRenameRetries), |
731 completion_callback(completion_callback) {} | 736 completion_callback(completion_callback) {} |
732 | 737 |
733 DownloadFileImpl::RenameParameters::~RenameParameters() {} | 738 DownloadFileImpl::RenameParameters::~RenameParameters() {} |
734 | 739 |
735 } // namespace content | 740 } // namespace content |
OLD | NEW |