OLD | NEW |
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/base/host_resolver_impl.h" | 5 #include "net/base/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> |
11 #endif | 11 #endif |
12 | 12 |
13 #include <cmath> | 13 #include <cmath> |
14 #include <deque> | 14 #include <utility> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include "base/basictypes.h" | 17 #include "base/basictypes.h" |
18 #include "base/bind.h" | 18 #include "base/bind.h" |
19 #include "base/bind_helpers.h" | 19 #include "base/bind_helpers.h" |
| 20 #include "base/callback.h" |
20 #include "base/compiler_specific.h" | 21 #include "base/compiler_specific.h" |
21 #include "base/debug/debugger.h" | 22 #include "base/debug/debugger.h" |
22 #include "base/debug/stack_trace.h" | 23 #include "base/debug/stack_trace.h" |
23 #include "base/message_loop_proxy.h" | 24 #include "base/message_loop_proxy.h" |
24 #include "base/metrics/field_trial.h" | 25 #include "base/metrics/field_trial.h" |
25 #include "base/metrics/histogram.h" | 26 #include "base/metrics/histogram.h" |
26 #include "base/stl_util.h" | 27 #include "base/stl_util.h" |
27 #include "base/string_util.h" | 28 #include "base/string_util.h" |
28 #include "base/threading/worker_pool.h" | 29 #include "base/threading/worker_pool.h" |
29 #include "base/time.h" | 30 #include "base/time.h" |
(...skipping 16 matching lines...) Expand all Loading... |
46 | 47 |
47 namespace { | 48 namespace { |
48 | 49 |
49 // Limit the size of hostnames that will be resolved to combat issues in | 50 // Limit the size of hostnames that will be resolved to combat issues in |
50 // some platform's resolvers. | 51 // some platform's resolvers. |
51 const size_t kMaxHostLength = 4096; | 52 const size_t kMaxHostLength = 4096; |
52 | 53 |
53 // Default TTL for successful resolutions with ProcTask. | 54 // Default TTL for successful resolutions with ProcTask. |
54 const unsigned kCacheEntryTTLSeconds = 60; | 55 const unsigned kCacheEntryTTLSeconds = 60; |
55 | 56 |
| 57 // Maximum of 8 concurrent resolver threads (excluding retries). |
| 58 // Some routers (or resolvers) appear to start to provide host-not-found if |
| 59 // too many simultaneous resolutions are pending. This number needs to be |
| 60 // further optimized, but 8 is what FF currently does. |
| 61 static const size_t kDefaultMaxProcTasks = 8u; |
| 62 |
56 // Helper to mutate the linked list contained by AddressList to the given | 63 // Helper to mutate the linked list contained by AddressList to the given |
57 // port. Note that in general this is dangerous since the AddressList's | 64 // port. Note that in general this is dangerous since the AddressList's |
58 // data might be shared (and you should use AddressList::SetPort). | 65 // data might be shared (and you should use AddressList::SetPort). |
59 // | 66 // |
60 // However since we allocated the AddressList ourselves we can safely | 67 // However since we allocated the AddressList ourselves we can safely |
61 // do this optimization and avoid reallocating the list. | 68 // do this optimization and avoid reallocating the list. |
62 void MutableSetPort(int port, AddressList* addrlist) { | 69 void MutableSetPort(int port, AddressList* addrlist) { |
63 struct addrinfo* mutable_head = | 70 struct addrinfo* mutable_head = |
64 const_cast<struct addrinfo*>(addrlist->head()); | 71 const_cast<struct addrinfo*>(addrlist->head()); |
65 SetPortForAllAddrinfos(mutable_head, port); | 72 SetPortForAllAddrinfos(mutable_head, port); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 | 129 |
123 // Ensure all errors are positive, as histogram only tracks positive values. | 130 // Ensure all errors are positive, as histogram only tracks positive values. |
124 for (size_t i = 0; i < arraysize(os_errors); ++i) { | 131 for (size_t i = 0; i < arraysize(os_errors); ++i) { |
125 os_errors[i] = std::abs(os_errors[i]); | 132 os_errors[i] = std::abs(os_errors[i]); |
126 } | 133 } |
127 | 134 |
128 return base::CustomHistogram::ArrayToCustomRanges(os_errors, | 135 return base::CustomHistogram::ArrayToCustomRanges(os_errors, |
129 arraysize(os_errors)); | 136 arraysize(os_errors)); |
130 } | 137 } |
131 | 138 |
132 } // anonymous namespace | 139 // Wraps call to SystemHostResolverProc as an instance of HostResolverProc. |
133 | 140 // TODO(szym): This should probably be declared in host_resolver_proc.h. |
134 // static | 141 class CallSystemHostResolverProc : public HostResolverProc { |
135 HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves, | 142 public: |
136 size_t max_retry_attempts, | 143 CallSystemHostResolverProc() : HostResolverProc(NULL) {} |
137 NetLog* net_log) { | 144 virtual int Resolve(const std::string& hostname, |
138 // Maximum of 8 concurrent resolver threads. | 145 AddressFamily address_family, |
139 // Some routers (or resolvers) appear to start to provide host-not-found if | 146 HostResolverFlags host_resolver_flags, |
140 // too many simultaneous resolutions are pending. This number needs to be | 147 AddressList* addrlist, |
141 // further optimized, but 8 is what FF currently does. | 148 int* os_error) OVERRIDE { |
142 static const size_t kDefaultMaxJobs = 8u; | 149 return SystemHostResolverProc(hostname, |
143 | 150 address_family, |
144 if (max_concurrent_resolves == HostResolver::kDefaultParallelism) | 151 host_resolver_flags, |
145 max_concurrent_resolves = kDefaultMaxJobs; | 152 addrlist, |
146 | 153 os_error); |
147 HostResolverImpl* resolver = | |
148 new HostResolverImpl(NULL, HostCache::CreateDefaultCache(), | |
149 max_concurrent_resolves, max_retry_attempts, net_log); | |
150 | |
151 return resolver; | |
152 } | |
153 | |
154 static int ResolveAddrInfo(HostResolverProc* resolver_proc, | |
155 const std::string& host, | |
156 AddressFamily address_family, | |
157 HostResolverFlags host_resolver_flags, | |
158 AddressList* out, | |
159 int* os_error) { | |
160 if (resolver_proc) { | |
161 // Use the custom procedure. | |
162 return resolver_proc->Resolve(host, address_family, | |
163 host_resolver_flags, out, os_error); | |
164 } else { | |
165 // Use the system procedure (getaddrinfo). | |
166 return SystemHostResolverProc(host, address_family, | |
167 host_resolver_flags, out, os_error); | |
168 } | 154 } |
169 } | 155 }; |
170 | 156 |
171 // Extra parameters to attach to the NetLog when the resolve failed. | 157 // Extra parameters to attach to the NetLog when the resolve failed. |
172 class HostResolveFailedParams : public NetLog::EventParameters { | 158 class HostResolveFailedParams : public NetLog::EventParameters { |
173 public: | 159 public: |
174 HostResolveFailedParams(uint32 attempt_number, | 160 HostResolveFailedParams(uint32 attempt_number, |
175 int net_error, | 161 int net_error, |
176 int os_error) | 162 int os_error) |
177 : attempt_number_(attempt_number), | 163 : attempt_number_(attempt_number), |
178 net_error_(net_error), | 164 net_error_(net_error), |
179 os_error_(os_error) { | 165 os_error_(os_error) { |
180 } | 166 } |
181 | 167 |
182 virtual Value* ToValue() const { | 168 virtual Value* ToValue() const OVERRIDE { |
183 DictionaryValue* dict = new DictionaryValue(); | 169 DictionaryValue* dict = new DictionaryValue(); |
184 if (attempt_number_) | 170 if (attempt_number_) |
185 dict->SetInteger("attempt_number", attempt_number_); | 171 dict->SetInteger("attempt_number", attempt_number_); |
186 | 172 |
187 dict->SetInteger("net_error", net_error_); | 173 dict->SetInteger("net_error", net_error_); |
188 | 174 |
189 if (os_error_) { | 175 if (os_error_) { |
190 dict->SetInteger("os_error", os_error_); | 176 dict->SetInteger("os_error", os_error_); |
191 #if defined(OS_POSIX) | 177 #if defined(OS_POSIX) |
192 dict->SetString("os_error_string", gai_strerror(os_error_)); | 178 dict->SetString("os_error_string", gai_strerror(os_error_)); |
(...skipping 23 matching lines...) Expand all Loading... |
216 }; | 202 }; |
217 | 203 |
218 // Parameters representing the information in a RequestInfo object, along with | 204 // Parameters representing the information in a RequestInfo object, along with |
219 // the associated NetLog::Source. | 205 // the associated NetLog::Source. |
220 class RequestInfoParameters : public NetLog::EventParameters { | 206 class RequestInfoParameters : public NetLog::EventParameters { |
221 public: | 207 public: |
222 RequestInfoParameters(const HostResolver::RequestInfo& info, | 208 RequestInfoParameters(const HostResolver::RequestInfo& info, |
223 const NetLog::Source& source) | 209 const NetLog::Source& source) |
224 : info_(info), source_(source) {} | 210 : info_(info), source_(source) {} |
225 | 211 |
226 virtual Value* ToValue() const { | 212 virtual Value* ToValue() const OVERRIDE { |
227 DictionaryValue* dict = new DictionaryValue(); | 213 DictionaryValue* dict = new DictionaryValue(); |
228 dict->SetString("host", info_.host_port_pair().ToString()); | 214 dict->SetString("host", info_.host_port_pair().ToString()); |
229 dict->SetInteger("address_family", | 215 dict->SetInteger("address_family", |
230 static_cast<int>(info_.address_family())); | 216 static_cast<int>(info_.address_family())); |
231 dict->SetBoolean("allow_cached_response", info_.allow_cached_response()); | 217 dict->SetBoolean("allow_cached_response", info_.allow_cached_response()); |
232 dict->SetBoolean("is_speculative", info_.is_speculative()); | 218 dict->SetBoolean("is_speculative", info_.is_speculative()); |
233 dict->SetInteger("priority", info_.priority()); | 219 dict->SetInteger("priority", info_.priority()); |
234 | 220 |
235 if (source_.is_valid()) | 221 if (source_.is_valid()) |
236 dict->Set("source_dependency", source_.ToValue()); | 222 dict->Set("source_dependency", source_.ToValue()); |
237 | 223 |
238 return dict; | 224 return dict; |
239 } | 225 } |
240 | 226 |
241 private: | 227 private: |
242 const HostResolver::RequestInfo info_; | 228 const HostResolver::RequestInfo info_; |
243 const NetLog::Source source_; | 229 const NetLog::Source source_; |
244 }; | 230 }; |
245 | 231 |
246 // Parameters associated with the creation of a HostResolverImpl::Job. | 232 // Parameters associated with the creation of a HostResolverImpl::Job |
| 233 // or a HostResolverImpl::ProcTask. |
247 class JobCreationParameters : public NetLog::EventParameters { | 234 class JobCreationParameters : public NetLog::EventParameters { |
248 public: | 235 public: |
249 JobCreationParameters(const std::string& host, const NetLog::Source& source) | 236 JobCreationParameters(const std::string& host, |
| 237 const NetLog::Source& source) |
250 : host_(host), source_(source) {} | 238 : host_(host), source_(source) {} |
251 | 239 |
252 virtual Value* ToValue() const { | 240 virtual Value* ToValue() const OVERRIDE { |
253 DictionaryValue* dict = new DictionaryValue(); | 241 DictionaryValue* dict = new DictionaryValue(); |
254 dict->SetString("host", host_); | 242 dict->SetString("host", host_); |
255 dict->Set("source_dependency", source_.ToValue()); | 243 dict->Set("source_dependency", source_.ToValue()); |
256 return dict; | 244 return dict; |
257 } | 245 } |
258 | 246 |
259 private: | 247 private: |
260 const std::string host_; | 248 const std::string host_; |
261 const NetLog::Source source_; | 249 const NetLog::Source source_; |
262 }; | 250 }; |
263 | 251 |
| 252 // Parameters of the HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH event. |
| 253 class JobAttachParameters : public NetLog::EventParameters { |
| 254 public: |
| 255 JobAttachParameters(const NetLog::Source& source, |
| 256 RequestPriority priority) |
| 257 : source_(source), priority_(priority) {} |
| 258 |
| 259 virtual Value* ToValue() const OVERRIDE { |
| 260 DictionaryValue* dict = new DictionaryValue(); |
| 261 dict->Set("source_dependency", source_.ToValue()); |
| 262 dict->SetInteger("priority", priority_); |
| 263 return dict; |
| 264 } |
| 265 |
| 266 private: |
| 267 const NetLog::Source source_; |
| 268 const RequestPriority priority_; |
| 269 }; |
| 270 |
| 271 // The logging routines are defined here because some requests are resolved |
| 272 // without a Request object. |
| 273 |
| 274 // Logs when a request has just been started. |
| 275 void LogStartRequest(const BoundNetLog& source_net_log, |
| 276 const BoundNetLog& request_net_log, |
| 277 const HostResolver::RequestInfo& info) { |
| 278 source_net_log.BeginEvent( |
| 279 NetLog::TYPE_HOST_RESOLVER_IMPL, |
| 280 make_scoped_refptr(new NetLogSourceParameter( |
| 281 "source_dependency", request_net_log.source()))); |
| 282 |
| 283 request_net_log.BeginEvent( |
| 284 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, |
| 285 make_scoped_refptr(new RequestInfoParameters( |
| 286 info, source_net_log.source()))); |
| 287 } |
| 288 |
| 289 // Logs when a request has just completed (before its callback is run). |
| 290 void LogFinishRequest(const BoundNetLog& source_net_log, |
| 291 const BoundNetLog& request_net_log, |
| 292 const HostResolver::RequestInfo& info, |
| 293 int net_error, |
| 294 int os_error) { |
| 295 scoped_refptr<NetLog::EventParameters> params; |
| 296 if (net_error != OK) { |
| 297 params = new HostResolveFailedParams(0, net_error, os_error); |
| 298 } |
| 299 |
| 300 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params); |
| 301 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL); |
| 302 } |
| 303 |
| 304 // Logs when a request has been cancelled. |
| 305 void LogCancelRequest(const BoundNetLog& source_net_log, |
| 306 const BoundNetLog& request_net_log, |
| 307 const HostResolverImpl::RequestInfo& info) { |
| 308 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL); |
| 309 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL); |
| 310 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL); |
| 311 } |
| 312 |
| 313 //----------------------------------------------------------------------------- |
| 314 |
| 315 // Keeps track of the highest priority. |
| 316 class PriorityTracker { |
| 317 public: |
| 318 PriorityTracker() |
| 319 : highest_priority_(IDLE), total_count_(0) { |
| 320 memset(counts_, 0, sizeof(counts_)); |
| 321 } |
| 322 |
| 323 RequestPriority highest_priority() const { |
| 324 return highest_priority_; |
| 325 } |
| 326 |
| 327 size_t total_count() const { |
| 328 return total_count_; |
| 329 } |
| 330 |
| 331 void Add(RequestPriority req_priority) { |
| 332 ++total_count_; |
| 333 ++counts_[req_priority]; |
| 334 if (highest_priority_ > req_priority) |
| 335 highest_priority_ = req_priority; |
| 336 } |
| 337 |
| 338 void Remove(RequestPriority req_priority) { |
| 339 DCHECK_GT(total_count_, 0u); |
| 340 DCHECK_GT(counts_[req_priority], 0u); |
| 341 --total_count_; |
| 342 --counts_[req_priority]; |
| 343 size_t i; |
| 344 for (i = highest_priority_; i < NUM_PRIORITIES && !counts_[i]; ++i); |
| 345 highest_priority_ = static_cast<RequestPriority>(i); |
| 346 |
| 347 // In absence of requests set default. |
| 348 if (highest_priority_ == NUM_PRIORITIES) { |
| 349 DCHECK_EQ(0u, total_count_); |
| 350 highest_priority_ = IDLE; |
| 351 } |
| 352 } |
| 353 |
| 354 private: |
| 355 RequestPriority highest_priority_; |
| 356 size_t total_count_; |
| 357 size_t counts_[NUM_PRIORITIES]; |
| 358 }; |
| 359 |
264 //----------------------------------------------------------------------------- | 360 //----------------------------------------------------------------------------- |
265 | 361 |
| 362 HostResolver* CreateHostResolver(size_t max_concurrent_resolves, |
| 363 size_t max_retry_attempts, |
| 364 bool use_cache, |
| 365 NetLog* net_log) { |
| 366 if (max_concurrent_resolves == HostResolver::kDefaultParallelism) |
| 367 max_concurrent_resolves = kDefaultMaxProcTasks; |
| 368 |
| 369 // TODO(szym): Add experiments with reserved slots for higher priority |
| 370 // requests. |
| 371 |
| 372 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves); |
| 373 |
| 374 HostResolverImpl* resolver = new HostResolverImpl( |
| 375 use_cache ? HostCache::CreateDefaultCache() : NULL, |
| 376 limits, |
| 377 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts), |
| 378 net_log); |
| 379 |
| 380 return resolver; |
| 381 } |
| 382 |
| 383 } // anonymous namespace |
| 384 |
| 385 //----------------------------------------------------------------------------- |
| 386 |
| 387 HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves, |
| 388 size_t max_retry_attempts, |
| 389 NetLog* net_log) { |
| 390 return CreateHostResolver(max_concurrent_resolves, |
| 391 max_retry_attempts, |
| 392 true /* use_cache */, |
| 393 net_log); |
| 394 } |
| 395 |
| 396 HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves, |
| 397 size_t max_retry_attempts, |
| 398 NetLog* net_log) { |
| 399 return CreateHostResolver(max_concurrent_resolves, |
| 400 max_retry_attempts, |
| 401 false /* use_cache */, |
| 402 net_log); |
| 403 } |
| 404 |
| 405 //----------------------------------------------------------------------------- |
| 406 |
| 407 // Holds the data for a request that could not be completed synchronously. |
| 408 // It is owned by a Job. Canceled Requests are only marked as canceled rather |
| 409 // than removed from the Job's |requests_| list. |
266 class HostResolverImpl::Request { | 410 class HostResolverImpl::Request { |
267 public: | 411 public: |
268 Request(const BoundNetLog& source_net_log, | 412 Request(const BoundNetLog& source_net_log, |
269 const BoundNetLog& request_net_log, | 413 const BoundNetLog& request_net_log, |
270 const RequestInfo& info, | 414 const RequestInfo& info, |
271 const CompletionCallback& callback, | 415 const CompletionCallback& callback, |
272 AddressList* addresses) | 416 AddressList* addresses) |
273 : source_net_log_(source_net_log), | 417 : source_net_log_(source_net_log), |
274 request_net_log_(request_net_log), | 418 request_net_log_(request_net_log), |
275 info_(info), | 419 info_(info), |
276 job_(NULL), | 420 job_(NULL), |
277 callback_(callback), | 421 callback_(callback), |
278 addresses_(addresses) { | 422 addresses_(addresses) { |
279 } | 423 } |
280 | 424 |
281 // Mark the request as cancelled. | 425 // Mark the request as canceled. |
282 void MarkAsCancelled() { | 426 void MarkAsCanceled() { |
283 job_ = NULL; | 427 job_ = NULL; |
284 addresses_ = NULL; | 428 addresses_ = NULL; |
285 callback_.Reset(); | 429 callback_.Reset(); |
286 } | 430 } |
287 | 431 |
288 bool was_cancelled() const { | 432 bool was_canceled() const { |
289 return callback_.is_null(); | 433 return callback_.is_null(); |
290 } | 434 } |
291 | 435 |
292 void set_job(Job* job) { | 436 void set_job(Job* job) { |
293 DCHECK(job != NULL); | 437 DCHECK(job); |
294 // Identify which job the request is waiting on. | 438 // Identify which job the request is waiting on. |
295 job_ = job; | 439 job_ = job; |
296 } | 440 } |
297 | 441 |
| 442 // Prepare final AddressList and call completion callback. |
298 void OnComplete(int error, const AddressList& addrlist) { | 443 void OnComplete(int error, const AddressList& addrlist) { |
299 if (error == OK) | 444 if (error == OK) |
300 *addresses_ = CreateAddressListUsingPort(addrlist, port()); | 445 *addresses_ = CreateAddressListUsingPort(addrlist, info_.port()); |
301 CompletionCallback callback = callback_; | 446 CompletionCallback callback = callback_; |
302 MarkAsCancelled(); | 447 MarkAsCanceled(); |
303 callback.Run(error); | 448 callback.Run(error); |
304 } | 449 } |
305 | 450 |
306 int port() const { | |
307 return info_.port(); | |
308 } | |
309 | |
310 Job* job() const { | 451 Job* job() const { |
311 return job_; | 452 return job_; |
312 } | 453 } |
313 | 454 |
| 455 // NetLog for the source, passed in HostResolver::Resolve. |
314 const BoundNetLog& source_net_log() { | 456 const BoundNetLog& source_net_log() { |
315 return source_net_log_; | 457 return source_net_log_; |
316 } | 458 } |
317 | 459 |
| 460 // NetLog for this request. |
318 const BoundNetLog& request_net_log() { | 461 const BoundNetLog& request_net_log() { |
319 return request_net_log_; | 462 return request_net_log_; |
320 } | 463 } |
321 | 464 |
322 const RequestInfo& info() const { | 465 const RequestInfo& info() const { |
323 return info_; | 466 return info_; |
324 } | 467 } |
325 | 468 |
326 private: | 469 private: |
327 BoundNetLog source_net_log_; | 470 BoundNetLog source_net_log_; |
328 BoundNetLog request_net_log_; | 471 BoundNetLog request_net_log_; |
329 | 472 |
330 // The request info that started the request. | 473 // The request info that started the request. |
331 RequestInfo info_; | 474 RequestInfo info_; |
332 | 475 |
333 // The resolve job (running in worker pool) that this request is dependent on. | 476 // The resolve job that this request is dependent on. |
334 Job* job_; | 477 Job* job_; |
335 | 478 |
336 // The user's callback to invoke when the request completes. | 479 // The user's callback to invoke when the request completes. |
337 CompletionCallback callback_; | 480 CompletionCallback callback_; |
338 | 481 |
339 // The address list to save result into. | 482 // The address list to save result into. |
340 AddressList* addresses_; | 483 AddressList* addresses_; |
341 | 484 |
342 DISALLOW_COPY_AND_ASSIGN(Request); | 485 DISALLOW_COPY_AND_ASSIGN(Request); |
343 }; | 486 }; |
344 | 487 |
345 //------------------------------------------------------------------------------ | 488 //------------------------------------------------------------------------------ |
346 | 489 |
347 // Provide a common macro to simplify code and readability. We must use a | 490 // Provide a common macro to simplify code and readability. We must use a |
348 // macros as the underlying HISTOGRAM macro creates static varibles. | 491 // macros as the underlying HISTOGRAM macro creates static varibles. |
349 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ | 492 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ |
350 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100) | 493 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100) |
351 | 494 |
352 // This class represents a request to the worker pool for a "getaddrinfo()" | 495 // Calls HostResolverProc on the WorkerPool. Performs retries if necessary. |
353 // call. | 496 // |
354 class HostResolverImpl::Job | 497 // Whenever we try to resolve the host, we post a delayed task to check if host |
355 : public base::RefCountedThreadSafe<HostResolverImpl::Job> { | 498 // resolution (OnLookupComplete) is completed or not. If the original attempt |
| 499 // hasn't completed, then we start another attempt for host resolution. We take |
| 500 // the results from the first attempt that finishes and ignore the results from |
| 501 // all other attempts. |
| 502 // |
| 503 // TODO(szym): Move to separate source file for testing and mocking. |
| 504 // |
| 505 class HostResolverImpl::ProcTask |
| 506 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> { |
356 public: | 507 public: |
357 Job(int id, | 508 typedef base::Callback<void(int, int, const AddressList&)> Callback; |
358 HostResolverImpl* resolver, | |
359 const Key& key, | |
360 const BoundNetLog& source_net_log, | |
361 NetLog* net_log) | |
362 : id_(id), | |
363 key_(key), | |
364 resolver_(resolver), | |
365 origin_loop_(base::MessageLoopProxy::current()), | |
366 resolver_proc_(resolver->effective_resolver_proc()), | |
367 unresponsive_delay_(resolver->unresponsive_delay()), | |
368 attempt_number_(0), | |
369 completed_attempt_number_(0), | |
370 completed_attempt_error_(ERR_UNEXPECTED), | |
371 had_non_speculative_request_(false), | |
372 net_log_(BoundNetLog::Make(net_log, | |
373 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { | |
374 DCHECK(resolver); | |
375 net_log_.BeginEvent( | |
376 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | |
377 make_scoped_refptr( | |
378 new JobCreationParameters(key.hostname, source_net_log.source()))); | |
379 } | |
380 | 509 |
381 // Attaches a request to this job. The job takes ownership of |req| and will | 510 ProcTask(const Key& key, |
382 // take care to delete it. | 511 const ProcTaskParams& params, |
383 void AddRequest(Request* req) { | 512 const Callback& callback, |
384 DCHECK(origin_loop_->BelongsToCurrentThread()); | 513 const BoundNetLog& job_net_log) |
385 req->request_net_log().BeginEvent( | 514 : key_(key), |
386 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, | 515 params_(params), |
387 make_scoped_refptr(new NetLogSourceParameter( | 516 callback_(callback), |
388 "source_dependency", net_log_.source()))); | 517 origin_loop_(base::MessageLoopProxy::current()), |
| 518 attempt_number_(0), |
| 519 completed_attempt_number_(0), |
| 520 completed_attempt_error_(ERR_UNEXPECTED), |
| 521 had_non_speculative_request_(false), |
| 522 net_log_(BoundNetLog::Make( |
| 523 job_net_log.net_log(), |
| 524 NetLog::SOURCE_HOST_RESOLVER_IMPL_PROC_TASK)) { |
| 525 if (!params_.resolver_proc) |
| 526 params_.resolver_proc = HostResolverProc::GetDefault(); |
| 527 // If default is unset, use the system proc. |
| 528 if (!params_.resolver_proc) |
| 529 params_.resolver_proc = new CallSystemHostResolverProc(); |
389 | 530 |
390 req->set_job(this); | 531 job_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_PROC_TASK, |
391 requests_.push_back(req); | 532 new NetLogSourceParameter("source_dependency", |
| 533 net_log_.source())); |
392 | 534 |
393 if (!req->info().is_speculative()) | 535 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, |
394 had_non_speculative_request_ = true; | 536 new JobCreationParameters(key_.hostname, |
| 537 job_net_log.source())); |
395 } | 538 } |
396 | 539 |
397 void Start() { | 540 void Start() { |
398 DCHECK(origin_loop_->BelongsToCurrentThread()); | 541 DCHECK(origin_loop_->BelongsToCurrentThread()); |
399 StartLookupAttempt(); | 542 StartLookupAttempt(); |
400 } | 543 } |
401 | 544 |
| 545 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve |
| 546 // attempts running on worker threads will continue running. Only once all the |
| 547 // attempts complete will the final reference to this ProcTask be released. |
| 548 void Cancel() { |
| 549 DCHECK(origin_loop_->BelongsToCurrentThread()); |
| 550 |
| 551 if (was_canceled()) |
| 552 return; |
| 553 |
| 554 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL); |
| 555 |
| 556 callback_.Reset(); |
| 557 |
| 558 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL); |
| 559 } |
| 560 |
| 561 void set_had_non_speculative_request() { |
| 562 DCHECK(origin_loop_->BelongsToCurrentThread()); |
| 563 had_non_speculative_request_ = true; |
| 564 } |
| 565 |
| 566 bool was_canceled() const { |
| 567 DCHECK(origin_loop_->BelongsToCurrentThread()); |
| 568 return callback_.is_null(); |
| 569 } |
| 570 |
| 571 bool was_completed() const { |
| 572 DCHECK(origin_loop_->BelongsToCurrentThread()); |
| 573 return completed_attempt_number_ > 0; |
| 574 } |
| 575 |
| 576 private: |
402 void StartLookupAttempt() { | 577 void StartLookupAttempt() { |
403 DCHECK(origin_loop_->BelongsToCurrentThread()); | 578 DCHECK(origin_loop_->BelongsToCurrentThread()); |
404 base::TimeTicks start_time = base::TimeTicks::Now(); | 579 base::TimeTicks start_time = base::TimeTicks::Now(); |
405 ++attempt_number_; | 580 ++attempt_number_; |
406 // Dispatch the lookup attempt to a worker thread. | 581 // Dispatch the lookup attempt to a worker thread. |
407 if (!base::WorkerPool::PostTask( | 582 if (!base::WorkerPool::PostTask( |
408 FROM_HERE, | 583 FROM_HERE, |
409 base::Bind(&Job::DoLookup, this, start_time, attempt_number_), | 584 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_), |
410 true)) { | 585 true)) { |
411 NOTREACHED(); | 586 NOTREACHED(); |
412 | 587 |
413 // Since we could be running within Resolve() right now, we can't just | 588 // Since we could be running within Resolve() right now, we can't just |
414 // call OnLookupComplete(). Instead we must wait until Resolve() has | 589 // call OnLookupComplete(). Instead we must wait until Resolve() has |
415 // returned (IO_PENDING). | 590 // returned (IO_PENDING). |
416 origin_loop_->PostTask( | 591 origin_loop_->PostTask( |
417 FROM_HERE, | 592 FROM_HERE, |
418 base::Bind(&Job::OnLookupComplete, this, AddressList(), | 593 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(), |
419 start_time, attempt_number_, ERR_UNEXPECTED, 0)); | 594 start_time, attempt_number_, ERR_UNEXPECTED, 0)); |
420 return; | 595 return; |
421 } | 596 } |
422 | 597 |
423 net_log_.AddEvent( | 598 net_log_.AddEvent( |
424 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED, | 599 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED, |
425 make_scoped_refptr(new NetLogIntegerParameter( | 600 make_scoped_refptr(new NetLogIntegerParameter( |
426 "attempt_number", attempt_number_))); | 601 "attempt_number", attempt_number_))); |
427 | 602 |
428 // Post a task to check if we get the results within a given time. | 603 // If we don't get the results within a given time, RetryIfNotComplete |
429 // OnCheckForComplete has the potential for starting a new attempt on a | 604 // will start a new attempt on a different worker thread if none of our |
430 // different worker thread if none of our outstanding attempts have | 605 // outstanding attempts have completed yet. |
431 // completed yet. | 606 if (attempt_number_ <= params_.max_retry_attempts) { |
432 if (attempt_number_ <= resolver_->max_retry_attempts()) { | |
433 origin_loop_->PostDelayedTask( | 607 origin_loop_->PostDelayedTask( |
434 FROM_HERE, | 608 FROM_HERE, |
435 base::Bind(&Job::OnCheckForComplete, this), | 609 base::Bind(&ProcTask::RetryIfNotComplete, this), |
436 unresponsive_delay_.InMilliseconds()); | 610 params_.unresponsive_delay.InMilliseconds()); |
437 } | 611 } |
438 } | 612 } |
439 | 613 |
440 // Cancels the current job. The Job will be orphaned. Any outstanding resolve | |
441 // attempts running on worker threads will continue running. Only once all the | |
442 // attempts complete will the final reference to this Job be released. | |
443 void Cancel() { | |
444 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
445 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL); | |
446 | |
447 HostResolver* resolver = resolver_; | |
448 resolver_ = NULL; | |
449 | |
450 // End here to prevent issues when a Job outlives the HostResolver that | |
451 // spawned it. | |
452 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL); | |
453 | |
454 // We will call HostResolverImpl::CancelRequest(Request*) on each one | |
455 // in order to notify any observers. | |
456 for (RequestsList::const_iterator it = requests_.begin(); | |
457 it != requests_.end(); ++it) { | |
458 HostResolverImpl::Request* req = *it; | |
459 if (!req->was_cancelled()) | |
460 resolver->CancelRequest(req); | |
461 } | |
462 } | |
463 | |
464 bool was_cancelled() const { | |
465 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
466 return resolver_ == NULL; | |
467 } | |
468 | |
469 bool was_completed() const { | |
470 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
471 return completed_attempt_number_ > 0; | |
472 } | |
473 | |
474 const Key& key() const { | |
475 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
476 return key_; | |
477 } | |
478 | |
479 int id() const { | |
480 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
481 return id_; | |
482 } | |
483 | |
484 const RequestsList& requests() const { | |
485 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
486 return requests_; | |
487 } | |
488 | |
489 // Returns the first request attached to the job. | |
490 const Request* initial_request() const { | |
491 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
492 DCHECK(!requests_.empty()); | |
493 return requests_[0]; | |
494 } | |
495 | |
496 // Returns true if |req_info| can be fulfilled by this job. | |
497 bool CanServiceRequest(const RequestInfo& req_info) const { | |
498 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
499 return key_ == resolver_->GetEffectiveKeyForRequest(req_info); | |
500 } | |
501 | |
502 private: | |
503 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>; | |
504 | |
505 ~Job() { | |
506 // Free the requests attached to this job. | |
507 STLDeleteElements(&requests_); | |
508 } | |
509 | |
510 // WARNING: This code runs inside a worker pool. The shutdown code cannot | 614 // WARNING: This code runs inside a worker pool. The shutdown code cannot |
511 // wait for it to finish, so we must be very careful here about using other | 615 // wait for it to finish, so we must be very careful here about using other |
512 // objects (like MessageLoops, Singletons, etc). During shutdown these objects | 616 // objects (like MessageLoops, Singletons, etc). During shutdown these objects |
513 // may no longer exist. Multiple DoLookups() could be running in parallel, so | 617 // may no longer exist. Multiple DoLookups() could be running in parallel, so |
514 // any state inside of |this| must not mutate . | 618 // any state inside of |this| must not mutate . |
515 void DoLookup(const base::TimeTicks& start_time, | 619 void DoLookup(const base::TimeTicks& start_time, |
516 const uint32 attempt_number) { | 620 const uint32 attempt_number) { |
517 AddressList results; | 621 AddressList results; |
518 int os_error = 0; | 622 int os_error = 0; |
519 // Running on the worker thread | 623 // Running on the worker thread |
520 int error = ResolveAddrInfo(resolver_proc_, | 624 |
521 key_.hostname, | 625 int error = params_.resolver_proc->Resolve(key_.hostname, |
522 key_.address_family, | 626 key_.address_family, |
523 key_.host_resolver_flags, | 627 key_.host_resolver_flags, |
524 &results, | 628 &results, |
525 &os_error); | 629 &os_error); |
526 | 630 |
527 origin_loop_->PostTask( | 631 origin_loop_->PostTask( |
528 FROM_HERE, | 632 FROM_HERE, |
529 base::Bind(&Job::OnLookupComplete, this, results, start_time, | 633 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time, |
530 attempt_number, error, os_error)); | 634 attempt_number, error, os_error)); |
531 } | 635 } |
532 | 636 |
533 // Callback to see if DoLookup() has finished or not (runs on origin thread). | 637 // Makes next attempt if DoLookup() has not finished (runs on origin thread). |
534 void OnCheckForComplete() { | 638 void RetryIfNotComplete() { |
535 DCHECK(origin_loop_->BelongsToCurrentThread()); | 639 DCHECK(origin_loop_->BelongsToCurrentThread()); |
536 | 640 |
537 if (was_completed() || was_cancelled()) | 641 if (was_completed() || was_canceled()) |
538 return; | 642 return; |
539 | 643 |
540 DCHECK(resolver_); | 644 params_.unresponsive_delay *= params_.retry_factor; |
541 unresponsive_delay_ *= resolver_->retry_factor(); | |
542 StartLookupAttempt(); | 645 StartLookupAttempt(); |
543 } | 646 } |
544 | 647 |
545 // Callback for when DoLookup() completes (runs on origin thread). | 648 // Callback for when DoLookup() completes (runs on origin thread). |
546 void OnLookupComplete(const AddressList& results, | 649 void OnLookupComplete(const AddressList& results, |
547 const base::TimeTicks& start_time, | 650 const base::TimeTicks& start_time, |
548 const uint32 attempt_number, | 651 const uint32 attempt_number, |
549 int error, | 652 int error, |
550 const int os_error) { | 653 const int os_error) { |
551 DCHECK(origin_loop_->BelongsToCurrentThread()); | 654 DCHECK(origin_loop_->BelongsToCurrentThread()); |
552 DCHECK(error || results.head()); | 655 DCHECK(error || results.head()); |
553 | 656 |
554 bool was_retry_attempt = attempt_number > 1; | 657 bool was_retry_attempt = attempt_number > 1; |
555 | 658 |
556 if (!was_cancelled()) { | |
557 scoped_refptr<NetLog::EventParameters> params; | |
558 if (error != OK) { | |
559 params = new HostResolveFailedParams(attempt_number, error, os_error); | |
560 } else { | |
561 params = new NetLogIntegerParameter("attempt_number", attempt_number_); | |
562 } | |
563 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED, | |
564 params); | |
565 | |
566 // If host is already resolved, then record data and return. | |
567 if (was_completed()) { | |
568 // If this is the first attempt that is finishing later, then record | |
569 // data for the first attempt. Won't contaminate with retry attempt's | |
570 // data. | |
571 if (!was_retry_attempt) | |
572 RecordPerformanceHistograms(start_time, error, os_error); | |
573 | |
574 RecordAttemptHistograms(start_time, attempt_number, error, os_error); | |
575 return; | |
576 } | |
577 | |
578 // Copy the results from the first worker thread that resolves the host. | |
579 results_ = results; | |
580 completed_attempt_number_ = attempt_number; | |
581 completed_attempt_error_ = error; | |
582 } | |
583 | |
584 // Ideally the following code would be part of host_resolver_proc.cc, | 659 // Ideally the following code would be part of host_resolver_proc.cc, |
585 // however it isn't safe to call NetworkChangeNotifier from worker | 660 // however it isn't safe to call NetworkChangeNotifier from worker |
586 // threads. So we do it here on the IO thread instead. | 661 // threads. So we do it here on the IO thread instead. |
587 if (error != OK && NetworkChangeNotifier::IsOffline()) | 662 if (error != OK && NetworkChangeNotifier::IsOffline()) |
588 error = ERR_INTERNET_DISCONNECTED; | 663 error = ERR_INTERNET_DISCONNECTED; |
589 | 664 |
590 // We will record data for the first attempt. Don't contaminate with retry | 665 // If this is the first attempt that is finishing later, then record |
591 // attempt's data. | 666 // data for the first attempt. Won't contaminate with retry attempt's |
| 667 // data. |
592 if (!was_retry_attempt) | 668 if (!was_retry_attempt) |
593 RecordPerformanceHistograms(start_time, error, os_error); | 669 RecordPerformanceHistograms(start_time, error, os_error); |
594 | 670 |
595 RecordAttemptHistograms(start_time, attempt_number, error, os_error); | 671 RecordAttemptHistograms(start_time, attempt_number, error, os_error); |
596 | 672 |
597 if (was_cancelled()) | 673 if (was_canceled()) |
598 return; | 674 return; |
599 | 675 |
| 676 scoped_refptr<NetLog::EventParameters> params; |
| 677 if (error != OK) { |
| 678 params = new HostResolveFailedParams(attempt_number, error, os_error); |
| 679 } else { |
| 680 params = new NetLogIntegerParameter("attempt_number", attempt_number_); |
| 681 } |
| 682 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED, params); |
| 683 |
| 684 if (was_completed()) |
| 685 return; |
| 686 |
| 687 // Copy the results from the first worker thread that resolves the host. |
| 688 results_ = results; |
| 689 completed_attempt_number_ = attempt_number; |
| 690 completed_attempt_error_ = error; |
| 691 |
600 if (was_retry_attempt) { | 692 if (was_retry_attempt) { |
601 // If retry attempt finishes before 1st attempt, then get stats on how | 693 // If retry attempt finishes before 1st attempt, then get stats on how |
602 // much time is saved by having spawned an extra attempt. | 694 // much time is saved by having spawned an extra attempt. |
603 retry_attempt_finished_time_ = base::TimeTicks::Now(); | 695 retry_attempt_finished_time_ = base::TimeTicks::Now(); |
604 } | 696 } |
605 | 697 |
606 scoped_refptr<NetLog::EventParameters> params; | |
607 if (error != OK) { | 698 if (error != OK) { |
608 params = new HostResolveFailedParams(0, error, os_error); | 699 params = new HostResolveFailedParams(0, error, os_error); |
609 } else { | 700 } else { |
610 params = new AddressListNetLogParam(results_); | 701 params = new AddressListNetLogParam(results_); |
611 } | 702 } |
| 703 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, params); |
612 | 704 |
613 // End here to prevent issues when a Job outlives the HostResolver that | 705 callback_.Run(error, os_error, results_); |
614 // spawned it. | |
615 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params); | |
616 | |
617 DCHECK(!requests_.empty()); | |
618 | |
619 // Use the port number of the first request. | |
620 if (error == OK) | |
621 MutableSetPort(requests_[0]->port(), &results_); | |
622 | |
623 resolver_->OnJobComplete(this, error, os_error, results_); | |
624 } | 706 } |
625 | 707 |
626 void RecordPerformanceHistograms(const base::TimeTicks& start_time, | 708 void RecordPerformanceHistograms(const base::TimeTicks& start_time, |
627 const int error, | 709 const int error, |
628 const int os_error) const { | 710 const int os_error) const { |
629 DCHECK(origin_loop_->BelongsToCurrentThread()); | 711 DCHECK(origin_loop_->BelongsToCurrentThread()); |
630 enum Category { // Used in HISTOGRAM_ENUMERATION. | 712 enum Category { // Used in HISTOGRAM_ENUMERATION. |
631 RESOLVE_SUCCESS, | 713 RESOLVE_SUCCESS, |
632 RESOLVE_FAIL, | 714 RESOLVE_FAIL, |
633 RESOLVE_SPECULATIVE_SUCCESS, | 715 RESOLVE_SPECULATIVE_SUCCESS, |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
709 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess", | 791 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess", |
710 "DnsParallelism"), duration); | 792 "DnsParallelism"), duration); |
711 } | 793 } |
712 } | 794 } |
713 } | 795 } |
714 | 796 |
715 void RecordAttemptHistograms(const base::TimeTicks& start_time, | 797 void RecordAttemptHistograms(const base::TimeTicks& start_time, |
716 const uint32 attempt_number, | 798 const uint32 attempt_number, |
717 const int error, | 799 const int error, |
718 const int os_error) const { | 800 const int os_error) const { |
| 801 DCHECK(origin_loop_->BelongsToCurrentThread()); |
719 bool first_attempt_to_complete = | 802 bool first_attempt_to_complete = |
720 completed_attempt_number_ == attempt_number; | 803 completed_attempt_number_ == attempt_number; |
721 bool is_first_attempt = (attempt_number == 1); | 804 bool is_first_attempt = (attempt_number == 1); |
722 | 805 |
723 if (first_attempt_to_complete) { | 806 if (first_attempt_to_complete) { |
724 // If this was first attempt to complete, then record the resolution | 807 // If this was first attempt to complete, then record the resolution |
725 // status of the attempt. | 808 // status of the attempt. |
726 if (completed_attempt_error_ == OK) { | 809 if (completed_attempt_error_ == OK) { |
727 UMA_HISTOGRAM_ENUMERATION( | 810 UMA_HISTOGRAM_ENUMERATION( |
728 "DNS.AttemptFirstSuccess", attempt_number, 100); | 811 "DNS.AttemptFirstSuccess", attempt_number, 100); |
729 } else { | 812 } else { |
730 UMA_HISTOGRAM_ENUMERATION( | 813 UMA_HISTOGRAM_ENUMERATION( |
731 "DNS.AttemptFirstFailure", attempt_number, 100); | 814 "DNS.AttemptFirstFailure", attempt_number, 100); |
732 } | 815 } |
733 } | 816 } |
734 | 817 |
735 if (error == OK) | 818 if (error == OK) |
736 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100); | 819 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100); |
737 else | 820 else |
738 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100); | 821 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100); |
739 | 822 |
740 // If first attempt didn't finish before retry attempt, then calculate stats | 823 // If first attempt didn't finish before retry attempt, then calculate stats |
741 // on how much time is saved by having spawned an extra attempt. | 824 // on how much time is saved by having spawned an extra attempt. |
742 if (!first_attempt_to_complete && is_first_attempt && !was_cancelled()) { | 825 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) { |
743 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry", | 826 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry", |
744 base::TimeTicks::Now() - retry_attempt_finished_time_); | 827 base::TimeTicks::Now() - retry_attempt_finished_time_); |
745 } | 828 } |
746 | 829 |
747 if (was_cancelled() || !first_attempt_to_complete) { | 830 if (was_canceled() || !first_attempt_to_complete) { |
748 // Count those attempts which completed after the job was already canceled | 831 // Count those attempts which completed after the job was already canceled |
749 // OR after the job was already completed by an earlier attempt (so in | 832 // OR after the job was already completed by an earlier attempt (so in |
750 // effect). | 833 // effect). |
751 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100); | 834 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100); |
752 | 835 |
753 // Record if job is cancelled. | 836 // Record if job is canceled. |
754 if (was_cancelled()) | 837 if (was_canceled()) |
755 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100); | 838 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100); |
756 } | 839 } |
757 | 840 |
758 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | 841 base::TimeDelta duration = base::TimeTicks::Now() - start_time; |
759 if (error == OK) | 842 if (error == OK) |
760 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration); | 843 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration); |
761 else | 844 else |
762 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration); | 845 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration); |
763 } | 846 } |
764 | 847 |
765 // Immutable. Can be read from either thread, | |
766 const int id_; | |
767 | |
768 // Set on the origin thread, read on the worker thread. | 848 // Set on the origin thread, read on the worker thread. |
769 Key key_; | 849 Key key_; |
770 | 850 |
771 // Only used on the origin thread (where Resolve was called). | 851 // Holds an owning reference to the HostResolverProc that we are going to use. |
772 HostResolverImpl* resolver_; | 852 // This may not be the current resolver procedure by the time we call |
773 RequestsList requests_; // The requests waiting on this job. | 853 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning |
| 854 // reference ensures that it remains valid until we are done. |
| 855 ProcTaskParams params_; |
| 856 |
| 857 // The listener to the results of this ProcTask. |
| 858 Callback callback_; |
774 | 859 |
775 // Used to post ourselves onto the origin thread. | 860 // Used to post ourselves onto the origin thread. |
776 scoped_refptr<base::MessageLoopProxy> origin_loop_; | 861 scoped_refptr<base::MessageLoopProxy> origin_loop_; |
777 | 862 |
778 // Hold an owning reference to the HostResolverProc that we are going to use. | |
779 // This may not be the current resolver procedure by the time we call | |
780 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning | |
781 // reference ensures that it remains valid until we are done. | |
782 scoped_refptr<HostResolverProc> resolver_proc_; | |
783 | |
784 // The amount of time after starting a resolution attempt until deciding to | |
785 // retry. | |
786 base::TimeDelta unresponsive_delay_; | |
787 | |
788 // Keeps track of the number of attempts we have made so far to resolve the | 863 // Keeps track of the number of attempts we have made so far to resolve the |
789 // host. Whenever we start an attempt to resolve the host, we increase this | 864 // host. Whenever we start an attempt to resolve the host, we increase this |
790 // number. | 865 // number. |
791 uint32 attempt_number_; | 866 uint32 attempt_number_; |
792 | 867 |
793 // The index of the attempt which finished first (or 0 if the job is still in | 868 // The index of the attempt which finished first (or 0 if the job is still in |
794 // progress). | 869 // progress). |
795 uint32 completed_attempt_number_; | 870 uint32 completed_attempt_number_; |
796 | 871 |
797 // The result (a net error code) from the first attempt to complete. | 872 // The result (a net error code) from the first attempt to complete. |
798 int completed_attempt_error_; | 873 int completed_attempt_error_; |
799 | 874 |
800 // The time when retry attempt was finished. | 875 // The time when retry attempt was finished. |
801 base::TimeTicks retry_attempt_finished_time_; | 876 base::TimeTicks retry_attempt_finished_time_; |
802 | 877 |
803 // True if a non-speculative request was ever attached to this job | 878 // True if a non-speculative request was ever attached to this job |
804 // (regardless of whether or not it was later cancelled. | 879 // (regardless of whether or not it was later canceled. |
805 // This boolean is used for histogramming the duration of jobs used to | 880 // This boolean is used for histogramming the duration of jobs used to |
806 // service non-speculative requests. | 881 // service non-speculative requests. |
807 bool had_non_speculative_request_; | 882 bool had_non_speculative_request_; |
808 | 883 |
809 AddressList results_; | 884 AddressList results_; |
810 | 885 |
811 BoundNetLog net_log_; | 886 BoundNetLog net_log_; |
812 | 887 |
813 DISALLOW_COPY_AND_ASSIGN(Job); | 888 DISALLOW_COPY_AND_ASSIGN(ProcTask); |
814 }; | 889 }; |
815 | 890 |
816 //----------------------------------------------------------------------------- | 891 //----------------------------------------------------------------------------- |
817 | 892 |
818 // This class represents a request to the worker pool for a "probe for IPv6 | 893 // Represents a request to the worker pool for a "probe for IPv6 support" call. |
819 // support" call. | |
820 class HostResolverImpl::IPv6ProbeJob | 894 class HostResolverImpl::IPv6ProbeJob |
821 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> { | 895 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> { |
822 public: | 896 public: |
823 explicit IPv6ProbeJob(HostResolverImpl* resolver) | 897 explicit IPv6ProbeJob(HostResolverImpl* resolver) |
824 : resolver_(resolver), | 898 : resolver_(resolver), |
825 origin_loop_(base::MessageLoopProxy::current()) { | 899 origin_loop_(base::MessageLoopProxy::current()) { |
826 DCHECK(resolver); | 900 DCHECK(resolver); |
827 } | 901 } |
828 | 902 |
829 void Start() { | 903 void Start() { |
830 DCHECK(origin_loop_->BelongsToCurrentThread()); | 904 DCHECK(origin_loop_->BelongsToCurrentThread()); |
831 if (was_cancelled()) | 905 if (was_canceled()) |
832 return; | 906 return; |
833 const bool kIsSlow = true; | 907 const bool kIsSlow = true; |
834 base::WorkerPool::PostTask( | 908 base::WorkerPool::PostTask( |
835 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow); | 909 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow); |
836 } | 910 } |
837 | 911 |
838 // Cancels the current job. | 912 // Cancels the current job. |
839 void Cancel() { | 913 void Cancel() { |
840 DCHECK(origin_loop_->BelongsToCurrentThread()); | 914 DCHECK(origin_loop_->BelongsToCurrentThread()); |
841 if (was_cancelled()) | 915 if (was_canceled()) |
842 return; | 916 return; |
843 resolver_ = NULL; // Read/write ONLY on origin thread. | 917 resolver_ = NULL; // Read/write ONLY on origin thread. |
844 } | 918 } |
845 | 919 |
846 private: | 920 private: |
847 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>; | 921 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>; |
848 | 922 |
849 ~IPv6ProbeJob() { | 923 ~IPv6ProbeJob() { |
850 } | 924 } |
851 | 925 |
852 bool was_cancelled() const { | 926 bool was_canceled() const { |
853 DCHECK(origin_loop_->BelongsToCurrentThread()); | 927 DCHECK(origin_loop_->BelongsToCurrentThread()); |
854 return !resolver_; | 928 return !resolver_; |
855 } | 929 } |
856 | 930 |
857 // Run on worker thread. | 931 // Run on worker thread. |
858 void DoProbe() { | 932 void DoProbe() { |
859 // Do actual testing on this thread, as it takes 40-100ms. | 933 // Do actual testing on this thread, as it takes 40-100ms. |
860 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED | 934 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED |
861 : ADDRESS_FAMILY_IPV4; | 935 : ADDRESS_FAMILY_IPV4; |
862 | 936 |
863 origin_loop_->PostTask( | 937 origin_loop_->PostTask( |
864 FROM_HERE, | 938 FROM_HERE, |
865 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family)); | 939 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family)); |
866 } | 940 } |
867 | 941 |
868 // Callback for when DoProbe() completes. | 942 // Callback for when DoProbe() completes. |
869 void OnProbeComplete(AddressFamily address_family) { | 943 void OnProbeComplete(AddressFamily address_family) { |
870 DCHECK(origin_loop_->BelongsToCurrentThread()); | 944 DCHECK(origin_loop_->BelongsToCurrentThread()); |
871 if (was_cancelled()) | 945 if (was_canceled()) |
872 return; | 946 return; |
873 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family); | 947 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family); |
874 } | 948 } |
875 | 949 |
876 // Used/set only on origin thread. | 950 // Used/set only on origin thread. |
877 HostResolverImpl* resolver_; | 951 HostResolverImpl* resolver_; |
878 | 952 |
879 // Used to post ourselves onto the origin thread. | 953 // Used to post ourselves onto the origin thread. |
880 scoped_refptr<base::MessageLoopProxy> origin_loop_; | 954 scoped_refptr<base::MessageLoopProxy> origin_loop_; |
881 | 955 |
882 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob); | 956 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob); |
883 }; | 957 }; |
884 | 958 |
885 //----------------------------------------------------------------------------- | 959 //----------------------------------------------------------------------------- |
886 | 960 |
887 // We rely on the priority enum values being sequential having starting at 0, | 961 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. |
888 // and increasing for lower priorities. | 962 // Spawns ProcTask when started. |
889 COMPILE_ASSERT(HIGHEST == 0u && | 963 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { |
890 LOWEST > HIGHEST && | |
891 IDLE > LOWEST && | |
892 NUM_PRIORITIES > IDLE, | |
893 priority_indexes_incompatible); | |
894 | |
895 // JobPool contains all the information relating to queued requests, including | |
896 // the limits on how many jobs are allowed to be used for this category of | |
897 // requests. | |
898 class HostResolverImpl::JobPool { | |
899 public: | 964 public: |
900 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests) | 965 // Creates new job for |key| where |request_net_log| is bound to the |
901 : num_outstanding_jobs_(0u) { | 966 // request that spawned it. |
902 SetConstraints(max_outstanding_jobs, max_pending_requests); | 967 Job(HostResolverImpl* resolver, |
903 } | 968 const Key& key, |
904 | 969 const BoundNetLog& request_net_log) |
905 ~JobPool() { | 970 : resolver_(resolver->AsWeakPtr()), |
906 // Free the pending requests. | 971 key_(key), |
907 for (size_t i = 0; i < arraysize(pending_requests_); ++i) | 972 had_non_speculative_request_(false), |
908 STLDeleteElements(&pending_requests_[i]); | 973 net_log_(BoundNetLog::Make(request_net_log.net_log(), |
909 } | 974 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)), |
910 | 975 net_error_(ERR_IO_PENDING), |
911 // Sets the constraints for this pool. See SetPoolConstraints() for the | 976 os_error_(0) { |
912 // specific meaning of these parameters. | 977 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL); |
913 void SetConstraints(size_t max_outstanding_jobs, | 978 |
914 size_t max_pending_requests) { | 979 net_log_.BeginEvent( |
915 CHECK_NE(max_outstanding_jobs, 0u); | 980 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, |
916 max_outstanding_jobs_ = max_outstanding_jobs; | 981 make_scoped_refptr(new JobCreationParameters( |
917 max_pending_requests_ = max_pending_requests; | 982 key_.hostname, request_net_log.source()))); |
918 } | 983 } |
919 | 984 |
920 // Returns the number of pending requests enqueued to this pool. | 985 virtual ~Job() { |
921 // A pending request is one waiting to be attached to a job. | 986 if (net_error_ == ERR_IO_PENDING) { |
922 size_t GetNumPendingRequests() const { | 987 if (is_running()) { |
923 size_t total = 0u; | 988 DCHECK_EQ(ERR_IO_PENDING, net_error_); |
924 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) | 989 proc_task_->Cancel(); |
925 total += pending_requests_[i].size(); | 990 proc_task_ = NULL; |
926 return total; | 991 net_error_ = ERR_ABORTED; |
927 } | 992 } else { |
928 | 993 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL); |
929 bool HasPendingRequests() const { | 994 net_error_ = OK; // For NetLog. |
930 return GetNumPendingRequests() > 0u; | 995 } |
931 } | 996 |
932 | 997 for (RequestsList::const_iterator it = requests_.begin(); |
933 // Enqueues a request to this pool. As a result of enqueing this request, | 998 it != requests_.end(); ++it) { |
934 // the queue may have reached its maximum size. In this case, a request is | 999 Request* req = *it; |
935 // evicted from the queue, and returned. Otherwise returns NULL. The caller | 1000 if (req->was_canceled()) |
936 // is responsible for freeing the evicted request. | 1001 continue; |
937 Request* InsertPendingRequest(Request* req) { | 1002 DCHECK_EQ(this, req->job()); |
938 req->request_net_log().BeginEvent( | 1003 LogCancelRequest(req->source_net_log(), req->request_net_log(), |
939 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, | 1004 req->info()); |
940 NULL); | |
941 | |
942 PendingRequestsQueue& q = pending_requests_[req->info().priority()]; | |
943 q.push_back(req); | |
944 | |
945 // If the queue is too big, kick out the lowest priority oldest request. | |
946 if (GetNumPendingRequests() > max_pending_requests_) { | |
947 // Iterate over the queues from lowest priority to highest priority. | |
948 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1; | |
949 i >= 0; --i) { | |
950 PendingRequestsQueue& q = pending_requests_[i]; | |
951 if (!q.empty()) { | |
952 Request* req = q.front(); | |
953 q.pop_front(); | |
954 req->request_net_log().AddEvent( | |
955 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL); | |
956 req->request_net_log().EndEvent( | |
957 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL); | |
958 return req; | |
959 } | |
960 } | 1005 } |
961 } | 1006 } |
962 | 1007 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, |
963 return NULL; | 1008 net_error_); |
964 } | 1009 STLDeleteElements(&requests_); |
965 | 1010 } |
966 // Erases |req| from this container. Caller is responsible for freeing | 1011 |
967 // |req| afterwards. | 1012 HostResolverImpl* resolver() const { |
968 void RemovePendingRequest(Request* req) { | 1013 return resolver_; |
969 PendingRequestsQueue& q = pending_requests_[req->info().priority()]; | 1014 } |
970 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req); | 1015 |
971 DCHECK(it != q.end()); | 1016 RequestPriority priority() const { |
972 q.erase(it); | 1017 return priority_tracker_.highest_priority(); |
973 req->request_net_log().EndEvent( | 1018 } |
974 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL); | 1019 |
975 } | 1020 // Number of non-canceled requests in |requests_|. |
976 | 1021 size_t num_active_requests() const { |
977 // Removes and returns the highest priority pending request. | 1022 return priority_tracker_.total_count(); |
978 Request* RemoveTopPendingRequest() { | 1023 } |
979 DCHECK(HasPendingRequests()); | 1024 |
980 | 1025 const Key& key() const { |
981 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) { | 1026 return key_; |
982 PendingRequestsQueue& q = pending_requests_[i]; | 1027 } |
983 if (!q.empty()) { | 1028 |
984 Request* req = q.front(); | 1029 int net_error() const { |
985 q.pop_front(); | 1030 return net_error_; |
986 req->request_net_log().EndEvent( | 1031 } |
987 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL); | 1032 |
988 return req; | 1033 // Used by HostResolverImpl with |dispatcher_|. |
989 } | 1034 const PrioritizedDispatcher::Handle& handle() const { |
| 1035 return handle_; |
| 1036 } |
| 1037 |
| 1038 void set_handle(const PrioritizedDispatcher::Handle& handle) { |
| 1039 handle_ = handle; |
| 1040 } |
| 1041 |
| 1042 // The Job will own |req| and destroy it in ~Job. |
| 1043 void AddRequest(Request* req) { |
| 1044 DCHECK_EQ(key_.hostname, req->info().hostname()); |
| 1045 |
| 1046 req->set_job(this); |
| 1047 requests_.push_back(req); |
| 1048 |
| 1049 priority_tracker_.Add(req->info().priority()); |
| 1050 |
| 1051 req->request_net_log().AddEvent( |
| 1052 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, |
| 1053 make_scoped_refptr(new NetLogSourceParameter( |
| 1054 "source_dependency", net_log_.source()))); |
| 1055 |
| 1056 net_log_.AddEvent( |
| 1057 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH, |
| 1058 make_scoped_refptr(new JobAttachParameters( |
| 1059 req->request_net_log().source(), priority()))); |
| 1060 |
| 1061 // TODO(szym): Check if this is still needed. |
| 1062 if (!req->info().is_speculative()) { |
| 1063 had_non_speculative_request_ = true; |
| 1064 if (proc_task_) |
| 1065 proc_task_->set_had_non_speculative_request(); |
990 } | 1066 } |
991 | 1067 } |
992 NOTREACHED(); | 1068 |
993 return NULL; | 1069 void CancelRequest(Request* req) { |
994 } | 1070 DCHECK_EQ(key_.hostname, req->info().hostname()); |
995 | 1071 DCHECK(!req->was_canceled()); |
996 // Keeps track of a job that was just added/removed, and belongs to this pool. | 1072 // Don't remove it from |requests_| just mark it canceled. |
997 void AdjustNumOutstandingJobs(int offset) { | 1073 req->MarkAsCanceled(); |
998 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u)); | 1074 LogCancelRequest(req->source_net_log(), req->request_net_log(), |
999 num_outstanding_jobs_ += offset; | 1075 req->info()); |
1000 } | 1076 priority_tracker_.Remove(req->info().priority()); |
1001 | 1077 net_log_.AddEvent( |
1002 void ResetNumOutstandingJobs() { | 1078 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH, |
1003 num_outstanding_jobs_ = 0; | 1079 make_scoped_refptr(new JobAttachParameters( |
1004 } | 1080 req->request_net_log().source(), priority()))); |
1005 | 1081 } |
1006 // Returns true if a new job can be created for this pool. | 1082 |
1007 bool CanCreateJob() const { | 1083 // Aborts and destroys the job, completes all requests as aborted. |
1008 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_; | 1084 void Abort() { |
1009 } | 1085 // Job should only be aborted if it's running. |
1010 | 1086 DCHECK(is_running()); |
1011 // Removes any pending requests from the queue which are for the | 1087 proc_task_->Cancel(); |
1012 // same (hostname / effective address-family) as |job|, and attaches them to | 1088 proc_task_ = NULL; |
1013 // |job|. | 1089 net_error_ = ERR_ABORTED; |
1014 void MoveRequestsToJob(Job* job) { | 1090 os_error_ = 0; |
1015 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) { | 1091 CompleteRequests(AddressList()); |
1016 PendingRequestsQueue& q = pending_requests_[i]; | 1092 } |
1017 PendingRequestsQueue::iterator req_it = q.begin(); | 1093 |
1018 while (req_it != q.end()) { | 1094 bool is_running() const { |
1019 Request* req = *req_it; | 1095 return proc_task_.get() != NULL; |
1020 if (job->CanServiceRequest(req->info())) { | 1096 } |
1021 // Job takes ownership of |req|. | 1097 |
1022 job->AddRequest(req); | 1098 // Called by HostResolverImpl when this job is evicted due to queue overflow. |
1023 req_it = q.erase(req_it); | 1099 void OnEvicted() { |
1024 } else { | 1100 // Must not be running. |
1025 ++req_it; | 1101 DCHECK(!is_running()); |
1026 } | 1102 handle_ = PrioritizedDispatcher::Handle(); |
1027 } | 1103 |
| 1104 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED, NULL); |
| 1105 |
| 1106 // This signals to CompleteRequests that this job never ran. |
| 1107 net_error_ = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; |
| 1108 os_error_ = 0; |
| 1109 CompleteRequests(AddressList()); |
| 1110 } |
| 1111 |
| 1112 // PriorityDispatch::Job interface. |
| 1113 virtual void Start() OVERRIDE { |
| 1114 DCHECK(!is_running()); |
| 1115 handle_ = PrioritizedDispatcher::Handle(); |
| 1116 |
| 1117 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL); |
| 1118 |
| 1119 proc_task_ = new ProcTask( |
| 1120 key_, |
| 1121 resolver_->proc_params_, |
| 1122 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)), |
| 1123 net_log_); |
| 1124 |
| 1125 if (had_non_speculative_request_) |
| 1126 proc_task_->set_had_non_speculative_request(); |
| 1127 // Start() could be called from within Resolve(), hence it must NOT directly |
| 1128 // call OnProcTaskComplete, for example, on synchronous failure. |
| 1129 proc_task_->Start(); |
| 1130 } |
| 1131 |
| 1132 private: |
| 1133 // Called by ProcTask when it completes. |
| 1134 void OnProcTaskComplete(int net_error, int os_error, |
| 1135 const AddressList& addrlist) { |
| 1136 DCHECK(is_running()); |
| 1137 proc_task_ = NULL; |
| 1138 net_error_ = net_error; |
| 1139 os_error_ = os_error; |
| 1140 |
| 1141 // We are the only consumer of |addrlist|, so we can safely change the port |
| 1142 // without copy-on-write. This pays off, when job has only one request. |
| 1143 AddressList list = addrlist; |
| 1144 if (net_error == OK && !requests_.empty()) |
| 1145 MutableSetPort(requests_.front()->info().port(), &list); |
| 1146 CompleteRequests(list); |
| 1147 } |
| 1148 |
| 1149 // Completes all Requests. Calls OnJobFinished and deletes self. |
| 1150 void CompleteRequests(const AddressList& addrlist) { |
| 1151 CHECK(resolver_); |
| 1152 |
| 1153 // This job must be removed from resolver's |jobs_| now to make room for a |
| 1154 // new job with the same key in case one of the OnComplete callbacks decides |
| 1155 // to spawn one. Consequently, the job deletes itself when CompleteRequests |
| 1156 // is done. |
| 1157 scoped_ptr<Job> self_deleter(this); |
| 1158 resolver_->OnJobFinished(this, addrlist); |
| 1159 |
| 1160 // Complete all of the requests that were attached to the job. |
| 1161 for (RequestsList::const_iterator it = requests_.begin(); |
| 1162 it != requests_.end(); ++it) { |
| 1163 Request* req = *it; |
| 1164 |
| 1165 if (req->was_canceled()) |
| 1166 continue; |
| 1167 |
| 1168 DCHECK_EQ(this, req->job()); |
| 1169 // Update the net log and notify registered observers. |
| 1170 LogFinishRequest(req->source_net_log(), req->request_net_log(), |
| 1171 req->info(), net_error_, os_error_); |
| 1172 |
| 1173 req->OnComplete(net_error_, addrlist); |
| 1174 |
| 1175 // Check if the resolver was destroyed as a result of running the |
| 1176 // callback. If it was, we could continue, but we choose to bail. |
| 1177 if (!resolver_) |
| 1178 return; |
1028 } | 1179 } |
1029 } | 1180 } |
1030 | 1181 |
1031 private: | 1182 // Used to call OnJobFinished and RemoveJob. |
1032 typedef std::deque<Request*> PendingRequestsQueue; | 1183 base::WeakPtr<HostResolverImpl> resolver_; |
1033 | 1184 |
1034 // Maximum number of concurrent jobs allowed to be started for requests | 1185 Key key_; |
1035 // belonging to this pool. | 1186 |
1036 size_t max_outstanding_jobs_; | 1187 // Tracks the highest priority across |requests_|. |
1037 | 1188 PriorityTracker priority_tracker_; |
1038 // The current number of running jobs that were started for requests | 1189 |
1039 // belonging to this pool. | 1190 bool had_non_speculative_request_; |
1040 size_t num_outstanding_jobs_; | 1191 |
1041 | 1192 BoundNetLog net_log_; |
1042 // The maximum number of requests we allow to be waiting on a job, | 1193 |
1043 // for this pool. | 1194 // Store result here in case the job fails fast in Resolve(). |
1044 size_t max_pending_requests_; | 1195 int net_error_; |
1045 | 1196 int os_error_; |
1046 // The requests which are waiting to be started for this pool. | 1197 |
1047 PendingRequestsQueue pending_requests_[NUM_PRIORITIES]; | 1198 // A ProcTask created and started when this Job is dispatched.. |
| 1199 scoped_refptr<ProcTask> proc_task_; |
| 1200 |
| 1201 // All Requests waiting for the result of this Job. Some can be canceled. |
| 1202 RequestsList requests_; |
| 1203 |
| 1204 // A handle used by HostResolverImpl in |dispatcher_|. |
| 1205 PrioritizedDispatcher::Handle handle_; |
1048 }; | 1206 }; |
1049 | 1207 |
1050 //----------------------------------------------------------------------------- | 1208 //----------------------------------------------------------------------------- |
1051 | 1209 |
| 1210 HostResolverImpl::ProcTaskParams::ProcTaskParams( |
| 1211 HostResolverProc* resolver_proc, |
| 1212 size_t max_retry_attempts) |
| 1213 : resolver_proc(resolver_proc), |
| 1214 max_retry_attempts(max_retry_attempts), |
| 1215 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)), |
| 1216 retry_factor(2) { |
| 1217 } |
| 1218 |
| 1219 HostResolverImpl::ProcTaskParams::~ProcTaskParams() {} |
| 1220 |
1052 HostResolverImpl::HostResolverImpl( | 1221 HostResolverImpl::HostResolverImpl( |
1053 HostResolverProc* resolver_proc, | |
1054 HostCache* cache, | 1222 HostCache* cache, |
1055 size_t max_jobs, | 1223 const PrioritizedDispatcher::Limits& job_limits, |
1056 size_t max_retry_attempts, | 1224 const ProcTaskParams& proc_params, |
1057 NetLog* net_log) | 1225 NetLog* net_log) |
1058 : cache_(cache), | 1226 : cache_(cache), |
1059 max_jobs_(max_jobs), | 1227 dispatcher_(job_limits), |
1060 max_retry_attempts_(max_retry_attempts), | 1228 max_queued_jobs_(job_limits.total_jobs * 100u), |
1061 unresponsive_delay_(base::TimeDelta::FromMilliseconds(6000)), | 1229 proc_params_(proc_params), |
1062 retry_factor_(2), | |
1063 next_job_id_(0), | |
1064 resolver_proc_(resolver_proc), | |
1065 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED), | 1230 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED), |
1066 ipv6_probe_monitoring_(false), | 1231 ipv6_probe_monitoring_(false), |
1067 additional_resolver_flags_(0), | 1232 additional_resolver_flags_(0), |
1068 net_log_(net_log) { | 1233 net_log_(net_log) { |
1069 DCHECK_GT(max_jobs, 0u); | 1234 |
| 1235 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES)); |
1070 | 1236 |
1071 // Maximum of 4 retry attempts for host resolution. | 1237 // Maximum of 4 retry attempts for host resolution. |
1072 static const size_t kDefaultMaxRetryAttempts = 4u; | 1238 static const size_t kDefaultMaxRetryAttempts = 4u; |
1073 | 1239 |
1074 if (max_retry_attempts_ == HostResolver::kDefaultRetryAttempts) | 1240 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts) |
1075 max_retry_attempts_ = kDefaultMaxRetryAttempts; | 1241 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts; |
1076 | |
1077 // It is cumbersome to expose all of the constraints in the constructor, | |
1078 // so we choose some defaults, which users can override later. | |
1079 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs); | |
1080 | 1242 |
1081 #if defined(OS_WIN) | 1243 #if defined(OS_WIN) |
1082 EnsureWinsockInit(); | 1244 EnsureWinsockInit(); |
1083 #endif | 1245 #endif |
1084 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 1246 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
1085 if (HaveOnlyLoopbackAddresses()) | 1247 if (HaveOnlyLoopbackAddresses()) |
1086 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY; | 1248 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY; |
1087 #endif | 1249 #endif |
1088 NetworkChangeNotifier::AddIPAddressObserver(this); | 1250 NetworkChangeNotifier::AddIPAddressObserver(this); |
1089 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) | 1251 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) |
1090 #if !defined(OS_ANDROID) | 1252 #if !defined(OS_ANDROID) |
1091 EnsureDnsReloaderInit(); | 1253 EnsureDnsReloaderInit(); |
1092 #endif | 1254 #endif |
1093 NetworkChangeNotifier::AddDNSObserver(this); | 1255 NetworkChangeNotifier::AddDNSObserver(this); |
1094 #endif | 1256 #endif |
1095 } | 1257 } |
1096 | 1258 |
1097 HostResolverImpl::~HostResolverImpl() { | 1259 HostResolverImpl::~HostResolverImpl() { |
1098 // Cancel the outstanding jobs. Those jobs may contain several attached | |
1099 // requests, which will also be cancelled. | |
1100 DiscardIPv6ProbeJob(); | 1260 DiscardIPv6ProbeJob(); |
1101 | 1261 |
1102 CancelAllJobs(); | 1262 // This will also cancel all outstanding requests. |
1103 | 1263 STLDeleteValues(&jobs_); |
1104 // In case we are being deleted during the processing of a callback. | |
1105 if (cur_completing_job_) | |
1106 cur_completing_job_->Cancel(); | |
1107 | 1264 |
1108 NetworkChangeNotifier::RemoveIPAddressObserver(this); | 1265 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
1109 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) | 1266 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) |
1110 NetworkChangeNotifier::RemoveDNSObserver(this); | 1267 NetworkChangeNotifier::RemoveDNSObserver(this); |
1111 #endif | 1268 #endif |
1112 | |
1113 // Delete the job pools. | |
1114 for (size_t i = 0u; i < arraysize(job_pools_); ++i) | |
1115 delete job_pools_[i]; | |
1116 } | 1269 } |
1117 | 1270 |
1118 void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index, | 1271 void HostResolverImpl::SetMaxQueuedJobs(size_t value) { |
1119 size_t max_outstanding_jobs, | 1272 DCHECK_EQ(0u, dispatcher_.num_queued_jobs()); |
1120 size_t max_pending_requests) { | 1273 DCHECK_GT(value, 0u); |
1121 DCHECK(CalledOnValidThread()); | 1274 max_queued_jobs_ = value; |
1122 CHECK_GE(pool_index, 0); | |
1123 CHECK_LT(pool_index, POOL_COUNT); | |
1124 CHECK(jobs_.empty()) << "Can only set constraints during setup"; | |
1125 JobPool* pool = job_pools_[pool_index]; | |
1126 pool->SetConstraints(max_outstanding_jobs, max_pending_requests); | |
1127 } | 1275 } |
1128 | 1276 |
1129 int HostResolverImpl::Resolve(const RequestInfo& info, | 1277 int HostResolverImpl::Resolve(const RequestInfo& info, |
1130 AddressList* addresses, | 1278 AddressList* addresses, |
1131 const CompletionCallback& callback, | 1279 const CompletionCallback& callback, |
1132 RequestHandle* out_req, | 1280 RequestHandle* out_req, |
1133 const BoundNetLog& source_net_log) { | 1281 const BoundNetLog& source_net_log) { |
1134 DCHECK(addresses); | 1282 DCHECK(addresses); |
1135 DCHECK(CalledOnValidThread()); | 1283 DCHECK(CalledOnValidThread()); |
1136 DCHECK_EQ(false, callback.is_null()); | 1284 DCHECK_EQ(false, callback.is_null()); |
1137 | 1285 |
1138 // Make a log item for the request. | 1286 // Make a log item for the request. |
1139 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, | 1287 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, |
1140 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST); | 1288 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST); |
1141 | 1289 |
1142 // Update the net log and notify registered observers. | 1290 LogStartRequest(source_net_log, request_net_log, info); |
1143 OnStartRequest(source_net_log, request_net_log, info); | |
1144 | 1291 |
1145 // Build a key that identifies the request in the cache and in the | 1292 // Build a key that identifies the request in the cache and in the |
1146 // outstanding jobs map. | 1293 // outstanding jobs map. |
1147 Key key = GetEffectiveKeyForRequest(info); | 1294 Key key = GetEffectiveKeyForRequest(info); |
1148 | 1295 |
1149 int rv = ResolveHelper(key, info, addresses, request_net_log); | 1296 int rv = ResolveHelper(key, info, addresses, request_net_log); |
1150 if (rv != ERR_DNS_CACHE_MISS) { | 1297 if (rv != ERR_DNS_CACHE_MISS) { |
1151 OnFinishRequest(source_net_log, request_net_log, info, | 1298 LogFinishRequest(source_net_log, request_net_log, info, rv, |
1152 rv, | 1299 0 /* os_error (unknown since from cache) */); |
1153 0 /* os_error (unknown since from cache) */); | |
1154 return rv; | 1300 return rv; |
1155 } | 1301 } |
1156 | 1302 |
1157 // Create a handle for this request, and pass it back to the user if they | 1303 // Next we need to attach our request to a "job". This job is responsible for |
1158 // asked for it (out_req != NULL). | 1304 // calling "getaddrinfo(hostname)" on a worker thread. |
1159 Request* req = new Request(source_net_log, request_net_log, info, | 1305 |
1160 callback, addresses); | 1306 JobMap::iterator jobit = jobs_.find(key); |
| 1307 Job* job; |
| 1308 if (jobit == jobs_.end()) { |
| 1309 // Create new Job. |
| 1310 job = new Job(this, key, request_net_log); |
| 1311 job->set_handle(dispatcher_.Add(job, info.priority())); |
| 1312 |
| 1313 // Check for queue overflow. |
| 1314 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { |
| 1315 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); |
| 1316 DCHECK(evicted); |
| 1317 if (evicted == job) { |
| 1318 delete job; |
| 1319 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; |
| 1320 LogFinishRequest(source_net_log, request_net_log, info, rv, 0); |
| 1321 return rv; |
| 1322 } |
| 1323 evicted->OnEvicted(); // Deletes |evicted|. |
| 1324 } |
| 1325 |
| 1326 jobs_.insert(jobit, std::make_pair(key, job)); |
| 1327 } else { |
| 1328 job = jobit->second; |
| 1329 } |
| 1330 |
| 1331 // Can't complete synchronously. Create and attach request. |
| 1332 Request* req = new Request(source_net_log, request_net_log, info, callback, |
| 1333 addresses); |
| 1334 job->AddRequest(req); |
| 1335 if (!job->handle().is_null()) |
| 1336 job->set_handle(dispatcher_.ChangePriority(job->handle(), job->priority())); |
1161 if (out_req) | 1337 if (out_req) |
1162 *out_req = reinterpret_cast<RequestHandle>(req); | 1338 *out_req = reinterpret_cast<RequestHandle>(req); |
1163 | 1339 |
1164 // Next we need to attach our request to a "job". This job is responsible for | 1340 DCHECK_EQ(ERR_IO_PENDING, job->net_error()); |
1165 // calling "getaddrinfo(hostname)" on a worker thread. | 1341 // Completion happens during Job::CompleteRequests(). |
1166 scoped_refptr<Job> job; | |
1167 | |
1168 // If there is already an outstanding job to resolve |key|, use | |
1169 // it. This prevents starting concurrent resolves for the same hostname. | |
1170 job = FindOutstandingJob(key); | |
1171 if (job) { | |
1172 job->AddRequest(req); | |
1173 } else { | |
1174 JobPool* pool = GetPoolForRequest(req); | |
1175 if (CanCreateJobForPool(*pool)) { | |
1176 CreateAndStartJob(req); | |
1177 } else { | |
1178 return EnqueueRequest(pool, req); | |
1179 } | |
1180 } | |
1181 | |
1182 // Completion happens during OnJobComplete(Job*). | |
1183 return ERR_IO_PENDING; | 1342 return ERR_IO_PENDING; |
1184 } | 1343 } |
1185 | 1344 |
1186 int HostResolverImpl::ResolveHelper(const Key& key, | 1345 int HostResolverImpl::ResolveHelper(const Key& key, |
1187 const RequestInfo& info, | 1346 const RequestInfo& info, |
1188 AddressList* addresses, | 1347 AddressList* addresses, |
1189 const BoundNetLog& request_net_log) { | 1348 const BoundNetLog& request_net_log) { |
1190 // The result of |getaddrinfo| for empty hosts is inconsistent across systems. | 1349 // The result of |getaddrinfo| for empty hosts is inconsistent across systems. |
1191 // On Windows it gives the default interface's address, whereas on Linux it | 1350 // On Windows it gives the default interface's address, whereas on Linux it |
1192 // gives an error. We will make it fail on all platforms for consistency. | 1351 // gives an error. We will make it fail on all platforms for consistency. |
(...skipping 12 matching lines...) Expand all Loading... |
1205 AddressList* addresses, | 1364 AddressList* addresses, |
1206 const BoundNetLog& source_net_log) { | 1365 const BoundNetLog& source_net_log) { |
1207 DCHECK(CalledOnValidThread()); | 1366 DCHECK(CalledOnValidThread()); |
1208 DCHECK(addresses); | 1367 DCHECK(addresses); |
1209 | 1368 |
1210 // Make a log item for the request. | 1369 // Make a log item for the request. |
1211 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, | 1370 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, |
1212 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST); | 1371 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST); |
1213 | 1372 |
1214 // Update the net log and notify registered observers. | 1373 // Update the net log and notify registered observers. |
1215 OnStartRequest(source_net_log, request_net_log, info); | 1374 LogStartRequest(source_net_log, request_net_log, info); |
1216 | 1375 |
1217 // Build a key that identifies the request in the cache and in the | |
1218 // outstanding jobs map. | |
1219 Key key = GetEffectiveKeyForRequest(info); | 1376 Key key = GetEffectiveKeyForRequest(info); |
1220 | 1377 |
1221 int rv = ResolveHelper(key, info, addresses, request_net_log); | 1378 int rv = ResolveHelper(key, info, addresses, request_net_log); |
1222 OnFinishRequest(source_net_log, request_net_log, info, | 1379 LogFinishRequest(source_net_log, request_net_log, info, rv, |
1223 rv, | 1380 0 /* os_error (unknown since from cache) */); |
1224 0 /* os_error (unknown since from cache) */); | |
1225 return rv; | 1381 return rv; |
1226 } | 1382 } |
1227 | 1383 |
1228 // See OnJobComplete(Job*) for why it is important not to clean out | |
1229 // cancelled requests from Job::requests_. | |
1230 void HostResolverImpl::CancelRequest(RequestHandle req_handle) { | 1384 void HostResolverImpl::CancelRequest(RequestHandle req_handle) { |
1231 DCHECK(CalledOnValidThread()); | 1385 DCHECK(CalledOnValidThread()); |
1232 Request* req = reinterpret_cast<Request*>(req_handle); | 1386 Request* req = reinterpret_cast<Request*>(req_handle); |
1233 DCHECK(req); | 1387 DCHECK(req); |
1234 | 1388 |
1235 scoped_ptr<Request> request_deleter; // Frees at end of function. | 1389 Job* job = req->job(); |
| 1390 DCHECK(job); |
1236 | 1391 |
1237 if (!req->job()) { | 1392 job->CancelRequest(req); |
1238 // If the request was not attached to a job yet, it must have been | 1393 |
1239 // enqueued into a pool. Remove it from that pool's queue. | 1394 if (!job->handle().is_null()) { |
1240 // Otherwise if it was attached to a job, the job is responsible for | 1395 // Still in queue. |
1241 // deleting it. | 1396 if (job->num_active_requests()) { |
1242 JobPool* pool = GetPoolForRequest(req); | 1397 job->set_handle(dispatcher_.ChangePriority(job->handle(), |
1243 pool->RemovePendingRequest(req); | 1398 job->priority())); |
1244 request_deleter.reset(req); | 1399 } else { |
| 1400 dispatcher_.Cancel(job->handle()); |
| 1401 RemoveJob(job); |
| 1402 delete job; |
| 1403 } |
1245 } else { | 1404 } else { |
1246 req->request_net_log().EndEvent( | 1405 // Job is running (and could be in CompleteRequests right now). |
1247 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL); | 1406 // But to be in Request::OnComplete we would have to have a non-canceled |
| 1407 // request. So it is safe to Abort it if it has no more active requests. |
| 1408 if (!job->num_active_requests()) { |
| 1409 job->Abort(); |
| 1410 } |
1248 } | 1411 } |
1249 | |
1250 // NULL out the fields of req, to mark it as cancelled. | |
1251 req->MarkAsCancelled(); | |
1252 OnCancelRequest(req->source_net_log(), req->request_net_log(), req->info()); | |
1253 } | 1412 } |
1254 | 1413 |
1255 void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) { | 1414 void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) { |
1256 DCHECK(CalledOnValidThread()); | 1415 DCHECK(CalledOnValidThread()); |
1257 ipv6_probe_monitoring_ = false; | 1416 ipv6_probe_monitoring_ = false; |
1258 DiscardIPv6ProbeJob(); | 1417 DiscardIPv6ProbeJob(); |
1259 default_address_family_ = address_family; | 1418 default_address_family_ = address_family; |
1260 } | 1419 } |
1261 | 1420 |
1262 AddressFamily HostResolverImpl::GetDefaultAddressFamily() const { | 1421 AddressFamily HostResolverImpl::GetDefaultAddressFamily() const { |
(...skipping 18 matching lines...) Expand all Loading... |
1281 DCHECK(addresses); | 1440 DCHECK(addresses); |
1282 DCHECK(net_error); | 1441 DCHECK(net_error); |
1283 IPAddressNumber ip_number; | 1442 IPAddressNumber ip_number; |
1284 if (!ParseIPLiteralToNumber(key.hostname, &ip_number)) | 1443 if (!ParseIPLiteralToNumber(key.hostname, &ip_number)) |
1285 return false; | 1444 return false; |
1286 | 1445 |
1287 DCHECK_EQ(key.host_resolver_flags & | 1446 DCHECK_EQ(key.host_resolver_flags & |
1288 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY | | 1447 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY | |
1289 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6), | 1448 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6), |
1290 0) << " Unhandled flag"; | 1449 0) << " Unhandled flag"; |
1291 bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 && | 1450 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) && |
1292 !ipv6_probe_monitoring_; | 1451 !ipv6_probe_monitoring_; |
1293 *net_error = OK; | 1452 *net_error = OK; |
1294 if (ip_number.size() == 16 && ipv6_disabled) { | 1453 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) { |
1295 *net_error = ERR_NAME_NOT_RESOLVED; | 1454 *net_error = ERR_NAME_NOT_RESOLVED; |
1296 } else { | 1455 } else { |
1297 *addresses = AddressList::CreateFromIPAddressWithCname( | 1456 *addresses = AddressList::CreateFromIPAddressWithCname( |
1298 ip_number, info.port(), | 1457 ip_number, info.port(), |
1299 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)); | 1458 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)); |
1300 } | 1459 } |
1301 return true; | 1460 return true; |
1302 } | 1461 } |
1303 | 1462 |
1304 bool HostResolverImpl::ServeFromCache(const Key& key, | 1463 bool HostResolverImpl::ServeFromCache(const Key& key, |
(...skipping 11 matching lines...) Expand all Loading... |
1316 if (!cache_entry) | 1475 if (!cache_entry) |
1317 return false; | 1476 return false; |
1318 | 1477 |
1319 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL); | 1478 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL); |
1320 *net_error = cache_entry->error; | 1479 *net_error = cache_entry->error; |
1321 if (*net_error == OK) | 1480 if (*net_error == OK) |
1322 *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port()); | 1481 *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port()); |
1323 return true; | 1482 return true; |
1324 } | 1483 } |
1325 | 1484 |
1326 void HostResolverImpl::AddOutstandingJob(Job* job) { | 1485 void HostResolverImpl::OnJobFinished(Job* job, const AddressList& addrlist) { |
1327 scoped_refptr<Job>& found_job = jobs_[job->key()]; | 1486 DCHECK(job); |
1328 DCHECK(!found_job); | 1487 DCHECK(job->handle().is_null()); |
1329 found_job = job; | 1488 RemoveJob(job); |
| 1489 if (job->net_error() == ERR_HOST_RESOLVER_QUEUE_TOO_LARGE) |
| 1490 return; |
1330 | 1491 |
1331 JobPool* pool = GetPoolForRequest(job->initial_request()); | 1492 // Signal dispatcher that a slot has opened. |
1332 pool->AdjustNumOutstandingJobs(1); | 1493 dispatcher_.OnJobFinished(); |
1333 } | 1494 if (job->net_error() == ERR_ABORTED) |
1334 | 1495 return; |
1335 HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) { | |
1336 JobMap::iterator it = jobs_.find(key); | |
1337 if (it != jobs_.end()) | |
1338 return it->second; | |
1339 return NULL; | |
1340 } | |
1341 | |
1342 void HostResolverImpl::RemoveOutstandingJob(Job* job) { | |
1343 JobMap::iterator it = jobs_.find(job->key()); | |
1344 DCHECK(it != jobs_.end()); | |
1345 DCHECK_EQ(it->second.get(), job); | |
1346 jobs_.erase(it); | |
1347 | |
1348 JobPool* pool = GetPoolForRequest(job->initial_request()); | |
1349 pool->AdjustNumOutstandingJobs(-1); | |
1350 } | |
1351 | |
1352 void HostResolverImpl::OnJobComplete(Job* job, | |
1353 int net_error, | |
1354 int os_error, | |
1355 const AddressList& addrlist) { | |
1356 RemoveOutstandingJob(job); | |
1357 | |
1358 // Write result to the cache. | 1496 // Write result to the cache. |
1359 if (cache_.get()) { | 1497 if (cache_.get()) { |
1360 base::TimeDelta ttl = base::TimeDelta::FromSeconds(0); | 1498 base::TimeDelta ttl = base::TimeDelta::FromSeconds(0); |
1361 if (net_error == OK) | 1499 if (job->net_error() == OK) |
1362 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); | 1500 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); |
1363 cache_->Set(job->key(), net_error, addrlist, | 1501 cache_->Set(job->key(), job->net_error(), addrlist, |
1364 base::TimeTicks::Now(), | 1502 base::TimeTicks::Now(), ttl); |
1365 ttl); | |
1366 } | 1503 } |
1367 OnJobCompleteInternal(job, net_error, os_error, addrlist); | |
1368 } | 1504 } |
1369 | 1505 |
1370 void HostResolverImpl::AbortJob(Job* job) { | 1506 void HostResolverImpl::RemoveJob(Job* job) { |
1371 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList()); | 1507 DCHECK(job); |
1372 } | 1508 jobs_.erase(job->key()); |
1373 | |
1374 void HostResolverImpl::OnJobCompleteInternal( | |
1375 Job* job, | |
1376 int net_error, | |
1377 int os_error, | |
1378 const AddressList& addrlist) { | |
1379 // Make a note that we are executing within OnJobComplete() in case the | |
1380 // HostResolver is deleted by a callback invocation. | |
1381 DCHECK(!cur_completing_job_); | |
1382 cur_completing_job_ = job; | |
1383 | |
1384 // Try to start any queued requests now that a job-slot has freed up. | |
1385 ProcessQueuedRequests(); | |
1386 | |
1387 // Complete all of the requests that were attached to the job. | |
1388 for (RequestsList::const_iterator it = job->requests().begin(); | |
1389 it != job->requests().end(); ++it) { | |
1390 Request* req = *it; | |
1391 if (!req->was_cancelled()) { | |
1392 DCHECK_EQ(job, req->job()); | |
1393 req->request_net_log().EndEvent( | |
1394 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL); | |
1395 | |
1396 // Update the net log and notify registered observers. | |
1397 OnFinishRequest(req->source_net_log(), req->request_net_log(), | |
1398 req->info(), net_error, os_error); | |
1399 | |
1400 req->OnComplete(net_error, addrlist); | |
1401 | |
1402 // Check if the job was cancelled as a result of running the callback. | |
1403 // (Meaning that |this| was deleted). | |
1404 if (job->was_cancelled()) | |
1405 return; | |
1406 } | |
1407 } | |
1408 | |
1409 cur_completing_job_ = NULL; | |
1410 } | |
1411 | |
1412 void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log, | |
1413 const BoundNetLog& request_net_log, | |
1414 const RequestInfo& info) { | |
1415 source_net_log.BeginEvent( | |
1416 NetLog::TYPE_HOST_RESOLVER_IMPL, | |
1417 make_scoped_refptr(new NetLogSourceParameter( | |
1418 "source_dependency", request_net_log.source()))); | |
1419 | |
1420 request_net_log.BeginEvent( | |
1421 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, | |
1422 make_scoped_refptr(new RequestInfoParameters( | |
1423 info, source_net_log.source()))); | |
1424 } | |
1425 | |
1426 void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log, | |
1427 const BoundNetLog& request_net_log, | |
1428 const RequestInfo& info, | |
1429 int net_error, | |
1430 int os_error) { | |
1431 bool was_resolved = net_error == OK; | |
1432 | |
1433 // Log some extra parameters on failure for synchronous requests. | |
1434 scoped_refptr<NetLog::EventParameters> params; | |
1435 if (!was_resolved) { | |
1436 params = new HostResolveFailedParams(0, net_error, os_error); | |
1437 } | |
1438 | |
1439 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params); | |
1440 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL); | |
1441 } | |
1442 | |
1443 void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log, | |
1444 const BoundNetLog& request_net_log, | |
1445 const RequestInfo& info) { | |
1446 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL); | |
1447 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL); | |
1448 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL); | |
1449 } | 1509 } |
1450 | 1510 |
1451 void HostResolverImpl::DiscardIPv6ProbeJob() { | 1511 void HostResolverImpl::DiscardIPv6ProbeJob() { |
1452 if (ipv6_probe_job_.get()) { | 1512 if (ipv6_probe_job_.get()) { |
1453 ipv6_probe_job_->Cancel(); | 1513 ipv6_probe_job_->Cancel(); |
1454 ipv6_probe_job_ = NULL; | 1514 ipv6_probe_job_ = NULL; |
1455 } | 1515 } |
1456 } | 1516 } |
1457 | 1517 |
1458 void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily( | 1518 void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily( |
1459 AddressFamily address_family) { | 1519 AddressFamily address_family) { |
1460 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED || | 1520 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED || |
1461 address_family == ADDRESS_FAMILY_IPV4); | 1521 address_family == ADDRESS_FAMILY_IPV4); |
1462 if (default_address_family_ != address_family) { | 1522 if (default_address_family_ != address_family) { |
1463 VLOG(1) << "IPv6Probe forced AddressFamily setting to " | 1523 VLOG(1) << "IPv6Probe forced AddressFamily setting to " |
1464 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ? | 1524 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ? |
1465 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4"); | 1525 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4"); |
1466 } | 1526 } |
1467 default_address_family_ = address_family; | 1527 default_address_family_ = address_family; |
1468 // Drop reference since the job has called us back. | 1528 // Drop reference since the job has called us back. |
1469 DiscardIPv6ProbeJob(); | 1529 DiscardIPv6ProbeJob(); |
1470 } | 1530 } |
1471 | 1531 |
1472 bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const { | |
1473 DCHECK_LE(jobs_.size(), max_jobs_); | |
1474 | |
1475 // We can't create another job if it would exceed the global total. | |
1476 if (jobs_.size() + 1 > max_jobs_) | |
1477 return false; | |
1478 | |
1479 // Check whether the pool's constraints are met. | |
1480 return pool.CanCreateJob(); | |
1481 } | |
1482 | |
1483 // static | |
1484 HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest( | |
1485 const Request* req) { | |
1486 return POOL_NORMAL; | |
1487 } | |
1488 | |
1489 void HostResolverImpl::ProcessQueuedRequests() { | |
1490 // Find the highest priority request that can be scheduled. | |
1491 Request* top_req = NULL; | |
1492 for (size_t i = 0; i < arraysize(job_pools_); ++i) { | |
1493 JobPool* pool = job_pools_[i]; | |
1494 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) { | |
1495 top_req = pool->RemoveTopPendingRequest(); | |
1496 break; | |
1497 } | |
1498 } | |
1499 | |
1500 if (!top_req) | |
1501 return; | |
1502 | |
1503 scoped_refptr<Job> job(CreateAndStartJob(top_req)); | |
1504 | |
1505 // Search for any other pending request which can piggy-back off this job. | |
1506 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) { | |
1507 JobPool* pool = job_pools_[pool_i]; | |
1508 pool->MoveRequestsToJob(job); | |
1509 } | |
1510 } | |
1511 | |
1512 HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest( | 1532 HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest( |
1513 const RequestInfo& info) const { | 1533 const RequestInfo& info) const { |
1514 HostResolverFlags effective_flags = | 1534 HostResolverFlags effective_flags = |
1515 info.host_resolver_flags() | additional_resolver_flags_; | 1535 info.host_resolver_flags() | additional_resolver_flags_; |
1516 AddressFamily effective_address_family = info.address_family(); | 1536 AddressFamily effective_address_family = info.address_family(); |
1517 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED && | 1537 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED && |
1518 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) { | 1538 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) { |
1519 effective_address_family = default_address_family_; | 1539 effective_address_family = default_address_family_; |
1520 if (ipv6_probe_monitoring_) | 1540 if (ipv6_probe_monitoring_) |
1521 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; | 1541 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; |
1522 } | 1542 } |
1523 return Key(info.hostname(), effective_address_family, effective_flags); | 1543 return Key(info.hostname(), effective_address_family, effective_flags); |
1524 } | 1544 } |
1525 | 1545 |
1526 HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) { | |
1527 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req))); | |
1528 Key key = GetEffectiveKeyForRequest(req->info()); | |
1529 | |
1530 req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, | |
1531 NULL); | |
1532 | |
1533 scoped_refptr<Job> job(new Job(next_job_id_++, this, key, | |
1534 req->request_net_log(), net_log_)); | |
1535 job->AddRequest(req); | |
1536 AddOutstandingJob(job); | |
1537 job->Start(); | |
1538 | |
1539 return job.get(); | |
1540 } | |
1541 | |
1542 int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) { | |
1543 scoped_ptr<Request> req_evicted_from_queue( | |
1544 pool->InsertPendingRequest(req)); | |
1545 | |
1546 // If the queue has become too large, we need to kick something out. | |
1547 if (req_evicted_from_queue.get()) { | |
1548 Request* r = req_evicted_from_queue.get(); | |
1549 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; | |
1550 | |
1551 OnFinishRequest(r->source_net_log(), r->request_net_log(), r->info(), error, | |
1552 0 /* os_error (not applicable) */); | |
1553 | |
1554 if (r == req) | |
1555 return error; | |
1556 | |
1557 r->OnComplete(error, AddressList()); | |
1558 } | |
1559 | |
1560 return ERR_IO_PENDING; | |
1561 } | |
1562 | |
1563 void HostResolverImpl::CancelAllJobs() { | |
1564 JobMap jobs; | |
1565 jobs.swap(jobs_); | |
1566 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) | |
1567 it->second->Cancel(); | |
1568 } | |
1569 | |
1570 void HostResolverImpl::AbortAllInProgressJobs() { | 1546 void HostResolverImpl::AbortAllInProgressJobs() { |
1571 for (size_t i = 0; i < arraysize(job_pools_); ++i) | 1547 base::WeakPtr<HostResolverImpl> self = AsWeakPtr(); |
1572 job_pools_[i]->ResetNumOutstandingJobs(); | 1548 // Scan |jobs_| for running jobs and abort them. |
1573 JobMap jobs; | 1549 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) { |
1574 jobs.swap(jobs_); | 1550 Job* job = it->second; |
1575 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) { | 1551 // Advance the iterator before we might erase it. |
1576 AbortJob(it->second); | 1552 ++it; |
1577 it->second->Cancel(); | 1553 if (job->is_running()) { |
| 1554 job->Abort(); |
| 1555 // Check if resolver was deleted in a request callback. |
| 1556 if (!self) |
| 1557 return; |
| 1558 } else { |
| 1559 // Keep it in |dispatch_|. |
| 1560 DCHECK(!job->handle().is_null()); |
| 1561 } |
1578 } | 1562 } |
1579 } | 1563 } |
1580 | 1564 |
1581 void HostResolverImpl::OnIPAddressChanged() { | 1565 void HostResolverImpl::OnIPAddressChanged() { |
1582 if (cache_.get()) | 1566 if (cache_.get()) |
1583 cache_->clear(); | 1567 cache_->clear(); |
1584 if (ipv6_probe_monitoring_) { | 1568 if (ipv6_probe_monitoring_) { |
1585 DiscardIPv6ProbeJob(); | 1569 DiscardIPv6ProbeJob(); |
1586 ipv6_probe_job_ = new IPv6ProbeJob(this); | 1570 ipv6_probe_job_ = new IPv6ProbeJob(this); |
1587 ipv6_probe_job_->Start(); | 1571 ipv6_probe_job_->Start(); |
(...skipping 16 matching lines...) Expand all Loading... |
1604 // resolv.conf changes so we don't need to do anything to clear that cache. | 1588 // resolv.conf changes so we don't need to do anything to clear that cache. |
1605 if (cache_.get()) | 1589 if (cache_.get()) |
1606 cache_->clear(); | 1590 cache_->clear(); |
1607 // Existing jobs will have been sent to the original server so they need to | 1591 // Existing jobs will have been sent to the original server so they need to |
1608 // be aborted. TODO(Craig): Should these jobs be restarted? | 1592 // be aborted. TODO(Craig): Should these jobs be restarted? |
1609 AbortAllInProgressJobs(); | 1593 AbortAllInProgressJobs(); |
1610 // |this| may be deleted inside AbortAllInProgressJobs(). | 1594 // |this| may be deleted inside AbortAllInProgressJobs(). |
1611 } | 1595 } |
1612 | 1596 |
1613 } // namespace net | 1597 } // namespace net |
OLD | NEW |