// Copyright (c) 2012 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. #ifndef EXTENSIONS_BROWSER_UPDATER_REQUEST_QUEUE_IMPL_H_ #define EXTENSIONS_BROWSER_UPDATER_REQUEST_QUEUE_IMPL_H_ #include #include #include #include "base/bind.h" #include "base/compiler_specific.h" #include "base/message_loop/message_loop.h" #include "base/stl_util.h" #include "extensions/browser/updater/request_queue.h" namespace extensions { template RequestQueue::RequestQueue( const net::BackoffEntry::Policy* const backoff_policy, const base::Closure& start_request_callback) : backoff_policy_(backoff_policy), start_request_callback_(start_request_callback), timer_(false, false) { } template RequestQueue::~RequestQueue() { } template T* RequestQueue::active_request() { return active_request_.get(); } template int RequestQueue::active_request_failure_count() { return active_backoff_entry_->failure_count(); } template scoped_ptr RequestQueue::reset_active_request() { active_backoff_entry_.reset(); return std::move(active_request_); } template void RequestQueue::ScheduleRequest(scoped_ptr request) { PushImpl(std::move(request), scoped_ptr( new net::BackoffEntry(backoff_policy_))); StartNextRequest(); } template void RequestQueue::PushImpl(scoped_ptr request, scoped_ptr backoff_entry) { pending_requests_.push_back( Request(backoff_entry.release(), request.release())); std::push_heap( pending_requests_.begin(), pending_requests_.end(), CompareRequests); } template bool RequestQueue::empty() const { return pending_requests_.empty(); } template size_t RequestQueue::size() const { return pending_requests_.size(); } template base::TimeTicks RequestQueue::NextReleaseTime() const { return pending_requests_.front().backoff_entry->GetReleaseTime(); } template void RequestQueue::StartNextRequest() { if (active_request_) // Already running a request, assume this method will be called again when // the request is done. return; if (empty()) // No requests in the queue, so we're done. return; base::TimeTicks next_release = NextReleaseTime(); base::TimeTicks now = base::TimeTicks::Now(); if (next_release > now) { // Not ready for the next update check yet, call this method when it is // time. timer_.Start( FROM_HERE, next_release - now, base::Bind(&RequestQueue::StartNextRequest, base::Unretained(this))); return; } // pop_heap swaps the first and last elements of pending_requests_, and after // that assures that the rest of pending_requests_ (excluding the // now last/formerly first element) forms a proper heap. After pop_heap // [begin, end-1) is a valid heap, and *(end - 1) contains the element that // used to be at the top of the heap. Since no elements are actually // removed from the container it is safe to read the entry being removed after // pop_heap is called (but before pop_back is called). std::pop_heap( pending_requests_.begin(), pending_requests_.end(), CompareRequests); active_backoff_entry_.reset(pending_requests_.back().backoff_entry.release()); active_request_.reset(pending_requests_.back().request.release()); pending_requests_.pop_back(); start_request_callback_.Run(); } template void RequestQueue::RetryRequest(const base::TimeDelta& min_backoff_delay) { active_backoff_entry_->InformOfRequest(false); if (active_backoff_entry_->GetTimeUntilRelease() < min_backoff_delay) { active_backoff_entry_->SetCustomReleaseTime(base::TimeTicks::Now() + min_backoff_delay); } PushImpl(std::move(active_request_), std::move(active_backoff_entry_)); } template typename RequestQueue::iterator RequestQueue::begin() { return iterator(pending_requests_.begin()); } template typename RequestQueue::iterator RequestQueue::end() { return iterator(pending_requests_.end()); } template void RequestQueue::set_backoff_policy( const net::BackoffEntry::Policy* backoff_policy) { backoff_policy_ = backoff_policy; } // static template bool RequestQueue::CompareRequests(const Request& a, const Request& b) { return a.backoff_entry->GetReleaseTime() > b.backoff_entry->GetReleaseTime(); } } // namespace extensions #endif // EXTENSIONS_BROWSER_UPDATER_REQUEST_QUEUE_IMPL_H_