Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: chrome/browser/net/dns_master.cc

Issue 21133: Revert "Clean up dns prefetch code, and also port it." (Closed)
Patch Set: Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/net/dns_master.h ('k') | chrome/browser/net/dns_master_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // See header file for description of class
6
5 #include "chrome/browser/net/dns_master.h" 7 #include "chrome/browser/net/dns_master.h"
6 8
7 #include <algorithm>
8 #include <set>
9 #include <sstream> 9 #include <sstream>
10 10
11 #include "base/compiler_specific.h"
12 #include "base/histogram.h" 11 #include "base/histogram.h"
13 #include "base/lock.h"
14 #include "base/ref_counted.h"
15 #include "base/stats_counters.h" 12 #include "base/stats_counters.h"
16 #include "base/string_util.h" 13 #include "base/string_util.h"
17 #include "base/time.h" 14 #include "base/thread.h"
18 #include "net/base/address_list.h" 15 #include "base/win_util.h"
19 #include "net/base/completion_callback.h" 16 #include "chrome/browser/net/dns_slave.h"
20 #include "net/base/host_resolver.h" 17
21 #include "net/base/net_errors.h" 18 using base::TimeDelta;
22 19
23 namespace chrome_browser_net { 20 namespace chrome_browser_net {
24 21
25 // static 22 DnsMaster::DnsMaster(TimeDelta shutdown_wait_time)
26 const size_t DnsMaster::kMaxConcurrentLookups = 8; 23 : slaves_have_work_(&lock_),
27 24 slave_count_(0),
28 class DnsMaster::LookupRequest { 25 running_slave_count_(0),
29 public: 26 shutdown_(false),
30 LookupRequest(DnsMaster* master, const std::string& hostname) 27 kShutdownWaitTime_(shutdown_wait_time) {
31 : ALLOW_THIS_IN_INITIALIZER_LIST( 28 for (size_t i = 0; i < kSlaveCountMax; i++) {
32 net_callback_(this, &LookupRequest::OnLookupFinished)), 29 thread_ids_[i] = 0;
33 master_(master), 30 thread_handles_[i] = 0;
34 hostname_(hostname) { 31 slaves_[i] = NULL;
35 }
36
37 bool Start() {
38 const int result = resolver_.Resolve(hostname_, 80, &addresses_,
39 &net_callback_);
40 return (result == net::ERR_IO_PENDING);
41 }
42
43 private:
44 void OnLookupFinished(int result) {
45 master_->OnLookupFinished(this, hostname_, result == net::OK);
46 }
47
48 // HostResolver will call us using this callback when resolution is complete.
49 net::CompletionCallbackImpl<LookupRequest> net_callback_;
50
51 DnsMaster* master_; // Master which started us.
52
53 const std::string hostname_; // Hostname to resolve.
54 net::HostResolver resolver_;
55 net::AddressList addresses_;
56
57 DISALLOW_COPY_AND_ASSIGN(LookupRequest);
58 };
59
60 DnsMaster::DnsMaster() : peak_pending_lookups_(0) {
61 }
62
63 DnsMaster::~DnsMaster() {
64 for (std::set<LookupRequest*>::iterator it = pending_lookups_.begin();
65 it != pending_lookups_.end(); ++it) {
66 delete *it;
67 } 32 }
68 } 33 }
69 34
70 // Overloaded Resolve() to take a vector of names. 35 // Overloaded Resolve() to take a vector of names.
71 void DnsMaster::ResolveList(const NameList& hostnames, 36 void DnsMaster::ResolveList(const NameList& hostnames,
72 DnsHostInfo::ResolutionMotivation motivation) { 37 DnsHostInfo::ResolutionMotivation motivation) {
73 AutoLock auto_lock(lock_); 38 bool need_to_signal = false;
39 {
40 AutoLock auto_lock(lock_);
41 if (shutdown_) return;
42 if (slave_count_ < kSlaveCountMin) {
43 for (int target_count = std::min(hostnames.size(), kSlaveCountMin);
44 target_count > 0;
45 target_count--)
46 PreLockedCreateNewSlaveIfNeeded();
47 } else {
48 PreLockedCreateNewSlaveIfNeeded(); // Allocate one per list call.
49 }
74 50
75 NameList::const_iterator it; 51 for (NameList::const_iterator it = hostnames.begin();
76 for (it = hostnames.begin(); it < hostnames.end(); ++it) 52 it < hostnames.end();
77 PreLockedResolve(*it, motivation); 53 it++) {
54 if (PreLockedResolve(*it, motivation))
55 need_to_signal = true;
56 }
57 }
58 if (need_to_signal)
59 slaves_have_work_.Signal();
78 } 60 }
79 61
80 // Basic Resolve() takes an invidual name, and adds it 62 // Basic Resolve() takes an invidual name, and adds it
81 // to the queue. 63 // to the queue.
82 void DnsMaster::Resolve(const std::string& hostname, 64 void DnsMaster::Resolve(const std::string& hostname,
83 DnsHostInfo::ResolutionMotivation motivation) { 65 DnsHostInfo::ResolutionMotivation motivation) {
84 if (0 == hostname.length()) 66 if (0 == hostname.length())
85 return; 67 return;
86 AutoLock auto_lock(lock_); 68 bool need_to_signal = false;
87 PreLockedResolve(hostname, motivation); 69 {
70 AutoLock auto_lock(lock_);
71 if (shutdown_) return;
72 PreLockedCreateNewSlaveIfNeeded(); // Allocate one at a time.
73 if (PreLockedResolve(hostname, motivation))
74 need_to_signal = true;
75 }
76 if (need_to_signal)
77 slaves_have_work_.Signal();
88 } 78 }
89 79
90 bool DnsMaster::AccruePrefetchBenefits(const GURL& referrer, 80 bool DnsMaster::AccruePrefetchBenefits(const GURL& referrer,
91 DnsHostInfo* navigation_info) { 81 DnsHostInfo* navigation_info) {
92 std::string hostname = navigation_info->hostname(); 82 std::string hostname = navigation_info->hostname();
93 83
94 AutoLock auto_lock(lock_); 84 AutoLock auto_lock(lock_);
95 Results::iterator it = results_.find(hostname); 85 Results::iterator it = results_.find(hostname);
96 if (it == results_.end()) { 86 if (it == results_.end()) {
97 // Remain under lock to assure static HISTOGRAM constructor is safely run. 87 // Remain under lock to assure static HISTOGRAM constructor is safely run.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 void DnsMaster::NonlinkNavigation(const GURL& referrer, 140 void DnsMaster::NonlinkNavigation(const GURL& referrer,
151 DnsHostInfo* navigation_info) { 141 DnsHostInfo* navigation_info) {
152 std::string referring_host = referrer.host(); 142 std::string referring_host = referrer.host();
153 if (referring_host.empty() || referring_host == navigation_info->hostname()) 143 if (referring_host.empty() || referring_host == navigation_info->hostname())
154 return; 144 return;
155 145
156 referrers_[referring_host].SuggestHost(navigation_info->hostname()); 146 referrers_[referring_host].SuggestHost(navigation_info->hostname());
157 } 147 }
158 148
159 void DnsMaster::NavigatingTo(const std::string& host_name) { 149 void DnsMaster::NavigatingTo(const std::string& host_name) {
160 AutoLock auto_lock(lock_); 150 bool need_to_signal = false;
161 Referrers::iterator it = referrers_.find(host_name); 151 {
162 if (referrers_.end() == it) 152 AutoLock auto_lock(lock_);
163 return; 153 Referrers::iterator it = referrers_.find(host_name);
164 Referrer* referrer = &(it->second); 154 if (referrers_.end() == it)
165 for (Referrer::iterator future_host = referrer->begin(); 155 return;
166 future_host != referrer->end(); ++future_host) { 156 Referrer* referrer = &(it->second);
167 DnsHostInfo* queued_info = PreLockedResolve( 157 for (Referrer::iterator future_host = referrer->begin();
168 future_host->first, 158 future_host != referrer->end(); ++future_host) {
169 DnsHostInfo::LEARNED_REFERAL_MOTIVATED); 159 DnsHostInfo* queued_info = PreLockedResolve(
170 if (queued_info) 160 future_host->first,
171 queued_info->SetReferringHostname(host_name); 161 DnsHostInfo::LEARNED_REFERAL_MOTIVATED);
162 if (queued_info) {
163 need_to_signal = true;
164 queued_info->SetReferringHostname(host_name);
165 }
166 }
172 } 167 }
168 if (need_to_signal)
169 slaves_have_work_.Signal();
173 } 170 }
174 171
175 // Provide sort order so all .com's are together, etc. 172 // Provide sort order so all .com's are together, etc.
176 struct RightToLeftStringSorter { 173 struct RightToLeftStringSorter {
177 bool operator()(const std::string& left, const std::string& right) const { 174 bool operator()(const std::string& left, const std::string& right) const {
178 if (left == right) return true; 175 if (left == right) return true;
179 size_t left_already_matched = left.size(); 176 size_t left_already_matched = left.size();
180 size_t right_already_matched = right.size(); 177 size_t right_already_matched = right.size();
181 178
182 // Ensure both strings have characters. 179 // Ensure both strings have characters.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 } 290 }
294 291
295 // Partition the DnsHostInfo's into categories. 292 // Partition the DnsHostInfo's into categories.
296 for (Snapshot::iterator it(snapshot.begin()); it != snapshot.end(); it++) { 293 for (Snapshot::iterator it(snapshot.begin()); it != snapshot.end(); it++) {
297 if (it->second.was_nonexistant()) { 294 if (it->second.was_nonexistant()) {
298 name_not_found.push_back(it->second); 295 name_not_found.push_back(it->second);
299 continue; 296 continue;
300 } 297 }
301 if (!it->second.was_found()) 298 if (!it->second.was_found())
302 continue; // Still being processed. 299 continue; // Still being processed.
303 if (base::TimeDelta() != it->second.benefits_remaining()) { 300 if (TimeDelta() != it->second.benefits_remaining()) {
304 network_hits.push_back(it->second); // With no benefit yet. 301 network_hits.push_back(it->second); // With no benefit yet.
305 continue; 302 continue;
306 } 303 }
307 if (DnsHostInfo::kMaxNonNetworkDnsLookupDuration > 304 if (DnsHostInfo::kMaxNonNetworkDnsLookupDuration >
308 it->second.resolve_duration()) { 305 it->second.resolve_duration()) {
309 already_cached.push_back(it->second); 306 already_cached.push_back(it->second);
310 continue; 307 continue;
311 } 308 }
312 // Remaining case is where prefetch benefit was significant, and was used. 309 // Remaining case is where prefetch benefit was significant, and was used.
313 // Since we shot those cases as historical hits, we won't bother here. 310 // Since we shot those cases as historical hits, we won't bother here.
(...skipping 14 matching lines...) Expand all
328 DnsHostInfo::GetHtmlTable(already_cached, 325 DnsHostInfo::GetHtmlTable(already_cached,
329 "Previously cached resolutions were found for ", brief, output); 326 "Previously cached resolutions were found for ", brief, output);
330 DnsHostInfo::GetHtmlTable(name_not_found, 327 DnsHostInfo::GetHtmlTable(name_not_found,
331 "Prefetching DNS records revealed non-existance for ", brief, output); 328 "Prefetching DNS records revealed non-existance for ", brief, output);
332 } 329 }
333 330
334 DnsHostInfo* DnsMaster::PreLockedResolve( 331 DnsHostInfo* DnsMaster::PreLockedResolve(
335 const std::string& hostname, 332 const std::string& hostname,
336 DnsHostInfo::ResolutionMotivation motivation) { 333 DnsHostInfo::ResolutionMotivation motivation) {
337 // DCHECK(We have the lock); 334 // DCHECK(We have the lock);
335 DCHECK(0 != slave_count_);
338 DCHECK(0 != hostname.length()); 336 DCHECK(0 != hostname.length());
339 337
340 DnsHostInfo* info = &results_[hostname]; 338 DnsHostInfo* info = &results_[hostname];
341 info->SetHostname(hostname); // Initialize or DCHECK. 339 info->SetHostname(hostname); // Initialize or DCHECK.
342 // TODO(jar): I need to discard names that have long since expired. 340 // TODO(jar): I need to discard names that have long since expired.
343 // Currently we only add to the domain map :-/ 341 // Currently we only add to the domain map :-/
344 342
345 DCHECK(info->HasHostname(hostname)); 343 DCHECK(info->HasHostname(hostname));
346 344
347 if (!info->NeedsDnsUpdate(hostname)) { 345 if (!info->NeedsDnsUpdate(hostname)) {
348 info->DLogResultsStats("DNS PrefetchNotUpdated"); 346 info->DLogResultsStats("DNS PrefetchNotUpdated");
349 return NULL; 347 return NULL;
350 } 348 }
351 349
352 info->SetQueuedState(motivation); 350 info->SetQueuedState(motivation);
353 name_buffer_.push(hostname); 351 name_buffer_.push(hostname);
354
355 PreLockedScheduleLookups();
356
357 return info; 352 return info;
358 } 353 }
359 354
360 void DnsMaster::PreLockedScheduleLookups() { 355 // GetNextAssignment() is executed on the thread associated with
361 while (!name_buffer_.empty() && 356 // with a prefetch slave instance.
362 pending_lookups_.size() < kMaxConcurrentLookups) { 357 // Return value of false indicates slave thread termination is needed.
363 const std::string hostname(name_buffer_.front()); 358 // Return value of true means info argument was populated
359 // with a pointer to the assigned DnsHostInfo instance.
360 bool DnsMaster::GetNextAssignment(std::string* hostname) {
361 bool ask_for_help = false;
362 {
363 AutoLock auto_lock(lock_); // For map and buffer access
364 while (0 == name_buffer_.size() && !shutdown_) {
365 // No work pending, so just wait.
366 // wait on condition variable while releasing lock temporarilly.
367 slaves_have_work_.Wait();
368 }
369 if (shutdown_)
370 return false; // Tell slaves to terminate also.
371 *hostname = name_buffer_.front();
364 name_buffer_.pop(); 372 name_buffer_.pop();
365 373
366 DnsHostInfo* info = &results_[hostname]; 374 DnsHostInfo* info = &results_[*hostname];
367 DCHECK(info->HasHostname(hostname)); 375 DCHECK(info->HasHostname(*hostname));
368 info->SetAssignedState(); 376 info->SetAssignedState();
369 377
370 LookupRequest* request = new LookupRequest(this, hostname); 378 ask_for_help = name_buffer_.size() > 0;
371 if (request->Start()) { 379 } // Release lock_
372 pending_lookups_.insert(request); 380 if (ask_for_help)
373 peak_pending_lookups_ = std::max(peak_pending_lookups_, 381 slaves_have_work_.Signal();
374 pending_lookups_.size()); 382 return true;
375 } else {
376 NOTREACHED();
377 delete request;
378 }
379 }
380 } 383 }
381 384
382 void DnsMaster::OnLookupFinished(LookupRequest* request, 385 void DnsMaster::SetFoundState(const std::string hostname) {
383 const std::string& hostname, bool found) {
384 AutoLock auto_lock(lock_); // For map access (changing info values). 386 AutoLock auto_lock(lock_); // For map access (changing info values).
385 DnsHostInfo* info = &results_[hostname]; 387 DnsHostInfo* info = &results_[hostname];
386 DCHECK(info->HasHostname(hostname)); 388 DCHECK(info->HasHostname(hostname));
387 if (info->is_marked_to_delete()) 389 if (info->is_marked_to_delete())
388 results_.erase(hostname); 390 results_.erase(hostname);
389 else { 391 else
390 if (found) 392 info->SetFoundState();
391 info->SetFoundState(); 393 }
392 else 394
393 info->SetNoSuchNameState(); 395 void DnsMaster::SetNoSuchNameState(const std::string hostname) {
396 AutoLock auto_lock(lock_); // For map access (changing info values).
397 DnsHostInfo* info = &results_[hostname];
398 DCHECK(info->HasHostname(hostname));
399 if (info->is_marked_to_delete())
400 results_.erase(hostname);
401 else
402 info->SetNoSuchNameState();
403 }
404
405 bool DnsMaster::PreLockedCreateNewSlaveIfNeeded() {
406 // Don't create more than max.
407 if (kSlaveCountMax <= slave_count_ || shutdown_)
408 return false;
409
410 DnsSlave* slave_instance = new DnsSlave(this, slave_count_);
411 DWORD thread_id;
412 size_t stack_size = 0;
413 unsigned int flags = CREATE_SUSPENDED;
414 if (win_util::GetWinVersion() >= win_util::WINVERSION_XP) {
415 // 128kb stack size.
416 stack_size = 128*1024;
417 flags |= STACK_SIZE_PARAM_IS_A_RESERVATION;
418 }
419 HANDLE handle = CreateThread(NULL, // security
420 stack_size,
421 DnsSlave::ThreadStart,
422 reinterpret_cast<void*>(slave_instance),
423 flags,
424 &thread_id);
425 DCHECK(NULL != handle);
426 if (NULL == handle)
427 return false;
428
429 // Carlos suggests it is not valuable to do a set priority.
430 // BOOL WINAPI SetThreadPriority(handle,int nPriority);
431
432 thread_ids_[slave_count_] = thread_id;
433 thread_handles_[slave_count_] = handle;
434 slaves_[slave_count_] = slave_instance;
435 slave_count_++;
436
437 ResumeThread(handle); // WINAPI call.
438 running_slave_count_++;
439
440 return true;
441 }
442
443 void DnsMaster::SetSlaveHasTerminated(int slave_index) {
444 DCHECK_EQ(GetCurrentThreadId(), thread_ids_[slave_index]);
445 AutoLock auto_lock(lock_);
446 running_slave_count_--;
447 DCHECK(thread_ids_[slave_index]);
448 thread_ids_[slave_index] = 0;
449 }
450
451 bool DnsMaster::ShutdownSlaves() {
452 int running_slave_count;
453 {
454 AutoLock auto_lock(lock_);
455 shutdown_ = true; // Block additional resolution requests.
456 // Empty the queue gracefully
457 while (name_buffer_.size() > 0) {
458 std::string hostname = name_buffer_.front();
459 name_buffer_.pop();
460 DnsHostInfo* info = &results_[hostname];
461 DCHECK(info->HasHostname(hostname));
462 // We should be in Queued state, so simulate to end of life.
463 info->SetAssignedState(); // Simulate slave assignment.
464 info->SetNoSuchNameState(); // Simulate failed lookup.
465 results_.erase(hostname);
466 }
467 running_slave_count = running_slave_count_;
468 // Release lock, so slaves can finish up.
394 } 469 }
395 470
396 pending_lookups_.erase(request); 471 if (running_slave_count) {
397 delete request; 472 slaves_have_work_.Broadcast(); // Slaves need to check for termination.
398 473
399 PreLockedScheduleLookups(); 474 DWORD result = WaitForMultipleObjects(
475 slave_count_,
476 thread_handles_,
477 TRUE, // Wait for all
478 static_cast<DWORD>(kShutdownWaitTime_.InMilliseconds()));
479
480 DCHECK(result != WAIT_TIMEOUT) << "Some slaves didn't stop";
481 if (WAIT_TIMEOUT == result)
482 return false;
483 }
484 {
485 AutoLock auto_lock(lock_);
486 while (0 < slave_count_--) {
487 if (0 == thread_ids_[slave_count_]) { // Thread terminated.
488 int result = CloseHandle(thread_handles_[slave_count_]);
489 CHECK(result);
490 thread_handles_[slave_count_] = 0;
491 delete slaves_[slave_count_];
492 slaves_[slave_count_] = NULL;
493 }
494 }
495 }
496 return true;
400 } 497 }
401 498
402 void DnsMaster::DiscardAllResults() { 499 void DnsMaster::DiscardAllResults() {
403 AutoLock auto_lock(lock_); 500 AutoLock auto_lock(lock_);
404 // Delete anything listed so far in this session that shows in about:dns. 501 // Delete anything listed so far in this session that shows in about:dns.
405 cache_eviction_map_.clear(); 502 cache_eviction_map_.clear();
406 cache_hits_.clear(); 503 cache_hits_.clear();
407 referrers_.clear(); 504 referrers_.clear();
408 505
409 506
410 // Try to delete anything in our work queue. 507 // Try to delete anything in our work queue.
411 while (!name_buffer_.empty()) { 508 while (!name_buffer_.empty()) {
412 // Emulate processing cycle as though host was not found. 509 // Emulate processing cycle as though host was not found.
413 std::string hostname = name_buffer_.front(); 510 std::string hostname = name_buffer_.front();
414 name_buffer_.pop(); 511 name_buffer_.pop();
415 DnsHostInfo* info = &results_[hostname]; 512 DnsHostInfo* info = &results_[hostname];
416 DCHECK(info->HasHostname(hostname)); 513 DCHECK(info->HasHostname(hostname));
417 info->SetAssignedState(); 514 info->SetAssignedState();
418 info->SetNoSuchNameState(); 515 info->SetNoSuchNameState();
419 } 516 }
420 // Now every result_ is either resolved, or is being resolved 517 // Now every result_ is either resolved, or is being worked on by a slave.
421 // (see LookupRequest).
422 518
423 // Step through result_, recording names of all hosts that can't be erased. 519 // Step through result_, recording names of all hosts that can't be erased.
424 // We can't erase anything being worked on. 520 // We can't erase anything being worked on by a slave.
425 Results assignees; 521 Results assignees;
426 for (Results::iterator it = results_.begin(); results_.end() != it; ++it) { 522 for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
427 std::string hostname = it->first; 523 std::string hostname = it->first;
428 DnsHostInfo* info = &it->second; 524 DnsHostInfo* info = &it->second;
429 DCHECK(info->HasHostname(hostname)); 525 DCHECK(info->HasHostname(hostname));
430 if (info->is_assigned()) { 526 if (info->is_assigned()) {
431 info->SetPendingDeleteState(); 527 info->SetPendingDeleteState();
432 assignees[hostname] = *info; 528 assignees[hostname] = *info;
433 } 529 }
434 } 530 }
435 DCHECK(assignees.size() <= kMaxConcurrentLookups); 531 DCHECK(kSlaveCountMax >= assignees.size());
436 results_.clear(); 532 results_.clear();
437 // Put back in the names being worked on. 533 // Put back in the names being worked on by slaves.
438 for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) { 534 for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
439 DCHECK(it->second.is_marked_to_delete()); 535 DCHECK(it->second.is_marked_to_delete());
440 results_[it->first] = it->second; 536 results_[it->first] = it->second;
441 } 537 }
442 } 538 }
443 539
444 } // namespace chrome_browser_net 540 } // namespace chrome_browser_net
541
OLDNEW
« no previous file with comments | « chrome/browser/net/dns_master.h ('k') | chrome/browser/net/dns_master_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698