scheduler.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. #include "components/domain_reliability/scheduler.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/metrics/field_trial.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/values.h"
  12. #include "components/domain_reliability/config.h"
  13. #include "components/domain_reliability/util.h"
  14. #include "net/base/backoff_entry.h"
  15. namespace {
  16. const unsigned kInvalidCollectorIndex = static_cast<unsigned>(-1);
  17. const unsigned kDefaultMinimumUploadDelaySec = 60;
  18. const unsigned kDefaultMaximumUploadDelaySec = 300;
  19. const unsigned kDefaultUploadRetryIntervalSec = 60;
  20. const char* kMinimumUploadDelayFieldTrialName = "DomRel-MinimumUploadDelay";
  21. const char* kMaximumUploadDelayFieldTrialName = "DomRel-MaximumUploadDelay";
  22. const char* kUploadRetryIntervalFieldTrialName = "DomRel-UploadRetryInterval";
  23. // Fixed elements of backoff policy
  24. const double kMultiplyFactor = 2.0;
  25. const double kJitterFactor = 0.1;
  26. const int64_t kMaximumBackoffMs = 60 * 1000 * 1000;
  27. unsigned GetUnsignedFieldTrialValueOrDefault(std::string field_trial_name,
  28. unsigned default_value) {
  29. if (!base::FieldTrialList::TrialExists(field_trial_name))
  30. return default_value;
  31. std::string group_name = base::FieldTrialList::FindFullName(field_trial_name);
  32. unsigned value;
  33. if (!base::StringToUint(group_name, &value)) {
  34. LOG(ERROR) << "Expected unsigned integer for field trial "
  35. << field_trial_name << " group name, but got \"" << group_name
  36. << "\".";
  37. return default_value;
  38. }
  39. return value;
  40. }
  41. } // namespace
  42. namespace domain_reliability {
  43. // static
  44. DomainReliabilityScheduler::Params
  45. DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults() {
  46. DomainReliabilityScheduler::Params params;
  47. params.minimum_upload_delay =
  48. base::Seconds(GetUnsignedFieldTrialValueOrDefault(
  49. kMinimumUploadDelayFieldTrialName, kDefaultMinimumUploadDelaySec));
  50. params.maximum_upload_delay =
  51. base::Seconds(GetUnsignedFieldTrialValueOrDefault(
  52. kMaximumUploadDelayFieldTrialName, kDefaultMaximumUploadDelaySec));
  53. params.upload_retry_interval =
  54. base::Seconds(GetUnsignedFieldTrialValueOrDefault(
  55. kUploadRetryIntervalFieldTrialName, kDefaultUploadRetryIntervalSec));
  56. return params;
  57. }
  58. DomainReliabilityScheduler::DomainReliabilityScheduler(
  59. const MockableTime* time,
  60. size_t num_collectors,
  61. const Params& params,
  62. const ScheduleUploadCallback& callback)
  63. : time_(time),
  64. params_(params),
  65. callback_(callback),
  66. upload_pending_(false),
  67. upload_scheduled_(false),
  68. upload_running_(false),
  69. collector_index_(kInvalidCollectorIndex) {
  70. backoff_policy_.num_errors_to_ignore = 0;
  71. backoff_policy_.initial_delay_ms =
  72. params.upload_retry_interval.InMilliseconds();
  73. backoff_policy_.multiply_factor = kMultiplyFactor;
  74. backoff_policy_.jitter_factor = kJitterFactor;
  75. backoff_policy_.maximum_backoff_ms = kMaximumBackoffMs;
  76. backoff_policy_.entry_lifetime_ms = 0;
  77. backoff_policy_.always_use_initial_delay = false;
  78. for (size_t i = 0; i < num_collectors; ++i) {
  79. collectors_.push_back(std::make_unique<net::BackoffEntry>(
  80. &backoff_policy_, time->AsTickClock()));
  81. }
  82. }
  83. DomainReliabilityScheduler::~DomainReliabilityScheduler() {}
  84. void DomainReliabilityScheduler::OnBeaconAdded() {
  85. if (!upload_pending_)
  86. first_beacon_time_ = time_->NowTicks();
  87. upload_pending_ = true;
  88. MaybeScheduleUpload();
  89. }
  90. size_t DomainReliabilityScheduler::OnUploadStart() {
  91. DCHECK(upload_scheduled_);
  92. DCHECK_EQ(kInvalidCollectorIndex, collector_index_);
  93. upload_pending_ = false;
  94. upload_scheduled_ = false;
  95. upload_running_ = true;
  96. base::TimeTicks now = time_->NowTicks();
  97. base::TimeTicks min_upload_time;
  98. GetNextUploadTimeAndCollector(now, &min_upload_time, &collector_index_);
  99. DCHECK(min_upload_time <= now);
  100. VLOG(1) << "Starting upload to collector " << collector_index_ << ".";
  101. return collector_index_;
  102. }
  103. void DomainReliabilityScheduler::OnUploadComplete(
  104. const DomainReliabilityUploader::UploadResult& result) {
  105. DCHECK(upload_running_);
  106. DCHECK_NE(kInvalidCollectorIndex, collector_index_);
  107. upload_running_ = false;
  108. VLOG(1) << "Upload to collector " << collector_index_
  109. << (result.is_success() ? " succeeded." : " failed.");
  110. net::BackoffEntry* backoff = collectors_[collector_index_].get();
  111. collector_index_ = kInvalidCollectorIndex;
  112. backoff->InformOfRequest(result.is_success());
  113. if (result.is_retry_after())
  114. backoff->SetCustomReleaseTime(time_->NowTicks() + result.retry_after);
  115. if (!result.is_success()) {
  116. // Restore upload_pending_ and first_beacon_time_ to pre-upload state,
  117. // since upload failed.
  118. upload_pending_ = true;
  119. first_beacon_time_ = old_first_beacon_time_;
  120. }
  121. MaybeScheduleUpload();
  122. }
  123. void DomainReliabilityScheduler::MakeDeterministicForTesting() {
  124. backoff_policy_.jitter_factor = 0.0;
  125. }
  126. void DomainReliabilityScheduler::MaybeScheduleUpload() {
  127. if (!upload_pending_ || upload_scheduled_ || upload_running_)
  128. return;
  129. upload_scheduled_ = true;
  130. old_first_beacon_time_ = first_beacon_time_;
  131. base::TimeTicks now = time_->NowTicks();
  132. base::TimeTicks min_by_deadline, max_by_deadline;
  133. min_by_deadline = first_beacon_time_ + params_.minimum_upload_delay;
  134. max_by_deadline = first_beacon_time_ + params_.maximum_upload_delay;
  135. DCHECK(min_by_deadline <= max_by_deadline);
  136. base::TimeTicks min_by_backoff;
  137. size_t collector_index;
  138. GetNextUploadTimeAndCollector(now, &min_by_backoff, &collector_index);
  139. base::TimeTicks scheduled_min_time =
  140. std::max(min_by_deadline, min_by_backoff);
  141. base::TimeTicks scheduled_max_time =
  142. std::max(max_by_deadline, min_by_backoff);
  143. base::TimeDelta min_delay = scheduled_min_time - now;
  144. base::TimeDelta max_delay = scheduled_max_time - now;
  145. VLOG(1) << "Scheduling upload for between " << min_delay.InSeconds()
  146. << " and " << max_delay.InSeconds() << " seconds from now.";
  147. callback_.Run(min_delay, max_delay);
  148. }
  149. // TODO(juliatuttle): Add min and max interval to config, use that instead.
  150. // TODO(juliatuttle): Cap min and max intervals received from config.
  151. void DomainReliabilityScheduler::GetNextUploadTimeAndCollector(
  152. base::TimeTicks now,
  153. base::TimeTicks* upload_time_out,
  154. size_t* collector_index_out) {
  155. DCHECK(upload_time_out);
  156. DCHECK(collector_index_out);
  157. base::TimeTicks min_time;
  158. size_t min_index = kInvalidCollectorIndex;
  159. for (size_t i = 0; i < collectors_.size(); ++i) {
  160. net::BackoffEntry* backoff = collectors_[i].get();
  161. // If a collector is usable, use the first one in the list.
  162. if (!backoff->ShouldRejectRequest()) {
  163. min_time = now;
  164. min_index = i;
  165. break;
  166. }
  167. // If not, keep track of which will be usable soonest:
  168. base::TimeTicks time = backoff->GetReleaseTime();
  169. if (min_index == kInvalidCollectorIndex || time < min_time) {
  170. min_time = time;
  171. min_index = i;
  172. }
  173. }
  174. DCHECK_NE(kInvalidCollectorIndex, min_index);
  175. *upload_time_out = min_time;
  176. *collector_index_out = min_index;
  177. }
  178. } // namespace domain_reliability