blob: 05c8e2e2f771f6340bf23494df16d4fde67c2c7e [file] [log] [blame]
// Copyright (c) 2006-2008 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 "chrome/common/net/url_fetcher_protect.h"
#include "base/logging.h"
// URLFetcherProtectEntry ----------------------------------------------------
using base::TimeDelta;
using base::TimeTicks;
// Default parameters. Time is in milliseconds.
// static
const int URLFetcherProtectEntry::kDefaultSlidingWindowPeriod = 2000;
const int URLFetcherProtectEntry::kDefaultMaxSendThreshold = 20;
const int URLFetcherProtectEntry::kDefaultMaxRetries = 0;
const int URLFetcherProtectEntry::kDefaultInitialTimeout = 100;
const double URLFetcherProtectEntry::kDefaultMultiplier = 2.0;
const int URLFetcherProtectEntry::kDefaultConstantFactor = 100;
const int URLFetcherProtectEntry::kDefaultMaximumTimeout = 60000;
URLFetcherProtectEntry::URLFetcherProtectEntry()
: sliding_window_period_(kDefaultSlidingWindowPeriod),
max_send_threshold_(kDefaultMaxSendThreshold),
max_retries_(kDefaultMaxRetries),
initial_timeout_(kDefaultInitialTimeout),
multiplier_(kDefaultMultiplier),
constant_factor_(kDefaultConstantFactor),
maximum_timeout_(kDefaultMaximumTimeout) {
ResetBackoff();
}
URLFetcherProtectEntry::URLFetcherProtectEntry(int sliding_window_period,
int max_send_threshold,
int max_retries,
int initial_timeout,
double multiplier,
int constant_factor,
int maximum_timeout)
: sliding_window_period_(sliding_window_period),
max_send_threshold_(max_send_threshold),
max_retries_(max_retries),
initial_timeout_(initial_timeout),
multiplier_(multiplier),
constant_factor_(constant_factor),
maximum_timeout_(maximum_timeout) {
ResetBackoff();
}
int64 URLFetcherProtectEntry::UpdateBackoff(EventType event_type) {
// request may be sent in different threads
AutoLock lock(lock_);
TimeDelta t;
switch (event_type) {
case SEND:
t = AntiOverload();
break;
case SUCCESS:
t = ResetBackoff();
break;
case FAILURE:
t = IncreaseBackoff();
break;
default:
NOTREACHED();
}
int64 wait = t.InMilliseconds();
DCHECK(wait >= 0);
return wait;
}
TimeDelta URLFetcherProtectEntry::AntiOverload() {
TimeDelta sw = TimeDelta::FromMilliseconds(sliding_window_period_);
TimeTicks now = TimeTicks::Now();
// Estimate when the next request will be sent.
release_time_ = now;
if (send_log_.size() > 0) {
release_time_ = std::max(release_time_, send_log_.back());
}
// Checks if there are too many send events in recent time.
if (send_log_.size() >= static_cast<unsigned>(max_send_threshold_)) {
release_time_ = std::max(release_time_, send_log_.front() + sw);
}
// Logs the new send event.
send_log_.push(release_time_);
// Drops the out-of-date events in the event list.
while (!send_log_.empty() &&
(send_log_.front() + sw <= send_log_.back())) {
send_log_.pop();
}
return release_time_ - now;
}
TimeDelta URLFetcherProtectEntry::ResetBackoff() {
timeout_period_ = initial_timeout_;
release_time_ = TimeTicks::Now();
return TimeDelta::FromMilliseconds(0);
}
TimeDelta URLFetcherProtectEntry::IncreaseBackoff() {
TimeTicks now = TimeTicks::Now();
release_time_ = std::max(release_time_, now) +
TimeDelta::FromMilliseconds(timeout_period_);
// Calculates the new backoff time.
timeout_period_ = static_cast<int>
(multiplier_ * timeout_period_ + constant_factor_);
if (maximum_timeout_ && timeout_period_ > maximum_timeout_)
timeout_period_ = maximum_timeout_;
return release_time_ - now;
}
// URLFetcherProtectManager --------------------------------------------------
// static
scoped_ptr<URLFetcherProtectManager> URLFetcherProtectManager::protect_manager_;
Lock URLFetcherProtectManager::lock_;
URLFetcherProtectManager::~URLFetcherProtectManager() {
// Deletes all entries
ProtectService::iterator i;
for (i = services_.begin(); i != services_.end(); ++i) {
if (i->second)
delete i->second;
}
}
// static
URLFetcherProtectManager* URLFetcherProtectManager::GetInstance() {
AutoLock lock(lock_);
if (protect_manager_.get() == NULL) {
protect_manager_.reset(new URLFetcherProtectManager());
}
return protect_manager_.get();
}
URLFetcherProtectEntry* URLFetcherProtectManager::Register(
const std::string& id) {
AutoLock lock(lock_);
ProtectService::iterator i = services_.find(id);
if (i != services_.end()) {
// The entry exists.
return i->second;
}
// Creates a new entry.
URLFetcherProtectEntry* entry = new URLFetcherProtectEntry();
services_[id] = entry;
return entry;
}
URLFetcherProtectEntry* URLFetcherProtectManager::Register(
const std::string& id, URLFetcherProtectEntry* entry) {
AutoLock lock(lock_);
ProtectService::iterator i = services_.find(id);
if (i != services_.end()) {
// The entry exists.
delete i->second;
}
services_[id] = entry;
return entry;
}