blob: b0992a61923b6d75f07b51280e9a305e5ad22f6e [file] [log] [blame]
// Copyright (c) 2013 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/policy/cloud/rate_limiter.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/time/tick_clock.h"
namespace policy {
RateLimiter::RateLimiter(size_t max_requests,
const base::TimeDelta& duration,
const base::Closure& callback,
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_ptr<base::TickClock> clock)
: max_requests_(max_requests),
duration_(duration),
callback_(callback),
task_runner_(task_runner),
clock_(clock.Pass()) {
DCHECK_GT(max_requests_, 0u);
}
RateLimiter::~RateLimiter() {}
void RateLimiter::PostRequest() {
DCHECK(CalledOnValidThread());
const base::TimeTicks now = clock_->NowTicks();
const base::TimeTicks period_start = now - duration_;
while (!invocation_times_.empty() &&
invocation_times_.front() <= period_start) {
invocation_times_.pop();
}
delayed_callback_.Cancel();
if (invocation_times_.size() < max_requests_) {
invocation_times_.push(now);
callback_.Run();
} else {
// From the while() loop above we have front() > period_start,
// so time_until_next_callback > 0.
const base::TimeDelta time_until_next_callback =
invocation_times_.front() - period_start;
delayed_callback_.Reset(
base::Bind(&RateLimiter::PostRequest, base::Unretained(this)));
task_runner_->PostDelayedTask(
FROM_HERE, delayed_callback_.callback(), time_until_next_callback);
}
}
} // namespace policy