From 45be8d87149b5a5de7e496b25b8c826868e12c92 Mon Sep 17 00:00:00 2001 From: "mef@chromium.org" Date: Thu, 23 May 2013 11:06:40 +0000 Subject: [net/dns] Measure performance of adaptive UDP timeout. Continuation of Szymon's work here: https://chromiumcodereview.appspot.com/12690019/. patch from issue 12690019 BUG=110197 Review URL: https://chromiumcodereview.appspot.com/15293009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@201747 0039d316-1c4b-4281-b951-d872f2087c98 --- net/dns/dns_transaction.cc | 108 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 18 deletions(-) (limited to 'net/dns/dns_transaction.cc') diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc index fdd2eb2..ea03502 100644 --- a/net/dns/dns_transaction.cc +++ b/net/dns/dns_transaction.cc @@ -73,6 +73,8 @@ Value* NetLogStartCallback(const std::string* hostname, // matches. Logging is done in the socket and in the outer DnsTransaction. class DnsAttempt { public: + DnsAttempt() : result_(ERR_FAILED) {} + virtual ~DnsAttempt() {} // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously // and calls |callback| upon completion. @@ -103,6 +105,25 @@ class DnsAttempt { GetSocketNetLog().source().AddToEventParameters(dict); return dict; } + + void set_result(int result) { + result_ = result; + } + + // True if current attempt is pending (waiting for server response). + bool is_pending() const { + return result_ == ERR_IO_PENDING; + } + + // True if attempt is completed (received server response). + bool is_completed() const { + return (result_ == OK) || (result_ == ERR_NAME_NOT_RESOLVED) || + (result_ == ERR_DNS_SERVER_REQUIRES_TCP); + } + + private: + // Result of last operation. + int result_; }; class DnsUDPAttempt : public DnsAttempt { @@ -178,6 +199,8 @@ class DnsUDPAttempt : public DnsAttempt { break; } } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); + + set_result(rv); // If we received a malformed response, and are now waiting for another one, // indicate to the transaction that the server might be misbehaving. if (rv == ERR_IO_PENDING && received_malformed_response_) @@ -196,9 +219,9 @@ class DnsUDPAttempt : public DnsAttempt { int DoSendQuery() { next_state_ = STATE_SEND_QUERY_COMPLETE; return socket()->Write(query_->io_buffer(), - query_->io_buffer()->size(), - base::Bind(&DnsUDPAttempt::OnIOComplete, - base::Unretained(this))); + query_->io_buffer()->size(), + base::Bind(&DnsUDPAttempt::OnIOComplete, + base::Unretained(this))); } int DoSendQueryComplete(int rv) { @@ -218,9 +241,9 @@ class DnsUDPAttempt : public DnsAttempt { next_state_ = STATE_READ_RESPONSE_COMPLETE; response_.reset(new DnsResponse()); return socket()->Read(response_->io_buffer(), - response_->io_buffer()->size(), - base::Bind(&DnsUDPAttempt::OnIOComplete, - base::Unretained(this))); + response_->io_buffer()->size(), + base::Bind(&DnsUDPAttempt::OnIOComplete, + base::Unretained(this))); } int DoReadResponseComplete(int rv) { @@ -272,9 +295,11 @@ class DnsUDPAttempt : public DnsAttempt { class DnsTCPAttempt : public DnsAttempt { public: - DnsTCPAttempt(scoped_ptr socket, + DnsTCPAttempt(unsigned server_index, + scoped_ptr socket, scoped_ptr query) : next_state_(STATE_NONE), + server_index_(server_index), socket_(socket.Pass()), query_(query.Pass()), length_buffer_(new IOBufferWithSize(sizeof(uint16))), @@ -289,8 +314,10 @@ class DnsTCPAttempt : public DnsAttempt { next_state_ = STATE_CONNECT_COMPLETE; int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); - if (rv == ERR_IO_PENDING) + if (rv == ERR_IO_PENDING) { + set_result(rv); return rv; + } return DoLoop(rv); } @@ -308,8 +335,7 @@ class DnsTCPAttempt : public DnsAttempt { } virtual unsigned GetServerIndex() const OVERRIDE { - NOTREACHED(); - return 0; + return server_index_; } private: @@ -349,6 +375,8 @@ class DnsTCPAttempt : public DnsAttempt { break; } } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); + + set_result(rv); if (rv == OK) { DCHECK_EQ(STATE_NONE, next_state_); DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess", @@ -467,6 +495,7 @@ class DnsTCPAttempt : public DnsAttempt { State next_state_; base::TimeTicks start_time_; + unsigned server_index_; scoped_ptr socket_; scoped_ptr query_; scoped_refptr length_buffer_; @@ -622,6 +651,7 @@ class DnsTransactionImpl : public DnsTransaction, CHECK(result.rv != OK || response != NULL); timer_.Stop(); + RecordLostPacketsIfAny(); if (response && qtype_ == dns_protocol::kTypeA) { UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size()); @@ -670,11 +700,13 @@ class DnsTransactionImpl : public DnsTransaction, NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, attempt->GetSocketNetLog().source().ToEventParametersCallback()); - int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete, - base::Unretained(this), - attempt_number)); + int rv = attempt->Start( + base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete, + base::Unretained(this), attempt_number, + base::TimeTicks::Now())); if (rv == ERR_IO_PENDING) { - base::TimeDelta timeout = session_->NextTimeout(attempt_number); + base::TimeDelta timeout = session_->NextTimeout(server_index, + attempt_number); timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); } return AttemptResult(rv, attempt); @@ -684,21 +716,24 @@ class DnsTransactionImpl : public DnsTransaction, DCHECK(previous_attempt); DCHECK(!had_tcp_attempt_); + unsigned server_index = previous_attempt->GetServerIndex(); + scoped_ptr socket( - session_->CreateTCPSocket(previous_attempt->GetServerIndex(), - net_log_.source())); + session_->CreateTCPSocket(server_index, net_log_.source())); // TODO(szym): Reuse the same id to help the server? uint16 id = session_->NextQueryId(); scoped_ptr query( previous_attempt->GetQuery()->CloneWithNewId(id)); + RecordLostPacketsIfAny(); // Cancel all other attempts, no point waiting on them. attempts_.clear(); unsigned attempt_number = attempts_.size(); - DnsTCPAttempt* attempt = new DnsTCPAttempt(socket.Pass(), query.Pass()); + DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(), + query.Pass()); attempts_.push_back(attempt); had_tcp_attempt_ = true; @@ -725,12 +760,24 @@ class DnsTransactionImpl : public DnsTransaction, NetLog::StringCallback("qname", &dotted_qname)); first_server_index_ = session_->NextFirstServerIndex(); - + RecordLostPacketsIfAny(); attempts_.clear(); had_tcp_attempt_ = false; return MakeAttempt(); } + void OnUdpAttemptComplete(unsigned attempt_number, + base::TimeTicks start, + int rv) { + DCHECK_LT(attempt_number, attempts_.size()); + const DnsAttempt* attempt = attempts_[attempt_number]; + if (attempt->GetResponse()) { + session_->RecordRTT(attempt->GetServerIndex(), + base::TimeTicks::Now() - start); + } + OnAttemptComplete(attempt_number, rv); + } + void OnAttemptComplete(unsigned attempt_number, int rv) { if (callback_.is_null()) return; @@ -741,6 +788,31 @@ class DnsTransactionImpl : public DnsTransaction, DoCallback(result); } + // Record packet loss for any incomplete attempts. + void RecordLostPacketsIfAny() { + // Loop through attempts until we find first that is completed + size_t first_completed = 0; + for (first_completed = 0; first_completed < attempts_.size(); + ++first_completed) { + if (attempts_[first_completed]->is_completed()) + break; + } + // If there were no completed attempts, then we must be offline, so don't + // record any attempts as lost packets. + if (first_completed == attempts_.size()) + return; + + std::vector num_rounds(session_->config().nameservers.size()); + for (size_t i = 0; i < first_completed; ++i) { + unsigned server_index = attempts_[i]->GetServerIndex(); + int server_round = num_rounds[server_index]++; + // Don't record lost packet unless attempt is in pending state. + if (!attempts_[i]->is_pending()) + continue; + session_->RecordLostPacket(server_index, server_round); + } + } + void LogResponse(const DnsAttempt* attempt) { if (attempt && attempt->GetResponse()) { net_log_.AddEvent( -- cgit v1.1