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

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

Issue 342233002: Revert 278483 "[Downloads] Retry renames after transient failures." (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 6 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/bind.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h" 13 #include "base/time/time.h"
14 #include "content/browser/byte_stream.h" 14 #include "content/browser/byte_stream.h"
15 #include "content/browser/download/download_create_info.h" 15 #include "content/browser/download/download_create_info.h"
16 #include "content/browser/download/download_interrupt_reasons_impl.h" 16 #include "content/browser/download/download_interrupt_reasons_impl.h"
17 #include "content/browser/download/download_net_log_parameters.h" 17 #include "content/browser/download/download_net_log_parameters.h"
18 #include "content/browser/download/download_stats.h" 18 #include "content/browser/download/download_stats.h"
19 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/download_destination_observer.h" 20 #include "content/public/browser/download_destination_observer.h"
21 #include "net/base/io_buffer.h" 21 #include "net/base/io_buffer.h"
22 22
23 namespace content { 23 namespace content {
24 24
25 const int kUpdatePeriodMs = 500; 25 const int kUpdatePeriodMs = 500;
26 const int kMaxTimeBlockingFileThreadMs = 1000; 26 const int kMaxTimeBlockingFileThreadMs = 1000;
27 27
28 // These constants control the default retry behavior for failing renames. Each
29 // retry is performed after a delay that is twice the previous delay. The
30 // initial delay is specified by kInitialRenameRetryDelayMs.
31 const int kMaxRenameRetries = 3;
32 const int kInitialRenameRetryDelayMs = 200;
33
34 int DownloadFile::number_active_objects_ = 0; 28 int DownloadFile::number_active_objects_ = 0;
35 29
36 DownloadFileImpl::DownloadFileImpl( 30 DownloadFileImpl::DownloadFileImpl(
37 scoped_ptr<DownloadSaveInfo> save_info, 31 scoped_ptr<DownloadSaveInfo> save_info,
38 const base::FilePath& default_download_directory, 32 const base::FilePath& default_download_directory,
39 const GURL& url, 33 const GURL& url,
40 const GURL& referrer_url, 34 const GURL& referrer_url,
41 bool calculate_hash, 35 bool calculate_hash,
42 scoped_ptr<ByteStreamReader> stream, 36 scoped_ptr<ByteStreamReader> stream,
43 const net::BoundNetLog& bound_net_log, 37 const net::BoundNetLog& bound_net_log,
44 base::WeakPtr<DownloadDestinationObserver> observer) 38 base::WeakPtr<DownloadDestinationObserver> observer)
45 : file_(save_info->file_path, 39 : file_(save_info->file_path,
46 url, 40 url,
47 referrer_url, 41 referrer_url,
48 save_info->offset, 42 save_info->offset,
49 calculate_hash, 43 calculate_hash,
50 save_info->hash_state, 44 save_info->hash_state,
51 save_info->file.Pass(), 45 save_info->file.Pass(),
52 bound_net_log), 46 bound_net_log),
53 default_download_directory_(default_download_directory), 47 default_download_directory_(default_download_directory),
54 stream_reader_(stream.Pass()), 48 stream_reader_(stream.Pass()),
55 bytes_seen_(0), 49 bytes_seen_(0),
56 bound_net_log_(bound_net_log), 50 bound_net_log_(bound_net_log),
57 observer_(observer), 51 observer_(observer),
58 weak_factory_(this) { 52 weak_factory_(this) {
59 } 53 }
60 54
61 DownloadFileImpl::~DownloadFileImpl() { 55 DownloadFileImpl::~DownloadFileImpl() {
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
63 --number_active_objects_; 57 --number_active_objects_;
64 } 58 }
65 59
66 void DownloadFileImpl::Initialize(const InitializeCallback& callback) { 60 void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
68 62
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), 96 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
103 this, &DownloadFileImpl::SendUpdate); 97 this, &DownloadFileImpl::SendUpdate);
104 } 98 }
105 rate_estimator_.Increment(data_len); 99 rate_estimator_.Increment(data_len);
106 return file_.AppendDataToFile(data, data_len); 100 return file_.AppendDataToFile(data, data_len);
107 } 101 }
108 102
109 void DownloadFileImpl::RenameAndUniquify( 103 void DownloadFileImpl::RenameAndUniquify(
110 const base::FilePath& full_path, 104 const base::FilePath& full_path,
111 const RenameCompletionCallback& callback) { 105 const RenameCompletionCallback& callback) {
112 RenameWithRetryInternal( 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
113 full_path, UNIQUIFY, kMaxRenameRetries, base::TimeTicks(), callback); 107
108 base::FilePath new_path(full_path);
109
110 int uniquifier = base::GetUniquePathNumber(
111 new_path, base::FilePath::StringType());
112 if (uniquifier > 0) {
113 new_path = new_path.InsertBeforeExtensionASCII(
114 base::StringPrintf(" (%d)", uniquifier));
115 }
116
117 DownloadInterruptReason reason = file_.Rename(new_path);
118 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
119 // Make sure our information is updated, since we're about to
120 // error out.
121 SendUpdate();
122
123 // Null out callback so that we don't do any more stream processing.
124 stream_reader_->RegisterCallback(base::Closure());
125
126 new_path.clear();
127 }
128
129 BrowserThread::PostTask(
130 BrowserThread::UI, FROM_HERE,
131 base::Bind(callback, reason, new_path));
114 } 132 }
115 133
116 void DownloadFileImpl::RenameAndAnnotate( 134 void DownloadFileImpl::RenameAndAnnotate(
117 const base::FilePath& full_path, 135 const base::FilePath& full_path,
118 const RenameCompletionCallback& callback) { 136 const RenameCompletionCallback& callback) {
119 RenameWithRetryInternal(full_path,
120 ANNOTATE_WITH_SOURCE_INFORMATION,
121 kMaxRenameRetries,
122 base::TimeTicks(),
123 callback);
124 }
125
126 base::TimeDelta DownloadFileImpl::GetRetryDelayForFailedRename(
127 int attempt_number) {
128 DCHECK_GE(attempt_number, 0);
129 // |delay| starts at kInitialRenameRetryDelayMs and increases by a factor of
130 // 2 at each subsequent retry. Assumes that |retries_left| starts at
131 // kMaxRenameRetries. Also assumes that kMaxRenameRetries is less than the
132 // number of bits in an int.
133 return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) *
134 (1 << attempt_number);
135 }
136
137 bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) {
138 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
139 }
140
141 void DownloadFileImpl::RenameWithRetryInternal(
142 const base::FilePath& full_path,
143 RenameOption option,
144 int retries_left,
145 base::TimeTicks time_of_first_failure,
146 const RenameCompletionCallback& callback) {
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
148 138
149 base::FilePath new_path(full_path); 139 base::FilePath new_path(full_path);
150 140
151 if ((option & UNIQUIFY) && full_path != file_.full_path()) { 141 DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
152 int uniquifier = 142 // Short circuit null rename.
153 base::GetUniquePathNumber(new_path, base::FilePath::StringType()); 143 if (full_path != file_.full_path())
154 if (uniquifier > 0) 144 reason = file_.Rename(new_path);
155 new_path = new_path.InsertBeforeExtensionASCII(
156 base::StringPrintf(" (%d)", uniquifier));
157 }
158 145
159 DownloadInterruptReason reason = file_.Rename(new_path); 146 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
160
161 // Attempt to retry the rename if possible. If the rename failed and the
162 // subsequent open also failed, then in_progress() would be false. We don't
163 // try to retry renames if the in_progress() was false to begin with since we
164 // have less assurance that the file at file_.full_path() was the one we were
165 // working with.
166 if (ShouldRetryFailedRename(reason) && file_.in_progress() &&
167 retries_left > 0) {
168 int attempt_number = kMaxRenameRetries - retries_left;
169 BrowserThread::PostDelayedTask(
170 BrowserThread::FILE,
171 FROM_HERE,
172 base::Bind(&DownloadFileImpl::RenameWithRetryInternal,
173 weak_factory_.GetWeakPtr(),
174 full_path,
175 option,
176 --retries_left,
177 time_of_first_failure.is_null() ? base::TimeTicks::Now()
178 : time_of_first_failure,
179 callback),
180 GetRetryDelayForFailedRename(attempt_number));
181 return;
182 }
183
184 if (!time_of_first_failure.is_null())
185 RecordDownloadFileRenameResultAfterRetry(
186 base::TimeTicks::Now() - time_of_first_failure, reason);
187
188 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
189 (option & ANNOTATE_WITH_SOURCE_INFORMATION)) {
190 // Doing the annotation after the rename rather than before leaves 147 // Doing the annotation after the rename rather than before leaves
191 // a very small window during which the file has the final name but 148 // a very small window during which the file has the final name but
192 // hasn't been marked with the Mark Of The Web. However, it allows 149 // hasn't been marked with the Mark Of The Web. However, it allows
193 // anti-virus scanners on Windows to actually see the data 150 // anti-virus scanners on Windows to actually see the data
194 // (http://crbug.com/127999) under the correct name (which is information 151 // (http://crbug.com/127999) under the correct name (which is information
195 // it uses). 152 // it uses).
196 reason = file_.AnnotateWithSourceInformation(); 153 reason = file_.AnnotateWithSourceInformation();
197 } 154 }
198 155
199 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { 156 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 observer_, file_.bytes_so_far(), CurrentSpeed(), 309 observer_, file_.bytes_so_far(), CurrentSpeed(),
353 GetHashState())); 310 GetHashState()));
354 } 311 }
355 312
356 // static 313 // static
357 int DownloadFile::GetNumberOfDownloadFiles() { 314 int DownloadFile::GetNumberOfDownloadFiles() {
358 return number_active_objects_; 315 return number_active_objects_;
359 } 316 }
360 317
361 } // namespace content 318 } // namespace content
OLDNEW
« no previous file with comments | « trunk/src/content/browser/download/download_file_impl.h ('k') | trunk/src/content/browser/download/download_file_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698