• 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_H_
6 #define CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_H_
7 
8 #include <deque>
9 #include <utility>
10 
11 #include "base/callback.h"
12 #include "base/memory/linked_ptr.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/time/time.h"
15 #include "base/timer/timer.h"
16 #include "net/base/backoff_entry.h"
17 
18 namespace extensions {
19 
20 // This class keeps track of a queue of requests, and contains the logic to
21 // retry requests with some backoff policy. Each request has a
22 // net::BackoffEntry instance associated with it.
23 //
24 // The general flow when using this class would be something like this:
25 //   - requests are queued up by calling ScheduleRequest.
26 //   - when a request is ready to be executed, RequestQueue removes the
27 //     request from the queue, assigns it as active request, and calls
28 //     the callback that was passed to the constructor.
29 //   - (optionally) when a request has completed unsuccessfully call
30 //     RetryRequest to put the request back in the queue, using the
31 //     backoff policy and minimum backoff delay to determine when to
32 //     next schedule this request.
33 //   - call reset_active_request() to indicate that the active request has
34 //     been dealt with.
35 //   - call StartNextRequest to schedule the next pending request (if any).
36 template<typename T>
37 class RequestQueue {
38  public:
39   class iterator;
40 
41   RequestQueue(const net::BackoffEntry::Policy* backoff_policy,
42                const base::Closure& start_request_callback);
43   ~RequestQueue();
44 
45   // Returns the request that is currently being processed.
46   T* active_request();
47 
48   // Returns the number of times the current request has been retried already.
49   int active_request_failure_count();
50 
51   // Signals RequestQueue that processing of the current request has completed.
52   scoped_ptr<T> reset_active_request();
53 
54   // Add the given request to the queue, and starts the next request if no
55   // request is currently being processed.
56   void ScheduleRequest(scoped_ptr<T> request);
57 
58   bool empty() const;
59   size_t size() const;
60 
61   // Returns the earliest release time of all requests currently in the queue.
62   base::TimeTicks NextReleaseTime() const;
63 
64   // Starts the next request, if no request is currently active. This will
65   // synchronously call the start_request_callback if the release time of the
66   // earliest available request is in the past, otherwise it will call that
67   // callback asynchronously after enough time has passed.
68   void StartNextRequest();
69 
70   // Tell RequestQueue to put the current request back in the queue, after
71   // applying the backoff policy to determine when to next try this request.
72   // If the policy results in a backoff delay smaller than |min_backoff_delay|,
73   // that delay is used instead.
74   void RetryRequest(const base::TimeDelta& min_backoff_delay);
75 
76   iterator begin();
77   iterator end();
78 
79   // Change the backoff policy used by the queue.
80   void set_backoff_policy(const net::BackoffEntry::Policy* backoff_policy);
81 
82  private:
83   struct Request {
RequestRequest84     Request(net::BackoffEntry* backoff_entry, T* request)
85         : backoff_entry(backoff_entry), request(request) {}
86     linked_ptr<net::BackoffEntry> backoff_entry;
87     linked_ptr<T> request;
88   };
89 
90   // Compares the release time of two pending requests.
91   static bool CompareRequests(const Request& a,
92                               const Request& b);
93 
94   // Pushes a request with a given backoff entry onto the queue.
95   void PushImpl(scoped_ptr<T> request,
96                 scoped_ptr<net::BackoffEntry> backoff_entry);
97 
98   // The backoff policy used to determine backoff delays.
99   const net::BackoffEntry::Policy* backoff_policy_;
100 
101   // Callback to call when a new request has become the active request.
102   base::Closure start_request_callback_;
103 
104   // Priority queue of pending requests. Not using std::priority_queue since
105   // the code needs to be able to iterate over all pending requests.
106   std::deque<Request> pending_requests_;
107 
108   // Active request and its associated backoff entry.
109   scoped_ptr<T> active_request_;
110   scoped_ptr<net::BackoffEntry> active_backoff_entry_;
111 
112   // Timer to schedule calls to StartNextRequest, if the first pending request
113   // hasn't passed its release time yet.
114   base::Timer timer_;
115 };
116 
117 // Iterator class that wraps a std::deque<> iterator, only giving access to the
118 // actual request part of each item.
119 template<typename T>
120 class RequestQueue<T>::iterator {
121  public:
iterator()122   iterator() {}
123 
124   T* operator*() { return it_->request.get(); }
125   T* operator->() { return it_->request.get(); }
126   iterator& operator++() {
127     ++it_;
128     return *this;
129   }
130   bool operator!=(const iterator& b) const {
131     return it_ != b.it_;
132   }
133 
134  private:
135   friend class RequestQueue<T>;
136   typedef std::deque<typename RequestQueue<T>::Request> Container;
137 
iterator(const typename Container::iterator & it)138   explicit iterator(const typename Container::iterator& it)
139       : it_(it) {}
140 
141   typename Container::iterator it_;
142 };
143 
144 
145 }  // namespace extensions
146 
147 #endif  // CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_H_
148