Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: components/cronet/stale_host_resolver.cc

Issue 1898873006: Cronet: Use stale DNS cache entries experimentally. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@dns_stale2
Patch Set: Move StaleHostResolver into cronet Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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.
4
5 #include "components/cronet/stale_host_resolver.h"
6
7 #include "base/callback_helpers.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/timer/timer.h"
10 #include "base/values.h"
11 #include "net/base/net_errors.h"
12 #include "net/dns/dns_util.h"
13
14 #define STALE_HISTOGRAM_ENUM(name, value, max) \
15 UMA_HISTOGRAM_ENUMERATION("DNS.StaleHostResolver." name, value, max)
16
17 #define STALE_HISTOGRAM_TIME(name, time) \
18 UMA_HISTOGRAM_MEDIUM_TIMES("DNS.StaleHostResolver." name, time)
19
20 using net::AddressList;
21 using net::AddressListDeltaType;
22 using net::BoundNetLog;
23 using net::CompletionCallback;
24 using net::ERR_DNS_CACHE_MISS;
25 using net::ERR_IO_PENDING;
26 using net::ERR_UNEXPECTED;
27 using net::HostCache;
28 using net::HostResolver;
29 using net::HostResolverImpl;
30 using net::MAX_DELTA_TYPE;
31 using net::OK;
32 using net::RequestPriority;
Randy Smith (Not in Mondays) 2016/06/08 19:20:03 https://google.github.io/styleguide/cppguide.html#
Julia Tuttle 2016/06/10 17:31:44 Done, but to me, this is morally part of net/, jus
33
34 namespace cronet {
35
36 namespace {
37
38 // Used in histograms; do not modify existing values.
39 enum RequestOutcome {
40 // Served from (valid) cache, hosts file, IP literal, etc.
41 SYNCHRONOUS = 0,
42
43 // Network responded; there was no usable stale data.
44 NETWORK_WITHOUT_STALE = 1,
45
46 // Network responded before stale delay; there was usable stale data.
47 NETWORK_WITH_STALE = 2,
48
49 // Stale data returned; network didn't respond before the stale delay.
50 STALE_BEFORE_NETWORK = 3,
51
52 // Request canceled; there was no usable stale data.
53 CANCELED_WITHOUT_STALE = 4,
54
55 // Request canceled; there was usable stale data.
56 CANCELED_WITH_STALE = 5,
57
58 MAX_REQUEST_OUTCOME
59 };
60
61 void RecordRequestOutcome(RequestOutcome outcome) {
62 STALE_HISTOGRAM_ENUM("RequestOutcome", outcome, MAX_REQUEST_OUTCOME);
63 }
64
65 void RecordAddressListDelta(AddressListDeltaType delta) {
66 STALE_HISTOGRAM_ENUM("StaleAddressListDelta", delta, MAX_DELTA_TYPE);
67 }
68
69 void RecordTimeDelta(base::TimeTicks network_time, base::TimeTicks stale_time) {
70 if (network_time < stale_time)
71 STALE_HISTOGRAM_TIME("NetworkEarly", stale_time - network_time);
72 else
73 STALE_HISTOGRAM_TIME("NetworkLate", network_time - stale_time);
74 }
75
76 int ResolveStale(HostResolverImpl* resolver,
Randy Smith (Not in Mondays) 2016/06/08 19:20:03 nit, suggestion: Since this is a helper routine us
Julia Tuttle 2016/06/10 17:31:44 I had it in the caller, and it felt a little too c
77 const HostResolver::RequestInfo& info,
78 RequestPriority priority,
79 AddressList* addresses,
Randy Smith (Not in Mondays) 2016/06/08 19:20:02 nitty nit: Slight preference for calling this netw
Julia Tuttle 2016/06/10 17:31:44 It's not network addresses if there is a fresh cac
80 const CompletionCallback& callback,
81 HostResolver::RequestHandle* out_req,
82 int* stale_error,
83 AddressList* stale_addresses,
84 HostCache::EntryStaleness* stale_info,
85 const BoundNetLog& net_log) {
86 AddressList cache_addresses;
87 int cache_rv = resolver->ResolveStaleFromCache(info, &cache_addresses,
88 stale_info, net_log);
89 // If it's a fresh cache hit (or literal), return it synchronously.
90 if (cache_rv != ERR_DNS_CACHE_MISS && !stale_info->is_stale()) {
91 *stale_error = ERR_UNEXPECTED;
92 *addresses = cache_addresses;
93 return cache_rv;
94 }
95
96 // If it's a stale cache hit, fill in |*stale_addresses| but run the network
97 // request anyway.
98 if (cache_rv != ERR_DNS_CACHE_MISS)
99 *stale_addresses = cache_addresses;
100
101 *stale_error = cache_rv;
102
103 // Don't check the cache again.
104 HostResolver::RequestInfo no_cache_info(info);
105 no_cache_info.set_allow_cached_response(false);
106 return resolver->Resolve(no_cache_info, priority, addresses, callback,
107 out_req, net_log);
108 }
109
110 } // namespace
111
112 // A request made by the StaleHostResolver. May return fresh cached data,
113 // network data, or stale cached data.
114 class StaleHostResolver::Request {
115 public:
116 Request();
117
118 // A callback for the caller to decide whether a stale entry is usable or not.
119 typedef base::Callback<bool(const HostCache::EntryStaleness&)>
120 StaleEntryUsableCallback;
121
122 // Starts the request. May call |usable_callback| inline if |resolver| returns
123 // stale data to let the caller decide whether the data is usable.
124 //
125 // Returns the result if the request finishes synchronously. Returns
126 // ERR_IO_PENDING and calls |callback| with the result if it finishes
127 // asynchronously, unless the requets is canceled (via |Cancel()|).
128 //
129 // |addresses| must remain valid until the Request completes (synchronously or
130 // via |callback|) or is canceled (via |Cancel()|).
131 int Start(HostResolverImpl* resolver,
132 const RequestInfo& info,
133 RequestPriority priority,
134 AddressList* addresses,
135 const CompletionCallback& callback,
136 const BoundNetLog& net_log,
137 const StaleEntryUsableCallback& usable_callback,
138 base::TimeDelta stale_delay);
139
140 // Cancels the request. |resolver| must be the same resolver passed to
141 // |Start()|. Does not call the callback passed to |Start()|.
142 //
143 // |Start()| must have been called and returned ERR_IO_PENDING; the request
144 // must not have been canceled already.
145 void Cancel(HostResolverImpl* resolver);
146
147 bool has_network_request() const { return !!network_handle_; }
148 bool returned_stale_result() const { return callback_.is_null(); }
149
150 private:
151 ~Request();
152
153 // Callback for the timer to return stale data.
154 void OnStaleDelayElapsed();
155
156 // Callback for the underlying network request.
157 void OnNetworkRequestComplete(int error);
158
159 // Populates |addresses_| from |addresses| if and only if rv is OK, clears
Randy Smith (Not in Mondays) 2016/06/08 19:20:02 nit: |*addresses_|.
Julia Tuttle 2016/06/10 17:31:44 Done.
160 // |addresses_| to make sure the request doesn't return twice, and then
161 // returns |rv|.
162 int HandleResult(int rv, const AddressList& addresses);
163
164 void RecordSynchronousRequest();
165 void RecordNetworkRequest(int error);
166 void RecordCanceledRequest();
167
168 AddressList* addresses_;
169 CompletionCallback callback_;
170
171 int stale_error_;
172 AddressList stale_addresses_;
173 base::OneShotTimer stale_timer_;
174
175 AddressList network_addresses_;
176 HostResolver::RequestHandle network_handle_;
177 };
178
179 StaleHostResolver::Request::Request()
180 : addresses_(nullptr), network_handle_(nullptr) {}
181
182 int StaleHostResolver::Request::Start(
183 HostResolverImpl* resolver,
184 const RequestInfo& info,
185 RequestPriority priority,
186 AddressList* addresses,
187 const CompletionCallback& callback,
188 const BoundNetLog& net_log,
189 const StaleEntryUsableCallback& usable_callback,
190 base::TimeDelta stale_delay) {
191 DCHECK(!callback.is_null());
192 DCHECK(!usable_callback.is_null());
193
194 callback_ = callback;
195 addresses_ = addresses;
196
197 CompletionCallback network_callback =
198 base::Bind(&StaleHostResolver::Request::OnNetworkRequestComplete,
199 base::Unretained(this));
Randy Smith (Not in Mondays) 2016/06/08 19:20:03 semi-nit: Comments above the base::Unretaineds as
Julia Tuttle 2016/06/10 17:31:44 Done.
200 base::Callback<void()> stale_callback = base::Bind(
201 &StaleHostResolver::Request::OnStaleDelayElapsed, base::Unretained(this));
202
203 HostCache::EntryStaleness stale_info;
204 int rv = ResolveStale(resolver, info, priority, &network_addresses_,
205 network_callback, &network_handle_, &stale_error_,
206 &stale_addresses_, &stale_info, net_log);
207 if (rv != ERR_IO_PENDING) {
208 DCHECK(!network_handle_);
209 rv = HandleResult(rv, network_addresses_);
210 RecordSynchronousRequest();
211 delete this;
212 return rv;
213 }
214
215 if (stale_error_ != ERR_DNS_CACHE_MISS && usable_callback.Run(stale_info))
216 stale_timer_.Start(FROM_HERE, stale_delay, stale_callback);
217 else
218 stale_addresses_.clear();
219
220 return ERR_IO_PENDING;
221 }
222
223 void StaleHostResolver::Request::Cancel(HostResolverImpl* resolver) {
224 DCHECK(has_network_request());
225 DCHECK(!returned_stale_result());
226
227 resolver->CancelRequest(network_handle_);
228 network_handle_ = nullptr;
229
230 RecordCanceledRequest();
231 delete this;
Randy Smith (Not in Mondays) 2016/06/08 19:20:02 This is unusual enough behavior that it really sho
Julia Tuttle 2016/06/10 17:31:44 See below; right now, the caller is *happily* unaw
232 }
233
234 StaleHostResolver::Request::~Request() {
235 DCHECK(!has_network_request());
236 }
237
238 void StaleHostResolver::Request::OnStaleDelayElapsed() {
239 DCHECK(has_network_request());
240 DCHECK(!returned_stale_result());
241
242 base::ResetAndReturn(&callback_)
243 .Run(HandleResult(stale_error_, stale_addresses_));
244
245 // Don't delete |this|; let the underlying request continue to backfill the
246 // host cache.
Randy Smith (Not in Mondays) 2016/06/08 19:20:03 Hmm. To me, this comment implies that we *could*
Julia Tuttle 2016/06/10 17:31:44 Done.
247 }
248
249 void StaleHostResolver::Request::OnNetworkRequestComplete(int error) {
250 DCHECK(has_network_request());
251
252 network_handle_ = nullptr;
253
254 if (!returned_stale_result())
255 callback_.Run(HandleResult(error, network_addresses_));
256
257 RecordNetworkRequest(error);
258 delete this;
Randy Smith (Not in Mondays) 2016/06/08 19:20:02 Um ... this isn't wrong, but it is scary. The fac
Julia Tuttle 2016/06/10 17:31:44 Whoa, hold on, I'm not sure I agree. Indirecting t
259 }
260
261 int StaleHostResolver::Request::HandleResult(int rv,
262 const AddressList& addresses) {
263 DCHECK(addresses_);
264
265 if (rv == OK)
266 *addresses_ = addresses;
267 addresses_ = nullptr;
268 return rv;
269 }
270
271 void StaleHostResolver::Request::RecordSynchronousRequest() {
272 RecordRequestOutcome(SYNCHRONOUS);
273 }
274
275 void StaleHostResolver::Request::RecordNetworkRequest(int error) {
276 if (stale_timer_.IsRunning() || returned_stale_result())
277 RecordTimeDelta(base::TimeTicks::Now(), stale_timer_.desired_run_time());
278
279 if (returned_stale_result() && stale_error_ == OK && error == OK) {
280 RecordAddressListDelta(
281 FindAddressListDeltaType(stale_addresses_, network_addresses_));
282 }
283
284 if (returned_stale_result())
285 RecordRequestOutcome(STALE_BEFORE_NETWORK);
286 else if (stale_timer_.IsRunning())
287 RecordRequestOutcome(NETWORK_WITH_STALE);
288 else
289 RecordRequestOutcome(NETWORK_WITHOUT_STALE);
290 }
291
292 void StaleHostResolver::Request::RecordCanceledRequest() {
293 if (stale_timer_.IsRunning())
294 RecordRequestOutcome(CANCELED_WITH_STALE);
295 else
296 RecordRequestOutcome(CANCELED_WITHOUT_STALE);
297 }
298
299 namespace {
300
301 bool StaleEntryIsUsable(const StaleHostResolver::StaleOptions& options,
302 const HostCache::EntryStaleness& entry) {
303 if (options.max_expired_time != base::TimeDelta() &&
304 entry.expired_by > options.max_expired_time) {
305 return false;
306 }
307 if (options.max_stale_uses > 0 && entry.stale_hits > options.max_stale_uses)
308 return false;
309 if (!options.allow_other_network && entry.network_changes > 0)
310 return false;
311 return true;
312 }
313
314 } // namespace
315
316 StaleHostResolver::StaleHostResolver(
317 std::unique_ptr<HostResolverImpl> inner_resolver,
318 const StaleOptions& stale_options)
319 : resolver_(std::move(inner_resolver)), options_(stale_options) {
320 DCHECK_GE(0, stale_options.max_expired_time.InMicroseconds());
321 DCHECK_GE(0, stale_options.max_stale_uses);
322 }
323
324 StaleHostResolver::~StaleHostResolver() {
325 for (auto* request : pending_requests_)
326 request->Cancel(resolver_.get());
327 pending_requests_.clear();
328 }
329
330 int StaleHostResolver::Resolve(const RequestInfo& info,
331 RequestPriority priority,
332 AddressList* addresses,
333 const CompletionCallback& callback,
334 RequestHandle* out_req,
335 const BoundNetLog& net_log) {
336 StaleHostResolver::Request::StaleEntryUsableCallback usable_callback =
337 base::Bind(&StaleEntryIsUsable, options_);
338
339 Request* request = new Request();
340 pending_requests_.insert(request);
341 CompletionCallback wrapped_callback =
342 base::Bind(&StaleHostResolver::OnRequestComplete, base::Unretained(this),
343 request, callback);
344
345 int rv = request->Start(resolver_.get(), info, priority, addresses,
346 wrapped_callback, net_log, usable_callback,
347 options_.delay);
348 if (rv == ERR_IO_PENDING && out_req)
349 *out_req = reinterpret_cast<RequestHandle>(request);
350 return rv;
351 }
352
353 void StaleHostResolver::CancelRequest(RequestHandle req_handle) {
354 Request* request = reinterpret_cast<Request*>(req_handle);
355 DCHECK(request);
356 DCHECK_EQ(1u, pending_requests_.count(request));
357
358 request->Cancel(resolver_.get());
359 pending_requests_.erase(request);
360 }
361
362 int StaleHostResolver::ResolveFromCache(const RequestInfo& info,
363 AddressList* addresses,
364 const BoundNetLog& net_log) {
365 return resolver_->ResolveFromCache(info, addresses, net_log);
366 }
367
368 void StaleHostResolver::SetDnsClientEnabled(bool enabled) {
369 resolver_->SetDnsClientEnabled(enabled);
370 }
371
372 HostCache* StaleHostResolver::GetHostCache() {
373 return resolver_->GetHostCache();
374 }
375
376 std::unique_ptr<base::Value> StaleHostResolver::GetDnsConfigAsValue() const {
377 return resolver_->GetDnsConfigAsValue();
378 }
379
380 void StaleHostResolver::OnRequestComplete(
381 StaleHostResolver::Request* request,
382 const CompletionCallback& outer_callback,
383 int error) {
384 DCHECK(request);
385 DCHECK_NE(ERR_IO_PENDING, error);
386
387 DCHECK_EQ(1u, pending_requests_.count(request));
388 pending_requests_.erase(request);
389
390 outer_callback.Run(error);
391 }
392
393 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698