Home | History | Annotate | Download | only in updater
      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 {
     84     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:
    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 
    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