diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-26 15:10:43 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-26 15:10:43 +0000 |
commit | fdc58a9963abb0a9f4cac157b2f3f1eac8e4160d (patch) | |
tree | 889dd032162f3c876c2bdcaa84a8b3717f134995 /chrome/browser/net/dns_master.cc | |
parent | 9127ca05f3d1cc8308a35429876b18090814ae73 (diff) | |
download | chromium_src-fdc58a9963abb0a9f4cac157b2f3f1eac8e4160d.zip chromium_src-fdc58a9963abb0a9f4cac157b2f3f1eac8e4160d.tar.gz chromium_src-fdc58a9963abb0a9f4cac157b2f3f1eac8e4160d.tar.bz2 |
Clean up dns prefetch code, and also port it.
BUG=5687, 6683
Review URL: http://codereview.chromium.org/15076
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8625 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/net/dns_master.cc')
-rw-r--r-- | chrome/browser/net/dns_master.cc | 289 |
1 files changed, 98 insertions, 191 deletions
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 - |