OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/domain_reliability/context.h" | 5 #include "components/domain_reliability/context.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
13 #include "base/metrics/sparse_histogram.h" | 13 #include "base/metrics/sparse_histogram.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "components/domain_reliability/dispatcher.h" | 15 #include "components/domain_reliability/dispatcher.h" |
16 #include "components/domain_reliability/uploader.h" | 16 #include "components/domain_reliability/uploader.h" |
17 #include "components/domain_reliability/util.h" | 17 #include "components/domain_reliability/util.h" |
18 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
19 #include "net/url_request/url_request_context_getter.h" | 19 #include "net/url_request/url_request_context_getter.h" |
20 | 20 |
21 using base::DictionaryValue; | 21 using base::DictionaryValue; |
22 using base::ListValue; | 22 using base::ListValue; |
23 using base::Value; | 23 using base::Value; |
24 | 24 |
25 namespace domain_reliability { | 25 namespace domain_reliability { |
26 | 26 |
27 namespace { | |
28 typedef std::deque<DomainReliabilityBeacon> BeaconDeque; | |
29 typedef BeaconDeque::iterator BeaconIterator; | |
30 typedef BeaconDeque::const_iterator BeaconConstIterator; | |
31 } // namespace | |
32 | |
33 DomainReliabilityContext::Factory::~Factory() { | 27 DomainReliabilityContext::Factory::~Factory() { |
34 } | 28 } |
35 | 29 |
36 class DomainReliabilityContext::ResourceState { | |
37 public: | |
38 ResourceState(DomainReliabilityContext* context, | |
39 const DomainReliabilityConfig::Resource* config) | |
40 : context(context), | |
41 config(config), | |
42 successful_requests(0), | |
43 failed_requests(0), | |
44 uploading_successful_requests(0), | |
45 uploading_failed_requests(0) {} | |
46 ~ResourceState() {} | |
47 | |
48 // Serializes the resource state into a Value to be included in an upload. | |
49 // If there is nothing to report (no beacons and all request counters are 0), | |
50 // returns a scoped_ptr to NULL instead so the resource can be omitted. | |
51 scoped_ptr<base::Value> ToValue(base::TimeTicks upload_time) const { | |
52 if (successful_requests == 0 && failed_requests == 0) | |
53 return scoped_ptr<base::Value>(); | |
54 | |
55 DictionaryValue* resource_value = new DictionaryValue(); | |
56 resource_value->SetString("name", config->name); | |
57 resource_value->SetInteger("successful_requests", successful_requests); | |
58 resource_value->SetInteger("failed_requests", failed_requests); | |
59 | |
60 return scoped_ptr<Value>(resource_value); | |
61 } | |
62 | |
63 // Remembers the current state of the resource data when an upload starts. | |
64 void MarkUpload() { | |
65 DCHECK_EQ(0u, uploading_successful_requests); | |
66 DCHECK_EQ(0u, uploading_failed_requests); | |
67 uploading_successful_requests = successful_requests; | |
68 uploading_failed_requests = failed_requests; | |
69 } | |
70 | |
71 // Uses the state remembered by |MarkUpload| to remove successfully uploaded | |
72 // data but keep beacons and request counts added after the upload started. | |
73 void CommitUpload() { | |
74 successful_requests -= uploading_successful_requests; | |
75 failed_requests -= uploading_failed_requests; | |
76 uploading_successful_requests = 0; | |
77 uploading_failed_requests = 0; | |
78 } | |
79 | |
80 void RollbackUpload() { | |
81 uploading_successful_requests = 0; | |
82 uploading_failed_requests = 0; | |
83 } | |
84 | |
85 DomainReliabilityContext* context; | |
86 const DomainReliabilityConfig::Resource* config; | |
87 | |
88 uint32 successful_requests; | |
89 uint32 failed_requests; | |
90 | |
91 // State saved during uploads; if an upload succeeds, these are used to | |
92 // remove uploaded data from the beacon list and request counters. | |
93 uint32 uploading_successful_requests; | |
94 uint32 uploading_failed_requests; | |
95 | |
96 private: | |
97 DISALLOW_COPY_AND_ASSIGN(ResourceState); | |
98 }; | |
99 | |
100 // static | 30 // static |
101 const size_t DomainReliabilityContext::kMaxQueuedBeacons = 150; | 31 const size_t DomainReliabilityContext::kMaxQueuedBeacons = 150; |
102 | 32 |
103 DomainReliabilityContext::DomainReliabilityContext( | 33 DomainReliabilityContext::DomainReliabilityContext( |
104 MockableTime* time, | 34 MockableTime* time, |
105 const DomainReliabilityScheduler::Params& scheduler_params, | 35 const DomainReliabilityScheduler::Params& scheduler_params, |
106 const std::string& upload_reporter_string, | 36 const std::string& upload_reporter_string, |
107 const base::TimeTicks* last_network_change_time, | 37 const base::TimeTicks* last_network_change_time, |
108 DomainReliabilityDispatcher* dispatcher, | 38 DomainReliabilityDispatcher* dispatcher, |
109 DomainReliabilityUploader* uploader, | 39 DomainReliabilityUploader* uploader, |
110 scoped_ptr<const DomainReliabilityConfig> config) | 40 scoped_ptr<const DomainReliabilityConfig> config) |
111 : config_(config.Pass()), | 41 : config_(config.Pass()), |
112 time_(time), | 42 time_(time), |
113 upload_reporter_string_(upload_reporter_string), | 43 upload_reporter_string_(upload_reporter_string), |
114 scheduler_(time, | 44 scheduler_(time, |
115 config_->collectors.size(), | 45 config_->collectors.size(), |
116 scheduler_params, | 46 scheduler_params, |
117 base::Bind(&DomainReliabilityContext::ScheduleUpload, | 47 base::Bind(&DomainReliabilityContext::ScheduleUpload, |
118 base::Unretained(this))), | 48 base::Unretained(this))), |
119 dispatcher_(dispatcher), | 49 dispatcher_(dispatcher), |
120 uploader_(uploader), | 50 uploader_(uploader), |
121 uploading_beacons_size_(0), | 51 uploading_beacons_size_(0), |
122 last_network_change_time_(last_network_change_time), | 52 last_network_change_time_(last_network_change_time), |
123 weak_factory_(this) { | 53 weak_factory_(this) { |
124 InitializeResourceStates(); | |
125 } | 54 } |
126 | 55 |
127 DomainReliabilityContext::~DomainReliabilityContext() {} | 56 DomainReliabilityContext::~DomainReliabilityContext() { |
57 ClearBeacons(); | |
58 } | |
128 | 59 |
129 void DomainReliabilityContext::OnBeacon(const GURL& url, | 60 void DomainReliabilityContext::OnBeacon( |
130 const DomainReliabilityBeacon& beacon) { | 61 scoped_ptr<DomainReliabilityBeacon> beacon) { |
131 size_t index = config_->GetResourceIndexForUrl(url); | 62 bool success = (beacon->status == "ok"); |
132 if (index == DomainReliabilityConfig::kInvalidResourceIndex) | 63 |
64 bool reported = config().DecideIfShouldReportRequest(success); | |
65 UMA_HISTOGRAM_BOOLEAN("DomainReliability.BeaconReported", reported); | |
66 if (!reported) { | |
67 UMA_HISTOGRAM_BOOLEAN("DomainReliability.OnBeaconDidEvict", false); | |
Randy Smith (Not in Mondays)
2015/11/03 21:48:12
Quick comment noting that you're entering this his
Deprecated (see juliatuttle)
2015/11/06 17:22:29
Done.
| |
133 return; | 68 return; |
134 DCHECK_GT(states_.size(), index); | |
135 | |
136 bool success = (beacon.status == "ok"); | |
137 | |
138 ResourceState* state = states_[index]; | |
139 if (success) | |
140 ++state->successful_requests; | |
141 else | |
142 ++state->failed_requests; | |
143 | |
144 bool reported = false; | |
145 bool evicted = false; | |
146 if (state->config->DecideIfShouldReportRequest(success)) { | |
147 beacons_.push_back(beacon); | |
148 beacons_.back().resource = state->config->name; | |
149 if (beacons_.size() > kMaxQueuedBeacons) { | |
150 RemoveOldestBeacon(); | |
151 evicted = true; | |
152 } | |
153 scheduler_.OnBeaconAdded(); | |
154 reported = true; | |
155 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.ReportedBeaconError", | |
156 -beacon.chrome_error); | |
157 if (!beacon.server_ip.empty()) { | |
158 UMA_HISTOGRAM_SPARSE_SLOWLY( | |
159 "DomainReliability.ReportedBeaconError_HasServerIP", | |
160 -beacon.chrome_error); | |
161 } | |
162 // TODO(ttuttle): Histogram HTTP response code? | |
163 } | 69 } |
164 | 70 |
165 UMA_HISTOGRAM_BOOLEAN("DomainReliability.BeaconReported", reported); | 71 bool evicted = false; |
72 | |
73 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.ReportedBeaconError", | |
74 -beacon->chrome_error); | |
75 if (!beacon->server_ip.empty()) { | |
76 UMA_HISTOGRAM_SPARSE_SLOWLY( | |
77 "DomainReliability.ReportedBeaconError_HasServerIP", | |
78 -beacon->chrome_error); | |
79 } | |
80 // TODO(ttuttle): Histogram HTTP response code? | |
81 | |
82 beacons_.push_back(beacon.release()); | |
83 if (beacons_.size() > kMaxQueuedBeacons) { | |
84 RemoveOldestBeacon(); | |
85 evicted = true; | |
86 } | |
87 | |
88 scheduler_.OnBeaconAdded(); | |
89 | |
166 UMA_HISTOGRAM_BOOLEAN("DomainReliability.OnBeaconDidEvict", evicted); | 90 UMA_HISTOGRAM_BOOLEAN("DomainReliability.OnBeaconDidEvict", evicted); |
167 } | 91 } |
168 | 92 |
169 void DomainReliabilityContext::ClearBeacons() { | 93 void DomainReliabilityContext::ClearBeacons() { |
170 for (auto& state : states_) { | 94 STLDeleteElements(&beacons_); |
171 state->successful_requests = 0; | |
172 state->failed_requests = 0; | |
173 state->uploading_successful_requests = 0; | |
174 state->uploading_failed_requests = 0; | |
175 } | |
176 beacons_.clear(); | 95 beacons_.clear(); |
177 uploading_beacons_size_ = 0; | 96 uploading_beacons_size_ = 0; |
178 } | 97 } |
179 | 98 |
180 scoped_ptr<base::Value> DomainReliabilityContext::GetWebUIData() const { | 99 scoped_ptr<Value> DomainReliabilityContext::GetWebUIData() const { |
181 base::DictionaryValue* context_value = new base::DictionaryValue(); | 100 DictionaryValue* context_value = new DictionaryValue(); |
182 | 101 |
183 context_value->SetString("domain", config().domain); | 102 context_value->SetString("origin", config().origin.spec()); |
184 context_value->SetInteger("beacon_count", static_cast<int>(beacons_.size())); | 103 context_value->SetInteger("beacon_count", static_cast<int>(beacons_.size())); |
185 context_value->SetInteger("uploading_beacon_count", | 104 context_value->SetInteger("uploading_beacon_count", |
186 static_cast<int>(uploading_beacons_size_)); | 105 static_cast<int>(uploading_beacons_size_)); |
187 context_value->Set("scheduler", scheduler_.GetWebUIData()); | 106 context_value->Set("scheduler", scheduler_.GetWebUIData()); |
188 | 107 |
189 return scoped_ptr<base::Value>(context_value); | 108 return scoped_ptr<Value>(context_value); |
190 } | 109 } |
191 | 110 |
192 void DomainReliabilityContext::GetQueuedBeaconsForTesting( | 111 void DomainReliabilityContext::GetQueuedBeaconsForTesting( |
193 std::vector<DomainReliabilityBeacon>* beacons_out) const { | 112 std::vector<const DomainReliabilityBeacon*>* beacons_out) const { |
113 DCHECK(this); | |
114 DCHECK(beacons_out); | |
194 beacons_out->assign(beacons_.begin(), beacons_.end()); | 115 beacons_out->assign(beacons_.begin(), beacons_.end()); |
195 } | 116 } |
196 | 117 |
197 void DomainReliabilityContext::GetRequestCountsForTesting( | |
198 size_t resource_index, | |
199 uint32_t* successful_requests_out, | |
200 uint32_t* failed_requests_out) const { | |
201 DCHECK_NE(DomainReliabilityConfig::kInvalidResourceIndex, resource_index); | |
202 DCHECK_GT(states_.size(), resource_index); | |
203 | |
204 const ResourceState& state = *states_[resource_index]; | |
205 *successful_requests_out = state.successful_requests; | |
206 *failed_requests_out = state.failed_requests; | |
207 } | |
208 | |
209 void DomainReliabilityContext::InitializeResourceStates() { | |
210 for (auto& resource : config_->resources) | |
211 states_.push_back(new ResourceState(this, resource)); | |
212 } | |
213 | |
214 void DomainReliabilityContext::ScheduleUpload( | 118 void DomainReliabilityContext::ScheduleUpload( |
215 base::TimeDelta min_delay, | 119 base::TimeDelta min_delay, |
216 base::TimeDelta max_delay) { | 120 base::TimeDelta max_delay) { |
217 dispatcher_->ScheduleTask( | 121 dispatcher_->ScheduleTask( |
218 base::Bind( | 122 base::Bind( |
219 &DomainReliabilityContext::StartUpload, | 123 &DomainReliabilityContext::StartUpload, |
220 weak_factory_.GetWeakPtr()), | 124 weak_factory_.GetWeakPtr()), |
221 min_delay, | 125 min_delay, |
222 max_delay); | 126 max_delay); |
223 } | 127 } |
224 | 128 |
225 void DomainReliabilityContext::StartUpload() { | 129 void DomainReliabilityContext::StartUpload() { |
226 MarkUpload(); | 130 MarkUpload(); |
227 | 131 |
228 DCHECK(upload_time_.is_null()); | 132 DCHECK(upload_time_.is_null()); |
229 upload_time_ = time_->NowTicks(); | 133 upload_time_ = time_->NowTicks(); |
134 size_t collector_index = scheduler_.OnUploadStart(); | |
135 const GURL& collector_url = *config().collectors[collector_index]; | |
136 | |
230 std::string report_json; | 137 std::string report_json; |
231 base::JSONWriter::Write(*CreateReport(upload_time_), &report_json); | 138 scoped_ptr<const Value> report = CreateReport(upload_time_, collector_url); |
232 | 139 base::JSONWriter::Write(*report, &report_json); |
233 size_t collector_index = scheduler_.OnUploadStart(); | 140 report.reset(); |
234 | 141 |
235 uploader_->UploadReport( | 142 uploader_->UploadReport( |
236 report_json, | 143 report_json, collector_url, |
237 config_->collectors[collector_index]->upload_url, | 144 base::Bind(&DomainReliabilityContext::OnUploadComplete, |
238 base::Bind( | 145 weak_factory_.GetWeakPtr())); |
239 &DomainReliabilityContext::OnUploadComplete, | |
240 weak_factory_.GetWeakPtr())); | |
241 | 146 |
242 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadCollectorIndex", | 147 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadCollectorIndex", |
243 static_cast<int>(collector_index)); | 148 static_cast<int>(collector_index)); |
244 if (!last_upload_time_.is_null()) { | 149 if (!last_upload_time_.is_null()) { |
245 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadInterval", | 150 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadInterval", |
246 upload_time_ - last_upload_time_); | 151 upload_time_ - last_upload_time_); |
247 } | 152 } |
248 } | 153 } |
249 | 154 |
250 void DomainReliabilityContext::OnUploadComplete( | 155 void DomainReliabilityContext::OnUploadComplete( |
(...skipping 12 matching lines...) Expand all Loading... | |
263 DCHECK(!upload_time_.is_null()); | 168 DCHECK(!upload_time_.is_null()); |
264 UMA_HISTOGRAM_MEDIUM_TIMES("DomainReliability.UploadDuration", | 169 UMA_HISTOGRAM_MEDIUM_TIMES("DomainReliability.UploadDuration", |
265 now - upload_time_); | 170 now - upload_time_); |
266 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadCollectorRetryDelay", | 171 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadCollectorRetryDelay", |
267 scheduler_.last_collector_retry_delay()); | 172 scheduler_.last_collector_retry_delay()); |
268 last_upload_time_ = upload_time_; | 173 last_upload_time_ = upload_time_; |
269 upload_time_ = base::TimeTicks(); | 174 upload_time_ = base::TimeTicks(); |
270 } | 175 } |
271 | 176 |
272 scoped_ptr<const Value> DomainReliabilityContext::CreateReport( | 177 scoped_ptr<const Value> DomainReliabilityContext::CreateReport( |
273 base::TimeTicks upload_time) const { | 178 base::TimeTicks upload_time, |
179 const GURL& collector_url) const { | |
274 scoped_ptr<ListValue> beacons_value(new ListValue()); | 180 scoped_ptr<ListValue> beacons_value(new ListValue()); |
275 for (const auto& beacon : beacons_) { | 181 for (const auto& beacon : beacons_) { |
276 beacons_value->Append( | 182 beacons_value->Append(beacon->ToValue(upload_time, |
277 beacon.ToValue(upload_time, *last_network_change_time_)); | 183 *last_network_change_time_, |
278 } | 184 collector_url, |
279 | 185 config().path_prefixes)); |
280 scoped_ptr<ListValue> resources_value(new ListValue()); | |
281 for (const auto& state : states_) { | |
282 scoped_ptr<Value> resource_report = state->ToValue(upload_time); | |
283 if (resource_report) | |
284 resources_value->Append(resource_report.release()); | |
285 } | 186 } |
286 | 187 |
287 scoped_ptr<DictionaryValue> report_value(new DictionaryValue()); | 188 scoped_ptr<DictionaryValue> report_value(new DictionaryValue()); |
288 if (!config().version.empty()) | |
289 report_value->SetString("config_version", config().version); | |
290 report_value->SetString("reporter", upload_reporter_string_); | 189 report_value->SetString("reporter", upload_reporter_string_); |
291 report_value->Set("entries", beacons_value.release()); | 190 report_value->Set("entries", beacons_value.release()); |
292 if (!resources_value->empty()) | |
293 report_value->Set("resources", resources_value.release()); | |
294 | 191 |
295 return report_value.Pass(); | 192 return report_value.Pass(); |
296 } | 193 } |
297 | 194 |
298 void DomainReliabilityContext::MarkUpload() { | 195 void DomainReliabilityContext::MarkUpload() { |
299 for (auto& state : states_) | |
300 state->MarkUpload(); | |
301 DCHECK_EQ(0u, uploading_beacons_size_); | 196 DCHECK_EQ(0u, uploading_beacons_size_); |
302 uploading_beacons_size_ = beacons_.size(); | 197 uploading_beacons_size_ = beacons_.size(); |
303 DCHECK_NE(0u, uploading_beacons_size_); | 198 DCHECK_NE(0u, uploading_beacons_size_); |
304 } | 199 } |
305 | 200 |
306 void DomainReliabilityContext::CommitUpload() { | 201 void DomainReliabilityContext::CommitUpload() { |
307 for (auto& state : states_) | 202 auto begin = beacons_.begin(); |
308 state->CommitUpload(); | 203 auto end = begin + uploading_beacons_size_; |
309 BeaconIterator begin = beacons_.begin(); | 204 STLDeleteContainerPointers(begin, end); |
310 BeaconIterator end = begin + uploading_beacons_size_; | |
311 beacons_.erase(begin, end); | 205 beacons_.erase(begin, end); |
312 DCHECK_NE(0u, uploading_beacons_size_); | 206 DCHECK_NE(0u, uploading_beacons_size_); |
313 uploading_beacons_size_ = 0; | 207 uploading_beacons_size_ = 0; |
314 } | 208 } |
315 | 209 |
316 void DomainReliabilityContext::RollbackUpload() { | 210 void DomainReliabilityContext::RollbackUpload() { |
317 for (auto& state : states_) | |
318 state->RollbackUpload(); | |
319 DCHECK_NE(0u, uploading_beacons_size_); | 211 DCHECK_NE(0u, uploading_beacons_size_); |
320 uploading_beacons_size_ = 0; | 212 uploading_beacons_size_ = 0; |
321 } | 213 } |
322 | 214 |
323 void DomainReliabilityContext::RemoveOldestBeacon() { | 215 void DomainReliabilityContext::RemoveOldestBeacon() { |
324 DCHECK(!beacons_.empty()); | 216 DCHECK(!beacons_.empty()); |
325 | 217 |
326 VLOG(1) << "Beacon queue for " << config().domain << " full; " | 218 VLOG(1) << "Beacon queue for " << config().origin << " full; " |
327 << "removing oldest beacon"; | 219 << "removing oldest beacon"; |
328 | 220 |
221 delete beacons_.front(); | |
329 beacons_.pop_front(); | 222 beacons_.pop_front(); |
330 | 223 |
331 // If that just removed a beacon counted in uploading_beacons_size_, decrement | 224 // If that just removed a beacon counted in uploading_beacons_size_, decrement |
332 // that. | 225 // that. |
333 if (uploading_beacons_size_ > 0) | 226 if (uploading_beacons_size_ > 0) |
334 --uploading_beacons_size_; | 227 --uploading_beacons_size_; |
335 } | 228 } |
336 | 229 |
337 } // namespace domain_reliability | 230 } // namespace domain_reliability |
OLD | NEW |