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

Unified Diff: chrome/browser/net/predictor.cc

Issue 7467012: Modifying prefetch to account for multi-profile. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/net/predictor.cc
===================================================================
--- chrome/browser/net/predictor.cc (revision 89645)
+++ chrome/browser/net/predictor.cc (working copy)
@@ -12,9 +12,15 @@
#include "base/compiler_specific.h"
#include "base/metrics/histogram.h"
#include "base/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
#include "base/time.h"
#include "base/values.h"
#include "chrome/browser/net/preconnect.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
@@ -28,6 +34,8 @@
namespace chrome_browser_net {
+static void DnsPrefetchMotivatedList(const UrlList& urls,
+ UrlInfo::ResolutionMotivation motivation);
// static
const double Predictor::kPreconnectWorthyExpectedValue = 0.8;
// static
@@ -54,6 +62,10 @@
// static
const size_t Predictor::kUrlsTrimmedPerIncrement = 5u;
+// A version number for prefs that are saved. This should be incremented when
+// we change the format so that we discard old data.
+static const int kPredictorStartupFormatVersion = 1;
+
class Predictor::LookupRequest {
public:
LookupRequest(Predictor* predictor,
@@ -102,8 +114,12 @@
Predictor::Predictor(net::HostResolver* host_resolver,
TimeDelta max_dns_queue_delay,
size_t max_concurrent,
- bool preconnect_enabled)
- : peak_pending_lookups_(0),
+ bool preconnect_enabled,
+ bool predictor_enabled)
+ : predictor_enabled_(true),
+ off_the_record_windows_count_(0),
+ on_the_record_(true),
+ peak_pending_lookups_(0),
shutdown_(false),
max_concurrent_dns_lookups_(max_concurrent),
max_dns_queue_delay_(max_dns_queue_delay),
@@ -112,6 +128,7 @@
consecutive_omnibox_preconnect_count_(0),
next_trim_time_(base::TimeTicks::Now() + kDurationBetweenTrimmings),
ALLOW_THIS_IN_INITIALIZER_LIST(trim_task_factory_(this)) {
+ initial_observer_.reset(new InitialObserver());
}
Predictor::~Predictor() {
@@ -151,6 +168,8 @@
void Predictor::LearnFromNavigation(const GURL& referring_url,
const GURL& target_url) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!predictor_enabled_)
+ return;
DCHECK_EQ(referring_url, Predictor::CanonicalizeUrl(referring_url));
DCHECK_NE(referring_url, GURL::EmptyGURL());
DCHECK_EQ(target_url, Predictor::CanonicalizeUrl(target_url));
@@ -169,6 +188,11 @@
};
void Predictor::AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!predictor_enabled_)
+ return;
+ if (!url.is_valid() || !url.has_host())
+ return;
std::string host = url.HostNoBrackets();
bool is_new_host_request = (host != last_omnibox_host_);
last_omnibox_host_ = host;
@@ -237,6 +261,10 @@
}
void Predictor::PreconnectUrlAndSubresources(const GURL& url) {
+ if (!predictor_enabled_)
+ return;
+ if (!url.is_valid() || !url.has_host())
+ return;
if (preconnect_enabled()) {
std::string host = url.HostNoBrackets();
UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED);
@@ -248,6 +276,8 @@
}
void Predictor::PredictFrameSubresources(const GURL& url) {
+ if (!predictor_enabled_)
+ return;
DCHECK_EQ(url.GetWithEmptyPath(), url);
// Add one pass through the message loop to allow current navigation to
// proceed.
@@ -423,6 +453,11 @@
void Predictor::GetHtmlInfo(std::string* output) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (initial_observer_.get())
+ initial_observer_->GetFirstResolutionsHtml(output);
+ // Show list of subresource predictions and stats.
+ GetHtmlReferrerLists(output);
+
// Local lists for calling UrlInfo
UrlInfo::UrlInfoTable name_not_found;
UrlInfo::UrlInfoTable name_preresolved;
@@ -703,8 +738,212 @@
PostIncrementalTrimTask();
}
+void Predictor::DiscardInitialNavigationHistory() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (initial_observer_.get())
+ initial_observer_->DiscardInitialNavigationHistory();
+}
+
+void Predictor::FinalizeInitialization(
+ const UrlList& startup_urls,
+ ListValue* referral_list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // Prefetch these hostnames on startup.
+ DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED);
+ DeserializeReferrersThenDelete(referral_list);
+}
+
//------------------------------------------------------------------------------
+// This section intermingles prefetch results with actual browser HTTP
+// network activity. It supports calculating of the benefit of a prefetch, as
+// well as recording what prefetched hostname resolutions might be potentially
+// helpful during the next chrome-startup.
+//------------------------------------------------------------------------------
+void Predictor::LearnAboutInitialNavigation(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!predictor_enabled_ || NULL == initial_observer_.get() )
+ return;
+ initial_observer_->Append(url, this);
+}
+
+// This API is only used in the browser process.
+// It is called from an IPC message originating in the renderer. It currently
+// includes both Page-Scan, and Link-Hover prefetching.
+// TODO(jar): Separate out link-hover prefetching, and page-scan results.
+void Predictor::DnsPrefetchList(const NameList& hostnames) {
+ // TODO(jar): Push GURL transport further back into renderer, but this will
+ // require a Webkit change in the observer :-/.
+ UrlList urls;
+ for (NameList::const_iterator it = hostnames.begin();
+ it < hostnames.end();
+ ++it) {
+ urls.push_back(GURL("http://" + *it + ":80"));
+ }
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DnsPrefetchMotivatedList(urls, UrlInfo::PAGE_SCAN_MOTIVATED);
+}
+
+void Predictor::DnsPrefetchMotivatedList(
+ const UrlList& urls,
+ UrlInfo::ResolutionMotivation motivation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+ BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!predictor_enabled_)
+ return;
+
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ ResolveList(urls, motivation);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(this, &Predictor::ResolveList, urls, motivation));
+ }
+}
+
+//------------------------------------------------------------------------------
+// Functions to handle saving of hostnames from one session to the next, to
+// expedite startup times.
+
+static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
+ ListValue* startup_list,
+ ListValue* referral_list,
+ base::WaitableEvent* completion,
+ Profile* profile) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (NULL == profile->GetPredictor()) {
+ completion->Signal();
+ return;
+ }
+ profile->GetPredictor()->SaveDnsPrefetchStateForNextStartupAndTrim(
+ startup_list, referral_list, completion);
+}
+
+void Predictor::SaveDnsPrefetchStateForNextStartupAndTrim(
+ ListValue* startup_list,
+ ListValue* referral_list,
+ base::WaitableEvent* completion) {
+ if (initial_observer_.get())
+ initial_observer_->GetInitialDnsResolutionList(startup_list);
+
+ // Do at least one trim at shutdown, in case the user wasn't running long
+ // enough to do any regular trimming of referrers.
+ TrimReferrersNow();
+ SerializeReferrers(referral_list);
+
+ completion->Signal();
+}
+
+void Predictor::SaveStateForNextStartupAndTrim(PrefService* prefs,
+ Profile* profile) {
+ if (!predictor_enabled_)
+ return;
+
+ base::WaitableEvent completion(true, false);
+
+ ListPrefUpdate update_startup_list(prefs, prefs::kDnsPrefetchingStartupList);
+ ListPrefUpdate update_referral_list(prefs,
+ prefs::kDnsPrefetchingHostReferralList);
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
+ update_startup_list.Get(),
+ update_referral_list.Get(),
+ &completion,
+ profile);
+ } else {
+ bool posted = BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableFunction(
+ SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread,
+ update_startup_list.Get(),
+ update_referral_list.Get(),
+ &completion,
+ profile));
+
+ // TODO(jar): Synchronous waiting for the IO thread is a potential source
+ // to deadlocks and should be investigated. See http://crbug.com/78451.
+ DCHECK(posted);
+ if (posted)
+ completion.Wait();
+ }
+}
+
+UrlList Predictor::GetPredictedUrlListAtStartup(
+ PrefService* user_prefs,
+ PrefService* local_state) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UrlList urls;
+ // Recall list of URLs we learned about during last session.
+ // This may catch secondary hostnames, pulled in by the homepages. It will
+ // also catch more of the "primary" home pages, since that was (presumably)
+ // rendered first (and will be rendered first this time too).
+ const ListValue* startup_list =
+ user_prefs->GetList(prefs::kDnsPrefetchingStartupList);
+
+ if (startup_list) {
+ ListValue::const_iterator it = startup_list->begin();
+ int format_version = -1;
+ if (it != startup_list->end() &&
+ (*it)->GetAsInteger(&format_version) &&
+ format_version == kPredictorStartupFormatVersion) {
+ ++it;
+ for (; it != startup_list->end(); ++it) {
+ std::string url_spec;
+ if (!(*it)->GetAsString(&url_spec)) {
+ LOG(DFATAL);
+ break; // Format incompatibility.
+ }
+ GURL url(url_spec);
+ if (!url.has_host() || !url.has_scheme()) {
+ LOG(DFATAL);
+ break; // Format incompatibility.
+ }
+
+ urls.push_back(url);
+ }
+ }
+ }
+
+ // Prepare for any static home page(s) the user has in prefs. The user may
+ // have a LOT of tab's specified, so we may as well try to warm them all.
+ SessionStartupPref tab_start_pref =
+ SessionStartupPref::GetStartupPref(user_prefs);
+ if (SessionStartupPref::URLS == tab_start_pref.type) {
+ for (size_t i = 0; i < tab_start_pref.urls.size(); i++) {
+ GURL gurl = tab_start_pref.urls[i];
+ if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty())
+ continue;
+ if (gurl.SchemeIs("http") || gurl.SchemeIs("https"))
+ urls.push_back(gurl.GetWithEmptyPath());
+ }
+ }
+
+ if (urls.empty())
+ urls.push_back(GURL("http://www.google.com:80"));
+
+ return urls;
+}
+
+bool Predictor::HandleIncognitoBrowserClosed() {
+ DCHECK_LT(0, off_the_record_windows_count_);
+ if (0 >= off_the_record_windows_count_) // Defensive coding.
+ return false;
+ if (--off_the_record_windows_count_)
+ return false; // Still some windows are incognito.
+ return true;
+}
+
+void Predictor::HandleIncognitoBrowserOpened() {
+ off_the_record_windows_count_++;
+}
+
+//------------------------------------------------------------------------------
+
Predictor::HostNameQueue::HostNameQueue() {
}
@@ -744,7 +983,59 @@
delete referral_list;
}
+//------------------------------------------------------------------------------
+// Member definitions for InitialObserver class.
+void Predictor::InitialObserver::Append(const GURL& url,
+ Predictor* predictor) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // TODO(rlp): Do we really need the predictor check here?
+ if (!predictor->on_the_record() || NULL == predictor)
+ return;
+ if (kStartupResolutionCount <= first_navigations_.size())
+ return;
+
+ DCHECK(url.SchemeIs("http") || url.SchemeIs("https"));
+ DCHECK_EQ(url, Predictor::CanonicalizeUrl(url));
+ if (first_navigations_.find(url) == first_navigations_.end())
+ first_navigations_[url] = base::TimeTicks::Now();
+}
+
+void Predictor::InitialObserver::GetInitialDnsResolutionList(
+ ListValue* startup_list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(startup_list);
+ startup_list->Clear();
+ DCHECK_EQ(0u, startup_list->GetSize());
+ startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion));
+ for (FirstNavigations::iterator it = first_navigations_.begin();
+ it != first_navigations_.end();
+ ++it) {
+ DCHECK(it->first == Predictor::CanonicalizeUrl(it->first));
+ startup_list->Append(new StringValue(it->first.spec()));
+ }
+}
+
+void Predictor::InitialObserver::GetFirstResolutionsHtml(
+ std::string* output) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ UrlInfo::UrlInfoTable resolution_list;
+ {
+ for (FirstNavigations::iterator it(first_navigations_.begin());
+ it != first_navigations_.end();
+ it++) {
+ UrlInfo info;
+ info.SetUrl(it->first);
+ info.set_time(it->second);
+ resolution_list.push_back(info);
+ }
+ }
+ UrlInfo::GetHtmlTable(resolution_list,
+ "Future startups will prefetch DNS records for ", false, output);
+}
+
//------------------------------------------------------------------------------
// Helper functions
//------------------------------------------------------------------------------

Powered by Google App Engine
This is Rietveld 408576698