ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / components / domain_reliability / context.cc
blobe33d056ec9cdf25f783e10738f39e630a4121e20
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/dispatcher.h"
16 #include "components/domain_reliability/uploader.h"
17 #include "components/domain_reliability/util.h"
18 #include "net/base/net_errors.h"
19 #include "net/url_request/url_request_context_getter.h"
21 using base::DictionaryValue;
22 using base::ListValue;
23 using base::Value;
25 namespace domain_reliability {
27 namespace {
28 typedef std::deque<DomainReliabilityBeacon> BeaconDeque;
29 typedef BeaconDeque::iterator BeaconIterator;
30 typedef BeaconDeque::const_iterator BeaconConstIterator;
31 } // namespace
33 class DomainReliabilityContext::ResourceState {
34 public:
35 ResourceState(DomainReliabilityContext* context,
36 const DomainReliabilityConfig::Resource* config)
37 : context(context),
38 config(config),
39 successful_requests(0),
40 failed_requests(0),
41 uploading_successful_requests(0),
42 uploading_failed_requests(0) {}
43 ~ResourceState() {}
45 // Serializes the resource state into a Value to be included in an upload.
46 // If there is nothing to report (no beacons and all request counters are 0),
47 // returns a scoped_ptr to NULL instead so the resource can be omitted.
48 scoped_ptr<base::Value> ToValue(base::TimeTicks upload_time) const {
49 if (successful_requests == 0 && failed_requests == 0)
50 return scoped_ptr<base::Value>();
52 DictionaryValue* resource_value = new DictionaryValue();
53 resource_value->SetString("name", config->name);
54 resource_value->SetInteger("successful_requests", successful_requests);
55 resource_value->SetInteger("failed_requests", failed_requests);
57 return scoped_ptr<Value>(resource_value);
60 // Remembers the current state of the resource data when an upload starts.
61 void MarkUpload() {
62 DCHECK_EQ(0u, uploading_successful_requests);
63 DCHECK_EQ(0u, uploading_failed_requests);
64 uploading_successful_requests = successful_requests;
65 uploading_failed_requests = failed_requests;
68 // Uses the state remembered by |MarkUpload| to remove successfully uploaded
69 // data but keep beacons and request counts added after the upload started.
70 void CommitUpload() {
71 successful_requests -= uploading_successful_requests;
72 failed_requests -= uploading_failed_requests;
73 uploading_successful_requests = 0;
74 uploading_failed_requests = 0;
77 void RollbackUpload() {
78 uploading_successful_requests = 0;
79 uploading_failed_requests = 0;
82 DomainReliabilityContext* context;
83 const DomainReliabilityConfig::Resource* config;
85 uint32 successful_requests;
86 uint32 failed_requests;
88 // State saved during uploads; if an upload succeeds, these are used to
89 // remove uploaded data from the beacon list and request counters.
90 uint32 uploading_successful_requests;
91 uint32 uploading_failed_requests;
93 private:
94 DISALLOW_COPY_AND_ASSIGN(ResourceState);
97 // static
98 const size_t DomainReliabilityContext::kMaxQueuedBeacons = 150;
100 DomainReliabilityContext::DomainReliabilityContext(
101 MockableTime* time,
102 const DomainReliabilityScheduler::Params& scheduler_params,
103 const std::string& upload_reporter_string,
104 const base::TimeTicks* last_network_change_time,
105 DomainReliabilityDispatcher* dispatcher,
106 DomainReliabilityUploader* uploader,
107 scoped_ptr<const DomainReliabilityConfig> config)
108 : config_(config.Pass()),
109 time_(time),
110 upload_reporter_string_(upload_reporter_string),
111 scheduler_(time,
112 config_->collectors.size(),
113 scheduler_params,
114 base::Bind(&DomainReliabilityContext::ScheduleUpload,
115 base::Unretained(this))),
116 dispatcher_(dispatcher),
117 uploader_(uploader),
118 uploading_beacons_size_(0),
119 last_network_change_time_(last_network_change_time),
120 weak_factory_(this) {
121 InitializeResourceStates();
124 DomainReliabilityContext::~DomainReliabilityContext() {}
126 void DomainReliabilityContext::OnBeacon(const GURL& url,
127 const DomainReliabilityBeacon& beacon) {
128 size_t index = config_->GetResourceIndexForUrl(url);
129 if (index == DomainReliabilityConfig::kInvalidResourceIndex)
130 return;
131 DCHECK_GT(states_.size(), index);
133 bool success = (beacon.status == "ok");
135 ResourceState* state = states_[index];
136 if (success)
137 ++state->successful_requests;
138 else
139 ++state->failed_requests;
141 bool reported = false;
142 bool evicted = false;
143 if (state->config->DecideIfShouldReportRequest(success)) {
144 beacons_.push_back(beacon);
145 beacons_.back().resource = state->config->name;
146 if (beacons_.size() > kMaxQueuedBeacons) {
147 RemoveOldestBeacon();
148 evicted = true;
150 scheduler_.OnBeaconAdded();
151 reported = true;
152 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.ReportedBeaconError",
153 -beacon.chrome_error);
154 // TODO(ttuttle): Histogram HTTP response code?
157 UMA_HISTOGRAM_BOOLEAN("DomainReliability.BeaconReported", reported);
158 UMA_HISTOGRAM_BOOLEAN("DomainReliability.OnBeaconDidEvict", evicted);
161 void DomainReliabilityContext::ClearBeacons() {
162 ResourceStateVector::iterator it;
163 for (it = states_.begin(); it != states_.end(); ++it) {
164 ResourceState* state = *it;
165 state->successful_requests = 0;
166 state->failed_requests = 0;
167 state->uploading_successful_requests = 0;
168 state->uploading_failed_requests = 0;
170 beacons_.clear();
171 uploading_beacons_size_ = 0;
174 scoped_ptr<base::Value> DomainReliabilityContext::GetWebUIData() const {
175 base::DictionaryValue* context_value = new base::DictionaryValue();
177 context_value->SetString("domain", config().domain);
178 context_value->SetInteger("beacon_count", static_cast<int>(beacons_.size()));
179 context_value->SetInteger("uploading_beacon_count",
180 static_cast<int>(uploading_beacons_size_));
181 context_value->Set("scheduler", scheduler_.GetWebUIData());
183 return scoped_ptr<base::Value>(context_value);
186 void DomainReliabilityContext::GetQueuedBeaconsForTesting(
187 std::vector<DomainReliabilityBeacon>* beacons_out) const {
188 beacons_out->assign(beacons_.begin(), beacons_.end());
191 void DomainReliabilityContext::GetRequestCountsForTesting(
192 size_t resource_index,
193 uint32_t* successful_requests_out,
194 uint32_t* failed_requests_out) const {
195 DCHECK_NE(DomainReliabilityConfig::kInvalidResourceIndex, resource_index);
196 DCHECK_GT(states_.size(), resource_index);
198 const ResourceState& state = *states_[resource_index];
199 *successful_requests_out = state.successful_requests;
200 *failed_requests_out = state.failed_requests;
203 void DomainReliabilityContext::InitializeResourceStates() {
204 ScopedVector<DomainReliabilityConfig::Resource>::const_iterator it;
205 for (it = config_->resources.begin(); it != config_->resources.end(); ++it)
206 states_.push_back(new ResourceState(this, *it));
209 void DomainReliabilityContext::ScheduleUpload(
210 base::TimeDelta min_delay,
211 base::TimeDelta max_delay) {
212 dispatcher_->ScheduleTask(
213 base::Bind(
214 &DomainReliabilityContext::StartUpload,
215 weak_factory_.GetWeakPtr()),
216 min_delay,
217 max_delay);
220 void DomainReliabilityContext::StartUpload() {
221 MarkUpload();
223 DCHECK(upload_time_.is_null());
224 upload_time_ = time_->NowTicks();
225 std::string report_json;
226 scoped_ptr<const Value> report_value(CreateReport(upload_time_));
227 base::JSONWriter::Write(report_value.get(), &report_json);
228 report_value.reset();
230 size_t collector_index = scheduler_.OnUploadStart();
232 uploader_->UploadReport(
233 report_json,
234 config_->collectors[collector_index]->upload_url,
235 base::Bind(
236 &DomainReliabilityContext::OnUploadComplete,
237 weak_factory_.GetWeakPtr()));
239 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadCollectorIndex",
240 static_cast<int>(collector_index));
241 if (!last_upload_time_.is_null()) {
242 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadInterval",
243 upload_time_ - last_upload_time_);
247 void DomainReliabilityContext::OnUploadComplete(
248 const DomainReliabilityUploader::UploadResult& result) {
249 if (result.is_success())
250 CommitUpload();
251 else
252 RollbackUpload();
253 base::TimeTicks first_beacon_time = scheduler_.first_beacon_time();
254 scheduler_.OnUploadComplete(result);
255 UMA_HISTOGRAM_BOOLEAN("DomainReliability.UploadSuccess",
256 result.is_success());
257 base::TimeTicks now = time_->NowTicks();
258 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadLatency",
259 now - first_beacon_time);
260 DCHECK(!upload_time_.is_null());
261 UMA_HISTOGRAM_MEDIUM_TIMES("DomainReliability.UploadDuration",
262 now - upload_time_);
263 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadCollectorRetryDelay",
264 scheduler_.last_collector_retry_delay());
265 last_upload_time_ = upload_time_;
266 upload_time_ = base::TimeTicks();
269 scoped_ptr<const Value> DomainReliabilityContext::CreateReport(
270 base::TimeTicks upload_time) const {
271 scoped_ptr<ListValue> beacons_value(new ListValue());
272 for (BeaconConstIterator it = beacons_.begin(); it != beacons_.end(); ++it)
273 beacons_value->Append(it->ToValue(upload_time, *last_network_change_time_));
275 scoped_ptr<ListValue> resources_value(new ListValue());
276 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it) {
277 scoped_ptr<Value> resource_report = (*it)->ToValue(upload_time);
278 if (resource_report)
279 resources_value->Append(resource_report.release());
282 DictionaryValue* report_value = new DictionaryValue();
283 if (!config().version.empty())
284 report_value->SetString("config_version", config().version);
285 report_value->SetString("reporter", upload_reporter_string_);
286 report_value->Set("entries", beacons_value.release());
287 if (!resources_value->empty())
288 report_value->Set("resources", resources_value.release());
290 return scoped_ptr<const Value>(report_value);
293 void DomainReliabilityContext::MarkUpload() {
294 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
295 (*it)->MarkUpload();
296 DCHECK_EQ(0u, uploading_beacons_size_);
297 uploading_beacons_size_ = beacons_.size();
298 DCHECK_NE(0u, uploading_beacons_size_);
301 void DomainReliabilityContext::CommitUpload() {
302 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
303 (*it)->CommitUpload();
304 BeaconIterator begin = beacons_.begin();
305 BeaconIterator end = begin + uploading_beacons_size_;
306 beacons_.erase(begin, end);
307 DCHECK_NE(0u, uploading_beacons_size_);
308 uploading_beacons_size_ = 0;
311 void DomainReliabilityContext::RollbackUpload() {
312 for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
313 (*it)->RollbackUpload();
314 DCHECK_NE(0u, uploading_beacons_size_);
315 uploading_beacons_size_ = 0;
318 void DomainReliabilityContext::RemoveOldestBeacon() {
319 DCHECK(!beacons_.empty());
321 VLOG(1) << "Beacon queue for " << config().domain << " full; "
322 << "removing oldest beacon";
324 beacons_.pop_front();
326 // If that just removed a beacon counted in uploading_beacons_size_, decrement
327 // that.
328 if (uploading_beacons_size_ > 0)
329 --uploading_beacons_size_;
332 } // namespace domain_reliability