Change to let media_stream_devices_controller.cc decide if a gUM request fail if...
[chromium-blink-merge.git] / components / domain_reliability / scheduler.cc
blob20da4fc001626f495059336c732077237e83e0a1
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 "components/domain_reliability/config.h"
12 #include "components/domain_reliability/util.h"
14 namespace {
16 const int kInvalidCollectorIndex = -1;
18 const int kDefaultMinimumUploadDelaySec = 60;
19 const int kDefaultMaximumUploadDelaySec = 300;
20 const int kDefaultUploadRetryIntervalSec = 60;
22 const char* kMinimumUploadDelayFieldTrialName = "DomRel-MinimumUploadDelay";
23 const char* kMaximumUploadDelayFieldTrialName = "DomRel-MaximumUploadDelay";
24 const char* kUploadRetryIntervalFieldTrialName = "DomRel-UploadRetryInterval";
26 int GetIntegerFieldTrialValueOrDefault(
27 std::string field_trial_name,
28 int default_value) {
29 if (!base::FieldTrialList::TrialExists(field_trial_name))
30 return default_value;
32 std::string group_name = base::FieldTrialList::FindFullName(field_trial_name);
33 int value;
34 if (!base::StringToInt(group_name, &value)) {
35 LOG(ERROR) << "Expected integer for field trial " << field_trial_name
36 << " group name, but got \"" << group_name << "\".";
37 return default_value;
40 return value;
43 } // namespace
45 namespace domain_reliability {
47 // static
48 DomainReliabilityScheduler::Params
49 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults() {
50 DomainReliabilityScheduler::Params params;
52 params.minimum_upload_delay = base::TimeDelta::FromSeconds(
53 GetIntegerFieldTrialValueOrDefault(kMinimumUploadDelayFieldTrialName,
54 kDefaultMinimumUploadDelaySec));
55 params.maximum_upload_delay = base::TimeDelta::FromSeconds(
56 GetIntegerFieldTrialValueOrDefault(kMaximumUploadDelayFieldTrialName,
57 kDefaultMaximumUploadDelaySec));
58 params.upload_retry_interval = base::TimeDelta::FromSeconds(
59 GetIntegerFieldTrialValueOrDefault(kUploadRetryIntervalFieldTrialName,
60 kDefaultUploadRetryIntervalSec));
62 return params;
65 DomainReliabilityScheduler::DomainReliabilityScheduler(
66 MockableTime* time,
67 size_t num_collectors,
68 const Params& params,
69 const ScheduleUploadCallback& callback)
70 : time_(time),
71 collectors_(num_collectors),
72 params_(params),
73 callback_(callback),
74 upload_pending_(false),
75 upload_scheduled_(false),
76 upload_running_(false),
77 collector_index_(kInvalidCollectorIndex) {
80 DomainReliabilityScheduler::~DomainReliabilityScheduler() {}
82 void DomainReliabilityScheduler::OnBeaconAdded() {
83 if (!upload_pending_)
84 first_beacon_time_ = time_->Now();
85 upload_pending_ = true;
86 VLOG(2) << "OnBeaconAdded";
87 MaybeScheduleUpload();
90 void DomainReliabilityScheduler::OnUploadStart(int* collector_index_out) {
91 DCHECK(collector_index_out);
92 DCHECK(upload_scheduled_);
93 DCHECK_EQ(kInvalidCollectorIndex, collector_index_);
94 upload_scheduled_ = false;
95 upload_running_ = true;
97 base::TimeTicks now = time_->Now();
98 base::TimeTicks min_upload_time;
99 GetNextUploadTimeAndCollector(now, &min_upload_time, &collector_index_);
100 DCHECK(min_upload_time <= now);
102 *collector_index_out = collector_index_;
104 VLOG(1) << "Starting upload to collector " << collector_index_ << ".";
107 void DomainReliabilityScheduler::OnUploadComplete(bool success) {
108 DCHECK(upload_running_);
109 DCHECK_NE(kInvalidCollectorIndex, collector_index_);
110 upload_running_ = false;
112 VLOG(1) << "Upload to collector " << collector_index_
113 << (success ? " succeeded." : " failed.");
115 CollectorState* collector = &collectors_[collector_index_];
116 collector_index_ = kInvalidCollectorIndex;
118 if (success) {
119 collector->failures = 0;
120 } else {
121 // Restore upload_pending_ and first_beacon_time_ to pre-upload state,
122 // since upload failed.
123 upload_pending_ = true;
124 first_beacon_time_ = old_first_beacon_time_;
126 ++collector->failures;
129 base::TimeDelta retry_interval = GetUploadRetryInterval(collector->failures);
130 collector->next_upload = time_->Now() + retry_interval;
132 VLOG(1) << "Next upload to collector at least "
133 << retry_interval.InSeconds() << " seconds from now.";
135 MaybeScheduleUpload();
138 DomainReliabilityScheduler::CollectorState::CollectorState() : failures(0) {}
140 void DomainReliabilityScheduler::MaybeScheduleUpload() {
141 if (!upload_pending_ || upload_scheduled_ || upload_running_)
142 return;
144 upload_pending_ = false;
145 upload_scheduled_ = true;
146 old_first_beacon_time_ = first_beacon_time_;
148 base::TimeTicks now = time_->Now();
150 base::TimeTicks min_by_deadline, max_by_deadline;
151 min_by_deadline = first_beacon_time_ + params_.minimum_upload_delay;
152 max_by_deadline = first_beacon_time_ + params_.maximum_upload_delay;
153 DCHECK(min_by_deadline <= max_by_deadline);
155 base::TimeTicks min_by_backoff;
156 int collector_index;
157 GetNextUploadTimeAndCollector(now, &min_by_backoff, &collector_index);
159 base::TimeDelta min_delay = std::max(min_by_deadline, min_by_backoff) - now;
160 base::TimeDelta max_delay = std::max(max_by_deadline, min_by_backoff) - now;
162 VLOG(1) << "Scheduling upload for between " << min_delay.InSeconds()
163 << " and " << max_delay.InSeconds() << " seconds from now.";
165 callback_.Run(min_delay, max_delay);
168 // TODO(ttuttle): Add min and max interval to config, use that instead.
169 // TODO(ttuttle): Cap min and max intervals received from config.
171 void DomainReliabilityScheduler::GetNextUploadTimeAndCollector(
172 base::TimeTicks now,
173 base::TimeTicks* upload_time_out,
174 int* collector_index_out) {
175 DCHECK(upload_time_out);
176 DCHECK(collector_index_out);
178 base::TimeTicks min_time;
179 int min_index = kInvalidCollectorIndex;
181 for (unsigned i = 0; i < collectors_.size(); ++i) {
182 CollectorState* collector = &collectors_[i];
183 // If a collector is usable, use the first one in the list.
184 if (collector->failures == 0 || collector->next_upload <= now) {
185 min_time = now;
186 min_index = i;
187 break;
188 // If not, keep track of which will be usable soonest:
189 } else if (min_index == kInvalidCollectorIndex ||
190 collector->next_upload < min_time) {
191 min_time = collector->next_upload;
192 min_index = i;
196 DCHECK_NE(kInvalidCollectorIndex, min_index);
197 *upload_time_out = min_time;
198 *collector_index_out = min_index;
201 base::TimeDelta DomainReliabilityScheduler::GetUploadRetryInterval(
202 int failures) {
203 if (failures == 0)
204 return base::TimeDelta::FromSeconds(0);
205 else {
206 return params_.upload_retry_interval * (1 << std::min(failures - 1, 5));
210 } // namespace domain_reliability