12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_IMPL_H_
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_IMPL_H_
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/updater/request_queue.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)RequestQueue<T>::RequestQueue(
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::BackoffEntry::Policy* const backoff_policy,
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Closure& start_request_callback)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : backoff_policy_(backoff_policy),
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      start_request_callback_(start_request_callback),
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      timer_(false, false) {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)RequestQueue<T>::~RequestQueue() {}
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)T* RequestQueue<T>::active_request() {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return active_request_.get();
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int RequestQueue<T>::active_request_failure_count() {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return active_backoff_entry_->failure_count();
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<T> RequestQueue<T>::reset_active_request() {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  active_backoff_entry_.reset();
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return active_request_.Pass();
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RequestQueue<T>::ScheduleRequest(scoped_ptr<T> request) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PushImpl(request.Pass(), scoped_ptr<net::BackoffEntry>(
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new net::BackoffEntry(backoff_policy_)));
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartNextRequest();
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RequestQueue<T>::PushImpl(scoped_ptr<T> request,
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               scoped_ptr<net::BackoffEntry> backoff_entry) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pending_requests_.push_back(Request(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      backoff_entry.release(), request.release()));
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::push_heap(pending_requests_.begin(), pending_requests_.end(),
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 CompareRequests);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool RequestQueue<T>::empty() const {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return pending_requests_.empty();
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t RequestQueue<T>::size() const {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return pending_requests_.size();
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::TimeTicks RequestQueue<T>::NextReleaseTime() const {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return pending_requests_.front().backoff_entry->GetReleaseTime();
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RequestQueue<T>::StartNextRequest() {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (active_request_)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Already running a request, assume this method will be called again when
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the request is done.
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (empty())
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // No requests in the queue, so we're done.
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks next_release = NextReleaseTime();
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (next_release > now) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Not ready for the next update check yet, call this method when it is
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // time.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    timer_.Start(FROM_HERE, next_release - now,
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&RequestQueue<T>::StartNextRequest,
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     base::Unretained(this)));
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // pop_heap swaps the first and last elements of pending_requests_, and after
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that assures that the rest of pending_requests_ (excluding the
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // now last/formerly first element) forms a proper heap. After pop_heap
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // [begin, end-1) is a valid heap, and *(end - 1) contains the element that
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // used to be at the top of the heap. Since no elements are actually
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // removed from the container it is safe to read the entry being removed after
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // pop_heap is called (but before pop_back is called).
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::pop_heap(pending_requests_.begin(), pending_requests_.end(),
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                CompareRequests);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  active_backoff_entry_.reset(pending_requests_.back().backoff_entry.release());
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  active_request_.reset(pending_requests_.back().request.release());
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pending_requests_.pop_back();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  start_request_callback_.Run();
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RequestQueue<T>::RetryRequest(const base::TimeDelta& min_backoff_delay) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  active_backoff_entry_->InformOfRequest(false);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (active_backoff_entry_->GetTimeUntilRelease() < min_backoff_delay) {
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    active_backoff_entry_->SetCustomReleaseTime(
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeTicks::Now() + min_backoff_delay);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PushImpl(active_request_.Pass(), active_backoff_entry_.Pass());
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typename RequestQueue<T>::iterator RequestQueue<T>::begin() {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return iterator(pending_requests_.begin());
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typename RequestQueue<T>::iterator RequestQueue<T>::end() {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return iterator(pending_requests_.end());
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RequestQueue<T>::set_backoff_policy(
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::BackoffEntry::Policy* backoff_policy) {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  backoff_policy_ = backoff_policy;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool RequestQueue<T>::CompareRequests(
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Request& a,
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Request& b) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return a.backoff_entry->GetReleaseTime() >
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         b.backoff_entry->GetReleaseTime();
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif  // CHROME_BROWSER_EXTENSIONS_UPDATER_REQUEST_QUEUE_IMPL_H_
155