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