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 16 namespace extensions { 17 18 template<typename T> 19 RequestQueue<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 27 template<typename T> 28 RequestQueue<T>::~RequestQueue() {} 29 30 template<typename T> 31 T* RequestQueue<T>::active_request() { 32 return active_request_.get(); 33 } 34 35 template<typename T> 36 int RequestQueue<T>::active_request_failure_count() { 37 return active_backoff_entry_->failure_count(); 38 } 39 40 template<typename T> 41 scoped_ptr<T> RequestQueue<T>::reset_active_request() { 42 active_backoff_entry_.reset(); 43 return active_request_.Pass(); 44 } 45 46 template<typename T> 47 void 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 53 template<typename T> 54 void 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 62 template<typename T> 63 bool RequestQueue<T>::empty() const { 64 return pending_requests_.empty(); 65 } 66 67 template<typename T> 68 size_t RequestQueue<T>::size() const { 69 return pending_requests_.size(); 70 } 71 72 template<typename T> 73 base::TimeTicks RequestQueue<T>::NextReleaseTime() const { 74 return pending_requests_.front().backoff_entry->GetReleaseTime(); 75 } 76 77 template<typename T> 78 void 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 117 template<typename T> 118 void 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 127 template<typename T> 128 typename RequestQueue<T>::iterator RequestQueue<T>::begin() { 129 return iterator(pending_requests_.begin()); 130 } 131 132 template<typename T> 133 typename RequestQueue<T>::iterator RequestQueue<T>::end() { 134 return iterator(pending_requests_.end()); 135 } 136 137 template<typename T> 138 void RequestQueue<T>::set_backoff_policy( 139 const net::BackoffEntry::Policy* backoff_policy) { 140 backoff_policy_ = backoff_policy; 141 } 142 143 // static 144 template<typename T> 145 bool 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