blob: a5b71e7cda4d4b2b8a82df663d0c0792d6912103 [file] [log] [blame]
[email protected]74be069e82010-06-25 00:12:491// Copyright (c) 2006-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]74be069e82010-06-25 00:12:495// A Predictor object is instantiated once in the browser process, and manages
6// both preresolution of hostnames, as well as TCP/IP preconnection to expected
7// subresources.
8// Most hostname lists are provided by the renderer processes, and include URLs
9// that *might* be used in the near future by the browsing user. One goal of
10// this class is to cause the underlying DNS structure to lookup a hostname
11// before it is really needed, and hence reduce latency in the standard lookup
12// paths.
13// Subresource relationships are usually acquired from the referrer field in a
14// navigation. A subresource URL may be associated with a referrer URL. Later
15// navigations may, if the likelihood of needing the subresource is high enough,
[email protected]f4ef861ba2010-07-28 22:37:2316// cause this module to speculatively create a TCP/IP connection. If there is
17// only a low likelihood, then a DNS pre-resolution operation may be performed.
initial.commit09911bf2008-07-26 23:55:2918
[email protected]3530cd92010-06-27 06:22:0119#ifndef CHROME_BROWSER_NET_PREDICTOR_H_
20#define CHROME_BROWSER_NET_PREDICTOR_H_
[email protected]32b76ef2010-07-26 23:08:2421#pragma once
initial.commit09911bf2008-07-26 23:55:2922
23#include <map>
24#include <queue>
[email protected]1933eb202009-02-19 18:23:2525#include <set>
initial.commit09911bf2008-07-26 23:55:2926#include <string>
[email protected]c5629c32010-06-23 01:22:4327#include <vector>
initial.commit09911bf2008-07-26 23:55:2928
[email protected]a918f872010-06-01 14:30:5129#include "base/gtest_prod_util.h"
[email protected]fd2f8afe2009-06-11 21:53:5530#include "base/ref_counted.h"
[email protected]3530cd92010-06-27 06:22:0131#include "chrome/browser/net/url_info.h"
[email protected]21dae9b2008-11-06 23:32:5332#include "chrome/browser/net/referrer.h"
[email protected]3530cd92010-06-27 06:22:0133#include "chrome/common/net/predictor_common.h"
[email protected]760d970a2010-05-18 00:39:1834#include "net/base/host_port_pair.h"
initial.commit09911bf2008-07-26 23:55:2935
[email protected]fd2f8afe2009-06-11 21:53:5536namespace net {
37class HostResolver;
[email protected]0ac83682010-01-22 17:46:2738} // namespace net
[email protected]fd2f8afe2009-06-11 21:53:5539
initial.commit09911bf2008-07-26 23:55:2940namespace chrome_browser_net {
41
[email protected]c5629c32010-06-23 01:22:4342typedef chrome_common_net::UrlList UrlList;
initial.commit09911bf2008-07-26 23:55:2943typedef chrome_common_net::NameList NameList;
[email protected]74be069e82010-06-25 00:12:4944typedef std::map<GURL, UrlInfo> Results;
initial.commit09911bf2008-07-26 23:55:2945
[email protected]74be069e82010-06-25 00:12:4946// Note that Predictor is not thread safe, and must only be called from
[email protected]ec86bea2009-12-08 18:35:1447// the IO thread. Failure to do so will result in a DCHECK at runtime.
[email protected]74be069e82010-06-25 00:12:4948class Predictor : public base::RefCountedThreadSafe<Predictor> {
initial.commit09911bf2008-07-26 23:55:2949 public:
[email protected]760d970a2010-05-18 00:39:1850 // A version number for prefs that are saved. This should be incremented when
51 // we change the format so that we discard old data.
[email protected]f4ef861ba2010-07-28 22:37:2352 enum { PREDICTOR_REFERRER_VERSION = 2 };
[email protected]760d970a2010-05-18 00:39:1853
[email protected]f4ef861ba2010-07-28 22:37:2354 // Depending on the expected_subresource_use_, we may either make a TCP/IP
55 // preconnection, or merely pre-resolve the hostname via DNS (or even do
56 // nothing). The following are the threasholds for taking those actions.
57 static const double kPreconnectWorthyExpectedValue;
58 static const double kDNSPreresolutionWorthyExpectedValue;
59 // Values of expected_subresource_use_ that are less than the following
60 // threshold will be discarded when we Trim() the values, such as is done when
61 // the process ends, and some values are persisted.
62 static const double kPersistWorthyExpectedValue;
63
64 // |max_concurrent| specifies how many concurrent (parallel) prefetches will
[email protected]ec86bea2009-12-08 18:35:1465 // be performed. Host lookups will be issued through |host_resolver|.
[email protected]74be069e82010-06-25 00:12:4966 Predictor(net::HostResolver* host_resolver,
[email protected]760d970a2010-05-18 00:39:1867 base::TimeDelta max_queue_delay_ms, size_t max_concurrent,
68 bool preconnect_enabled);
[email protected]b2b8b832009-02-06 19:03:2969
[email protected]1933eb202009-02-19 18:23:2570 // Cancel pending requests and prevent new ones from being made.
71 void Shutdown();
initial.commit09911bf2008-07-26 23:55:2972
73 // In some circumstances, for privacy reasons, all results should be
74 // discarded. This method gracefully handles that activity.
75 // Destroy all our internal state, which shows what names we've looked up, and
76 // how long each has taken, etc. etc. We also destroy records of suggesses
77 // (cache hits etc.).
78 void DiscardAllResults();
79
[email protected]1933eb202009-02-19 18:23:2580 // Add hostname(s) to the queue for processing.
[email protected]c5629c32010-06-23 01:22:4381 void ResolveList(const UrlList& urls,
[email protected]74be069e82010-06-25 00:12:4982 UrlInfo::ResolutionMotivation motivation);
[email protected]c5629c32010-06-23 01:22:4383 void Resolve(const GURL& url,
[email protected]74be069e82010-06-25 00:12:4984 UrlInfo::ResolutionMotivation motivation);
initial.commit09911bf2008-07-26 23:55:2985
[email protected]c5629c32010-06-23 01:22:4386 // Instigate pre-connection to any URLs we predict will be needed after this
87 // navigation (typically more-embedded resources on a page).
[email protected]74be069e82010-06-25 00:12:4988 void PredictFrameSubresources(const GURL& url);
[email protected]21dae9b2008-11-06 23:32:5389
90 // Record details of a navigation so that we can preresolve the host name
91 // ahead of time the next time the users navigates to the indicated host.
[email protected]74be069e82010-06-25 00:12:4992 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url);
[email protected]21dae9b2008-11-06 23:32:5393
94 // Dump HTML table containing list of referrers for about:dns.
95 void GetHtmlReferrerLists(std::string* output);
96
[email protected]74be069e82010-06-25 00:12:4997 // Dump the list of currently known referrer domains and related prefetchable
[email protected]21dae9b2008-11-06 23:32:5398 // domains.
initial.commit09911bf2008-07-26 23:55:2999 void GetHtmlInfo(std::string* output);
100
[email protected]03c5e862009-02-17 22:50:14101 // Discard any referrer for which all the suggested host names are currently
102 // annotated with no user latency reduction. Also scale down (diminish) the
103 // total benefit of those that did help, so that their reported contribution
104 // wll go done by a factor of 2 each time we trim (moving the referrer closer
105 // to being discarded at a future Trim).
106 void TrimReferrers();
107
108 // Construct a ListValue object that contains all the data in the referrers_
109 // so that it can be persisted in a pref.
110 void SerializeReferrers(ListValue* referral_list);
111
112 // Process a ListValue that contains all the data from a previous reference
113 // list, as constructed by SerializeReferrers(), and add all the identified
114 // values into the current referrer list.
115 void DeserializeReferrers(const ListValue& referral_list);
116
[email protected]ec86bea2009-12-08 18:35:14117 void DeserializeReferrersThenDelete(ListValue* referral_list) {
118 DeserializeReferrers(*referral_list);
119 delete referral_list;
120 }
121
[email protected]e695fbd62009-06-30 16:31:54122 // For unit test code only.
[email protected]74be069e82010-06-25 00:12:49123 size_t max_concurrent_dns_lookups() const {
124 return max_concurrent_dns_lookups_;
125 }
[email protected]e695fbd62009-06-30 16:31:54126
[email protected]760d970a2010-05-18 00:39:18127 // Flag setting to use preconnection instead of just DNS pre-fetching.
128 bool preconnect_enabled() const { return preconnect_enabled_; }
129
[email protected]b2b8b832009-02-06 19:03:29130 private:
[email protected]74be069e82010-06-25 00:12:49131 friend class base::RefCountedThreadSafe<Predictor>;
132 FRIEND_TEST_ALL_PREFIXES(PredictorTest, BenefitLookupTest);
133 FRIEND_TEST_ALL_PREFIXES(PredictorTest, ShutdownWhenResolutionIsPendingTest);
134 FRIEND_TEST_ALL_PREFIXES(PredictorTest, SingleLookupTest);
135 FRIEND_TEST_ALL_PREFIXES(PredictorTest, ConcurrentLookupTest);
136 FRIEND_TEST_ALL_PREFIXES(PredictorTest, MassiveConcurrentLookupTest);
137 FRIEND_TEST_ALL_PREFIXES(PredictorTest, PriorityQueuePushPopTest);
138 FRIEND_TEST_ALL_PREFIXES(PredictorTest, PriorityQueueReorderTest);
[email protected]1933eb202009-02-19 18:23:25139 friend class WaitForResolutionHelper; // For testing.
140
[email protected]74be069e82010-06-25 00:12:49141 ~Predictor();
[email protected]7991a232009-11-06 01:55:48142
[email protected]1933eb202009-02-19 18:23:25143 class LookupRequest;
144
[email protected]a20bc092009-06-05 01:34:20145 // A simple priority queue for handling host names.
146 // Some names that are queued up have |motivation| that requires very rapid
147 // handling. For example, a sub-resource name lookup MUST be done before the
148 // actual sub-resource is fetched. In contrast, a name that was speculatively
149 // noted in a page has to be resolved before the user "gets around to"
150 // clicking on a link. By tagging (with a motivation) each push we make into
151 // this FIFO queue, the queue can re-order the more important names to service
152 // them sooner (relative to some low priority background resolutions).
153 class HostNameQueue {
154 public:
155 HostNameQueue();
156 ~HostNameQueue();
[email protected]c5629c32010-06-23 01:22:43157 void Push(const GURL& url,
[email protected]74be069e82010-06-25 00:12:49158 UrlInfo::ResolutionMotivation motivation);
[email protected]a20bc092009-06-05 01:34:20159 bool IsEmpty() const;
[email protected]c5629c32010-06-23 01:22:43160 GURL Pop();
[email protected]a20bc092009-06-05 01:34:20161
162 private:
163 // The names in the queue that should be serviced (popped) ASAP.
[email protected]c5629c32010-06-23 01:22:43164 std::queue<GURL> rush_queue_;
[email protected]a20bc092009-06-05 01:34:20165 // The names in the queue that should only be serviced when rush_queue is
166 // empty.
[email protected]c5629c32010-06-23 01:22:43167 std::queue<GURL> background_queue_;
[email protected]a20bc092009-06-05 01:34:20168
169 DISALLOW_COPY_AND_ASSIGN(HostNameQueue);
170 };
171
[email protected]760d970a2010-05-18 00:39:18172 // A map that is keyed with the host/port that we've learned were the cause
173 // of loading additional URLs. The list of additional targets is held
174 // in a Referrer instance, which is a value in this map.
[email protected]c5629c32010-06-23 01:22:43175 typedef std::map<GURL, Referrer> Referrers;
[email protected]7c19b87b02009-01-26 16:19:44176
[email protected]1933eb202009-02-19 18:23:25177 // Only for testing. Returns true if hostname has been successfully resolved
178 // (name found).
[email protected]c5629c32010-06-23 01:22:43179 bool WasFound(const GURL& url) const {
180 Results::const_iterator it(results_.find(url));
[email protected]760d970a2010-05-18 00:39:18181 return (it != results_.end()) &&
182 it->second.was_found();
[email protected]1933eb202009-02-19 18:23:25183 }
184
185 // Only for testing. Return how long was the resolution
[email protected]74be069e82010-06-25 00:12:49186 // or UrlInfo::kNullDuration if it hasn't been resolved yet.
[email protected]c5629c32010-06-23 01:22:43187 base::TimeDelta GetResolutionDuration(const GURL& url) {
[email protected]c5629c32010-06-23 01:22:43188 if (results_.find(url) == results_.end())
[email protected]74be069e82010-06-25 00:12:49189 return UrlInfo::kNullDuration;
[email protected]c5629c32010-06-23 01:22:43190 return results_[url].resolve_duration();
[email protected]1933eb202009-02-19 18:23:25191 }
192
193 // Only for testing;
194 size_t peak_pending_lookups() const { return peak_pending_lookups_; }
195
[email protected]85398532009-06-16 21:32:18196 // Access method for use by async lookup request to pass resolution result.
[email protected]c5629c32010-06-23 01:22:43197 void OnLookupFinished(LookupRequest* request, const GURL& url, bool found);
[email protected]1933eb202009-02-19 18:23:25198
[email protected]85398532009-06-16 21:32:18199 // Underlying method for both async and synchronous lookup to update state.
[email protected]ec86bea2009-12-08 18:35:14200 void LookupFinished(LookupRequest* request,
[email protected]c5629c32010-06-23 01:22:43201 const GURL& url, bool found);
[email protected]85398532009-06-16 21:32:18202
[email protected]21dae9b2008-11-06 23:32:53203 // Queue hostname for resolution. If queueing was done, return the pointer
204 // to the queued instance, otherwise return NULL.
[email protected]74be069e82010-06-25 00:12:49205 UrlInfo* AppendToResolutionQueue(const GURL& url,
206 UrlInfo::ResolutionMotivation motivation);
initial.commit09911bf2008-07-26 23:55:29207
[email protected]a20bc092009-06-05 01:34:20208 // Check to see if too much queuing delay has been noted for the given info,
209 // which indicates that there is "congestion" or growing delay in handling the
210 // resolution of names. Rather than letting this congestion potentially grow
211 // without bounds, we abandon our queued efforts at pre-resolutions in such a
212 // case.
213 // To do this, we will recycle |info|, as well as all queued items, back to
214 // the state they had before they were queued up. We can't do anything about
215 // the resolutions we've already sent off for processing on another thread, so
216 // we just let them complete. On a slow system, subject to congestion, this
217 // will greatly reduce the number of resolutions done, but it will assure that
218 // any resolutions that are done, are in a timely and hence potentially
219 // helpful manner.
[email protected]74be069e82010-06-25 00:12:49220 bool CongestionControlPerformed(UrlInfo* info);
[email protected]a20bc092009-06-05 01:34:20221
222 // Take lookup requests from work_queue_ and tell HostResolver to look them up
223 // asynchronously, provided we don't exceed concurrent resolution limit.
[email protected]ec86bea2009-12-08 18:35:14224 void StartSomeQueuedResolutions();
initial.commit09911bf2008-07-26 23:55:29225
[email protected]a20bc092009-06-05 01:34:20226 // work_queue_ holds a list of names we need to look up.
227 HostNameQueue work_queue_;
initial.commit09911bf2008-07-26 23:55:29228
[email protected]21dae9b2008-11-06 23:32:53229 // results_ contains information for existing/prior prefetches.
initial.commit09911bf2008-07-26 23:55:29230 Results results_;
231
[email protected]760d970a2010-05-18 00:39:18232 // For each URL that we might navigate to (that we've "learned about")
[email protected]21dae9b2008-11-06 23:32:53233 // we have a Referrer list. Each Referrer list has all hostnames we need to
234 // pre-resolve when there is a navigation to the orginial hostname.
235 Referrers referrers_;
236
[email protected]1933eb202009-02-19 18:23:25237 std::set<LookupRequest*> pending_lookups_;
initial.commit09911bf2008-07-26 23:55:29238
[email protected]1933eb202009-02-19 18:23:25239 // For testing, to verify that we don't exceed the limit.
240 size_t peak_pending_lookups_;
[email protected]b2b8b832009-02-06 19:03:29241
[email protected]1933eb202009-02-19 18:23:25242 // When true, we don't make new lookup requests.
[email protected]b2b8b832009-02-06 19:03:29243 bool shutdown_;
244
[email protected]e085c302009-06-01 18:31:36245 // The number of concurrent lookups currently allowed.
[email protected]74be069e82010-06-25 00:12:49246 const size_t max_concurrent_dns_lookups_;
[email protected]e085c302009-06-01 18:31:36247
[email protected]602faf3c2009-06-27 14:35:44248 // The maximum queueing delay that is acceptable before we enter congestion
249 // reduction mode, and discard all queued (but not yet assigned) resolutions.
[email protected]74be069e82010-06-25 00:12:49250 const base::TimeDelta max_dns_queue_delay_;
[email protected]602faf3c2009-06-27 14:35:44251
[email protected]ec86bea2009-12-08 18:35:14252 // The host resovler we warm DNS entries for.
[email protected]94a0d3d92009-06-27 01:50:14253 scoped_refptr<net::HostResolver> host_resolver_;
[email protected]fd2f8afe2009-06-11 21:53:55254
[email protected]760d970a2010-05-18 00:39:18255 // Are we currently using preconnection, rather than just DNS resolution, for
256 // subresources and omni-box search URLs.
257 bool preconnect_enabled_;
258
[email protected]74be069e82010-06-25 00:12:49259 DISALLOW_COPY_AND_ASSIGN(Predictor);
initial.commit09911bf2008-07-26 23:55:29260};
261
262} // namespace chrome_browser_net
263
[email protected]3530cd92010-06-27 06:22:01264#endif // CHROME_BROWSER_NET_PREDICTOR_H_