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

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