summaryrefslogtreecommitdiffstats
path: root/chrome/browser/net/dns_master.cc
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-26 15:10:43 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-26 15:10:43 +0000
commitfdc58a9963abb0a9f4cac157b2f3f1eac8e4160d (patch)
tree889dd032162f3c876c2bdcaa84a8b3717f134995 /chrome/browser/net/dns_master.cc
parent9127ca05f3d1cc8308a35429876b18090814ae73 (diff)
downloadchromium_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.cc289
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
-