diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.scons | 4 | ||||
-rw-r--r-- | chrome/browser/browser.vcproj | 8 | ||||
-rw-r--r-- | chrome/browser/net/dns_global.cc | 14 | ||||
-rw-r--r-- | chrome/browser/net/dns_host_info.cc | 4 | ||||
-rw-r--r-- | chrome/browser/net/dns_host_info.h | 11 | ||||
-rw-r--r-- | chrome/browser/net/dns_host_info_unittest.cc | 6 | ||||
-rw-r--r-- | chrome/browser/net/dns_master.cc | 289 | ||||
-rw-r--r-- | chrome/browser/net/dns_master.h | 134 | ||||
-rw-r--r-- | chrome/browser/net/dns_master_unittest.cc | 408 | ||||
-rw-r--r-- | chrome/browser/net/dns_slave.cc | 96 | ||||
-rw-r--r-- | chrome/browser/net/dns_slave.h | 72 |
11 files changed, 310 insertions, 736 deletions
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons index 225d6fa..0fb23ae 100644 --- a/chrome/browser/browser.scons +++ b/chrome/browser/browser.scons @@ -426,8 +426,6 @@ input_files = ChromeFileList([ 'net/dns_host_info.h', 'net/dns_master.cc', 'net/dns_master.h', - 'net/dns_slave.cc', - 'net/dns_slave.h', 'net/referrer.cc', 'net/referrer.h', 'net/sdch_dictionary_fetcher.cc', @@ -748,8 +746,6 @@ if not env.Bit('windows'): 'metrics/metrics_service.cc', 'modal_html_dialog_delegate.cc', 'net/dns_global.cc', - 'net/dns_master.cc', - 'net/dns_slave.cc', 'google_update.cc', 'password_manager/encryptor.cc', 'password_manager/ie7_password.cc', diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index c1cbed3..f6bba92 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -1614,14 +1614,6 @@ > </File> <File - RelativePath=".\net\dns_slave.cc" - > - </File> - <File - RelativePath=".\net\dns_slave.h" - > - </File> - <File RelativePath=".\net\referrer.cc" > </File> diff --git a/chrome/browser/net/dns_global.cc b/chrome/browser/net/dns_global.cc index 3ea79ff..693a2cd 100644 --- a/chrome/browser/net/dns_global.cc +++ b/chrome/browser/net/dns_global.cc @@ -377,13 +377,9 @@ void DnsPrefetchGetHtmlInfo(std::string* output) { static PrefetchObserver dns_resolution_observer; void InitDnsPrefetch(PrefService* user_prefs) { - // Use a large shutdown time so that UI tests (that instigate lookups, and - // then try to shutdown the browser) don't instigate the CHECK about - // "some slaves have not finished" - const TimeDelta kAllowableShutdownTime(TimeDelta::FromSeconds(10)); DCHECK(NULL == dns_master); if (!dns_master) { - dns_master = new DnsMaster(kAllowableShutdownTime); + dns_master = new DnsMaster(); // We did the initialization, so we should prime the pump, and set up // the DNS resolution system to run. off_the_record_observer.Register(); @@ -402,14 +398,8 @@ void InitDnsPrefetch(PrefService* user_prefs) { void ShutdownDnsPrefetch() { DCHECK(NULL != dns_master); - DnsMaster* master = dns_master; + delete dns_master; dns_master = NULL; - if (master->ShutdownSlaves()) { - delete master; - } else { - // Leak instance if shutdown problem. - DCHECK(0); - } } static void DiscardAllPrefetchState() { diff --git a/chrome/browser/net/dns_host_info.cc b/chrome/browser/net/dns_host_info.cc index 9be4b2d..a219420 100644 --- a/chrome/browser/net/dns_host_info.cc +++ b/chrome/browser/net/dns_host_info.cc @@ -39,8 +39,8 @@ bool DnsHostInfo::NeedsDnsUpdate(const std::string& hostname) { return true; case QUEUED: // In queue. - case ASSIGNED: // Slave is working on it. - case ASSIGNED_BUT_MARKED: // Slave is working on it. + case ASSIGNED: // It's being resolved. + case ASSIGNED_BUT_MARKED: // It's being resolved. return false; // We're already working on it case NO_SUCH_NAME: // Lookup failed. diff --git a/chrome/browser/net/dns_host_info.h b/chrome/browser/net/dns_host_info.h index 50c44f3..b9ea157 100644 --- a/chrome/browser/net/dns_host_info.h +++ b/chrome/browser/net/dns_host_info.h @@ -4,9 +4,8 @@ // A DnsHostInfo object is used to store status of a Dns lookup of a specific // hostname. -// It includes progress, from placement in the DnsMaster's queue, to assignment -// to a slave, to resolution by the (blocking) DNS service as either FOUND or -// NO_SUCH_NAME. +// It includes progress, from placement in the DnsMaster's queue, to resolution +// by the DNS service as either FOUND or NO_SUCH_NAME. #ifndef CHROME_BROWSER_NET_DNS_HOST_INFO_H_ #define CHROME_BROWSER_NET_DNS_HOST_INFO_H_ @@ -54,9 +53,9 @@ class DnsHostInfo { enum DnsProcessingState { // When processed by our prefetching system, the states are: PENDING, // Constructor has completed. - QUEUED, // In prefetch queue but not yet assigned to a slave. - ASSIGNED, // Currently being processed by a slave. - ASSIGNED_BUT_MARKED, // Needs to be deleted as soon as slave is done. + QUEUED, // In prefetch queue but not yet being resolved. + ASSIGNED, // Currently being processed. + ASSIGNED_BUT_MARKED, // Needs to be deleted as soon as it's resolved. FOUND, // DNS prefetch search completed. NO_SUCH_NAME, // DNS prefetch search completed. // When processed by the network stack during navigation, the states are: diff --git a/chrome/browser/net/dns_host_info_unittest.cc b/chrome/browser/net/dns_host_info_unittest.cc index 79cca93..9d2fb21 100644 --- a/chrome/browser/net/dns_host_info_unittest.cc +++ b/chrome/browser/net/dns_host_info_unittest.cc @@ -41,8 +41,7 @@ TEST(DnsHostInfoTest, StateChangeTest) { EXPECT_FALSE(info.NeedsDnsUpdate(hostname1)) << "update needed after being queued"; info.SetAssignedState(); - EXPECT_FALSE(info.NeedsDnsUpdate(hostname1)) - << "update needed while assigned to slave"; + EXPECT_FALSE(info.NeedsDnsUpdate(hostname1)); info.SetFoundState(); EXPECT_FALSE(info.NeedsDnsUpdate(hostname1)) << "default expiration time is TOOOOO short"; @@ -69,8 +68,7 @@ TEST(DnsHostInfoTest, StateChangeTest) { // be found. We'll sleep for a while, and then come back with not-found. info.SetQueuedState(DnsHostInfo::UNIT_TEST_MOTIVATED); info.SetAssignedState(); - EXPECT_FALSE(info.NeedsDnsUpdate(hostname1)) - << "update needed while assigned to slave"; + EXPECT_FALSE(info.NeedsDnsUpdate(hostname1)); // Greater than minimal expected network latency on DNS lookup. PlatformThread::Sleep(25); info.SetNoSuchNameState(); diff --git a/chrome/browser/net/dns_master.cc b/chrome/browser/net/dns_master.cc index 4d477b0..c170e79 100644 --- a/chrome/browser/net/dns_master.cc +++ b/chrome/browser/net/dns_master.cc @@ -2,61 +2,79 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// See header file for description of class - #include "chrome/browser/net/dns_master.h" +#include <algorithm> #include <sstream> #include "base/histogram.h" +#include "base/lock.h" +#include "base/revocable_store.h" #include "base/stats_counters.h" #include "base/string_util.h" -#include "base/thread.h" -#include "base/win_util.h" -#include "chrome/browser/net/dns_slave.h" - -using base::TimeDelta; +#include "base/time.h" +#include "net/base/address_list.h" +#include "net/base/completion_callback.h" +#include "net/base/host_resolver.h" +#include "net/base/net_errors.h" namespace chrome_browser_net { -DnsMaster::DnsMaster(TimeDelta shutdown_wait_time) - : slaves_have_work_(&lock_), - slave_count_(0), - running_slave_count_(0), - shutdown_(false), - kShutdownWaitTime_(shutdown_wait_time) { - for (size_t i = 0; i < kSlaveCountMax; i++) { - thread_ids_[i] = 0; - thread_handles_[i] = 0; - slaves_[i] = NULL; +// static +const size_t DnsMaster::kMaxConcurrentLookups = 8; + +class DnsMaster::LookupRequest : RevocableStore::Revocable { + public: + LookupRequest(DnsMaster* master, const std::string& hostname) + : RevocableStore::Revocable(&master->pending_callbacks_), + callback_(this, &LookupRequest::OnLookupFinished), + hostname_(hostname), + master_(master) { + } + + bool Start() { + const int result = resolver_.Resolve(hostname_, 80, &addresses_, + &callback_); + return (result == net::ERR_IO_PENDING); } + + private: + void OnLookupFinished(int result) { + if (revoked()) { + delete this; + return; + } + + if (result == net::OK) + master_->SetFoundState(hostname_); + else + master_->SetNoSuchNameState(hostname_); + + delete this; + } + + net::CompletionCallbackImpl<LookupRequest> callback_; + const std::string hostname_; + net::HostResolver resolver_; + net::AddressList addresses_; + DnsMaster* master_; +}; + +DnsMaster::DnsMaster() : pending_lookups_(0), peak_pending_lookups_(0) { +} + +DnsMaster::~DnsMaster() { + pending_callbacks_.RevokeAll(); } // Overloaded Resolve() to take a vector of names. void DnsMaster::ResolveList(const NameList& hostnames, DnsHostInfo::ResolutionMotivation motivation) { - bool need_to_signal = false; - { - AutoLock auto_lock(lock_); - if (shutdown_) return; - if (slave_count_ < kSlaveCountMin) { - for (int target_count = std::min(hostnames.size(), kSlaveCountMin); - target_count > 0; - target_count--) - PreLockedCreateNewSlaveIfNeeded(); - } else { - PreLockedCreateNewSlaveIfNeeded(); // Allocate one per list call. - } + AutoLock auto_lock(lock_); - for (NameList::const_iterator it = hostnames.begin(); - it < hostnames.end(); - it++) { - if (PreLockedResolve(*it, motivation)) - need_to_signal = true; - } - } - if (need_to_signal) - slaves_have_work_.Signal(); + NameList::const_iterator it; + for (it = hostnames.begin(); it < hostnames.end(); ++it) + PreLockedResolve(*it, motivation); } // Basic Resolve() takes an invidual name, and adds it @@ -65,16 +83,8 @@ void DnsMaster::Resolve(const std::string& hostname, DnsHostInfo::ResolutionMotivation motivation) { if (0 == hostname.length()) return; - bool need_to_signal = false; - { - AutoLock auto_lock(lock_); - if (shutdown_) return; - PreLockedCreateNewSlaveIfNeeded(); // Allocate one at a time. - if (PreLockedResolve(hostname, motivation)) - need_to_signal = true; - } - if (need_to_signal) - slaves_have_work_.Signal(); + AutoLock auto_lock(lock_); + PreLockedResolve(hostname, motivation); } bool DnsMaster::AccruePrefetchBenefits(const GURL& referrer, @@ -147,26 +157,19 @@ void DnsMaster::NonlinkNavigation(const GURL& referrer, } void DnsMaster::NavigatingTo(const std::string& host_name) { - bool need_to_signal = false; - { - AutoLock auto_lock(lock_); - Referrers::iterator it = referrers_.find(host_name); - if (referrers_.end() == it) - return; - Referrer* referrer = &(it->second); - for (Referrer::iterator future_host = referrer->begin(); - future_host != referrer->end(); ++future_host) { - DnsHostInfo* queued_info = PreLockedResolve( - future_host->first, - DnsHostInfo::LEARNED_REFERAL_MOTIVATED); - if (queued_info) { - need_to_signal = true; - queued_info->SetReferringHostname(host_name); - } - } + AutoLock auto_lock(lock_); + Referrers::iterator it = referrers_.find(host_name); + if (referrers_.end() == it) + return; + Referrer* referrer = &(it->second); + for (Referrer::iterator future_host = referrer->begin(); + future_host != referrer->end(); ++future_host) { + DnsHostInfo* queued_info = PreLockedResolve( + future_host->first, + DnsHostInfo::LEARNED_REFERAL_MOTIVATED); + if (queued_info) + queued_info->SetReferringHostname(host_name); } - if (need_to_signal) - slaves_have_work_.Signal(); } // Provide sort order so all .com's are together, etc. @@ -297,7 +300,7 @@ void DnsMaster::GetHtmlInfo(std::string* output) { } if (!it->second.was_found()) continue; // Still being processed. - if (TimeDelta() != it->second.benefits_remaining()) { + if (base::TimeDelta() != it->second.benefits_remaining()) { network_hits.push_back(it->second); // With no benefit yet. continue; } @@ -332,7 +335,6 @@ DnsHostInfo* DnsMaster::PreLockedResolve( const std::string& hostname, DnsHostInfo::ResolutionMotivation motivation) { // DCHECK(We have the lock); - DCHECK(0 != slave_count_); DCHECK(0 != hostname.length()); DnsHostInfo* info = &results_[hostname]; @@ -349,37 +351,30 @@ DnsHostInfo* DnsMaster::PreLockedResolve( info->SetQueuedState(motivation); name_buffer_.push(hostname); + + PreLockedScheduleLookups(); + return info; } -// GetNextAssignment() is executed on the thread associated with -// with a prefetch slave instance. -// Return value of false indicates slave thread termination is needed. -// Return value of true means info argument was populated -// with a pointer to the assigned DnsHostInfo instance. -bool DnsMaster::GetNextAssignment(std::string* hostname) { - bool ask_for_help = false; - { - AutoLock auto_lock(lock_); // For map and buffer access - while (0 == name_buffer_.size() && !shutdown_) { - // No work pending, so just wait. - // wait on condition variable while releasing lock temporarilly. - slaves_have_work_.Wait(); - } - if (shutdown_) - return false; // Tell slaves to terminate also. - *hostname = name_buffer_.front(); +void DnsMaster::PreLockedScheduleLookups() { + while (!name_buffer_.empty() && pending_lookups_ < kMaxConcurrentLookups) { + const std::string hostname(name_buffer_.front()); name_buffer_.pop(); - DnsHostInfo* info = &results_[*hostname]; - DCHECK(info->HasHostname(*hostname)); + DnsHostInfo* info = &results_[hostname]; + DCHECK(info->HasHostname(hostname)); info->SetAssignedState(); - ask_for_help = name_buffer_.size() > 0; - } // Release lock_ - if (ask_for_help) - slaves_have_work_.Signal(); - return true; + LookupRequest* request = new LookupRequest(this, hostname); + if (request->Start()) { + pending_lookups_++; + peak_pending_lookups_ = std::max(peak_pending_lookups_, pending_lookups_); + } else { + NOTREACHED(); + delete request; + } + } } void DnsMaster::SetFoundState(const std::string hostname) { @@ -390,6 +385,9 @@ void DnsMaster::SetFoundState(const std::string hostname) { results_.erase(hostname); else info->SetFoundState(); + + pending_lookups_--; + PreLockedScheduleLookups(); } void DnsMaster::SetNoSuchNameState(const std::string hostname) { @@ -400,100 +398,9 @@ void DnsMaster::SetNoSuchNameState(const std::string hostname) { results_.erase(hostname); else info->SetNoSuchNameState(); -} - -bool DnsMaster::PreLockedCreateNewSlaveIfNeeded() { - // Don't create more than max. - if (kSlaveCountMax <= slave_count_ || shutdown_) - return false; - - DnsSlave* slave_instance = new DnsSlave(this, slave_count_); - DWORD thread_id; - size_t stack_size = 0; - unsigned int flags = CREATE_SUSPENDED; - if (win_util::GetWinVersion() >= win_util::WINVERSION_XP) { - // 128kb stack size. - stack_size = 128*1024; - flags |= STACK_SIZE_PARAM_IS_A_RESERVATION; - } - HANDLE handle = CreateThread(NULL, // security - stack_size, - DnsSlave::ThreadStart, - reinterpret_cast<void*>(slave_instance), - flags, - &thread_id); - DCHECK(NULL != handle); - if (NULL == handle) - return false; - - // Carlos suggests it is not valuable to do a set priority. - // BOOL WINAPI SetThreadPriority(handle,int nPriority); - - thread_ids_[slave_count_] = thread_id; - thread_handles_[slave_count_] = handle; - slaves_[slave_count_] = slave_instance; - slave_count_++; - - ResumeThread(handle); // WINAPI call. - running_slave_count_++; - - return true; -} -void DnsMaster::SetSlaveHasTerminated(int slave_index) { - DCHECK_EQ(GetCurrentThreadId(), thread_ids_[slave_index]); - AutoLock auto_lock(lock_); - running_slave_count_--; - DCHECK(thread_ids_[slave_index]); - thread_ids_[slave_index] = 0; -} - -bool DnsMaster::ShutdownSlaves() { - int running_slave_count; - { - AutoLock auto_lock(lock_); - shutdown_ = true; // Block additional resolution requests. - // Empty the queue gracefully - while (name_buffer_.size() > 0) { - std::string hostname = name_buffer_.front(); - name_buffer_.pop(); - DnsHostInfo* info = &results_[hostname]; - DCHECK(info->HasHostname(hostname)); - // We should be in Queued state, so simulate to end of life. - info->SetAssignedState(); // Simulate slave assignment. - info->SetNoSuchNameState(); // Simulate failed lookup. - results_.erase(hostname); - } - running_slave_count = running_slave_count_; - // Release lock, so slaves can finish up. - } - - if (running_slave_count) { - slaves_have_work_.Broadcast(); // Slaves need to check for termination. - - DWORD result = WaitForMultipleObjects( - slave_count_, - thread_handles_, - TRUE, // Wait for all - static_cast<DWORD>(kShutdownWaitTime_.InMilliseconds())); - - DCHECK(result != WAIT_TIMEOUT) << "Some slaves didn't stop"; - if (WAIT_TIMEOUT == result) - return false; - } - { - AutoLock auto_lock(lock_); - while (0 < slave_count_--) { - if (0 == thread_ids_[slave_count_]) { // Thread terminated. - int result = CloseHandle(thread_handles_[slave_count_]); - CHECK(result); - thread_handles_[slave_count_] = 0; - delete slaves_[slave_count_]; - slaves_[slave_count_] = NULL; - } - } - } - return true; + pending_lookups_--; + PreLockedScheduleLookups(); } void DnsMaster::DiscardAllResults() { @@ -514,10 +421,11 @@ void DnsMaster::DiscardAllResults() { info->SetAssignedState(); info->SetNoSuchNameState(); } - // Now every result_ is either resolved, or is being worked on by a slave. + // Now every result_ is either resolved, or is being resolved + // (see LookupRequest). // Step through result_, recording names of all hosts that can't be erased. - // We can't erase anything being worked on by a slave. + // We can't erase anything being worked on. Results assignees; for (Results::iterator it = results_.begin(); results_.end() != it; ++it) { std::string hostname = it->first; @@ -528,9 +436,9 @@ void DnsMaster::DiscardAllResults() { assignees[hostname] = *info; } } - DCHECK(kSlaveCountMax >= assignees.size()); + DCHECK(assignees.size() <= kMaxConcurrentLookups); results_.clear(); - // Put back in the names being worked on by slaves. + // Put back in the names being worked on. for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) { DCHECK(it->second.is_marked_to_delete()); results_[it->first] = it->second; @@ -538,4 +446,3 @@ void DnsMaster::DiscardAllResults() { } } // namespace chrome_browser_net - diff --git a/chrome/browser/net/dns_master.h b/chrome/browser/net/dns_master.h index 7620d7c..78f5540 100644 --- a/chrome/browser/net/dns_master.h +++ b/chrome/browser/net/dns_master.h @@ -3,16 +3,13 @@ // found in the LICENSE file. // A DnsMaster object is instantiated once in the browser -// process, and delivers DNS prefetch assignments (hostnames) -// to any of several DnsSlave objects. +// process, and manages asynchronous resolution of DNS hostnames. // Most hostname lists are sent out by renderer processes, and // involve lists of hostnames that *might* be used in the near // future by the browsing user. The goal of this class is to // cause the underlying DNS structure to lookup a hostname before // it is really needed, and hence reduce latency in the standard -// lookup paths. Since some DNS lookups may take a LONG time, we -// use several DnsSlave threads to concurrently perform the -// lookups. +// lookup paths. #ifndef CHROME_BROWSER_NET_DNS_MASTER_H_ #define CHROME_BROWSER_NET_DNS_MASTER_H_ @@ -21,40 +18,27 @@ #include <queue> #include <string> -#include "base/condition_variable.h" -#include "base/scoped_ptr.h" +#include "base/lock.h" +#include "base/revocable_store.h" #include "chrome/browser/net/dns_host_info.h" #include "chrome/browser/net/referrer.h" #include "chrome/common/net/dns.h" #include "googleurl/src/url_canon.h" +#include "testing/gtest/include/gtest/gtest_prod.h" namespace chrome_browser_net { -class DnsSlave; - typedef chrome_common_net::NameList NameList; typedef std::map<std::string, DnsHostInfo> Results; class DnsMaster { public: - // The number of slave processes that will do DNS prefetching - static const size_t kSlaveCountMax = 8; - - explicit DnsMaster(base::TimeDelta shutdown_wait_time); - - ~DnsMaster() { - if (!shutdown_) - ShutdownSlaves(); // Ensure we did our cleanup. - } + // Too many concurrent lookups negate benefits of prefetching + // by trashing the OS cache. + static const size_t kMaxConcurrentLookups; - // ShutdownSlaves() gets all spawned threads to terminate, closes - // their handles, and deletes their DnsSlave instances. - // Return value of true means all operations succeeded. - // Return value of false means that the threads wouldn't terminate, - // and that resources may leak. If this returns false, it is best - // to NOT delete this DnsMaster, as slave threads may still call into - // this object. - bool ShutdownSlaves(); + DnsMaster(); + ~DnsMaster(); // In some circumstances, for privacy reasons, all results should be // discarded. This method gracefully handles that activity. @@ -63,7 +47,7 @@ class DnsMaster { // (cache hits etc.). void DiscardAllResults(); - // Add hostname(s) to the queue for processing by slaves + // Add hostname(s) to the queue for processing. void ResolveList(const NameList& hostnames, DnsHostInfo::ResolutionMotivation motivation); void Resolve(const std::string& hostname, @@ -88,72 +72,62 @@ class DnsMaster { // domains. void GetHtmlInfo(std::string* output); - // For testing only... - // Currently testing only provides a crude measure of success. + private: + FRIEND_TEST(DnsMasterTest, BenefitLookupTest); + FRIEND_TEST(DnsMasterTest, ShutdownWhenResolutionIsPendingTest); + FRIEND_TEST(DnsMasterTest, SingleLookupTest); + FRIEND_TEST(DnsMasterTest, ConcurrentLookupTest); + FRIEND_TEST(DnsMasterTest, MassiveConcurrentLookupTest); + friend class WaitForResolutionHelper; // For testing. + + class LookupRequest; + + // A map that is keyed with the hostnames that we've learned were the cause + // of loading additional hostnames. The list of additional hostnames in held + // in a Referrer instance, which is found in this type. + typedef std::map<std::string, Referrer> Referrers; + + // Only for testing. Returns true if hostname has been successfully resolved + // (name found). bool WasFound(const std::string& hostname) { AutoLock auto_lock(lock_); return (results_.find(hostname) != results_.end()) && results_[hostname].was_found(); } - // Accessor methods, used mostly for testing. - // Both functions return DnsHostInfo::kNullDuration if name was not yet - // processed enough. - base::TimeDelta GetResolutionDuration(const std::string hostname) { + // Only for testing. Return how long was the resolution + // or DnsHostInfo::kNullDuration if it hasn't been resolved yet. + base::TimeDelta GetResolutionDuration(const std::string& hostname) { AutoLock auto_lock(lock_); if (results_.find(hostname) == results_.end()) return DnsHostInfo::kNullDuration; return results_[hostname].resolve_duration(); } - base::TimeDelta GetQueueDuration(const std::string hostname) { - AutoLock auto_lock(lock_); - if (results_.find(hostname) == results_.end()) - return DnsHostInfo::kNullDuration; - return results_[hostname].queue_duration(); - } - - size_t running_slave_count() { - AutoLock auto_lock(lock_); - return running_slave_count_; - } - - //---------------------------------------------------------------------------- - // Methods below this line should only be called by slave processes. - - // GetNextAssignment() gets the next hostname from queue for processing - // It is not meant to be public, and should only be used by the slave. - // GetNextAssignment() waits on a condition variable if there are no more - // names in queue. - // Return false if slave thread should terminate. - // Return true if slave thread should process the value. - bool GetNextAssignment(std::string* hostname); + // Only for testing; + size_t peak_pending_lookups() const { return peak_pending_lookups_; } - // Access methods for use by slave threads to callback with state updates. + // Access methods for use by lookup callbacks to pass resolution result. void SetFoundState(const std::string hostname); void SetNoSuchNameState(const std::string hostname); - // Notification during ShutdownSlaves. - void SetSlaveHasTerminated(int slave_index); - - private: - // A map that is keyed with the hostnames that we've learned were the cause - // of loading additional hostnames. The list of additional hostnames in held - // in a Referrer instance, which is found in this type. - typedef std::map<std::string, Referrer> Referrers; - // "PreLocked" means that the caller has already Acquired lock_ in the // following method names. // Queue hostname for resolution. If queueing was done, return the pointer // to the queued instance, otherwise return NULL. DnsHostInfo* PreLockedResolve(const std::string& hostname, DnsHostInfo::ResolutionMotivation motivation); - bool PreLockedCreateNewSlaveIfNeeded(); // Lazy slave processes creation. - // Number of slave processes started early (to help with startup prefetch). - static const size_t kSlaveCountMin = 4; + // Take lookup requests from name_buffer_ and tell HostResolver + // to look them up asynchronously, provided we don't exceed + // concurrent resolution limit. + void PreLockedScheduleLookups(); - // Synchronize access to results_, referrers_, and slave control data. + // Synchronize access to results_, referrers_, pending_lookups_. + // TODO(phajdan.jr): Re-evaluate usage of this lock. After restructuring + // the code to run only on the IO thread and using PostTask from other threads + // the lock should not be needed. If that's not possible, then at least its + // usage can be reduced. Lock lock_; // name_buffer_ holds a list of names we need to look up. @@ -167,25 +141,13 @@ class DnsMaster { // pre-resolve when there is a navigation to the orginial hostname. Referrers referrers_; - // Signaling slaves to process elements in the queue, or to terminate, - // is done using ConditionVariables. - ConditionVariable slaves_have_work_; - - size_t slave_count_; // Count of slave processes started. - size_t running_slave_count_; // Count of slaves process still running. - - // The following arrays are only initialized as - // slave_count_ grows (up to the indicated max). - DWORD thread_ids_[kSlaveCountMax]; - HANDLE thread_handles_[kSlaveCountMax]; - DnsSlave* slaves_[kSlaveCountMax]; + // Count of started, but not yet finished dns lookups + size_t pending_lookups_; - // shutdown_ is set to tell the slaves to terminate. - bool shutdown_; + // For testing, to verify that we don't exceed the limit; + size_t peak_pending_lookups_; - // The following is the maximum time the ShutdownSlaves method - // will wait for all the slave processes to terminate. - const base::TimeDelta kShutdownWaitTime_; + RevocableStore pending_callbacks_; // We'll cancel them on shutdown. // A list of successful events resulting from pre-fetching. DnsHostInfo::DnsInfoTable cache_hits_; diff --git a/chrome/browser/net/dns_master_unittest.cc b/chrome/browser/net/dns_master_unittest.cc index 650a8ff..70c263c2 100644 --- a/chrome/browser/net/dns_master_unittest.cc +++ b/chrome/browser/net/dns_master_unittest.cc @@ -2,104 +2,89 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Multi-threaded tests of DnsMaster and DnsPrefetch slave functionality. - #include <time.h> -#include <ws2tcpip.h> -#include <Wspiapi.h> // Needed for win2k compatibility #include <algorithm> #include <map> #include <sstream> #include <string> +#include <vector> +#include "base/message_loop.h" #include "base/platform_thread.h" #include "base/spin_wait.h" +#include "base/timer.h" #include "chrome/browser/net/dns_global.h" #include "chrome/browser/net/dns_host_info.h" -#include "chrome/browser/net/dns_slave.h" +#include "chrome/common/net/dns.h" +#include "net/base/address_list.h" +#include "net/base/host_resolver.h" +#include "net/base/scoped_host_mapper.h" #include "net/base/winsock_init.h" #include "testing/gtest/include/gtest/gtest.h" - using base::Time; using base::TimeDelta; -namespace { +namespace chrome_browser_net { -class DnsMasterTest : public testing::Test { -}; +class WaitForResolutionHelper; -typedef chrome_browser_net::DnsMaster DnsMaster; -typedef chrome_browser_net::DnsPrefetcherInit DnsPrefetcherInit; -typedef chrome_browser_net::DnsHostInfo DnsHostInfo; -typedef chrome_browser_net::NameList NameList; +typedef base::RepeatingTimer<WaitForResolutionHelper> HelperTimer; +class WaitForResolutionHelper { + public: + WaitForResolutionHelper(DnsMaster* master, const NameList& hosts, + HelperTimer* timer) + : master_(master), + hosts_(hosts), + timer_(timer) { + } -//------------------------------------------------------------------------------ -// Provide network function stubs to run tests offline (and avoid the variance -// of real DNS lookups. -//------------------------------------------------------------------------------ + void Run() { + for (NameList::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i) + if (master_->GetResolutionDuration(*i) == DnsHostInfo::kNullDuration) + return; // We don't have resolution for that host. -static void __stdcall fake_free_addr_info(struct addrinfo* ai) { - // Kill off the dummy results. - EXPECT_TRUE(NULL != ai); - delete ai; -} + // When all hostnames have been resolved, exit the loop. + timer_->Stop(); + MessageLoop::current()->Quit(); + delete timer_; + delete this; + } -static int __stdcall fake_get_addr_info(const char* nodename, - const char* servname, - const struct addrinfo* hints, - struct addrinfo** result) { - static Lock lock; - int duration; - bool was_found; - std::string hostname(nodename); - // Dummy up *some* return results to pass along. - *result = new addrinfo; - EXPECT_TRUE(NULL != *result); - { - AutoLock autolock(lock); - - static bool initialized = false; - typedef std::map<std::string, int> Latency; - static Latency latency; - static std::map<std::string, bool> found; - if (!initialized) { - initialized = true; - // List all known hostnames - latency["www.google.com"] = 50; - latency["gmail.google.com.com"] = 70; - latency["mail.google.com"] = 44; - latency["gmail.com"] = 63; - - for (Latency::iterator it = latency.begin(); latency.end() != it; it++) { - found[it->first] = true; - } - } // End static initialization - - was_found = found[hostname]; - - if (latency.end() != latency.find(hostname)) { - duration = latency[hostname]; - } else { - duration = 500; - } - // Change latency to simulate cache warming (next latency will be short). - latency[hostname] = 1; - } // Release lock. - - PlatformThread::Sleep(duration); - - return was_found ? 0 : WSAHOST_NOT_FOUND; -} + private: + DnsMaster* master_; + const NameList hosts_; + HelperTimer* timer_; +}; -static void SetupNetworkInfrastructure() { - bool kUseFakeNetwork = true; - if (kUseFakeNetwork) - chrome_browser_net::SetAddrinfoCallbacks(fake_get_addr_info, - fake_free_addr_info); -} +class DnsMasterTest : public testing::Test { + protected: + virtual void SetUp() { +#if defined(OS_WIN) + net::EnsureWinsockInit(); +#endif + mapper_.AddRuleWithLatency("www.google.com", "127.0.0.1", 50); + mapper_.AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70); + mapper_.AddRuleWithLatency("mail.google.com", "127.0.0.1", 44); + mapper_.AddRuleWithLatency("gmail.com", "127.0.0.1", 63); + + mapper_.AddRuleWithLatency("veryslow.net", "127.0.0.1", 10000); + } + + void WaitForResolution(DnsMaster* master, const NameList& hosts) { + HelperTimer* timer = new HelperTimer(); + timer->Start(TimeDelta::FromMilliseconds(100), + new WaitForResolutionHelper(master, hosts, timer), + &WaitForResolutionHelper::Run); + MessageLoop::current()->Run(); + } + + private: + MessageLoop loop_; + net::ScopedHostMapper mapper_; +}; //------------------------------------------------------------------------------ // Provide a function to create unique (nonexistant) domains at *every* call. @@ -120,53 +105,63 @@ static std::string GetNonexistantDomain() { // Use a blocking function to contrast results we get via async services. //------------------------------------------------------------------------------ TimeDelta BlockingDnsLookup(const std::string& hostname) { - char* port = "80"; // I may need to get the real port - struct addrinfo* result = NULL; Time start = Time::Now(); - // Use the same underlying methods as dns_prefetch_slave does - chrome_browser_net::get_getaddrinfo()(hostname.c_str(), port, - NULL, &result); - - TimeDelta duration = Time::Now() - start; - - if (result) { - chrome_browser_net::get_freeaddrinfo()(result); - result = NULL; - } + net::HostResolver resolver; + net::AddressList addresses; + resolver.Resolve(hostname, 80, &addresses, NULL); - return duration; + return Time::Now() - start; } //------------------------------------------------------------------------------ // First test to be sure the OS is caching lookups, which is the whole premise // of DNS prefetching. -TEST(DnsMasterTest, OsCachesLookupsTest) { - SetupNetworkInfrastructure(); - net::EnsureWinsockInit(); - - for (int i = 0; i < 5; i++) { +TEST_F(DnsMasterTest, OsCachesLookupsTest) { + const Time start = Time::Now(); + int all_lookups = 0; + int lookups_with_improvement = 0; + // This test can be really flaky on Linux. It should run in much shorter time, + // but sometimes it won't and we don't like bogus failures. + while (Time::Now() - start < TimeDelta::FromMinutes(1)) { std::string badname; badname = GetNonexistantDomain(); + TimeDelta duration = BlockingDnsLookup(badname); - TimeDelta cached_duration = BlockingDnsLookup(badname); - EXPECT_TRUE(duration > cached_duration); + + // Produce more than one result and remove the largest one + // to reduce flakiness. + std::vector<TimeDelta> cached_results; + for (int j = 0; j < 3; j++) + cached_results.push_back(BlockingDnsLookup(badname)); + std::sort(cached_results.begin(), cached_results.end()); + cached_results.pop_back(); + + TimeDelta cached_sum = TimeDelta::FromSeconds(0); + for (std::vector<TimeDelta>::const_iterator j = cached_results.begin(); + j != cached_results.end(); ++j) + cached_sum += *j; + TimeDelta cached_duration = cached_sum / cached_results.size(); + + all_lookups++; + if (cached_duration < duration) + lookups_with_improvement++; + if (all_lookups >= 10) + if (lookups_with_improvement * 100 > all_lookups * 75) + // Okay, we see the improvement for more than 75% of all lookups. + return; } + FAIL() << "No substantial improvement in lookup time."; } -TEST(DnsMasterTest, StartupShutdownTest) { - DnsMaster testing_master(TimeDelta::FromMilliseconds(5000)); - - // With no threads, we should have no problem doing a shutdown. - EXPECT_TRUE(testing_master.ShutdownSlaves()); +TEST_F(DnsMasterTest, StartupShutdownTest) { + DnsMaster testing_master; + // We do shutdown on destruction. } -TEST(DnsMasterTest, BenefitLookupTest) { - SetupNetworkInfrastructure(); - net::EnsureWinsockInit(); - DnsPrefetcherInit dns_init(NULL); // Creates global service . - DnsMaster testing_master(TimeDelta::FromMilliseconds(5000)); +TEST_F(DnsMasterTest, BenefitLookupTest) { + DnsMaster testing_master; std::string goog("www.google.com"), goog2("gmail.google.com.com"), @@ -196,23 +191,9 @@ TEST(DnsMasterTest, BenefitLookupTest) { names.insert(names.end(), goog3); names.insert(names.end(), goog4); - // First only cause a minimal set of threads to start up. - // Currently we actually start 4 threads when we get called with an array testing_master.ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); - // Wait for some resoultion for each google. - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog).InMilliseconds()); - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog2).InMilliseconds()); - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog3).InMilliseconds()); - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog4).InMilliseconds()); - - EXPECT_EQ(std::min(names.size(), - 4u /* chrome_browser_net::DnsMaster::kSlaveCountMin */ ), - testing_master.running_slave_count()); + WaitForResolution(&testing_master, names); EXPECT_TRUE(testing_master.WasFound(goog)); EXPECT_TRUE(testing_master.WasFound(goog2)); @@ -234,68 +215,51 @@ TEST(DnsMasterTest, BenefitLookupTest) { EXPECT_FALSE(testing_master.AccruePrefetchBenefits(GURL(), &goog2_info)); EXPECT_FALSE(testing_master.AccruePrefetchBenefits(GURL(), &goog3_info)); EXPECT_FALSE(testing_master.AccruePrefetchBenefits(GURL(), &goog4_info)); - - // Ensure a clean shutdown. - EXPECT_TRUE(testing_master.ShutdownSlaves()); } -TEST(DnsMasterTest, DISABLED_SingleSlaveLookupTest) { - SetupNetworkInfrastructure(); - net::EnsureWinsockInit(); - DnsPrefetcherInit dns_init(NULL); // Creates global service. - DnsMaster testing_master(TimeDelta::FromMilliseconds(5000)); +TEST_F(DnsMasterTest, ShutdownWhenResolutionIsPendingTest) { + DnsMaster testing_master; - std::string goog("www.google.com"), - goog2("gmail.google.com.com"), - goog3("mail.google.com"), - goog4("gmail.com"); - std::string bad1(GetNonexistantDomain()), - bad2(GetNonexistantDomain()); + std::string slow("veryslow.net"); + NameList names; + names.insert(names.end(), slow); - // Warm up local OS cache. - BlockingDnsLookup(goog); + testing_master.ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); + + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new MessageLoop::QuitTask(), 500); + MessageLoop::current()->Run(); + MessageLoop::current()->RunAllPending(); + + EXPECT_FALSE(testing_master.WasFound(slow)); +} + +TEST_F(DnsMasterTest, SingleLookupTest) { + DnsMaster testing_master; + + std::string goog("www.google.com"); NameList names; names.insert(names.end(), goog); - names.insert(names.end(), bad1); - names.insert(names.end(), bad2); - // First only cause a single thread to start up - testing_master.ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); + // Try to flood the master with many concurrent requests. + for (int i = 0; i < 10; i++) + testing_master.ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); - // Wait for some resoultion for google. - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog).InMilliseconds()); + WaitForResolution(&testing_master, names); EXPECT_TRUE(testing_master.WasFound(goog)); - EXPECT_FALSE(testing_master.WasFound(bad1)); - EXPECT_FALSE(testing_master.WasFound(bad2)); - // Verify the reason it is not found is that it is still being proceessed. - // Negative time mean no resolution yet. - EXPECT_GT(0, testing_master.GetResolutionDuration(bad2).InMilliseconds()); - - // Spin long enough that we *do* find the resolution of bad2. - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(bad2).InMilliseconds()); - - // Verify both fictitious names are resolved by now. - // Typical random name takes about 20-30 ms - EXPECT_LT(0, testing_master.GetResolutionDuration(bad1).InMilliseconds()); - EXPECT_LT(0, testing_master.GetResolutionDuration(bad2).InMilliseconds()); - EXPECT_FALSE(testing_master.WasFound(bad1)); - EXPECT_FALSE(testing_master.WasFound(bad2)); - EXPECT_EQ(1U, testing_master.running_slave_count()); + MessageLoop::current()->RunAllPending(); - // With just one thread (doing nothing now), ensure a clean shutdown. - EXPECT_TRUE(testing_master.ShutdownSlaves()); + EXPECT_GT(testing_master.peak_pending_lookups(), names.size() / 2); + EXPECT_LE(testing_master.peak_pending_lookups(), names.size()); + EXPECT_LE(testing_master.peak_pending_lookups(), + DnsMaster::kMaxConcurrentLookups); } -TEST(DnsMasterTest, DISABLED_MultiThreadedLookupTest) { - SetupNetworkInfrastructure(); - net::EnsureWinsockInit(); - DnsMaster testing_master(TimeDelta::FromSeconds(30)); - DnsPrefetcherInit dns_init(NULL); +TEST_F(DnsMasterTest, ConcurrentLookupTest) { + DnsMaster testing_master; std::string goog("www.google.com"), goog2("gmail.google.com.com"), @@ -319,12 +283,11 @@ TEST(DnsMasterTest, DISABLED_MultiThreadedLookupTest) { BlockingDnsLookup(goog3); BlockingDnsLookup(goog4); - // Get all 8 threads running by calling many times before queue is handled. - for (int i = 0; i < 10; i++) { + // Try to flood the master with many concurrent requests. + for (int i = 0; i < 10; i++) testing_master.ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); - } - Sleep(10); // Allow time for async DNS to get answers. + WaitForResolution(&testing_master, names); EXPECT_TRUE(testing_master.WasFound(goog)); EXPECT_TRUE(testing_master.WasFound(goog3)); @@ -333,100 +296,35 @@ TEST(DnsMasterTest, DISABLED_MultiThreadedLookupTest) { EXPECT_FALSE(testing_master.WasFound(bad1)); EXPECT_FALSE(testing_master.WasFound(bad2)); - EXPECT_EQ(8U, testing_master.running_slave_count()); - - EXPECT_TRUE(testing_master.ShutdownSlaves()); -} - -TEST(DnsMasterTest, DISABLED_MultiThreadedSpeedupTest) { - SetupNetworkInfrastructure(); - net::EnsureWinsockInit(); - DnsMaster testing_master(TimeDelta::FromSeconds(30)); - DnsPrefetcherInit dns_init(NULL); + MessageLoop::current()->RunAllPending(); - std::string goog("www.google.com"), - goog2("gmail.google.com.com"), - goog3("mail.google.com"), - goog4("gmail.com"); - std::string bad1(GetNonexistantDomain()), - bad2(GetNonexistantDomain()), - bad3(GetNonexistantDomain()), - bad4(GetNonexistantDomain()); - - NameList names; - names.insert(names.end(), goog); - names.insert(names.end(), bad1); - names.insert(names.end(), bad2); - names.insert(names.end(), goog3); - names.insert(names.end(), goog2); - names.insert(names.end(), bad3); - names.insert(names.end(), bad4); - names.insert(names.end(), goog4); - - // First cause a lookup using a single thread. - testing_master.ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); - - // Wait for some resoultion for google. - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog).InMilliseconds()); - - EXPECT_TRUE(testing_master.WasFound(goog)); EXPECT_FALSE(testing_master.WasFound(bad1)); EXPECT_FALSE(testing_master.WasFound(bad2)); - // ...and due to delay in geting resolution of bad names, the single slave - // thread won't have time to finish the list. - EXPECT_FALSE(testing_master.WasFound(goog3)); - EXPECT_FALSE(testing_master.WasFound(goog2)); - EXPECT_FALSE(testing_master.WasFound(goog4)); - - EXPECT_EQ(1U, testing_master.running_slave_count()); - // Get all 8 threads running by calling many times before queue is handled. - names.clear(); - for (int i = 0; i < 10; i++) - testing_master.Resolve(GetNonexistantDomain(), - DnsHostInfo::PAGE_SCAN_MOTIVATED); - - // Wait long enough for all the goog's to be resolved. - // They should all take about the same time, and run in parallel. - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog2).InMilliseconds()); - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog3).InMilliseconds()); - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(goog4).InMilliseconds()); - - EXPECT_TRUE(testing_master.WasFound(goog3)); - EXPECT_TRUE(testing_master.WasFound(goog2)); - EXPECT_TRUE(testing_master.WasFound(goog4)); - - EXPECT_FALSE(testing_master.WasFound(bad1)); - EXPECT_FALSE(testing_master.WasFound(bad2)); // Perhaps not even decided. - - // Queue durations should be distinct from when 1 slave was working. - EXPECT_GT(testing_master.GetQueueDuration(goog3).InMilliseconds(), - testing_master.GetQueueDuration(goog).InMilliseconds()); - EXPECT_GT(testing_master.GetQueueDuration(goog4).InMilliseconds(), - testing_master.GetQueueDuration(goog).InMilliseconds()); + EXPECT_GT(testing_master.peak_pending_lookups(), names.size() / 2); + EXPECT_LE(testing_master.peak_pending_lookups(), names.size()); + EXPECT_LE(testing_master.peak_pending_lookups(), + DnsMaster::kMaxConcurrentLookups); +} - // Give bad names a chance to be determined as unresolved. - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(bad1).InMilliseconds()); - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <= - testing_master.GetResolutionDuration(bad2).InMilliseconds()); +TEST_F(DnsMasterTest, MassiveConcurrentLookupTest) { + DnsMaster testing_master; + NameList names; + for (int i = 0; i < 100; i++) + names.push_back(GetNonexistantDomain()); - // Well known names should resolve faster than bad names. - EXPECT_GE(testing_master.GetResolutionDuration(bad1).InMilliseconds(), - testing_master.GetResolutionDuration(goog).InMilliseconds()); + // Try to flood the master with many concurrent requests. + for (int i = 0; i < 10; i++) + testing_master.ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); - EXPECT_GE(testing_master.GetResolutionDuration(bad2).InMilliseconds(), - testing_master.GetResolutionDuration(goog4).InMilliseconds()); + WaitForResolution(&testing_master, names); - EXPECT_EQ(8U, testing_master.running_slave_count()); + MessageLoop::current()->RunAllPending(); - EXPECT_TRUE(testing_master.ShutdownSlaves()); + EXPECT_LE(testing_master.peak_pending_lookups(), names.size()); + EXPECT_LE(testing_master.peak_pending_lookups(), + DnsMaster::kMaxConcurrentLookups); } -} // namespace - +} // namespace chrome_browser_net diff --git a/chrome/browser/net/dns_slave.cc b/chrome/browser/net/dns_slave.cc deleted file mode 100644 index 2ffb78d..0000000 --- a/chrome/browser/net/dns_slave.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2006-2008 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. - -// See header file for description of class - -#include <ws2tcpip.h> -#include <Wspiapi.h> // Needed for win2k compatibility - -#include "chrome/browser/net/dns_slave.h" - -#include "base/logging.h" -#include "base/platform_thread.h" -#include "base/string_util.h" -#include "chrome/browser/net/dns_host_info.h" -#include "chrome/browser/net/dns_master.h" - - -namespace chrome_browser_net { - -//------------------------------------------------------------------------------ -// We supply a functions for stubbing network callbacks, so that offline testing -// can be performed. -//------------------------------------------------------------------------------ -static GetAddrInfoFunction get_addr = getaddrinfo; -static FreeAddrInfoFunction free_addr = freeaddrinfo; -void SetAddrinfoCallbacks(GetAddrInfoFunction getaddrinfo, - FreeAddrInfoFunction freeaddrinfo) { - get_addr = getaddrinfo; - free_addr = freeaddrinfo; -} - -GetAddrInfoFunction get_getaddrinfo() {return get_addr;} -FreeAddrInfoFunction get_freeaddrinfo() {return free_addr;} - - -//------------------------------------------------------------------------------ -// This is the entry method used by DnsMaster to start our thread. -//------------------------------------------------------------------------------ - -DWORD __stdcall DnsSlave::ThreadStart(void* pThis) { - DnsSlave* slave_instance = reinterpret_cast<DnsSlave*>(pThis); - return slave_instance->Run(); -} - -//------------------------------------------------------------------------------ -// The following are methods on the DnsPrefetch class. -//------------------------------------------------------------------------------ - -unsigned DnsSlave::Run() { - DCHECK(slave_index_ >= 0 && slave_index_ < DnsMaster::kSlaveCountMax); - - std::string name = StringPrintf( - "dns_prefetcher_%d_of_%d", slave_index_ + 1, DnsMaster::kSlaveCountMax); - DLOG(INFO) << "Now Running " << name; - PlatformThread::SetName(name.c_str()); - - while (master_->GetNextAssignment(&hostname_)) { - BlockingDnsLookup(); - } - // GetNextAssignment() fails when we are told to terminate. - master_->SetSlaveHasTerminated(slave_index_); - return 0; -} - -void DnsSlave::BlockingDnsLookup() { - const char* port = "80"; // I may need to get the real port - addrinfo* result = NULL; - - int error_code = get_addr(hostname_.c_str(), port, NULL, &result); - - // Note that since info has value semantics, I need to ask - // master_ to set the new states atomically in its map. - switch (error_code) { - case 0: - master_->SetFoundState(hostname_); - break; - - default: - DCHECK_EQ(0, error_code) << "surprising output" ; - // fall through - - case WSAHOST_NOT_FOUND: - master_->SetNoSuchNameState(hostname_); - break; - } - - // We don't save results, so lets free them... - if (result) { - free_addr(result); - result = NULL; - } -} - -} // namespace chrome_browser_net - diff --git a/chrome/browser/net/dns_slave.h b/chrome/browser/net/dns_slave.h deleted file mode 100644 index 6bbc17f..0000000 --- a/chrome/browser/net/dns_slave.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2006-2008 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. - -// A DnsSlave object processes hostname lookups -// via DNS on a single thread, waiting for that blocking -// call to complete, and then getting its next hostname -// from its associated DnsMaster object. -// Since this class only is concerned with prefetching -// to warm the underlying DNS cache, the actual IP -// does not need to be recorded. It is necessary to record -// when the lookup finished, so that the associated DnsMaster -// won't (wastefully) ask for the same name in "too short a -// period of time." -// This class does no "de-duping," and merely slavishly services -// items supplied by its DnsMaster. - -#ifndef CHROME_BROWSER_NET_DNS_SLAVE_H_ -#define CHROME_BROWSER_NET_DNS_SLAVE_H_ - -#include <windows.h> -#include <string> - -#include "base/basictypes.h" - -namespace chrome_browser_net { - -class DnsMaster; -class DnsSlave; - -// Support testing infrastructure, and allow off-line testing. -typedef void (__stdcall *FreeAddrInfoFunction)(struct addrinfo* ai); -typedef int (__stdcall *GetAddrInfoFunction)(const char* nodename, - const char* servname, - const struct addrinfo* hints, - struct addrinfo** result); -void SetAddrinfoCallbacks(GetAddrInfoFunction getaddrinfo, - FreeAddrInfoFunction freeaddrinfo); - -GetAddrInfoFunction get_getaddrinfo(); -FreeAddrInfoFunction get_freeaddrinfo(); - -class DnsSlave { - public: - DnsSlave(DnsMaster* master, size_t slave_index) - : master_(master), - slave_index_(slave_index) { - } - - ~DnsSlave() { - master_ = NULL; - } - - static DWORD WINAPI ThreadStart(void* pThis); - - unsigned Run(); - - private: - std::string hostname_; // Name being looked up. - - DnsMaster* master_; // Master that started us. - size_t slave_index_; // Our index into DnsMaster's array. - - void BlockingDnsLookup(); - - DISALLOW_COPY_AND_ASSIGN(DnsSlave); -}; - -} // namespace chrome_browser_net - -#endif // CHROME_BROWSER_NET_DNS_SLAVE_H_ - |