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

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: Response to comments Created 7 years, 4 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 949 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 960
961 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); 961 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob);
962 }; 962 };
963 963
964 //----------------------------------------------------------------------------- 964 //-----------------------------------------------------------------------------
965 965
966 // Resolves the hostname using DnsTransaction. 966 // Resolves the hostname using DnsTransaction.
967 // TODO(szym): This could be moved to separate source file as well. 967 // TODO(szym): This could be moved to separate source file as well.
968 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { 968 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
969 public: 969 public:
970 typedef base::Callback<void(int net_error, 970 class Delegate {
971 const AddressList& addr_list, 971 public:
972 base::TimeDelta ttl)> Callback; 972 virtual void OnDnsTaskComplete(base::TimeTicks start_time,
973 int net_error,
974 const AddressList& addr_list,
975 base::TimeDelta ttl) = 0;
976
977 // Called when the first of two jobs succeeds. If the first completed
978 // transaction fails, this is not called. Also not called when the DnsTask
979 // only needs to run one transaction.
980 virtual void OnFirstDnsTransactionComplete() = 0;
981
982 protected:
983 Delegate() {}
984 virtual ~Delegate() {}
985 };
973 986
974 DnsTask(DnsClient* client, 987 DnsTask(DnsClient* client,
975 const Key& key, 988 const Key& key,
976 const Callback& callback, 989 Delegate* delegate,
977 const BoundNetLog& job_net_log) 990 const BoundNetLog& job_net_log)
978 : client_(client), 991 : client_(client),
979 family_(key.address_family), 992 key_(key),
980 callback_(callback), 993 delegate_(delegate),
981 net_log_(job_net_log) { 994 net_log_(job_net_log),
995 num_completed_transactions_(0),
996 task_start_time_(base::TimeTicks::Now()) {
982 DCHECK(client); 997 DCHECK(client);
983 DCHECK(!callback.is_null()); 998 DCHECK(delegate_);
999 }
984 1000
985 // If unspecified, do IPv4 first, because suffix search will be faster. 1001 bool needs_two_transactions() const {
986 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ? 1002 return key_.address_family == ADDRESS_FAMILY_UNSPECIFIED;
987 dns_protocol::kTypeAAAA : 1003 }
988 dns_protocol::kTypeA; 1004
989 transaction_ = client_->GetTransactionFactory()->CreateTransaction( 1005 bool needs_another_transaction() const {
990 key.hostname, 1006 return needs_two_transactions() && !transaction_aaaa_;
991 qtype, 1007 }
1008
1009 void StartFirstTransaction() {
1010 DCHECK_EQ(0u, num_completed_transactions_);
1011 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
1012 if (key_.address_family == ADDRESS_FAMILY_IPV6) {
1013 StartAAAA();
1014 } else {
1015 StartA();
1016 }
1017 }
1018
1019 void StartSecondTransaction() {
1020 DCHECK(needs_two_transactions());
1021 StartAAAA();
1022 }
1023
1024 private:
1025 void StartA() {
1026 DCHECK(!transaction_a_);
1027 DCHECK_NE(ADDRESS_FAMILY_IPV6, key_.address_family);
1028 transaction_a_ = CreateTransaction(ADDRESS_FAMILY_IPV4);
1029 transaction_a_->Start();
1030 }
1031
1032 void StartAAAA() {
1033 DCHECK(!transaction_aaaa_);
1034 DCHECK_NE(ADDRESS_FAMILY_IPV4, key_.address_family);
1035 transaction_aaaa_ = CreateTransaction(ADDRESS_FAMILY_IPV6);
1036 transaction_aaaa_->Start();
1037 }
1038
1039 scoped_ptr<DnsTransaction> CreateTransaction(AddressFamily family) {
1040 DCHECK_NE(ADDRESS_FAMILY_UNSPECIFIED, family);
1041 return client_->GetTransactionFactory()->CreateTransaction(
1042 key_.hostname,
1043 family == ADDRESS_FAMILY_IPV6 ? dns_protocol::kTypeAAAA :
1044 dns_protocol::kTypeA,
992 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), 1045 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
993 true /* first_query */, base::TimeTicks::Now()), 1046 base::TimeTicks::Now()),
994 net_log_); 1047 net_log_);
995 } 1048 }
996 1049
997 void Start() { 1050 void OnTransactionComplete(const base::TimeTicks& start_time,
998 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
999 transaction_->Start();
1000 }
1001
1002 private:
1003 void OnTransactionComplete(bool first_query,
1004 const base::TimeTicks& start_time,
1005 DnsTransaction* transaction, 1051 DnsTransaction* transaction,
1006 int net_error, 1052 int net_error,
1007 const DnsResponse* response) { 1053 const DnsResponse* response) {
1008 DCHECK(transaction); 1054 DCHECK(transaction);
1009 base::TimeDelta duration = base::TimeTicks::Now() - start_time; 1055 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1010 // Run |callback_| last since the owning Job will then delete this DnsTask.
1011 if (net_error != OK) { 1056 if (net_error != OK) {
1012 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); 1057 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration);
1013 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); 1058 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1014 return; 1059 return;
1015 } 1060 }
1016 1061
1017 CHECK(response);
1018 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); 1062 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration);
1019 switch (transaction->GetType()) { 1063 switch (transaction->GetType()) {
1020 case dns_protocol::kTypeA: 1064 case dns_protocol::kTypeA:
1021 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); 1065 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration);
1022 break; 1066 break;
1023 case dns_protocol::kTypeAAAA: 1067 case dns_protocol::kTypeAAAA:
1024 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); 1068 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration);
1025 break; 1069 break;
1026 } 1070 }
1071
1027 AddressList addr_list; 1072 AddressList addr_list;
1028 base::TimeDelta ttl; 1073 base::TimeDelta ttl;
1029 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); 1074 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
1030 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", 1075 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1031 result, 1076 result,
1032 DnsResponse::DNS_PARSE_RESULT_MAX); 1077 DnsResponse::DNS_PARSE_RESULT_MAX);
1033 if (result != DnsResponse::DNS_PARSE_OK) { 1078 if (result != DnsResponse::DNS_PARSE_OK) {
1034 // Fail even if the other query succeeds. 1079 // Fail even if the other query succeeds.
1035 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); 1080 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result);
1036 return; 1081 return;
1037 } 1082 }
1038 1083
1039 bool needs_sort = false; 1084 ++num_completed_transactions_;
1040 if (first_query) { 1085 if (num_completed_transactions_ == 1) {
1041 DCHECK(client_->GetConfig()) << 1086 ttl_ = ttl;
1042 "Transaction should have been aborted when config changed!";
1043 if (family_ == ADDRESS_FAMILY_IPV6) {
1044 needs_sort = (addr_list.size() > 1);
1045 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1046 first_addr_list_ = addr_list;
1047 first_ttl_ = ttl;
1048 // Use fully-qualified domain name to avoid search.
1049 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1050 response->GetDottedName() + ".",
1051 dns_protocol::kTypeAAAA,
1052 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1053 false /* first_query */, base::TimeTicks::Now()),
1054 net_log_);
1055 transaction_->Start();
1056 return;
1057 }
1058 } else { 1087 } else {
1059 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_); 1088 ttl_ = std::min(ttl_, ttl);
1060 bool has_ipv6_addresses = !addr_list.empty();
1061 if (!first_addr_list_.empty()) {
1062 ttl = std::min(ttl, first_ttl_);
1063 // Place IPv4 addresses after IPv6.
1064 addr_list.insert(addr_list.end(), first_addr_list_.begin(),
1065 first_addr_list_.end());
1066 }
1067 needs_sort = (has_ipv6_addresses && addr_list.size() > 1);
1068 } 1089 }
1069 1090
1070 if (addr_list.empty()) { 1091 if (transaction->GetType() == dns_protocol::kTypeA) {
1071 // TODO(szym): Don't fallback to ProcTask in this case. 1092 DCHECK_EQ(transaction_a_.get(), transaction);
1072 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); 1093 // Place IPv4 addresses after IPv6.
1094 addr_list_.insert(addr_list_.end(), addr_list.begin(), addr_list.end());
1095 } else {
1096 DCHECK_EQ(transaction_aaaa_.get(), transaction);
1097 // Place IPv6 addresses before IPv4.
1098 addr_list_.insert(addr_list_.begin(), addr_list.begin(), addr_list.end());
1099 }
1100
1101 if (needs_two_transactions() && num_completed_transactions_ == 1) {
1102 // No need to repeat the suffix search.
1103 key_.hostname = transaction->GetHostname();
1104 delegate_->OnFirstDnsTransactionComplete();
1073 return; 1105 return;
1074 } 1106 }
1075 1107
1076 if (needs_sort) { 1108 // If there are multiple addresses, and at least one is IPv6, need to sort
1077 // Sort could complete synchronously. 1109 // them. Note that IPv6 addresses are always put before IPv4 ones, so it's
1110 // sufficient to just check the family of the first address.
1111 if (addr_list_.size() > 1 &&
1112 addr_list_[0].GetFamily() == ADDRESS_FAMILY_IPV6) {
1113 // Sort addresses if needed. Sort could complete synchronously.
1078 client_->GetAddressSorter()->Sort( 1114 client_->GetAddressSorter()->Sort(
1079 addr_list, 1115 addr_list_,
1080 base::Bind(&DnsTask::OnSortComplete, 1116 base::Bind(&DnsTask::OnSortComplete,
1081 AsWeakPtr(), 1117 AsWeakPtr(),
1082 base::TimeTicks::Now(), 1118 base::TimeTicks::Now()));
1083 ttl));
1084 } else { 1119 } else {
1085 OnSuccess(addr_list, ttl); 1120 OnSuccess(addr_list_);
1086 } 1121 }
1087 } 1122 }
1088 1123
1089 void OnSortComplete(base::TimeTicks start_time, 1124 void OnSortComplete(base::TimeTicks start_time,
1090 base::TimeDelta ttl,
1091 bool success, 1125 bool success,
1092 const AddressList& addr_list) { 1126 const AddressList& addr_list) {
1093 if (!success) { 1127 if (!success) {
1094 DNS_HISTOGRAM("AsyncDNS.SortFailure", 1128 DNS_HISTOGRAM("AsyncDNS.SortFailure",
1095 base::TimeTicks::Now() - start_time); 1129 base::TimeTicks::Now() - start_time);
1096 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); 1130 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK);
1097 return; 1131 return;
1098 } 1132 }
1099 1133
1100 DNS_HISTOGRAM("AsyncDNS.SortSuccess", 1134 DNS_HISTOGRAM("AsyncDNS.SortSuccess",
1101 base::TimeTicks::Now() - start_time); 1135 base::TimeTicks::Now() - start_time);
1102 1136
1103 // AddressSorter prunes unusable destinations. 1137 // AddressSorter prunes unusable destinations.
1104 if (addr_list.empty()) { 1138 if (addr_list.empty()) {
1105 LOG(WARNING) << "Address list empty after RFC3484 sort"; 1139 LOG(WARNING) << "Address list empty after RFC3484 sort";
1106 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); 1140 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1107 return; 1141 return;
1108 } 1142 }
1109 1143
1110 OnSuccess(addr_list, ttl); 1144 OnSuccess(addr_list);
1111 } 1145 }
1112 1146
1113 void OnFailure(int net_error, DnsResponse::Result result) { 1147 void OnFailure(int net_error, DnsResponse::Result result) {
1114 DCHECK_NE(OK, net_error); 1148 DCHECK_NE(OK, net_error);
1115 net_log_.EndEvent( 1149 net_log_.EndEvent(
1116 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1150 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1117 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); 1151 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
1118 callback_.Run(net_error, AddressList(), base::TimeDelta()); 1152 delegate_->OnDnsTaskComplete(task_start_time_, net_error, AddressList(),
1153 base::TimeDelta());
1119 } 1154 }
1120 1155
1121 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) { 1156 void OnSuccess(const AddressList& addr_list) {
1122 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1157 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1123 addr_list.CreateNetLogCallback()); 1158 addr_list.CreateNetLogCallback());
1124 callback_.Run(OK, addr_list, ttl); 1159 delegate_->OnDnsTaskComplete(task_start_time_, OK, addr_list, ttl_);
1125 } 1160 }
1126 1161
1127 DnsClient* client_; 1162 DnsClient* client_;
1128 AddressFamily family_; 1163 Key key_;
1164
1129 // The listener to the results of this DnsTask. 1165 // The listener to the results of this DnsTask.
1130 Callback callback_; 1166 Delegate* delegate_;
1131 const BoundNetLog net_log_; 1167 const BoundNetLog net_log_;
1132 1168
1133 scoped_ptr<DnsTransaction> transaction_; 1169 scoped_ptr<DnsTransaction> transaction_a_;
1170 scoped_ptr<DnsTransaction> transaction_aaaa_;
1134 1171
1135 // Results from the first transaction. Used only if |family_| is unspecified. 1172 unsigned num_completed_transactions_;
1136 AddressList first_addr_list_; 1173
1137 base::TimeDelta first_ttl_; 1174 // These are updated as each transaction completes.
1175 base::TimeDelta ttl_;
1176 // IPv6 addresses must appear first in the list.
1177 AddressList addr_list_;
1178
1179 base::TimeTicks task_start_time_;
1138 1180
1139 DISALLOW_COPY_AND_ASSIGN(DnsTask); 1181 DISALLOW_COPY_AND_ASSIGN(DnsTask);
1140 }; 1182 };
1141 1183
1142 //----------------------------------------------------------------------------- 1184 //-----------------------------------------------------------------------------
1143 1185
1144 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. 1186 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
1145 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { 1187 class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
1188 public HostResolverImpl::DnsTask::Delegate {
1146 public: 1189 public:
1147 // Creates new job for |key| where |request_net_log| is bound to the 1190 // Creates new job for |key| where |request_net_log| is bound to the
1148 // request that spawned it. 1191 // request that spawned it.
1149 Job(const base::WeakPtr<HostResolverImpl>& resolver, 1192 Job(const base::WeakPtr<HostResolverImpl>& resolver,
1150 const Key& key, 1193 const Key& key,
1151 RequestPriority priority, 1194 RequestPriority priority,
1152 const BoundNetLog& request_net_log) 1195 const BoundNetLog& request_net_log)
1153 : resolver_(resolver), 1196 : resolver_(resolver),
1154 key_(key), 1197 key_(key),
1155 priority_tracker_(priority), 1198 priority_tracker_(priority),
1156 had_non_speculative_request_(false), 1199 had_non_speculative_request_(false),
1157 had_dns_config_(false), 1200 had_dns_config_(false),
1201 num_occupied_job_slots_(0),
1158 dns_task_error_(OK), 1202 dns_task_error_(OK),
1159 creation_time_(base::TimeTicks::Now()), 1203 creation_time_(base::TimeTicks::Now()),
1160 priority_change_time_(creation_time_), 1204 priority_change_time_(creation_time_),
1161 net_log_(BoundNetLog::Make(request_net_log.net_log(), 1205 net_log_(BoundNetLog::Make(request_net_log.net_log(),
1162 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { 1206 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
1163 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); 1207 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
1164 1208
1165 net_log_.BeginEvent( 1209 net_log_.BeginEvent(
1166 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, 1210 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1167 base::Bind(&NetLogJobCreationCallback, 1211 base::Bind(&NetLogJobCreationCallback,
1168 request_net_log.source(), 1212 request_net_log.source(),
1169 &key_.hostname)); 1213 &key_.hostname));
1170 } 1214 }
1171 1215
1172 virtual ~Job() { 1216 virtual ~Job() {
1173 if (is_running()) { 1217 if (is_running()) {
1174 // |resolver_| was destroyed with this Job still in flight. 1218 // |resolver_| was destroyed with this Job still in flight.
1175 // Clean-up, record in the log, but don't run any callbacks. 1219 // Clean-up, record in the log, but don't run any callbacks.
1176 if (is_proc_running()) { 1220 if (is_proc_running()) {
1177 proc_task_->Cancel(); 1221 proc_task_->Cancel();
1178 proc_task_ = NULL; 1222 proc_task_ = NULL;
1179 } 1223 }
1180 // Clean up now for nice NetLog. 1224 // Clean up now for nice NetLog.
1181 dns_task_.reset(NULL); 1225 KillDnsTask();
1182 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, 1226 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1183 ERR_ABORTED); 1227 ERR_ABORTED);
1184 } else if (is_queued()) { 1228 } else if (is_queued()) {
1185 // |resolver_| was destroyed without running this Job. 1229 // |resolver_| was destroyed without running this Job.
1186 // TODO(szym): is there any benefit in having this distinction? 1230 // TODO(szym): is there any benefit in having this distinction?
1187 net_log_.AddEvent(NetLog::TYPE_CANCELLED); 1231 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1188 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); 1232 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
1189 } 1233 }
1190 // else CompleteRequests logged EndEvent. 1234 // else CompleteRequests logged EndEvent.
1191 1235
1192 // Log any remaining Requests as cancelled. 1236 // Log any remaining Requests as cancelled.
1193 for (RequestsList::const_iterator it = requests_.begin(); 1237 for (RequestsList::const_iterator it = requests_.begin();
1194 it != requests_.end(); ++it) { 1238 it != requests_.end(); ++it) {
1195 Request* req = *it; 1239 Request* req = *it;
1196 if (req->was_canceled()) 1240 if (req->was_canceled())
1197 continue; 1241 continue;
1198 DCHECK_EQ(this, req->job()); 1242 DCHECK_EQ(this, req->job());
1199 LogCancelRequest(req->source_net_log(), req->request_net_log(), 1243 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1200 req->info()); 1244 req->info());
1201 } 1245 }
1202 } 1246 }
1203 1247
1204 // Add this job to the dispatcher. 1248 // Add this job to the dispatcher. If "at_head" is true, adds at the front
1205 void Schedule() { 1249 // of the queue.
1206 handle_ = resolver_->dispatcher_.Add(this, priority()); 1250 void Schedule(bool at_head) {
1251 DCHECK(!is_queued());
1252 PrioritizedDispatcher::Handle handle;
1253 if (!at_head) {
1254 handle = resolver_->dispatcher_.Add(this, priority());
1255 } else {
1256 handle = resolver_->dispatcher_.AddAtHead(this, priority());
1257 }
1258 // The dispatcher could have started |this| in the above call to Add, which
1259 // could have called Schedule again. In that case |handle| will be null,
1260 // but |handle_| may have been set by the other nested call to Schedule.
1261 if (!handle.is_null()) {
1262 DCHECK(handle_.is_null());
1263 handle_ = handle;
1264 }
1207 } 1265 }
1208 1266
1209 void AddRequest(scoped_ptr<Request> req) { 1267 void AddRequest(scoped_ptr<Request> req) {
1210 DCHECK_EQ(key_.hostname, req->info().hostname()); 1268 DCHECK_EQ(key_.hostname, req->info().hostname());
1211 1269
1212 req->set_job(this); 1270 req->set_job(this);
1213 priority_tracker_.Add(req->info().priority()); 1271 priority_tracker_.Add(req->info().priority());
1214 1272
1215 req->request_net_log().AddEvent( 1273 req->request_net_log().AddEvent(
1216 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, 1274 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1265 // Called from AbortAllInProgressJobs. Completes all requests and destroys 1323 // Called from AbortAllInProgressJobs. Completes all requests and destroys
1266 // the job. This currently assumes the abort is due to a network change. 1324 // the job. This currently assumes the abort is due to a network change.
1267 void Abort() { 1325 void Abort() {
1268 DCHECK(is_running()); 1326 DCHECK(is_running());
1269 CompleteRequestsWithError(ERR_NETWORK_CHANGED); 1327 CompleteRequestsWithError(ERR_NETWORK_CHANGED);
1270 } 1328 }
1271 1329
1272 // If DnsTask present, abort it and fall back to ProcTask. 1330 // If DnsTask present, abort it and fall back to ProcTask.
1273 void AbortDnsTask() { 1331 void AbortDnsTask() {
1274 if (dns_task_) { 1332 if (dns_task_) {
1275 dns_task_.reset(); 1333 KillDnsTask();
1276 dns_task_error_ = OK; 1334 dns_task_error_ = OK;
1277 StartProcTask(); 1335 StartProcTask();
1278 } 1336 }
1279 } 1337 }
1280 1338
1281 // Called by HostResolverImpl when this job is evicted due to queue overflow. 1339 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1282 // Completes all requests and destroys the job. 1340 // Completes all requests and destroys the job.
1283 void OnEvicted() { 1341 void OnEvicted() {
1284 DCHECK(!is_running()); 1342 DCHECK(!is_running());
1285 DCHECK(is_queued()); 1343 DCHECK(is_queued());
(...skipping 28 matching lines...) Expand all
1314 1372
1315 bool is_queued() const { 1373 bool is_queued() const {
1316 return !handle_.is_null(); 1374 return !handle_.is_null();
1317 } 1375 }
1318 1376
1319 bool is_running() const { 1377 bool is_running() const {
1320 return is_dns_running() || is_proc_running(); 1378 return is_dns_running() || is_proc_running();
1321 } 1379 }
1322 1380
1323 private: 1381 private:
1382 void KillDnsTask() {
1383 if (dns_task_) {
1384 ReduceToOneJobSlot();
1385 dns_task_.reset();
1386 }
1387 }
1388
1389 // Reduce the number of job slots occupied and queued in the dispatcher
1390 // to one. If the second Job slot is queued in the dispatcher, cancels the
1391 // queued job. Otherwise, the second Job was been started by the
szym 2013/08/19 18:47:21 nit: was -> has
mmenke 2013/08/19 19:31:33 Done
1392 // PriorityizedDispatcher, so signals it is complete.
szym 2013/08/19 18:47:21 nit: Prioritized
mmenke 2013/08/19 19:31:33 Done
1393 void ReduceToOneJobSlot() {
1394 DCHECK_GE(num_occupied_job_slots_, 1u);
1395 if (is_queued()) {
1396 resolver_->dispatcher_.Cancel(handle_);
1397 handle_.Reset();
1398 } else if (num_occupied_job_slots_ > 1) {
1399 resolver_->dispatcher_.OnJobFinished();
1400 --num_occupied_job_slots_;
1401 }
1402 DCHECK_EQ(1u, num_occupied_job_slots_);
1403 }
1404
1324 void UpdatePriority() { 1405 void UpdatePriority() {
1325 if (is_queued()) { 1406 if (is_queued()) {
1326 if (priority() != static_cast<RequestPriority>(handle_.priority())) 1407 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1327 priority_change_time_ = base::TimeTicks::Now(); 1408 priority_change_time_ = base::TimeTicks::Now();
1328 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); 1409 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1329 } 1410 }
1330 } 1411 }
1331 1412
1332 AddressList MakeAddressListForRequest(const AddressList& list) const { 1413 AddressList MakeAddressListForRequest(const AddressList& list) const {
1333 if (requests_.empty()) 1414 if (requests_.empty())
1334 return list; 1415 return list;
1335 return AddressList::CopyWithPort(list, requests_.front()->info().port()); 1416 return AddressList::CopyWithPort(list, requests_.front()->info().port());
1336 } 1417 }
1337 1418
1338 // PriorityDispatch::Job: 1419 // PriorityDispatch::Job:
1339 virtual void Start() OVERRIDE { 1420 virtual void Start() OVERRIDE {
1421 DCHECK_LE(num_occupied_job_slots_, 1u);
1422
1423 handle_.Reset();
1424 ++num_occupied_job_slots_;
1425
1426 if (num_occupied_job_slots_ == 2) {
1427 StartSecondDnsTransaction();
1428 return;
1429 }
1430
1340 DCHECK(!is_running()); 1431 DCHECK(!is_running());
1341 handle_.Reset();
1342 1432
1343 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); 1433 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
1344 1434
1345 had_dns_config_ = resolver_->HaveDnsConfig(); 1435 had_dns_config_ = resolver_->HaveDnsConfig();
1346 1436
1347 base::TimeTicks now = base::TimeTicks::Now(); 1437 base::TimeTicks now = base::TimeTicks::Now();
1348 base::TimeDelta queue_time = now - creation_time_; 1438 base::TimeDelta queue_time = now - creation_time_;
1349 base::TimeDelta queue_time_after_change = now - priority_change_time_; 1439 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1350 1440
1351 if (had_dns_config_) { 1441 if (had_dns_config_) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1435 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); 1525 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
1436 1526
1437 // Don't store the |ttl| in cache since it's not obtained from the server. 1527 // Don't store the |ttl| in cache since it's not obtained from the server.
1438 CompleteRequests( 1528 CompleteRequests(
1439 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), 1529 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)),
1440 ttl); 1530 ttl);
1441 } 1531 }
1442 1532
1443 void StartDnsTask() { 1533 void StartDnsTask() {
1444 DCHECK(resolver_->HaveDnsConfig()); 1534 DCHECK(resolver_->HaveDnsConfig());
1445 base::TimeTicks start_time = base::TimeTicks::Now(); 1535 dns_task_.reset(new DnsTask(resolver_->dns_client_.get(), key_, this,
1446 dns_task_.reset(new DnsTask( 1536 net_log_));
1447 resolver_->dns_client_.get(),
1448 key_,
1449 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), start_time),
1450 net_log_));
1451 1537
1452 dns_task_->Start(); 1538 dns_task_->StartFirstTransaction();
1539 // Schedule a second transaction, if needed.
1540 if (dns_task_->needs_two_transactions())
1541 Schedule(true);
1542 }
1543
1544 void StartSecondDnsTransaction() {
1545 DCHECK(dns_task_->needs_two_transactions());
1546 dns_task_->StartSecondTransaction();
1453 } 1547 }
1454 1548
1455 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be 1549 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
1456 // deleted before this callback. In this case dns_task is deleted as well, 1550 // deleted before this callback. In this case dns_task is deleted as well,
1457 // so we use it as indicator whether Job is still valid. 1551 // so we use it as indicator whether Job is still valid.
1458 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task, 1552 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task,
1459 base::TimeDelta duration, 1553 base::TimeDelta duration,
1460 int net_error) { 1554 int net_error) {
1461 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); 1555 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
1462 1556
1463 if (dns_task == NULL) 1557 if (dns_task == NULL)
1464 return; 1558 return;
1465 1559
1466 dns_task_error_ = net_error; 1560 dns_task_error_ = net_error;
1467 1561
1468 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. 1562 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1469 // http://crbug.com/117655 1563 // http://crbug.com/117655
1470 1564
1471 // TODO(szym): Some net errors indicate lack of connectivity. Starting 1565 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1472 // ProcTask in that case is a waste of time. 1566 // ProcTask in that case is a waste of time.
1473 if (resolver_->fallback_to_proctask_) { 1567 if (resolver_->fallback_to_proctask_) {
1474 dns_task_.reset(); 1568 KillDnsTask();
1475 StartProcTask(); 1569 StartProcTask();
1476 } else { 1570 } else {
1477 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); 1571 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1478 CompleteRequestsWithError(net_error); 1572 CompleteRequestsWithError(net_error);
1479 } 1573 }
1480 } 1574 }
1481 1575
1482 // Called by DnsTask when it completes. 1576
1483 void OnDnsTaskComplete(base::TimeTicks start_time, 1577 // HostResolverImpl::DnsTask::Delegate implementation:
1484 int net_error, 1578
1485 const AddressList& addr_list, 1579 virtual void OnDnsTaskComplete(base::TimeTicks start_time,
1486 base::TimeDelta ttl) { 1580 int net_error,
1581 const AddressList& addr_list,
1582 base::TimeDelta ttl) OVERRIDE {
1487 DCHECK(is_dns_running()); 1583 DCHECK(is_dns_running());
1488 1584
1489 base::TimeDelta duration = base::TimeTicks::Now() - start_time; 1585 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1490 if (net_error != OK) { 1586 if (net_error != OK) {
1491 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error); 1587 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error);
1492 return; 1588 return;
1493 } 1589 }
1494 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); 1590 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration);
1495 // Log DNS lookups based on |address_family|. 1591 // Log DNS lookups based on |address_family|.
1496 switch(key_.address_family) { 1592 switch(key_.address_family) {
(...skipping 14 matching lines...) Expand all
1511 resolver_->OnDnsTaskResolve(OK); 1607 resolver_->OnDnsTaskResolve(OK);
1512 1608
1513 base::TimeDelta bounded_ttl = 1609 base::TimeDelta bounded_ttl =
1514 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); 1610 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds));
1515 1611
1516 CompleteRequests( 1612 CompleteRequests(
1517 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), 1613 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl),
1518 bounded_ttl); 1614 bounded_ttl);
1519 } 1615 }
1520 1616
1617 virtual void OnFirstDnsTransactionComplete() OVERRIDE {
1618 DCHECK(dns_task_->needs_two_transactions());
1619 DCHECK_EQ(dns_task_->needs_another_transaction(), is_queued());
1620 // No longer need to occupy two dispatcher slots.
1621 ReduceToOneJobSlot();
1622
1623 // We already have a job slot at the dispatcher, so if the second
1624 // transaction hasn't started, reuse it now instead of waiting in the queue
1625 // for the second slot.
1626 if (dns_task_->needs_another_transaction())
1627 dns_task_->StartSecondTransaction();
1628 }
1629
1521 // Performs Job's last rites. Completes all Requests. Deletes this. 1630 // Performs Job's last rites. Completes all Requests. Deletes this.
1522 void CompleteRequests(const HostCache::Entry& entry, 1631 void CompleteRequests(const HostCache::Entry& entry,
1523 base::TimeDelta ttl) { 1632 base::TimeDelta ttl) {
1524 CHECK(resolver_.get()); 1633 CHECK(resolver_.get());
1525 1634
1526 // This job must be removed from resolver's |jobs_| now to make room for a 1635 // This job must be removed from resolver's |jobs_| now to make room for a
1527 // new job with the same key in case one of the OnComplete callbacks decides 1636 // new job with the same key in case one of the OnComplete callbacks decides
1528 // to spawn one. Consequently, the job deletes itself when CompleteRequests 1637 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1529 // is done. 1638 // is done.
1530 scoped_ptr<Job> self_deleter(this); 1639 scoped_ptr<Job> self_deleter(this);
1531 1640
1532 resolver_->RemoveJob(this); 1641 resolver_->RemoveJob(this);
1533 1642
1534 if (is_running()) { 1643 if (is_running()) {
1535 DCHECK(!is_queued());
1536 if (is_proc_running()) { 1644 if (is_proc_running()) {
1645 DCHECK(!is_queued());
1537 proc_task_->Cancel(); 1646 proc_task_->Cancel();
1538 proc_task_ = NULL; 1647 proc_task_ = NULL;
1539 } 1648 }
1540 dns_task_.reset(); 1649 KillDnsTask();
1541 1650
1542 // Signal dispatcher that a slot has opened. 1651 // Signal dispatcher that a slot has opened.
1543 resolver_->dispatcher_.OnJobFinished(); 1652 resolver_->dispatcher_.OnJobFinished();
1544 } else if (is_queued()) { 1653 } else if (is_queued()) {
1545 resolver_->dispatcher_.Cancel(handle_); 1654 resolver_->dispatcher_.Cancel(handle_);
1546 handle_.Reset(); 1655 handle_.Reset();
1547 } 1656 }
1548 1657
1549 if (num_active_requests() == 0) { 1658 if (num_active_requests() == 0) {
1550 net_log_.AddEvent(NetLog::TYPE_CANCELLED); 1659 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1624 Key key_; 1733 Key key_;
1625 1734
1626 // Tracks the highest priority across |requests_|. 1735 // Tracks the highest priority across |requests_|.
1627 PriorityTracker priority_tracker_; 1736 PriorityTracker priority_tracker_;
1628 1737
1629 bool had_non_speculative_request_; 1738 bool had_non_speculative_request_;
1630 1739
1631 // Distinguishes measurements taken while DnsClient was fully configured. 1740 // Distinguishes measurements taken while DnsClient was fully configured.
1632 bool had_dns_config_; 1741 bool had_dns_config_;
1633 1742
1743 // Number of slots occupied by this Job in resolver's PrioritizedDispatcher.
1744 unsigned num_occupied_job_slots_;
1745
1634 // Result of DnsTask. 1746 // Result of DnsTask.
1635 int dns_task_error_; 1747 int dns_task_error_;
1636 1748
1637 const base::TimeTicks creation_time_; 1749 const base::TimeTicks creation_time_;
1638 base::TimeTicks priority_change_time_; 1750 base::TimeTicks priority_change_time_;
1639 1751
1640 BoundNetLog net_log_; 1752 BoundNetLog net_log_;
1641 1753
1642 // Resolves the host using a HostResolverProc. 1754 // Resolves the host using a HostResolverProc.
1643 scoped_refptr<ProcTask> proc_task_; 1755 scoped_refptr<ProcTask> proc_task_;
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1763 } 1875 }
1764 1876
1765 // Next we need to attach our request to a "job". This job is responsible for 1877 // Next we need to attach our request to a "job". This job is responsible for
1766 // calling "getaddrinfo(hostname)" on a worker thread. 1878 // calling "getaddrinfo(hostname)" on a worker thread.
1767 1879
1768 JobMap::iterator jobit = jobs_.find(key); 1880 JobMap::iterator jobit = jobs_.find(key);
1769 Job* job; 1881 Job* job;
1770 if (jobit == jobs_.end()) { 1882 if (jobit == jobs_.end()) {
1771 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(), 1883 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(),
1772 request_net_log); 1884 request_net_log);
1773 job->Schedule(); 1885 job->Schedule(false);
1774 1886
1775 // Check for queue overflow. 1887 // Check for queue overflow.
1776 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { 1888 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1777 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); 1889 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1778 DCHECK(evicted); 1890 DCHECK(evicted);
1779 evicted->OnEvicted(); // Deletes |evicted|. 1891 evicted->OnEvicted(); // Deletes |evicted|.
1780 if (evicted == job) { 1892 if (evicted == job) {
1781 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; 1893 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1782 LogFinishRequest(source_net_log, request_net_log, info, rv); 1894 LogFinishRequest(source_net_log, request_net_log, info, rv);
1783 return rv; 1895 return rv;
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
2063 Job* job = it->second; 2175 Job* job = it->second;
2064 if (job->is_running()) { 2176 if (job->is_running()) {
2065 jobs_to_abort.push_back(job); 2177 jobs_to_abort.push_back(job);
2066 jobs_.erase(it++); 2178 jobs_.erase(it++);
2067 } else { 2179 } else {
2068 DCHECK(job->is_queued()); 2180 DCHECK(job->is_queued());
2069 ++it; 2181 ++it;
2070 } 2182 }
2071 } 2183 }
2072 2184
2073 // Check if no dispatcher slots leaked out.
2074 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
2075
2076 // Life check to bail once |this| is deleted. 2185 // Life check to bail once |this| is deleted.
2077 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); 2186 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
2078 2187
2079 // Then Abort them. 2188 // Then Abort them.
2080 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) { 2189 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) {
2081 jobs_to_abort[i]->Abort(); 2190 jobs_to_abort[i]->Abort();
2082 jobs_to_abort[i] = NULL; 2191 jobs_to_abort[i] = NULL;
2083 } 2192 }
2084 } 2193 }
2085 2194
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
2197 } 2306 }
2198 DnsConfig dns_config; 2307 DnsConfig dns_config;
2199 NetworkChangeNotifier::GetDnsConfig(&dns_config); 2308 NetworkChangeNotifier::GetDnsConfig(&dns_config);
2200 dns_client_->SetConfig(dns_config); 2309 dns_client_->SetConfig(dns_config);
2201 num_dns_failures_ = 0; 2310 num_dns_failures_ = 0;
2202 if (dns_config.IsValid()) 2311 if (dns_config.IsValid())
2203 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); 2312 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
2204 } 2313 }
2205 2314
2206 } // namespace net 2315 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698