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

Side by Side Diff: net/dns/dns_session.cc

Issue 1778933002: DNS: Per-network-type and Finch-variable timeouts (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix NaCl build issue? Created 4 years, 9 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "net/dns/dns_session.h" 5 #include "net/dns/dns_session.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <limits> 8 #include <limits>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/lazy_instance.h" 12 #include "base/lazy_instance.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
15 #include "base/metrics/sample_vector.h" 15 #include "base/metrics/sample_vector.h"
16 #include "base/rand_util.h" 16 #include "base/rand_util.h"
17 #include "base/stl_util.h" 17 #include "base/stl_util.h"
18 #include "base/time/time.h" 18 #include "base/time/time.h"
19 #include "net/base/ip_endpoint.h" 19 #include "net/base/ip_endpoint.h"
20 #include "net/base/net_errors.h" 20 #include "net/base/net_errors.h"
21 #include "net/dns/dns_config_service.h" 21 #include "net/dns/dns_config_service.h"
22 #include "net/dns/dns_socket_pool.h" 22 #include "net/dns/dns_socket_pool.h"
23 #include "net/dns/dns_util.h"
23 #include "net/socket/stream_socket.h" 24 #include "net/socket/stream_socket.h"
24 #include "net/udp/datagram_client_socket.h" 25 #include "net/udp/datagram_client_socket.h"
25 26
26 namespace net { 27 namespace net {
27 28
28 namespace { 29 namespace {
29 // Never exceed max timeout. 30
30 const unsigned kMaxTimeoutMs = 5000;
31 // Set min timeout, in case we are talking to a local DNS proxy. 31 // Set min timeout, in case we are talking to a local DNS proxy.
32 const unsigned kMinTimeoutMs = 10; 32 const unsigned kMinTimeoutMs = 10;
33 33
34 // Default maximum timeout between queries, even with exponential backoff.
35 // (Can be overridden by field trial.)
36 const unsigned kDefaultMaxTimeoutMs = 5000;
37
38 // Maximum RTT that will fit in the RTT histograms.
39 const int32_t kRTTMaxMs = 30000;
34 // Number of buckets in the histogram of observed RTTs. 40 // Number of buckets in the histogram of observed RTTs.
35 const size_t kRTTBucketCount = 100; 41 const size_t kRTTBucketCount = 350;
36 // Target percentile in the RTT histogram used for retransmission timeout. 42 // Target percentile in the RTT histogram used for retransmission timeout.
37 const unsigned kRTOPercentile = 99; 43 const unsigned kRTOPercentile = 99;
44
45 base::TimeDelta GetInitialTimeout(NetworkChangeNotifier::ConnectionType type,
Randy Smith (Not in Mondays) 2016/03/16 20:11:06 Up to you, but from my perspective the contents of
Deprecated (see juliatuttle) 2016/03/17 16:29:46 Done.
46 base::TimeDelta config_timeout) {
47 return GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
48 "AsyncDnsInitialTimeoutMsByConnectionType", config_timeout, type);
49 }
50
51 base::TimeDelta GetMaxTimeout(NetworkChangeNotifier::ConnectionType type) {
52 return GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
53 "AsyncDnsMaxTimeoutMsByConnectionType",
54 base::TimeDelta::FromMilliseconds(kDefaultMaxTimeoutMs), type);
55 }
56
38 } // namespace 57 } // namespace
39 58
40 // Runtime statistics of DNS server. 59 // Runtime statistics of DNS server.
41 struct DnsSession::ServerStats { 60 struct DnsSession::ServerStats {
42 ServerStats(base::TimeDelta rtt_estimate_param, RttBuckets* buckets) 61 ServerStats(base::TimeDelta rtt_estimate_param, RttBuckets* buckets)
43 : last_failure_count(0), rtt_estimate(rtt_estimate_param) { 62 : last_failure_count(0), rtt_estimate(rtt_estimate_param) {
44 rtt_histogram.reset(new base::SampleVector(buckets)); 63 rtt_histogram.reset(new base::SampleVector(buckets));
45 // Seed histogram with 2 samples at |rtt_estimate| timeout. 64 // Seed histogram with 2 samples at |rtt_estimate| timeout.
46 rtt_histogram->Accumulate( 65 rtt_histogram->Accumulate(
47 static_cast<base::HistogramBase::Sample>(rtt_estimate.InMilliseconds()), 66 static_cast<base::HistogramBase::Sample>(rtt_estimate.InMilliseconds()),
(...skipping 17 matching lines...) Expand all
65 scoped_ptr<base::SampleVector> rtt_histogram; 84 scoped_ptr<base::SampleVector> rtt_histogram;
66 85
67 DISALLOW_COPY_AND_ASSIGN(ServerStats); 86 DISALLOW_COPY_AND_ASSIGN(ServerStats);
68 }; 87 };
69 88
70 // static 89 // static
71 base::LazyInstance<DnsSession::RttBuckets>::Leaky DnsSession::rtt_buckets_ = 90 base::LazyInstance<DnsSession::RttBuckets>::Leaky DnsSession::rtt_buckets_ =
72 LAZY_INSTANCE_INITIALIZER; 91 LAZY_INSTANCE_INITIALIZER;
73 92
74 DnsSession::RttBuckets::RttBuckets() : base::BucketRanges(kRTTBucketCount + 1) { 93 DnsSession::RttBuckets::RttBuckets() : base::BucketRanges(kRTTBucketCount + 1) {
75 base::Histogram::InitializeBucketRanges(1, 5000, this); 94 base::Histogram::InitializeBucketRanges(1, kRTTMaxMs, this);
76 } 95 }
77 96
78 DnsSession::SocketLease::SocketLease(scoped_refptr<DnsSession> session, 97 DnsSession::SocketLease::SocketLease(scoped_refptr<DnsSession> session,
79 unsigned server_index, 98 unsigned server_index,
80 scoped_ptr<DatagramClientSocket> socket) 99 scoped_ptr<DatagramClientSocket> socket)
81 : session_(session), 100 : session_(session),
82 server_index_(server_index), 101 server_index_(server_index),
83 socket_(std::move(socket)) {} 102 socket_(std::move(socket)) {}
84 103
85 DnsSession::SocketLease::~SocketLease() { 104 DnsSession::SocketLease::~SocketLease() {
86 session_->FreeSocket(server_index_, std::move(socket_)); 105 session_->FreeSocket(server_index_, std::move(socket_));
87 } 106 }
88 107
89 DnsSession::DnsSession(const DnsConfig& config, 108 DnsSession::DnsSession(const DnsConfig& config,
90 scoped_ptr<DnsSocketPool> socket_pool, 109 scoped_ptr<DnsSocketPool> socket_pool,
91 const RandIntCallback& rand_int_callback, 110 const RandIntCallback& rand_int_callback,
92 NetLog* net_log) 111 NetLog* net_log)
93 : config_(config), 112 : config_(config),
94 socket_pool_(std::move(socket_pool)), 113 socket_pool_(std::move(socket_pool)),
95 rand_callback_(base::Bind(rand_int_callback, 114 rand_callback_(base::Bind(rand_int_callback,
96 0, 115 0,
97 std::numeric_limits<uint16_t>::max())), 116 std::numeric_limits<uint16_t>::max())),
98 net_log_(net_log), 117 net_log_(net_log),
99 server_index_(0) { 118 server_index_(0) {
100 socket_pool_->Initialize(&config_.nameservers, net_log); 119 socket_pool_->Initialize(&config_.nameservers, net_log);
101 UMA_HISTOGRAM_CUSTOM_COUNTS( 120 UMA_HISTOGRAM_CUSTOM_COUNTS(
102 "AsyncDNS.ServerCount", config_.nameservers.size(), 0, 10, 11); 121 "AsyncDNS.ServerCount", config_.nameservers.size(), 0, 10, 11);
103 for (size_t i = 0; i < config_.nameservers.size(); ++i) { 122 UpdateTimeouts(NetworkChangeNotifier::GetConnectionType());
104 server_stats_.push_back(make_scoped_ptr( 123 InitializeServerStats();
105 new ServerStats(config_.timeout, rtt_buckets_.Pointer()))); 124 NetworkChangeNotifier::AddConnectionTypeObserver(this);
106 }
107 } 125 }
108 126
109 DnsSession::~DnsSession() { 127 DnsSession::~DnsSession() {
110 RecordServerStats(); 128 RecordServerStats();
129 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
130 }
131
132 void DnsSession::UpdateTimeouts(NetworkChangeNotifier::ConnectionType type) {
133 initial_timeout_ = GetInitialTimeout(type, config_.timeout);
134 max_timeout_ = GetMaxTimeout(type);
135 }
136
137 void DnsSession::InitializeServerStats() {
138 server_stats_.clear();
139 for (size_t i = 0; i < config_.nameservers.size(); ++i) {
140 server_stats_.push_back(make_scoped_ptr(
141 new ServerStats(initial_timeout_, rtt_buckets_.Pointer())));
142 }
143 }
144
145 void DnsSession::OnConnectionTypeChanged(
146 NetworkChangeNotifier::ConnectionType type) {
147 base::TimeDelta old_initial_timeout = initial_timeout_;
148 UpdateTimeouts(type);
149 if (initial_timeout_ != old_initial_timeout) {
150 RecordServerStats();
151 InitializeServerStats();
Randy Smith (Not in Mondays) 2016/03/16 20:15:02 Actually, on my third (:-}) read-through I realize
Deprecated (see juliatuttle) 2016/03/17 16:29:46 This isn't a functionality change unless a field t
Randy Smith (Not in Mondays) 2016/03/17 21:58:16 Presuming we resolved this in in-person conversati
152 }
111 } 153 }
112 154
113 uint16_t DnsSession::NextQueryId() const { 155 uint16_t DnsSession::NextQueryId() const {
114 return static_cast<uint16_t>(rand_callback_.Run()); 156 return static_cast<uint16_t>(rand_callback_.Run());
115 } 157 }
116 158
117 unsigned DnsSession::NextFirstServerIndex() { 159 unsigned DnsSession::NextFirstServerIndex() {
118 unsigned index = NextGoodServerIndex(server_index_); 160 unsigned index = NextGoodServerIndex(server_index_);
119 if (config_.rotate) 161 if (config_.rotate)
120 server_index_ = (server_index_ + 1) % config_.nameservers.size(); 162 server_index_ = (server_index_ + 1) % config_.nameservers.size();
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 } else { 258 } else {
217 UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresAfterSuccess", 259 UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresAfterSuccess",
218 server_stats_[index]->last_failure_count); 260 server_stats_[index]->last_failure_count);
219 } 261 }
220 } 262 }
221 } 263 }
222 } 264 }
223 265
224 266
225 base::TimeDelta DnsSession::NextTimeout(unsigned server_index, int attempt) { 267 base::TimeDelta DnsSession::NextTimeout(unsigned server_index, int attempt) {
226 // Respect config timeout if it exceeds |kMaxTimeoutMs|. 268 // Respect initial timeout (from config or field trial) if it exceeds max.
227 if (config_.timeout.InMilliseconds() >= kMaxTimeoutMs) 269 if (initial_timeout_ > max_timeout_)
228 return config_.timeout; 270 return initial_timeout_;
229 return NextTimeoutFromHistogram(server_index, attempt); 271 return NextTimeoutFromHistogram(server_index, attempt);
230 } 272 }
231 273
232 // Allocate a socket, already connected to the server address. 274 // Allocate a socket, already connected to the server address.
233 scoped_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket( 275 scoped_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket(
234 unsigned server_index, const NetLog::Source& source) { 276 unsigned server_index, const NetLog::Source& source) {
235 scoped_ptr<DatagramClientSocket> socket; 277 scoped_ptr<DatagramClientSocket> socket;
236 278
237 socket = socket_pool_->AllocateSocket(server_index); 279 socket = socket_pool_->AllocateSocket(server_index);
238 if (!socket.get()) 280 if (!socket.get())
(...skipping 26 matching lines...) Expand all
265 DCHECK_LT(server_index, server_stats_.size()); 307 DCHECK_LT(server_index, server_stats_.size());
266 308
267 base::TimeDelta timeout = server_stats_[server_index]->rtt_estimate + 309 base::TimeDelta timeout = server_stats_[server_index]->rtt_estimate +
268 4 * server_stats_[server_index]->rtt_deviation; 310 4 * server_stats_[server_index]->rtt_deviation;
269 311
270 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs)); 312 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs));
271 313
272 // The timeout doubles every full round. 314 // The timeout doubles every full round.
273 unsigned num_backoffs = attempt / config_.nameservers.size(); 315 unsigned num_backoffs = attempt / config_.nameservers.size();
274 316
275 return std::min(timeout * (1 << num_backoffs), 317 return std::min(timeout * (1 << num_backoffs), max_timeout_);
276 base::TimeDelta::FromMilliseconds(kMaxTimeoutMs));
277 } 318 }
278 319
279 base::TimeDelta DnsSession::NextTimeoutFromHistogram(unsigned server_index, 320 base::TimeDelta DnsSession::NextTimeoutFromHistogram(unsigned server_index,
280 int attempt) { 321 int attempt) {
281 DCHECK_LT(server_index, server_stats_.size()); 322 DCHECK_LT(server_index, server_stats_.size());
282 323
283 static_assert(std::numeric_limits<base::HistogramBase::Count>::is_signed, 324 static_assert(std::numeric_limits<base::HistogramBase::Count>::is_signed,
284 "histogram base count assumed to be signed"); 325 "histogram base count assumed to be signed");
285 326
286 // Use fixed percentile of observed samples. 327 // Use fixed percentile of observed samples.
287 const base::SampleVector& samples = 328 const base::SampleVector& samples =
288 *server_stats_[server_index]->rtt_histogram; 329 *server_stats_[server_index]->rtt_histogram;
289 330
290 base::HistogramBase::Count total = samples.TotalCount(); 331 base::HistogramBase::Count total = samples.TotalCount();
291 base::HistogramBase::Count remaining_count = kRTOPercentile * total / 100; 332 base::HistogramBase::Count remaining_count = kRTOPercentile * total / 100;
292 size_t index = 0; 333 size_t index = 0;
293 while (remaining_count > 0 && index < rtt_buckets_.Get().size()) { 334 while (remaining_count > 0 && index < rtt_buckets_.Get().size()) {
294 remaining_count -= samples.GetCountAtIndex(index); 335 remaining_count -= samples.GetCountAtIndex(index);
295 ++index; 336 ++index;
296 } 337 }
297 338
298 base::TimeDelta timeout = 339 base::TimeDelta timeout =
299 base::TimeDelta::FromMilliseconds(rtt_buckets_.Get().range(index)); 340 base::TimeDelta::FromMilliseconds(rtt_buckets_.Get().range(index));
300 341
301 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs)); 342 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs));
302 343
303 // The timeout still doubles every full round. 344 // The timeout still doubles every full round.
304 unsigned num_backoffs = attempt / config_.nameservers.size(); 345 unsigned num_backoffs = attempt / config_.nameservers.size();
305 346
306 return std::min(timeout * (1 << num_backoffs), 347 return std::min(timeout * (1 << num_backoffs), max_timeout_);
307 base::TimeDelta::FromMilliseconds(kMaxTimeoutMs));
308 } 348 }
309 349
310 } // namespace net 350 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_session.h ('k') | net/dns/dns_session_unittest.cc » ('j') | net/dns/dns_util.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698