Chromium Code Reviews| 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/base/backoff_entry.h" | 5 #include "net/base/backoff_entry.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
| 12 | 12 |
| 13 namespace net { | 13 namespace net { |
| 14 | 14 |
| 15 BackoffEntry::BackoffEntry(const BackoffEntry::Policy* const policy) | 15 BackoffEntry::BackoffEntry(const BackoffEntry::Policy* const policy) |
| 16 : failure_count_(0), | 16 : failure_count_(0), |
| 17 policy_(policy) { | 17 policy_(policy) { |
| 18 DCHECK(policy_); | 18 DCHECK(policy_); |
| 19 | 19 |
| 20 // Can't use GetTimeNow() as it's virtual. | 20 // Can't use ImplGetTimeNow() as it's virtual. |
|
wtc
2011/05/25 23:12:06
IMPORTANT: I wonder if the constructor should just
Jói
2011/05/26 14:53:42
Good point, I fixed this so that the constructor c
| |
| 21 exponential_backoff_release_time_ = base::TimeTicks::Now(); | 21 exponential_backoff_release_time_ = base::TimeTicks::Now(); |
| 22 } | 22 } |
| 23 | 23 |
| 24 BackoffEntry::~BackoffEntry() { | 24 BackoffEntry::~BackoffEntry() { |
| 25 // TODO(joi): Remove this once our clients (e.g. URLRequestThrottlerManager) | 25 // TODO(joi): Remove this once our clients (e.g. URLRequestThrottlerManager) |
| 26 // always destroy from the I/O thread. | 26 // always destroy from the I/O thread. |
| 27 DetachFromThread(); | 27 DetachFromThread(); |
| 28 } | 28 } |
| 29 | 29 |
| 30 void BackoffEntry::InformOfRequest(bool succeeded) { | 30 void BackoffEntry::InformOfRequest(bool succeeded) { |
| 31 if (!succeeded) { | 31 if (!succeeded) { |
| 32 ++failure_count_; | 32 ++failure_count_; |
| 33 exponential_backoff_release_time_ = CalculateReleaseTime(); | 33 exponential_backoff_release_time_ = CalculateReleaseTime(); |
| 34 } else { | 34 } else { |
| 35 // We slowly decay the number of times delayed instead of resetting it to 0 | 35 // We slowly decay the number of times delayed instead of resetting it to 0 |
| 36 // in order to stay stable if we receive successes interleaved between lots | 36 // in order to stay stable if we receive successes interleaved between lots |
| 37 // of failures. | 37 // of failures. |
| 38 // | 38 // |
| 39 // TODO(joi): Revisit this; it might be most correct to go to zero | 39 // TODO(joi): Revisit this; it might be most correct to go to zero |
| 40 // but have a way to go back to "old error count +1" if there is | 40 // but have a way to go back to "old error count +1" if there is |
| 41 // another error soon after. | 41 // another error soon after. |
| 42 if (failure_count_ > 0) | 42 if (failure_count_ > 0) |
| 43 --failure_count_; | 43 --failure_count_; |
| 44 | 44 |
| 45 // The reason why we are not just cutting the release time to GetTimeNow() | 45 // The reason why we are not just cutting the release time to |
| 46 // is on the one hand, it would unset a release time set by | 46 // ImplGetTimeNow() is on the one hand, it would unset a release |
| 47 // SetCustomReleaseTime and on the other we would like to push every | 47 // time set by SetCustomReleaseTime and on the other we would like |
| 48 // request up to our "horizon" when dealing with multiple in-flight | 48 // to push every request up to our "horizon" when dealing with |
| 49 // requests. Ex: If we send three requests and we receive 2 failures and | 49 // multiple in-flight requests. Ex: If we send three requests and |
| 50 // 1 success. The success that follows those failures will not reset the | 50 // we receive 2 failures and 1 success. The success that follows |
| 51 // release time, further requests will then need to wait the delay caused | 51 // those failures will not reset the release time, further |
| 52 // by the 2 failures. | 52 // requests will then need to wait the delay caused by the 2 |
| 53 // failures. | |
| 53 exponential_backoff_release_time_ = std::max( | 54 exponential_backoff_release_time_ = std::max( |
| 54 GetTimeNow(), exponential_backoff_release_time_); | 55 ImplGetTimeNow(), exponential_backoff_release_time_); |
| 55 } | 56 } |
| 56 } | 57 } |
| 57 | 58 |
| 58 bool BackoffEntry::ShouldRejectRequest() const { | 59 bool BackoffEntry::ShouldRejectRequest() const { |
| 59 return exponential_backoff_release_time_ > GetTimeNow(); | 60 return exponential_backoff_release_time_ > ImplGetTimeNow(); |
| 60 } | 61 } |
| 61 | 62 |
| 62 base::TimeTicks BackoffEntry::GetReleaseTime() const { | 63 base::TimeTicks BackoffEntry::GetReleaseTime() const { |
| 63 return exponential_backoff_release_time_; | 64 return exponential_backoff_release_time_; |
| 64 } | 65 } |
| 65 | 66 |
| 66 void BackoffEntry::SetCustomReleaseTime(const base::TimeTicks& release_time) { | 67 void BackoffEntry::SetCustomReleaseTime(const base::TimeTicks& release_time) { |
| 67 exponential_backoff_release_time_ = release_time; | 68 exponential_backoff_release_time_ = release_time; |
| 68 } | 69 } |
| 69 | 70 |
| 70 bool BackoffEntry::CanDiscard() const { | 71 bool BackoffEntry::CanDiscard() const { |
| 71 if (policy_->entry_lifetime_ms == -1) | 72 if (policy_->entry_lifetime_ms == -1) |
| 72 return false; | 73 return false; |
| 73 | 74 |
| 74 base::TimeTicks now = GetTimeNow(); | 75 base::TimeTicks now = ImplGetTimeNow(); |
| 75 | 76 |
| 76 int64 unused_since_ms = | 77 int64 unused_since_ms = |
| 77 (now - exponential_backoff_release_time_).InMilliseconds(); | 78 (now - exponential_backoff_release_time_).InMilliseconds(); |
| 78 | 79 |
| 79 // Release time is further than now, we are managing it. | 80 // Release time is further than now, we are managing it. |
| 80 if (unused_since_ms < 0) | 81 if (unused_since_ms < 0) |
| 81 return false; | 82 return false; |
| 82 | 83 |
| 83 if (failure_count_ > 0) { | 84 if (failure_count_ > 0) { |
| 84 // Need to keep track of failures until maximum back-off period | 85 // Need to keep track of failures until maximum back-off period |
| 85 // has passed (since further failures can add to back-off). | 86 // has passed (since further failures can add to back-off). |
| 86 return unused_since_ms >= std::max(policy_->maximum_backoff_ms, | 87 return unused_since_ms >= std::max(policy_->maximum_backoff_ms, |
| 87 policy_->entry_lifetime_ms); | 88 policy_->entry_lifetime_ms); |
| 88 } | 89 } |
| 89 | 90 |
| 90 // Otherwise, consider the entry is outdated if it hasn't been used for the | 91 // Otherwise, consider the entry is outdated if it hasn't been used for the |
| 91 // specified lifetime period. | 92 // specified lifetime period. |
| 92 return unused_since_ms >= policy_->entry_lifetime_ms; | 93 return unused_since_ms >= policy_->entry_lifetime_ms; |
| 93 } | 94 } |
| 94 | 95 |
| 95 base::TimeTicks BackoffEntry::GetTimeNow() const { | 96 void BackoffEntry::Reset() { |
| 97 failure_count_ = 0; | |
| 98 exponential_backoff_release_time_ = ImplGetTimeNow(); | |
| 99 } | |
| 100 | |
| 101 int BackoffEntry::failure_count() const { | |
| 102 return failure_count_; | |
| 103 } | |
| 104 | |
| 105 base::TimeTicks BackoffEntry::ImplGetTimeNow() const { | |
| 96 return base::TimeTicks::Now(); | 106 return base::TimeTicks::Now(); |
| 97 } | 107 } |
| 98 | 108 |
| 99 base::TimeTicks BackoffEntry::CalculateReleaseTime() const { | 109 base::TimeTicks BackoffEntry::CalculateReleaseTime() const { |
| 100 int effective_failure_count = | 110 int effective_failure_count = |
| 101 std::max(0, failure_count_ - policy_->num_errors_to_ignore); | 111 std::max(0, failure_count_ - policy_->num_errors_to_ignore); |
| 102 if (effective_failure_count == 0) { | 112 if (effective_failure_count == 0) { |
| 103 // Never reduce previously set release horizon, e.g. due to Retry-After | 113 // Never reduce previously set release horizon, e.g. due to Retry-After |
| 104 // header. | 114 // header. |
| 105 return std::max(GetTimeNow(), exponential_backoff_release_time_); | 115 return std::max(ImplGetTimeNow(), exponential_backoff_release_time_); |
| 106 } | 116 } |
| 107 | 117 |
| 108 // The delay is calculated with this formula: | 118 // The delay is calculated with this formula: |
| 109 // delay = initial_backoff * multiply_factor^( | 119 // delay = initial_backoff * multiply_factor^( |
| 110 // effective_failure_count - 1) * Uniform(1 - jitter_factor, 1] | 120 // effective_failure_count - 1) * Uniform(1 - jitter_factor, 1] |
| 111 double delay = policy_->initial_backoff_ms; | 121 double delay = policy_->initial_backoff_ms; |
| 112 delay *= pow(policy_->multiply_factor, effective_failure_count - 1); | 122 delay *= pow(policy_->multiply_factor, effective_failure_count - 1); |
| 113 delay -= base::RandDouble() * policy_->jitter_factor * delay; | 123 delay -= base::RandDouble() * policy_->jitter_factor * delay; |
| 114 | 124 |
| 115 // Ensure that we do not exceed maximum delay. | 125 // Ensure that we do not exceed maximum delay. |
| 116 int64 delay_int = static_cast<int64>(delay + 0.5); | 126 int64 delay_int = static_cast<int64>(delay + 0.5); |
| 117 delay_int = std::min(delay_int, | 127 delay_int = std::min(delay_int, |
| 118 static_cast<int64>(policy_->maximum_backoff_ms)); | 128 static_cast<int64>(policy_->maximum_backoff_ms)); |
| 119 | 129 |
| 120 // Never reduce previously set release horizon, e.g. due to Retry-After | 130 // Never reduce previously set release horizon, e.g. due to Retry-After |
| 121 // header. | 131 // header. |
| 122 return std::max(GetTimeNow() + base::TimeDelta::FromMilliseconds(delay_int), | 132 return std::max( |
| 123 exponential_backoff_release_time_); | 133 ImplGetTimeNow() + base::TimeDelta::FromMilliseconds(delay_int), |
| 134 exponential_backoff_release_time_); | |
| 124 } | 135 } |
| 125 | 136 |
| 126 } // namespace net | 137 } // namespace net |
| OLD | NEW |