blob: 5c1b518b95c128c00fe5db42a1e0a5c285fdb9e3 [file] [log] [blame]
[email protected]2fbaecf22010-07-22 22:20:351// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]3530cd92010-06-27 06:22:015#include "chrome/browser/net/predictor.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]1933eb202009-02-19 18:23:257#include <algorithm>
[email protected]319d9e6f2009-02-18 19:47:218#include <set>
[email protected]1933eb202009-02-19 18:23:259#include <sstream>
initial.commit09911bf2008-07-26 23:55:2910
[email protected]1933eb202009-02-19 18:23:2511#include "base/compiler_specific.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/histogram.h"
13#include "base/stats_counters.h"
[email protected]21dae9b2008-11-06 23:32:5314#include "base/string_util.h"
[email protected]1933eb202009-02-19 18:23:2515#include "base/time.h"
[email protected]6fad2632009-11-02 05:59:3716#include "chrome/browser/chrome_thread.h"
[email protected]760d970a2010-05-18 00:39:1817#include "chrome/browser/net/preconnect.h"
[email protected]1933eb202009-02-19 18:23:2518#include "net/base/address_list.h"
19#include "net/base/completion_callback.h"
[email protected]760d970a2010-05-18 00:39:1820#include "net/base/host_port_pair.h"
[email protected]1933eb202009-02-19 18:23:2521#include "net/base/host_resolver.h"
22#include "net/base/net_errors.h"
[email protected]9e743cd2010-03-16 07:03:5323#include "net/base/net_log.h"
[email protected]e1acf6f2008-10-27 20:43:3324
[email protected]602faf3c2009-06-27 14:35:4425using base::TimeDelta;
26
initial.commit09911bf2008-07-26 23:55:2927namespace chrome_browser_net {
28
[email protected]f4ef861ba2010-07-28 22:37:2329// static
30const double Predictor::kPreconnectWorthyExpectedValue = 0.7;
31// static
32const double Predictor::kDNSPreresolutionWorthyExpectedValue = 0.2;
33// static
34const double Predictor::kPersistWorthyExpectedValue = 0.1;
35
36
[email protected]74be069e82010-06-25 00:12:4937class Predictor::LookupRequest {
[email protected]1933eb202009-02-19 18:23:2538 public:
[email protected]74be069e82010-06-25 00:12:4939 LookupRequest(Predictor* predictor,
[email protected]8a00f00a2009-06-12 00:49:3840 net::HostResolver* host_resolver,
[email protected]c5629c32010-06-23 01:22:4341 const GURL& url)
[email protected]1933eb202009-02-19 18:23:2542 : ALLOW_THIS_IN_INITIALIZER_LIST(
43 net_callback_(this, &LookupRequest::OnLookupFinished)),
[email protected]74be069e82010-06-25 00:12:4944 predictor_(predictor),
[email protected]c5629c32010-06-23 01:22:4345 url_(url),
[email protected]8a00f00a2009-06-12 00:49:3846 resolver_(host_resolver) {
initial.commit09911bf2008-07-26 23:55:2947 }
[email protected]1933eb202009-02-19 18:23:2548
[email protected]85398532009-06-16 21:32:1849 // Return underlying network resolver status.
50 // net::OK ==> Host was found synchronously.
51 // net:ERR_IO_PENDING ==> Network will callback later with result.
52 // anything else ==> Host was not found synchronously.
53 int Start() {
[email protected]c5629c32010-06-23 01:22:4354 net::HostResolver::RequestInfo resolve_info(url_.host(),
55 url_.EffectiveIntPort());
[email protected]2884a462009-06-15 05:08:4256
57 // Make a note that this is a speculative resolve request. This allows us
58 // to separate it from real navigations in the observer's callback, and
59 // lets the HostResolver know it can de-prioritize it.
60 resolve_info.set_is_speculative(true);
[email protected]ec08bb22009-08-12 00:25:1261 return resolver_.Resolve(
[email protected]9e743cd2010-03-16 07:03:5362 resolve_info, &addresses_, &net_callback_, net::BoundNetLog());
[email protected]1933eb202009-02-19 18:23:2563 }
64
65 private:
66 void OnLookupFinished(int result) {
[email protected]74be069e82010-06-25 00:12:4967 predictor_->OnLookupFinished(this, url_, result == net::OK);
[email protected]1933eb202009-02-19 18:23:2568 }
69
70 // HostResolver will call us using this callback when resolution is complete.
71 net::CompletionCallbackImpl<LookupRequest> net_callback_;
72
[email protected]74be069e82010-06-25 00:12:4973 Predictor* predictor_; // The predictor which started us.
[email protected]1933eb202009-02-19 18:23:2574
[email protected]c5629c32010-06-23 01:22:4375 const GURL url_; // Hostname to resolve.
[email protected]8a00f00a2009-06-12 00:49:3876 net::SingleRequestHostResolver resolver_;
[email protected]1933eb202009-02-19 18:23:2577 net::AddressList addresses_;
78
79 DISALLOW_COPY_AND_ASSIGN(LookupRequest);
80};
81
[email protected]74be069e82010-06-25 00:12:4982Predictor::Predictor(net::HostResolver* host_resolver,
83 base::TimeDelta max_dns_queue_delay,
[email protected]760d970a2010-05-18 00:39:1884 size_t max_concurrent,
85 bool preconnect_enabled)
86 : peak_pending_lookups_(0),
87 shutdown_(false),
[email protected]74be069e82010-06-25 00:12:4988 max_concurrent_dns_lookups_(max_concurrent),
89 max_dns_queue_delay_(max_dns_queue_delay),
[email protected]760d970a2010-05-18 00:39:1890 host_resolver_(host_resolver),
91 preconnect_enabled_(preconnect_enabled) {
92 Referrer::SetUsePreconnectValuations(preconnect_enabled);
[email protected]1933eb202009-02-19 18:23:2593}
94
[email protected]74be069e82010-06-25 00:12:4995Predictor::~Predictor() {
[email protected]1933eb202009-02-19 18:23:2596 DCHECK(shutdown_);
97}
98
[email protected]74be069e82010-06-25 00:12:4999void Predictor::Shutdown() {
[email protected]ec86bea2009-12-08 18:35:14100 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]1933eb202009-02-19 18:23:25101 DCHECK(!shutdown_);
102 shutdown_ = true;
103
104 std::set<LookupRequest*>::iterator it;
105 for (it = pending_lookups_.begin(); it != pending_lookups_.end(); ++it)
106 delete *it;
initial.commit09911bf2008-07-26 23:55:29107}
108
109// Overloaded Resolve() to take a vector of names.
[email protected]74be069e82010-06-25 00:12:49110void Predictor::ResolveList(const UrlList& urls,
111 UrlInfo::ResolutionMotivation motivation) {
[email protected]ec86bea2009-12-08 18:35:14112 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fd2f8afe2009-06-11 21:53:55113
[email protected]c5629c32010-06-23 01:22:43114 for (UrlList::const_iterator it = urls.begin(); it < urls.end(); ++it) {
115 AppendToResolutionQueue(*it, motivation);
116 }
initial.commit09911bf2008-07-26 23:55:29117}
118
119// Basic Resolve() takes an invidual name, and adds it
120// to the queue.
[email protected]74be069e82010-06-25 00:12:49121void Predictor::Resolve(const GURL& url,
122 UrlInfo::ResolutionMotivation motivation) {
[email protected]ec86bea2009-12-08 18:35:14123 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]c5629c32010-06-23 01:22:43124 if (!url.has_host())
initial.commit09911bf2008-07-26 23:55:29125 return;
[email protected]c5629c32010-06-23 01:22:43126 AppendToResolutionQueue(url, motivation);
initial.commit09911bf2008-07-26 23:55:29127}
128
[email protected]74be069e82010-06-25 00:12:49129void Predictor::LearnFromNavigation(const GURL& referring_url,
130 const GURL& target_url) {
[email protected]ec86bea2009-12-08 18:35:14131 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]c5629c32010-06-23 01:22:43132 if (referring_url.has_host() &&
133 referring_url != target_url) {
134 DCHECK(referring_url == referring_url.GetWithEmptyPath());
135 referrers_[referring_url].SuggestHost(target_url);
136 }
[email protected]21dae9b2008-11-06 23:32:53137}
138
[email protected]f4ef861ba2010-07-28 22:37:23139enum SubresourceValue {
140 PRECONNECTION,
141 PRERESOLUTION,
142 TOO_NEW,
143 SUBRESOURCE_VALUE_MAX
144};
[email protected]c5629c32010-06-23 01:22:43145
[email protected]74be069e82010-06-25 00:12:49146void Predictor::PredictFrameSubresources(const GURL& url) {
[email protected]c5629c32010-06-23 01:22:43147 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
148 DCHECK(url.GetWithEmptyPath() == url);
149 Referrers::iterator it = referrers_.find(url);
150 if (referrers_.end() == it)
151 return;
[email protected]9008c86f2010-08-06 07:10:24152 ChromeThread::PostTask(
153 ChromeThread::IO,
154 FROM_HERE,
155 NewRunnableMethod(this,
156 &Predictor::PrepareFrameSubresources, url));
157}
158
159void Predictor::PrepareFrameSubresources(const GURL& url) {
160 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
161 DCHECK(url.GetWithEmptyPath() == url);
162 Referrers::iterator it = referrers_.find(url);
163 if (referrers_.end() == it)
164 return;
165
[email protected]c5629c32010-06-23 01:22:43166 Referrer* referrer = &(it->second);
167 referrer->IncrementUseCount();
[email protected]f4ef861ba2010-07-28 22:37:23168 const UrlInfo::ResolutionMotivation motivation =
169 UrlInfo::LEARNED_REFERAL_MOTIVATED;
[email protected]c5629c32010-06-23 01:22:43170 for (Referrer::iterator future_url = referrer->begin();
171 future_url != referrer->end(); ++future_url) {
[email protected]f4ef861ba2010-07-28 22:37:23172 SubresourceValue evalution(TOO_NEW);
173 double connection_expectation = future_url->second.subresource_use_rate();
174 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation",
175 static_cast<int>(connection_expectation * 100),
176 10, 5000, 50);
177 future_url->second.ReferrerWasObserved();
178 if (preconnect_enabled_ &&
179 kPreconnectWorthyExpectedValue < connection_expectation) {
180 evalution = PRECONNECTION;
181 future_url->second.IncrementPreconnectionCount();
182 Preconnect::PreconnectOnIOThread(future_url->first, motivation);
183 } else if (kDNSPreresolutionWorthyExpectedValue < connection_expectation) {
184 evalution = PRERESOLUTION;
185 future_url->second.preresolution_increment();
186 UrlInfo* queued_info = AppendToResolutionQueue(future_url->first,
187 motivation);
188 if (queued_info)
189 queued_info->SetReferringHostname(url);
190 }
191 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution,
192 SUBRESOURCE_VALUE_MAX);
initial.commit09911bf2008-07-26 23:55:29193 }
194}
195
initial.commit09911bf2008-07-26 23:55:29196// Provide sort order so all .com's are together, etc.
197struct RightToLeftStringSorter {
[email protected]760d970a2010-05-18 00:39:18198 bool operator()(const GURL& left,
199 const GURL& right) const {
200 return string_compare(left.host(), right.host());
201 }
202
203 static bool string_compare(const std::string& left_host,
204 const std::string right_host) {
205 if (left_host == right_host) return true;
206 size_t left_already_matched = left_host.size();
207 size_t right_already_matched = right_host.size();
[email protected]21dae9b2008-11-06 23:32:53208
209 // Ensure both strings have characters.
210 if (!left_already_matched) return true;
211 if (!right_already_matched) return false;
212
213 // Watch for trailing dot, so we'll always be safe to go one beyond dot.
[email protected]760d970a2010-05-18 00:39:18214 if ('.' == left_host[left_already_matched - 1]) {
215 if ('.' != right_host[right_already_matched - 1])
initial.commit09911bf2008-07-26 23:55:29216 return true;
[email protected]21dae9b2008-11-06 23:32:53217 // Both have dots at end of string.
218 --left_already_matched;
219 --right_already_matched;
220 } else {
[email protected]760d970a2010-05-18 00:39:18221 if ('.' == right_host[right_already_matched - 1])
[email protected]21dae9b2008-11-06 23:32:53222 return false;
223 }
224
225 while (1) {
226 if (!left_already_matched) return true;
227 if (!right_already_matched) return false;
228
229 size_t left_length, right_length;
[email protected]760d970a2010-05-18 00:39:18230 size_t left_start = left_host.find_last_of('.', left_already_matched - 1);
[email protected]21dae9b2008-11-06 23:32:53231 if (std::string::npos == left_start) {
232 left_length = left_already_matched;
233 left_already_matched = left_start = 0;
234 } else {
235 left_length = left_already_matched - left_start;
236 left_already_matched = left_start;
237 ++left_start; // Don't compare the dot.
238 }
[email protected]760d970a2010-05-18 00:39:18239 size_t right_start = right_host.find_last_of('.',
240 right_already_matched - 1);
[email protected]21dae9b2008-11-06 23:32:53241 if (std::string::npos == right_start) {
242 right_length = right_already_matched;
243 right_already_matched = right_start = 0;
244 } else {
245 right_length = right_already_matched - right_start;
246 right_already_matched = right_start;
247 ++right_start; // Don't compare the dot.
248 }
249
[email protected]760d970a2010-05-18 00:39:18250 int diff = left_host.compare(left_start, left_host.size(),
251 right_host, right_start, right_host.size());
[email protected]21dae9b2008-11-06 23:32:53252 if (diff > 0) return false;
253 if (diff < 0) return true;
initial.commit09911bf2008-07-26 23:55:29254 }
255 }
256};
257
[email protected]74be069e82010-06-25 00:12:49258void Predictor::GetHtmlReferrerLists(std::string* output) {
[email protected]ec86bea2009-12-08 18:35:14259 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]21dae9b2008-11-06 23:32:53260 if (referrers_.empty())
261 return;
262
263 // TODO(jar): Remove any plausible JavaScript from names before displaying.
264
[email protected]c5629c32010-06-23 01:22:43265 typedef std::set<GURL, struct RightToLeftStringSorter>
[email protected]760d970a2010-05-18 00:39:18266 SortedNames;
[email protected]21dae9b2008-11-06 23:32:53267 SortedNames sorted_names;
268
269 for (Referrers::iterator it = referrers_.begin();
270 referrers_.end() != it; ++it)
271 sorted_names.insert(it->first);
272
273 output->append("<br><table border>");
[email protected]760d970a2010-05-18 00:39:18274 output->append(
275 "<tr><th>Host for Page</th>"
276 "<th>Page Load<br>Count</th>"
277 "<th>Subresource<br>Navigations</th>"
278 "<th>Subresource<br>PreConnects</th>"
[email protected]f4ef861ba2010-07-28 22:37:23279 "<th>Subresource<br>PreResolves</th>"
[email protected]760d970a2010-05-18 00:39:18280 "<th>Expected<br>Connects</th>"
[email protected]760d970a2010-05-18 00:39:18281 "<th>Subresource Spec</th></tr>");
[email protected]21dae9b2008-11-06 23:32:53282
283 for (SortedNames::iterator it = sorted_names.begin();
284 sorted_names.end() != it; ++it) {
285 Referrer* referrer = &(referrers_[*it]);
[email protected]760d970a2010-05-18 00:39:18286 bool first_set_of_futures = true;
[email protected]c5629c32010-06-23 01:22:43287 for (Referrer::iterator future_url = referrer->begin();
288 future_url != referrer->end(); ++future_url) {
[email protected]760d970a2010-05-18 00:39:18289 output->append("<tr align=right>");
290 if (first_set_of_futures)
291 StringAppendF(output, "<td rowspan=%d>%s</td><td rowspan=%d>%d</td>",
292 static_cast<int>(referrer->size()),
[email protected]c5629c32010-06-23 01:22:43293 it->spec().c_str(),
[email protected]760d970a2010-05-18 00:39:18294 static_cast<int>(referrer->size()),
295 static_cast<int>(referrer->use_count()));
296 first_set_of_futures = false;
297 StringAppendF(output,
[email protected]f4ef861ba2010-07-28 22:37:23298 "<td>%d</td><td>%d</td><td>%d</td><td>%2.3f</td><td>%s</td></tr>",
[email protected]c5629c32010-06-23 01:22:43299 static_cast<int>(future_url->second.navigation_count()),
300 static_cast<int>(future_url->second.preconnection_count()),
[email protected]f4ef861ba2010-07-28 22:37:23301 static_cast<int>(future_url->second.preresolution_count()),
[email protected]c5629c32010-06-23 01:22:43302 static_cast<double>(future_url->second.subresource_use_rate()),
[email protected]c5629c32010-06-23 01:22:43303 future_url->first.spec().c_str());
[email protected]21dae9b2008-11-06 23:32:53304 }
[email protected]21dae9b2008-11-06 23:32:53305 }
306 output->append("</table>");
307}
308
[email protected]74be069e82010-06-25 00:12:49309void Predictor::GetHtmlInfo(std::string* output) {
[email protected]ec86bea2009-12-08 18:35:14310 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]74be069e82010-06-25 00:12:49311 // Local lists for calling UrlInfo
[email protected]f4ef861ba2010-07-28 22:37:23312 UrlInfo::UrlInfoTable name_not_found;
313 UrlInfo::UrlInfoTable name_preresolved;
initial.commit09911bf2008-07-26 23:55:29314
[email protected]ec86bea2009-12-08 18:35:14315 // Get copies of all useful data.
[email protected]f4ef861ba2010-07-28 22:37:23316 typedef std::map<GURL, UrlInfo, RightToLeftStringSorter> SortedUrlInfo;
317 SortedUrlInfo snapshot;
318 // UrlInfo supports value semantics, so we can do a shallow copy.
319 for (Results::iterator it(results_.begin()); it != results_.end(); it++)
320 snapshot[it->first] = it->second;
initial.commit09911bf2008-07-26 23:55:29321
[email protected]74be069e82010-06-25 00:12:49322 // Partition the UrlInfo's into categories.
[email protected]f4ef861ba2010-07-28 22:37:23323 for (SortedUrlInfo::iterator it(snapshot.begin());
324 it != snapshot.end(); it++) {
initial.commit09911bf2008-07-26 23:55:29325 if (it->second.was_nonexistant()) {
326 name_not_found.push_back(it->second);
327 continue;
328 }
329 if (!it->second.was_found())
330 continue; // Still being processed.
[email protected]f4ef861ba2010-07-28 22:37:23331 name_preresolved.push_back(it->second);
initial.commit09911bf2008-07-26 23:55:29332 }
333
334 bool brief = false;
335#ifdef NDEBUG
336 brief = true;
337#endif // NDEBUG
338
339 // Call for display of each table, along with title.
[email protected]f4ef861ba2010-07-28 22:37:23340 UrlInfo::GetHtmlTable(name_preresolved,
341 "Preresolution DNS records performed for ", brief, output);
[email protected]74be069e82010-06-25 00:12:49342 UrlInfo::GetHtmlTable(name_not_found,
[email protected]f4ef861ba2010-07-28 22:37:23343 "Preresolving DNS records revealed non-existance for ", brief, output);
initial.commit09911bf2008-07-26 23:55:29344}
345
[email protected]74be069e82010-06-25 00:12:49346UrlInfo* Predictor::AppendToResolutionQueue(
[email protected]c5629c32010-06-23 01:22:43347 const GURL& url,
[email protected]74be069e82010-06-25 00:12:49348 UrlInfo::ResolutionMotivation motivation) {
[email protected]ec86bea2009-12-08 18:35:14349 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]c5629c32010-06-23 01:22:43350 DCHECK(url.has_host());
initial.commit09911bf2008-07-26 23:55:29351
[email protected]1933eb202009-02-19 18:23:25352 if (shutdown_)
353 return NULL;
354
[email protected]74be069e82010-06-25 00:12:49355 UrlInfo* info = &results_[url];
[email protected]c5629c32010-06-23 01:22:43356 info->SetUrl(url); // Initialize or DCHECK.
initial.commit09911bf2008-07-26 23:55:29357 // TODO(jar): I need to discard names that have long since expired.
358 // Currently we only add to the domain map :-/
359
[email protected]c5629c32010-06-23 01:22:43360 DCHECK(info->HasUrl(url));
initial.commit09911bf2008-07-26 23:55:29361
[email protected]760d970a2010-05-18 00:39:18362 if (!info->NeedsDnsUpdate()) {
initial.commit09911bf2008-07-26 23:55:29363 info->DLogResultsStats("DNS PrefetchNotUpdated");
[email protected]21dae9b2008-11-06 23:32:53364 return NULL;
initial.commit09911bf2008-07-26 23:55:29365 }
366
[email protected]21dae9b2008-11-06 23:32:53367 info->SetQueuedState(motivation);
[email protected]c5629c32010-06-23 01:22:43368 work_queue_.Push(url, motivation);
[email protected]ec86bea2009-12-08 18:35:14369 StartSomeQueuedResolutions();
[email protected]21dae9b2008-11-06 23:32:53370 return info;
initial.commit09911bf2008-07-26 23:55:29371}
372
[email protected]74be069e82010-06-25 00:12:49373void Predictor::StartSomeQueuedResolutions() {
[email protected]6fad2632009-11-02 05:59:37374 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fd2f8afe2009-06-11 21:53:55375
[email protected]a20bc092009-06-05 01:34:20376 while (!work_queue_.IsEmpty() &&
[email protected]74be069e82010-06-25 00:12:49377 pending_lookups_.size() < max_concurrent_dns_lookups_) {
[email protected]c5629c32010-06-23 01:22:43378 const GURL url(work_queue_.Pop());
[email protected]74be069e82010-06-25 00:12:49379 UrlInfo* info = &results_[url];
[email protected]c5629c32010-06-23 01:22:43380 DCHECK(info->HasUrl(url));
initial.commit09911bf2008-07-26 23:55:29381 info->SetAssignedState();
382
[email protected]ec86bea2009-12-08 18:35:14383 if (CongestionControlPerformed(info)) {
[email protected]a20bc092009-06-05 01:34:20384 DCHECK(work_queue_.IsEmpty());
385 return;
386 }
387
[email protected]c5629c32010-06-23 01:22:43388 LookupRequest* request = new LookupRequest(this, host_resolver_, url);
[email protected]85398532009-06-16 21:32:18389 int status = request->Start();
390 if (status == net::ERR_IO_PENDING) {
[email protected]fd2f8afe2009-06-11 21:53:55391 // Will complete asynchronously.
[email protected]1933eb202009-02-19 18:23:25392 pending_lookups_.insert(request);
393 peak_pending_lookups_ = std::max(peak_pending_lookups_,
394 pending_lookups_.size());
395 } else {
[email protected]221f33362009-06-29 20:46:48396 // Completed synchronously (was already cached by HostResolver), or else
[email protected]85398532009-06-16 21:32:18397 // there was (equivalently) some network error that prevents us from
398 // finding the name. Status net::OK means it was "found."
[email protected]c5629c32010-06-23 01:22:43399 LookupFinished(request, url, status == net::OK);
[email protected]1933eb202009-02-19 18:23:25400 delete request;
401 }
402 }
initial.commit09911bf2008-07-26 23:55:29403}
404
[email protected]74be069e82010-06-25 00:12:49405bool Predictor::CongestionControlPerformed(UrlInfo* info) {
[email protected]ec86bea2009-12-08 18:35:14406 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]a20bc092009-06-05 01:34:20407 // Note: queue_duration is ONLY valid after we go to assigned state.
[email protected]74be069e82010-06-25 00:12:49408 if (info->queue_duration() < max_dns_queue_delay_)
[email protected]a20bc092009-06-05 01:34:20409 return false;
410 // We need to discard all entries in our queue, as we're keeping them waiting
411 // too long. By doing this, we'll have a chance to quickly service urgent
412 // resolutions, and not have a bogged down system.
413 while (true) {
414 info->RemoveFromQueue();
415 if (work_queue_.IsEmpty())
416 break;
417 info = &results_[work_queue_.Pop()];
418 info->SetAssignedState();
419 }
420 return true;
421}
422
[email protected]74be069e82010-06-25 00:12:49423void Predictor::OnLookupFinished(LookupRequest* request, const GURL& url,
[email protected]760d970a2010-05-18 00:39:18424 bool found) {
[email protected]6fad2632009-11-02 05:59:37425 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fd2f8afe2009-06-11 21:53:55426
[email protected]c5629c32010-06-23 01:22:43427 LookupFinished(request, url, found);
[email protected]85398532009-06-16 21:32:18428 pending_lookups_.erase(request);
429 delete request;
430
[email protected]ec86bea2009-12-08 18:35:14431 StartSomeQueuedResolutions();
[email protected]85398532009-06-16 21:32:18432}
433
[email protected]74be069e82010-06-25 00:12:49434void Predictor::LookupFinished(LookupRequest* request, const GURL& url,
[email protected]ec86bea2009-12-08 18:35:14435 bool found) {
436 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]74be069e82010-06-25 00:12:49437 UrlInfo* info = &results_[url];
[email protected]c5629c32010-06-23 01:22:43438 DCHECK(info->HasUrl(url));
[email protected]a20bc092009-06-05 01:34:20439 if (info->is_marked_to_delete()) {
[email protected]c5629c32010-06-23 01:22:43440 results_.erase(url);
[email protected]a20bc092009-06-05 01:34:20441 } else {
[email protected]1933eb202009-02-19 18:23:25442 if (found)
443 info->SetFoundState();
444 else
445 info->SetNoSuchNameState();
[email protected]7c19b87b02009-01-26 16:19:44446 }
initial.commit09911bf2008-07-26 23:55:29447}
448
[email protected]74be069e82010-06-25 00:12:49449void Predictor::DiscardAllResults() {
[email protected]ec86bea2009-12-08 18:35:14450 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29451 // Delete anything listed so far in this session that shows in about:dns.
[email protected]21dae9b2008-11-06 23:32:53452 referrers_.clear();
initial.commit09911bf2008-07-26 23:55:29453
454
455 // Try to delete anything in our work queue.
[email protected]a20bc092009-06-05 01:34:20456 while (!work_queue_.IsEmpty()) {
initial.commit09911bf2008-07-26 23:55:29457 // Emulate processing cycle as though host was not found.
[email protected]c5629c32010-06-23 01:22:43458 GURL url = work_queue_.Pop();
[email protected]74be069e82010-06-25 00:12:49459 UrlInfo* info = &results_[url];
[email protected]c5629c32010-06-23 01:22:43460 DCHECK(info->HasUrl(url));
initial.commit09911bf2008-07-26 23:55:29461 info->SetAssignedState();
462 info->SetNoSuchNameState();
463 }
[email protected]1933eb202009-02-19 18:23:25464 // Now every result_ is either resolved, or is being resolved
465 // (see LookupRequest).
initial.commit09911bf2008-07-26 23:55:29466
467 // Step through result_, recording names of all hosts that can't be erased.
[email protected]1933eb202009-02-19 18:23:25468 // We can't erase anything being worked on.
initial.commit09911bf2008-07-26 23:55:29469 Results assignees;
470 for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
[email protected]c5629c32010-06-23 01:22:43471 GURL url(it->first);
[email protected]74be069e82010-06-25 00:12:49472 UrlInfo* info = &it->second;
[email protected]c5629c32010-06-23 01:22:43473 DCHECK(info->HasUrl(url));
initial.commit09911bf2008-07-26 23:55:29474 if (info->is_assigned()) {
475 info->SetPendingDeleteState();
[email protected]c5629c32010-06-23 01:22:43476 assignees[url] = *info;
initial.commit09911bf2008-07-26 23:55:29477 }
478 }
[email protected]74be069e82010-06-25 00:12:49479 DCHECK(assignees.size() <= max_concurrent_dns_lookups_);
initial.commit09911bf2008-07-26 23:55:29480 results_.clear();
[email protected]1933eb202009-02-19 18:23:25481 // Put back in the names being worked on.
initial.commit09911bf2008-07-26 23:55:29482 for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
483 DCHECK(it->second.is_marked_to_delete());
484 results_[it->first] = it->second;
485 }
486}
487
[email protected]74be069e82010-06-25 00:12:49488void Predictor::TrimReferrers() {
[email protected]ec86bea2009-12-08 18:35:14489 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]c5629c32010-06-23 01:22:43490 std::vector<GURL> urls;
[email protected]03c5e862009-02-17 22:50:14491 for (Referrers::const_iterator it = referrers_.begin();
492 it != referrers_.end(); ++it)
[email protected]c5629c32010-06-23 01:22:43493 urls.push_back(it->first);
494 for (size_t i = 0; i < urls.size(); ++i)
495 if (!referrers_[urls[i]].Trim())
496 referrers_.erase(urls[i]);
[email protected]03c5e862009-02-17 22:50:14497}
498
[email protected]74be069e82010-06-25 00:12:49499void Predictor::SerializeReferrers(ListValue* referral_list) {
[email protected]ec86bea2009-12-08 18:35:14500 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]03c5e862009-02-17 22:50:14501 referral_list->Clear();
[email protected]f4ef861ba2010-07-28 22:37:23502 referral_list->Append(new FundamentalValue(PREDICTOR_REFERRER_VERSION));
[email protected]03c5e862009-02-17 22:50:14503 for (Referrers::const_iterator it = referrers_.begin();
504 it != referrers_.end(); ++it) {
505 // Serialize the list of subresource names.
506 Value* subresource_list(it->second.Serialize());
507
508 // Create a list for each referer.
[email protected]760d970a2010-05-18 00:39:18509 ListValue* motivator(new ListValue);
[email protected]c5629c32010-06-23 01:22:43510 motivator->Append(new StringValue(it->first.spec()));
[email protected]760d970a2010-05-18 00:39:18511 motivator->Append(subresource_list);
[email protected]03c5e862009-02-17 22:50:14512
[email protected]760d970a2010-05-18 00:39:18513 referral_list->Append(motivator);
[email protected]03c5e862009-02-17 22:50:14514 }
515}
516
[email protected]74be069e82010-06-25 00:12:49517void Predictor::DeserializeReferrers(const ListValue& referral_list) {
[email protected]ec86bea2009-12-08 18:35:14518 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18519 int format_version = -1;
520 if (referral_list.GetSize() > 0 &&
521 referral_list.GetInteger(0, &format_version) &&
[email protected]f4ef861ba2010-07-28 22:37:23522 format_version == PREDICTOR_REFERRER_VERSION) {
[email protected]760d970a2010-05-18 00:39:18523 for (size_t i = 1; i < referral_list.GetSize(); ++i) {
524 ListValue* motivator;
525 if (!referral_list.GetList(i, &motivator)) {
526 NOTREACHED();
[email protected]c5629c32010-06-23 01:22:43527 return;
[email protected]760d970a2010-05-18 00:39:18528 }
[email protected]c5629c32010-06-23 01:22:43529 std::string motivating_url_spec;
530 if (!motivator->GetString(0, &motivating_url_spec)) {
[email protected]760d970a2010-05-18 00:39:18531 NOTREACHED();
[email protected]c5629c32010-06-23 01:22:43532 return;
[email protected]760d970a2010-05-18 00:39:18533 }
534
535 Value* subresource_list;
[email protected]c5629c32010-06-23 01:22:43536 if (!motivator->Get(1, &subresource_list)) {
[email protected]760d970a2010-05-18 00:39:18537 NOTREACHED();
[email protected]c5629c32010-06-23 01:22:43538 return;
[email protected]760d970a2010-05-18 00:39:18539 }
[email protected]c5629c32010-06-23 01:22:43540
541 referrers_[GURL(motivating_url_spec)].Deserialize(*subresource_list);
[email protected]760d970a2010-05-18 00:39:18542 }
[email protected]03c5e862009-02-17 22:50:14543 }
544}
545
[email protected]a20bc092009-06-05 01:34:20546
547//------------------------------------------------------------------------------
548
[email protected]74be069e82010-06-25 00:12:49549Predictor::HostNameQueue::HostNameQueue() {
[email protected]a20bc092009-06-05 01:34:20550}
551
[email protected]74be069e82010-06-25 00:12:49552Predictor::HostNameQueue::~HostNameQueue() {
[email protected]a20bc092009-06-05 01:34:20553}
554
[email protected]74be069e82010-06-25 00:12:49555void Predictor::HostNameQueue::Push(const GURL& url,
556 UrlInfo::ResolutionMotivation motivation) {
[email protected]a20bc092009-06-05 01:34:20557 switch (motivation) {
[email protected]74be069e82010-06-25 00:12:49558 case UrlInfo::STATIC_REFERAL_MOTIVATED:
559 case UrlInfo::LEARNED_REFERAL_MOTIVATED:
560 case UrlInfo::MOUSE_OVER_MOTIVATED:
[email protected]c5629c32010-06-23 01:22:43561 rush_queue_.push(url);
[email protected]a20bc092009-06-05 01:34:20562 break;
563
564 default:
[email protected]c5629c32010-06-23 01:22:43565 background_queue_.push(url);
[email protected]a20bc092009-06-05 01:34:20566 break;
567 }
568}
569
[email protected]74be069e82010-06-25 00:12:49570bool Predictor::HostNameQueue::IsEmpty() const {
[email protected]a20bc092009-06-05 01:34:20571 return rush_queue_.empty() && background_queue_.empty();
572}
573
[email protected]74be069e82010-06-25 00:12:49574GURL Predictor::HostNameQueue::Pop() {
[email protected]a20bc092009-06-05 01:34:20575 DCHECK(!IsEmpty());
[email protected]c5629c32010-06-23 01:22:43576 std::queue<GURL> *queue(rush_queue_.empty() ? &background_queue_
577 : &rush_queue_);
578 GURL url(queue->front());
579 queue->pop();
580 return url;
[email protected]a20bc092009-06-05 01:34:20581}
582
initial.commit09911bf2008-07-26 23:55:29583} // namespace chrome_browser_net