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

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

Issue 9101011: [net/dns] Refactoring of job dispatch in HostResolverImpl in preparation for DnsTransactionFactory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed license header for the presubmit check.' Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/host_resolver_impl.h ('k') | net/base/host_resolver_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/base/host_resolver_impl.h ('k') | net/base/host_resolver_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698