serial_worker.cc 5.5 KB

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