// 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 task_runner, scoped_ptr 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