1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "components/policy/core/common/cloud/rate_limiter.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/location.h" 10#include "base/logging.h" 11#include "base/sequenced_task_runner.h" 12#include "base/time/tick_clock.h" 13 14namespace policy { 15 16RateLimiter::RateLimiter(size_t max_requests, 17 const base::TimeDelta& duration, 18 const base::Closure& callback, 19 scoped_refptr<base::SequencedTaskRunner> task_runner, 20 scoped_ptr<base::TickClock> clock) 21 : max_requests_(max_requests), 22 duration_(duration), 23 callback_(callback), 24 task_runner_(task_runner), 25 clock_(clock.Pass()) { 26 DCHECK_GT(max_requests_, 0u); 27} 28 29RateLimiter::~RateLimiter() {} 30 31void RateLimiter::PostRequest() { 32 DCHECK(CalledOnValidThread()); 33 34 const base::TimeTicks now = clock_->NowTicks(); 35 const base::TimeTicks period_start = now - duration_; 36 while (!invocation_times_.empty() && 37 invocation_times_.front() <= period_start) { 38 invocation_times_.pop(); 39 } 40 41 delayed_callback_.Cancel(); 42 43 if (invocation_times_.size() < max_requests_) { 44 invocation_times_.push(now); 45 callback_.Run(); 46 } else { 47 // From the while() loop above we have front() > period_start, 48 // so time_until_next_callback > 0. 49 const base::TimeDelta time_until_next_callback = 50 invocation_times_.front() - period_start; 51 delayed_callback_.Reset( 52 base::Bind(&RateLimiter::PostRequest, base::Unretained(this))); 53 task_runner_->PostDelayedTask( 54 FROM_HERE, delayed_callback_.callback(), time_until_next_callback); 55 } 56} 57 58} // namespace policy 59