| OLD | NEW |
| 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 // A DnsMaster object is instantiated once in the browser | 5 // A DnsMaster object is instantiated once in the browser |
| 6 // process, and manages asynchronous resolution of DNS hostnames. | 6 // process, and delivers DNS prefetch assignments (hostnames) |
| 7 // to any of several DnsSlave objects. |
| 7 // Most hostname lists are sent out by renderer processes, and | 8 // Most hostname lists are sent out by renderer processes, and |
| 8 // involve lists of hostnames that *might* be used in the near | 9 // involve lists of hostnames that *might* be used in the near |
| 9 // future by the browsing user. The goal of this class is to | 10 // future by the browsing user. The goal of this class is to |
| 10 // cause the underlying DNS structure to lookup a hostname before | 11 // cause the underlying DNS structure to lookup a hostname before |
| 11 // it is really needed, and hence reduce latency in the standard | 12 // it is really needed, and hence reduce latency in the standard |
| 12 // lookup paths. | 13 // lookup paths. Since some DNS lookups may take a LONG time, we |
| 14 // use several DnsSlave threads to concurrently perform the |
| 15 // lookups. |
| 13 | 16 |
| 14 #ifndef CHROME_BROWSER_NET_DNS_MASTER_H_ | 17 #ifndef CHROME_BROWSER_NET_DNS_MASTER_H_ |
| 15 #define CHROME_BROWSER_NET_DNS_MASTER_H_ | 18 #define CHROME_BROWSER_NET_DNS_MASTER_H_ |
| 16 | 19 |
| 17 #include <map> | 20 #include <map> |
| 18 #include <queue> | 21 #include <queue> |
| 19 #include <set> | |
| 20 #include <string> | 22 #include <string> |
| 21 | 23 |
| 22 #include "base/lock.h" | 24 #include "base/condition_variable.h" |
| 25 #include "base/scoped_ptr.h" |
| 23 #include "chrome/browser/net/dns_host_info.h" | 26 #include "chrome/browser/net/dns_host_info.h" |
| 24 #include "chrome/browser/net/referrer.h" | 27 #include "chrome/browser/net/referrer.h" |
| 25 #include "chrome/common/net/dns.h" | 28 #include "chrome/common/net/dns.h" |
| 26 #include "googleurl/src/url_canon.h" | 29 #include "googleurl/src/url_canon.h" |
| 27 #include "testing/gtest/include/gtest/gtest_prod.h" | |
| 28 | 30 |
| 29 namespace chrome_browser_net { | 31 namespace chrome_browser_net { |
| 30 | 32 |
| 33 class DnsSlave; |
| 34 |
| 31 typedef chrome_common_net::NameList NameList; | 35 typedef chrome_common_net::NameList NameList; |
| 32 typedef std::map<std::string, DnsHostInfo> Results; | 36 typedef std::map<std::string, DnsHostInfo> Results; |
| 33 | 37 |
| 34 class DnsMaster { | 38 class DnsMaster { |
| 35 public: | 39 public: |
| 36 // Too many concurrent lookups negate benefits of prefetching | 40 // The number of slave processes that will do DNS prefetching |
| 37 // by trashing the OS cache. | 41 static const size_t kSlaveCountMax = 8; |
| 38 static const size_t kMaxConcurrentLookups; | |
| 39 | 42 |
| 40 DnsMaster(); | 43 explicit DnsMaster(base::TimeDelta shutdown_wait_time); |
| 41 ~DnsMaster(); | 44 |
| 45 ~DnsMaster() { |
| 46 if (!shutdown_) |
| 47 ShutdownSlaves(); // Ensure we did our cleanup. |
| 48 } |
| 49 |
| 50 // ShutdownSlaves() gets all spawned threads to terminate, closes |
| 51 // their handles, and deletes their DnsSlave instances. |
| 52 // Return value of true means all operations succeeded. |
| 53 // Return value of false means that the threads wouldn't terminate, |
| 54 // and that resources may leak. If this returns false, it is best |
| 55 // to NOT delete this DnsMaster, as slave threads may still call into |
| 56 // this object. |
| 57 bool ShutdownSlaves(); |
| 42 | 58 |
| 43 // In some circumstances, for privacy reasons, all results should be | 59 // In some circumstances, for privacy reasons, all results should be |
| 44 // discarded. This method gracefully handles that activity. | 60 // discarded. This method gracefully handles that activity. |
| 45 // Destroy all our internal state, which shows what names we've looked up, and | 61 // Destroy all our internal state, which shows what names we've looked up, and |
| 46 // how long each has taken, etc. etc. We also destroy records of suggesses | 62 // how long each has taken, etc. etc. We also destroy records of suggesses |
| 47 // (cache hits etc.). | 63 // (cache hits etc.). |
| 48 void DiscardAllResults(); | 64 void DiscardAllResults(); |
| 49 | 65 |
| 50 // Add hostname(s) to the queue for processing. | 66 // Add hostname(s) to the queue for processing by slaves |
| 51 void ResolveList(const NameList& hostnames, | 67 void ResolveList(const NameList& hostnames, |
| 52 DnsHostInfo::ResolutionMotivation motivation); | 68 DnsHostInfo::ResolutionMotivation motivation); |
| 53 void Resolve(const std::string& hostname, | 69 void Resolve(const std::string& hostname, |
| 54 DnsHostInfo::ResolutionMotivation motivation); | 70 DnsHostInfo::ResolutionMotivation motivation); |
| 55 | 71 |
| 56 // Get latency benefit of the prefetch that we are navigating to. | 72 // Get latency benefit of the prefetch that we are navigating to. |
| 57 bool AccruePrefetchBenefits(const GURL& referrer, | 73 bool AccruePrefetchBenefits(const GURL& referrer, |
| 58 DnsHostInfo* navigation_info); | 74 DnsHostInfo* navigation_info); |
| 59 | 75 |
| 60 // Instigate prefetch of any domains we predict will be needed after this | 76 // Instigate prefetch of any domains we predict will be needed after this |
| 61 // navigation. | 77 // navigation. |
| 62 void NavigatingTo(const std::string& host_name); | 78 void NavigatingTo(const std::string& host_name); |
| 63 | 79 |
| 64 // Record details of a navigation so that we can preresolve the host name | 80 // Record details of a navigation so that we can preresolve the host name |
| 65 // ahead of time the next time the users navigates to the indicated host. | 81 // ahead of time the next time the users navigates to the indicated host. |
| 66 void NonlinkNavigation(const GURL& referrer, DnsHostInfo* navigation_info); | 82 void NonlinkNavigation(const GURL& referrer, DnsHostInfo* navigation_info); |
| 67 | 83 |
| 68 // Dump HTML table containing list of referrers for about:dns. | 84 // Dump HTML table containing list of referrers for about:dns. |
| 69 void GetHtmlReferrerLists(std::string* output); | 85 void GetHtmlReferrerLists(std::string* output); |
| 70 | 86 |
| 71 // Dump the list of currently know referrer domains and related prefetchable | 87 // Dump the list of currently know referrer domains and related prefetchable |
| 72 // domains. | 88 // domains. |
| 73 void GetHtmlInfo(std::string* output); | 89 void GetHtmlInfo(std::string* output); |
| 74 | 90 |
| 75 private: | 91 // For testing only... |
| 76 FRIEND_TEST(DnsMasterTest, BenefitLookupTest); | 92 // Currently testing only provides a crude measure of success. |
| 77 FRIEND_TEST(DnsMasterTest, ShutdownWhenResolutionIsPendingTest); | |
| 78 FRIEND_TEST(DnsMasterTest, SingleLookupTest); | |
| 79 FRIEND_TEST(DnsMasterTest, ConcurrentLookupTest); | |
| 80 FRIEND_TEST(DnsMasterTest, MassiveConcurrentLookupTest); | |
| 81 friend class WaitForResolutionHelper; // For testing. | |
| 82 | |
| 83 class LookupRequest; | |
| 84 | |
| 85 // A map that is keyed with the hostnames that we've learned were the cause | |
| 86 // of loading additional hostnames. The list of additional hostnames in held | |
| 87 // in a Referrer instance, which is found in this type. | |
| 88 typedef std::map<std::string, Referrer> Referrers; | |
| 89 | |
| 90 // Only for testing. Returns true if hostname has been successfully resolved | |
| 91 // (name found). | |
| 92 bool WasFound(const std::string& hostname) { | 93 bool WasFound(const std::string& hostname) { |
| 93 AutoLock auto_lock(lock_); | 94 AutoLock auto_lock(lock_); |
| 94 return (results_.find(hostname) != results_.end()) && | 95 return (results_.find(hostname) != results_.end()) && |
| 95 results_[hostname].was_found(); | 96 results_[hostname].was_found(); |
| 96 } | 97 } |
| 97 | 98 |
| 98 // Only for testing. Return how long was the resolution | 99 // Accessor methods, used mostly for testing. |
| 99 // or DnsHostInfo::kNullDuration if it hasn't been resolved yet. | 100 // Both functions return DnsHostInfo::kNullDuration if name was not yet |
| 100 base::TimeDelta GetResolutionDuration(const std::string& hostname) { | 101 // processed enough. |
| 102 base::TimeDelta GetResolutionDuration(const std::string hostname) { |
| 101 AutoLock auto_lock(lock_); | 103 AutoLock auto_lock(lock_); |
| 102 if (results_.find(hostname) == results_.end()) | 104 if (results_.find(hostname) == results_.end()) |
| 103 return DnsHostInfo::kNullDuration; | 105 return DnsHostInfo::kNullDuration; |
| 104 return results_[hostname].resolve_duration(); | 106 return results_[hostname].resolve_duration(); |
| 105 } | 107 } |
| 106 | 108 |
| 107 // Only for testing; | 109 base::TimeDelta GetQueueDuration(const std::string hostname) { |
| 108 size_t peak_pending_lookups() const { return peak_pending_lookups_; } | 110 AutoLock auto_lock(lock_); |
| 111 if (results_.find(hostname) == results_.end()) |
| 112 return DnsHostInfo::kNullDuration; |
| 113 return results_[hostname].queue_duration(); |
| 114 } |
| 109 | 115 |
| 110 // Access method for use by lookup request to pass resolution result. | 116 size_t running_slave_count() { |
| 111 void OnLookupFinished(LookupRequest* request, | 117 AutoLock auto_lock(lock_); |
| 112 const std::string& hostname, bool found); | 118 return running_slave_count_; |
| 119 } |
| 120 |
| 121 //---------------------------------------------------------------------------- |
| 122 // Methods below this line should only be called by slave processes. |
| 123 |
| 124 // GetNextAssignment() gets the next hostname from queue for processing |
| 125 // It is not meant to be public, and should only be used by the slave. |
| 126 // GetNextAssignment() waits on a condition variable if there are no more |
| 127 // names in queue. |
| 128 // Return false if slave thread should terminate. |
| 129 // Return true if slave thread should process the value. |
| 130 bool GetNextAssignment(std::string* hostname); |
| 131 |
| 132 // Access methods for use by slave threads to callback with state updates. |
| 133 void SetFoundState(const std::string hostname); |
| 134 void SetNoSuchNameState(const std::string hostname); |
| 135 |
| 136 // Notification during ShutdownSlaves. |
| 137 void SetSlaveHasTerminated(int slave_index); |
| 138 |
| 139 private: |
| 140 // A map that is keyed with the hostnames that we've learned were the cause |
| 141 // of loading additional hostnames. The list of additional hostnames in held |
| 142 // in a Referrer instance, which is found in this type. |
| 143 typedef std::map<std::string, Referrer> Referrers; |
| 113 | 144 |
| 114 // "PreLocked" means that the caller has already Acquired lock_ in the | 145 // "PreLocked" means that the caller has already Acquired lock_ in the |
| 115 // following method names. | 146 // following method names. |
| 116 // Queue hostname for resolution. If queueing was done, return the pointer | 147 // Queue hostname for resolution. If queueing was done, return the pointer |
| 117 // to the queued instance, otherwise return NULL. | 148 // to the queued instance, otherwise return NULL. |
| 118 DnsHostInfo* PreLockedResolve(const std::string& hostname, | 149 DnsHostInfo* PreLockedResolve(const std::string& hostname, |
| 119 DnsHostInfo::ResolutionMotivation motivation); | 150 DnsHostInfo::ResolutionMotivation motivation); |
| 151 bool PreLockedCreateNewSlaveIfNeeded(); // Lazy slave processes creation. |
| 120 | 152 |
| 121 // Take lookup requests from name_buffer_ and tell HostResolver | 153 // Number of slave processes started early (to help with startup prefetch). |
| 122 // to look them up asynchronously, provided we don't exceed | 154 static const size_t kSlaveCountMin = 4; |
| 123 // concurrent resolution limit. | |
| 124 void PreLockedScheduleLookups(); | |
| 125 | 155 |
| 126 // Synchronize access to results_, referrers_, pending_lookups_. | 156 // Synchronize access to results_, referrers_, and slave control data. |
| 127 // TODO(phajdan.jr): Re-evaluate usage of this lock. After restructuring | |
| 128 // the code to run only on the IO thread and using PostTask from other threads | |
| 129 // the lock should not be needed. If that's not possible, then at least its | |
| 130 // usage can be reduced. | |
| 131 Lock lock_; | 157 Lock lock_; |
| 132 | 158 |
| 133 // name_buffer_ holds a list of names we need to look up. | 159 // name_buffer_ holds a list of names we need to look up. |
| 134 std::queue<std::string> name_buffer_; | 160 std::queue<std::string> name_buffer_; |
| 135 | 161 |
| 136 // results_ contains information for existing/prior prefetches. | 162 // results_ contains information for existing/prior prefetches. |
| 137 Results results_; | 163 Results results_; |
| 138 | 164 |
| 139 // For each hostname that we might navigate to (that we've "learned about") | 165 // For each hostname that we might navigate to (that we've "learned about") |
| 140 // we have a Referrer list. Each Referrer list has all hostnames we need to | 166 // we have a Referrer list. Each Referrer list has all hostnames we need to |
| 141 // pre-resolve when there is a navigation to the orginial hostname. | 167 // pre-resolve when there is a navigation to the orginial hostname. |
| 142 Referrers referrers_; | 168 Referrers referrers_; |
| 143 | 169 |
| 144 std::set<LookupRequest*> pending_lookups_; | 170 // Signaling slaves to process elements in the queue, or to terminate, |
| 171 // is done using ConditionVariables. |
| 172 ConditionVariable slaves_have_work_; |
| 145 | 173 |
| 146 // For testing, to verify that we don't exceed the limit. | 174 size_t slave_count_; // Count of slave processes started. |
| 147 size_t peak_pending_lookups_; | 175 size_t running_slave_count_; // Count of slaves process still running. |
| 176 |
| 177 // TODO(jrg): wait for CL 15076 from _ph to come in which resolves |
| 178 // this. In the short term this file is hacked to be happy when |
| 179 // included in render_process.h. |
| 180 #if defined(OS_WIN) |
| 181 // The following arrays are only initialized as |
| 182 // slave_count_ grows (up to the indicated max). |
| 183 DWORD thread_ids_[kSlaveCountMax]; |
| 184 HANDLE thread_handles_[kSlaveCountMax]; |
| 185 DnsSlave* slaves_[kSlaveCountMax]; |
| 186 #endif |
| 187 |
| 188 // shutdown_ is set to tell the slaves to terminate. |
| 189 bool shutdown_; |
| 190 |
| 191 // The following is the maximum time the ShutdownSlaves method |
| 192 // will wait for all the slave processes to terminate. |
| 193 const base::TimeDelta kShutdownWaitTime_; |
| 148 | 194 |
| 149 // A list of successful events resulting from pre-fetching. | 195 // A list of successful events resulting from pre-fetching. |
| 150 DnsHostInfo::DnsInfoTable cache_hits_; | 196 DnsHostInfo::DnsInfoTable cache_hits_; |
| 151 // A map of hosts that were evicted from our cache (after we prefetched them) | 197 // A map of hosts that were evicted from our cache (after we prefetched them) |
| 152 // and before the HTTP stack tried to look them up. | 198 // and before the HTTP stack tried to look them up. |
| 153 Results cache_eviction_map_; | 199 Results cache_eviction_map_; |
| 154 | 200 |
| 155 DISALLOW_COPY_AND_ASSIGN(DnsMaster); | 201 DISALLOW_COPY_AND_ASSIGN(DnsMaster); |
| 156 }; | 202 }; |
| 157 | 203 |
| 158 } // namespace chrome_browser_net | 204 } // namespace chrome_browser_net |
| 159 | 205 |
| 160 #endif // CHROME_BROWSER_NET_DNS_MASTER_H_ | 206 #endif // CHROME_BROWSER_NET_DNS_MASTER_H_ |
| 161 | 207 |
| OLD | NEW |