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

Side by Side Diff: net/request_throttler/request_throttler_entry.cc

Issue 3005049: This CL will introduce a new way to do exponential back-off on failure within... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/request_throttler/request_throttler_entry.h"
6
7 #include <cmath>
8
9 #include "base/logging.h"
10 #include "base/rand_util.h"
11 #include "base/string_number_conversions.h"
12 #include "base/string_util.h"
13 #include "net/request_throttler/request_throttler_header_interface.h"
14
15 const int RequestThrottlerEntry::kAdditionalConstantMs = 100;
16 const int RequestThrottlerEntry::kEntryLifetimeSec = 120;
17 const double RequestThrottlerEntry::kJitterFactor = 0.4;
18 const int RequestThrottlerEntry::kInitialBackoffMs = 700;
19 const int RequestThrottlerEntry::kMaximumBackoffMs = 24 * 60 * 60 * 1000;
20 const double RequestThrottlerEntry::kMultiplyFactor = 2.0;
21 const char RequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After";
22
23 RequestThrottlerEntry::RequestThrottlerEntry()
24 : release_time_(base::TimeTicks::Now()),
25 num_times_delayed_(0),
26 is_managed_(false) {
27 SaveState();
28 }
29
30 RequestThrottlerEntry::~RequestThrottlerEntry() {
31 }
32
33 bool RequestThrottlerEntry::IsRequestAllowed() const {
34 return (release_time_ <= GetTimeNow());
35 }
36
37 void RequestThrottlerEntry::UpdateWithResponse(
38 const RequestThrottlerHeaderInterface* response) {
39 SaveState();
40 if (response->GetResponseCode() >= 500) {
41 num_times_delayed_++;
42 release_time_ = std::max(CalculateReleaseTime(), release_time_);
43 is_managed_ = true;
44 } else {
45 // We slowly decay the number of times delayed instead of resetting it to 0
46 // in order to stay stable if we received lots of requests with
47 // malformed bodies at the same time.
48 if (num_times_delayed_ > 0)
49 num_times_delayed_--;
50 is_managed_ = false;
51 // The reason why we are not just cutting release_time to GetTimeNow() is
52 // on the one hand, it would unset delay put by our custom retry-after
53 // header and on the other we would like to push every request up to our
54 // "horizon" when dealing with multiple in-flight request. Ex: If we send
55 // three request and we receive 2 failures and 1 success. The success that
56 // follows those failures will not reset release time further request will
57 // then need to wait the delay caused by the 2 failures.
58 release_time_ = std::max(GetTimeNow(), release_time_);
59 if (response->GetNormalizedValue(kRetryHeaderName) != std::string())
60 HandleCustomRetryAfter(response->GetNormalizedValue(kRetryHeaderName));
61 }
62 }
63
64 bool RequestThrottlerEntry::IsEntryOutdated() const {
65 int64 unused_since_ms = (GetTimeNow() - release_time_).InMilliseconds();
66 int64 lifespan_ms = kEntryLifetimeSec * 1000;
67
68 // Release time is further than now, we are managing it.
69 if (unused_since_ms < 0)
70 return false;
71
72 // There are two cases. First one, when the entry is currently being managed
73 // and should not be collected unless it is older than the maximum allowed
74 // back-off. The other one, when the entry is outdated, unmanaged and should
75 // be collected.
76 if (is_managed_)
77 return unused_since_ms > kMaximumBackoffMs;
78
79 return unused_since_ms > lifespan_ms;
80 }
81
82 void RequestThrottlerEntry::ReceivedContentWasMalformed() {
83 // We should never revert to less back-off or else an attacker could put a
84 // malformed body in cache and replay it to decrease delay.
85 num_times_delayed_ =
86 std::max(old_values_.number_of_failed_requests, num_times_delayed_);
87 num_times_delayed_++;
88 is_managed_ = true;
89 release_time_ = std::max(CalculateReleaseTime(),
90 std::max(old_values_.release_time, release_time_));
91 }
92
93 base::TimeTicks RequestThrottlerEntry::CalculateReleaseTime() {
94 double delay = kInitialBackoffMs;
95 delay *= pow(kMultiplyFactor, num_times_delayed_);
96 delay += kAdditionalConstantMs;
97 delay -= base::RandDouble() * kJitterFactor * delay;
98
99 // Ensure that we do not exceed maximum delay
100 int64 delay_int = static_cast<int64>(delay + 0.5);
101 delay_int = std::min(delay_int, static_cast<int64>(kMaximumBackoffMs));
102
103 return GetTimeNow() + base::TimeDelta::FromMilliseconds(delay_int);
104 }
105
106 base::TimeTicks RequestThrottlerEntry::GetTimeNow() const {
107 return base::TimeTicks::Now();
108 }
109
110 void RequestThrottlerEntry::HandleCustomRetryAfter(
111 const std::string& header_value) {
112 // Input parameter is the number of seconds to wait in a floating point value.
113 double time_in_sec = 0;
114 bool conversion_is_ok = base::StringToDouble(header_value, &time_in_sec);
115
116 // Conversion of custom retry-after header value failed.
117 if (!conversion_is_ok)
118 return;
119
120 // We must use an int value later so we transform this in milliseconds.
121 int64 value_ms = static_cast<int64>(0.5 + time_in_sec * 1000);
122
123 if (kMaximumBackoffMs < value_ms || value_ms < 0)
124 return;
125
126 release_time_ = std::max(
127 (GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms)),
128 release_time_);
129 }
130
131 void RequestThrottlerEntry::SaveState() {
132 old_values_.release_time = release_time_;
133 old_values_.number_of_failed_requests = num_times_delayed_;
134 }
OLDNEW
« no previous file with comments | « net/request_throttler/request_throttler_entry.h ('k') | net/request_throttler/request_throttler_entry_interface.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698