diff options
Diffstat (limited to 'net/base/backoff_entry.cc')
-rw-r--r-- | net/base/backoff_entry.cc | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/net/base/backoff_entry.cc b/net/base/backoff_entry.cc new file mode 100644 index 0000000..830eca4 --- /dev/null +++ b/net/base/backoff_entry.cc @@ -0,0 +1,119 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/base/backoff_entry.h" + +#include <algorithm> +#include <cmath> + +#include "base/logging.h" +#include "base/rand_util.h" + +namespace net { + +BackoffEntry::BackoffEntry(const BackoffEntry::Policy* const policy) + : failure_count_(0), + policy_(policy) { + DCHECK(policy_); + + // Can't use GetTimeNow() as it's virtual. + exponential_backoff_release_time_ = base::TimeTicks::Now(); +} + +BackoffEntry::~BackoffEntry() { + // TODO(joi): Remove this once our clients (e.g. URLRequestThrottlerManager) + // always destroy from the I/O thread; at the moment we may be destroyed + // from the main thread (during AtExit processing). + DetachFromThread(); +} + +void BackoffEntry::InformOfRequest(bool succeeded) { + if (!succeeded) { + failure_count_++; + exponential_backoff_release_time_ = CalculateReleaseTime(); + } else { + failure_count_ = 0; + + // The reason why we are not just cutting the release time to GetTimeNow() + // is on the one hand, it would unset a release time set by + // SetCustomReleaseTime and on the other we would like to push every + // request up to our "horizon" when dealing with multiple in-flight + // requests. Ex: If we send three requests and we receive 2 failures and + // 1 success. The success that follows those failures will not reset the + // release time, further requests will then need to wait the delay caused + // by the 2 failures. + exponential_backoff_release_time_ = std::max( + GetTimeNow(), exponential_backoff_release_time_); + } +} + +bool BackoffEntry::ShouldRejectRequest() const { + return exponential_backoff_release_time_ > GetTimeNow(); +} + +base::TimeTicks BackoffEntry::GetReleaseTime() const { + return exponential_backoff_release_time_; +} + +void BackoffEntry::SetCustomReleaseTime(const base::TimeTicks& release_time) { + exponential_backoff_release_time_ = release_time; +} + +bool BackoffEntry::CanDiscard() const { + if (policy_->entry_lifetime_ms == -1) + return false; + + base::TimeTicks now = GetTimeNow(); + + int64 unused_since_ms = + (now - exponential_backoff_release_time_).InMilliseconds(); + + // Release time is further than now, we are managing it. + if (unused_since_ms < 0) + return false; + + if (failure_count_ > 0) { + // Need to keep track of failures until maximum back-off period + // has passed (since further failures can add to back-off). + return unused_since_ms >= std::max(policy_->maximum_backoff_ms, + policy_->entry_lifetime_ms); + } + + // Otherwise, consider the entry is outdated if it hasn't been used for the + // specified lifetime period. + return unused_since_ms >= policy_->entry_lifetime_ms; +} + +base::TimeTicks BackoffEntry::GetTimeNow() const { + return base::TimeTicks::Now(); +} + +base::TimeTicks BackoffEntry::CalculateReleaseTime() const { + int effective_failure_count = + std::max(0, failure_count_ - policy_->num_errors_to_ignore); + if (effective_failure_count == 0) { + // Never reduce previously set release horizon, e.g. due to Retry-After + // header. + return std::max(GetTimeNow(), exponential_backoff_release_time_); + } + + // The delay is calculated with this formula: + // delay = initial_backoff * multiply_factor^( + // effective_failure_count - 1) * Uniform(1 - jitter_factor, 1] + double delay = policy_->initial_backoff_ms; + delay *= pow(policy_->multiply_factor, effective_failure_count - 1); + delay -= base::RandDouble() * policy_->jitter_factor * delay; + + // Ensure that we do not exceed maximum delay. + int64 delay_int = static_cast<int64>(delay + 0.5); + delay_int = std::min(delay_int, + static_cast<int64>(policy_->maximum_backoff_ms)); + + // Never reduce previously set release horizon, e.g. due to Retry-After + // header. + return std::max(GetTimeNow() + base::TimeDelta::FromMilliseconds(delay_int), + exponential_backoff_release_time_); +} + +} // namespace net |