Fix undefined variable when running bisect (path_to_file -> config_file_path).
[chromium-blink-merge.git] / components / domain_reliability / context.cc
blob994adcd6e268d3f5f596a2352549c1e0d581791e
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/context.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/metrics/sparse_histogram.h"
14 #include "base/values.h"
15 #include "components/domain_reliability/beacon.h"
16 #include "components/domain_reliability/dispatcher.h"
17 #include "components/domain_reliability/uploader.h"
18 #include "components/domain_reliability/util.h"
19 #include "net/base/net_errors.h"
20 #include "net/url_request/url_request_context_getter.h"
22 using base::DictionaryValue;
23 using base::ListValue;
24 using base::Value;
26 namespace domain_reliability {
28 namespace {
29 typedef std::deque<DomainReliabilityBeacon> BeaconDeque;
30 typedef BeaconDeque::iterator BeaconIterator;
31 typedef BeaconDeque::const_iterator BeaconConstIterator;
32 } // namespace
34 class DomainReliabilityContext::ResourceState {
35 public:
36 ResourceState(DomainReliabilityContext* context,
37 const DomainReliabilityConfig::Resource* config)
38 : context(context),
39 config(config),
40 successful_requests(0),
41 failed_requests(0),
42 uploading_beacons_size(0),
43 uploading_successful_requests(0),
44 uploading_failed_requests(0) {}
45 ~ResourceState() {}
47 // Serializes the resource state into a Value to be included in an upload.
48 // If there is nothing to report (no beacons and all request counters are 0),
49 // returns a scoped_ptr to NULL instead so the resource can be omitted.
50 scoped_ptr<base::Value> ToValue(base::TimeTicks upload_time) const {
51 if (beacons.empty() && successful_requests == 0 && failed_requests == 0)
52 return scoped_ptr<base::Value>();
54 ListValue* beacons_value = new ListValue();
55 for (BeaconConstIterator it = beacons.begin(); it != beacons.end(); ++it)
56 beacons_value->Append(it->ToValue(upload_time));
58 DictionaryValue* resource_value = new DictionaryValue();
59 resource_value->SetString("resource_name", config->name);
60 resource_value->SetInteger("successful_requests", successful_requests);
61 resource_value->SetInteger("failed_requests", failed_requests);
62 resource_value->Set("beacons", beacons_value);
64 return scoped_ptr<Value>(resource_value);
67 // Remembers the current state of the resource data when an upload starts.
68 void MarkUpload() {
69 uploading_beacons_size = beacons.size();
70 uploading_successful_requests = successful_requests;
71 uploading_failed_requests = failed_requests;
74 // Uses the state remembered by |MarkUpload| to remove successfully uploaded
75 // data but keep beacons and request counts added after the upload started.
76 void CommitUpload() {
77 BeaconIterator begin = beacons.begin();
78 BeaconIterator end = begin + uploading_beacons_size;
79 beacons.erase(begin, end);
80 successful_requests -= uploading_successful_requests;
81 failed_requests -= uploading_failed_requests;
84 // Gets the start time of the oldest beacon, if there are any. Returns true
85 // and sets |oldest_start_out| if so; otherwise, returns false.
86 bool GetOldestBeaconStart(base::TimeTicks* oldest_start_out) const {
87 if (beacons.empty())
88 return false;
89 *oldest_start_out = beacons[0].start_time;
90 return true;
93 // Removes the oldest beacon. DCHECKs if there isn't one.
94 void RemoveOldestBeacon() {
95 DCHECK(!beacons.empty());
96 beacons.erase(beacons.begin());
97 // If that just removed a beacon counted in uploading_beacons_size,
98 // decrement
99 // that.
100 if (uploading_beacons_size > 0)
101 --uploading_beacons_size;
104 DomainReliabilityContext* context;
105 const DomainReliabilityConfig::Resource* config;
107 std::deque<DomainReliabilityBeacon> beacons;
108 uint32 successful_requests;
109 uint32 failed_requests;
111 // State saved during uploads; if an upload succeeds, these are used to
112 // remove uploaded data from the beacon list and request counters.
113 size_t uploading_beacons_size;
114 uint32 uploading_successful_requests;
115 uint32 uploading_failed_requests;
117 private:
118 DISALLOW_COPY_AND_ASSIGN(ResourceState);
121 // static
122 const size_t DomainReliabilityContext::kMaxQueuedBeacons = 150;
124 DomainReliabilityContext::DomainReliabilityContext(
125 MockableTime* time,
126 const DomainReliabilityScheduler::Params& scheduler_params,
127 const std::string& upload_reporter_string,
128 DomainReliabilityDispatcher* dispatcher,
129 DomainReliabilityUploader* uploader,
130 scoped_ptr<const DomainReliabilityConfig> config)
131 : config_(config.Pass()),
132 time_(time),
133 upload_reporter_string_(upload_reporter_string),
134 scheduler_(time,
135 config_->collectors.size(),
136 scheduler_params,
137 base::Bind(&DomainReliabilityContext::ScheduleUpload,
138 base::Unretained(this))),
139 dispatcher_(dispatcher),
140 uploader_(uploader),
141 beacon_count_(0),
142 uploading_beacon_count_(0),
143 weak_factory_(this) {
144 InitializeResourceStates();
147 DomainReliabilityContext::~DomainReliabilityContext() {}
149 void DomainReliabilityContext::OnBeacon(const GURL& url,
150 const DomainReliabilityBeacon& beacon) {
151 size_t index = config_->GetResourceIndexForUrl(url);
152 if (index == DomainReliabilityConfig::kInvalidResourceIndex)
153 return;
154 DCHECK_GT(states_.size(), index);
156 bool success = (beacon.status == "ok");
158 ResourceState* state = states_[index];
159 if (success)
160 ++state->successful_requests;
161 else
162 ++state->failed_requests;
164 bool reported = false;
165 bool evicted = false;
166 if (state->config->DecideIfShouldReportRequest(success)) {
167 state->beacons.push_back(beacon);
168 ++beacon_count_;
169 if (beacon_count_ > kMaxQueuedBeacons) {
170 RemoveOldestBeacon();
171 evicted = true;
173 scheduler_.OnBeaconAdded();
174 reported = true;
175 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.ReportedBeaconError",
176 -beacon.chrome_error);
177 // TODO(ttuttle): Histogram HTTP response code?
180 UMA_HISTOGRAM_BOOLEAN("DomainReliability.BeaconReported", reported);
181 UMA_HISTOGRAM_BOOLEAN("DomainReliability.OnBeaconDidEvict", evicted);
184 void DomainReliabilityContext::ClearBeacons() {
185 ResourceStateVector::iterator it;
186 for (it = states_.begin(); it != states_.end(); ++it) {
187 ResourceState* state = *it;
188 state->beacons.clear();
189 state->successful_requests = 0;
190 state->failed_requests = 0;
191 state->uploading_beacons_size = 0;
192 state->uploading_successful_requests = 0;
193 state->uploading_failed_requests = 0;
195 beacon_count_ = 0;
196 uploading_beacon_count_ = 0;
199 scoped_ptr<base::Value> DomainReliabilityContext::GetWebUIData() const {
200 base::DictionaryValue* context_value = new base::DictionaryValue();
202 context_value->SetString("domain", config().domain);
203 context_value->SetInteger("beacon_count", static_cast<int>(beacon_count_));
204 context_value->SetInteger("uploading_beacon_count",
205 static_cast<int>(uploading_beacon_count_));
206 context_value->Set("scheduler", scheduler_.GetWebUIData());
208 return scoped_ptr<base::Value>(context_value);
211 void DomainReliabilityContext::GetQueuedDataForTesting(
212 size_t resource_index,
213 std::vector<DomainReliabilityBeacon>* beacons_out,
214 uint32* successful_requests_out,
215 uint32* failed_requests_out) const {
216 DCHECK_NE(DomainReliabilityConfig::kInvalidResourceIndex, resource_index);
217 DCHECK_GT(states_.size(), resource_index);
218 const ResourceState& state = *states_[resource_index];
219 if (beacons_out)
220 beacons_out->assign(state.beacons.begin(), state.beacons.end());
221 if (successful_requests_out)
222 *successful_requests_out = state.successful_requests;
223 if (failed_requests_out)
224 *failed_requests_out = state.failed_requests;
227 void DomainReliabilityContext::InitializeResourceStates() {
228 ScopedVector<DomainReliabilityConfig::Resource>::const_iterator it;
229 for (it = config_->resources.begin(); it != config_->resources.end(); ++it)
230 states_.push_back(new ResourceState(this, *it));
233 void DomainReliabilityContext::ScheduleUpload(
234 base::TimeDelta min_delay,
235 base::TimeDelta max_delay) {
236 dispatcher_->ScheduleTask(
237 base::Bind(
238 &DomainReliabilityContext::StartUpload,
239 weak_factory_.GetWeakPtr()),
240 min_delay,
241 max_delay);
244 void DomainReliabilityContext::StartUpload() {
245 MarkUpload();
247 DCHECK(upload_time_.is_null());
248 upload_time_ = time_->NowTicks();
249 std::string report_json;
250 scoped_ptr<const Value> report_value(CreateReport(upload_time_));
251 base::JSONWriter::Write(report_value.get(), &report_json);
252 report_value.reset();
254 size_t collector_index = scheduler_.OnUploadStart();
256 uploader_->UploadReport(
257 report_json,
258 config_->collectors[collector_index]->upload_url,
259 base::Bind(
260 &DomainReliabilityContext::OnUploadComplete,
261 weak_factory_.GetWeakPtr()));
263 UMA_HISTOGRAM_BOOLEAN("DomainReliability.UploadFailover",
264 collector_index > 0);
265 if (!last_upload_time_.is_null()) {
266 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadInterval",
267 upload_time_ - last_upload_time_);
271 void DomainReliabilityContext::OnUploadComplete(bool success) {
272 if (success)
273 CommitUpload();
274 scheduler_.OnUploadComplete(success);
275 UMA_HISTOGRAM_BOOLEAN("DomainReliability.UploadSuccess", success);
276 DCHECK(!upload_time_.is_null());
277 UMA_HISTOGRAM_MEDIUM_TIMES("DomainReliability.UploadDuration",
278 time_->NowTicks() - upload_time_);
279 last_upload_time_ = upload_time_;
280 upload_time_ = base::TimeTicks();
283 scoped_ptr<const Value> DomainReliabilityContext::CreateReport(
284 base::TimeTicks upload_time) const {
285 ListValue* resources_value = new ListValue();
286 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it) {
287 scoped_ptr<Value> resource_report = (*it)->ToValue(upload_time);
288 if (resource_report)
289 resources_value->Append(resource_report.release());
292 DictionaryValue* report_value = new DictionaryValue();
293 report_value->SetString("config_version", config().version);
294 report_value->SetString("reporter", upload_reporter_string_);
295 report_value->Set("resource_reports", resources_value);
297 return scoped_ptr<const Value>(report_value);
300 void DomainReliabilityContext::MarkUpload() {
301 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
302 (*it)->MarkUpload();
303 uploading_beacon_count_ = beacon_count_;
306 void DomainReliabilityContext::CommitUpload() {
307 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
308 (*it)->CommitUpload();
309 beacon_count_ -= uploading_beacon_count_;
312 void DomainReliabilityContext::RemoveOldestBeacon() {
313 DCHECK_LT(0u, beacon_count_);
315 base::TimeTicks min_time;
316 ResourceState* min_resource = NULL;
317 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it) {
318 base::TimeTicks oldest;
319 if ((*it)->GetOldestBeaconStart(&oldest)) {
320 if (!min_resource || oldest < min_time) {
321 min_time = oldest;
322 min_resource = *it;
326 DCHECK(min_resource);
328 VLOG(1) << "Beacon queue for " << config().domain << " full; "
329 << "removing oldest beacon from " << min_resource->config->name;
331 min_resource->RemoveOldestBeacon();
332 --beacon_count_;
333 // If that just removed a beacon counted in uploading_beacon_count_, decrement
334 // that.
335 if (uploading_beacon_count_ > 0)
336 --uploading_beacon_count_;
339 } // namespace domain_reliability