summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/connection_tester.cc10
-rw-r--r--chrome/browser/net/passive_log_collector.cc54
-rw-r--r--chrome/browser/net/passive_log_collector.h35
-rw-r--r--chrome/browser/resources/net_internals/events_view.css11
-rw-r--r--chrome/browser/resources/net_internals/source_entry.js3
-rw-r--r--net/base/host_resolver.h8
-rw-r--r--net/base/host_resolver_impl.cc1348
-rw-r--r--net/base/host_resolver_impl.h270
-rw-r--r--net/base/host_resolver_impl_unittest.cc146
-rw-r--r--net/base/net_log_event_type_list.h86
-rw-r--r--net/base/net_log_source_type_list.h24
11 files changed, 984 insertions, 1011 deletions
diff --git a/chrome/browser/net/connection_tester.cc b/chrome/browser/net/connection_tester.cc
index 63af8d1..00e7482 100644
--- a/chrome/browser/net/connection_tester.cc
+++ b/chrome/browser/net/connection_tester.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -17,7 +17,6 @@
#include "net/base/cert_verifier.h"
#include "net/base/cookie_monster.h"
#include "net/base/host_resolver.h"
-#include "net/base/host_resolver_impl.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -110,9 +109,10 @@ class ExperimentURLRequestContext : public net::URLRequestContext {
// Create a vanilla HostResolver that disables caching.
const size_t kMaxJobs = 50u;
const size_t kMaxRetryAttempts = 4u;
- net::HostResolverImpl* impl =
- new net::HostResolverImpl(NULL, NULL, kMaxJobs, kMaxRetryAttempts,
- NULL);
+ net::HostResolver* impl = net::CreateNonCachingSystemHostResolver(
+ kMaxJobs,
+ kMaxRetryAttempts,
+ NULL /* NetLog */);
host_resolver->reset(impl);
diff --git a/chrome/browser/net/passive_log_collector.cc b/chrome/browser/net/passive_log_collector.cc
index d7b93e0..9ca4b63 100644
--- a/chrome/browser/net/passive_log_collector.cc
+++ b/chrome/browser/net/passive_log_collector.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -72,6 +72,8 @@ PassiveLogCollector::PassiveLogCollector()
trackers_[net::NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST] =
&dns_request_tracker_;
trackers_[net::NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB] = &dns_job_tracker_;
+ trackers_[net::NetLog::SOURCE_HOST_RESOLVER_IMPL_PROC_TASK] =
+ &dns_proc_task_tracker_;
trackers_[net::NetLog::SOURCE_DISK_CACHE_ENTRY] = &disk_cache_entry_tracker_;
trackers_[net::NetLog::SOURCE_MEMORY_CACHE_ENTRY] = &mem_cache_entry_tracker_;
trackers_[net::NetLog::SOURCE_HTTP_STREAM_JOB] = &http_stream_job_tracker_;
@@ -536,18 +538,20 @@ PassiveLogCollector::SpdySessionTracker::DoAddEntry(
}
//----------------------------------------------------------------------------
-// DNSRequestTracker
+// HostResolverRequestTracker
//----------------------------------------------------------------------------
-const size_t PassiveLogCollector::DNSRequestTracker::kMaxNumSources = 200;
-const size_t PassiveLogCollector::DNSRequestTracker::kMaxGraveyardSize = 20;
+const size_t
+PassiveLogCollector::HostResolverRequestTracker::kMaxNumSources = 200;
+const size_t
+PassiveLogCollector::HostResolverRequestTracker::kMaxGraveyardSize = 20;
-PassiveLogCollector::DNSRequestTracker::DNSRequestTracker()
+PassiveLogCollector::HostResolverRequestTracker::HostResolverRequestTracker()
: SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::DNSRequestTracker::DoAddEntry(
+PassiveLogCollector::HostResolverRequestTracker::DoAddEntry(
const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST &&
@@ -558,19 +562,21 @@ PassiveLogCollector::DNSRequestTracker::DoAddEntry(
}
//----------------------------------------------------------------------------
-// DNSJobTracker
+// HostResolverJobTracker
//----------------------------------------------------------------------------
-const size_t PassiveLogCollector::DNSJobTracker::kMaxNumSources = 100;
-const size_t PassiveLogCollector::DNSJobTracker::kMaxGraveyardSize = 15;
+const size_t
+PassiveLogCollector::HostResolverJobTracker::kMaxNumSources = 100;
+const size_t
+PassiveLogCollector::HostResolverJobTracker::kMaxGraveyardSize = 15;
-PassiveLogCollector::DNSJobTracker::DNSJobTracker()
+PassiveLogCollector::HostResolverJobTracker::HostResolverJobTracker()
: SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::DNSJobTracker::DoAddEntry(const ChromeNetLog::Entry& entry,
- SourceInfo* out_info) {
+PassiveLogCollector::HostResolverJobTracker::DoAddEntry(
+ const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_JOB &&
entry.phase == net::NetLog::PHASE_END) {
@@ -580,6 +586,30 @@ PassiveLogCollector::DNSJobTracker::DoAddEntry(const ChromeNetLog::Entry& entry,
}
//----------------------------------------------------------------------------
+// HostResolverProcTaskTracker
+//----------------------------------------------------------------------------
+
+const size_t
+PassiveLogCollector::HostResolverProcTaskTracker::kMaxNumSources = 100;
+const size_t
+PassiveLogCollector::HostResolverProcTaskTracker::kMaxGraveyardSize = 15;
+
+PassiveLogCollector::HostResolverProcTaskTracker::HostResolverProcTaskTracker()
+ : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
+}
+
+PassiveLogCollector::SourceTracker::Action
+PassiveLogCollector::HostResolverProcTaskTracker::DoAddEntry(
+ const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
+ AddEntryToSourceInfo(entry, out_info);
+ if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK &&
+ entry.phase == net::NetLog::PHASE_END) {
+ return ACTION_MOVE_TO_GRAVEYARD;
+ }
+ return ACTION_NONE;
+}
+
+//----------------------------------------------------------------------------
// DiskCacheEntryTracker
//----------------------------------------------------------------------------
diff --git a/chrome/browser/net/passive_log_collector.h b/chrome/browser/net/passive_log_collector.h
index b1a079a..2cb9ab4 100644
--- a/chrome/browser/net/passive_log_collector.h
+++ b/chrome/browser/net/passive_log_collector.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -268,33 +268,49 @@ class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserverImpl {
};
// Tracks the log entries for the last seen SOURCE_HOST_RESOLVER_IMPL_REQUEST.
- class DNSRequestTracker : public SourceTracker {
+ class HostResolverRequestTracker : public SourceTracker {
public:
static const size_t kMaxNumSources;
static const size_t kMaxGraveyardSize;
- DNSRequestTracker();
+ HostResolverRequestTracker();
private:
virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
SourceInfo* out_info) OVERRIDE;
- DISALLOW_COPY_AND_ASSIGN(DNSRequestTracker);
+ DISALLOW_COPY_AND_ASSIGN(HostResolverRequestTracker);
};
// Tracks the log entries for the last seen SOURCE_HOST_RESOLVER_IMPL_JOB.
- class DNSJobTracker : public SourceTracker {
+ class HostResolverJobTracker : public SourceTracker {
public:
static const size_t kMaxNumSources;
static const size_t kMaxGraveyardSize;
- DNSJobTracker();
+ HostResolverJobTracker();
private:
virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
SourceInfo* out_info) OVERRIDE;
- DISALLOW_COPY_AND_ASSIGN(DNSJobTracker);
+ DISALLOW_COPY_AND_ASSIGN(HostResolverJobTracker);
+ };
+
+ // Tracks the log entries for the last seen
+ // SOURCE_HOST_RESOLVER_IMPL_PROC_TASK.
+ class HostResolverProcTaskTracker : public SourceTracker {
+ public:
+ static const size_t kMaxNumSources;
+ static const size_t kMaxGraveyardSize;
+
+ HostResolverProcTaskTracker();
+
+ private:
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(HostResolverProcTaskTracker);
};
// Tracks the log entries for the last seen SOURCE_DISK_CACHE_ENTRY.
@@ -464,8 +480,9 @@ class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserverImpl {
RequestTracker socket_stream_tracker_;
ProxyScriptDeciderTracker proxy_script_decider_tracker_;
SpdySessionTracker spdy_session_tracker_;
- DNSRequestTracker dns_request_tracker_;
- DNSJobTracker dns_job_tracker_;
+ HostResolverRequestTracker dns_request_tracker_;
+ HostResolverJobTracker dns_job_tracker_;
+ HostResolverProcTaskTracker dns_proc_task_tracker_;
DiskCacheEntryTracker disk_cache_entry_tracker_;
MemCacheEntryTracker mem_cache_entry_tracker_;
HttpStreamJobTracker http_stream_job_tracker_;
diff --git a/chrome/browser/resources/net_internals/events_view.css b/chrome/browser/resources/net_internals/events_view.css
index 914c72b..3b0c7bb 100644
--- a/chrome/browser/resources/net_internals/events_view.css
+++ b/chrome/browser/resources/net_internals/events_view.css
@@ -1,8 +1,8 @@
-/*
-Copyright (c) 2011 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-*/
+/**
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#events-view-filter-box {
background: #efefef;
@@ -74,6 +74,7 @@ found in the LICENSE file.
#events-view-source-list-tbody .source_HOST_RESOLVER_IMPL_JOB,
#events-view-source-list-tbody .source_HOST_RESOLVER_IMPL_REQUEST,
+#events-view-source-list-tbody .source_HOST_RESOLVER_IMPL_PROC_TASK,
#events-view-source-list-tbody .source_ASYNC_HOST_RESOLVER_REQUEST,
#events-view-source-list-tbody .source_DNS_TRANSACTION {
color: #206060;
diff --git a/chrome/browser/resources/net_internals/source_entry.js b/chrome/browser/resources/net_internals/source_entry.js
index 1a244db..389369b 100644
--- a/chrome/browser/resources/net_internals/source_entry.js
+++ b/chrome/browser/resources/net_internals/source_entry.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -88,6 +88,7 @@ var SourceEntry = (function() {
break;
case LogSourceType.HOST_RESOLVER_IMPL_REQUEST:
case LogSourceType.HOST_RESOLVER_IMPL_JOB:
+ case LogSourceType.HOST_RESOLVER_IMPL_PROC_TASK:
this.description_ = e.params.host;
break;
case LogSourceType.DISK_CACHE_ENTRY:
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index a596610..02b61af 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -182,6 +182,12 @@ NET_EXPORT HostResolver* CreateSystemHostResolver(
size_t max_retry_attempts,
NetLog* net_log);
+// As above, but the created HostResolver does not use a cache.
+NET_EXPORT HostResolver* CreateNonCachingSystemHostResolver(
+ size_t max_concurrent_resolves,
+ size_t max_retry_attempts,
+ NetLog* net_log);
+
// Creates a HostResolver implementation that sends actual DNS queries to
// the specified DNS server and parses response and returns results.
NET_EXPORT HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index c5fc2e7..daf9b04 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -11,12 +11,13 @@
#endif
#include <cmath>
-#include <deque>
+#include <utility>
#include <vector>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/debug/debugger.h"
#include "base/debug/stack_trace.h"
@@ -53,6 +54,12 @@ const size_t kMaxHostLength = 4096;
// Default TTL for successful resolutions with ProcTask.
const unsigned kCacheEntryTTLSeconds = 60;
+// Maximum of 8 concurrent resolver threads (excluding retries).
+// Some routers (or resolvers) appear to start to provide host-not-found if
+// too many simultaneous resolutions are pending. This number needs to be
+// further optimized, but 8 is what FF currently does.
+static const size_t kDefaultMaxProcTasks = 8u;
+
// Helper to mutate the linked list contained by AddressList to the given
// port. Note that in general this is dangerous since the AddressList's
// data might be shared (and you should use AddressList::SetPort).
@@ -129,44 +136,23 @@ std::vector<int> GetAllGetAddrinfoOSErrors() {
arraysize(os_errors));
}
-} // anonymous namespace
-
-// static
-HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
- size_t max_retry_attempts,
- NetLog* net_log) {
- // Maximum of 8 concurrent resolver threads.
- // Some routers (or resolvers) appear to start to provide host-not-found if
- // too many simultaneous resolutions are pending. This number needs to be
- // further optimized, but 8 is what FF currently does.
- static const size_t kDefaultMaxJobs = 8u;
-
- if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
- max_concurrent_resolves = kDefaultMaxJobs;
-
- HostResolverImpl* resolver =
- new HostResolverImpl(NULL, HostCache::CreateDefaultCache(),
- max_concurrent_resolves, max_retry_attempts, net_log);
-
- return resolver;
-}
-
-static int ResolveAddrInfo(HostResolverProc* resolver_proc,
- const std::string& host,
- AddressFamily address_family,
- HostResolverFlags host_resolver_flags,
- AddressList* out,
- int* os_error) {
- if (resolver_proc) {
- // Use the custom procedure.
- return resolver_proc->Resolve(host, address_family,
- host_resolver_flags, out, os_error);
- } else {
- // Use the system procedure (getaddrinfo).
- return SystemHostResolverProc(host, address_family,
- host_resolver_flags, out, os_error);
+// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
+// TODO(szym): This should probably be declared in host_resolver_proc.h.
+class CallSystemHostResolverProc : public HostResolverProc {
+ public:
+ CallSystemHostResolverProc() : HostResolverProc(NULL) {}
+ virtual int Resolve(const std::string& hostname,
+ AddressFamily address_family,
+ HostResolverFlags host_resolver_flags,
+ AddressList* addrlist,
+ int* os_error) OVERRIDE {
+ return SystemHostResolverProc(hostname,
+ address_family,
+ host_resolver_flags,
+ addrlist,
+ os_error);
}
-}
+};
// Extra parameters to attach to the NetLog when the resolve failed.
class HostResolveFailedParams : public NetLog::EventParameters {
@@ -179,7 +165,7 @@ class HostResolveFailedParams : public NetLog::EventParameters {
os_error_(os_error) {
}
- virtual Value* ToValue() const {
+ virtual Value* ToValue() const OVERRIDE {
DictionaryValue* dict = new DictionaryValue();
if (attempt_number_)
dict->SetInteger("attempt_number", attempt_number_);
@@ -223,7 +209,7 @@ class RequestInfoParameters : public NetLog::EventParameters {
const NetLog::Source& source)
: info_(info), source_(source) {}
- virtual Value* ToValue() const {
+ virtual Value* ToValue() const OVERRIDE {
DictionaryValue* dict = new DictionaryValue();
dict->SetString("host", info_.host_port_pair().ToString());
dict->SetInteger("address_family",
@@ -243,13 +229,15 @@ class RequestInfoParameters : public NetLog::EventParameters {
const NetLog::Source source_;
};
-// Parameters associated with the creation of a HostResolverImpl::Job.
+// Parameters associated with the creation of a HostResolverImpl::Job
+// or a HostResolverImpl::ProcTask.
class JobCreationParameters : public NetLog::EventParameters {
public:
- JobCreationParameters(const std::string& host, const NetLog::Source& source)
+ JobCreationParameters(const std::string& host,
+ const NetLog::Source& source)
: host_(host), source_(source) {}
- virtual Value* ToValue() const {
+ virtual Value* ToValue() const OVERRIDE {
DictionaryValue* dict = new DictionaryValue();
dict->SetString("host", host_);
dict->Set("source_dependency", source_.ToValue());
@@ -261,8 +249,164 @@ class JobCreationParameters : public NetLog::EventParameters {
const NetLog::Source source_;
};
+// Parameters of the HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH event.
+class JobAttachParameters : public NetLog::EventParameters {
+ public:
+ JobAttachParameters(const NetLog::Source& source,
+ RequestPriority priority)
+ : source_(source), priority_(priority) {}
+
+ virtual Value* ToValue() const OVERRIDE {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->Set("source_dependency", source_.ToValue());
+ dict->SetInteger("priority", priority_);
+ return dict;
+ }
+
+ private:
+ const NetLog::Source source_;
+ const RequestPriority priority_;
+};
+
+// The logging routines are defined here because some requests are resolved
+// without a Request object.
+
+// Logs when a request has just been started.
+void LogStartRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
+ const HostResolver::RequestInfo& info) {
+ source_net_log.BeginEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL,
+ make_scoped_refptr(new NetLogSourceParameter(
+ "source_dependency", request_net_log.source())));
+
+ request_net_log.BeginEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
+ make_scoped_refptr(new RequestInfoParameters(
+ info, source_net_log.source())));
+}
+
+// Logs when a request has just completed (before its callback is run).
+void LogFinishRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
+ const HostResolver::RequestInfo& info,
+ int net_error,
+ int os_error) {
+ scoped_refptr<NetLog::EventParameters> params;
+ if (net_error != OK) {
+ params = new HostResolveFailedParams(0, net_error, os_error);
+ }
+
+ request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
+ source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
+}
+
+// Logs when a request has been cancelled.
+void LogCancelRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
+ const HostResolverImpl::RequestInfo& info) {
+ request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
+ request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
+ source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
+}
+
+//-----------------------------------------------------------------------------
+
+// Keeps track of the highest priority.
+class PriorityTracker {
+ public:
+ PriorityTracker()
+ : highest_priority_(IDLE), total_count_(0) {
+ memset(counts_, 0, sizeof(counts_));
+ }
+
+ RequestPriority highest_priority() const {
+ return highest_priority_;
+ }
+
+ size_t total_count() const {
+ return total_count_;
+ }
+
+ void Add(RequestPriority req_priority) {
+ ++total_count_;
+ ++counts_[req_priority];
+ if (highest_priority_ > req_priority)
+ highest_priority_ = req_priority;
+ }
+
+ void Remove(RequestPriority req_priority) {
+ DCHECK_GT(total_count_, 0u);
+ DCHECK_GT(counts_[req_priority], 0u);
+ --total_count_;
+ --counts_[req_priority];
+ size_t i;
+ for (i = highest_priority_; i < NUM_PRIORITIES && !counts_[i]; ++i);
+ highest_priority_ = static_cast<RequestPriority>(i);
+
+ // In absence of requests set default.
+ if (highest_priority_ == NUM_PRIORITIES) {
+ DCHECK_EQ(0u, total_count_);
+ highest_priority_ = IDLE;
+ }
+ }
+
+ private:
+ RequestPriority highest_priority_;
+ size_t total_count_;
+ size_t counts_[NUM_PRIORITIES];
+};
+
//-----------------------------------------------------------------------------
+HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
+ size_t max_retry_attempts,
+ bool use_cache,
+ NetLog* net_log) {
+ if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
+ max_concurrent_resolves = kDefaultMaxProcTasks;
+
+ // TODO(szym): Add experiments with reserved slots for higher priority
+ // requests.
+
+ PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
+
+ HostResolverImpl* resolver = new HostResolverImpl(
+ use_cache ? HostCache::CreateDefaultCache() : NULL,
+ limits,
+ HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
+ net_log);
+
+ return resolver;
+}
+
+} // anonymous namespace
+
+//-----------------------------------------------------------------------------
+
+HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
+ size_t max_retry_attempts,
+ NetLog* net_log) {
+ return CreateHostResolver(max_concurrent_resolves,
+ max_retry_attempts,
+ true /* use_cache */,
+ net_log);
+}
+
+HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
+ size_t max_retry_attempts,
+ NetLog* net_log) {
+ return CreateHostResolver(max_concurrent_resolves,
+ max_retry_attempts,
+ false /* use_cache */,
+ net_log);
+}
+
+//-----------------------------------------------------------------------------
+
+// Holds the data for a request that could not be completed synchronously.
+// It is owned by a Job. Canceled Requests are only marked as canceled rather
+// than removed from the Job's |requests_| list.
class HostResolverImpl::Request {
public:
Request(const BoundNetLog& source_net_log,
@@ -278,43 +422,42 @@ class HostResolverImpl::Request {
addresses_(addresses) {
}
- // Mark the request as cancelled.
- void MarkAsCancelled() {
+ // Mark the request as canceled.
+ void MarkAsCanceled() {
job_ = NULL;
addresses_ = NULL;
callback_.Reset();
}
- bool was_cancelled() const {
+ bool was_canceled() const {
return callback_.is_null();
}
void set_job(Job* job) {
- DCHECK(job != NULL);
+ DCHECK(job);
// Identify which job the request is waiting on.
job_ = job;
}
+ // Prepare final AddressList and call completion callback.
void OnComplete(int error, const AddressList& addrlist) {
if (error == OK)
- *addresses_ = CreateAddressListUsingPort(addrlist, port());
+ *addresses_ = CreateAddressListUsingPort(addrlist, info_.port());
CompletionCallback callback = callback_;
- MarkAsCancelled();
+ MarkAsCanceled();
callback.Run(error);
}
- int port() const {
- return info_.port();
- }
-
Job* job() const {
return job_;
}
+ // NetLog for the source, passed in HostResolver::Resolve.
const BoundNetLog& source_net_log() {
return source_net_log_;
}
+ // NetLog for this request.
const BoundNetLog& request_net_log() {
return request_net_log_;
}
@@ -330,7 +473,7 @@ class HostResolverImpl::Request {
// The request info that started the request.
RequestInfo info_;
- // The resolve job (running in worker pool) that this request is dependent on.
+ // The resolve job that this request is dependent on.
Job* job_;
// The user's callback to invoke when the request completes.
@@ -349,56 +492,88 @@ class HostResolverImpl::Request {
#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
-// This class represents a request to the worker pool for a "getaddrinfo()"
-// call.
-class HostResolverImpl::Job
- : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
+// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
+//
+// Whenever we try to resolve the host, we post a delayed task to check if host
+// resolution (OnLookupComplete) is completed or not. If the original attempt
+// hasn't completed, then we start another attempt for host resolution. We take
+// the results from the first attempt that finishes and ignore the results from
+// all other attempts.
+//
+// TODO(szym): Move to separate source file for testing and mocking.
+//
+class HostResolverImpl::ProcTask
+ : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
public:
- Job(int id,
- HostResolverImpl* resolver,
- const Key& key,
- const BoundNetLog& source_net_log,
- NetLog* net_log)
- : id_(id),
- key_(key),
- resolver_(resolver),
- origin_loop_(base::MessageLoopProxy::current()),
- resolver_proc_(resolver->effective_resolver_proc()),
- unresponsive_delay_(resolver->unresponsive_delay()),
- attempt_number_(0),
- completed_attempt_number_(0),
- completed_attempt_error_(ERR_UNEXPECTED),
- had_non_speculative_request_(false),
- net_log_(BoundNetLog::Make(net_log,
- NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
- DCHECK(resolver);
- net_log_.BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
- make_scoped_refptr(
- new JobCreationParameters(key.hostname, source_net_log.source())));
+ typedef base::Callback<void(int, int, const AddressList&)> Callback;
+
+ ProcTask(const Key& key,
+ const ProcTaskParams& params,
+ const Callback& callback,
+ const BoundNetLog& job_net_log)
+ : key_(key),
+ params_(params),
+ callback_(callback),
+ origin_loop_(base::MessageLoopProxy::current()),
+ attempt_number_(0),
+ completed_attempt_number_(0),
+ completed_attempt_error_(ERR_UNEXPECTED),
+ had_non_speculative_request_(false),
+ net_log_(BoundNetLog::Make(
+ job_net_log.net_log(),
+ NetLog::SOURCE_HOST_RESOLVER_IMPL_PROC_TASK)) {
+ if (!params_.resolver_proc)
+ params_.resolver_proc = HostResolverProc::GetDefault();
+ // If default is unset, use the system proc.
+ if (!params_.resolver_proc)
+ params_.resolver_proc = new CallSystemHostResolverProc();
+
+ job_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_PROC_TASK,
+ new NetLogSourceParameter("source_dependency",
+ net_log_.source()));
+
+ net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
+ new JobCreationParameters(key_.hostname,
+ job_net_log.source()));
}
- // Attaches a request to this job. The job takes ownership of |req| and will
- // take care to delete it.
- void AddRequest(Request* req) {
+ void Start() {
DCHECK(origin_loop_->BelongsToCurrentThread());
- req->request_net_log().BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
- make_scoped_refptr(new NetLogSourceParameter(
- "source_dependency", net_log_.source())));
+ StartLookupAttempt();
+ }
- req->set_job(this);
- requests_.push_back(req);
+ // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
+ // attempts running on worker threads will continue running. Only once all the
+ // attempts complete will the final reference to this ProcTask be released.
+ void Cancel() {
+ DCHECK(origin_loop_->BelongsToCurrentThread());
- if (!req->info().is_speculative())
- had_non_speculative_request_ = true;
+ if (was_canceled())
+ return;
+
+ net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
+
+ callback_.Reset();
+
+ net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
}
- void Start() {
+ void set_had_non_speculative_request() {
DCHECK(origin_loop_->BelongsToCurrentThread());
- StartLookupAttempt();
+ had_non_speculative_request_ = true;
+ }
+
+ bool was_canceled() const {
+ DCHECK(origin_loop_->BelongsToCurrentThread());
+ return callback_.is_null();
+ }
+
+ bool was_completed() const {
+ DCHECK(origin_loop_->BelongsToCurrentThread());
+ return completed_attempt_number_ > 0;
}
+ private:
void StartLookupAttempt() {
DCHECK(origin_loop_->BelongsToCurrentThread());
base::TimeTicks start_time = base::TimeTicks::Now();
@@ -406,7 +581,7 @@ class HostResolverImpl::Job
// Dispatch the lookup attempt to a worker thread.
if (!base::WorkerPool::PostTask(
FROM_HERE,
- base::Bind(&Job::DoLookup, this, start_time, attempt_number_),
+ base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
true)) {
NOTREACHED();
@@ -415,7 +590,7 @@ class HostResolverImpl::Job
// returned (IO_PENDING).
origin_loop_->PostTask(
FROM_HERE,
- base::Bind(&Job::OnLookupComplete, this, AddressList(),
+ base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
start_time, attempt_number_, ERR_UNEXPECTED, 0));
return;
}
@@ -425,88 +600,17 @@ class HostResolverImpl::Job
make_scoped_refptr(new NetLogIntegerParameter(
"attempt_number", attempt_number_)));
- // Post a task to check if we get the results within a given time.
- // OnCheckForComplete has the potential for starting a new attempt on a
- // different worker thread if none of our outstanding attempts have
- // completed yet.
- if (attempt_number_ <= resolver_->max_retry_attempts()) {
+ // If we don't get the results within a given time, RetryIfNotComplete
+ // will start a new attempt on a different worker thread if none of our
+ // outstanding attempts have completed yet.
+ if (attempt_number_ <= params_.max_retry_attempts) {
origin_loop_->PostDelayedTask(
FROM_HERE,
- base::Bind(&Job::OnCheckForComplete, this),
- unresponsive_delay_.InMilliseconds());
+ base::Bind(&ProcTask::RetryIfNotComplete, this),
+ params_.unresponsive_delay.InMilliseconds());
}
}
- // Cancels the current job. The Job will be orphaned. Any outstanding resolve
- // attempts running on worker threads will continue running. Only once all the
- // attempts complete will the final reference to this Job be released.
- void Cancel() {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
-
- HostResolver* resolver = resolver_;
- resolver_ = NULL;
-
- // End here to prevent issues when a Job outlives the HostResolver that
- // spawned it.
- net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
-
- // We will call HostResolverImpl::CancelRequest(Request*) on each one
- // in order to notify any observers.
- for (RequestsList::const_iterator it = requests_.begin();
- it != requests_.end(); ++it) {
- HostResolverImpl::Request* req = *it;
- if (!req->was_cancelled())
- resolver->CancelRequest(req);
- }
- }
-
- bool was_cancelled() const {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- return resolver_ == NULL;
- }
-
- bool was_completed() const {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- return completed_attempt_number_ > 0;
- }
-
- const Key& key() const {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- return key_;
- }
-
- int id() const {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- return id_;
- }
-
- const RequestsList& requests() const {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- return requests_;
- }
-
- // Returns the first request attached to the job.
- const Request* initial_request() const {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- DCHECK(!requests_.empty());
- return requests_[0];
- }
-
- // Returns true if |req_info| can be fulfilled by this job.
- bool CanServiceRequest(const RequestInfo& req_info) const {
- DCHECK(origin_loop_->BelongsToCurrentThread());
- return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
- }
-
- private:
- friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
-
- ~Job() {
- // Free the requests attached to this job.
- STLDeleteElements(&requests_);
- }
-
// WARNING: This code runs inside a worker pool. The shutdown code cannot
// wait for it to finish, so we must be very careful here about using other
// objects (like MessageLoops, Singletons, etc). During shutdown these objects
@@ -517,28 +621,27 @@ class HostResolverImpl::Job
AddressList results;
int os_error = 0;
// Running on the worker thread
- int error = ResolveAddrInfo(resolver_proc_,
- key_.hostname,
- key_.address_family,
- key_.host_resolver_flags,
- &results,
- &os_error);
+
+ int error = params_.resolver_proc->Resolve(key_.hostname,
+ key_.address_family,
+ key_.host_resolver_flags,
+ &results,
+ &os_error);
origin_loop_->PostTask(
FROM_HERE,
- base::Bind(&Job::OnLookupComplete, this, results, start_time,
+ base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
attempt_number, error, os_error));
}
- // Callback to see if DoLookup() has finished or not (runs on origin thread).
- void OnCheckForComplete() {
+ // Makes next attempt if DoLookup() has not finished (runs on origin thread).
+ void RetryIfNotComplete() {
DCHECK(origin_loop_->BelongsToCurrentThread());
- if (was_completed() || was_cancelled())
+ if (was_completed() || was_canceled())
return;
- DCHECK(resolver_);
- unresponsive_delay_ *= resolver_->retry_factor();
+ params_.unresponsive_delay *= params_.retry_factor;
StartLookupAttempt();
}
@@ -553,74 +656,53 @@ class HostResolverImpl::Job
bool was_retry_attempt = attempt_number > 1;
- if (!was_cancelled()) {
- scoped_refptr<NetLog::EventParameters> params;
- if (error != OK) {
- params = new HostResolveFailedParams(attempt_number, error, os_error);
- } else {
- params = new NetLogIntegerParameter("attempt_number", attempt_number_);
- }
- net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
- params);
-
- // If host is already resolved, then record data and return.
- if (was_completed()) {
- // If this is the first attempt that is finishing later, then record
- // data for the first attempt. Won't contaminate with retry attempt's
- // data.
- if (!was_retry_attempt)
- RecordPerformanceHistograms(start_time, error, os_error);
-
- RecordAttemptHistograms(start_time, attempt_number, error, os_error);
- return;
- }
-
- // Copy the results from the first worker thread that resolves the host.
- results_ = results;
- completed_attempt_number_ = attempt_number;
- completed_attempt_error_ = error;
- }
-
// Ideally the following code would be part of host_resolver_proc.cc,
// however it isn't safe to call NetworkChangeNotifier from worker
// threads. So we do it here on the IO thread instead.
if (error != OK && NetworkChangeNotifier::IsOffline())
error = ERR_INTERNET_DISCONNECTED;
- // We will record data for the first attempt. Don't contaminate with retry
- // attempt's data.
+ // If this is the first attempt that is finishing later, then record
+ // data for the first attempt. Won't contaminate with retry attempt's
+ // data.
if (!was_retry_attempt)
RecordPerformanceHistograms(start_time, error, os_error);
RecordAttemptHistograms(start_time, attempt_number, error, os_error);
- if (was_cancelled())
+ if (was_canceled())
+ return;
+
+ scoped_refptr<NetLog::EventParameters> params;
+ if (error != OK) {
+ params = new HostResolveFailedParams(attempt_number, error, os_error);
+ } else {
+ params = new NetLogIntegerParameter("attempt_number", attempt_number_);
+ }
+ net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED, params);
+
+ if (was_completed())
return;
+ // Copy the results from the first worker thread that resolves the host.
+ results_ = results;
+ completed_attempt_number_ = attempt_number;
+ completed_attempt_error_ = error;
+
if (was_retry_attempt) {
// If retry attempt finishes before 1st attempt, then get stats on how
// much time is saved by having spawned an extra attempt.
retry_attempt_finished_time_ = base::TimeTicks::Now();
}
- scoped_refptr<NetLog::EventParameters> params;
if (error != OK) {
params = new HostResolveFailedParams(0, error, os_error);
} else {
params = new AddressListNetLogParam(results_);
}
+ net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, params);
- // End here to prevent issues when a Job outlives the HostResolver that
- // spawned it.
- net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
-
- DCHECK(!requests_.empty());
-
- // Use the port number of the first request.
- if (error == OK)
- MutableSetPort(requests_[0]->port(), &results_);
-
- resolver_->OnJobComplete(this, error, os_error, results_);
+ callback_.Run(error, os_error, results_);
}
void RecordPerformanceHistograms(const base::TimeTicks& start_time,
@@ -716,6 +798,7 @@ class HostResolverImpl::Job
const uint32 attempt_number,
const int error,
const int os_error) const {
+ DCHECK(origin_loop_->BelongsToCurrentThread());
bool first_attempt_to_complete =
completed_attempt_number_ == attempt_number;
bool is_first_attempt = (attempt_number == 1);
@@ -739,19 +822,19 @@ class HostResolverImpl::Job
// If first attempt didn't finish before retry attempt, then calculate stats
// on how much time is saved by having spawned an extra attempt.
- if (!first_attempt_to_complete && is_first_attempt && !was_cancelled()) {
+ if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
base::TimeTicks::Now() - retry_attempt_finished_time_);
}
- if (was_cancelled() || !first_attempt_to_complete) {
+ if (was_canceled() || !first_attempt_to_complete) {
// Count those attempts which completed after the job was already canceled
// OR after the job was already completed by an earlier attempt (so in
// effect).
UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
- // Record if job is cancelled.
- if (was_cancelled())
+ // Record if job is canceled.
+ if (was_canceled())
UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
}
@@ -762,28 +845,20 @@ class HostResolverImpl::Job
DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
}
- // Immutable. Can be read from either thread,
- const int id_;
-
// Set on the origin thread, read on the worker thread.
Key key_;
- // Only used on the origin thread (where Resolve was called).
- HostResolverImpl* resolver_;
- RequestsList requests_; // The requests waiting on this job.
-
- // Used to post ourselves onto the origin thread.
- scoped_refptr<base::MessageLoopProxy> origin_loop_;
-
- // Hold an owning reference to the HostResolverProc that we are going to use.
+ // Holds an owning reference to the HostResolverProc that we are going to use.
// This may not be the current resolver procedure by the time we call
// ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
// reference ensures that it remains valid until we are done.
- scoped_refptr<HostResolverProc> resolver_proc_;
+ ProcTaskParams params_;
+
+ // The listener to the results of this ProcTask.
+ Callback callback_;
- // The amount of time after starting a resolution attempt until deciding to
- // retry.
- base::TimeDelta unresponsive_delay_;
+ // Used to post ourselves onto the origin thread.
+ scoped_refptr<base::MessageLoopProxy> origin_loop_;
// Keeps track of the number of attempts we have made so far to resolve the
// host. Whenever we start an attempt to resolve the host, we increase this
@@ -801,7 +876,7 @@ class HostResolverImpl::Job
base::TimeTicks retry_attempt_finished_time_;
// True if a non-speculative request was ever attached to this job
- // (regardless of whether or not it was later cancelled.
+ // (regardless of whether or not it was later canceled.
// This boolean is used for histogramming the duration of jobs used to
// service non-speculative requests.
bool had_non_speculative_request_;
@@ -810,13 +885,12 @@ class HostResolverImpl::Job
BoundNetLog net_log_;
- DISALLOW_COPY_AND_ASSIGN(Job);
+ DISALLOW_COPY_AND_ASSIGN(ProcTask);
};
//-----------------------------------------------------------------------------
-// This class represents a request to the worker pool for a "probe for IPv6
-// support" call.
+// Represents a request to the worker pool for a "probe for IPv6 support" call.
class HostResolverImpl::IPv6ProbeJob
: public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
public:
@@ -828,7 +902,7 @@ class HostResolverImpl::IPv6ProbeJob
void Start() {
DCHECK(origin_loop_->BelongsToCurrentThread());
- if (was_cancelled())
+ if (was_canceled())
return;
const bool kIsSlow = true;
base::WorkerPool::PostTask(
@@ -838,7 +912,7 @@ class HostResolverImpl::IPv6ProbeJob
// Cancels the current job.
void Cancel() {
DCHECK(origin_loop_->BelongsToCurrentThread());
- if (was_cancelled())
+ if (was_canceled())
return;
resolver_ = NULL; // Read/write ONLY on origin thread.
}
@@ -849,7 +923,7 @@ class HostResolverImpl::IPv6ProbeJob
~IPv6ProbeJob() {
}
- bool was_cancelled() const {
+ bool was_canceled() const {
DCHECK(origin_loop_->BelongsToCurrentThread());
return !resolver_;
}
@@ -868,7 +942,7 @@ class HostResolverImpl::IPv6ProbeJob
// Callback for when DoProbe() completes.
void OnProbeComplete(AddressFamily address_family) {
DCHECK(origin_loop_->BelongsToCurrentThread());
- if (was_cancelled())
+ if (was_canceled())
return;
resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
}
@@ -884,199 +958,287 @@ class HostResolverImpl::IPv6ProbeJob
//-----------------------------------------------------------------------------
-// We rely on the priority enum values being sequential having starting at 0,
-// and increasing for lower priorities.
-COMPILE_ASSERT(HIGHEST == 0u &&
- LOWEST > HIGHEST &&
- IDLE > LOWEST &&
- NUM_PRIORITIES > IDLE,
- priority_indexes_incompatible);
-
-// JobPool contains all the information relating to queued requests, including
-// the limits on how many jobs are allowed to be used for this category of
-// requests.
-class HostResolverImpl::JobPool {
+// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
+// Spawns ProcTask when started.
+class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
public:
- JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
- : num_outstanding_jobs_(0u) {
- SetConstraints(max_outstanding_jobs, max_pending_requests);
- }
-
- ~JobPool() {
- // Free the pending requests.
- for (size_t i = 0; i < arraysize(pending_requests_); ++i)
- STLDeleteElements(&pending_requests_[i]);
- }
-
- // Sets the constraints for this pool. See SetPoolConstraints() for the
- // specific meaning of these parameters.
- void SetConstraints(size_t max_outstanding_jobs,
- size_t max_pending_requests) {
- CHECK_NE(max_outstanding_jobs, 0u);
- max_outstanding_jobs_ = max_outstanding_jobs;
- max_pending_requests_ = max_pending_requests;
- }
-
- // Returns the number of pending requests enqueued to this pool.
- // A pending request is one waiting to be attached to a job.
- size_t GetNumPendingRequests() const {
- size_t total = 0u;
- for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
- total += pending_requests_[i].size();
- return total;
- }
-
- bool HasPendingRequests() const {
- return GetNumPendingRequests() > 0u;
- }
-
- // Enqueues a request to this pool. As a result of enqueing this request,
- // the queue may have reached its maximum size. In this case, a request is
- // evicted from the queue, and returned. Otherwise returns NULL. The caller
- // is responsible for freeing the evicted request.
- Request* InsertPendingRequest(Request* req) {
- req->request_net_log().BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
- NULL);
-
- PendingRequestsQueue& q = pending_requests_[req->info().priority()];
- q.push_back(req);
-
- // If the queue is too big, kick out the lowest priority oldest request.
- if (GetNumPendingRequests() > max_pending_requests_) {
- // Iterate over the queues from lowest priority to highest priority.
- for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
- i >= 0; --i) {
- PendingRequestsQueue& q = pending_requests_[i];
- if (!q.empty()) {
- Request* req = q.front();
- q.pop_front();
- req->request_net_log().AddEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
- req->request_net_log().EndEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
- return req;
- }
+ // Creates new job for |key| where |request_net_log| is bound to the
+ // request that spawned it.
+ Job(HostResolverImpl* resolver,
+ const Key& key,
+ const BoundNetLog& request_net_log)
+ : resolver_(resolver->AsWeakPtr()),
+ key_(key),
+ had_non_speculative_request_(false),
+ net_log_(BoundNetLog::Make(request_net_log.net_log(),
+ NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)),
+ net_error_(ERR_IO_PENDING),
+ os_error_(0) {
+ request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL);
+
+ net_log_.BeginEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ make_scoped_refptr(new JobCreationParameters(
+ key_.hostname, request_net_log.source())));
+ }
+
+ virtual ~Job() {
+ if (net_error_ == ERR_IO_PENDING) {
+ if (is_running()) {
+ DCHECK_EQ(ERR_IO_PENDING, net_error_);
+ proc_task_->Cancel();
+ proc_task_ = NULL;
+ net_error_ = ERR_ABORTED;
+ } else {
+ net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
+ net_error_ = OK; // For NetLog.
+ }
+
+ for (RequestsList::const_iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ Request* req = *it;
+ if (req->was_canceled())
+ continue;
+ DCHECK_EQ(this, req->job());
+ LogCancelRequest(req->source_net_log(), req->request_net_log(),
+ req->info());
}
}
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ net_error_);
+ STLDeleteElements(&requests_);
+ }
- return NULL;
+ HostResolverImpl* resolver() const {
+ return resolver_;
}
- // Erases |req| from this container. Caller is responsible for freeing
- // |req| afterwards.
- void RemovePendingRequest(Request* req) {
- PendingRequestsQueue& q = pending_requests_[req->info().priority()];
- PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
- DCHECK(it != q.end());
- q.erase(it);
- req->request_net_log().EndEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
+ RequestPriority priority() const {
+ return priority_tracker_.highest_priority();
}
- // Removes and returns the highest priority pending request.
- Request* RemoveTopPendingRequest() {
- DCHECK(HasPendingRequests());
+ // Number of non-canceled requests in |requests_|.
+ size_t num_active_requests() const {
+ return priority_tracker_.total_count();
+ }
- for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
- PendingRequestsQueue& q = pending_requests_[i];
- if (!q.empty()) {
- Request* req = q.front();
- q.pop_front();
- req->request_net_log().EndEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
- return req;
- }
+ const Key& key() const {
+ return key_;
+ }
+
+ int net_error() const {
+ return net_error_;
+ }
+
+ // Used by HostResolverImpl with |dispatcher_|.
+ const PrioritizedDispatcher::Handle& handle() const {
+ return handle_;
+ }
+
+ void set_handle(const PrioritizedDispatcher::Handle& handle) {
+ handle_ = handle;
+ }
+
+ // The Job will own |req| and destroy it in ~Job.
+ void AddRequest(Request* req) {
+ DCHECK_EQ(key_.hostname, req->info().hostname());
+
+ req->set_job(this);
+ requests_.push_back(req);
+
+ priority_tracker_.Add(req->info().priority());
+
+ req->request_net_log().AddEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
+ make_scoped_refptr(new NetLogSourceParameter(
+ "source_dependency", net_log_.source())));
+
+ net_log_.AddEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
+ make_scoped_refptr(new JobAttachParameters(
+ req->request_net_log().source(), priority())));
+
+ // TODO(szym): Check if this is still needed.
+ if (!req->info().is_speculative()) {
+ had_non_speculative_request_ = true;
+ if (proc_task_)
+ proc_task_->set_had_non_speculative_request();
}
+ }
- NOTREACHED();
- return NULL;
+ void CancelRequest(Request* req) {
+ DCHECK_EQ(key_.hostname, req->info().hostname());
+ DCHECK(!req->was_canceled());
+ // Don't remove it from |requests_| just mark it canceled.
+ req->MarkAsCanceled();
+ LogCancelRequest(req->source_net_log(), req->request_net_log(),
+ req->info());
+ priority_tracker_.Remove(req->info().priority());
+ net_log_.AddEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
+ make_scoped_refptr(new JobAttachParameters(
+ req->request_net_log().source(), priority())));
}
- // Keeps track of a job that was just added/removed, and belongs to this pool.
- void AdjustNumOutstandingJobs(int offset) {
- DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
- num_outstanding_jobs_ += offset;
+ // Aborts and destroys the job, completes all requests as aborted.
+ void Abort() {
+ // Job should only be aborted if it's running.
+ DCHECK(is_running());
+ proc_task_->Cancel();
+ proc_task_ = NULL;
+ net_error_ = ERR_ABORTED;
+ os_error_ = 0;
+ CompleteRequests(AddressList());
}
- void ResetNumOutstandingJobs() {
- num_outstanding_jobs_ = 0;
+ bool is_running() const {
+ return proc_task_.get() != NULL;
}
- // Returns true if a new job can be created for this pool.
- bool CanCreateJob() const {
- return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
+ // Called by HostResolverImpl when this job is evicted due to queue overflow.
+ void OnEvicted() {
+ // Must not be running.
+ DCHECK(!is_running());
+ handle_ = PrioritizedDispatcher::Handle();
+
+ net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED, NULL);
+
+ // This signals to CompleteRequests that this job never ran.
+ net_error_ = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
+ os_error_ = 0;
+ CompleteRequests(AddressList());
}
- // Removes any pending requests from the queue which are for the
- // same (hostname / effective address-family) as |job|, and attaches them to
- // |job|.
- void MoveRequestsToJob(Job* job) {
- for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
- PendingRequestsQueue& q = pending_requests_[i];
- PendingRequestsQueue::iterator req_it = q.begin();
- while (req_it != q.end()) {
- Request* req = *req_it;
- if (job->CanServiceRequest(req->info())) {
- // Job takes ownership of |req|.
- job->AddRequest(req);
- req_it = q.erase(req_it);
- } else {
- ++req_it;
- }
- }
- }
+ // PriorityDispatch::Job interface.
+ virtual void Start() OVERRIDE {
+ DCHECK(!is_running());
+ handle_ = PrioritizedDispatcher::Handle();
+
+ net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL);
+
+ proc_task_ = new ProcTask(
+ key_,
+ resolver_->proc_params_,
+ base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
+ net_log_);
+
+ if (had_non_speculative_request_)
+ proc_task_->set_had_non_speculative_request();
+ // Start() could be called from within Resolve(), hence it must NOT directly
+ // call OnProcTaskComplete, for example, on synchronous failure.
+ proc_task_->Start();
}
private:
- typedef std::deque<Request*> PendingRequestsQueue;
+ // Called by ProcTask when it completes.
+ void OnProcTaskComplete(int net_error, int os_error,
+ const AddressList& addrlist) {
+ DCHECK(is_running());
+ proc_task_ = NULL;
+ net_error_ = net_error;
+ os_error_ = os_error;
+
+ // We are the only consumer of |addrlist|, so we can safely change the port
+ // without copy-on-write. This pays off, when job has only one request.
+ AddressList list = addrlist;
+ if (net_error == OK && !requests_.empty())
+ MutableSetPort(requests_.front()->info().port(), &list);
+ CompleteRequests(list);
+ }
+
+ // Completes all Requests. Calls OnJobFinished and deletes self.
+ void CompleteRequests(const AddressList& addrlist) {
+ CHECK(resolver_);
+
+ // This job must be removed from resolver's |jobs_| now to make room for a
+ // new job with the same key in case one of the OnComplete callbacks decides
+ // to spawn one. Consequently, the job deletes itself when CompleteRequests
+ // is done.
+ scoped_ptr<Job> self_deleter(this);
+ resolver_->OnJobFinished(this, addrlist);
+
+ // Complete all of the requests that were attached to the job.
+ for (RequestsList::const_iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ Request* req = *it;
+
+ if (req->was_canceled())
+ continue;
+
+ DCHECK_EQ(this, req->job());
+ // Update the net log and notify registered observers.
+ LogFinishRequest(req->source_net_log(), req->request_net_log(),
+ req->info(), net_error_, os_error_);
+
+ req->OnComplete(net_error_, addrlist);
+
+ // Check if the resolver was destroyed as a result of running the
+ // callback. If it was, we could continue, but we choose to bail.
+ if (!resolver_)
+ return;
+ }
+ }
+
+ // Used to call OnJobFinished and RemoveJob.
+ base::WeakPtr<HostResolverImpl> resolver_;
- // Maximum number of concurrent jobs allowed to be started for requests
- // belonging to this pool.
- size_t max_outstanding_jobs_;
+ Key key_;
+
+ // Tracks the highest priority across |requests_|.
+ PriorityTracker priority_tracker_;
+
+ bool had_non_speculative_request_;
+
+ BoundNetLog net_log_;
- // The current number of running jobs that were started for requests
- // belonging to this pool.
- size_t num_outstanding_jobs_;
+ // Store result here in case the job fails fast in Resolve().
+ int net_error_;
+ int os_error_;
- // The maximum number of requests we allow to be waiting on a job,
- // for this pool.
- size_t max_pending_requests_;
+ // A ProcTask created and started when this Job is dispatched..
+ scoped_refptr<ProcTask> proc_task_;
- // The requests which are waiting to be started for this pool.
- PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
+ // All Requests waiting for the result of this Job. Some can be canceled.
+ RequestsList requests_;
+
+ // A handle used by HostResolverImpl in |dispatcher_|.
+ PrioritizedDispatcher::Handle handle_;
};
//-----------------------------------------------------------------------------
-HostResolverImpl::HostResolverImpl(
+HostResolverImpl::ProcTaskParams::ProcTaskParams(
HostResolverProc* resolver_proc,
+ size_t max_retry_attempts)
+ : resolver_proc(resolver_proc),
+ max_retry_attempts(max_retry_attempts),
+ unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
+ retry_factor(2) {
+}
+
+HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
+
+HostResolverImpl::HostResolverImpl(
HostCache* cache,
- size_t max_jobs,
- size_t max_retry_attempts,
+ const PrioritizedDispatcher::Limits& job_limits,
+ const ProcTaskParams& proc_params,
NetLog* net_log)
: cache_(cache),
- max_jobs_(max_jobs),
- max_retry_attempts_(max_retry_attempts),
- unresponsive_delay_(base::TimeDelta::FromMilliseconds(6000)),
- retry_factor_(2),
- next_job_id_(0),
- resolver_proc_(resolver_proc),
+ dispatcher_(job_limits),
+ max_queued_jobs_(job_limits.total_jobs * 100u),
+ proc_params_(proc_params),
default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
ipv6_probe_monitoring_(false),
additional_resolver_flags_(0),
net_log_(net_log) {
- DCHECK_GT(max_jobs, 0u);
+
+ DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
// Maximum of 4 retry attempts for host resolution.
static const size_t kDefaultMaxRetryAttempts = 4u;
- if (max_retry_attempts_ == HostResolver::kDefaultRetryAttempts)
- max_retry_attempts_ = kDefaultMaxRetryAttempts;
-
- // It is cumbersome to expose all of the constraints in the constructor,
- // so we choose some defaults, which users can override later.
- job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
+ if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
+ proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
#if defined(OS_WIN)
EnsureWinsockInit();
@@ -1095,35 +1257,21 @@ HostResolverImpl::HostResolverImpl(
}
HostResolverImpl::~HostResolverImpl() {
- // Cancel the outstanding jobs. Those jobs may contain several attached
- // requests, which will also be cancelled.
DiscardIPv6ProbeJob();
- CancelAllJobs();
-
- // In case we are being deleted during the processing of a callback.
- if (cur_completing_job_)
- cur_completing_job_->Cancel();
+ // This will also cancel all outstanding requests.
+ STLDeleteValues(&jobs_);
NetworkChangeNotifier::RemoveIPAddressObserver(this);
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
NetworkChangeNotifier::RemoveDNSObserver(this);
#endif
-
- // Delete the job pools.
- for (size_t i = 0u; i < arraysize(job_pools_); ++i)
- delete job_pools_[i];
}
-void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
- size_t max_outstanding_jobs,
- size_t max_pending_requests) {
- DCHECK(CalledOnValidThread());
- CHECK_GE(pool_index, 0);
- CHECK_LT(pool_index, POOL_COUNT);
- CHECK(jobs_.empty()) << "Can only set constraints during setup";
- JobPool* pool = job_pools_[pool_index];
- pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
+void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
+ DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
+ DCHECK_GT(value, 0u);
+ max_queued_jobs_ = value;
}
int HostResolverImpl::Resolve(const RequestInfo& info,
@@ -1139,8 +1287,7 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
- // Update the net log and notify registered observers.
- OnStartRequest(source_net_log, request_net_log, info);
+ LogStartRequest(source_net_log, request_net_log, info);
// Build a key that identifies the request in the cache and in the
// outstanding jobs map.
@@ -1148,38 +1295,50 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
int rv = ResolveHelper(key, info, addresses, request_net_log);
if (rv != ERR_DNS_CACHE_MISS) {
- OnFinishRequest(source_net_log, request_net_log, info,
- rv,
- 0 /* os_error (unknown since from cache) */);
+ LogFinishRequest(source_net_log, request_net_log, info, rv,
+ 0 /* os_error (unknown since from cache) */);
return rv;
}
- // Create a handle for this request, and pass it back to the user if they
- // asked for it (out_req != NULL).
- Request* req = new Request(source_net_log, request_net_log, info,
- callback, addresses);
- if (out_req)
- *out_req = reinterpret_cast<RequestHandle>(req);
-
// Next we need to attach our request to a "job". This job is responsible for
// calling "getaddrinfo(hostname)" on a worker thread.
- scoped_refptr<Job> job;
- // If there is already an outstanding job to resolve |key|, use
- // it. This prevents starting concurrent resolves for the same hostname.
- job = FindOutstandingJob(key);
- if (job) {
- job->AddRequest(req);
- } else {
- JobPool* pool = GetPoolForRequest(req);
- if (CanCreateJobForPool(*pool)) {
- CreateAndStartJob(req);
- } else {
- return EnqueueRequest(pool, req);
+ JobMap::iterator jobit = jobs_.find(key);
+ Job* job;
+ if (jobit == jobs_.end()) {
+ // Create new Job.
+ job = new Job(this, key, request_net_log);
+ job->set_handle(dispatcher_.Add(job, info.priority()));
+
+ // Check for queue overflow.
+ if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
+ Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
+ DCHECK(evicted);
+ if (evicted == job) {
+ delete job;
+ rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
+ LogFinishRequest(source_net_log, request_net_log, info, rv, 0);
+ return rv;
+ }
+ evicted->OnEvicted(); // Deletes |evicted|.
}
+
+ jobs_.insert(jobit, std::make_pair(key, job));
+ } else {
+ job = jobit->second;
}
- // Completion happens during OnJobComplete(Job*).
+ // Can't complete synchronously. Create and attach request.
+ Request* req = new Request(source_net_log, request_net_log, info, callback,
+ addresses);
+ job->AddRequest(req);
+ if (!job->handle().is_null())
+ job->set_handle(dispatcher_.ChangePriority(job->handle(), job->priority()));
+ if (out_req)
+ *out_req = reinterpret_cast<RequestHandle>(req);
+
+ DCHECK_EQ(ERR_IO_PENDING, job->net_error());
+ // Completion happens during Job::CompleteRequests().
return ERR_IO_PENDING;
}
@@ -1212,44 +1371,44 @@ int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
// Update the net log and notify registered observers.
- OnStartRequest(source_net_log, request_net_log, info);
+ LogStartRequest(source_net_log, request_net_log, info);
- // Build a key that identifies the request in the cache and in the
- // outstanding jobs map.
Key key = GetEffectiveKeyForRequest(info);
int rv = ResolveHelper(key, info, addresses, request_net_log);
- OnFinishRequest(source_net_log, request_net_log, info,
- rv,
- 0 /* os_error (unknown since from cache) */);
+ LogFinishRequest(source_net_log, request_net_log, info, rv,
+ 0 /* os_error (unknown since from cache) */);
return rv;
}
-// See OnJobComplete(Job*) for why it is important not to clean out
-// cancelled requests from Job::requests_.
void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
DCHECK(CalledOnValidThread());
Request* req = reinterpret_cast<Request*>(req_handle);
DCHECK(req);
- scoped_ptr<Request> request_deleter; // Frees at end of function.
+ Job* job = req->job();
+ DCHECK(job);
+
+ job->CancelRequest(req);
- if (!req->job()) {
- // If the request was not attached to a job yet, it must have been
- // enqueued into a pool. Remove it from that pool's queue.
- // Otherwise if it was attached to a job, the job is responsible for
- // deleting it.
- JobPool* pool = GetPoolForRequest(req);
- pool->RemovePendingRequest(req);
- request_deleter.reset(req);
+ if (!job->handle().is_null()) {
+ // Still in queue.
+ if (job->num_active_requests()) {
+ job->set_handle(dispatcher_.ChangePriority(job->handle(),
+ job->priority()));
+ } else {
+ dispatcher_.Cancel(job->handle());
+ RemoveJob(job);
+ delete job;
+ }
} else {
- req->request_net_log().EndEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
+ // Job is running (and could be in CompleteRequests right now).
+ // But to be in Request::OnComplete we would have to have a non-canceled
+ // request. So it is safe to Abort it if it has no more active requests.
+ if (!job->num_active_requests()) {
+ job->Abort();
+ }
}
-
- // NULL out the fields of req, to mark it as cancelled.
- req->MarkAsCancelled();
- OnCancelRequest(req->source_net_log(), req->request_net_log(), req->info());
}
void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
@@ -1288,10 +1447,10 @@ bool HostResolverImpl::ResolveAsIP(const Key& key,
~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
0) << " Unhandled flag";
- bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
- !ipv6_probe_monitoring_;
+ bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
+ !ipv6_probe_monitoring_;
*net_error = OK;
- if (ip_number.size() == 16 && ipv6_disabled) {
+ if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
*net_error = ERR_NAME_NOT_RESOLVED;
} else {
*addresses = AddressList::CreateFromIPAddressWithCname(
@@ -1323,129 +1482,30 @@ bool HostResolverImpl::ServeFromCache(const Key& key,
return true;
}
-void HostResolverImpl::AddOutstandingJob(Job* job) {
- scoped_refptr<Job>& found_job = jobs_[job->key()];
- DCHECK(!found_job);
- found_job = job;
-
- JobPool* pool = GetPoolForRequest(job->initial_request());
- pool->AdjustNumOutstandingJobs(1);
-}
-
-HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
- JobMap::iterator it = jobs_.find(key);
- if (it != jobs_.end())
- return it->second;
- return NULL;
-}
-
-void HostResolverImpl::RemoveOutstandingJob(Job* job) {
- JobMap::iterator it = jobs_.find(job->key());
- DCHECK(it != jobs_.end());
- DCHECK_EQ(it->second.get(), job);
- jobs_.erase(it);
-
- JobPool* pool = GetPoolForRequest(job->initial_request());
- pool->AdjustNumOutstandingJobs(-1);
-}
-
-void HostResolverImpl::OnJobComplete(Job* job,
- int net_error,
- int os_error,
- const AddressList& addrlist) {
- RemoveOutstandingJob(job);
+void HostResolverImpl::OnJobFinished(Job* job, const AddressList& addrlist) {
+ DCHECK(job);
+ DCHECK(job->handle().is_null());
+ RemoveJob(job);
+ if (job->net_error() == ERR_HOST_RESOLVER_QUEUE_TOO_LARGE)
+ return;
+ // Signal dispatcher that a slot has opened.
+ dispatcher_.OnJobFinished();
+ if (job->net_error() == ERR_ABORTED)
+ return;
// Write result to the cache.
if (cache_.get()) {
base::TimeDelta ttl = base::TimeDelta::FromSeconds(0);
- if (net_error == OK)
+ if (job->net_error() == OK)
ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
- cache_->Set(job->key(), net_error, addrlist,
- base::TimeTicks::Now(),
- ttl);
- }
- OnJobCompleteInternal(job, net_error, os_error, addrlist);
-}
-
-void HostResolverImpl::AbortJob(Job* job) {
- OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
-}
-
-void HostResolverImpl::OnJobCompleteInternal(
- Job* job,
- int net_error,
- int os_error,
- const AddressList& addrlist) {
- // Make a note that we are executing within OnJobComplete() in case the
- // HostResolver is deleted by a callback invocation.
- DCHECK(!cur_completing_job_);
- cur_completing_job_ = job;
-
- // Try to start any queued requests now that a job-slot has freed up.
- ProcessQueuedRequests();
-
- // Complete all of the requests that were attached to the job.
- for (RequestsList::const_iterator it = job->requests().begin();
- it != job->requests().end(); ++it) {
- Request* req = *it;
- if (!req->was_cancelled()) {
- DCHECK_EQ(job, req->job());
- req->request_net_log().EndEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
-
- // Update the net log and notify registered observers.
- OnFinishRequest(req->source_net_log(), req->request_net_log(),
- req->info(), net_error, os_error);
-
- req->OnComplete(net_error, addrlist);
-
- // Check if the job was cancelled as a result of running the callback.
- // (Meaning that |this| was deleted).
- if (job->was_cancelled())
- return;
- }
+ cache_->Set(job->key(), job->net_error(), addrlist,
+ base::TimeTicks::Now(), ttl);
}
-
- cur_completing_job_ = NULL;
}
-void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
- const RequestInfo& info) {
- source_net_log.BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL,
- make_scoped_refptr(new NetLogSourceParameter(
- "source_dependency", request_net_log.source())));
-
- request_net_log.BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
- make_scoped_refptr(new RequestInfoParameters(
- info, source_net_log.source())));
-}
-
-void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
- const RequestInfo& info,
- int net_error,
- int os_error) {
- bool was_resolved = net_error == OK;
-
- // Log some extra parameters on failure for synchronous requests.
- scoped_refptr<NetLog::EventParameters> params;
- if (!was_resolved) {
- params = new HostResolveFailedParams(0, net_error, os_error);
- }
-
- request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
- source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
-}
-
-void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
- const RequestInfo& info) {
- request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
- request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
- source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
+void HostResolverImpl::RemoveJob(Job* job) {
+ DCHECK(job);
+ jobs_.erase(job->key());
}
void HostResolverImpl::DiscardIPv6ProbeJob() {
@@ -1469,46 +1529,6 @@ void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
DiscardIPv6ProbeJob();
}
-bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
- DCHECK_LE(jobs_.size(), max_jobs_);
-
- // We can't create another job if it would exceed the global total.
- if (jobs_.size() + 1 > max_jobs_)
- return false;
-
- // Check whether the pool's constraints are met.
- return pool.CanCreateJob();
-}
-
-// static
-HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
- const Request* req) {
- return POOL_NORMAL;
-}
-
-void HostResolverImpl::ProcessQueuedRequests() {
- // Find the highest priority request that can be scheduled.
- Request* top_req = NULL;
- for (size_t i = 0; i < arraysize(job_pools_); ++i) {
- JobPool* pool = job_pools_[i];
- if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
- top_req = pool->RemoveTopPendingRequest();
- break;
- }
- }
-
- if (!top_req)
- return;
-
- scoped_refptr<Job> job(CreateAndStartJob(top_req));
-
- // Search for any other pending request which can piggy-back off this job.
- for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
- JobPool* pool = job_pools_[pool_i];
- pool->MoveRequestsToJob(job);
- }
-}
-
HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
const RequestInfo& info) const {
HostResolverFlags effective_flags =
@@ -1523,58 +1543,22 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
return Key(info.hostname(), effective_address_family, effective_flags);
}
-HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
- DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
- Key key = GetEffectiveKeyForRequest(req->info());
-
- req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
- NULL);
-
- scoped_refptr<Job> job(new Job(next_job_id_++, this, key,
- req->request_net_log(), net_log_));
- job->AddRequest(req);
- AddOutstandingJob(job);
- job->Start();
-
- return job.get();
-}
-
-int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
- scoped_ptr<Request> req_evicted_from_queue(
- pool->InsertPendingRequest(req));
-
- // If the queue has become too large, we need to kick something out.
- if (req_evicted_from_queue.get()) {
- Request* r = req_evicted_from_queue.get();
- int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
-
- OnFinishRequest(r->source_net_log(), r->request_net_log(), r->info(), error,
- 0 /* os_error (not applicable) */);
-
- if (r == req)
- return error;
-
- r->OnComplete(error, AddressList());
- }
-
- return ERR_IO_PENDING;
-}
-
-void HostResolverImpl::CancelAllJobs() {
- JobMap jobs;
- jobs.swap(jobs_);
- for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
- it->second->Cancel();
-}
-
void HostResolverImpl::AbortAllInProgressJobs() {
- for (size_t i = 0; i < arraysize(job_pools_); ++i)
- job_pools_[i]->ResetNumOutstandingJobs();
- JobMap jobs;
- jobs.swap(jobs_);
- for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
- AbortJob(it->second);
- it->second->Cancel();
+ base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
+ // Scan |jobs_| for running jobs and abort them.
+ for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
+ Job* job = it->second;
+ // Advance the iterator before we might erase it.
+ ++it;
+ if (job->is_running()) {
+ job->Abort();
+ // Check if resolver was deleted in a request callback.
+ if (!self)
+ return;
+ } else {
+ // Keep it in |dispatch_|.
+ DCHECK(!job->handle().is_null());
+ }
}
}
diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h
index da69451..d5ff027 100644
--- a/net/base/host_resolver_impl.h
+++ b/net/base/host_resolver_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,11 +6,13 @@
#define NET_BASE_HOST_RESOLVER_IMPL_H_
#pragma once
+#include <map>
#include <vector>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "base/time.h"
#include "net/base/capturing_net_log.h"
@@ -20,15 +22,16 @@
#include "net/base/net_export.h"
#include "net/base/net_log.h"
#include "net/base/network_change_notifier.h"
+#include "net/base/prioritized_dispatcher.h"
namespace net {
// For each hostname that is requested, HostResolver creates a
-// HostResolverImpl::Job. This job gets dispatched to a thread in the global
-// WorkerPool, where it runs SystemHostResolverProc(). If requests for that same
-// host are made while the job is already outstanding, then they are attached
-// to the existing job rather than creating a new one. This avoids doing
-// parallel resolves for the same host.
+// HostResolverImpl::Job. When this job gets dispatched it creates a ProcJob
+// which runs the given HostResolverProc on a WorkerPool thread. If requests for
+// that same host are made during the job's lifetime, they are attached to the
+// existing job rather than creating a new one. This avoids doing parallel
+// resolves for the same host.
//
// The way these classes fit together is illustrated by:
//
@@ -41,69 +44,74 @@ namespace net {
// Request ... Request Request ... Request Request ... Request
// (port1) (port2) (port3) (port4) (port5) (portX)
//
-//
-// When a HostResolverImpl::Job finishes its work in the threadpool, the
-// callbacks of each waiting request are run on the origin thread.
+// When a HostResolverImpl::Job finishes, the callbacks of each waiting request
+// are run on the origin thread.
//
// Thread safety: This class is not threadsafe, and must only be called
// from one thread!
//
-// The HostResolverImpl enforces |max_jobs_| as the maximum number of concurrent
-// threads.
+// The HostResolverImpl enforces limits on the maximum number of concurrent
+// threads using PrioritizedDispatcher::Limits.
//
-// Requests are ordered in the queue based on their priority.
+// Jobs are ordered in the queue based on their priority and order of arrival.
//
-// Whenever we try to resolve the host, we post a delayed task to check if host
-// resolution (OnLookupComplete) is completed or not. If the original attempt
-// hasn't completed, then we start another attempt for host resolution. We take
-// the results from the first attempt that finishes and ignore the results from
-// all other attempts.
-
class NET_EXPORT HostResolverImpl
: public HostResolver,
NON_EXPORTED_BASE(public base::NonThreadSafe),
public NetworkChangeNotifier::IPAddressObserver,
- public NetworkChangeNotifier::DNSObserver {
+ public NetworkChangeNotifier::DNSObserver,
+ public base::SupportsWeakPtr<HostResolverImpl> {
public:
- // The index into |job_pools_| for the various job pools. Pools with a higher
- // index have lower priority.
- //
- // Note: This is currently unused, since there is a single pool
- // for all requests.
- enum JobPoolIndex {
- POOL_NORMAL = 0,
- POOL_COUNT,
- };
-
- // Creates a HostResolver that first uses the local cache |cache|, and then
- // falls back to |resolver_proc|.
- //
- // If |cache| is NULL, then no caching is used. Otherwise we take
- // ownership of the |cache| pointer, and will free it during destructor.
+ // Parameters for ProcTask which resolves hostnames using HostResolveProc.
//
// |resolver_proc| is used to perform the actual resolves; it must be
// thread-safe since it is run from multiple worker threads. If
// |resolver_proc| is NULL then the default host resolver procedure is
// used (which is SystemHostResolverProc except if overridden).
- // |max_jobs| specifies the maximum number of threads that the host resolver
- // will use (not counting potential duplicate attempts). Use
- // SetPoolConstraints() to specify finer-grain settings.
- // |max_retry_attempts| is the maximum number of times we will retry for host
- // resolution. Pass HostResolver::kDefaultRetryAttempts to choose a default
- // value.
//
// For each attempt, we could start another attempt if host is not resolved
- // within unresponsive_delay_ time. We keep attempting to resolve the host
- // for max_retry_attempts. For every retry attempt, we grow the
- // unresponsive_delay_ by the retry_factor_ amount (that is retry interval is
- // multiplied by the retry factor each time). Once we have retried
- // max_retry_attempts, we give up on additional attempts.
+ // within |unresponsive_delay| time. We keep attempting to resolve the host
+ // for |max_retry_attempts|. For every retry attempt, we grow the
+ // |unresponsive_delay| by the |retry_factor| amount (that is retry interval
+ // is multiplied by the retry factor each time). Once we have retried
+ // |max_retry_attempts|, we give up on additional attempts.
+ //
+ struct NET_EXPORT_PRIVATE ProcTaskParams {
+ // Sets up defaults.
+ ProcTaskParams(HostResolverProc* resolver_proc, size_t max_retry_attempts);
+
+ ~ProcTaskParams();
+
+ // The procedure to use for resolving host names. This will be NULL, except
+ // in the case of unit-tests which inject custom host resolving behaviors.
+ scoped_refptr<HostResolverProc> resolver_proc;
+
+ // Maximum number retry attempts to resolve the hostname.
+ // Pass HostResolver::kDefaultRetryAttempts to choose a default value.
+ size_t max_retry_attempts;
+
+ // This is the limit after which we make another attempt to resolve the host
+ // if the worker thread has not responded yet.
+ base::TimeDelta unresponsive_delay;
+
+ // Factor to grow |unresponsive_delay| when we re-re-try.
+ uint32 retry_factor;
+ };
+
+ // Creates a HostResolver that first uses the local cache |cache|, and then
+ // falls back to |proc_params.resolver_proc|.
+ //
+ // If |cache| is NULL, then no caching is used. Otherwise we take
+ // ownership of the |cache| pointer, and will free it during destruction.
+ //
+ // |job_limits| specifies the maximum number of jobs that the resolver will
+ // run at once (not counting potential duplicate attempts).
//
// |net_log| must remain valid for the life of the HostResolverImpl.
- HostResolverImpl(HostResolverProc* resolver_proc,
- HostCache* cache,
- size_t max_jobs,
- size_t max_retry_attempts,
+ // TODO(szym): change to scoped_ptr<HostCache>.
+ HostResolverImpl(HostCache* cache,
+ const PrioritizedDispatcher::Limits& job_limits,
+ const ProcTaskParams& proc_params,
NetLog* net_log);
// If any completion callbacks are pending when the resolver is destroyed,
@@ -111,20 +119,9 @@ class NET_EXPORT HostResolverImpl
// be called.
virtual ~HostResolverImpl();
- // Applies a set of constraints for requests that belong to the specified
- // pool. NOTE: Don't call this after requests have been already been started.
- //
- // |pool_index| -- Specifies which pool these constraints should be applied
- // to.
- // |max_outstanding_jobs| -- How many concurrent jobs are allowed for this
- // pool.
- // |max_pending_requests| -- How many requests can be enqueued for this pool
- // before we start dropping requests. Dropped
- // requests fail with
- // ERR_HOST_RESOLVER_QUEUE_TOO_LARGE.
- void SetPoolConstraints(JobPoolIndex pool_index,
- size_t max_outstanding_jobs,
- size_t max_pending_requests);
+ // Configures maximum number of Jobs in the queue. Exposed for testing.
+ // Only allowed when the queue is empty.
+ void SetMaxQueuedJobs(size_t value);
// HostResolver methods:
virtual int Resolve(const RequestInfo& info,
@@ -142,19 +139,13 @@ class NET_EXPORT HostResolverImpl
virtual HostCache* GetHostCache() OVERRIDE;
private:
- // Allow tests to access our innards for testing purposes.
- friend class LookupAttemptHostResolverProc;
-
- // Allow tests to access our innards for testing purposes.
- FRIEND_TEST_ALL_PREFIXES(HostResolverImplTest, MultipleAttempts);
-
class Job;
- class JobPool;
+ class ProcTask;
class IPv6ProbeJob;
class Request;
- typedef std::vector<Request*> RequestsList;
typedef HostCache::Key Key;
- typedef std::map<Key, scoped_refptr<Job> > JobMap;
+ typedef std::map<Key, Job*> JobMap;
+ typedef std::vector<Request*> RequestsList;
// Helper used by |Resolve()| and |ResolveFromCache()|. Performs IP
// literal and cache lookup, returns OK if successful,
@@ -181,153 +172,48 @@ class NET_EXPORT HostResolverImpl
int* net_error,
AddressList* addresses);
- // Returns the HostResolverProc to use for this instance.
- HostResolverProc* effective_resolver_proc() const {
- return resolver_proc_ ?
- resolver_proc_.get() : HostResolverProc::GetDefault();
- }
-
- // Adds a job to outstanding jobs list.
- void AddOutstandingJob(Job* job);
-
- // Returns the outstanding job for |key|, or NULL if there is none.
- Job* FindOutstandingJob(const Key& key);
-
- // Removes |job| from the outstanding jobs list.
- void RemoveOutstandingJob(Job* job);
-
- // Callback for when |job| has completed with |net_error| and |addrlist|.
- void OnJobComplete(Job* job, int net_error, int os_error,
- const AddressList& addrlist);
-
- // Aborts |job|. Same as OnJobComplete() except does not remove |job|
- // from |jobs_| and does not cache the result (ERR_ABORTED).
- void AbortJob(Job* job);
-
- // Used by both OnJobComplete() and AbortJob();
- void OnJobCompleteInternal(Job* job, int net_error, int os_error,
- const AddressList& addrlist);
-
- // Called when a request has just been started.
- void OnStartRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
- const RequestInfo& info);
-
- // Called when a request has just completed (before its callback is run).
- void OnFinishRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
- const RequestInfo& info,
- int net_error,
- int os_error);
-
- // Called when a request has been cancelled.
- void OnCancelRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
- const RequestInfo& info);
-
- // Notify IPv6ProbeJob not to call back, and discard reference to the job.
+ // Notifies IPv6ProbeJob not to call back, and discard reference to the job.
void DiscardIPv6ProbeJob();
// Callback from IPv6 probe activity.
void IPv6ProbeSetDefaultAddressFamily(AddressFamily address_family);
- // Returns true if the constraints for |pool| are met, and a new job can be
- // created for this pool.
- bool CanCreateJobForPool(const JobPool& pool) const;
-
- // Returns the index of the pool that request |req| maps to.
- static JobPoolIndex GetJobPoolIndexForRequest(const Request* req);
-
- JobPool* GetPoolForRequest(const Request* req) {
- return job_pools_[GetJobPoolIndexForRequest(req)];
- }
-
- // Starts up to 1 job given the current pool constraints. This job
- // may have multiple requests attached to it.
- void ProcessQueuedRequests();
-
// Returns the (hostname, address_family) key to use for |info|, choosing an
// "effective" address family by inheriting the resolver's default address
// family when the request leaves it unspecified.
Key GetEffectiveKeyForRequest(const RequestInfo& info) const;
- // Attaches |req| to a new job, and starts it. Returns that job.
- Job* CreateAndStartJob(Request* req);
-
- // Adds a pending request |req| to |pool|.
- int EnqueueRequest(JobPool* pool, Request* req);
+ // Called by |job| when it has finished running. Records the result in cache
+ // if necessary and dispatches another job if possible.
+ void OnJobFinished(Job* job, const AddressList& addrlist);
- // Cancels all jobs.
- void CancelAllJobs();
+ // Removes |job| from |jobs_|.
+ void RemoveJob(Job* job);
- // Aborts all in progress jobs (but might start new ones).
+ // Aborts all in progress jobs and notifies their requests.
+ // Might start new jobs.
void AbortAllInProgressJobs();
// NetworkChangeNotifier::IPAddressObserver methods:
virtual void OnIPAddressChanged() OVERRIDE;
- // Helper methods to get and set max_retry_attempts_.
- size_t max_retry_attempts() const {
- return max_retry_attempts_;
- }
- void set_max_retry_attempts(const size_t max_retry_attempts) {
- max_retry_attempts_ = max_retry_attempts;
- }
-
- // Helper methods for unit tests to get and set unresponsive_delay_.
- base::TimeDelta unresponsive_delay() const { return unresponsive_delay_; }
- void set_unresponsive_delay(const base::TimeDelta& unresponsive_delay) {
- unresponsive_delay_ = unresponsive_delay;
- }
-
- // Helper methods to get and set retry_factor_.
- uint32 retry_factor() const {
- return retry_factor_;
- }
- void set_retry_factor(const uint32 retry_factor) {
- retry_factor_ = retry_factor;
- }
-
// NetworkChangeNotifier::OnDNSChanged methods:
virtual void OnDNSChanged() OVERRIDE;
// Cache of host resolution results.
scoped_ptr<HostCache> cache_;
- // Map from hostname to outstanding job.
+ // Map from HostCache::Key to a Job.
JobMap jobs_;
- // Maximum number of concurrent jobs allowed, across all pools. Each job may
- // create multiple concurrent resolve attempts for the hostname.
- size_t max_jobs_;
-
- // Maximum number retry attempts to resolve the hostname.
- size_t max_retry_attempts_;
-
- // This is the limit after which we make another attempt to resolve the host
- // if the worker thread has not responded yet. Allow unit tests to change the
- // value.
- base::TimeDelta unresponsive_delay_;
-
- // Factor to grow unresponsive_delay_ when we re-re-try. Allow unit tests to
- // change the value.
- uint32 retry_factor_;
-
- // The information to track pending requests for a JobPool, as well as
- // how many outstanding jobs the pool already has, and its constraints.
- JobPool* job_pools_[POOL_COUNT];
-
- // The job that OnJobComplete() is currently processing (needed in case
- // HostResolver gets deleted from within the callback).
- scoped_refptr<Job> cur_completing_job_;
+ // Starts Jobs according to their priority and the configured limits.
+ PrioritizedDispatcher dispatcher_;
- // Monotonically increasing ID number to assign to the next job.
- // The only consumer of this ID is the requests tracing code.
- int next_job_id_;
+ // Limit on the maximum number of jobs queued in |dispatcher_|.
+ size_t max_queued_jobs_;
- // The procedure to use for resolving host names. This will be NULL, except
- // in the case of unit-tests which inject custom host resolving behaviors.
- scoped_refptr<HostResolverProc> resolver_proc_;
+ // Parameters for ProcTask.
+ ProcTaskParams proc_params_;
// Address family to use when the request doesn't specify one.
AddressFamily default_address_family_;
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index 7acf244..9a299c1 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -27,10 +27,6 @@
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
-// TODO(eroman):
-// - Test mixing async with sync (in particular how does sync update the
-// cache while an async is already pending).
-
namespace net {
using base::TimeDelta;
@@ -39,9 +35,37 @@ using base::TimeTicks;
static const size_t kMaxJobs = 10u;
static const size_t kMaxRetryAttempts = 4u;
+PrioritizedDispatcher::Limits DefaultLimits() {
+ PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, kMaxJobs);
+ return limits;
+}
+
+HostResolverImpl::ProcTaskParams DefaultParams(
+ HostResolverProc* resolver_proc) {
+ return HostResolverImpl::ProcTaskParams(resolver_proc,
+ kMaxRetryAttempts);
+}
+
HostResolverImpl* CreateHostResolverImpl(HostResolverProc* resolver_proc) {
- return new HostResolverImpl(resolver_proc, HostCache::CreateDefaultCache(),
- kMaxJobs, kMaxRetryAttempts, NULL);
+ return new HostResolverImpl(
+ HostCache::CreateDefaultCache(),
+ DefaultLimits(),
+ DefaultParams(resolver_proc),
+ NULL);
+}
+
+// This HostResolverImpl will only allow 1 outstanding resolve at a time.
+HostResolverImpl* CreateSerialHostResolverImpl(
+ HostResolverProc* resolver_proc) {
+ HostResolverImpl::ProcTaskParams params = DefaultParams(resolver_proc);
+ params.max_retry_attempts = 0u;
+
+ PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
+
+ return new HostResolverImpl(HostCache::CreateDefaultCache(),
+ limits,
+ params,
+ NULL);
}
// Helper to create a HostResolver::RequestInfo.
@@ -482,18 +506,18 @@ class WaitingHostResolverProc : public HostResolverProc {
base::WaitableEvent is_signaled_;
};
-TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) {
+TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
scoped_refptr<WaitingHostResolverProc> resolver_proc(
new WaitingHostResolverProc(NULL));
CapturingNetLog net_log(CapturingNetLog::kUnbounded);
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
{
+ // This resolver will be destroyed while a lookup is running on WorkerPool.
scoped_ptr<HostResolver> host_resolver(
- new HostResolverImpl(resolver_proc,
- HostCache::CreateDefaultCache(),
- kMaxJobs,
- kMaxRetryAttempts,
+ new HostResolverImpl(HostCache::CreateDefaultCache(),
+ DefaultLimits(),
+ DefaultParams(resolver_proc),
&net_log));
AddressList addrlist;
const int kPortnum = 80;
@@ -526,12 +550,15 @@ TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) {
pos = ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
NetLog::PHASE_BEGIN);
- // Both Job and Request need to be cancelled.
+ pos = ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
+ NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
+ NetLog::PHASE_BEGIN);
+ // Both Request and ProcTask need to be cancelled. (The Job is "aborted".)
pos = ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
NetLog::TYPE_CANCELLED,
NetLog::PHASE_NONE);
- // Don't care about order in which they end, or when the other one is
- // cancelled.
+ // Don't care about order in which Request, Job and ProcTask end, or when the
+ // other one is cancelled.
ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
NetLog::TYPE_CANCELLED,
NetLog::PHASE_NONE);
@@ -539,6 +566,9 @@ TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) {
NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
NetLog::PHASE_END);
ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
+ NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
+ NetLog::PHASE_END);
+ ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
NetLog::PHASE_END);
@@ -942,9 +972,8 @@ TEST_F(HostResolverImplTest, StartWithinCallback) {
new CapturingHostResolverProc(NULL));
// Turn off caching for this host resolver.
- scoped_ptr<HostResolver> host_resolver(
- new HostResolverImpl(resolver_proc, NULL, kMaxJobs, kMaxRetryAttempts,
- NULL));
+ scoped_ptr<HostResolver> host_resolver(new HostResolverImpl(
+ NULL, DefaultLimits(), DefaultParams(resolver_proc), NULL));
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened.
@@ -1024,12 +1053,11 @@ TEST_F(HostResolverImplTest, BypassCache) {
// Test that IP address changes flush the cache.
TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) {
scoped_ptr<HostResolver> host_resolver(
- new HostResolverImpl(NULL, HostCache::CreateDefaultCache(), kMaxJobs,
- kMaxRetryAttempts, NULL));
+ CreateHostResolverImpl(NULL));
AddressList addrlist;
- // Resolve "host1".
+ // Resolve "host1". Assume that ScopedDefaultHostResolverProc resolves all.
HostResolver::RequestInfo info1(HostPortPair("host1", 70));
TestCompletionCallback callback;
int rv = host_resolver->Resolve(info1, &addrlist, callback.callback(), NULL,
@@ -1083,15 +1111,9 @@ TEST_F(HostResolverImplTest, AbortOnIPAddressChanged) {
TEST_F(HostResolverImplTest, ObeyPoolConstraintsAfterIPAddressChange) {
scoped_refptr<WaitingHostResolverProc> resolver_proc(
new WaitingHostResolverProc(CreateCatchAllHostResolverProc()));
- scoped_ptr<HostResolverImpl> host_resolver(
- new HostResolverImpl(resolver_proc, HostCache::CreateDefaultCache(),
- kMaxJobs, kMaxRetryAttempts, NULL));
- const size_t kMaxOutstandingJobs = 1u;
- const size_t kMaxPendingRequests = 1000000u; // not relevant.
- host_resolver->SetPoolConstraints(HostResolverImpl::POOL_NORMAL,
- kMaxOutstandingJobs,
- kMaxPendingRequests);
+ scoped_ptr<HostResolverImpl> host_resolver(
+ CreateSerialHostResolverImpl(resolver_proc));
// Resolve "host1".
HostResolver::RequestInfo info(HostPortPair("host1", 70));
@@ -1179,12 +1201,8 @@ TEST_F(HostResolverImplTest, HigherPriorityRequestsStartedFirst) {
scoped_refptr<CapturingHostResolverProc> resolver_proc(
new CapturingHostResolverProc(NULL));
- // This HostResolverImpl will only allow 1 outstanding resolve at a time.
- size_t kMaxJobs = 1u;
- const size_t kRetryAttempts = 0u;
- scoped_ptr<HostResolver> host_resolver(
- new HostResolverImpl(resolver_proc, HostCache::CreateDefaultCache(),
- kMaxJobs, kRetryAttempts, NULL));
+ scoped_ptr<HostResolverImpl> host_resolver(
+ CreateSerialHostResolverImpl(resolver_proc));
// Note that at this point the CapturingHostResolverProc is blocked, so any
// requests we make will not complete.
@@ -1241,12 +1259,8 @@ TEST_F(HostResolverImplTest, CancelPendingRequest) {
scoped_refptr<CapturingHostResolverProc> resolver_proc(
new CapturingHostResolverProc(NULL));
- // This HostResolverImpl will only allow 1 outstanding resolve at a time.
- const size_t kMaxJobs = 1u;
- const size_t kRetryAttempts = 0u;
- scoped_ptr<HostResolver> host_resolver(
- new HostResolverImpl(resolver_proc, HostCache::CreateDefaultCache(),
- kMaxJobs, kRetryAttempts, NULL));
+ scoped_ptr<HostResolverImpl> host_resolver(
+ CreateSerialHostResolverImpl(resolver_proc));
// Note that at this point the CapturingHostResolverProc is blocked, so any
// requests we make will not complete.
@@ -1256,8 +1270,8 @@ TEST_F(HostResolverImplTest, CancelPendingRequest) {
CreateResolverRequest("req1", HIGHEST), // Will cancel.
CreateResolverRequest("req2", MEDIUM),
CreateResolverRequest("req3", LOW),
- CreateResolverRequest("req4", HIGHEST), // Will cancel.
- CreateResolverRequest("req5", LOWEST), // Will cancel.
+ CreateResolverRequest("req4", HIGHEST), // Will cancel.
+ CreateResolverRequest("req5", LOWEST), // Will cancel.
CreateResolverRequest("req6", MEDIUM),
};
@@ -1306,18 +1320,12 @@ TEST_F(HostResolverImplTest, QueueOverflow) {
scoped_refptr<CapturingHostResolverProc> resolver_proc(
new CapturingHostResolverProc(NULL));
- // This HostResolverImpl will only allow 1 outstanding resolve at a time.
- const size_t kMaxOutstandingJobs = 1u;
- const size_t kRetryAttempts = 0u;
- scoped_ptr<HostResolverImpl> host_resolver(new HostResolverImpl(
- resolver_proc, HostCache::CreateDefaultCache(), kMaxOutstandingJobs,
- kRetryAttempts, NULL));
-
- // Only allow up to 3 requests to be enqueued at a time.
- const size_t kMaxPendingRequests = 3u;
- host_resolver->SetPoolConstraints(HostResolverImpl::POOL_NORMAL,
- kMaxOutstandingJobs,
- kMaxPendingRequests);
+ scoped_ptr<HostResolverImpl> host_resolver(
+ CreateSerialHostResolverImpl(resolver_proc));
+
+ // Allow only 3 queued jobs.
+ const size_t kMaxPendingJobs = 3u;
+ host_resolver->SetMaxQueuedJobs(kMaxPendingJobs);
// Note that at this point the CapturingHostResolverProc is blocked, so any
// requests we make will not complete.
@@ -1388,11 +1396,8 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) {
new CapturingHostResolverProc(new EchoingHostResolverProc));
// This HostResolverImpl will only allow 1 outstanding resolve at a time.
- const size_t kMaxOutstandingJobs = 1u;
- const size_t kRetryAttempts = 0u;
- scoped_ptr<HostResolverImpl> host_resolver(new HostResolverImpl(
- resolver_proc, HostCache::CreateDefaultCache(), kMaxOutstandingJobs,
- kRetryAttempts, NULL));
+ scoped_ptr<HostResolverImpl> host_resolver(
+ CreateSerialHostResolverImpl(resolver_proc));
host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
@@ -1458,12 +1463,8 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) {
scoped_refptr<CapturingHostResolverProc> resolver_proc(
new CapturingHostResolverProc(new EchoingHostResolverProc));
- // This HostResolverImpl will only allow 1 outstanding resolve at a time.
- const size_t kMaxOutstandingJobs = 1u;
- const size_t kRetryAttempts = 0u;
- scoped_ptr<HostResolverImpl> host_resolver(new HostResolverImpl(
- resolver_proc, HostCache::CreateDefaultCache(), kMaxOutstandingJobs,
- kRetryAttempts, NULL));
+ scoped_ptr<HostResolverImpl> host_resolver(
+ CreateSerialHostResolverImpl(resolver_proc));
host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV6);
@@ -1573,16 +1574,19 @@ TEST_F(HostResolverImplTest, MultipleAttempts) {
scoped_refptr<LookupAttemptHostResolverProc> resolver_proc(
new LookupAttemptHostResolverProc(
NULL, kAttemptNumberToResolve, kTotalAttempts));
- HostCache* cache = HostCache::CreateDefaultCache();
- scoped_ptr<HostResolverImpl> host_resolver(
- new HostResolverImpl(resolver_proc, cache, kMaxJobs, kMaxRetryAttempts,
- NULL));
+
+ HostResolverImpl::ProcTaskParams params = DefaultParams(resolver_proc);
// Specify smaller interval for unresponsive_delay_ for HostResolverImpl so
// that unit test runs faster. For example, this test finishes in 1.5 secs
// (500ms * 3).
- TimeDelta kUnresponsiveTime = TimeDelta::FromMilliseconds(500);
- host_resolver->set_unresponsive_delay(kUnresponsiveTime);
+ params.unresponsive_delay = TimeDelta::FromMilliseconds(500);
+
+ scoped_ptr<HostResolverImpl> host_resolver(
+ new HostResolverImpl(HostCache::CreateDefaultCache(),
+ DefaultLimits(),
+ params,
+ NULL));
// Resolve "host1".
HostResolver::RequestInfo info(HostPortPair("host1", 70));
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 44f6f22..9a7e208 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -58,32 +58,46 @@ EVENT_TYPE(HOST_RESOLVER_IMPL)
// "net_error": <The net error code integer for the failure>,
// "os_error": <The exact error code integer that getaddrinfo() returned>,
// }
-
EVENT_TYPE(HOST_RESOLVER_IMPL_REQUEST)
// This event is logged when a request is handled by a cache entry.
EVENT_TYPE(HOST_RESOLVER_IMPL_CACHE_HIT)
-// This event means a request was queued/dequeued for subsequent job creation,
-// because there are already too many active HostResolverImpl::Jobs.
+// This event is created when a new HostResolverImpl::Job is about to be created
+// for a request.
+EVENT_TYPE(HOST_RESOLVER_IMPL_CREATE_JOB)
+
+// The creation/completion of a HostResolverImpl::Job which is created for
+// Requests that cannot be resolved synchronously.
//
// The BEGIN phase contains the following parameters:
//
// {
-// "priority": <Priority of the queued request>,
+// "host": <Hostname associated with the request>,
+// "source_dependency": <Source id, if any, of what created the request>,
+// }
+//
+// On success, the END phase has these parameters:
+// {
+// "address_list": <The host name being resolved>,
+// }
+// If an error occurred, the END phase will contain these parameters:
+// {
+// "net_error": <The net error code integer for the failure>,
+// "os_error": <The exact error code integer that getaddrinfo() returned>,
// }
-EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_POOL_QUEUE)
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB)
-// This event is created when a new HostResolverImpl::Request is evicted from
-// JobPool without a Job being created, because the limit on number of queued
-// Requests was reached.
-EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED)
+// This event is created when a HostResolverImpl::Job is evicted from
+// PriorityDispatch before it can start, because the limit on number of queued
+// Jobs was reached.
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_EVICTED)
-// This event is created when a new HostResolverImpl::Job is about to be created
-// for a request.
-EVENT_TYPE(HOST_RESOLVER_IMPL_CREATE_JOB)
+// This event is created when a HostResolverImpl::Job is started by
+// PriorityDispatch.
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_STARTED)
-// This event is created when HostResolverImpl::Job is about to start a new
+// This event is created when HostResolverImpl::ProcJob is about to start a new
// attempt to resolve the host.
//
// The ATTEMPT_STARTED event has the parameters:
@@ -93,8 +107,8 @@ EVENT_TYPE(HOST_RESOLVER_IMPL_CREATE_JOB)
// }
EVENT_TYPE(HOST_RESOLVER_IMPL_ATTEMPT_STARTED)
-// This event is created when HostResolverImpl::Job has finished resolving the
-// host.
+// This event is created when HostResolverImpl::ProcJob has finished resolving
+// the host.
//
// The ATTEMPT_FINISHED event has the parameters:
//
@@ -109,24 +123,52 @@ EVENT_TYPE(HOST_RESOLVER_IMPL_ATTEMPT_STARTED)
EVENT_TYPE(HOST_RESOLVER_IMPL_ATTEMPT_FINISHED)
// This is logged for a request when it's attached to a
-// HostResolverImpl::Job. When this occurs without a preceding
+// HostResolverImpl::Job. When this occurs without a preceding
// HOST_RESOLVER_IMPL_CREATE_JOB entry, it means the request was attached to an
// existing HostResolverImpl::Job.
//
-// If the BoundNetLog used to create the event has a valid source id, the BEGIN
-// phase contains the following parameters:
+// The event contains the following parameters:
//
// {
// "source_dependency": <Source identifier for the attached Job>,
// }
+//
EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_ATTACH)
-// The creation/completion of a host resolve (DNS) job.
+// This event is logged for the job to which the request is attached.
+// In that case, the event contains the following parameters:
+//
+// {
+// "source_dependency": <Source identifier for the attached Request>,
+// "priority": <New priority of the job>,
+// }
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH)
+
+// This is logged for a job when a request is cancelled and detached.
+//
+// The event contains the following parameters:
+//
+// {
+// "source_dependency": <Source identifier for the detached Request>,
+// "priority": <New priority of the job>,
+// }
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH)
+
+// Logged for a HostResolverImpl::Job when it creates a ProcTask.
+//
+// The event contains the following parameters:
+//
+// {
+// "source_dependency": <Source id of parent HostResolverImpl::Job>,
+// }
+EVENT_TYPE(HOST_RESOLVER_IMPL_CREATE_PROC_TASK)
+
+// The creation/completion of a HostResolverImpl::ProcTask to call getaddrinfo.
// The BEGIN phase contains the following parameters:
//
// {
-// "host": <Hostname associated with the request>,
-// "source_dependency": <Source id, if any, of what created the request>,
+// "hostname": <Hostname associated with the request>,
+// "source_dependency": <Source id of parent HostResolverImpl::Job>,
// }
//
// On success, the END phase has these parameters:
@@ -138,7 +180,7 @@ EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_ATTACH)
// "net_error": <The net error code integer for the failure>,
// "os_error": <The exact error code integer that getaddrinfo() returned>,
// }
-EVENT_TYPE(HOST_RESOLVER_IMPL_JOB)
+EVENT_TYPE(HOST_RESOLVER_IMPL_PROC_TASK)
// ------------------------------------------------------------------------
// InitProxyResolver
diff --git a/net/base/net_log_source_type_list.h b/net/base/net_log_source_type_list.h
index a8565d9..d4aac9f 100644
--- a/net/base/net_log_source_type_list.h
+++ b/net/base/net_log_source_type_list.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,14 +16,16 @@ SOURCE_TYPE(SOCKET, 5)
SOURCE_TYPE(SPDY_SESSION, 6)
SOURCE_TYPE(HOST_RESOLVER_IMPL_REQUEST, 7)
SOURCE_TYPE(HOST_RESOLVER_IMPL_JOB, 8)
-SOURCE_TYPE(DISK_CACHE_ENTRY, 9)
-SOURCE_TYPE(MEMORY_CACHE_ENTRY, 10)
-SOURCE_TYPE(HTTP_STREAM_JOB, 11)
-SOURCE_TYPE(EXPONENTIAL_BACKOFF_THROTTLING, 12)
-SOURCE_TYPE(DNS_TRANSACTION, 13)
-SOURCE_TYPE(ASYNC_HOST_RESOLVER_REQUEST, 14)
-SOURCE_TYPE(UDP_SOCKET, 15)
-SOURCE_TYPE(CERT_VERIFIER_JOB, 16)
-SOURCE_TYPE(HTTP_PIPELINED_CONNECTION, 17)
+SOURCE_TYPE(HOST_RESOLVER_IMPL_PROC_TASK, 9)
+SOURCE_TYPE(DISK_CACHE_ENTRY, 10)
+SOURCE_TYPE(MEMORY_CACHE_ENTRY, 11)
+SOURCE_TYPE(HTTP_STREAM_JOB, 12)
+SOURCE_TYPE(EXPONENTIAL_BACKOFF_THROTTLING, 13)
+SOURCE_TYPE(DNS_TRANSACTION, 14)
+SOURCE_TYPE(ASYNC_HOST_RESOLVER_REQUEST, 15)
+SOURCE_TYPE(UDP_SOCKET, 16)
+SOURCE_TYPE(CERT_VERIFIER_JOB, 17)
+SOURCE_TYPE(HTTP_PIPELINED_CONNECTION, 18)
+
+SOURCE_TYPE(COUNT, 19) // Always keep this as the last entry.
-SOURCE_TYPE(COUNT, 18) // Always keep this as the last entry.