[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 1 | // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 4 | |
[email protected] | 3530cd9 | 2010-06-27 06:22:01 | [diff] [blame^] | 5 | #include "chrome/browser/net/predictor.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 6 | |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 7 | #include <algorithm> |
[email protected] | 319d9e6f | 2009-02-18 19:47:21 | [diff] [blame] | 8 | #include <set> |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 9 | #include <sstream> |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 10 | |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 11 | #include "base/compiler_specific.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 12 | #include "base/histogram.h" |
| 13 | #include "base/stats_counters.h" |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 14 | #include "base/string_util.h" |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 15 | #include "base/time.h" |
[email protected] | 6fad263 | 2009-11-02 05:59:37 | [diff] [blame] | 16 | #include "chrome/browser/chrome_thread.h" |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 17 | #include "chrome/browser/net/preconnect.h" |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 18 | #include "net/base/address_list.h" |
| 19 | #include "net/base/completion_callback.h" |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 20 | #include "net/base/host_port_pair.h" |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 21 | #include "net/base/host_resolver.h" |
| 22 | #include "net/base/net_errors.h" |
[email protected] | 9e743cd | 2010-03-16 07:03:53 | [diff] [blame] | 23 | #include "net/base/net_log.h" |
[email protected] | e1acf6f | 2008-10-27 20:43:33 | [diff] [blame] | 24 | |
[email protected] | 602faf3c | 2009-06-27 14:35:44 | [diff] [blame] | 25 | using base::TimeDelta; |
| 26 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 27 | namespace chrome_browser_net { |
| 28 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 29 | class Predictor::LookupRequest { |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 30 | public: |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 31 | LookupRequest(Predictor* predictor, |
[email protected] | 8a00f00a | 2009-06-12 00:49:38 | [diff] [blame] | 32 | net::HostResolver* host_resolver, |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 33 | const GURL& url) |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 34 | : ALLOW_THIS_IN_INITIALIZER_LIST( |
| 35 | net_callback_(this, &LookupRequest::OnLookupFinished)), |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 36 | predictor_(predictor), |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 37 | url_(url), |
[email protected] | 8a00f00a | 2009-06-12 00:49:38 | [diff] [blame] | 38 | resolver_(host_resolver) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 39 | } |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 40 | |
[email protected] | 8539853 | 2009-06-16 21:32:18 | [diff] [blame] | 41 | // Return underlying network resolver status. |
| 42 | // net::OK ==> Host was found synchronously. |
| 43 | // net:ERR_IO_PENDING ==> Network will callback later with result. |
| 44 | // anything else ==> Host was not found synchronously. |
| 45 | int Start() { |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 46 | net::HostResolver::RequestInfo resolve_info(url_.host(), |
| 47 | url_.EffectiveIntPort()); |
[email protected] | 2884a46 | 2009-06-15 05:08:42 | [diff] [blame] | 48 | |
| 49 | // Make a note that this is a speculative resolve request. This allows us |
| 50 | // to separate it from real navigations in the observer's callback, and |
| 51 | // lets the HostResolver know it can de-prioritize it. |
| 52 | resolve_info.set_is_speculative(true); |
[email protected] | ec08bb2 | 2009-08-12 00:25:12 | [diff] [blame] | 53 | return resolver_.Resolve( |
[email protected] | 9e743cd | 2010-03-16 07:03:53 | [diff] [blame] | 54 | resolve_info, &addresses_, &net_callback_, net::BoundNetLog()); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | private: |
| 58 | void OnLookupFinished(int result) { |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 59 | predictor_->OnLookupFinished(this, url_, result == net::OK); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | // HostResolver will call us using this callback when resolution is complete. |
| 63 | net::CompletionCallbackImpl<LookupRequest> net_callback_; |
| 64 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 65 | Predictor* predictor_; // The predictor which started us. |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 66 | |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 67 | const GURL url_; // Hostname to resolve. |
[email protected] | 8a00f00a | 2009-06-12 00:49:38 | [diff] [blame] | 68 | net::SingleRequestHostResolver resolver_; |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 69 | net::AddressList addresses_; |
| 70 | |
| 71 | DISALLOW_COPY_AND_ASSIGN(LookupRequest); |
| 72 | }; |
| 73 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 74 | Predictor::Predictor(net::HostResolver* host_resolver, |
| 75 | base::TimeDelta max_dns_queue_delay, |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 76 | size_t max_concurrent, |
| 77 | bool preconnect_enabled) |
| 78 | : peak_pending_lookups_(0), |
| 79 | shutdown_(false), |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 80 | max_concurrent_dns_lookups_(max_concurrent), |
| 81 | max_dns_queue_delay_(max_dns_queue_delay), |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 82 | host_resolver_(host_resolver), |
| 83 | preconnect_enabled_(preconnect_enabled) { |
| 84 | Referrer::SetUsePreconnectValuations(preconnect_enabled); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 85 | } |
| 86 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 87 | Predictor::~Predictor() { |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 88 | DCHECK(shutdown_); |
| 89 | } |
| 90 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 91 | void Predictor::Shutdown() { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 92 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 93 | DCHECK(!shutdown_); |
| 94 | shutdown_ = true; |
| 95 | |
| 96 | std::set<LookupRequest*>::iterator it; |
| 97 | for (it = pending_lookups_.begin(); it != pending_lookups_.end(); ++it) |
| 98 | delete *it; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | // Overloaded Resolve() to take a vector of names. |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 102 | void Predictor::ResolveList(const UrlList& urls, |
| 103 | UrlInfo::ResolutionMotivation motivation) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 104 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | fd2f8afe | 2009-06-11 21:53:55 | [diff] [blame] | 105 | |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 106 | for (UrlList::const_iterator it = urls.begin(); it < urls.end(); ++it) { |
| 107 | AppendToResolutionQueue(*it, motivation); |
| 108 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | // Basic Resolve() takes an invidual name, and adds it |
| 112 | // to the queue. |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 113 | void Predictor::Resolve(const GURL& url, |
| 114 | UrlInfo::ResolutionMotivation motivation) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 115 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 116 | if (!url.has_host()) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 117 | return; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 118 | AppendToResolutionQueue(url, motivation); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 119 | } |
| 120 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 121 | bool Predictor::AccruePrefetchBenefits(const GURL& referrer, |
| 122 | UrlInfo* navigation_info) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 123 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 124 | GURL url = navigation_info->url(); |
| 125 | Results::iterator it = results_.find(url); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 126 | if (it == results_.end()) { |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 127 | // Use UMA histogram to quantify potential future gains here. |
[email protected] | 553dba6 | 2009-02-24 19:08:23 | [diff] [blame] | 128 | UMA_HISTOGRAM_LONG_TIMES("DNS.UnexpectedResolutionL", |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 129 | navigation_info->resolve_duration()); |
| 130 | navigation_info->DLogResultsStats("DNS UnexpectedResolution"); |
| 131 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 132 | LearnFromNavigation(referrer, navigation_info->url()); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 133 | return false; |
| 134 | } |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 135 | UrlInfo& prefetched_host_info(it->second); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 136 | |
| 137 | // Sometimes a host is used as a subresource by several referrers, so it is |
| 138 | // in our list, but was never motivated by a page-link-scan. In that case, it |
| 139 | // really is an "unexpected" navigation, and we should tally it, and augment |
| 140 | // our referrers_. |
| 141 | bool referrer_based_prefetch = !prefetched_host_info.was_linked(); |
| 142 | if (referrer_based_prefetch) { |
| 143 | // This wasn't the first time this host refered to *some* referrer. |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 144 | LearnFromNavigation(referrer, navigation_info->url()); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | DnsBenefit benefit = prefetched_host_info.AccruePrefetchBenefits( |
| 148 | navigation_info); |
| 149 | switch (benefit) { |
| 150 | case PREFETCH_NAME_FOUND: |
| 151 | case PREFETCH_NAME_NONEXISTANT: |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 152 | dns_cache_hits_.push_back(*navigation_info); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 153 | if (referrer_based_prefetch) { |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 154 | if (referrer.has_host()) { |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 155 | referrers_[referrer].AccrueValue( |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 156 | navigation_info->benefits_remaining(), url); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 157 | } |
| 158 | } |
| 159 | return true; |
| 160 | |
| 161 | case PREFETCH_CACHE_EVICTION: |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 162 | cache_eviction_map_[url] = *navigation_info; |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 163 | return false; |
| 164 | |
| 165 | case PREFETCH_NO_BENEFIT: |
| 166 | // Prefetch never hit the network. Name was pre-cached. |
| 167 | return false; |
| 168 | |
| 169 | default: |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 170 | NOTREACHED(); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 171 | return false; |
| 172 | } |
| 173 | } |
| 174 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 175 | void Predictor::LearnFromNavigation(const GURL& referring_url, |
| 176 | const GURL& target_url) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 177 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 178 | if (referring_url.has_host() && |
| 179 | referring_url != target_url) { |
| 180 | DCHECK(referring_url == referring_url.GetWithEmptyPath()); |
| 181 | referrers_[referring_url].SuggestHost(target_url); |
| 182 | } |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 183 | } |
| 184 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 185 | void Predictor::PredictSubresources(const GURL& url) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 186 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 187 | Referrers::iterator it = referrers_.find(url); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 188 | if (referrers_.end() == it) |
| 189 | return; |
| 190 | Referrer* referrer = &(it->second); |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 191 | referrer->IncrementUseCount(); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 192 | for (Referrer::iterator future_url = referrer->begin(); |
| 193 | future_url != referrer->end(); ++future_url) { |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 194 | UrlInfo* queued_info = AppendToResolutionQueue( |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 195 | future_url->first, |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 196 | UrlInfo::LEARNED_REFERAL_MOTIVATED); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 197 | if (queued_info) |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 198 | queued_info->SetReferringHostname(url); |
| 199 | } |
| 200 | } |
| 201 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 202 | void Predictor::PredictFrameSubresources(const GURL& url) { |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 203 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 204 | DCHECK(url.GetWithEmptyPath() == url); |
| 205 | Referrers::iterator it = referrers_.find(url); |
| 206 | if (referrers_.end() == it) |
| 207 | return; |
| 208 | Referrer* referrer = &(it->second); |
| 209 | referrer->IncrementUseCount(); |
| 210 | for (Referrer::iterator future_url = referrer->begin(); |
| 211 | future_url != referrer->end(); ++future_url) { |
| 212 | if (future_url->second.IsPreconnectWorthDoing()) |
| 213 | Preconnect::PreconnectOnIOThread(future_url->first); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 214 | } |
| 215 | } |
| 216 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 217 | // Provide sort order so all .com's are together, etc. |
| 218 | struct RightToLeftStringSorter { |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 219 | bool operator()(const net::HostPortPair& left, |
| 220 | const net::HostPortPair& right) const { |
| 221 | return string_compare(left.host, right.host); |
| 222 | } |
| 223 | bool operator()(const GURL& left, |
| 224 | const GURL& right) const { |
| 225 | return string_compare(left.host(), right.host()); |
| 226 | } |
| 227 | |
| 228 | static bool string_compare(const std::string& left_host, |
| 229 | const std::string right_host) { |
| 230 | if (left_host == right_host) return true; |
| 231 | size_t left_already_matched = left_host.size(); |
| 232 | size_t right_already_matched = right_host.size(); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 233 | |
| 234 | // Ensure both strings have characters. |
| 235 | if (!left_already_matched) return true; |
| 236 | if (!right_already_matched) return false; |
| 237 | |
| 238 | // Watch for trailing dot, so we'll always be safe to go one beyond dot. |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 239 | if ('.' == left_host[left_already_matched - 1]) { |
| 240 | if ('.' != right_host[right_already_matched - 1]) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 241 | return true; |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 242 | // Both have dots at end of string. |
| 243 | --left_already_matched; |
| 244 | --right_already_matched; |
| 245 | } else { |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 246 | if ('.' == right_host[right_already_matched - 1]) |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 247 | return false; |
| 248 | } |
| 249 | |
| 250 | while (1) { |
| 251 | if (!left_already_matched) return true; |
| 252 | if (!right_already_matched) return false; |
| 253 | |
| 254 | size_t left_length, right_length; |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 255 | size_t left_start = left_host.find_last_of('.', left_already_matched - 1); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 256 | if (std::string::npos == left_start) { |
| 257 | left_length = left_already_matched; |
| 258 | left_already_matched = left_start = 0; |
| 259 | } else { |
| 260 | left_length = left_already_matched - left_start; |
| 261 | left_already_matched = left_start; |
| 262 | ++left_start; // Don't compare the dot. |
| 263 | } |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 264 | size_t right_start = right_host.find_last_of('.', |
| 265 | right_already_matched - 1); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 266 | if (std::string::npos == right_start) { |
| 267 | right_length = right_already_matched; |
| 268 | right_already_matched = right_start = 0; |
| 269 | } else { |
| 270 | right_length = right_already_matched - right_start; |
| 271 | right_already_matched = right_start; |
| 272 | ++right_start; // Don't compare the dot. |
| 273 | } |
| 274 | |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 275 | int diff = left_host.compare(left_start, left_host.size(), |
| 276 | right_host, right_start, right_host.size()); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 277 | if (diff > 0) return false; |
| 278 | if (diff < 0) return true; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 279 | } |
| 280 | } |
| 281 | }; |
| 282 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 283 | void Predictor::GetHtmlReferrerLists(std::string* output) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 284 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 285 | if (referrers_.empty()) |
| 286 | return; |
| 287 | |
| 288 | // TODO(jar): Remove any plausible JavaScript from names before displaying. |
| 289 | |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 290 | typedef std::set<GURL, struct RightToLeftStringSorter> |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 291 | SortedNames; |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 292 | SortedNames sorted_names; |
| 293 | |
| 294 | for (Referrers::iterator it = referrers_.begin(); |
| 295 | referrers_.end() != it; ++it) |
| 296 | sorted_names.insert(it->first); |
| 297 | |
| 298 | output->append("<br><table border>"); |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 299 | output->append( |
| 300 | "<tr><th>Host for Page</th>" |
| 301 | "<th>Page Load<br>Count</th>" |
| 302 | "<th>Subresource<br>Navigations</th>" |
| 303 | "<th>Subresource<br>PreConnects</th>" |
| 304 | "<th>Expected<br>Connects</th>" |
| 305 | "<th>DNS<br>Savings</th>" |
| 306 | "<th>Subresource Spec</th></tr>"); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 307 | |
| 308 | for (SortedNames::iterator it = sorted_names.begin(); |
| 309 | sorted_names.end() != it; ++it) { |
| 310 | Referrer* referrer = &(referrers_[*it]); |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 311 | bool first_set_of_futures = true; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 312 | for (Referrer::iterator future_url = referrer->begin(); |
| 313 | future_url != referrer->end(); ++future_url) { |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 314 | output->append("<tr align=right>"); |
| 315 | if (first_set_of_futures) |
| 316 | StringAppendF(output, "<td rowspan=%d>%s</td><td rowspan=%d>%d</td>", |
| 317 | static_cast<int>(referrer->size()), |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 318 | it->spec().c_str(), |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 319 | static_cast<int>(referrer->size()), |
| 320 | static_cast<int>(referrer->use_count())); |
| 321 | first_set_of_futures = false; |
| 322 | StringAppendF(output, |
| 323 | "<td>%d</td><td>%d</td><td>%2.3f</td><td>%dms</td><td>%s</td></tr>", |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 324 | static_cast<int>(future_url->second.navigation_count()), |
| 325 | static_cast<int>(future_url->second.preconnection_count()), |
| 326 | static_cast<double>(future_url->second.subresource_use_rate()), |
| 327 | static_cast<int>(future_url->second.latency().InMilliseconds()), |
| 328 | future_url->first.spec().c_str()); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 329 | } |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 330 | } |
| 331 | output->append("</table>"); |
| 332 | } |
| 333 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 334 | void Predictor::GetHtmlInfo(std::string* output) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 335 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 336 | // Local lists for calling UrlInfo |
| 337 | UrlInfo::DnsInfoTable cache_hits; |
| 338 | UrlInfo::DnsInfoTable cache_evictions; |
| 339 | UrlInfo::DnsInfoTable name_not_found; |
| 340 | UrlInfo::DnsInfoTable network_hits; |
| 341 | UrlInfo::DnsInfoTable already_cached; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 342 | |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 343 | // Get copies of all useful data. |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 344 | typedef std::map<GURL, UrlInfo, RightToLeftStringSorter> |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 345 | Snapshot; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 346 | Snapshot snapshot; |
| 347 | { |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 348 | // UrlInfo supports value semantics, so we can do a shallow copy. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 349 | for (Results::iterator it(results_.begin()); it != results_.end(); it++) { |
| 350 | snapshot[it->first] = it->second; |
| 351 | } |
| 352 | for (Results::iterator it(cache_eviction_map_.begin()); |
| 353 | it != cache_eviction_map_.end(); |
| 354 | it++) { |
| 355 | cache_evictions.push_back(it->second); |
| 356 | } |
| 357 | // Reverse list as we copy cache hits, so that new hits are at the top. |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 358 | size_t index = dns_cache_hits_.size(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 359 | while (index > 0) { |
| 360 | index--; |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 361 | cache_hits.push_back(dns_cache_hits_[index]); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 362 | } |
| 363 | } |
| 364 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 365 | // Partition the UrlInfo's into categories. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 366 | for (Snapshot::iterator it(snapshot.begin()); it != snapshot.end(); it++) { |
| 367 | if (it->second.was_nonexistant()) { |
| 368 | name_not_found.push_back(it->second); |
| 369 | continue; |
| 370 | } |
| 371 | if (!it->second.was_found()) |
| 372 | continue; // Still being processed. |
[email protected] | 602faf3c | 2009-06-27 14:35:44 | [diff] [blame] | 373 | if (TimeDelta() != it->second.benefits_remaining()) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 374 | network_hits.push_back(it->second); // With no benefit yet. |
| 375 | continue; |
| 376 | } |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 377 | if (UrlInfo::kMaxNonNetworkDnsLookupDuration > |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 378 | it->second.resolve_duration()) { |
| 379 | already_cached.push_back(it->second); |
| 380 | continue; |
| 381 | } |
| 382 | // Remaining case is where prefetch benefit was significant, and was used. |
| 383 | // Since we shot those cases as historical hits, we won't bother here. |
| 384 | } |
| 385 | |
| 386 | bool brief = false; |
| 387 | #ifdef NDEBUG |
| 388 | brief = true; |
| 389 | #endif // NDEBUG |
| 390 | |
| 391 | // Call for display of each table, along with title. |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 392 | UrlInfo::GetHtmlTable(cache_hits, |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 393 | "Prefetching DNS records produced benefits for ", false, output); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 394 | UrlInfo::GetHtmlTable(cache_evictions, |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 395 | "Cache evictions negated DNS prefetching benefits for ", brief, output); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 396 | UrlInfo::GetHtmlTable(network_hits, |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 397 | "Prefetching DNS records was not yet beneficial for ", brief, output); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 398 | UrlInfo::GetHtmlTable(already_cached, |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 399 | "Previously cached resolutions were found for ", brief, output); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 400 | UrlInfo::GetHtmlTable(name_not_found, |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 401 | "Prefetching DNS records revealed non-existance for ", brief, output); |
| 402 | } |
| 403 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 404 | UrlInfo* Predictor::AppendToResolutionQueue( |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 405 | const GURL& url, |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 406 | UrlInfo::ResolutionMotivation motivation) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 407 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 408 | DCHECK(url.has_host()); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 409 | |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 410 | if (shutdown_) |
| 411 | return NULL; |
| 412 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 413 | UrlInfo* info = &results_[url]; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 414 | info->SetUrl(url); // Initialize or DCHECK. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 415 | // TODO(jar): I need to discard names that have long since expired. |
| 416 | // Currently we only add to the domain map :-/ |
| 417 | |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 418 | DCHECK(info->HasUrl(url)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 419 | |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 420 | if (!info->NeedsDnsUpdate()) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 421 | info->DLogResultsStats("DNS PrefetchNotUpdated"); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 422 | return NULL; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 423 | } |
| 424 | |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 425 | info->SetQueuedState(motivation); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 426 | work_queue_.Push(url, motivation); |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 427 | StartSomeQueuedResolutions(); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 428 | return info; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 429 | } |
| 430 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 431 | void Predictor::StartSomeQueuedResolutions() { |
[email protected] | 6fad263 | 2009-11-02 05:59:37 | [diff] [blame] | 432 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | fd2f8afe | 2009-06-11 21:53:55 | [diff] [blame] | 433 | |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 434 | while (!work_queue_.IsEmpty() && |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 435 | pending_lookups_.size() < max_concurrent_dns_lookups_) { |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 436 | const GURL url(work_queue_.Pop()); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 437 | UrlInfo* info = &results_[url]; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 438 | DCHECK(info->HasUrl(url)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 439 | info->SetAssignedState(); |
| 440 | |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 441 | if (CongestionControlPerformed(info)) { |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 442 | DCHECK(work_queue_.IsEmpty()); |
| 443 | return; |
| 444 | } |
| 445 | |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 446 | LookupRequest* request = new LookupRequest(this, host_resolver_, url); |
[email protected] | 8539853 | 2009-06-16 21:32:18 | [diff] [blame] | 447 | int status = request->Start(); |
| 448 | if (status == net::ERR_IO_PENDING) { |
[email protected] | fd2f8afe | 2009-06-11 21:53:55 | [diff] [blame] | 449 | // Will complete asynchronously. |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 450 | pending_lookups_.insert(request); |
| 451 | peak_pending_lookups_ = std::max(peak_pending_lookups_, |
| 452 | pending_lookups_.size()); |
| 453 | } else { |
[email protected] | 221f3336 | 2009-06-29 20:46:48 | [diff] [blame] | 454 | // Completed synchronously (was already cached by HostResolver), or else |
[email protected] | 8539853 | 2009-06-16 21:32:18 | [diff] [blame] | 455 | // there was (equivalently) some network error that prevents us from |
| 456 | // finding the name. Status net::OK means it was "found." |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 457 | LookupFinished(request, url, status == net::OK); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 458 | delete request; |
| 459 | } |
| 460 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 461 | } |
| 462 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 463 | bool Predictor::CongestionControlPerformed(UrlInfo* info) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 464 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 465 | // Note: queue_duration is ONLY valid after we go to assigned state. |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 466 | if (info->queue_duration() < max_dns_queue_delay_) |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 467 | return false; |
| 468 | // We need to discard all entries in our queue, as we're keeping them waiting |
| 469 | // too long. By doing this, we'll have a chance to quickly service urgent |
| 470 | // resolutions, and not have a bogged down system. |
| 471 | while (true) { |
| 472 | info->RemoveFromQueue(); |
| 473 | if (work_queue_.IsEmpty()) |
| 474 | break; |
| 475 | info = &results_[work_queue_.Pop()]; |
| 476 | info->SetAssignedState(); |
| 477 | } |
| 478 | return true; |
| 479 | } |
| 480 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 481 | void Predictor::OnLookupFinished(LookupRequest* request, const GURL& url, |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 482 | bool found) { |
[email protected] | 6fad263 | 2009-11-02 05:59:37 | [diff] [blame] | 483 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | fd2f8afe | 2009-06-11 21:53:55 | [diff] [blame] | 484 | |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 485 | LookupFinished(request, url, found); |
[email protected] | 8539853 | 2009-06-16 21:32:18 | [diff] [blame] | 486 | pending_lookups_.erase(request); |
| 487 | delete request; |
| 488 | |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 489 | StartSomeQueuedResolutions(); |
[email protected] | 8539853 | 2009-06-16 21:32:18 | [diff] [blame] | 490 | } |
| 491 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 492 | void Predictor::LookupFinished(LookupRequest* request, const GURL& url, |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 493 | bool found) { |
| 494 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 495 | UrlInfo* info = &results_[url]; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 496 | DCHECK(info->HasUrl(url)); |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 497 | if (info->is_marked_to_delete()) { |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 498 | results_.erase(url); |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 499 | } else { |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 500 | if (found) |
| 501 | info->SetFoundState(); |
| 502 | else |
| 503 | info->SetNoSuchNameState(); |
[email protected] | 7c19b87b0 | 2009-01-26 16:19:44 | [diff] [blame] | 504 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 505 | } |
| 506 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 507 | void Predictor::DiscardAllResults() { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 508 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 509 | // Delete anything listed so far in this session that shows in about:dns. |
| 510 | cache_eviction_map_.clear(); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 511 | dns_cache_hits_.clear(); |
[email protected] | 21dae9b | 2008-11-06 23:32:53 | [diff] [blame] | 512 | referrers_.clear(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 513 | |
| 514 | |
| 515 | // Try to delete anything in our work queue. |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 516 | while (!work_queue_.IsEmpty()) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 517 | // Emulate processing cycle as though host was not found. |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 518 | GURL url = work_queue_.Pop(); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 519 | UrlInfo* info = &results_[url]; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 520 | DCHECK(info->HasUrl(url)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 521 | info->SetAssignedState(); |
| 522 | info->SetNoSuchNameState(); |
| 523 | } |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 524 | // Now every result_ is either resolved, or is being resolved |
| 525 | // (see LookupRequest). |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 526 | |
| 527 | // Step through result_, recording names of all hosts that can't be erased. |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 528 | // We can't erase anything being worked on. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 529 | Results assignees; |
| 530 | for (Results::iterator it = results_.begin(); results_.end() != it; ++it) { |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 531 | GURL url(it->first); |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 532 | UrlInfo* info = &it->second; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 533 | DCHECK(info->HasUrl(url)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 534 | if (info->is_assigned()) { |
| 535 | info->SetPendingDeleteState(); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 536 | assignees[url] = *info; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 537 | } |
| 538 | } |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 539 | DCHECK(assignees.size() <= max_concurrent_dns_lookups_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 540 | results_.clear(); |
[email protected] | 1933eb20 | 2009-02-19 18:23:25 | [diff] [blame] | 541 | // Put back in the names being worked on. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 542 | for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) { |
| 543 | DCHECK(it->second.is_marked_to_delete()); |
| 544 | results_[it->first] = it->second; |
| 545 | } |
| 546 | } |
| 547 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 548 | void Predictor::TrimReferrers() { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 549 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 550 | std::vector<GURL> urls; |
[email protected] | 03c5e86 | 2009-02-17 22:50:14 | [diff] [blame] | 551 | for (Referrers::const_iterator it = referrers_.begin(); |
| 552 | it != referrers_.end(); ++it) |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 553 | urls.push_back(it->first); |
| 554 | for (size_t i = 0; i < urls.size(); ++i) |
| 555 | if (!referrers_[urls[i]].Trim()) |
| 556 | referrers_.erase(urls[i]); |
[email protected] | 03c5e86 | 2009-02-17 22:50:14 | [diff] [blame] | 557 | } |
| 558 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 559 | void Predictor::SerializeReferrers(ListValue* referral_list) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 560 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | 03c5e86 | 2009-02-17 22:50:14 | [diff] [blame] | 561 | referral_list->Clear(); |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 562 | referral_list->Append(new FundamentalValue(DNS_REFERRER_VERSION)); |
[email protected] | 03c5e86 | 2009-02-17 22:50:14 | [diff] [blame] | 563 | for (Referrers::const_iterator it = referrers_.begin(); |
| 564 | it != referrers_.end(); ++it) { |
| 565 | // Serialize the list of subresource names. |
| 566 | Value* subresource_list(it->second.Serialize()); |
| 567 | |
| 568 | // Create a list for each referer. |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 569 | ListValue* motivator(new ListValue); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 570 | motivator->Append(new StringValue(it->first.spec())); |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 571 | motivator->Append(subresource_list); |
[email protected] | 03c5e86 | 2009-02-17 22:50:14 | [diff] [blame] | 572 | |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 573 | referral_list->Append(motivator); |
[email protected] | 03c5e86 | 2009-02-17 22:50:14 | [diff] [blame] | 574 | } |
| 575 | } |
| 576 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 577 | void Predictor::DeserializeReferrers(const ListValue& referral_list) { |
[email protected] | ec86bea | 2009-12-08 18:35:14 | [diff] [blame] | 578 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 579 | int format_version = -1; |
| 580 | if (referral_list.GetSize() > 0 && |
| 581 | referral_list.GetInteger(0, &format_version) && |
| 582 | format_version == DNS_REFERRER_VERSION) { |
| 583 | for (size_t i = 1; i < referral_list.GetSize(); ++i) { |
| 584 | ListValue* motivator; |
| 585 | if (!referral_list.GetList(i, &motivator)) { |
| 586 | NOTREACHED(); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 587 | return; |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 588 | } |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 589 | std::string motivating_url_spec; |
| 590 | if (!motivator->GetString(0, &motivating_url_spec)) { |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 591 | NOTREACHED(); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 592 | return; |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 593 | } |
| 594 | |
| 595 | Value* subresource_list; |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 596 | if (!motivator->Get(1, &subresource_list)) { |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 597 | NOTREACHED(); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 598 | return; |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 599 | } |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 600 | |
| 601 | referrers_[GURL(motivating_url_spec)].Deserialize(*subresource_list); |
[email protected] | 760d970a | 2010-05-18 00:39:18 | [diff] [blame] | 602 | } |
[email protected] | 03c5e86 | 2009-02-17 22:50:14 | [diff] [blame] | 603 | } |
| 604 | } |
| 605 | |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 606 | |
| 607 | //------------------------------------------------------------------------------ |
| 608 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 609 | Predictor::HostNameQueue::HostNameQueue() { |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 610 | } |
| 611 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 612 | Predictor::HostNameQueue::~HostNameQueue() { |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 613 | } |
| 614 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 615 | void Predictor::HostNameQueue::Push(const GURL& url, |
| 616 | UrlInfo::ResolutionMotivation motivation) { |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 617 | switch (motivation) { |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 618 | case UrlInfo::STATIC_REFERAL_MOTIVATED: |
| 619 | case UrlInfo::LEARNED_REFERAL_MOTIVATED: |
| 620 | case UrlInfo::MOUSE_OVER_MOTIVATED: |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 621 | rush_queue_.push(url); |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 622 | break; |
| 623 | |
| 624 | default: |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 625 | background_queue_.push(url); |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 626 | break; |
| 627 | } |
| 628 | } |
| 629 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 630 | bool Predictor::HostNameQueue::IsEmpty() const { |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 631 | return rush_queue_.empty() && background_queue_.empty(); |
| 632 | } |
| 633 | |
[email protected] | 74be069e8 | 2010-06-25 00:12:49 | [diff] [blame] | 634 | GURL Predictor::HostNameQueue::Pop() { |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 635 | DCHECK(!IsEmpty()); |
[email protected] | c5629c3 | 2010-06-23 01:22:43 | [diff] [blame] | 636 | std::queue<GURL> *queue(rush_queue_.empty() ? &background_queue_ |
| 637 | : &rush_queue_); |
| 638 | GURL url(queue->front()); |
| 639 | queue->pop(); |
| 640 | return url; |
[email protected] | a20bc09 | 2009-06-05 01:34:20 | [diff] [blame] | 641 | } |
| 642 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 643 | } // namespace chrome_browser_net |