• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
RequestQueue(const net::BackoffEntry::Policy * const backoff_policy,const base::Closure & start_request_callback)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>
~RequestQueue()28 RequestQueue<T>::~RequestQueue() {}
29 
30 template<typename T>
active_request()31 T* RequestQueue<T>::active_request() {
32   return active_request_.get();
33 }
34 
35 template<typename T>
active_request_failure_count()36 int RequestQueue<T>::active_request_failure_count() {
37   return active_backoff_entry_->failure_count();
38 }
39 
40 template<typename T>
reset_active_request()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>
ScheduleRequest(scoped_ptr<T> request)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>
PushImpl(scoped_ptr<T> request,scoped_ptr<net::BackoffEntry> backoff_entry)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>
empty()63 bool RequestQueue<T>::empty() const {
64   return pending_requests_.empty();
65 }
66 
67 template<typename T>
size()68 size_t RequestQueue<T>::size() const {
69   return pending_requests_.size();
70 }
71 
72 template<typename T>
NextReleaseTime()73 base::TimeTicks RequestQueue<T>::NextReleaseTime() const {
74   return pending_requests_.front().backoff_entry->GetReleaseTime();
75 }
76 
77 template<typename T>
StartNextRequest()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>
RetryRequest(const base::TimeDelta & min_backoff_delay)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>
begin()128 typename RequestQueue<T>::iterator RequestQueue<T>::begin() {
129   return iterator(pending_requests_.begin());
130 }
131 
132 template<typename T>
end()133 typename RequestQueue<T>::iterator RequestQueue<T>::end() {
134   return iterator(pending_requests_.end());
135 }
136 
137 template<typename T>
set_backoff_policy(const net::BackoffEntry::Policy * backoff_policy)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>
CompareRequests(const Request & a,const Request & b)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