1effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// found in the LICENSE file.
4effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/domain_reliability/dispatcher.h"
6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/bind.h"
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/callback.h"
9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/message_loop/message_loop.h"
10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/stl_util.h"
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/timer/timer.h"
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/domain_reliability/util.h"
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace domain_reliability {
15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
160de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)struct DomainReliabilityDispatcher::Task {
170de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  Task(const base::Closure& closure,
180de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)       scoped_ptr<MockableTime::Timer> timer,
190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)       base::TimeDelta min_delay,
200de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)       base::TimeDelta max_delay);
210de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  ~Task();
220de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
230de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  base::Closure closure;
240de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  scoped_ptr<MockableTime::Timer> timer;
250de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  base::TimeDelta min_delay;
260de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  base::TimeDelta max_delay;
270de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  bool eligible;
280de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)};
290de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
300de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)DomainReliabilityDispatcher::Task::Task(const base::Closure& closure,
310de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                        scoped_ptr<MockableTime::Timer> timer,
320de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                        base::TimeDelta min_delay,
330de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                        base::TimeDelta max_delay)
340de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    : closure(closure),
350de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      timer(timer.Pass()),
360de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      min_delay(min_delay),
370de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      max_delay(max_delay),
380de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      eligible(false) {}
390de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
400de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)DomainReliabilityDispatcher::Task::~Task() {}
410de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
42effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochDomainReliabilityDispatcher::DomainReliabilityDispatcher(MockableTime* time)
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : time_(time) {}
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
45effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochDomainReliabilityDispatcher::~DomainReliabilityDispatcher() {
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // TODO(ttuttle): STLElementDeleter?
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  STLDeleteElements(&tasks_);
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid DomainReliabilityDispatcher::ScheduleTask(
51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const base::Closure& closure,
52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    base::TimeDelta min_delay,
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    base::TimeDelta max_delay) {
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!closure.is_null());
55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Would be DCHECK_LE, but you can't << a TimeDelta.
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(min_delay <= max_delay);
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Task* task = new Task(closure, time_->CreateTimer(), min_delay, max_delay);
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  tasks_.insert(task);
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (max_delay.InMicroseconds() < 0)
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    RunAndDeleteTask(task);
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else if (min_delay.InMicroseconds() < 0)
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    MakeTaskEligible(task);
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    MakeTaskWaiting(task);
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid DomainReliabilityDispatcher::RunEligibleTasks() {
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Move all eligible tasks to a separate set so that eligible_tasks_.erase in
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // RunAndDeleteTask won't erase elements out from under the iterator.  (Also
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // keeps RunEligibleTasks from running forever if a task adds a new, already-
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // eligible task that does the same, and so on.)
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::set<Task*> tasks;
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  tasks.swap(eligible_tasks_);
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (std::set<Task*>::const_iterator it = tasks.begin();
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != tasks.end();
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++it) {
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    Task* task = *it;
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK(task);
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK(task->eligible);
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    RunAndDeleteTask(task);
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid DomainReliabilityDispatcher::MakeTaskWaiting(Task* task) {
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(task);
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!task->eligible);
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!task->timer->IsRunning());
900de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  task->timer->Start(FROM_HERE,
910de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                     task->min_delay,
920de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                     base::Bind(&DomainReliabilityDispatcher::MakeTaskEligible,
930de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                base::Unretained(this),
940de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                task));
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid
98effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochDomainReliabilityDispatcher::MakeTaskEligible(Task* task) {
99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(task);
100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!task->eligible);
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  task->eligible = true;
102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  eligible_tasks_.insert(task);
1030de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  task->timer->Start(FROM_HERE,
1040de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                     task->max_delay - task->min_delay,
1050de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                     base::Bind(&DomainReliabilityDispatcher::RunAndDeleteTask,
1060de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                base::Unretained(this),
1070de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                task));
108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid DomainReliabilityDispatcher::RunAndDeleteTask(Task* task) {
111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(task);
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!task->closure.is_null());
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  task->closure.Run();
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (task->eligible)
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    eligible_tasks_.erase(task);
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  tasks_.erase(task);
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  delete task;
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}  // namespace domain_reliability
121