[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 1 | // Copyright 2014 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 | #include "components/domain_reliability/dispatcher.h" |
| 6 | |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 7 | #include <algorithm> |
Gyuyoung Kim | 6afb508 | 2018-01-19 13:35:57 | [diff] [blame] | 8 | #include <memory> |
dcheng | 5160635 | 2015-12-26 21:16:23 | [diff] [blame] | 9 | #include <utility> |
| 10 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 11 | #include "base/bind.h" |
[email protected] | b5c2b74 | 2014-06-14 22:21:42 | [diff] [blame] | 12 | #include "base/callback.h" |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 13 | #include "base/timer/timer.h" |
| 14 | #include "components/domain_reliability/util.h" |
| 15 | |
| 16 | namespace domain_reliability { |
| 17 | |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 18 | struct DomainReliabilityDispatcher::Task { |
| 19 | Task(const base::Closure& closure, |
dcheng | 04a35cd | 2016-04-22 15:07:24 | [diff] [blame] | 20 | std::unique_ptr<MockableTime::Timer> timer, |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 21 | base::TimeDelta min_delay, |
| 22 | base::TimeDelta max_delay); |
| 23 | ~Task(); |
| 24 | |
| 25 | base::Closure closure; |
dcheng | 04a35cd | 2016-04-22 15:07:24 | [diff] [blame] | 26 | std::unique_ptr<MockableTime::Timer> timer; |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 27 | base::TimeDelta min_delay; |
| 28 | base::TimeDelta max_delay; |
| 29 | bool eligible; |
| 30 | }; |
| 31 | |
dcheng | 04a35cd | 2016-04-22 15:07:24 | [diff] [blame] | 32 | DomainReliabilityDispatcher::Task::Task( |
| 33 | const base::Closure& closure, |
| 34 | std::unique_ptr<MockableTime::Timer> timer, |
| 35 | base::TimeDelta min_delay, |
| 36 | base::TimeDelta max_delay) |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 37 | : closure(closure), |
dcheng | 5160635 | 2015-12-26 21:16:23 | [diff] [blame] | 38 | timer(std::move(timer)), |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 39 | min_delay(min_delay), |
| 40 | max_delay(max_delay), |
| 41 | eligible(false) {} |
| 42 | |
| 43 | DomainReliabilityDispatcher::Task::~Task() {} |
| 44 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 45 | DomainReliabilityDispatcher::DomainReliabilityDispatcher(MockableTime* time) |
| 46 | : time_(time) {} |
| 47 | |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 48 | DomainReliabilityDispatcher::~DomainReliabilityDispatcher() {} |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 49 | |
| 50 | void DomainReliabilityDispatcher::ScheduleTask( |
| 51 | const base::Closure& closure, |
| 52 | base::TimeDelta min_delay, |
| 53 | base::TimeDelta max_delay) { |
| 54 | DCHECK(!closure.is_null()); |
| 55 | // Would be DCHECK_LE, but you can't << a TimeDelta. |
| 56 | DCHECK(min_delay <= max_delay); |
| 57 | |
Gyuyoung Kim | 6afb508 | 2018-01-19 13:35:57 | [diff] [blame] | 58 | std::unique_ptr<Task> owned_task = std::make_unique<Task>( |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 59 | closure, time_->CreateTimer(), min_delay, max_delay); |
| 60 | Task* task = owned_task.get(); |
| 61 | tasks_.insert(std::move(owned_task)); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 62 | if (max_delay.InMicroseconds() < 0) |
| 63 | RunAndDeleteTask(task); |
| 64 | else if (min_delay.InMicroseconds() < 0) |
| 65 | MakeTaskEligible(task); |
| 66 | else |
| 67 | MakeTaskWaiting(task); |
| 68 | } |
| 69 | |
| 70 | void DomainReliabilityDispatcher::RunEligibleTasks() { |
| 71 | // Move all eligible tasks to a separate set so that eligible_tasks_.erase in |
| 72 | // RunAndDeleteTask won't erase elements out from under the iterator. (Also |
| 73 | // keeps RunEligibleTasks from running forever if a task adds a new, already- |
| 74 | // eligible task that does the same, and so on.) |
| 75 | std::set<Task*> tasks; |
| 76 | tasks.swap(eligible_tasks_); |
| 77 | |
vmpstr | 2de366b | 2016-07-20 21:35:48 | [diff] [blame] | 78 | for (auto* task : tasks) { |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 79 | DCHECK(task); |
| 80 | DCHECK(task->eligible); |
| 81 | RunAndDeleteTask(task); |
| 82 | } |
| 83 | } |
| 84 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 85 | void DomainReliabilityDispatcher::RunAllTasksForTesting() { |
| 86 | std::set<Task*> tasks; |
| 87 | for (auto& task : tasks_) |
| 88 | tasks.insert(task.get()); |
| 89 | |
| 90 | for (auto* task : tasks) { |
| 91 | DCHECK(task); |
| 92 | RunAndDeleteTask(task); |
| 93 | } |
| 94 | } |
| 95 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 96 | void DomainReliabilityDispatcher::MakeTaskWaiting(Task* task) { |
| 97 | DCHECK(task); |
| 98 | DCHECK(!task->eligible); |
| 99 | DCHECK(!task->timer->IsRunning()); |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 100 | task->timer->Start(FROM_HERE, |
| 101 | task->min_delay, |
| 102 | base::Bind(&DomainReliabilityDispatcher::MakeTaskEligible, |
| 103 | base::Unretained(this), |
| 104 | task)); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | void |
| 108 | DomainReliabilityDispatcher::MakeTaskEligible(Task* task) { |
| 109 | DCHECK(task); |
| 110 | DCHECK(!task->eligible); |
| 111 | task->eligible = true; |
| 112 | eligible_tasks_.insert(task); |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 113 | task->timer->Start(FROM_HERE, |
| 114 | task->max_delay - task->min_delay, |
| 115 | base::Bind(&DomainReliabilityDispatcher::RunAndDeleteTask, |
| 116 | base::Unretained(this), |
| 117 | task)); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | void DomainReliabilityDispatcher::RunAndDeleteTask(Task* task) { |
| 121 | DCHECK(task); |
| 122 | DCHECK(!task->closure.is_null()); |
| 123 | task->closure.Run(); |
| 124 | if (task->eligible) |
| 125 | eligible_tasks_.erase(task); |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 126 | |
| 127 | auto it = std::find_if(tasks_.begin(), tasks_.end(), |
| 128 | [task](const std::unique_ptr<Task>& task_ptr) { |
| 129 | return task_ptr.get() == task; |
| 130 | }); |
| 131 | |
| 132 | DCHECK(it != tasks_.end()); |
| 133 | tasks_.erase(it); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | } // namespace domain_reliability |