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