1// Copyright (c) 2012 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#ifndef CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_IMPL_H_ 6#define CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_IMPL_H_ 7 8#include <algorithm> 9 10#include "base/bind.h" 11#include "base/compiler_specific.h" 12#include "base/message_loop/message_loop.h" 13#include "base/stl_util.h" 14#include "chrome/browser/extensions/updater/request_queue.h" 15 16namespace extensions { 17 18template<typename T> 19RequestQueue<T>::RequestQueue( 20 const net::BackoffEntry::Policy* const backoff_policy, 21 const base::Closure& start_request_callback) 22 : backoff_policy_(backoff_policy), 23 start_request_callback_(start_request_callback), 24 timer_(false, false) { 25} 26 27template<typename T> 28RequestQueue<T>::~RequestQueue() {} 29 30template<typename T> 31T* RequestQueue<T>::active_request() { 32 return active_request_.get(); 33} 34 35template<typename T> 36int RequestQueue<T>::active_request_failure_count() { 37 return active_backoff_entry_->failure_count(); 38} 39 40template<typename T> 41scoped_ptr<T> RequestQueue<T>::reset_active_request() { 42 active_backoff_entry_.reset(); 43 return active_request_.Pass(); 44} 45 46template<typename T> 47void RequestQueue<T>::ScheduleRequest(scoped_ptr<T> request) { 48 PushImpl(request.Pass(), scoped_ptr<net::BackoffEntry>( 49 new net::BackoffEntry(backoff_policy_))); 50 StartNextRequest(); 51} 52 53template<typename T> 54void RequestQueue<T>::PushImpl(scoped_ptr<T> request, 55 scoped_ptr<net::BackoffEntry> backoff_entry) { 56 pending_requests_.push_back(Request( 57 backoff_entry.release(), request.release())); 58 std::push_heap(pending_requests_.begin(), pending_requests_.end(), 59 CompareRequests); 60} 61 62template<typename T> 63bool RequestQueue<T>::empty() const { 64 return pending_requests_.empty(); 65} 66 67template<typename T> 68size_t RequestQueue<T>::size() const { 69 return pending_requests_.size(); 70} 71 72template<typename T> 73base::TimeTicks RequestQueue<T>::NextReleaseTime() const { 74 return pending_requests_.front().backoff_entry->GetReleaseTime(); 75} 76 77template<typename T> 78void RequestQueue<T>::StartNextRequest() { 79 if (active_request_) 80 // Already running a request, assume this method will be called again when 81 // the request is done. 82 return; 83 84 if (empty()) 85 // No requests in the queue, so we're done. 86 return; 87 88 base::TimeTicks next_release = NextReleaseTime(); 89 base::TimeTicks now = base::TimeTicks::Now(); 90 if (next_release > now) { 91 // Not ready for the next update check yet, call this method when it is 92 // time. 93 timer_.Start(FROM_HERE, next_release - now, 94 base::Bind(&RequestQueue<T>::StartNextRequest, 95 base::Unretained(this))); 96 return; 97 } 98 99 // pop_heap swaps the first and last elements of pending_requests_, and after 100 // that assures that the rest of pending_requests_ (excluding the 101 // now last/formerly first element) forms a proper heap. After pop_heap 102 // [begin, end-1) is a valid heap, and *(end - 1) contains the element that 103 // used to be at the top of the heap. Since no elements are actually 104 // removed from the container it is safe to read the entry being removed after 105 // pop_heap is called (but before pop_back is called). 106 std::pop_heap(pending_requests_.begin(), pending_requests_.end(), 107 CompareRequests); 108 109 active_backoff_entry_.reset(pending_requests_.back().backoff_entry.release()); 110 active_request_.reset(pending_requests_.back().request.release()); 111 112 pending_requests_.pop_back(); 113 114 start_request_callback_.Run(); 115} 116 117template<typename T> 118void RequestQueue<T>::RetryRequest(const base::TimeDelta& min_backoff_delay) { 119 active_backoff_entry_->InformOfRequest(false); 120 if (active_backoff_entry_->GetTimeUntilRelease() < min_backoff_delay) { 121 active_backoff_entry_->SetCustomReleaseTime( 122 base::TimeTicks::Now() + min_backoff_delay); 123 } 124 PushImpl(active_request_.Pass(), active_backoff_entry_.Pass()); 125} 126 127template<typename T> 128typename RequestQueue<T>::iterator RequestQueue<T>::begin() { 129 return iterator(pending_requests_.begin()); 130} 131 132template<typename T> 133typename RequestQueue<T>::iterator RequestQueue<T>::end() { 134 return iterator(pending_requests_.end()); 135} 136 137template<typename T> 138void RequestQueue<T>::set_backoff_policy( 139 const net::BackoffEntry::Policy* backoff_policy) { 140 backoff_policy_ = backoff_policy; 141} 142 143// static 144template<typename T> 145bool RequestQueue<T>::CompareRequests( 146 const Request& a, 147 const Request& b) { 148 return a.backoff_entry->GetReleaseTime() > 149 b.backoff_entry->GetReleaseTime(); 150} 151 152} // namespace extensions 153 154#endif // CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_IMPL_H_ 155