OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "net/url_request/url_request_throttler_entry.h" | 5 #include "net/url_request/url_request_throttler_entry.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/field_trial.h" | |
11 #include "base/metrics/histogram.h" | |
10 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
11 #include "base/string_number_conversions.h" | 13 #include "base/string_number_conversions.h" |
14 #include "base/time.h" | |
15 #include "base/values.h" | |
16 #include "net/base/net_log.h" | |
12 #include "net/url_request/url_request_throttler_header_interface.h" | 17 #include "net/url_request/url_request_throttler_header_interface.h" |
13 #include "net/url_request/url_request_throttler_manager.h" | 18 #include "net/url_request/url_request_throttler_manager.h" |
14 | 19 |
15 namespace net { | 20 namespace net { |
16 | 21 |
17 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; | 22 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; |
18 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; | 23 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; |
19 | 24 |
20 // This set of back-off parameters will (at maximum values, i.e. without | 25 // This set of back-off parameters will (at maximum values, i.e. without |
21 // the reduction caused by jitter) add 0-41% (distributed uniformly | 26 // the reduction caused by jitter) add 0-41% (distributed uniformly |
22 // in that range) to the "perceived downtime" of the remote server, once | 27 // in that range) to the "perceived downtime" of the remote server, once |
23 // exponential back-off kicks in and is throttling requests for more than | 28 // exponential back-off kicks in and is throttling requests for more than |
24 // about a second at a time. Once the maximum back-off is reached, the added | 29 // about a second at a time. Once the maximum back-off is reached, the added |
25 // perceived downtime decreases rapidly, percentage-wise. | 30 // perceived downtime decreases rapidly, percentage-wise. |
26 // | 31 // |
27 // Another way to put it is that the maximum additional perceived downtime | 32 // Another way to put it is that the maximum additional perceived downtime |
28 // with these numbers is a couple of seconds shy of 15 minutes, and such | 33 // with these numbers is a couple of seconds shy of 15 minutes, and such |
29 // a delay would not occur until the remote server has been actually | 34 // a delay would not occur until the remote server has been actually |
30 // unavailable at the end of each back-off period for a total of about | 35 // unavailable at the end of each back-off period for a total of about |
31 // 48 minutes. | 36 // 48 minutes. |
32 // | 37 // |
33 // Ignoring the first 4 errors helps avoid back-off from kicking in on | 38 // Ignoring the first couple of errors is just a conservative measure to |
34 // flaky connections. | 39 // avoid false positives. It should help avoid back-off from kicking in e.g. |
35 const int URLRequestThrottlerEntry::kDefaultNumErrorsToIgnore = 4; | 40 // on flaky connections. |
41 const int URLRequestThrottlerEntry::kDefaultNumErrorsToIgnore = 2; | |
36 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700; | 42 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700; |
37 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4; | 43 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4; |
38 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4; | 44 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4; |
39 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 15 * 60 * 1000; | 45 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 15 * 60 * 1000; |
40 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000; | 46 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000; |
41 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After"; | 47 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After"; |
42 const char URLRequestThrottlerEntry::kExponentialThrottlingHeader[] = | 48 const char URLRequestThrottlerEntry::kExponentialThrottlingHeader[] = |
43 "X-Chrome-Exponential-Throttling"; | 49 "X-Chrome-Exponential-Throttling"; |
44 const char URLRequestThrottlerEntry::kExponentialThrottlingDisableValue[] = | 50 const char URLRequestThrottlerEntry::kExponentialThrottlingDisableValue[] = |
45 "disable"; | 51 "disable"; |
46 | 52 |
53 // NetLog parameters when a request is rejected by throttling. | |
54 class RejectedRequestParameters : public NetLog::EventParameters { | |
55 public: | |
56 RejectedRequestParameters(const std::string& url_id, | |
57 int num_failures, | |
58 int release_after_ms) | |
59 : url_id_(url_id), | |
60 num_failures_(num_failures), | |
61 release_after_ms_(release_after_ms) { | |
62 } | |
63 | |
64 virtual Value* ToValue() const { | |
65 DictionaryValue* dict = new DictionaryValue(); | |
66 dict->SetString("url", url_id_); | |
67 dict->SetInteger("num_failures", num_failures_); | |
68 dict->SetInteger("release_after_ms", release_after_ms_); | |
69 return dict; | |
70 } | |
71 | |
72 private: | |
73 std::string url_id_; | |
74 int num_failures_; | |
75 int release_after_ms_; | |
76 }; | |
77 | |
78 // NetLog parameters when a response contains an X-Retry-After header. | |
79 class RetryAfterParameters : public NetLog::EventParameters { | |
80 public: | |
81 RetryAfterParameters(const std::string& url_id, | |
82 int retry_after_ms) | |
yzshen1
2011/05/25 03:49:06
Wrong indent.
Jói
2011/05/25 14:30:35
Done.
| |
83 : url_id_(url_id), | |
84 retry_after_ms_(retry_after_ms) { | |
85 } | |
86 | |
87 virtual Value* ToValue() const { | |
88 DictionaryValue* dict = new DictionaryValue(); | |
89 dict->SetString("url", url_id_); | |
90 dict->SetInteger("retry_after_ms", retry_after_ms_); | |
91 return dict; | |
92 } | |
93 | |
94 private: | |
95 std::string url_id_; | |
96 int retry_after_ms_; | |
97 }; | |
98 | |
47 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 99 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
48 URLRequestThrottlerManager* manager) | 100 URLRequestThrottlerManager* manager, |
101 const std::string& url_id) | |
49 : sliding_window_period_( | 102 : sliding_window_period_( |
50 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), | 103 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), |
51 max_send_threshold_(kDefaultMaxSendThreshold), | 104 max_send_threshold_(kDefaultMaxSendThreshold), |
52 is_backoff_disabled_(false), | 105 is_backoff_disabled_(false), |
53 backoff_entry_(&backoff_policy_), | 106 backoff_entry_(&backoff_policy_), |
54 manager_(manager) { | 107 manager_(manager), |
108 url_id_(url_id), | |
109 net_log_(BoundNetLog::Make( | |
110 manager->net_log(), NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) { | |
55 DCHECK(manager_); | 111 DCHECK(manager_); |
56 Initialize(); | 112 Initialize(); |
57 } | 113 } |
58 | 114 |
59 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 115 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
60 URLRequestThrottlerManager* manager, | 116 URLRequestThrottlerManager* manager, |
117 const std::string& url_id, | |
61 int sliding_window_period_ms, | 118 int sliding_window_period_ms, |
62 int max_send_threshold, | 119 int max_send_threshold, |
63 int initial_backoff_ms, | 120 int initial_backoff_ms, |
64 double multiply_factor, | 121 double multiply_factor, |
65 double jitter_factor, | 122 double jitter_factor, |
66 int maximum_backoff_ms) | 123 int maximum_backoff_ms) |
67 : sliding_window_period_( | 124 : sliding_window_period_( |
68 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)), | 125 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)), |
69 max_send_threshold_(max_send_threshold), | 126 max_send_threshold_(max_send_threshold), |
70 is_backoff_disabled_(false), | 127 is_backoff_disabled_(false), |
71 backoff_entry_(&backoff_policy_), | 128 backoff_entry_(&backoff_policy_), |
72 manager_(manager) { | 129 manager_(manager), |
130 url_id_(url_id) { | |
73 DCHECK_GT(sliding_window_period_ms, 0); | 131 DCHECK_GT(sliding_window_period_ms, 0); |
74 DCHECK_GT(max_send_threshold_, 0); | 132 DCHECK_GT(max_send_threshold_, 0); |
75 DCHECK_GE(initial_backoff_ms, 0); | 133 DCHECK_GE(initial_backoff_ms, 0); |
76 DCHECK_GT(multiply_factor, 0); | 134 DCHECK_GT(multiply_factor, 0); |
77 DCHECK_GE(jitter_factor, 0.0); | 135 DCHECK_GE(jitter_factor, 0.0); |
78 DCHECK_LT(jitter_factor, 1.0); | 136 DCHECK_LT(jitter_factor, 1.0); |
79 DCHECK_GE(maximum_backoff_ms, 0); | 137 DCHECK_GE(maximum_backoff_ms, 0); |
80 DCHECK(manager_); | 138 DCHECK(manager_); |
81 | 139 |
82 Initialize(); | 140 Initialize(); |
(...skipping 16 matching lines...) Expand all Loading... | |
99 // it should not be considered outdated. | 157 // it should not be considered outdated. |
100 // | 158 // |
101 // TODO(joi): Once the manager is not a Singleton, revisit whether | 159 // TODO(joi): Once the manager is not a Singleton, revisit whether |
102 // refcounting is needed at all. | 160 // refcounting is needed at all. |
103 if (!HasOneRef()) | 161 if (!HasOneRef()) |
104 return false; | 162 return false; |
105 | 163 |
106 // If there are send events in the sliding window period, we still need this | 164 // If there are send events in the sliding window period, we still need this |
107 // entry. | 165 // entry. |
108 if (!send_log_.empty() && | 166 if (!send_log_.empty() && |
109 send_log_.back() + sliding_window_period_ > GetTimeNow()) { | 167 send_log_.back() + sliding_window_period_ > ImplGetTimeNow()) { |
110 return false; | 168 return false; |
111 } | 169 } |
112 | 170 |
113 return GetBackoffEntry()->CanDiscard(); | 171 return GetBackoffEntry()->CanDiscard(); |
114 } | 172 } |
115 | 173 |
116 void URLRequestThrottlerEntry::DisableBackoffThrottling() { | 174 void URLRequestThrottlerEntry::DisableBackoffThrottling() { |
117 is_backoff_disabled_ = true; | 175 is_backoff_disabled_ = true; |
118 } | 176 } |
119 | 177 |
120 void URLRequestThrottlerEntry::DetachManager() { | 178 void URLRequestThrottlerEntry::DetachManager() { |
121 manager_ = NULL; | 179 manager_ = NULL; |
122 } | 180 } |
123 | 181 |
124 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { | 182 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { |
125 if (is_backoff_disabled_) | 183 bool reject_request = false; |
126 return false; | 184 if (!is_backoff_disabled_ && GetBackoffEntry()->ShouldRejectRequest()) { |
185 int num_failures = GetBackoffEntry()->failure_count(); | |
186 int release_after_ms = | |
187 (GetBackoffEntry()->GetReleaseTime() - base::TimeTicks::Now()) | |
188 .InMilliseconds(); | |
127 | 189 |
128 return GetBackoffEntry()->ShouldRejectRequest(); | 190 net_log_.AddEvent( |
191 NetLog::TYPE_THROTTLING_REJECTED_REQUEST, | |
yzshen1
2011/05/25 03:49:06
Wrong indent.
Jói
2011/05/25 14:30:35
Done.
| |
192 make_scoped_refptr( | |
193 new RejectedRequestParameters(url_id_, | |
194 num_failures, | |
195 release_after_ms))); | |
196 | |
197 reject_request = true; | |
198 } | |
199 | |
200 int reject_count = reject_request ? 1 : 0; | |
201 UMA_HISTOGRAM_ENUMERATION( | |
202 "Throttling.RequestThrottled", reject_count, 2); | |
203 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { | |
204 UMA_HISTOGRAM_ENUMERATION(base::FieldTrial::MakeName( | |
205 "Throttling.RequestThrottled", "ThrottlingEnabled"), reject_count, 2); | |
206 } | |
207 | |
208 return reject_request; | |
129 } | 209 } |
130 | 210 |
131 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( | 211 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( |
132 const base::TimeTicks& earliest_time) { | 212 const base::TimeTicks& earliest_time) { |
133 base::TimeTicks now = GetTimeNow(); | 213 base::TimeTicks now = ImplGetTimeNow(); |
134 | 214 |
135 // If a lot of requests were successfully made recently, | 215 // If a lot of requests were successfully made recently, |
136 // sliding_window_release_time_ may be greater than | 216 // sliding_window_release_time_ may be greater than |
137 // exponential_backoff_release_time_. | 217 // exponential_backoff_release_time_. |
138 base::TimeTicks recommended_sending_time = | 218 base::TimeTicks recommended_sending_time = |
139 std::max(std::max(now, earliest_time), | 219 std::max(std::max(now, earliest_time), |
140 std::max(GetBackoffEntry()->GetReleaseTime(), | 220 std::max(GetBackoffEntry()->GetReleaseTime(), |
141 sliding_window_release_time_)); | 221 sliding_window_release_time_)); |
142 | 222 |
143 DCHECK(send_log_.empty() || | 223 DCHECK(send_log_.empty() || |
(...skipping 20 matching lines...) Expand all Loading... | |
164 } | 244 } |
165 | 245 |
166 base::TimeTicks | 246 base::TimeTicks |
167 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { | 247 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { |
168 // If a site opts out, it's likely because they have problems that trigger | 248 // If a site opts out, it's likely because they have problems that trigger |
169 // the back-off mechanism when it shouldn't be triggered, in which case | 249 // the back-off mechanism when it shouldn't be triggered, in which case |
170 // returning the calculated back-off release time would probably be the | 250 // returning the calculated back-off release time would probably be the |
171 // wrong thing to do (i.e. it would likely be too long). Therefore, we | 251 // wrong thing to do (i.e. it would likely be too long). Therefore, we |
172 // return "now" so that retries are not delayed. | 252 // return "now" so that retries are not delayed. |
173 if (is_backoff_disabled_) | 253 if (is_backoff_disabled_) |
174 return GetTimeNow(); | 254 return ImplGetTimeNow(); |
175 | 255 |
176 return GetBackoffEntry()->GetReleaseTime(); | 256 return GetBackoffEntry()->GetReleaseTime(); |
177 } | 257 } |
178 | 258 |
179 void URLRequestThrottlerEntry::UpdateWithResponse( | 259 void URLRequestThrottlerEntry::UpdateWithResponse( |
180 const std::string& host, | 260 const std::string& host, |
181 const URLRequestThrottlerHeaderInterface* response) { | 261 const URLRequestThrottlerHeaderInterface* response) { |
182 if (response->GetResponseCode() >= 500) { | 262 int status_code = response->GetResponseCode(); |
263 HandleMetricsTracking(status_code); | |
264 | |
265 if (IsConsideredError(status_code)) { | |
183 GetBackoffEntry()->InformOfRequest(false); | 266 GetBackoffEntry()->InformOfRequest(false); |
184 } else { | 267 } else { |
185 GetBackoffEntry()->InformOfRequest(true); | 268 GetBackoffEntry()->InformOfRequest(true); |
186 | 269 |
187 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); | 270 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); |
188 if (!retry_header.empty()) | 271 if (!retry_header.empty()) |
189 HandleCustomRetryAfter(retry_header); | 272 HandleCustomRetryAfter(retry_header); |
190 | 273 |
191 std::string throttling_header = response->GetNormalizedValue( | 274 std::string throttling_header = response->GetNormalizedValue( |
192 kExponentialThrottlingHeader); | 275 kExponentialThrottlingHeader); |
193 if (!throttling_header.empty()) | 276 if (!throttling_header.empty()) |
194 HandleThrottlingHeader(throttling_header, host); | 277 HandleThrottlingHeader(throttling_header, host); |
195 } | 278 } |
196 } | 279 } |
197 | 280 |
198 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() { | 281 void URLRequestThrottlerEntry::ReceivedContentWasMalformed(int status_code) { |
199 // A malformed body can only occur when the request to fetch a resource | 282 // A malformed body can only occur when the request to fetch a resource |
200 // was successful. Therefore, in such a situation, we will receive one | 283 // was successful. Therefore, in such a situation, we will receive one |
201 // call to ReceivedContentWasMalformed() and one call to UpdateWithResponse() | 284 // call to ReceivedContentWasMalformed() and one call to |
202 // with a response categorized as "good". To end up counting one failure, | 285 // UpdateWithResponse() with a response categorized as "good". To end |
203 // we need to count two failures here against the one success in | 286 // up counting one failure, we need to count two failures here against |
204 // UpdateWithResponse(). | 287 // the one success in UpdateWithResponse(). |
205 GetBackoffEntry()->InformOfRequest(false); | 288 // |
206 GetBackoffEntry()->InformOfRequest(false); | 289 // We do nothing for a response that is already being considered an error |
290 // based on its status code (otherwise we would count 3 errors instead of 1). | |
291 if (!IsConsideredError(status_code)) { | |
292 GetBackoffEntry()->InformOfRequest(false); | |
293 GetBackoffEntry()->InformOfRequest(false); | |
294 } | |
207 } | 295 } |
208 | 296 |
209 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { | 297 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { |
210 } | 298 } |
211 | 299 |
212 void URLRequestThrottlerEntry::Initialize() { | 300 void URLRequestThrottlerEntry::Initialize() { |
213 sliding_window_release_time_ = base::TimeTicks::Now(); | 301 sliding_window_release_time_ = base::TimeTicks::Now(); |
214 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore; | 302 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore; |
215 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; | 303 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; |
216 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; | 304 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; |
217 backoff_policy_.jitter_factor = kDefaultJitterFactor; | 305 backoff_policy_.jitter_factor = kDefaultJitterFactor; |
218 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; | 306 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; |
219 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; | 307 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; |
308 | |
309 // We pretend we just had a successful response so that we have a | |
310 // starting point to our tracking. | |
311 last_successful_response_time_ = base::TimeTicks::Now(); | |
yzshen1
2011/05/25 03:49:06
It would be good to comment about why ImplGetTimeN
Jói
2011/05/25 14:30:35
Done.
| |
312 last_response_was_success_ = true; | |
220 } | 313 } |
221 | 314 |
222 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const { | 315 bool URLRequestThrottlerEntry::IsConsideredError(int status_code) { |
316 // We throttle only for the status codes most likely to indicate the server | |
317 // is failing because it is too busy or otherwise are likely to be | |
318 // because of DDoS. | |
319 // | |
320 // 500 is the generic error when no better message is suitable, and | |
321 // as such does not necessarily indicate a temporary state, but | |
322 // other status codes cover most of the permanent error states. | |
323 // 503 is explicitly documented as a temporary state where the server | |
324 // is either overloaded or down for maintenance. | |
325 // 509 is the (non-standard but widely implemented) Bandwidth Limit Exceeded | |
326 // status code, which might indicate DDoS. | |
327 // | |
328 // We do not back off on 502 or 504, which are reported by gateways | |
329 // (proxies) on timeouts or failures, because in many cases these requests | |
330 // have not made it to the destination server and so we do not actually | |
331 // know that it is down or busy. One degenerate case could be a proxy on | |
332 // localhost, where you are not actually connected to the network. | |
333 return (status_code == 500 || | |
334 status_code == 503 || | |
335 status_code == 509); | |
336 } | |
337 | |
338 base::TimeTicks URLRequestThrottlerEntry::ImplGetTimeNow() const { | |
223 return base::TimeTicks::Now(); | 339 return base::TimeTicks::Now(); |
224 } | 340 } |
225 | 341 |
226 void URLRequestThrottlerEntry::HandleCustomRetryAfter( | 342 void URLRequestThrottlerEntry::HandleCustomRetryAfter( |
227 const std::string& header_value) { | 343 const std::string& header_value) { |
228 // Input parameter is the number of seconds to wait in a floating point value. | 344 // Input parameter is the number of seconds to wait in a floating point value. |
229 double time_in_sec = 0; | 345 double time_in_sec = 0; |
230 bool conversion_is_ok = base::StringToDouble(header_value, &time_in_sec); | 346 bool conversion_is_ok = base::StringToDouble(header_value, &time_in_sec); |
231 | 347 |
232 // Conversion of custom retry-after header value failed. | 348 // Conversion of custom retry-after header value failed. |
233 if (!conversion_is_ok) | 349 if (!conversion_is_ok) |
234 return; | 350 return; |
235 | 351 |
236 // We must use an int value later so we transform this in milliseconds. | 352 // We must use an int value later so we transform this in milliseconds. |
237 int64 value_ms = static_cast<int64>(0.5 + time_in_sec * 1000); | 353 int64 value_ms = static_cast<int64>(0.5 + time_in_sec * 1000); |
238 | 354 |
239 // We do not check for an upper bound; the server can set any Retry-After it | 355 // We do not check for an upper bound; the server can set any Retry-After it |
240 // desires. Recovery from error would involve restarting the browser. | 356 // desires. Recovery from error would involve restarting the browser. |
241 if (value_ms < 0) | 357 if (value_ms < 0) |
242 return; | 358 return; |
243 | 359 |
244 GetBackoffEntry()->SetCustomReleaseTime( | 360 net_log_.AddEvent( |
245 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms)); | 361 NetLog::TYPE_THROTTLING_GOT_CUSTOM_RETRY_AFTER, |
362 make_scoped_refptr(new RetryAfterParameters(url_id_, value_ms))); | |
363 | |
364 base::TimeDelta value = base::TimeDelta::FromMilliseconds(value_ms); | |
365 GetBackoffEntry()->SetCustomReleaseTime(ImplGetTimeNow() + value); | |
366 | |
367 UMA_HISTOGRAM_CUSTOM_TIMES( | |
368 "Throttling.CustomRetryAfterMs", value, | |
369 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromHours(12), 50); | |
370 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { | |
371 UMA_HISTOGRAM_CUSTOM_TIMES( | |
372 base::FieldTrial::MakeName("Throttling.CustomRetryAfterMs", | |
373 "ThrottlingEnabled"), value, | |
374 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromHours(12), 50); | |
375 } | |
246 } | 376 } |
247 | 377 |
248 void URLRequestThrottlerEntry::HandleThrottlingHeader( | 378 void URLRequestThrottlerEntry::HandleThrottlingHeader( |
249 const std::string& header_value, | 379 const std::string& header_value, |
250 const std::string& host) { | 380 const std::string& host) { |
251 if (header_value == kExponentialThrottlingDisableValue) { | 381 if (header_value == kExponentialThrottlingDisableValue) { |
252 DisableBackoffThrottling(); | 382 DisableBackoffThrottling(); |
253 if (manager_) | 383 if (manager_) |
254 manager_->AddToOptOutList(host); | 384 manager_->AddToOptOutList(host); |
255 } else { | 385 } else { |
256 // TODO(joi): Log this. | 386 // TODO(joi): Log this. |
257 } | 387 } |
258 } | 388 } |
259 | 389 |
390 void URLRequestThrottlerEntry::HandleMetricsTracking(int status_code) { | |
391 // This is essentially the same as the "Net.HttpResponseCode" UMA stat | |
392 // but we are tracking it separately here for the throttling experiment | |
393 // to make sure we count only the responses seen by throttling. | |
394 // TODO(joi): Remove after experiment. | |
395 UMA_HISTOGRAM_ENUMERATION("Throttling.HttpResponseCode", status_code, 600); | |
396 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { | |
397 UMA_HISTOGRAM_ENUMERATION(base::FieldTrial::MakeName( | |
398 "Throttling.HttpResponseCode", "ThrottlingEnabled"), status_code, 600); | |
399 } | |
400 | |
401 // Note that we are not interested in whether the code is considered | |
402 // an error for the backoff logic, but whether it is a 5xx error in | |
403 // general. This is because here, we are tracking the apparent total | |
404 // downtime of a server. | |
405 if (status_code >= 500) { | |
406 last_response_was_success_ = false; | |
407 } else { | |
408 base::TimeTicks now = base::TimeTicks::Now(); | |
yzshen1
2011/05/25 03:49:06
Is it intended to not use ImplGetTimeNow here?
Jói
2011/05/25 14:30:35
No, thanks for catching that. I am writing tests
| |
409 if (!last_response_was_success_) { | |
410 // We are transitioning from failure to success, so generate our stats. | |
411 base::TimeDelta down_time = now - last_successful_response_time_; | |
412 int failure_count = GetBackoffEntry()->failure_count(); | |
413 | |
414 UMA_HISTOGRAM_COUNTS("Throttling.FailureCountAtSuccess", failure_count); | |
415 UMA_HISTOGRAM_CUSTOM_TIMES( | |
416 "Throttling.PerceivedDowntime", down_time, | |
417 base::TimeDelta::FromMilliseconds(10), | |
418 base::TimeDelta::FromHours(6), 50); | |
419 | |
420 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { | |
421 UMA_HISTOGRAM_COUNTS(base::FieldTrial::MakeName( | |
422 "Throttling.FailureCountAtSuccess", "ThrottlingEnabled"), | |
423 failure_count); | |
424 UMA_HISTOGRAM_CUSTOM_TIMES(base::FieldTrial::MakeName( | |
425 "Throttling.PerceivedDowntime", "ThrottlingEnabled"), down_time, | |
426 base::TimeDelta::FromMilliseconds(10), | |
427 base::TimeDelta::FromHours(6), 50); | |
428 } | |
429 } | |
430 | |
431 last_successful_response_time_ = now; | |
432 last_response_was_success_ = true; | |
433 } | |
434 } | |
435 | |
260 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { | 436 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { |
261 return &backoff_entry_; | 437 return &backoff_entry_; |
262 } | 438 } |
263 | 439 |
264 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { | 440 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { |
265 return &backoff_entry_; | 441 return &backoff_entry_; |
266 } | 442 } |
267 | 443 |
268 } // namespace net | 444 } // namespace net |
OLD | NEW |