1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/dns/serial_worker.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <memory>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/timer/timer.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/base/backoff_entry.h"
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker namespace net {
20*6777b538SAndroid Build Coastguard Worker
21*6777b538SAndroid Build Coastguard Worker namespace {
22*6777b538SAndroid Build Coastguard Worker // Default retry configuration. Only in effect if |max_number_of_retries| is
23*6777b538SAndroid Build Coastguard Worker // greater than 0.
24*6777b538SAndroid Build Coastguard Worker constexpr BackoffEntry::Policy kDefaultBackoffPolicy = {
25*6777b538SAndroid Build Coastguard Worker 0, // Number of initial errors to ignore without backoff.
26*6777b538SAndroid Build Coastguard Worker 5000, // Initial delay for backoff in ms: 5 seconds.
27*6777b538SAndroid Build Coastguard Worker 2, // Factor to multiply for exponential backoff.
28*6777b538SAndroid Build Coastguard Worker 0, // Fuzzing percentage.
29*6777b538SAndroid Build Coastguard Worker -1, // No maximum delay.
30*6777b538SAndroid Build Coastguard Worker -1, // Don't discard entry.
31*6777b538SAndroid Build Coastguard Worker false // Don't use initial delay unless the last was an error.
32*6777b538SAndroid Build Coastguard Worker };
33*6777b538SAndroid Build Coastguard Worker } // namespace
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Worker namespace {
DoWork(std::unique_ptr<SerialWorker::WorkItem> work_item)36*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SerialWorker::WorkItem> DoWork(
37*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SerialWorker::WorkItem> work_item) {
38*6777b538SAndroid Build Coastguard Worker DCHECK(work_item);
39*6777b538SAndroid Build Coastguard Worker work_item->DoWork();
40*6777b538SAndroid Build Coastguard Worker return work_item;
41*6777b538SAndroid Build Coastguard Worker }
42*6777b538SAndroid Build Coastguard Worker } // namespace
43*6777b538SAndroid Build Coastguard Worker
FollowupWork(base::OnceClosure closure)44*6777b538SAndroid Build Coastguard Worker void SerialWorker::WorkItem::FollowupWork(base::OnceClosure closure) {
45*6777b538SAndroid Build Coastguard Worker std::move(closure).Run();
46*6777b538SAndroid Build Coastguard Worker }
47*6777b538SAndroid Build Coastguard Worker
SerialWorker(int max_number_of_retries,const net::BackoffEntry::Policy * backoff_policy)48*6777b538SAndroid Build Coastguard Worker SerialWorker::SerialWorker(int max_number_of_retries,
49*6777b538SAndroid Build Coastguard Worker const net::BackoffEntry::Policy* backoff_policy)
50*6777b538SAndroid Build Coastguard Worker : max_number_of_retries_(max_number_of_retries),
51*6777b538SAndroid Build Coastguard Worker backoff_entry_(backoff_policy ? backoff_policy : &kDefaultBackoffPolicy) {
52*6777b538SAndroid Build Coastguard Worker }
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker SerialWorker::~SerialWorker() = default;
55*6777b538SAndroid Build Coastguard Worker
WorkNow()56*6777b538SAndroid Build Coastguard Worker void SerialWorker::WorkNow() {
57*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
58*6777b538SAndroid Build Coastguard Worker // Not a retry; reset failure count and cancel the pending retry (if any).
59*6777b538SAndroid Build Coastguard Worker backoff_entry_.Reset();
60*6777b538SAndroid Build Coastguard Worker retry_timer_.Stop();
61*6777b538SAndroid Build Coastguard Worker WorkNowInternal();
62*6777b538SAndroid Build Coastguard Worker }
63*6777b538SAndroid Build Coastguard Worker
WorkNowInternal()64*6777b538SAndroid Build Coastguard Worker void SerialWorker::WorkNowInternal() {
65*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
66*6777b538SAndroid Build Coastguard Worker switch (state_) {
67*6777b538SAndroid Build Coastguard Worker case State::kIdle:
68*6777b538SAndroid Build Coastguard Worker // We are posting weak pointer to OnWorkJobFinished to avoid a leak when
69*6777b538SAndroid Build Coastguard Worker // PostTaskAndReply fails to post task back to the original
70*6777b538SAndroid Build Coastguard Worker // task runner. In this case the callback is not destroyed, and the
71*6777b538SAndroid Build Coastguard Worker // weak reference allows SerialWorker instance to be deleted.
72*6777b538SAndroid Build Coastguard Worker base::ThreadPool::PostTaskAndReplyWithResult(
73*6777b538SAndroid Build Coastguard Worker FROM_HERE,
74*6777b538SAndroid Build Coastguard Worker {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
75*6777b538SAndroid Build Coastguard Worker base::BindOnce(&DoWork, CreateWorkItem()),
76*6777b538SAndroid Build Coastguard Worker base::BindOnce(&SerialWorker::OnDoWorkFinished, AsWeakPtr()));
77*6777b538SAndroid Build Coastguard Worker state_ = State::kWorking;
78*6777b538SAndroid Build Coastguard Worker return;
79*6777b538SAndroid Build Coastguard Worker case State::kWorking:
80*6777b538SAndroid Build Coastguard Worker // Remember to re-read after `DoWork()` finishes.
81*6777b538SAndroid Build Coastguard Worker state_ = State::kPending;
82*6777b538SAndroid Build Coastguard Worker return;
83*6777b538SAndroid Build Coastguard Worker case State::kCancelled:
84*6777b538SAndroid Build Coastguard Worker case State::kPending:
85*6777b538SAndroid Build Coastguard Worker return;
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker
Cancel()89*6777b538SAndroid Build Coastguard Worker void SerialWorker::Cancel() {
90*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
91*6777b538SAndroid Build Coastguard Worker state_ = State::kCancelled;
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker
OnDoWorkFinished(std::unique_ptr<WorkItem> work_item)94*6777b538SAndroid Build Coastguard Worker void SerialWorker::OnDoWorkFinished(std::unique_ptr<WorkItem> work_item) {
95*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
96*6777b538SAndroid Build Coastguard Worker
97*6777b538SAndroid Build Coastguard Worker switch (state_) {
98*6777b538SAndroid Build Coastguard Worker case State::kCancelled:
99*6777b538SAndroid Build Coastguard Worker return;
100*6777b538SAndroid Build Coastguard Worker case State::kWorking: {
101*6777b538SAndroid Build Coastguard Worker WorkItem* work_item_ptr = work_item.get();
102*6777b538SAndroid Build Coastguard Worker work_item_ptr->FollowupWork(
103*6777b538SAndroid Build Coastguard Worker base::BindOnce(&SerialWorker::OnFollowupWorkFinished,
104*6777b538SAndroid Build Coastguard Worker weak_factory_.GetWeakPtr(), std::move(work_item)));
105*6777b538SAndroid Build Coastguard Worker return;
106*6777b538SAndroid Build Coastguard Worker }
107*6777b538SAndroid Build Coastguard Worker case State::kPending: {
108*6777b538SAndroid Build Coastguard Worker RerunWork(std::move(work_item));
109*6777b538SAndroid Build Coastguard Worker return;
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker default:
112*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Unexpected state " << static_cast<int>(state_);
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker }
115*6777b538SAndroid Build Coastguard Worker
OnFollowupWorkFinished(std::unique_ptr<WorkItem> work_item)116*6777b538SAndroid Build Coastguard Worker void SerialWorker::OnFollowupWorkFinished(std::unique_ptr<WorkItem> work_item) {
117*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
118*6777b538SAndroid Build Coastguard Worker switch (state_) {
119*6777b538SAndroid Build Coastguard Worker case State::kCancelled:
120*6777b538SAndroid Build Coastguard Worker return;
121*6777b538SAndroid Build Coastguard Worker case State::kWorking:
122*6777b538SAndroid Build Coastguard Worker state_ = State::kIdle;
123*6777b538SAndroid Build Coastguard Worker if (OnWorkFinished(std::move(work_item)) ||
124*6777b538SAndroid Build Coastguard Worker backoff_entry_.failure_count() >= max_number_of_retries_) {
125*6777b538SAndroid Build Coastguard Worker backoff_entry_.Reset();
126*6777b538SAndroid Build Coastguard Worker } else {
127*6777b538SAndroid Build Coastguard Worker backoff_entry_.InformOfRequest(/*succeeded=*/false);
128*6777b538SAndroid Build Coastguard Worker
129*6777b538SAndroid Build Coastguard Worker // Try again after a delay.
130*6777b538SAndroid Build Coastguard Worker retry_timer_.Start(FROM_HERE, backoff_entry_.GetTimeUntilRelease(),
131*6777b538SAndroid Build Coastguard Worker this, &SerialWorker::WorkNowInternal);
132*6777b538SAndroid Build Coastguard Worker }
133*6777b538SAndroid Build Coastguard Worker return;
134*6777b538SAndroid Build Coastguard Worker case State::kPending:
135*6777b538SAndroid Build Coastguard Worker RerunWork(std::move(work_item));
136*6777b538SAndroid Build Coastguard Worker return;
137*6777b538SAndroid Build Coastguard Worker default:
138*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Unexpected state " << static_cast<int>(state_);
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker
RerunWork(std::unique_ptr<WorkItem> work_item)142*6777b538SAndroid Build Coastguard Worker void SerialWorker::RerunWork(std::unique_ptr<WorkItem> work_item) {
143*6777b538SAndroid Build Coastguard Worker // `WorkNow()` was retriggered while working, so need to redo work
144*6777b538SAndroid Build Coastguard Worker // immediately to ensure up-to-date results. Reuse `work_item` rather than
145*6777b538SAndroid Build Coastguard Worker // returning it to the derived class (and letting it potentially act on a
146*6777b538SAndroid Build Coastguard Worker // potential obsolete result).
147*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(state_, State::kPending);
148*6777b538SAndroid Build Coastguard Worker state_ = State::kWorking;
149*6777b538SAndroid Build Coastguard Worker base::ThreadPool::PostTaskAndReplyWithResult(
150*6777b538SAndroid Build Coastguard Worker FROM_HERE,
151*6777b538SAndroid Build Coastguard Worker {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
152*6777b538SAndroid Build Coastguard Worker base::BindOnce(&DoWork, std::move(work_item)),
153*6777b538SAndroid Build Coastguard Worker base::BindOnce(&SerialWorker::OnDoWorkFinished, AsWeakPtr()));
154*6777b538SAndroid Build Coastguard Worker }
155*6777b538SAndroid Build Coastguard Worker
GetBackoffEntryForTesting() const156*6777b538SAndroid Build Coastguard Worker const BackoffEntry& SerialWorker::GetBackoffEntryForTesting() const {
157*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
158*6777b538SAndroid Build Coastguard Worker return backoff_entry_;
159*6777b538SAndroid Build Coastguard Worker }
160*6777b538SAndroid Build Coastguard Worker
GetRetryTimerForTesting() const161*6777b538SAndroid Build Coastguard Worker const base::OneShotTimer& SerialWorker::GetRetryTimerForTesting() const {
162*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
163*6777b538SAndroid Build Coastguard Worker return retry_timer_;
164*6777b538SAndroid Build Coastguard Worker }
165*6777b538SAndroid Build Coastguard Worker
GetFailureCount() const166*6777b538SAndroid Build Coastguard Worker int SerialWorker::GetFailureCount() const {
167*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
168*6777b538SAndroid Build Coastguard Worker return backoff_entry_.failure_count();
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker
AsWeakPtr()171*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SerialWorker> SerialWorker::AsWeakPtr() {
172*6777b538SAndroid Build Coastguard Worker return weak_factory_.GetWeakPtr();
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker } // namespace net
176