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

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

Issue 2770303002: Add a helper method to truncate SourceStream's length (Closed)
Patch Set: Created 3 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
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 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 13 matching lines...) Expand all
24 #include "crypto/secure_hash.h" 24 #include "crypto/secure_hash.h"
25 #include "crypto/sha2.h" 25 #include "crypto/sha2.h"
26 #include "net/base/io_buffer.h" 26 #include "net/base/io_buffer.h"
27 #include "net/log/net_log.h" 27 #include "net/log/net_log.h"
28 #include "net/log/net_log_event_type.h" 28 #include "net/log/net_log_event_type.h"
29 #include "net/log/net_log_source.h" 29 #include "net/log/net_log_source.h"
30 #include "net/log/net_log_source_type.h" 30 #include "net/log/net_log_source_type.h"
31 31
32 namespace content { 32 namespace content {
33 33
34 namespace {
35
34 const int kUpdatePeriodMs = 500; 36 const int kUpdatePeriodMs = 500;
35 const int kMaxTimeBlockingFileThreadMs = 1000; 37 const int kMaxTimeBlockingFileThreadMs = 1000;
36 38
37 // These constants control the default retry behavior for failing renames. Each 39 // These constants control the default retry behavior for failing renames. Each
38 // retry is performed after a delay that is twice the previous delay. The 40 // retry is performed after a delay that is twice the previous delay. The
39 // initial delay is specified by kInitialRenameRetryDelayMs. 41 // initial delay is specified by kInitialRenameRetryDelayMs.
40 const int kInitialRenameRetryDelayMs = 200; 42 const int kInitialRenameRetryDelayMs = 200;
41 43
42 // Number of times a failing rename is retried before giving up. 44 // Number of times a failing rename is retried before giving up.
43 const int kMaxRenameRetries = 3; 45 const int kMaxRenameRetries = 3;
44 46
47 // Because DownloadSaveInfo::kLengthFullContent is 0, we should avoid using
48 // 0 for length if we found that a stream can no longer write any data.
49 const int kNoBytesToWrite = -1;
50
51 } // namespace
52
45 DownloadFileImpl::SourceStream::SourceStream( 53 DownloadFileImpl::SourceStream::SourceStream(
46 int64_t offset, 54 int64_t offset,
47 int64_t length, 55 int64_t length,
48 std::unique_ptr<ByteStreamReader> stream_reader) 56 std::unique_ptr<ByteStreamReader> stream_reader)
49 : offset_(offset), 57 : offset_(offset),
50 length_(length), 58 length_(length),
51 bytes_written_(0), 59 bytes_written_(0),
52 finished_(false), 60 finished_(false),
53 index_(0u), 61 index_(0u),
54 stream_reader_(std::move(stream_reader)) {} 62 stream_reader_(std::move(stream_reader)) {}
55 63
56 DownloadFileImpl::SourceStream::~SourceStream() = default; 64 DownloadFileImpl::SourceStream::~SourceStream() = default;
57 65
58 void DownloadFileImpl::SourceStream::OnWriteBytesToDisk(int64_t bytes_write) { 66 void DownloadFileImpl::SourceStream::OnWriteBytesToDisk(int64_t bytes_write) {
59 bytes_written_ += bytes_write; 67 bytes_written_ += bytes_write;
60 } 68 }
61 69
70 void DownloadFileImpl::SourceStream::TruncateLengthWithWrittenDataBlock(
71 int64_t offset,
72 int64_t bytes_written) {
73 DCHECK_GT(bytes_written, 0);
74 if (offset < offset_) {
xingliu 2017/03/24 19:13:47 nit%: Should we also do it when offset == offset_
qinmin 2017/03/24 20:39:01 Done. == is originally captured in the next if blo
75 if (offset + bytes_written > offset_)
xingliu 2017/03/24 19:13:47 nit%: what about if (..&& ..)
qinmin 2017/03/24 20:39:01 No, we want to early return here if offset < offse
xingliu 2017/03/24 21:14:08 My bad, I see.
76 length_ = kNoBytesToWrite;
77 return;
78 }
79
80 if (length_ == DownloadSaveInfo::kLengthFullContent ||
81 length_ > offset - offset_) {
82 length_ = offset - offset;
xingliu 2017/03/24 19:13:47 should it be (offset_ - offset) ? Also if length_
qinmin 2017/03/24 20:39:01 No, (offset_-offset) is negative in in this if blo
xingliu 2017/03/24 21:14:08 offset - offset is always 0, I think we are trying
qinmin 2017/03/24 21:38:31 should be offset-offset_, fixed.
83 // Because DownloadSaveInfo::kLengthFullContent is 0, we should avoid using
84 // 0 here.
85 if (length_ == 0)
86 length_ = kNoBytesToWrite;
87 }
88 }
89
62 DownloadFileImpl::DownloadFileImpl( 90 DownloadFileImpl::DownloadFileImpl(
63 std::unique_ptr<DownloadSaveInfo> save_info, 91 std::unique_ptr<DownloadSaveInfo> save_info,
64 const base::FilePath& default_download_directory, 92 const base::FilePath& default_download_directory,
65 std::unique_ptr<ByteStreamReader> stream_reader, 93 std::unique_ptr<ByteStreamReader> stream_reader,
66 const std::vector<DownloadItem::ReceivedSlice>& received_slices, 94 const std::vector<DownloadItem::ReceivedSlice>& received_slices,
67 const net::NetLogWithSource& download_item_net_log, 95 const net::NetLogWithSource& download_item_net_log,
68 bool is_sparse_file, 96 bool is_sparse_file,
69 base::WeakPtr<DownloadDestinationObserver> observer) 97 base::WeakPtr<DownloadDestinationObserver> observer)
70 : net_log_( 98 : net_log_(
71 net::NetLogWithSource::Make(download_item_net_log.net_log(), 99 net::NetLogWithSource::Make(download_item_net_log.net_log(),
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 const char* data, 182 const char* data,
155 size_t data_len) { 183 size_t data_len) {
156 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 184 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
157 WillWriteToDisk(data_len); 185 WillWriteToDisk(data_len);
158 return file_.WriteDataToFile(offset, data, data_len); 186 return file_.WriteDataToFile(offset, data, data_len);
159 } 187 }
160 188
161 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, 189 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream,
162 size_t bytes_available_to_write, 190 size_t bytes_available_to_write,
163 size_t* bytes_to_write) { 191 size_t* bytes_to_write) {
192 if (source_stream->length() == kNoBytesToWrite) {
193 *bytes_to_write = 0;
194 return true;
195 }
196
164 // If a new slice finds that its target position has already been written, 197 // If a new slice finds that its target position has already been written,
165 // terminate the stream. 198 // terminate the stream.
166 if (source_stream->bytes_written() == 0) { 199 if (source_stream->bytes_written() == 0) {
167 for (const auto& received_slice : received_slices_) { 200 for (const auto& received_slice : received_slices_) {
168 if (received_slice.offset <= source_stream->offset() && 201 if (received_slice.offset <= source_stream->offset() &&
169 received_slice.offset + received_slice.received_bytes > 202 received_slice.offset + received_slice.received_bytes >
170 source_stream->offset()) { 203 source_stream->offset()) {
171 *bytes_to_write = 0; 204 *bytes_to_write = 0;
172 return true; 205 return true;
173 } 206 }
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 } 474 }
442 } 475 }
443 476
444 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { 477 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) {
445 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 478 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
446 ByteStreamReader* stream_reader = source_stream->stream_reader(); 479 ByteStreamReader* stream_reader = source_stream->stream_reader();
447 if (stream_reader) { 480 if (stream_reader) {
448 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, 481 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive,
449 weak_factory_.GetWeakPtr(), 482 weak_factory_.GetWeakPtr(),
450 source_stream)); 483 source_stream));
484 // Truncate |source_stream|'s length if necessary.
485 for (const auto& received_slice : received_slices_) {
486 source_stream->TruncateLengthWithWrittenDataBlock(
487 received_slice.offset, received_slice.received_bytes);
488 }
451 StreamActive(source_stream); 489 StreamActive(source_stream);
452 num_active_streams_++; 490 num_active_streams_++;
453 } 491 }
454 } 492 }
455 493
456 int64_t DownloadFileImpl::TotalBytesReceived() const { 494 int64_t DownloadFileImpl::TotalBytesReceived() const {
457 return file_.bytes_so_far(); 495 return file_.bytes_so_far();
458 } 496 }
459 497
460 void DownloadFileImpl::SendUpdate() { 498 void DownloadFileImpl::SendUpdate() {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 // Check if the slice is added as a new slice, or merged with an existing one. 534 // Check if the slice is added as a new slice, or merged with an existing one.
497 bool slice_added = (offset == received_slices_[index].offset); 535 bool slice_added = (offset == received_slices_[index].offset);
498 // Update the index of exising SourceStreams. 536 // Update the index of exising SourceStreams.
499 for (auto& stream : source_streams_) { 537 for (auto& stream : source_streams_) {
500 SourceStream* source_stream = stream.second.get(); 538 SourceStream* source_stream = stream.second.get();
501 if (source_stream->offset() > offset) { 539 if (source_stream->offset() > offset) {
502 if (slice_added && source_stream->bytes_written() > 0) 540 if (slice_added && source_stream->bytes_written() > 0)
503 source_stream->set_index(source_stream->index() + 1); 541 source_stream->set_index(source_stream->index() + 1);
504 } else if (source_stream->offset() == offset) { 542 } else if (source_stream->offset() == offset) {
505 source_stream->set_index(index); 543 source_stream->set_index(index);
506 } else if (source_stream->length() == 544 } else {
507 DownloadSaveInfo::kLengthFullContent || 545 source_stream->TruncateLengthWithWrittenDataBlock(offset, length);
508 source_stream->length() > offset - source_stream->offset()) {
509 // The newly introduced slice will impact the length of the SourceStreams
510 // preceding it.
511 source_stream->set_length(offset - source_stream->offset());
512 } 546 }
513 } 547 }
514 } 548 }
515 549
516 bool DownloadFileImpl::IsDownloadCompleted() { 550 bool DownloadFileImpl::IsDownloadCompleted() {
517 SourceStream* stream_for_last_slice = nullptr; 551 SourceStream* stream_for_last_slice = nullptr;
518 int64_t last_slice_offset = 0; 552 int64_t last_slice_offset = 0;
519 for (auto& stream : source_streams_) { 553 for (auto& stream : source_streams_) {
520 SourceStream* source_stream = stream.second.get(); 554 SourceStream* source_stream = stream.second.get();
521 if (source_stream->offset() >= last_slice_offset && 555 if (source_stream->offset() >= last_slice_offset &&
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 591
558 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, 592 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream,
559 DownloadInterruptReason reason) { 593 DownloadInterruptReason reason) {
560 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 594 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
561 source_stream->stream_reader()->RegisterCallback(base::Closure()); 595 source_stream->stream_reader()->RegisterCallback(base::Closure());
562 source_stream->set_finished(true); 596 source_stream->set_finished(true);
563 num_active_streams_--; 597 num_active_streams_--;
564 598
565 bool can_recover_from_error = false; 599 bool can_recover_from_error = false;
566 600
567 if (is_sparse_file_) { 601 if (is_sparse_file_ && source_stream->length() != kNoBytesToWrite) {
568 // If a neighboring stream request is available, check if it can help 602 // If a neighboring stream request is available, check if it can help
569 // download all the data left by |source stream| or has already done so. We 603 // download all the data left by |source stream| or has already done so. We
570 // want to avoid the situation that a server always fail additional requests 604 // want to avoid the situation that a server always fail additional requests
571 // from the client thus causing the initial request and the download going 605 // from the client thus causing the initial request and the download going
572 // nowhere. 606 // nowhere.
573 // TODO(qinmin): make all streams half open so that they can recover 607 // TODO(qinmin): make all streams half open so that they can recover
574 // failures from their neighbors. 608 // failures from their neighbors.
575 SourceStream* preceding_neighbor = FindPrecedingNeighbor(source_stream); 609 SourceStream* preceding_neighbor = FindPrecedingNeighbor(source_stream);
576 while (preceding_neighbor) { 610 while (preceding_neighbor) {
577 int64_t upper_range = source_stream->offset() + source_stream->length(); 611 int64_t upper_range = source_stream->offset() + source_stream->length();
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 const base::FilePath& new_path, 676 const base::FilePath& new_path,
643 const RenameCompletionCallback& completion_callback) 677 const RenameCompletionCallback& completion_callback)
644 : option(option), 678 : option(option),
645 new_path(new_path), 679 new_path(new_path),
646 retries_left(kMaxRenameRetries), 680 retries_left(kMaxRenameRetries),
647 completion_callback(completion_callback) {} 681 completion_callback(completion_callback) {}
648 682
649 DownloadFileImpl::RenameParameters::~RenameParameters() {} 683 DownloadFileImpl::RenameParameters::~RenameParameters() {}
650 684
651 } // namespace content 685 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/download/download_file_impl.h ('k') | content/browser/download/download_item_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698