Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / components / domain_reliability / scheduler.cc
blob5bcff24486419a81dda989a673288a15ea6a98a5
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.
5 #include "components/domain_reliability/scheduler.h"
7 #include <algorithm>
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"
15 namespace {
17 const unsigned kInvalidCollectorIndex = static_cast<unsigned>(-1);
19 const unsigned kDefaultMinimumUploadDelaySec = 60;
20 const unsigned kDefaultMaximumUploadDelaySec = 300;
21 const unsigned kDefaultUploadRetryIntervalSec = 60;
23 const char* kMinimumUploadDelayFieldTrialName = "DomRel-MinimumUploadDelay";
24 const char* kMaximumUploadDelayFieldTrialName = "DomRel-MaximumUploadDelay";
25 const char* kUploadRetryIntervalFieldTrialName = "DomRel-UploadRetryInterval";
27 // Fixed elements of backoff policy
28 const double kMultiplyFactor = 2.0;
29 const double kJitterFactor = 0.1;
30 const int64 kMaximumBackoffMs = 60 * 1000 * 1000;
32 unsigned GetUnsignedFieldTrialValueOrDefault(std::string field_trial_name,
33 unsigned default_value) {
34 if (!base::FieldTrialList::TrialExists(field_trial_name))
35 return default_value;
37 std::string group_name = base::FieldTrialList::FindFullName(field_trial_name);
38 unsigned value;
39 if (!base::StringToUint(group_name, &value)) {
40 LOG(ERROR) << "Expected unsigned integer for field trial "
41 << field_trial_name << " group name, but got \"" << group_name
42 << "\".";
43 return default_value;
46 return value;
49 } // namespace
51 namespace domain_reliability {
53 // static
54 DomainReliabilityScheduler::Params
55 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults() {
56 DomainReliabilityScheduler::Params params;
58 params.minimum_upload_delay =
59 base::TimeDelta::FromSeconds(GetUnsignedFieldTrialValueOrDefault(
60 kMinimumUploadDelayFieldTrialName, kDefaultMinimumUploadDelaySec));
61 params.maximum_upload_delay =
62 base::TimeDelta::FromSeconds(GetUnsignedFieldTrialValueOrDefault(
63 kMaximumUploadDelayFieldTrialName, kDefaultMaximumUploadDelaySec));
64 params.upload_retry_interval =
65 base::TimeDelta::FromSeconds(GetUnsignedFieldTrialValueOrDefault(
66 kUploadRetryIntervalFieldTrialName, kDefaultUploadRetryIntervalSec));
68 return params;
71 DomainReliabilityScheduler::DomainReliabilityScheduler(
72 MockableTime* time,
73 size_t num_collectors,
74 const Params& params,
75 const ScheduleUploadCallback& callback)
76 : time_(time),
77 params_(params),
78 callback_(callback),
79 upload_pending_(false),
80 upload_scheduled_(false),
81 upload_running_(false),
82 collector_index_(kInvalidCollectorIndex),
83 last_upload_finished_(false) {
84 backoff_policy_.num_errors_to_ignore = 0;
85 backoff_policy_.initial_delay_ms =
86 params.upload_retry_interval.InMilliseconds();
87 backoff_policy_.multiply_factor = kMultiplyFactor;
88 backoff_policy_.jitter_factor = kJitterFactor;
89 backoff_policy_.maximum_backoff_ms = kMaximumBackoffMs;
90 backoff_policy_.entry_lifetime_ms = 0;
91 backoff_policy_.always_use_initial_delay = false;
93 for (size_t i = 0; i < num_collectors; ++i) {
94 collectors_.push_back(
95 new MockableTimeBackoffEntry(&backoff_policy_, time_));
99 DomainReliabilityScheduler::~DomainReliabilityScheduler() {}
101 void DomainReliabilityScheduler::OnBeaconAdded() {
102 if (!upload_pending_)
103 first_beacon_time_ = time_->NowTicks();
104 upload_pending_ = true;
105 MaybeScheduleUpload();
108 size_t DomainReliabilityScheduler::OnUploadStart() {
109 DCHECK(upload_scheduled_);
110 DCHECK_EQ(kInvalidCollectorIndex, collector_index_);
111 upload_pending_ = false;
112 upload_scheduled_ = false;
113 upload_running_ = true;
115 base::TimeTicks now = time_->NowTicks();
116 base::TimeTicks min_upload_time;
117 GetNextUploadTimeAndCollector(now, &min_upload_time, &collector_index_);
118 DCHECK(min_upload_time <= now);
120 VLOG(1) << "Starting upload to collector " << collector_index_ << ".";
122 last_upload_start_time_ = now;
123 last_upload_collector_index_ = collector_index_;
125 return collector_index_;
128 void DomainReliabilityScheduler::OnUploadComplete(
129 const DomainReliabilityUploader::UploadResult& result) {
130 DCHECK(upload_running_);
131 DCHECK_NE(kInvalidCollectorIndex, collector_index_);
132 upload_running_ = false;
134 VLOG(1) << "Upload to collector " << collector_index_
135 << (result.is_success() ? " succeeded." : " failed.");
137 net::BackoffEntry* backoff = collectors_[collector_index_];
138 collector_index_ = kInvalidCollectorIndex;
140 backoff->InformOfRequest(result.is_success());
141 if (result.is_retry_after())
142 backoff->SetCustomReleaseTime(time_->NowTicks() + result.retry_after);
144 if (!result.is_success()) {
145 // Restore upload_pending_ and first_beacon_time_ to pre-upload state,
146 // since upload failed.
147 upload_pending_ = true;
148 first_beacon_time_ = old_first_beacon_time_;
151 last_upload_end_time_ = time_->NowTicks();
152 last_upload_success_ = result.is_success();
153 last_upload_finished_ = true;
155 MaybeScheduleUpload();
158 base::Value* DomainReliabilityScheduler::GetWebUIData() const {
159 base::TimeTicks now = time_->NowTicks();
161 base::DictionaryValue* data = new base::DictionaryValue();
163 data->SetBoolean("upload_pending", upload_pending_);
164 data->SetBoolean("upload_scheduled", upload_scheduled_);
165 data->SetBoolean("upload_running", upload_running_);
167 data->SetInteger("scheduled_min", (scheduled_min_time_ - now).InSeconds());
168 data->SetInteger("scheduled_max", (scheduled_max_time_ - now).InSeconds());
170 data->SetInteger("collector_index", static_cast<int>(collector_index_));
172 if (last_upload_finished_) {
173 base::DictionaryValue* last = new base::DictionaryValue();
174 last->SetInteger("start_time", (now - last_upload_start_time_).InSeconds());
175 last->SetInteger("end_time", (now - last_upload_end_time_).InSeconds());
176 last->SetInteger("collector_index",
177 static_cast<int>(last_upload_collector_index_));
178 last->SetBoolean("success", last_upload_success_);
179 data->Set("last_upload", last);
182 base::ListValue* collectors = new base::ListValue();
183 for (size_t i = 0; i < collectors_.size(); ++i) {
184 const net::BackoffEntry* backoff = collectors_[i];
185 base::DictionaryValue* value = new base::DictionaryValue();
186 value->SetInteger("failures", backoff->failure_count());
187 value->SetInteger("next_upload",
188 (backoff->GetReleaseTime() - now).InSeconds());
189 collectors->Append(value);
191 data->Set("collectors", collectors);
193 return data;
196 void DomainReliabilityScheduler::MakeDeterministicForTesting() {
197 backoff_policy_.jitter_factor = 0.0;
200 void DomainReliabilityScheduler::MaybeScheduleUpload() {
201 if (!upload_pending_ || upload_scheduled_ || upload_running_)
202 return;
204 upload_scheduled_ = true;
205 old_first_beacon_time_ = first_beacon_time_;
207 base::TimeTicks now = time_->NowTicks();
209 base::TimeTicks min_by_deadline, max_by_deadline;
210 min_by_deadline = first_beacon_time_ + params_.minimum_upload_delay;
211 max_by_deadline = first_beacon_time_ + params_.maximum_upload_delay;
212 DCHECK(min_by_deadline <= max_by_deadline);
214 base::TimeTicks min_by_backoff;
215 size_t collector_index;
216 GetNextUploadTimeAndCollector(now, &min_by_backoff, &collector_index);
218 scheduled_min_time_ = std::max(min_by_deadline, min_by_backoff);
219 scheduled_max_time_ = std::max(max_by_deadline, min_by_backoff);
221 base::TimeDelta min_delay = scheduled_min_time_ - now;
222 base::TimeDelta max_delay = scheduled_max_time_ - now;
224 VLOG(1) << "Scheduling upload for between " << min_delay.InSeconds()
225 << " and " << max_delay.InSeconds() << " seconds from now.";
227 callback_.Run(min_delay, max_delay);
230 // TODO(ttuttle): Add min and max interval to config, use that instead.
232 // TODO(ttuttle): Cap min and max intervals received from config.
234 void DomainReliabilityScheduler::GetNextUploadTimeAndCollector(
235 base::TimeTicks now,
236 base::TimeTicks* upload_time_out,
237 size_t* collector_index_out) {
238 DCHECK(upload_time_out);
239 DCHECK(collector_index_out);
241 base::TimeTicks min_time;
242 size_t min_index = kInvalidCollectorIndex;
244 for (size_t i = 0; i < collectors_.size(); ++i) {
245 net::BackoffEntry* backoff = collectors_[i];
246 // If a collector is usable, use the first one in the list.
247 if (!backoff->ShouldRejectRequest()) {
248 min_time = now;
249 min_index = i;
250 break;
253 // If not, keep track of which will be usable soonest:
254 base::TimeTicks time = backoff->GetReleaseTime();
255 if (min_index == kInvalidCollectorIndex || time < min_time) {
256 min_time = time;
257 min_index = i;
261 DCHECK_NE(kInvalidCollectorIndex, min_index);
262 *upload_time_out = min_time;
263 *collector_index_out = min_index;
266 } // namespace domain_reliability