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

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: Remove change to gdig. 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
« no previous file with comments | « net/dns/dns_session.h ('k') | net/dns/dns_session_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/field_trial.h"
14 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
15 #include "base/metrics/sample_vector.h" 16 #include "base/metrics/sample_vector.h"
16 #include "base/rand_util.h" 17 #include "base/rand_util.h"
17 #include "base/stl_util.h" 18 #include "base/stl_util.h"
18 #include "base/time/time.h" 19 #include "base/time/time.h"
19 #include "net/base/ip_endpoint.h" 20 #include "net/base/ip_endpoint.h"
20 #include "net/base/net_errors.h" 21 #include "net/base/net_errors.h"
21 #include "net/dns/dns_config_service.h" 22 #include "net/dns/dns_config_service.h"
22 #include "net/dns/dns_socket_pool.h" 23 #include "net/dns/dns_socket_pool.h"
24 #include "net/dns/dns_util.h"
23 #include "net/socket/stream_socket.h" 25 #include "net/socket/stream_socket.h"
24 #include "net/udp/datagram_client_socket.h" 26 #include "net/udp/datagram_client_socket.h"
25 27
26 namespace net { 28 namespace net {
27 29
28 namespace { 30 namespace {
29 // Never exceed max timeout. 31
30 const unsigned kMaxTimeoutMs = 5000;
31 // Set min timeout, in case we are talking to a local DNS proxy. 32 // Set min timeout, in case we are talking to a local DNS proxy.
32 const unsigned kMinTimeoutMs = 10; 33 const unsigned kMinTimeoutMs = 10;
33 34
35 // Default maximum timeout between queries, even with exponential backoff.
36 // (Can be overridden by field trial.)
37 const unsigned kDefaultMaxTimeoutMs = 5000;
38
39 // Maximum RTT that will fit in the RTT histograms.
40 const int32_t kRTTMaxMs = 30000;
34 // Number of buckets in the histogram of observed RTTs. 41 // Number of buckets in the histogram of observed RTTs.
35 const size_t kRTTBucketCount = 100; 42 const size_t kRTTBucketCount = 350;
36 // Target percentile in the RTT histogram used for retransmission timeout. 43 // Target percentile in the RTT histogram used for retransmission timeout.
37 const unsigned kRTOPercentile = 99; 44 const unsigned kRTOPercentile = 99;
45
38 } // namespace 46 } // namespace
39 47
40 // Runtime statistics of DNS server. 48 // Runtime statistics of DNS server.
41 struct DnsSession::ServerStats { 49 struct DnsSession::ServerStats {
42 ServerStats(base::TimeDelta rtt_estimate_param, RttBuckets* buckets) 50 ServerStats(base::TimeDelta rtt_estimate_param, RttBuckets* buckets)
43 : last_failure_count(0), rtt_estimate(rtt_estimate_param) { 51 : last_failure_count(0), rtt_estimate(rtt_estimate_param) {
44 rtt_histogram.reset(new base::SampleVector(buckets)); 52 rtt_histogram.reset(new base::SampleVector(buckets));
45 // Seed histogram with 2 samples at |rtt_estimate| timeout. 53 // Seed histogram with 2 samples at |rtt_estimate| timeout.
46 rtt_histogram->Accumulate( 54 rtt_histogram->Accumulate(
47 static_cast<base::HistogramBase::Sample>(rtt_estimate.InMilliseconds()), 55 static_cast<base::HistogramBase::Sample>(rtt_estimate.InMilliseconds()),
(...skipping 17 matching lines...) Expand all
65 scoped_ptr<base::SampleVector> rtt_histogram; 73 scoped_ptr<base::SampleVector> rtt_histogram;
66 74
67 DISALLOW_COPY_AND_ASSIGN(ServerStats); 75 DISALLOW_COPY_AND_ASSIGN(ServerStats);
68 }; 76 };
69 77
70 // static 78 // static
71 base::LazyInstance<DnsSession::RttBuckets>::Leaky DnsSession::rtt_buckets_ = 79 base::LazyInstance<DnsSession::RttBuckets>::Leaky DnsSession::rtt_buckets_ =
72 LAZY_INSTANCE_INITIALIZER; 80 LAZY_INSTANCE_INITIALIZER;
73 81
74 DnsSession::RttBuckets::RttBuckets() : base::BucketRanges(kRTTBucketCount + 1) { 82 DnsSession::RttBuckets::RttBuckets() : base::BucketRanges(kRTTBucketCount + 1) {
75 base::Histogram::InitializeBucketRanges(1, 5000, this); 83 base::Histogram::InitializeBucketRanges(1, kRTTMaxMs, this);
76 } 84 }
77 85
78 DnsSession::SocketLease::SocketLease(scoped_refptr<DnsSession> session, 86 DnsSession::SocketLease::SocketLease(scoped_refptr<DnsSession> session,
79 unsigned server_index, 87 unsigned server_index,
80 scoped_ptr<DatagramClientSocket> socket) 88 scoped_ptr<DatagramClientSocket> socket)
81 : session_(session), 89 : session_(session),
82 server_index_(server_index), 90 server_index_(server_index),
83 socket_(std::move(socket)) {} 91 socket_(std::move(socket)) {}
84 92
85 DnsSession::SocketLease::~SocketLease() { 93 DnsSession::SocketLease::~SocketLease() {
86 session_->FreeSocket(server_index_, std::move(socket_)); 94 session_->FreeSocket(server_index_, std::move(socket_));
87 } 95 }
88 96
89 DnsSession::DnsSession(const DnsConfig& config, 97 DnsSession::DnsSession(const DnsConfig& config,
90 scoped_ptr<DnsSocketPool> socket_pool, 98 scoped_ptr<DnsSocketPool> socket_pool,
91 const RandIntCallback& rand_int_callback, 99 const RandIntCallback& rand_int_callback,
92 NetLog* net_log) 100 NetLog* net_log)
93 : config_(config), 101 : config_(config),
94 socket_pool_(std::move(socket_pool)), 102 socket_pool_(std::move(socket_pool)),
95 rand_callback_(base::Bind(rand_int_callback, 103 rand_callback_(base::Bind(rand_int_callback,
96 0, 104 0,
97 std::numeric_limits<uint16_t>::max())), 105 std::numeric_limits<uint16_t>::max())),
98 net_log_(net_log), 106 net_log_(net_log),
99 server_index_(0) { 107 server_index_(0) {
100 socket_pool_->Initialize(&config_.nameservers, net_log); 108 socket_pool_->Initialize(&config_.nameservers, net_log);
101 UMA_HISTOGRAM_CUSTOM_COUNTS( 109 UMA_HISTOGRAM_CUSTOM_COUNTS(
102 "AsyncDNS.ServerCount", config_.nameservers.size(), 0, 10, 11); 110 "AsyncDNS.ServerCount", config_.nameservers.size(), 0, 10, 11);
103 for (size_t i = 0; i < config_.nameservers.size(); ++i) { 111 UpdateTimeouts(NetworkChangeNotifier::GetConnectionType());
104 server_stats_.push_back(make_scoped_ptr( 112 InitializeServerStats();
105 new ServerStats(config_.timeout, rtt_buckets_.Pointer()))); 113 NetworkChangeNotifier::AddConnectionTypeObserver(this);
106 }
107 } 114 }
108 115
109 DnsSession::~DnsSession() { 116 DnsSession::~DnsSession() {
110 RecordServerStats(); 117 RecordServerStats();
118 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
119 }
120
121 void DnsSession::UpdateTimeouts(NetworkChangeNotifier::ConnectionType type) {
122 initial_timeout_ = GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
123 "AsyncDnsInitialTimeoutMsByConnectionType", config_.timeout, type);
124 max_timeout_ = GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
125 "AsyncDnsMaxTimeoutMsByConnectionType",
126 base::TimeDelta::FromMilliseconds(kDefaultMaxTimeoutMs), type);
127 }
128
129 void DnsSession::InitializeServerStats() {
130 server_stats_.clear();
131 for (size_t i = 0; i < config_.nameservers.size(); ++i) {
132 server_stats_.push_back(make_scoped_ptr(
133 new ServerStats(initial_timeout_, rtt_buckets_.Pointer())));
134 }
135 }
136
137 void DnsSession::OnConnectionTypeChanged(
138 NetworkChangeNotifier::ConnectionType type) {
139 UpdateTimeouts(type);
140 const char* kTrialName = "AsyncDnsFlushServerStatsOnConnectionTypeChange";
141 if (base::FieldTrialList::FindFullName(kTrialName) == "enable") {
142 RecordServerStats();
143 InitializeServerStats();
144 }
111 } 145 }
112 146
113 uint16_t DnsSession::NextQueryId() const { 147 uint16_t DnsSession::NextQueryId() const {
114 return static_cast<uint16_t>(rand_callback_.Run()); 148 return static_cast<uint16_t>(rand_callback_.Run());
115 } 149 }
116 150
117 unsigned DnsSession::NextFirstServerIndex() { 151 unsigned DnsSession::NextFirstServerIndex() {
118 unsigned index = NextGoodServerIndex(server_index_); 152 unsigned index = NextGoodServerIndex(server_index_);
119 if (config_.rotate) 153 if (config_.rotate)
120 server_index_ = (server_index_ + 1) % config_.nameservers.size(); 154 server_index_ = (server_index_ + 1) % config_.nameservers.size();
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 } else { 250 } else {
217 UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresAfterSuccess", 251 UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresAfterSuccess",
218 server_stats_[index]->last_failure_count); 252 server_stats_[index]->last_failure_count);
219 } 253 }
220 } 254 }
221 } 255 }
222 } 256 }
223 257
224 258
225 base::TimeDelta DnsSession::NextTimeout(unsigned server_index, int attempt) { 259 base::TimeDelta DnsSession::NextTimeout(unsigned server_index, int attempt) {
226 // Respect config timeout if it exceeds |kMaxTimeoutMs|. 260 // Respect initial timeout (from config or field trial) if it exceeds max.
227 if (config_.timeout.InMilliseconds() >= kMaxTimeoutMs) 261 if (initial_timeout_ > max_timeout_)
228 return config_.timeout; 262 return initial_timeout_;
229 return NextTimeoutFromHistogram(server_index, attempt); 263 return NextTimeoutFromHistogram(server_index, attempt);
230 } 264 }
231 265
232 // Allocate a socket, already connected to the server address. 266 // Allocate a socket, already connected to the server address.
233 scoped_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket( 267 scoped_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket(
234 unsigned server_index, const NetLog::Source& source) { 268 unsigned server_index, const NetLog::Source& source) {
235 scoped_ptr<DatagramClientSocket> socket; 269 scoped_ptr<DatagramClientSocket> socket;
236 270
237 socket = socket_pool_->AllocateSocket(server_index); 271 socket = socket_pool_->AllocateSocket(server_index);
238 if (!socket.get()) 272 if (!socket.get())
(...skipping 26 matching lines...) Expand all
265 DCHECK_LT(server_index, server_stats_.size()); 299 DCHECK_LT(server_index, server_stats_.size());
266 300
267 base::TimeDelta timeout = server_stats_[server_index]->rtt_estimate + 301 base::TimeDelta timeout = server_stats_[server_index]->rtt_estimate +
268 4 * server_stats_[server_index]->rtt_deviation; 302 4 * server_stats_[server_index]->rtt_deviation;
269 303
270 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs)); 304 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs));
271 305
272 // The timeout doubles every full round. 306 // The timeout doubles every full round.
273 unsigned num_backoffs = attempt / config_.nameservers.size(); 307 unsigned num_backoffs = attempt / config_.nameservers.size();
274 308
275 return std::min(timeout * (1 << num_backoffs), 309 return std::min(timeout * (1 << num_backoffs), max_timeout_);
276 base::TimeDelta::FromMilliseconds(kMaxTimeoutMs));
277 } 310 }
278 311
279 base::TimeDelta DnsSession::NextTimeoutFromHistogram(unsigned server_index, 312 base::TimeDelta DnsSession::NextTimeoutFromHistogram(unsigned server_index,
280 int attempt) { 313 int attempt) {
281 DCHECK_LT(server_index, server_stats_.size()); 314 DCHECK_LT(server_index, server_stats_.size());
282 315
283 static_assert(std::numeric_limits<base::HistogramBase::Count>::is_signed, 316 static_assert(std::numeric_limits<base::HistogramBase::Count>::is_signed,
284 "histogram base count assumed to be signed"); 317 "histogram base count assumed to be signed");
285 318
286 // Use fixed percentile of observed samples. 319 // Use fixed percentile of observed samples.
287 const base::SampleVector& samples = 320 const base::SampleVector& samples =
288 *server_stats_[server_index]->rtt_histogram; 321 *server_stats_[server_index]->rtt_histogram;
289 322
290 base::HistogramBase::Count total = samples.TotalCount(); 323 base::HistogramBase::Count total = samples.TotalCount();
291 base::HistogramBase::Count remaining_count = kRTOPercentile * total / 100; 324 base::HistogramBase::Count remaining_count = kRTOPercentile * total / 100;
292 size_t index = 0; 325 size_t index = 0;
293 while (remaining_count > 0 && index < rtt_buckets_.Get().size()) { 326 while (remaining_count > 0 && index < rtt_buckets_.Get().size()) {
294 remaining_count -= samples.GetCountAtIndex(index); 327 remaining_count -= samples.GetCountAtIndex(index);
295 ++index; 328 ++index;
296 } 329 }
297 330
298 base::TimeDelta timeout = 331 base::TimeDelta timeout =
299 base::TimeDelta::FromMilliseconds(rtt_buckets_.Get().range(index)); 332 base::TimeDelta::FromMilliseconds(rtt_buckets_.Get().range(index));
300 333
301 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs)); 334 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs));
302 335
303 // The timeout still doubles every full round. 336 // The timeout still doubles every full round.
304 unsigned num_backoffs = attempt / config_.nameservers.size(); 337 unsigned num_backoffs = attempt / config_.nameservers.size();
305 338
306 return std::min(timeout * (1 << num_backoffs), 339 return std::min(timeout * (1 << num_backoffs), max_timeout_);
307 base::TimeDelta::FromMilliseconds(kMaxTimeoutMs));
308 } 340 }
309 341
310 } // namespace net 342 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_session.h ('k') | net/dns/dns_session_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698