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"
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"
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
,
29 if (!base::FieldTrialList::TrialExists(field_trial_name
))
32 std::string group_name
= base::FieldTrialList::FindFullName(field_trial_name
);
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
<< "\".";
45 namespace domain_reliability
{
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
));
65 DomainReliabilityScheduler::DomainReliabilityScheduler(
67 size_t num_collectors
,
69 const ScheduleUploadCallback
& callback
)
71 collectors_(num_collectors
),
74 upload_pending_(false),
75 upload_scheduled_(false),
76 upload_running_(false),
77 collector_index_(kInvalidCollectorIndex
) {
80 DomainReliabilityScheduler::~DomainReliabilityScheduler() {}
82 void DomainReliabilityScheduler::OnBeaconAdded() {
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
;
119 collector
->failures
= 0;
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_
)
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
;
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(
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
) {
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
;
196 DCHECK_NE(kInvalidCollectorIndex
, min_index
);
197 *upload_time_out
= min_time
;
198 *collector_index_out
= min_index
;
201 base::TimeDelta
DomainReliabilityScheduler::GetUploadRetryInterval(
204 return base::TimeDelta::FromSeconds(0);
206 return params_
.upload_retry_interval
* (1 << std::min(failures
- 1, 5));
210 } // namespace domain_reliability