summaryrefslogtreecommitdiffstats
path: root/chrome/browser/url_fetcher_protect.cc
blob: b19be6082e9d911bb77f2f780ba46559ddfa3fd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// 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/browser/url_fetcher_protect.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();
}

int 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();
  }

  int wait = static_cast<int>(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(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(
    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;
}