Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: chrome/browser/net/dns_global.cc

Issue 2866026: Rename Dns prefetching files to Predictor files... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/net/dns_global.h ('k') | chrome/browser/net/dns_host_info.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/net/dns_global.h"
6
7 #include <map>
8 #include <string>
9
10 #include "base/singleton.h"
11 #include "base/stats_counters.h"
12 #include "base/stl_util-inl.h"
13 #include "base/string_util.h"
14 #include "base/thread.h"
15 #include "base/waitable_event.h"
16 #include "base/values.h"
17 #include "chrome/browser/browser.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chrome_thread.h"
20 #include "chrome/browser/io_thread.h"
21 #include "chrome/browser/net/dns_host_info.h"
22 #include "chrome/browser/net/preconnect.h"
23 #include "chrome/browser/net/referrer.h"
24 #include "chrome/browser/pref_service.h"
25 #include "chrome/browser/profile.h"
26 #include "chrome/browser/session_startup_pref.h"
27 #include "chrome/common/notification_registrar.h"
28 #include "chrome/common/notification_service.h"
29 #include "chrome/common/pref_names.h"
30 #include "net/base/host_resolver.h"
31 #include "net/base/host_resolver_impl.h"
32
33 using base::Time;
34 using base::TimeDelta;
35
36 namespace chrome_browser_net {
37
38 static void DnsMotivatedPrefetch(const GURL& url,
39 UrlInfo::ResolutionMotivation motivation);
40
41 static void DnsPrefetchMotivatedList(const UrlList& urls,
42 UrlInfo::ResolutionMotivation motivation);
43
44 static UrlList GetPredictedUrlListAtStartup(
45 PrefService* user_prefs, PrefService* local_state);
46
47 // static
48 const size_t PredictorInit::kMaxPrefetchConcurrentLookups = 8;
49
50 // static
51 const int PredictorInit::kMaxPrefetchQueueingDelayMs = 500;
52
53 // A version number for prefs that are saved. This should be incremented when
54 // we change the format so that we discard old data.
55 static const int kPredictorStartupFormatVersion = 1;
56
57 //------------------------------------------------------------------------------
58 // Static helper functions
59 //------------------------------------------------------------------------------
60
61 // Put URL in canonical form, including a scheme, host, and port.
62 // Returns GURL::EmptyGURL() if the scheme is not http/https or if the url
63 // cannot be otherwise canonicalized.
64 static GURL CanonicalizeUrl(const GURL& url) {
65 if (!url.has_host())
66 return GURL::EmptyGURL();
67
68 std::string scheme;
69 if (url.has_scheme()) {
70 scheme = url.scheme();
71 if (scheme != "http" && scheme != "https")
72 return GURL::EmptyGURL();
73 if (url.has_port())
74 return url.GetWithEmptyPath();
75 } else {
76 scheme = "http";
77 }
78
79 // If we omit a port, it will default to 80 or 443 as appropriate.
80 std::string colon_plus_port;
81 if (url.has_port())
82 colon_plus_port = ":" + url.port();
83
84 return GURL(scheme + "://" + url.host() + colon_plus_port);
85 }
86
87 //------------------------------------------------------------------------------
88 // This section contains all the globally accessable API entry points for the
89 // DNS Prefetching feature.
90 //------------------------------------------------------------------------------
91
92 // Status of prefetch feature, controlling whether any prefetching is done.
93 static bool dns_prefetch_enabled = true;
94
95 // Cached inverted copy of the off_the_record pref.
96 static bool on_the_record_switch = true;
97
98 // Enable/disable Dns prefetch activity (either via command line, or via pref).
99 void EnablePredictor(bool enable) {
100 // NOTE: this is invoked on the UI thread.
101 dns_prefetch_enabled = enable;
102 }
103
104 void OnTheRecord(bool enable) {
105 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
106 if (on_the_record_switch == enable)
107 return;
108 on_the_record_switch = enable;
109 if (on_the_record_switch)
110 g_browser_process->io_thread()->ChangedToOnTheRecord();
111 }
112
113 void RegisterPrefs(PrefService* local_state) {
114 local_state->RegisterListPref(prefs::kDnsStartupPrefetchList);
115 local_state->RegisterListPref(prefs::kDnsHostReferralList);
116 }
117
118 void RegisterUserPrefs(PrefService* user_prefs) {
119 user_prefs->RegisterBooleanPref(prefs::kDnsPrefetchingEnabled, true);
120 }
121
122 // When enabled, we use the following instance to service all requests in the
123 // browser process.
124 // TODO(willchan): Look at killing this.
125 static Predictor* predictor = NULL;
126
127 // This API is only used in the browser process.
128 // It is called from an IPC message originating in the renderer. It currently
129 // includes both Page-Scan, and Link-Hover prefetching.
130 // TODO(jar): Separate out link-hover prefetching, and page-scan results.
131 void DnsPrefetchList(const NameList& hostnames) {
132 // TODO(jar): Push GURL transport further back into renderer.
133 UrlList urls;
134 for (NameList::const_iterator it = hostnames.begin();
135 it < hostnames.end();
136 ++it) {
137 urls.push_back(GURL("http://" + *it + ":80"));
138 }
139
140 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
141 DnsPrefetchMotivatedList(urls, UrlInfo::PAGE_SCAN_MOTIVATED);
142 }
143
144 static void DnsPrefetchMotivatedList(
145 const UrlList& urls,
146 UrlInfo::ResolutionMotivation motivation) {
147 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI) ||
148 ChromeThread::CurrentlyOn(ChromeThread::IO));
149 if (!dns_prefetch_enabled || NULL == predictor)
150 return;
151
152 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
153 predictor->ResolveList(urls, motivation);
154 } else {
155 ChromeThread::PostTask(
156 ChromeThread::IO,
157 FROM_HERE,
158 NewRunnableMethod(predictor,
159 &Predictor::ResolveList, urls, motivation));
160 }
161 }
162
163 // This API is used by the autocomplete popup box (where URLs are typed).
164 void AnticipateUrl(const GURL& url, bool preconnectable) {
165 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
166 if (!dns_prefetch_enabled || NULL == predictor)
167 return;
168 if (!url.is_valid())
169 return;
170
171 static std::string last_host;
172 std::string host = url.HostNoBrackets();
173 bool is_new_host_request = (host != last_host);
174 last_host = host;
175
176 // Omnibox tends to call in pairs (just a few milliseconds apart), and we
177 // really don't need to keep resolving a name that often.
178 // TODO(jar): A/B tests could check for perf impact of the early returns.
179 static base::TimeTicks last_prefetch_for_host;
180 base::TimeTicks now = base::TimeTicks::Now();
181 if (!is_new_host_request) {
182 const int kMinPreresolveSeconds(10);
183 if (kMinPreresolveSeconds > (now - last_prefetch_for_host).InSeconds())
184 return;
185 }
186 last_prefetch_for_host = now;
187
188 GURL canonical_url(CanonicalizeUrl(url));
189
190 if (predictor->preconnect_enabled() && preconnectable) {
191 static base::TimeTicks last_keepalive;
192 // TODO(jar): The wild guess of 30 seconds could be tuned/tested, but it
193 // currently is just a guess that most sockets will remain open for at least
194 // 30 seconds.
195 const int kMaxSearchKeepaliveSeconds(30);
196 if ((now - last_keepalive).InSeconds() < kMaxSearchKeepaliveSeconds)
197 return;
198 last_keepalive = now;
199
200 if (Preconnect::PreconnectOnUIThread(canonical_url))
201 return; // Skip pre-resolution, since we'll open a connection.
202 }
203
204 // Perform at least DNS pre-resolution.
205 DnsMotivatedPrefetch(canonical_url, UrlInfo::OMNIBOX_MOTIVATED);
206 }
207
208 static void DnsMotivatedPrefetch(const GURL& url,
209 UrlInfo::ResolutionMotivation motivation) {
210 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
211 if (!dns_prefetch_enabled || NULL == predictor || !url.has_host())
212 return;
213
214 ChromeThread::PostTask(
215 ChromeThread::IO,
216 FROM_HERE,
217 NewRunnableMethod(predictor,
218 &Predictor::Resolve, url, motivation));
219 }
220
221 //------------------------------------------------------------------------------
222 // This section intermingles prefetch results with actual browser HTTP
223 // network activity. It supports calculating of the benefit of a prefetch, as
224 // well as recording what prefetched hostname resolutions might be potentially
225 // helpful during the next chrome-startup.
226 //------------------------------------------------------------------------------
227
228 // This function determines if there was a saving by prefetching the hostname
229 // for which the navigation_info is supplied.
230 static bool AccruePrefetchBenefits(const GURL& referrer_url,
231 UrlInfo* navigation_info) {
232 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
233 if (!dns_prefetch_enabled || NULL == predictor)
234 return false;
235 DCHECK(referrer_url == referrer_url.GetWithEmptyPath());
236 return predictor->AccruePrefetchBenefits(referrer_url, navigation_info);
237 }
238
239 void PredictSubresources(const GURL& url) {
240 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
241 if (!dns_prefetch_enabled || NULL == predictor)
242 return;
243 predictor->PredictSubresources(url);
244 }
245
246 void PredictFrameSubresources(const GURL& url) {
247 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
248 if (!dns_prefetch_enabled || NULL == predictor)
249 return;
250 predictor->PredictFrameSubresources(url);
251 }
252
253 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
254 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
255 if (!dns_prefetch_enabled || NULL == predictor)
256 return;
257 predictor->LearnFromNavigation(referring_url, target_url);
258 }
259
260 // The observer class needs to connect starts and finishes of HTTP network
261 // resolutions. We use the following type for that map.
262 typedef std::map<int, UrlInfo> ObservedResolutionMap;
263
264 // There will only be one instance ever created of the following Observer
265 // class. The PrefetchObserver lives on the IO thread, and intercepts DNS
266 // resolutions made by the network stack.
267 class PrefetchObserver : public net::HostResolver::Observer {
268 public:
269 typedef std::map<GURL, UrlInfo> FirstResolutionMap;
270
271 // net::HostResolver::Observer implementation:
272 virtual void OnStartResolution(
273 int request_id,
274 const net::HostResolver::RequestInfo& request_info);
275 virtual void OnFinishResolutionWithStatus(
276 int request_id,
277 bool was_resolved,
278 const net::HostResolver::RequestInfo& request_info);
279 virtual void OnCancelResolution(
280 int request_id,
281 const net::HostResolver::RequestInfo& request_info);
282
283 void DnsGetFirstResolutionsHtml(std::string* output);
284 void GetInitialDnsResolutionList(ListValue* startup_list);
285
286 private:
287 void StartupListAppend(const UrlInfo& navigation_info);
288
289 // Map of pending resolutions seen by observer.
290 ObservedResolutionMap resolutions_;
291 // List of the first N hostname resolutions observed in this run.
292 FirstResolutionMap first_resolutions_;
293 // The number of hostnames we'll save for prefetching at next startup.
294 static const size_t kStartupResolutionCount = 10;
295 };
296
297 // TODO(willchan): Look at killing this global.
298 static PrefetchObserver* g_prefetch_observer = NULL;
299
300 //------------------------------------------------------------------------------
301 // Member definitions for above Observer class.
302
303 void PrefetchObserver::OnStartResolution(
304 int request_id,
305 const net::HostResolver::RequestInfo& request_info) {
306 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
307 if (request_info.is_speculative())
308 return; // One of our own requests.
309 if (!request_info.hostname().length())
310 return; // PAC scripts may create queries without a hostname.
311
312 UrlInfo navigation_info;
313 // TODO(jar): Remove hack which guestimates ssl via port number, and perhaps
314 // have actual URL passed down in request_info instead.
315 bool is_ssl(443 == request_info.port());
316 std::string url_spec = is_ssl ? "https://" : "http://";
317 url_spec += request_info.hostname();
318 url_spec += ":";
319 url_spec += IntToString(request_info.port());
320 navigation_info.SetUrl(GURL(url_spec));
321 navigation_info.SetStartedState();
322
323 // This entry will be deleted either by OnFinishResolutionWithStatus(), or
324 // by OnCancelResolution().
325 resolutions_[request_id] = navigation_info;
326 }
327
328 void PrefetchObserver::OnFinishResolutionWithStatus(
329 int request_id,
330 bool was_resolved,
331 const net::HostResolver::RequestInfo& request_info) {
332 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
333 if (request_info.is_speculative())
334 return; // One of our own requests.
335 if (!request_info.hostname().length())
336 return; // PAC scripts may create queries without a hostname.
337 UrlInfo navigation_info;
338 size_t startup_count = 0;
339 {
340 ObservedResolutionMap::iterator it = resolutions_.find(request_id);
341 if (resolutions_.end() == it) {
342 NOTREACHED();
343 return;
344 }
345 navigation_info = it->second;
346 resolutions_.erase(it);
347 startup_count = first_resolutions_.size();
348 }
349
350 navigation_info.SetFinishedState(was_resolved); // Get timing info
351 AccruePrefetchBenefits(CanonicalizeUrl(request_info.referrer()),
352 &navigation_info);
353
354 // Handle sub-resource resolutions now that the critical navigational
355 // resolution has completed. This prevents us from in any way delaying that
356 // navigational resolution.
357 std::string url_spec;
358 StringAppendF(&url_spec, "http%s://%s:%d", "",
359 request_info.hostname().c_str(), request_info.port());
360 PredictSubresources(GURL(url_spec));
361
362 if (kStartupResolutionCount <= startup_count || !was_resolved)
363 return;
364 // TODO(jar): Don't add host to our list if it is a non-linked lookup, and
365 // instead rely on Referrers to pull this in automatically with the enclosing
366 // page load (once we start to persist elements of our referrer tree).
367 StartupListAppend(navigation_info);
368 }
369
370 void PrefetchObserver::OnCancelResolution(
371 int request_id,
372 const net::HostResolver::RequestInfo& request_info) {
373 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
374 if (request_info.is_speculative())
375 return; // One of our own requests.
376 if (!request_info.hostname().length())
377 return; // PAC scripts may create queries without a hostname.
378
379 // Remove the entry from |resolutions| that was added by OnStartResolution().
380 ObservedResolutionMap::iterator it = resolutions_.find(request_id);
381 if (resolutions_.end() == it) {
382 NOTREACHED();
383 return;
384 }
385 resolutions_.erase(it);
386 }
387
388 void PrefetchObserver::StartupListAppend(const UrlInfo& navigation_info) {
389 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
390
391 if (!on_the_record_switch || NULL == predictor)
392 return;
393 if (kStartupResolutionCount <= first_resolutions_.size())
394 return; // Someone just added the last item.
395 if (ContainsKey(first_resolutions_, navigation_info.url()))
396 return; // We already have this hostname listed.
397 first_resolutions_[navigation_info.url()] = navigation_info;
398 }
399
400 void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
401 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
402 DCHECK(startup_list);
403 startup_list->Clear();
404 DCHECK_EQ(0u, startup_list->GetSize());
405 startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion));
406 for (FirstResolutionMap::iterator it = first_resolutions_.begin();
407 it != first_resolutions_.end();
408 ++it) {
409 DCHECK(it->first == CanonicalizeUrl(it->first));
410 startup_list->Append(new StringValue(it->first.spec()));
411 }
412 }
413
414 void PrefetchObserver::DnsGetFirstResolutionsHtml(std::string* output) {
415 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
416
417 UrlInfo::DnsInfoTable resolution_list;
418 {
419 for (FirstResolutionMap::iterator it(first_resolutions_.begin());
420 it != first_resolutions_.end();
421 it++) {
422 resolution_list.push_back(it->second);
423 }
424 }
425 UrlInfo::GetHtmlTable(resolution_list,
426 "Future startups will prefetch DNS records for ", false, output);
427 }
428
429 //------------------------------------------------------------------------------
430 // Support observer to detect opening and closing of OffTheRecord windows.
431 // This object lives on the UI thread.
432
433 class OffTheRecordObserver : public NotificationObserver {
434 public:
435 void Register() {
436 // TODO(pkasting): This test should not be necessary. See crbug.com/12475.
437 if (registrar_.IsEmpty()) {
438 registrar_.Add(this, NotificationType::BROWSER_CLOSED,
439 NotificationService::AllSources());
440 registrar_.Add(this, NotificationType::BROWSER_OPENED,
441 NotificationService::AllSources());
442 }
443 }
444
445 void Observe(NotificationType type, const NotificationSource& source,
446 const NotificationDetails& details) {
447 switch (type.value) {
448 case NotificationType::BROWSER_OPENED:
449 if (!Source<Browser>(source)->profile()->IsOffTheRecord())
450 break;
451 ++count_off_the_record_windows_;
452 OnTheRecord(false);
453 break;
454
455 case NotificationType::BROWSER_CLOSED:
456 if (!Source<Browser>(source)->profile()->IsOffTheRecord())
457 break; // Ignore ordinary windows.
458 DCHECK_LT(0, count_off_the_record_windows_);
459 if (0 >= count_off_the_record_windows_) // Defensive coding.
460 break;
461 if (--count_off_the_record_windows_)
462 break; // Still some windows are incognito.
463 OnTheRecord(true);
464 break;
465
466 default:
467 break;
468 }
469 }
470
471 private:
472 friend struct DefaultSingletonTraits<OffTheRecordObserver>;
473 OffTheRecordObserver() : count_off_the_record_windows_(0) {}
474 ~OffTheRecordObserver() {}
475
476 NotificationRegistrar registrar_;
477 int count_off_the_record_windows_;
478
479 DISALLOW_COPY_AND_ASSIGN(OffTheRecordObserver);
480 };
481
482 //------------------------------------------------------------------------------
483 // This section supports the about:dns page.
484 //------------------------------------------------------------------------------
485
486 // Provide global support for the about:dns page.
487 void PredictorGetHtmlInfo(std::string* output) {
488 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
489
490 output->append("<html><head><title>About DNS</title>"
491 // We'd like the following no-cache... but it doesn't work.
492 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
493 "</head><body>");
494 if (!dns_prefetch_enabled || NULL == predictor) {
495 output->append("Dns Prefetching is disabled.");
496 } else {
497 if (!on_the_record_switch) {
498 output->append("Incognito mode is active in a window.");
499 } else {
500 predictor->GetHtmlInfo(output);
501 if (g_prefetch_observer)
502 g_prefetch_observer->DnsGetFirstResolutionsHtml(output);
503 predictor->GetHtmlReferrerLists(output);
504 }
505 }
506 output->append("</body></html>");
507 }
508
509 //------------------------------------------------------------------------------
510 // This section intializes global DNS prefetch services.
511 //------------------------------------------------------------------------------
512
513 static void InitNetworkPredictor(TimeDelta max_dns_queue_delay,
514 size_t max_concurrent, PrefService* user_prefs, PrefService* local_state,
515 bool preconnect_enabled) {
516 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
517
518 bool prefetching_enabled =
519 user_prefs->GetBoolean(prefs::kDnsPrefetchingEnabled);
520
521 // Gather the list of hostnames to prefetch on startup.
522 UrlList urls =
523 GetPredictedUrlListAtStartup(user_prefs, local_state);
524
525 ListValue* referral_list =
526 static_cast<ListValue*>(
527 local_state->GetMutableList(prefs::kDnsHostReferralList)->DeepCopy());
528
529 g_browser_process->io_thread()->InitNetworkPredictor(
530 prefetching_enabled, max_dns_queue_delay, max_concurrent, urls,
531 referral_list, preconnect_enabled);
532 }
533
534 void FinalizePredictorInitialization(
535 Predictor* global_predictor,
536 net::HostResolver::Observer* global_prefetch_observer,
537 const UrlList& startup_urls,
538 ListValue* referral_list) {
539 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
540 predictor = global_predictor;
541 g_prefetch_observer =
542 static_cast<PrefetchObserver*>(global_prefetch_observer);
543
544 DLOG(INFO) << "DNS Prefetch service started";
545
546 // Prefetch these hostnames on startup.
547 DnsPrefetchMotivatedList(startup_urls,
548 UrlInfo::STARTUP_LIST_MOTIVATED);
549 predictor->DeserializeReferrersThenDelete(referral_list);
550 }
551
552 void FreePredictorResources() {
553 predictor = NULL;
554 g_prefetch_observer = NULL;
555 }
556
557 //------------------------------------------------------------------------------
558
559 net::HostResolver::Observer* CreateResolverObserver() {
560 return new PrefetchObserver();
561 }
562
563 //------------------------------------------------------------------------------
564 // Functions to handle saving of hostnames from one session to the next, to
565 // expedite startup times.
566
567 static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
568 ListValue* startup_list,
569 ListValue* referral_list,
570 base::WaitableEvent* completion) {
571 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
572
573 if (NULL == predictor) {
574 completion->Signal();
575 return;
576 }
577
578 if (g_prefetch_observer)
579 g_prefetch_observer->GetInitialDnsResolutionList(startup_list);
580
581 // TODO(jar): Trimming should be done more regularly, such as every 48 hours
582 // of physical time, or perhaps after 48 hours of running (excluding time
583 // between sessions possibly).
584 // For now, we'll just trim at shutdown.
585 predictor->TrimReferrers();
586 predictor->SerializeReferrers(referral_list);
587
588 completion->Signal();
589 }
590
591 void SavePredictorStateForNextStartupAndTrim(PrefService* prefs) {
592 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
593
594 if (!dns_prefetch_enabled || predictor == NULL)
595 return;
596
597 base::WaitableEvent completion(true, false);
598
599 bool posted = ChromeThread::PostTask(
600 ChromeThread::IO,
601 FROM_HERE,
602 NewRunnableFunction(SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread,
603 prefs->GetMutableList(prefs::kDnsStartupPrefetchList),
604 prefs->GetMutableList(prefs::kDnsHostReferralList),
605 &completion));
606
607 DCHECK(posted);
608 if (posted)
609 completion.Wait();
610 }
611
612 static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
613 PrefService* local_state) {
614 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
615 UrlList urls;
616 // Recall list of URLs we learned about during last session.
617 // This may catch secondary hostnames, pulled in by the homepages. It will
618 // also catch more of the "primary" home pages, since that was (presumably)
619 // rendered first (and will be rendered first this time too).
620 ListValue* startup_list =
621 local_state->GetMutableList(prefs::kDnsStartupPrefetchList);
622 if (startup_list) {
623 ListValue::iterator it = startup_list->begin();
624 int format_version = -1;
625 if (it != startup_list->end() &&
626 (*it)->GetAsInteger(&format_version) &&
627 format_version == kPredictorStartupFormatVersion) {
628 ++it;
629 for (; it != startup_list->end(); ++it) {
630 std::string url_spec;
631 if (!(*it)->GetAsString(&url_spec)) {
632 LOG(DFATAL);
633 break; // Format incompatibility.
634 }
635 GURL url(url_spec);
636 if (!url.has_host() || !url.has_scheme()) {
637 LOG(DFATAL);
638 break; // Format incompatibility.
639 }
640
641 urls.push_back(url);
642 }
643 }
644 }
645
646 // Prepare for any static home page(s) the user has in prefs. The user may
647 // have a LOT of tab's specified, so we may as well try to warm them all.
648 SessionStartupPref tab_start_pref =
649 SessionStartupPref::GetStartupPref(user_prefs);
650 if (SessionStartupPref::URLS == tab_start_pref.type) {
651 for (size_t i = 0; i < tab_start_pref.urls.size(); i++) {
652 GURL gurl = tab_start_pref.urls[i];
653 if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty())
654 continue;
655 if (gurl.SchemeIs("http") || gurl.SchemeIs("https"))
656 urls.push_back(gurl.GetWithEmptyPath());
657 }
658 }
659
660 if (urls.empty())
661 urls.push_back(GURL("http://www.google.com:80"));
662
663 return urls;
664 }
665
666 //------------------------------------------------------------------------------
667 // Methods for the helper class that is used to startup and teardown the whole
668 // predictor system (both DNS pre-resolution and TCP/IP connection prewarming).
669
670 PredictorInit::PredictorInit(PrefService* user_prefs,
671 PrefService* local_state,
672 bool preconnect_enabled) {
673 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
674 // Set up a field trial to see what disabling DNS pre-resolution does to
675 // latency of page loads.
676 FieldTrial::Probability kDivisor = 1000;
677 // For each option (i.e., non-default), we have a fixed probability.
678 FieldTrial::Probability kProbabilityPerGroup = 1; // 0.1% probability.
679
680 trial_ = new FieldTrial("DnsImpact", kDivisor);
681
682 // First option is to disable prefetching completely.
683 int disabled_prefetch = trial_->AppendGroup("_disabled_prefetch",
684 kProbabilityPerGroup);
685
686
687 // We're running two experiments at the same time. The first set of trials
688 // modulates the delay-time until we declare a congestion event (and purge
689 // our queue). The second modulates the number of concurrent resolutions
690 // we do at any time. Users are in exactly one trial (or the default) during
691 // any one run, and hence only one experiment at a time.
692 // Experiment 1:
693 // Set congestion detection at 250, 500, or 750ms, rather than the 1 second
694 // default.
695 int max_250ms_prefetch = trial_->AppendGroup("_max_250ms_queue_prefetch",
696 kProbabilityPerGroup);
697 int max_500ms_prefetch = trial_->AppendGroup("_max_500ms_queue_prefetch",
698 kProbabilityPerGroup);
699 int max_750ms_prefetch = trial_->AppendGroup("_max_750ms_queue_prefetch",
700 kProbabilityPerGroup);
701 // Set congestion detection at 2 seconds instead of the 1 second default.
702 int max_2s_prefetch = trial_->AppendGroup("_max_2s_queue_prefetch",
703 kProbabilityPerGroup);
704 // Experiment 2:
705 // Set max simultaneous resoultions to 2, 4, or 6, and scale the congestion
706 // limit proportionally (so we don't impact average probability of asserting
707 // congesion very much).
708 int max_2_concurrent_prefetch = trial_->AppendGroup(
709 "_max_2 concurrent_prefetch", kProbabilityPerGroup);
710 int max_4_concurrent_prefetch = trial_->AppendGroup(
711 "_max_4 concurrent_prefetch", kProbabilityPerGroup);
712 int max_6_concurrent_prefetch = trial_->AppendGroup(
713 "_max_6 concurrent_prefetch", kProbabilityPerGroup);
714
715 trial_->AppendGroup("_default_enabled_prefetch",
716 FieldTrial::kAllRemainingProbability);
717
718 // We will register the incognito observer regardless of whether prefetching
719 // is enabled, as it is also used to clear the host cache.
720 Singleton<OffTheRecordObserver>::get()->Register();
721
722 if (trial_->group() != disabled_prefetch) {
723 // Initialize the DNS prefetch system.
724 size_t max_concurrent = kMaxPrefetchConcurrentLookups;
725 int max_queueing_delay_ms = kMaxPrefetchQueueingDelayMs;
726
727 if (trial_->group() == max_250ms_prefetch)
728 max_queueing_delay_ms = 250;
729 else if (trial_->group() == max_500ms_prefetch)
730 max_queueing_delay_ms = 500;
731 else if (trial_->group() == max_750ms_prefetch)
732 max_queueing_delay_ms = 750;
733 else if (trial_->group() == max_2s_prefetch)
734 max_queueing_delay_ms = 2000;
735 if (trial_->group() == max_2_concurrent_prefetch)
736 max_concurrent = 2;
737 else if (trial_->group() == max_4_concurrent_prefetch)
738 max_concurrent = 4;
739 else if (trial_->group() == max_6_concurrent_prefetch)
740 max_concurrent = 6;
741 // Scale acceptable delay so we don't cause congestion limits to fire as
742 // we modulate max_concurrent (*if* we are modulating it at all).
743 max_queueing_delay_ms = (kMaxPrefetchQueueingDelayMs *
744 kMaxPrefetchConcurrentLookups) / max_concurrent;
745
746 TimeDelta max_queueing_delay(
747 TimeDelta::FromMilliseconds(max_queueing_delay_ms));
748
749 DCHECK(!predictor);
750 InitNetworkPredictor(max_queueing_delay, max_concurrent, user_prefs,
751 local_state, preconnect_enabled);
752 }
753 }
754
755
756 } // namespace chrome_browser_net
OLDNEW
« no previous file with comments | « chrome/browser/net/dns_global.h ('k') | chrome/browser/net/dns_host_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698