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