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_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