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

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

Issue 19498003: [net/dns] Perform A/AAAA queries for AF_UNSPEC resolutions in parallel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Add space Created 7 years, 5 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 | Annotate | Revision Log
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/host_resolver_impl.h" 5 #include "net/dns/host_resolver_impl.h"
6 6
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <Winsock2.h> 8 #include <Winsock2.h>
9 #elif defined(OS_POSIX) 9 #elif defined(OS_POSIX)
10 #include <netdb.h> 10 #include <netdb.h>
(...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 959
960 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); 960 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob);
961 }; 961 };
962 962
963 //----------------------------------------------------------------------------- 963 //-----------------------------------------------------------------------------
964 964
965 // Resolves the hostname using DnsTransaction. 965 // Resolves the hostname using DnsTransaction.
966 // TODO(szym): This could be moved to separate source file as well. 966 // TODO(szym): This could be moved to separate source file as well.
967 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { 967 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
968 public: 968 public:
969 typedef base::Callback<void(int net_error, 969 class Delegate {
970 const AddressList& addr_list, 970 public:
971 base::TimeDelta ttl)> Callback; 971 virtual void OnDnsTaskComplete(base::TimeTicks start_time,
972 int net_error,
973 const AddressList& addr_list,
974 base::TimeDelta ttl) = 0;
975
976 // Called when the first of two jobs succeeds. If the first completed
977 // transaction fails, this is not called. Also not called when the DnsTask
978 // only needs to run one transaction.
979 virtual void OnFirstDnsTransactionComplete() = 0;
980
981 protected:
982 Delegate() {}
983 virtual ~Delegate() {}
984 };
972 985
973 DnsTask(DnsClient* client, 986 DnsTask(DnsClient* client,
974 const Key& key, 987 const Key& key,
975 const Callback& callback, 988 Delegate* delegate,
976 const BoundNetLog& job_net_log) 989 const BoundNetLog& job_net_log)
977 : client_(client), 990 : client_(client),
978 family_(key.address_family), 991 key_(key),
979 callback_(callback), 992 delegate_(delegate),
980 net_log_(job_net_log) { 993 net_log_(job_net_log),
994 num_completed_transactions_(0),
995 task_start_time_(base::TimeTicks::Now()) {
981 DCHECK(client); 996 DCHECK(client);
982 DCHECK(!callback.is_null()); 997 DCHECK(delegate_);
998 }
983 999
984 // If unspecified, do IPv4 first, because suffix search will be faster. 1000 bool needs_two_transactions() const {
985 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ? 1001 return key_.address_family == ADDRESS_FAMILY_UNSPECIFIED;
986 dns_protocol::kTypeAAAA : 1002 }
987 dns_protocol::kTypeA; 1003
988 transaction_ = client_->GetTransactionFactory()->CreateTransaction( 1004 void StartFirstTransaction() {
989 key.hostname, 1005 DCHECK_EQ(0u, num_completed_transactions_);
990 qtype, 1006 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
1007 if (key_.address_family == ADDRESS_FAMILY_IPV6) {
1008 StartAAAA();
1009 } else {
1010 StartA();
1011 }
1012 }
1013
1014 void StartSecondTransaction() {
1015 DCHECK(needs_two_transactions());
1016 StartAAAA();
1017 }
1018
1019 private:
1020 void StartA() {
1021 DCHECK(!transaction_a_);
1022 DCHECK_NE(ADDRESS_FAMILY_IPV6, key_.address_family);
1023 transaction_a_ = CreateTransaction(ADDRESS_FAMILY_IPV4);
1024 transaction_a_->Start();
1025 }
1026
1027 void StartAAAA() {
1028 DCHECK(!transaction_aaaa_);
1029 DCHECK_NE(ADDRESS_FAMILY_IPV4, key_.address_family);
1030 transaction_aaaa_ = CreateTransaction(ADDRESS_FAMILY_IPV6);
1031 transaction_aaaa_->Start();
1032 }
1033
1034 scoped_ptr<DnsTransaction> CreateTransaction(AddressFamily family) {
1035 DCHECK_NE(ADDRESS_FAMILY_UNSPECIFIED, family);
1036 return client_->GetTransactionFactory()->CreateTransaction(
1037 key_.hostname,
1038 family == ADDRESS_FAMILY_IPV6 ? dns_protocol::kTypeAAAA :
1039 dns_protocol::kTypeA,
991 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), 1040 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
992 true /* first_query */, base::TimeTicks::Now()), 1041 base::TimeTicks::Now()),
993 net_log_); 1042 net_log_);
994 } 1043 }
995 1044
996 void Start() { 1045 void OnTransactionComplete(const base::TimeTicks& start_time,
997 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
998 transaction_->Start();
999 }
1000
1001 private:
1002 void OnTransactionComplete(bool first_query,
1003 const base::TimeTicks& start_time,
1004 DnsTransaction* transaction, 1046 DnsTransaction* transaction,
1005 int net_error, 1047 int net_error,
1006 const DnsResponse* response) { 1048 const DnsResponse* response) {
1007 DCHECK(transaction); 1049 DCHECK(transaction);
1008 base::TimeDelta duration = base::TimeTicks::Now() - start_time; 1050 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1009 // Run |callback_| last since the owning Job will then delete this DnsTask.
1010 if (net_error != OK) { 1051 if (net_error != OK) {
1011 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); 1052 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration);
1012 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); 1053 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1013 return; 1054 return;
1014 } 1055 }
1015 1056
1016 CHECK(response);
1017 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); 1057 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration);
1018 switch (transaction->GetType()) { 1058 switch (transaction->GetType()) {
1019 case dns_protocol::kTypeA: 1059 case dns_protocol::kTypeA:
1020 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); 1060 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration);
1021 break; 1061 break;
1022 case dns_protocol::kTypeAAAA: 1062 case dns_protocol::kTypeAAAA:
1023 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); 1063 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration);
1024 break; 1064 break;
1025 } 1065 }
1066
1026 AddressList addr_list; 1067 AddressList addr_list;
1027 base::TimeDelta ttl; 1068 base::TimeDelta ttl;
1028 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); 1069 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
1029 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", 1070 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1030 result, 1071 result,
1031 DnsResponse::DNS_PARSE_RESULT_MAX); 1072 DnsResponse::DNS_PARSE_RESULT_MAX);
1032 if (result != DnsResponse::DNS_PARSE_OK) { 1073 if (result != DnsResponse::DNS_PARSE_OK) {
1033 // Fail even if the other query succeeds. 1074 // Fail even if the other query succeeds.
1034 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); 1075 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result);
1035 return; 1076 return;
1036 } 1077 }
1037 1078
1038 bool needs_sort = false; 1079 ++num_completed_transactions_;
1039 if (first_query) { 1080 if (num_completed_transactions_ == 1) {
1040 DCHECK(client_->GetConfig()) << 1081 ttl_ = ttl;
1041 "Transaction should have been aborted when config changed!";
1042 if (family_ == ADDRESS_FAMILY_IPV6) {
1043 needs_sort = (addr_list.size() > 1);
1044 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1045 first_addr_list_ = addr_list;
1046 first_ttl_ = ttl;
1047 // Use fully-qualified domain name to avoid search.
1048 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1049 response->GetDottedName() + ".",
1050 dns_protocol::kTypeAAAA,
1051 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1052 false /* first_query */, base::TimeTicks::Now()),
1053 net_log_);
1054 transaction_->Start();
1055 return;
1056 }
1057 } else { 1082 } else {
1058 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_); 1083 ttl_ = std::min(ttl_, ttl);
1059 bool has_ipv6_addresses = !addr_list.empty();
1060 if (!first_addr_list_.empty()) {
1061 ttl = std::min(ttl, first_ttl_);
1062 // Place IPv4 addresses after IPv6.
1063 addr_list.insert(addr_list.end(), first_addr_list_.begin(),
1064 first_addr_list_.end());
1065 }
1066 needs_sort = (has_ipv6_addresses && addr_list.size() > 1);
1067 } 1084 }
1068 1085
1069 if (addr_list.empty()) { 1086 if (transaction->GetType() == dns_protocol::kTypeA) {
1070 // TODO(szym): Don't fallback to ProcTask in this case. 1087 DCHECK_EQ(transaction_a_.get(), transaction);
1071 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); 1088 // Place IPv4 addresses after IPv6.
1089 addr_list_.insert(addr_list_.end(), addr_list.begin(), addr_list.end());
1090 } else {
1091 DCHECK_EQ(transaction_aaaa_.get(), transaction);
1092 // Place IPv6 addresses before IPv4.
1093 addr_list_.insert(addr_list_.begin(), addr_list.begin(), addr_list.end());
1094 }
1095
1096 if (needs_two_transactions() && num_completed_transactions_ == 1) {
szym 2013/08/06 20:35:31 At this point we could also set key_.hostname = tr
mmenke 2013/08/19 17:31:11 Done. Wonder how difficult it would be to make a
1097 delegate_->OnFirstDnsTransactionComplete();
1072 return; 1098 return;
1073 } 1099 }
1074 1100
1075 if (needs_sort) { 1101 // If there are multiple addresses, and at least one is IPv6, need to sort
1076 // Sort could complete synchronously. 1102 // them. Note that IPv6 addresses are always put before IPv4 ones, so it's
1103 // sufficient to just check the family of the first address.
1104 if (addr_list_.size() > 1 &&
1105 addr_list_[0].GetFamily() == ADDRESS_FAMILY_IPV6) {
1106 // Sort addresses if needed. Sort could complete synchronously.
1077 client_->GetAddressSorter()->Sort( 1107 client_->GetAddressSorter()->Sort(
1078 addr_list, 1108 addr_list_,
1079 base::Bind(&DnsTask::OnSortComplete, 1109 base::Bind(&DnsTask::OnSortComplete,
1080 AsWeakPtr(), 1110 AsWeakPtr(),
1081 base::TimeTicks::Now(), 1111 base::TimeTicks::Now()));
1082 ttl));
1083 } else { 1112 } else {
1084 OnSuccess(addr_list, ttl); 1113 OnSuccess(addr_list_);
1085 } 1114 }
1086 } 1115 }
1087 1116
1088 void OnSortComplete(base::TimeTicks start_time, 1117 void OnSortComplete(base::TimeTicks start_time,
1089 base::TimeDelta ttl,
1090 bool success, 1118 bool success,
1091 const AddressList& addr_list) { 1119 const AddressList& addr_list) {
1092 if (!success) { 1120 if (!success) {
1093 DNS_HISTOGRAM("AsyncDNS.SortFailure", 1121 DNS_HISTOGRAM("AsyncDNS.SortFailure",
1094 base::TimeTicks::Now() - start_time); 1122 base::TimeTicks::Now() - start_time);
1095 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); 1123 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK);
1096 return; 1124 return;
1097 } 1125 }
1098 1126
1099 DNS_HISTOGRAM("AsyncDNS.SortSuccess", 1127 DNS_HISTOGRAM("AsyncDNS.SortSuccess",
1100 base::TimeTicks::Now() - start_time); 1128 base::TimeTicks::Now() - start_time);
1101 1129
1102 // AddressSorter prunes unusable destinations. 1130 // AddressSorter prunes unusable destinations.
1103 if (addr_list.empty()) { 1131 if (addr_list.empty()) {
1104 LOG(WARNING) << "Address list empty after RFC3484 sort"; 1132 LOG(WARNING) << "Address list empty after RFC3484 sort";
1105 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); 1133 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1106 return; 1134 return;
1107 } 1135 }
1108 1136
1109 OnSuccess(addr_list, ttl); 1137 OnSuccess(addr_list);
1110 } 1138 }
1111 1139
1112 void OnFailure(int net_error, DnsResponse::Result result) { 1140 void OnFailure(int net_error, DnsResponse::Result result) {
1113 DCHECK_NE(OK, net_error); 1141 DCHECK_NE(OK, net_error);
1114 net_log_.EndEvent( 1142 net_log_.EndEvent(
1115 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1143 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1116 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); 1144 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
1117 callback_.Run(net_error, AddressList(), base::TimeDelta()); 1145 delegate_->OnDnsTaskComplete(task_start_time_, net_error, AddressList(),
1146 base::TimeDelta());
1118 } 1147 }
1119 1148
1120 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) { 1149 void OnSuccess(const AddressList& addr_list) {
1121 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1150 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1122 addr_list.CreateNetLogCallback()); 1151 addr_list.CreateNetLogCallback());
1123 callback_.Run(OK, addr_list, ttl); 1152 delegate_->OnDnsTaskComplete(task_start_time_, OK, addr_list, ttl_);
1124 } 1153 }
1125 1154
1126 DnsClient* client_; 1155 DnsClient* client_;
1127 AddressFamily family_; 1156 Key key_;
1157
1128 // The listener to the results of this DnsTask. 1158 // The listener to the results of this DnsTask.
1129 Callback callback_; 1159 Delegate* delegate_;
1130 const BoundNetLog net_log_; 1160 const BoundNetLog net_log_;
1131 1161
1132 scoped_ptr<DnsTransaction> transaction_; 1162 scoped_ptr<DnsTransaction> transaction_a_;
1163 scoped_ptr<DnsTransaction> transaction_aaaa_;
1133 1164
1134 // Results from the first transaction. Used only if |family_| is unspecified. 1165 // Number of transactions that have started, but not yet completed.
szym 2013/08/06 20:35:31 The name of the variable is in direct conflict wit
mmenke 2013/08/19 17:31:11 Done.
1135 AddressList first_addr_list_; 1166 unsigned num_completed_transactions_;
1136 base::TimeDelta first_ttl_; 1167
1168 // These are updated as each transaction completes.
1169 base::TimeDelta ttl_;
1170 // IPv6 addresses must appear first in the list.
1171 AddressList addr_list_;
1172
1173 base::TimeTicks task_start_time_;
1137 1174
1138 DISALLOW_COPY_AND_ASSIGN(DnsTask); 1175 DISALLOW_COPY_AND_ASSIGN(DnsTask);
1139 }; 1176 };
1140 1177
1141 //----------------------------------------------------------------------------- 1178 //-----------------------------------------------------------------------------
1142 1179
1143 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. 1180 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
1144 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { 1181 class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
1182 public HostResolverImpl::DnsTask::Delegate {
1145 public: 1183 public:
1146 // Creates new job for |key| where |request_net_log| is bound to the 1184 // Creates new job for |key| where |request_net_log| is bound to the
1147 // request that spawned it. 1185 // request that spawned it.
1148 Job(const base::WeakPtr<HostResolverImpl>& resolver, 1186 Job(const base::WeakPtr<HostResolverImpl>& resolver,
1149 const Key& key, 1187 const Key& key,
1150 RequestPriority priority, 1188 RequestPriority priority,
1151 const BoundNetLog& request_net_log) 1189 const BoundNetLog& request_net_log)
1152 : resolver_(resolver), 1190 : resolver_(resolver),
1153 key_(key), 1191 key_(key),
1154 priority_tracker_(priority), 1192 priority_tracker_(priority),
1155 had_non_speculative_request_(false), 1193 had_non_speculative_request_(false),
1156 had_dns_config_(false), 1194 had_dns_config_(false),
1195 num_occupied_job_slots_(0),
1157 dns_task_error_(OK), 1196 dns_task_error_(OK),
1158 creation_time_(base::TimeTicks::Now()), 1197 creation_time_(base::TimeTicks::Now()),
1159 priority_change_time_(creation_time_), 1198 priority_change_time_(creation_time_),
1160 net_log_(BoundNetLog::Make(request_net_log.net_log(), 1199 net_log_(BoundNetLog::Make(request_net_log.net_log(),
1161 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { 1200 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
1162 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); 1201 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
1163 1202
1164 net_log_.BeginEvent( 1203 net_log_.BeginEvent(
1165 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, 1204 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1166 base::Bind(&NetLogJobCreationCallback, 1205 base::Bind(&NetLogJobCreationCallback,
1167 request_net_log.source(), 1206 request_net_log.source(),
1168 &key_.hostname)); 1207 &key_.hostname));
1169 } 1208 }
1170 1209
1171 virtual ~Job() { 1210 virtual ~Job() {
1172 if (is_running()) { 1211 if (is_running()) {
1173 // |resolver_| was destroyed with this Job still in flight. 1212 // |resolver_| was destroyed with this Job still in flight.
1174 // Clean-up, record in the log, but don't run any callbacks. 1213 // Clean-up, record in the log, but don't run any callbacks.
1175 if (is_proc_running()) { 1214 if (is_proc_running()) {
1176 proc_task_->Cancel(); 1215 proc_task_->Cancel();
1177 proc_task_ = NULL; 1216 proc_task_ = NULL;
1178 } 1217 }
1179 // Clean up now for nice NetLog. 1218 // Clean up now for nice NetLog.
1180 dns_task_.reset(NULL); 1219 KillDnsTask();
szym 2013/08/06 20:35:31 I suggest leave it as is. Job is destroyed while r
mmenke 2013/08/19 17:31:11 I'm not comfortable relying on that being true - i
szym 2013/08/19 18:47:21 I understand the sentiment. My major concern is an
mmenke 2013/08/19 19:31:33 I don't think performance is a huge concern, since
szym 2013/08/19 19:46:45 I wasn't clear. I am suggesting going with your co
mmenke 2013/08/19 19:57:40 That causes problems in the other case... When Re
szym 2013/08/19 20:00:41 Well, then how about PrioritizedDispatcher::Disabl
mmenke 2013/08/19 20:41:12 Done. That was what I meant by my PrepareToDie()
1181 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, 1220 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1182 ERR_ABORTED); 1221 ERR_ABORTED);
1183 } else if (is_queued()) { 1222 } else if (is_queued()) {
1184 // |resolver_| was destroyed without running this Job. 1223 // |resolver_| was destroyed without running this Job.
1185 // TODO(szym): is there any benefit in having this distinction? 1224 // TODO(szym): is there any benefit in having this distinction?
1186 net_log_.AddEvent(NetLog::TYPE_CANCELLED); 1225 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1187 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); 1226 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
1188 } 1227 }
1189 // else CompleteRequests logged EndEvent. 1228 // else CompleteRequests logged EndEvent.
1190 1229
1191 // Log any remaining Requests as cancelled. 1230 // Log any remaining Requests as cancelled.
1192 for (RequestsList::const_iterator it = requests_.begin(); 1231 for (RequestsList::const_iterator it = requests_.begin();
1193 it != requests_.end(); ++it) { 1232 it != requests_.end(); ++it) {
1194 Request* req = *it; 1233 Request* req = *it;
1195 if (req->was_canceled()) 1234 if (req->was_canceled())
1196 continue; 1235 continue;
1197 DCHECK_EQ(this, req->job()); 1236 DCHECK_EQ(this, req->job());
1198 LogCancelRequest(req->source_net_log(), req->request_net_log(), 1237 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1199 req->info()); 1238 req->info());
1200 } 1239 }
1201 } 1240 }
1202 1241
1203 // Add this job to the dispatcher. 1242 // Add this job to the dispatcher. If "at_head" is true, adds at the front
1204 void Schedule() { 1243 // of the queue.
1205 handle_ = resolver_->dispatcher_.Add(this, priority()); 1244 void Schedule(bool at_head) {
1245 DCHECK(!is_queued());
1246 PrioritizedDispatcher::Handle handle;
1247 if (!at_head) {
1248 handle = resolver_->dispatcher_.Add(this, priority());
1249 } else {
1250 handle = resolver_->dispatcher_.AddAtHead(this, priority());
1251 }
1252 // This test is needed for the case that the dispatcher starts |this|
1253 // synchronously, and then |this| adds itself again to the dispatcher,
1254 // and the second attempt does not complete synchronously.
szym 2013/08/06 20:35:31 "attempt" is ambiguous. Suggest: "The dispatcher c
mmenke 2013/08/19 17:31:11 Done (With some slight rewording).
1255 if (!handle.is_null()) {
1256 DCHECK(handle_.is_null());
1257 handle_ = handle;
1258 }
1206 } 1259 }
1207 1260
1208 void AddRequest(scoped_ptr<Request> req) { 1261 void AddRequest(scoped_ptr<Request> req) {
1209 DCHECK_EQ(key_.hostname, req->info().hostname()); 1262 DCHECK_EQ(key_.hostname, req->info().hostname());
1210 1263
1211 req->set_job(this); 1264 req->set_job(this);
1212 priority_tracker_.Add(req->info().priority()); 1265 priority_tracker_.Add(req->info().priority());
1213 1266
1214 req->request_net_log().AddEvent( 1267 req->request_net_log().AddEvent(
1215 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, 1268 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1264 // Called from AbortAllInProgressJobs. Completes all requests and destroys 1317 // Called from AbortAllInProgressJobs. Completes all requests and destroys
1265 // the job. This currently assumes the abort is due to a network change. 1318 // the job. This currently assumes the abort is due to a network change.
1266 void Abort() { 1319 void Abort() {
1267 DCHECK(is_running()); 1320 DCHECK(is_running());
1268 CompleteRequestsWithError(ERR_NETWORK_CHANGED); 1321 CompleteRequestsWithError(ERR_NETWORK_CHANGED);
1269 } 1322 }
1270 1323
1271 // If DnsTask present, abort it and fall back to ProcTask. 1324 // If DnsTask present, abort it and fall back to ProcTask.
1272 void AbortDnsTask() { 1325 void AbortDnsTask() {
1273 if (dns_task_) { 1326 if (dns_task_) {
1274 dns_task_.reset(); 1327 KillDnsTask();
1275 dns_task_error_ = OK; 1328 dns_task_error_ = OK;
1276 StartProcTask(); 1329 StartProcTask();
1277 } 1330 }
1278 } 1331 }
1279 1332
1280 // Called by HostResolverImpl when this job is evicted due to queue overflow. 1333 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1281 // Completes all requests and destroys the job. 1334 // Completes all requests and destroys the job.
1282 void OnEvicted() { 1335 void OnEvicted() {
1283 DCHECK(!is_running()); 1336 DCHECK(!is_running());
1284 DCHECK(is_queued()); 1337 DCHECK(is_queued());
(...skipping 28 matching lines...) Expand all
1313 1366
1314 bool is_queued() const { 1367 bool is_queued() const {
1315 return !handle_.is_null(); 1368 return !handle_.is_null();
1316 } 1369 }
1317 1370
1318 bool is_running() const { 1371 bool is_running() const {
1319 return is_dns_running() || is_proc_running(); 1372 return is_dns_running() || is_proc_running();
1320 } 1373 }
1321 1374
1322 private: 1375 private:
1376 void KillDnsTask() {
1377 if (dns_task_) {
1378 FinishOrCancelSecondDispatcherJob();
1379 dns_task_.reset();
1380 }
1381 }
1382
1383 // If this task is occupying two slots in the PrioritizedDispatcher, cancels
1384 // or finishes the second Job, depending on if its started or not. Otherwise,
1385 // does nothing.
1386 void FinishOrCancelSecondDispatcherJob() {
szym 2013/08/06 20:35:31 I've spent a lot of time trying to make it more ob
mmenke 2013/08/19 17:31:11 Done, though I changed the comment (What "let" mea
1387 DCHECK_GE(num_occupied_job_slots_, 1u);
1388 if (num_occupied_job_slots_ > 1) {
1389 DCHECK(dns_task_->needs_two_transactions());
1390 resolver_->dispatcher_.OnJobFinished();
1391 --num_occupied_job_slots_;
1392 } else if (is_queued()) {
1393 resolver_->dispatcher_.Cancel(handle_);
1394 handle_.Reset();
1395 }
1396 DCHECK_EQ(1u, num_occupied_job_slots_);
1397 }
1398
1323 void UpdatePriority() { 1399 void UpdatePriority() {
1324 if (is_queued()) { 1400 if (is_queued()) {
1325 if (priority() != static_cast<RequestPriority>(handle_.priority())) 1401 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1326 priority_change_time_ = base::TimeTicks::Now(); 1402 priority_change_time_ = base::TimeTicks::Now();
1327 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); 1403 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1328 } 1404 }
1329 } 1405 }
1330 1406
1331 AddressList MakeAddressListForRequest(const AddressList& list) const { 1407 AddressList MakeAddressListForRequest(const AddressList& list) const {
1332 if (requests_.empty()) 1408 if (requests_.empty())
1333 return list; 1409 return list;
1334 return AddressList::CopyWithPort(list, requests_.front()->info().port()); 1410 return AddressList::CopyWithPort(list, requests_.front()->info().port());
1335 } 1411 }
1336 1412
1337 // PriorityDispatch::Job: 1413 // PriorityDispatch::Job:
1338 virtual void Start() OVERRIDE { 1414 virtual void Start() OVERRIDE {
1415 DCHECK_LE(num_occupied_job_slots_, 1u);
1416
1417 handle_.Reset();
1418 ++num_occupied_job_slots_;
1419
1420 if (num_occupied_job_slots_ == 2) {
1421 StartSecondDnsTransaction();
1422 return;
1423 }
1424
1339 DCHECK(!is_running()); 1425 DCHECK(!is_running());
1340 handle_.Reset();
1341 1426
1342 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); 1427 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
1343 1428
1344 had_dns_config_ = resolver_->HaveDnsConfig(); 1429 had_dns_config_ = resolver_->HaveDnsConfig();
1345 1430
1346 base::TimeTicks now = base::TimeTicks::Now(); 1431 base::TimeTicks now = base::TimeTicks::Now();
1347 base::TimeDelta queue_time = now - creation_time_; 1432 base::TimeDelta queue_time = now - creation_time_;
1348 base::TimeDelta queue_time_after_change = now - priority_change_time_; 1433 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1349 1434
1350 if (had_dns_config_) { 1435 if (had_dns_config_) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1432 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); 1517 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
1433 1518
1434 // Don't store the |ttl| in cache since it's not obtained from the server. 1519 // Don't store the |ttl| in cache since it's not obtained from the server.
1435 CompleteRequests( 1520 CompleteRequests(
1436 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), 1521 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)),
1437 ttl); 1522 ttl);
1438 } 1523 }
1439 1524
1440 void StartDnsTask() { 1525 void StartDnsTask() {
1441 DCHECK(resolver_->HaveDnsConfig()); 1526 DCHECK(resolver_->HaveDnsConfig());
1442 base::TimeTicks start_time = base::TimeTicks::Now(); 1527 dns_task_.reset(new DnsTask(resolver_->dns_client_.get(), key_, this,
1443 dns_task_.reset(new DnsTask( 1528 net_log_));
1444 resolver_->dns_client_.get(),
1445 key_,
1446 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), start_time),
1447 net_log_));
1448 1529
1449 dns_task_->Start(); 1530 dns_task_->StartFirstTransaction();
1531 // Schedule a second transaciton, if needed.
szym 2013/08/06 20:35:31 nit: transaction
mmenke 2013/08/19 17:31:11 Done.
1532 if (dns_task_->needs_two_transactions())
1533 Schedule(true);
1534 }
1535
1536 void StartSecondDnsTransaction() {
1537 DCHECK(dns_task_->needs_two_transactions());
1538 dns_task_->StartSecondTransaction();
1450 } 1539 }
1451 1540
1452 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be 1541 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
1453 // deleted before this callback. In this case dns_task is deleted as well, 1542 // deleted before this callback. In this case dns_task is deleted as well,
1454 // so we use it as indicator whether Job is still valid. 1543 // so we use it as indicator whether Job is still valid.
1455 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task, 1544 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task,
1456 base::TimeDelta duration, 1545 base::TimeDelta duration,
1457 int net_error) { 1546 int net_error) {
1458 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); 1547 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
1459 1548
1460 if (dns_task == NULL) 1549 if (dns_task == NULL)
1461 return; 1550 return;
1462 1551
1463 dns_task_error_ = net_error; 1552 dns_task_error_ = net_error;
1464 1553
1465 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. 1554 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1466 // http://crbug.com/117655 1555 // http://crbug.com/117655
1467 1556
1468 // TODO(szym): Some net errors indicate lack of connectivity. Starting 1557 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1469 // ProcTask in that case is a waste of time. 1558 // ProcTask in that case is a waste of time.
1470 if (resolver_->fallback_to_proctask_) { 1559 if (resolver_->fallback_to_proctask_) {
1471 dns_task_.reset(); 1560 KillDnsTask();
1472 StartProcTask(); 1561 StartProcTask();
1473 } else { 1562 } else {
1474 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); 1563 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1475 CompleteRequestsWithError(net_error); 1564 CompleteRequestsWithError(net_error);
1476 } 1565 }
1477 } 1566 }
1478 1567
1479 // Called by DnsTask when it completes. 1568
1480 void OnDnsTaskComplete(base::TimeTicks start_time, 1569 // HostResolverImpl::DnsTask::Delegate implementation:
1481 int net_error, 1570
1482 const AddressList& addr_list, 1571 virtual void OnDnsTaskComplete(base::TimeTicks start_time,
1483 base::TimeDelta ttl) { 1572 int net_error,
1573 const AddressList& addr_list,
1574 base::TimeDelta ttl) OVERRIDE {
1484 DCHECK(is_dns_running()); 1575 DCHECK(is_dns_running());
1485 1576
1486 base::TimeDelta duration = base::TimeTicks::Now() - start_time; 1577 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1487 if (net_error != OK) { 1578 if (net_error != OK) {
1488 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error); 1579 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error);
1489 return; 1580 return;
1490 } 1581 }
1491 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); 1582 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration);
1492 // Log DNS lookups based on |address_family|. 1583 // Log DNS lookups based on |address_family|.
1493 switch(key_.address_family) { 1584 switch(key_.address_family) {
(...skipping 14 matching lines...) Expand all
1508 resolver_->OnDnsTaskResolve(OK); 1599 resolver_->OnDnsTaskResolve(OK);
1509 1600
1510 base::TimeDelta bounded_ttl = 1601 base::TimeDelta bounded_ttl =
1511 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); 1602 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds));
1512 1603
1513 CompleteRequests( 1604 CompleteRequests(
1514 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), 1605 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl),
1515 bounded_ttl); 1606 bounded_ttl);
1516 } 1607 }
1517 1608
1609 virtual void OnFirstDnsTransactionComplete() OVERRIDE {
1610 DCHECK(dns_task_->needs_two_transactions());
1611 // If the second job is still queued, start it now.
szym 2013/08/06 20:35:31 "Second job" is a bit confusing. Suggest further e
mmenke 2013/08/19 17:31:11 Done (Comment slightly modified).
1612 if (is_queued())
1613 dns_task_->StartSecondTransaction();
1614 FinishOrCancelSecondDispatcherJob();
szym 2013/08/06 20:35:31 If we already started both jobs, then we are actua
mmenke 2013/08/19 17:31:11 Done.
1615 }
1616
1518 // Performs Job's last rites. Completes all Requests. Deletes this. 1617 // Performs Job's last rites. Completes all Requests. Deletes this.
1519 void CompleteRequests(const HostCache::Entry& entry, 1618 void CompleteRequests(const HostCache::Entry& entry,
1520 base::TimeDelta ttl) { 1619 base::TimeDelta ttl) {
1521 CHECK(resolver_.get()); 1620 CHECK(resolver_.get());
1522 1621
1523 // This job must be removed from resolver's |jobs_| now to make room for a 1622 // This job must be removed from resolver's |jobs_| now to make room for a
1524 // new job with the same key in case one of the OnComplete callbacks decides 1623 // new job with the same key in case one of the OnComplete callbacks decides
1525 // to spawn one. Consequently, the job deletes itself when CompleteRequests 1624 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1526 // is done. 1625 // is done.
1527 scoped_ptr<Job> self_deleter(this); 1626 scoped_ptr<Job> self_deleter(this);
1528 1627
1529 resolver_->RemoveJob(this); 1628 resolver_->RemoveJob(this);
1530 1629
1531 if (is_running()) { 1630 if (is_running()) {
1532 DCHECK(!is_queued());
1533 if (is_proc_running()) { 1631 if (is_proc_running()) {
1632 DCHECK(!is_queued());
1534 proc_task_->Cancel(); 1633 proc_task_->Cancel();
1535 proc_task_ = NULL; 1634 proc_task_ = NULL;
1536 } 1635 }
1537 dns_task_.reset(); 1636 KillDnsTask();
1538 1637
1539 // Signal dispatcher that a slot has opened. 1638 // Signal dispatcher that a slot has opened.
1540 resolver_->dispatcher_.OnJobFinished(); 1639 resolver_->dispatcher_.OnJobFinished();
1541 } else if (is_queued()) { 1640 } else if (is_queued()) {
1542 resolver_->dispatcher_.Cancel(handle_); 1641 resolver_->dispatcher_.Cancel(handle_);
1543 handle_.Reset(); 1642 handle_.Reset();
1544 } 1643 }
1545 1644
1546 if (num_active_requests() == 0) { 1645 if (num_active_requests() == 0) {
1547 net_log_.AddEvent(NetLog::TYPE_CANCELLED); 1646 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1621 Key key_; 1720 Key key_;
1622 1721
1623 // Tracks the highest priority across |requests_|. 1722 // Tracks the highest priority across |requests_|.
1624 PriorityTracker priority_tracker_; 1723 PriorityTracker priority_tracker_;
1625 1724
1626 bool had_non_speculative_request_; 1725 bool had_non_speculative_request_;
1627 1726
1628 // Distinguishes measurements taken while DnsClient was fully configured. 1727 // Distinguishes measurements taken while DnsClient was fully configured.
1629 bool had_dns_config_; 1728 bool had_dns_config_;
1630 1729
1730 // Number of slots occupied by this Job in resolver's PrioritizedDispatcher.
1731 unsigned num_occupied_job_slots_;
1732
1631 // Result of DnsTask. 1733 // Result of DnsTask.
1632 int dns_task_error_; 1734 int dns_task_error_;
1633 1735
1634 const base::TimeTicks creation_time_; 1736 const base::TimeTicks creation_time_;
1635 base::TimeTicks priority_change_time_; 1737 base::TimeTicks priority_change_time_;
1636 1738
1637 BoundNetLog net_log_; 1739 BoundNetLog net_log_;
1638 1740
1639 // Resolves the host using a HostResolverProc. 1741 // Resolves the host using a HostResolverProc.
1640 scoped_refptr<ProcTask> proc_task_; 1742 scoped_refptr<ProcTask> proc_task_;
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1760 } 1862 }
1761 1863
1762 // Next we need to attach our request to a "job". This job is responsible for 1864 // Next we need to attach our request to a "job". This job is responsible for
1763 // calling "getaddrinfo(hostname)" on a worker thread. 1865 // calling "getaddrinfo(hostname)" on a worker thread.
1764 1866
1765 JobMap::iterator jobit = jobs_.find(key); 1867 JobMap::iterator jobit = jobs_.find(key);
1766 Job* job; 1868 Job* job;
1767 if (jobit == jobs_.end()) { 1869 if (jobit == jobs_.end()) {
1768 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(), 1870 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(),
1769 request_net_log); 1871 request_net_log);
1770 job->Schedule(); 1872 job->Schedule(false);
1771 1873
1772 // Check for queue overflow. 1874 // Check for queue overflow.
1773 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { 1875 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1774 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); 1876 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1775 DCHECK(evicted); 1877 DCHECK(evicted);
1776 evicted->OnEvicted(); // Deletes |evicted|. 1878 evicted->OnEvicted(); // Deletes |evicted|.
1777 if (evicted == job) { 1879 if (evicted == job) {
1778 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; 1880 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1779 LogFinishRequest(source_net_log, request_net_log, info, rv); 1881 LogFinishRequest(source_net_log, request_net_log, info, rv);
1780 return rv; 1882 return rv;
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
2058 Job* job = it->second; 2160 Job* job = it->second;
2059 if (job->is_running()) { 2161 if (job->is_running()) {
2060 jobs_to_abort.push_back(job); 2162 jobs_to_abort.push_back(job);
2061 jobs_.erase(it++); 2163 jobs_.erase(it++);
2062 } else { 2164 } else {
2063 DCHECK(job->is_queued()); 2165 DCHECK(job->is_queued());
2064 ++it; 2166 ++it;
2065 } 2167 }
2066 } 2168 }
2067 2169
2068 // Check if no dispatcher slots leaked out.
2069 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
2070
2071 // Life check to bail once |this| is deleted. 2170 // Life check to bail once |this| is deleted.
2072 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); 2171 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
2073 2172
2074 // Then Abort them. 2173 // Then Abort them.
2075 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) { 2174 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) {
2076 jobs_to_abort[i]->Abort(); 2175 jobs_to_abort[i]->Abort();
2077 jobs_to_abort[i] = NULL; 2176 jobs_to_abort[i] = NULL;
2078 } 2177 }
2079 } 2178 }
2080 2179
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
2192 } 2291 }
2193 DnsConfig dns_config; 2292 DnsConfig dns_config;
2194 NetworkChangeNotifier::GetDnsConfig(&dns_config); 2293 NetworkChangeNotifier::GetDnsConfig(&dns_config);
2195 dns_client_->SetConfig(dns_config); 2294 dns_client_->SetConfig(dns_config);
2196 num_dns_failures_ = 0; 2295 num_dns_failures_ = 0;
2197 if (dns_config.IsValid()) 2296 if (dns_config.IsValid())
2198 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); 2297 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
2199 } 2298 }
2200 2299
2201 } // namespace net 2300 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698