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

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

Issue 7685009: Revert "Modifying prefetch to account for multi-profile." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 4 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
« no previous file with comments | « chrome/browser/net/predictor.h ('k') | chrome/browser/net/predictor_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/net/predictor.cc
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index 358c162cf0fa64fafc5ea5d57582c0ffce264018..ffc5e573b9074b1c439b4c9b3da2b5c0eee8290a 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.cc
@@ -9,23 +9,12 @@
#include <set>
#include <sstream>
-#include "base/bind.h"
-#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/metrics/histogram.h"
-#include "base/stl_util.h"
#include "base/stringprintf.h"
-#include "base/synchronization/waitable_event.h"
#include "base/time.h"
#include "base/values.h"
-#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/preconnect.h"
-#include "chrome/browser/prefs/browser_prefs.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/common/chrome_switches.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"
@@ -64,25 +53,6 @@ const TimeDelta Predictor::kDurationBetweenTrimmingIncrements =
TimeDelta::FromSeconds(15);
// static
const size_t Predictor::kUrlsTrimmedPerIncrement = 5u;
-// static
-const size_t Predictor::kMaxSpeculativeParallelResolves = 3;
-// To control our congestion avoidance system, which discards a queue when
-// resolutions are "taking too long," we need an expected resolution time.
-// Common average is in the range of 300-500ms.
-const int kExpectedResolutionTimeMs = 500;
-// static
-const int Predictor::kTypicalSpeculativeGroupSize = 8;
-// static
-const int Predictor::kMaxSpeculativeResolveQueueDelayMs =
- (kExpectedResolutionTimeMs * Predictor::kTypicalSpeculativeGroupSize) /
- Predictor::kMaxSpeculativeParallelResolves;
-
-static int g_max_queueing_delay_ms = 0;
-static size_t g_max_parallel_resolves = 0u;
-
-// 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:
@@ -129,88 +99,76 @@ class Predictor::LookupRequest {
DISALLOW_COPY_AND_ASSIGN(LookupRequest);
};
-Predictor::Predictor(bool preconnect_enabled)
- : initial_observer_(NULL),
- predictor_enabled_(true),
- peak_pending_lookups_(0),
+Predictor::Predictor(net::HostResolver* host_resolver,
+ TimeDelta max_dns_queue_delay,
+ size_t max_concurrent,
+ bool preconnect_enabled)
+ : peak_pending_lookups_(0),
shutdown_(false),
- max_concurrent_dns_lookups_(g_max_parallel_resolves),
- max_dns_queue_delay_(
- TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)),
- host_resolver_(NULL),
+ max_concurrent_dns_lookups_(max_concurrent),
+ max_dns_queue_delay_(max_dns_queue_delay),
+ host_resolver_(host_resolver),
preconnect_enabled_(preconnect_enabled),
consecutive_omnibox_preconnect_count_(0),
- next_trim_time_(base::TimeTicks::Now() + kDurationBetweenTrimmings) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ next_trim_time_(base::TimeTicks::Now() + kDurationBetweenTrimmings),
+ ALLOW_THIS_IN_INITIALIZER_LIST(trim_task_factory_(this)) {
}
Predictor::~Predictor() {
- // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the
- // ProfileManagerTest has been updated with a mock profile.
DCHECK(shutdown_);
}
-// static
-Predictor* Predictor::CreatePredictor(
- bool preconnect_enabled, bool simple_shutdown) {
- if (simple_shutdown)
- return new SimpleShutdownPredictor(preconnect_enabled);
- return new Predictor(preconnect_enabled);
-}
+void Predictor::Shutdown() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!shutdown_);
+ shutdown_ = true;
-void Predictor::RegisterUserPrefs(PrefService* user_prefs) {
- user_prefs->RegisterListPref(prefs::kDnsPrefetchingStartupList,
- PrefService::UNSYNCABLE_PREF);
- user_prefs->RegisterListPref(prefs::kDnsPrefetchingHostReferralList,
- PrefService::UNSYNCABLE_PREF);
+ std::set<LookupRequest*>::iterator it;
+ for (it = pending_lookups_.begin(); it != pending_lookups_.end(); ++it)
+ delete *it;
}
-// --------------------- Start UI methods. ------------------------------------
-
-void Predictor::InitNetworkPredictor(PrefService* user_prefs,
- PrefService* local_state,
- IOThread* io_thread) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- predictor_enabled_ = user_prefs->GetBoolean(prefs::kNetworkPredictionEnabled);
-
- // Gather the list of hostnames to prefetch on startup.
- UrlList urls = GetPredictedUrlListAtStartup(user_prefs, local_state);
-
- base::ListValue* referral_list =
- static_cast<base::ListValue*>(user_prefs->GetList(
- prefs::kDnsPrefetchingHostReferralList)->DeepCopy());
-
- // Remove obsolete preferences from local state if necessary.
- int current_version =
- local_state->GetInteger(prefs::kMultipleProfilePrefMigration);
- if ((current_version & browser::DNS_PREFS) == 0) {
- local_state->RegisterListPref(prefs::kDnsStartupPrefetchList,
- PrefService::UNSYNCABLE_PREF);
- local_state->RegisterListPref(prefs::kDnsHostReferralList,
- PrefService::UNSYNCABLE_PREF);
- local_state->ClearPref(prefs::kDnsStartupPrefetchList);
- local_state->ClearPref(prefs::kDnsHostReferralList);
- local_state->SetInteger(prefs::kMultipleProfilePrefMigration,
- current_version | browser::DNS_PREFS);
+// Overloaded Resolve() to take a vector of names.
+void Predictor::ResolveList(const UrlList& urls,
+ UrlInfo::ResolutionMotivation motivation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ for (UrlList::const_iterator it = urls.begin(); it < urls.end(); ++it) {
+ AppendToResolutionQueue(*it, motivation);
}
+}
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &Predictor::FinalizeInitializationOnIOThread,
- base::Unretained(this),
- urls, referral_list,
- io_thread));
+// Basic Resolve() takes an invidual name, and adds it
+// to the queue.
+void Predictor::Resolve(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!url.has_host())
+ return;
+ AppendToResolutionQueue(url, motivation);
+}
+
+void Predictor::LearnFromNavigation(const GURL& referring_url,
+ const GURL& target_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_EQ(referring_url, Predictor::CanonicalizeUrl(referring_url));
+ DCHECK_NE(referring_url, GURL::EmptyGURL());
+ DCHECK_EQ(target_url, Predictor::CanonicalizeUrl(target_url));
+ DCHECK_NE(target_url, GURL::EmptyGURL());
+
+ referrers_[referring_url].SuggestHost(target_url);
+ // Possibly do some referrer trimming.
+ TrimReferrers();
}
+enum SubresourceValue {
+ PRECONNECTION,
+ PRERESOLUTION,
+ TOO_NEW,
+ SUBRESOURCE_VALUE_MAX
+};
+
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;
@@ -274,16 +232,11 @@ void Predictor::AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- base::Bind(&Predictor::Resolve, base::Unretained(this),
- CanonicalizeUrl(url), motivation));
+ NewRunnableMethod(this, &Predictor::Resolve, CanonicalizeUrl(url),
+ motivation));
}
void Predictor::PreconnectUrlAndSubresources(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- 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);
@@ -294,186 +247,63 @@ void Predictor::PreconnectUrlAndSubresources(const GURL& url) {
}
}
-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) {
- base::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;
-}
-
-void Predictor::set_max_queueing_delay(int max_queueing_delay_ms) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- g_max_queueing_delay_ms = max_queueing_delay_ms;
-}
-
-void Predictor::set_max_parallel_resolves(size_t max_parallel_resolves) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- g_max_parallel_resolves = max_parallel_resolves;
-}
-
-void Predictor::ShutdownOnUIThread(PrefService* user_prefs) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- SaveStateForNextStartupAndTrim(user_prefs);
-
+void Predictor::PredictFrameSubresources(const GURL& url) {
+ DCHECK_EQ(url.GetWithEmptyPath(), url);
+ // Add one pass through the message loop to allow current navigation to
+ // proceed.
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- base::Bind(&Predictor::Shutdown, base::Unretained(this)));
-}
-
-// ---------------------- End UI methods. -------------------------------------
-
-// --------------------- Start IO methods. ------------------------------------
-
-void Predictor::Shutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!shutdown_);
- shutdown_ = true;
-
- STLDeleteElements(&pending_lookups_);
+ NewRunnableMethod(this, &Predictor::PrepareFrameSubresources, url));
}
-void Predictor::DiscardAllResults() {
+void Predictor::PrepareFrameSubresources(const GURL& url) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Delete anything listed so far in this session that shows in about:dns.
- referrers_.clear();
-
-
- // Try to delete anything in our work queue.
- while (!work_queue_.IsEmpty()) {
- // Emulate processing cycle as though host was not found.
- GURL url = work_queue_.Pop();
- UrlInfo* info = &results_[url];
- DCHECK(info->HasUrl(url));
- info->SetAssignedState();
- info->SetNoSuchNameState();
+ DCHECK_EQ(url.GetWithEmptyPath(), url);
+ Referrers::iterator it = referrers_.find(url);
+ if (referrers_.end() == it) {
+ // Only when we don't know anything about this url, make 2 connections
+ // available. We could do this completely via learning (by prepopulating
+ // the referrer_ list with this expected value), but it would swell the
+ // size of the list with all the "Leaf" nodes in the tree (nodes that don't
+ // load any subresources). If we learn about this resource, we will instead
+ // provide a more carefully estimated preconnection count.
+ if (preconnect_enabled_)
+ PreconnectOnIOThread(url, UrlInfo::SELF_REFERAL_MOTIVATED, 2);
+ return;
}
- // Now every result_ is either resolved, or is being resolved
- // (see LookupRequest).
- // Step through result_, recording names of all hosts that can't be erased.
- // We can't erase anything being worked on.
- Results assignees;
- for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
- GURL url(it->first);
- UrlInfo* info = &it->second;
- DCHECK(info->HasUrl(url));
- if (info->is_assigned()) {
- info->SetPendingDeleteState();
- assignees[url] = *info;
+ Referrer* referrer = &(it->second);
+ referrer->IncrementUseCount();
+ const UrlInfo::ResolutionMotivation motivation =
+ UrlInfo::LEARNED_REFERAL_MOTIVATED;
+ for (Referrer::iterator future_url = referrer->begin();
+ future_url != referrer->end(); ++future_url) {
+ SubresourceValue evalution(TOO_NEW);
+ double connection_expectation = future_url->second.subresource_use_rate();
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation",
+ static_cast<int>(connection_expectation * 100),
+ 10, 5000, 50);
+ future_url->second.ReferrerWasObserved();
+ if (preconnect_enabled_ &&
+ connection_expectation > kPreconnectWorthyExpectedValue) {
+ evalution = PRECONNECTION;
+ future_url->second.IncrementPreconnectionCount();
+ int count = static_cast<int>(std::ceil(connection_expectation));
+ if (url.host() == future_url->first.host())
+ ++count;
+ PreconnectOnIOThread(future_url->first, motivation, count);
+ } else if (connection_expectation > kDNSPreresolutionWorthyExpectedValue) {
+ evalution = PRERESOLUTION;
+ future_url->second.preresolution_increment();
+ UrlInfo* queued_info = AppendToResolutionQueue(future_url->first,
+ motivation);
+ if (queued_info)
+ queued_info->SetReferringHostname(url);
}
+ UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution,
+ SUBRESOURCE_VALUE_MAX);
}
- DCHECK_LE(assignees.size(), max_concurrent_dns_lookups_);
- results_.clear();
- // Put back in the names being worked on.
- for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
- DCHECK(it->second.is_marked_to_delete());
- results_[it->first] = it->second;
- }
-}
-
-// Overloaded Resolve() to take a vector of names.
-void Predictor::ResolveList(const UrlList& urls,
- UrlInfo::ResolutionMotivation motivation) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- for (UrlList::const_iterator it = urls.begin(); it < urls.end(); ++it) {
- AppendToResolutionQueue(*it, motivation);
- }
-}
-
-// Basic Resolve() takes an invidual name, and adds it
-// to the queue.
-void Predictor::Resolve(const GURL& url,
- UrlInfo::ResolutionMotivation motivation) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!url.has_host())
- return;
- AppendToResolutionQueue(url, motivation);
-}
-
-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));
- DCHECK_NE(target_url, GURL::EmptyGURL());
-
- referrers_[referring_url].SuggestHost(target_url);
- // Possibly do some referrer trimming.
- TrimReferrers();
-}
-
-//-----------------------------------------------------------------------------
-// This section supports the about:dns page.
-
-void Predictor::PredictorGetHtmlInfo(Predictor* predictor,
- std::string* output) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- output->append("<html><head><title>About DNS</title>"
- // We'd like the following no-cache... but it doesn't work.
- // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
- "</head><body>");
- if (predictor && predictor->predictor_enabled()) {
- predictor->GetHtmlInfo(output);
- } else {
- output->append("DNS pre-resolution and TCP pre-connection is disabled.");
- }
- output->append("</body></html>");
}
// Provide sort order so all .com's are together, etc.
@@ -588,11 +418,6 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
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;
@@ -628,306 +453,81 @@ void Predictor::GetHtmlInfo(std::string* output) {
"Preresolving DNS records revealed non-existence for ", brief, output);
}
-void Predictor::TrimReferrersNow() {
+UrlInfo* Predictor::AppendToResolutionQueue(
+ const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Just finish up work if an incremental trim is in progress.
- if (urls_being_trimmed_.empty())
- LoadUrlsForTrimming();
- IncrementalTrimReferrers(true); // Do everything now.
-}
+ DCHECK(url.has_host());
-void Predictor::SerializeReferrers(base::ListValue* referral_list) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- referral_list->Clear();
- referral_list->Append(new base::FundamentalValue(PREDICTOR_REFERRER_VERSION));
- for (Referrers::const_iterator it = referrers_.begin();
- it != referrers_.end(); ++it) {
- // Serialize the list of subresource names.
- Value* subresource_list(it->second.Serialize());
+ if (shutdown_)
+ return NULL;
- // Create a list for each referer.
- ListValue* motivator(new ListValue);
- motivator->Append(new StringValue(it->first.spec()));
- motivator->Append(subresource_list);
+ UrlInfo* info = &results_[url];
+ info->SetUrl(url); // Initialize or DCHECK.
+ // TODO(jar): I need to discard names that have long since expired.
+ // Currently we only add to the domain map :-/
- referral_list->Append(motivator);
+ DCHECK(info->HasUrl(url));
+
+ if (!info->NeedsDnsUpdate()) {
+ info->DLogResultsStats("DNS PrefetchNotUpdated");
+ return NULL;
}
+
+ info->SetQueuedState(motivation);
+ work_queue_.Push(url, motivation);
+ StartSomeQueuedResolutions();
+ return info;
}
-void Predictor::DeserializeReferrers(const base::ListValue& referral_list) {
+void Predictor::StartSomeQueuedResolutions() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- int format_version = -1;
- if (referral_list.GetSize() > 0 &&
- referral_list.GetInteger(0, &format_version) &&
- format_version == PREDICTOR_REFERRER_VERSION) {
- for (size_t i = 1; i < referral_list.GetSize(); ++i) {
- base::ListValue* motivator;
- if (!referral_list.GetList(i, &motivator)) {
- NOTREACHED();
- return;
- }
- std::string motivating_url_spec;
- if (!motivator->GetString(0, &motivating_url_spec)) {
- NOTREACHED();
- return;
- }
- Value* subresource_list;
- if (!motivator->Get(1, &subresource_list)) {
- NOTREACHED();
- return;
- }
+ while (!work_queue_.IsEmpty() &&
+ pending_lookups_.size() < max_concurrent_dns_lookups_) {
+ const GURL url(work_queue_.Pop());
+ UrlInfo* info = &results_[url];
+ DCHECK(info->HasUrl(url));
+ info->SetAssignedState();
- referrers_[GURL(motivating_url_spec)].Deserialize(*subresource_list);
+ if (CongestionControlPerformed(info)) {
+ DCHECK(work_queue_.IsEmpty());
+ return;
}
- }
-}
-
-void Predictor::DeserializeReferrersThenDelete(
- base::ListValue* referral_list) {
- DeserializeReferrers(*referral_list);
- delete referral_list;
-}
-
-void Predictor::DiscardInitialNavigationHistory() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (initial_observer_.get())
- initial_observer_->DiscardInitialNavigationHistory();
-}
-
-void Predictor::FinalizeInitializationOnIOThread(
- const UrlList& startup_urls,
- base::ListValue* referral_list,
- IOThread* io_thread) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- initial_observer_.reset(new InitialObserver());
- host_resolver_ = io_thread->globals()->host_resolver.get();
-
- // ScopedRunnableMethodFactory instances need to be created and destroyed
- // on the same thread. The predictor lives on the IO thread and will die
- // from there so now that we're on the IO thread we need to properly
- // initialize the ScopedrunnableMethodFactory.
- trim_task_factory_.reset(new ScopedRunnableMethodFactory<Predictor>(this));
-
- // 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,
- base::Bind(&Predictor::ResolveList, base::Unretained(this),
- urls, motivation));
- }
-}
-
-//-----------------------------------------------------------------------------
-// Functions to handle saving of hostnames from one session to the next, to
-// expedite startup times.
-
-static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
- base::ListValue* startup_list,
- base::ListValue* referral_list,
- base::WaitableEvent* completion,
- Predictor* predictor) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (NULL == predictor) {
- completion->Signal();
- return;
- }
- predictor->SaveDnsPrefetchStateForNextStartupAndTrim(
- startup_list, referral_list, completion);
-}
-
-void Predictor::SaveStateForNextStartupAndTrim(PrefService* prefs) {
- 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,
- this);
- } else {
- bool posted = BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread,
- update_startup_list.Get(),
- update_referral_list.Get(),
- &completion,
- this));
-
- // 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();
- }
-}
-
-void Predictor::SaveDnsPrefetchStateForNextStartupAndTrim(
- base::ListValue* startup_list,
- base::ListValue* referral_list,
- base::WaitableEvent* completion) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- 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::EnablePredictor(bool enable) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
- BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- EnablePredictorOnIOThread(enable);
- } else {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&Predictor::EnablePredictorOnIOThread,
- base::Unretained(this), enable));
- }
-}
-void Predictor::EnablePredictorOnIOThread(bool enable) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- predictor_enabled_ = enable;
-}
-
-void Predictor::PredictFrameSubresources(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
- BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!predictor_enabled_)
- return;
- DCHECK_EQ(url.GetWithEmptyPath(), url);
- // Add one pass through the message loop to allow current navigation to
- // proceed.
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- PrepareFrameSubresources(url);
- } else {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&Predictor::PrepareFrameSubresources,
- base::Unretained(this), url));
+ LookupRequest* request = new LookupRequest(this, host_resolver_, url);
+ int status = request->Start();
+ if (status == net::ERR_IO_PENDING) {
+ // Will complete asynchronously.
+ pending_lookups_.insert(request);
+ peak_pending_lookups_ = std::max(peak_pending_lookups_,
+ pending_lookups_.size());
+ } else {
+ // Completed synchronously (was already cached by HostResolver), or else
+ // there was (equivalently) some network error that prevents us from
+ // finding the name. Status net::OK means it was "found."
+ LookupFinished(request, url, status == net::OK);
+ delete request;
+ }
}
}
-enum SubresourceValue {
- PRECONNECTION,
- PRERESOLUTION,
- TOO_NEW,
- SUBRESOURCE_VALUE_MAX
-};
-
-void Predictor::PrepareFrameSubresources(const GURL& url) {
+bool Predictor::CongestionControlPerformed(UrlInfo* info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(url.GetWithEmptyPath(), url);
- Referrers::iterator it = referrers_.find(url);
- if (referrers_.end() == it) {
- // Only when we don't know anything about this url, make 2 connections
- // available. We could do this completely via learning (by prepopulating
- // the referrer_ list with this expected value), but it would swell the
- // size of the list with all the "Leaf" nodes in the tree (nodes that don't
- // load any subresources). If we learn about this resource, we will instead
- // provide a more carefully estimated preconnection count.
- if (preconnect_enabled_)
- PreconnectOnIOThread(url, UrlInfo::SELF_REFERAL_MOTIVATED, 2);
- return;
- }
-
- Referrer* referrer = &(it->second);
- referrer->IncrementUseCount();
- const UrlInfo::ResolutionMotivation motivation =
- UrlInfo::LEARNED_REFERAL_MOTIVATED;
- for (Referrer::iterator future_url = referrer->begin();
- future_url != referrer->end(); ++future_url) {
- SubresourceValue evalution(TOO_NEW);
- double connection_expectation = future_url->second.subresource_use_rate();
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation",
- static_cast<int>(connection_expectation * 100),
- 10, 5000, 50);
- future_url->second.ReferrerWasObserved();
- if (preconnect_enabled_ &&
- connection_expectation > kPreconnectWorthyExpectedValue) {
- evalution = PRECONNECTION;
- future_url->second.IncrementPreconnectionCount();
- int count = static_cast<int>(std::ceil(connection_expectation));
- if (url.host() == future_url->first.host())
- ++count;
- PreconnectOnIOThread(future_url->first, motivation, count);
- } else if (connection_expectation > kDNSPreresolutionWorthyExpectedValue) {
- evalution = PRERESOLUTION;
- future_url->second.preresolution_increment();
- UrlInfo* queued_info = AppendToResolutionQueue(future_url->first,
- motivation);
- if (queued_info)
- queued_info->SetReferringHostname(url);
- }
- UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution,
- SUBRESOURCE_VALUE_MAX);
+ // Note: queue_duration is ONLY valid after we go to assigned state.
+ if (info->queue_duration() < max_dns_queue_delay_)
+ return false;
+ // We need to discard all entries in our queue, as we're keeping them waiting
+ // too long. By doing this, we'll have a chance to quickly service urgent
+ // resolutions, and not have a bogged down system.
+ while (true) {
+ info->RemoveFromQueue();
+ if (work_queue_.IsEmpty())
+ break;
+ info = &results_[work_queue_.Pop()];
+ info->SetAssignedState();
}
+ return true;
}
void Predictor::OnLookupFinished(LookupRequest* request, const GURL& url,
@@ -956,79 +556,96 @@ void Predictor::LookupFinished(LookupRequest* request, const GURL& url,
}
}
-UrlInfo* Predictor::AppendToResolutionQueue(
- const GURL& url,
- UrlInfo::ResolutionMotivation motivation) {
+void Predictor::DiscardAllResults() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(url.has_host());
-
- if (shutdown_)
- return NULL;
+ // Delete anything listed so far in this session that shows in about:dns.
+ referrers_.clear();
- UrlInfo* info = &results_[url];
- info->SetUrl(url); // Initialize or DCHECK.
- // TODO(jar): I need to discard names that have long since expired.
- // Currently we only add to the domain map :-/
- DCHECK(info->HasUrl(url));
+ // Try to delete anything in our work queue.
+ while (!work_queue_.IsEmpty()) {
+ // Emulate processing cycle as though host was not found.
+ GURL url = work_queue_.Pop();
+ UrlInfo* info = &results_[url];
+ DCHECK(info->HasUrl(url));
+ info->SetAssignedState();
+ info->SetNoSuchNameState();
+ }
+ // Now every result_ is either resolved, or is being resolved
+ // (see LookupRequest).
- if (!info->NeedsDnsUpdate()) {
- info->DLogResultsStats("DNS PrefetchNotUpdated");
- return NULL;
+ // Step through result_, recording names of all hosts that can't be erased.
+ // We can't erase anything being worked on.
+ Results assignees;
+ for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
+ GURL url(it->first);
+ UrlInfo* info = &it->second;
+ DCHECK(info->HasUrl(url));
+ if (info->is_assigned()) {
+ info->SetPendingDeleteState();
+ assignees[url] = *info;
+ }
+ }
+ DCHECK(assignees.size() <= max_concurrent_dns_lookups_);
+ results_.clear();
+ // Put back in the names being worked on.
+ for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
+ DCHECK(it->second.is_marked_to_delete());
+ results_[it->first] = it->second;
}
+}
- info->SetQueuedState(motivation);
- work_queue_.Push(url, motivation);
- StartSomeQueuedResolutions();
- return info;
+void Predictor::TrimReferrersNow() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Just finish up work if an incremental trim is in progress.
+ if (urls_being_trimmed_.empty())
+ LoadUrlsForTrimming();
+ IncrementalTrimReferrers(true); // Do everything now.
}
-bool Predictor::CongestionControlPerformed(UrlInfo* info) {
+void Predictor::SerializeReferrers(ListValue* referral_list) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Note: queue_duration is ONLY valid after we go to assigned state.
- if (info->queue_duration() < max_dns_queue_delay_)
- return false;
- // We need to discard all entries in our queue, as we're keeping them waiting
- // too long. By doing this, we'll have a chance to quickly service urgent
- // resolutions, and not have a bogged down system.
- while (true) {
- info->RemoveFromQueue();
- if (work_queue_.IsEmpty())
- break;
- info = &results_[work_queue_.Pop()];
- info->SetAssignedState();
+ referral_list->Clear();
+ referral_list->Append(new base::FundamentalValue(PREDICTOR_REFERRER_VERSION));
+ for (Referrers::const_iterator it = referrers_.begin();
+ it != referrers_.end(); ++it) {
+ // Serialize the list of subresource names.
+ Value* subresource_list(it->second.Serialize());
+
+ // Create a list for each referer.
+ ListValue* motivator(new ListValue);
+ motivator->Append(new StringValue(it->first.spec()));
+ motivator->Append(subresource_list);
+
+ referral_list->Append(motivator);
}
- return true;
}
-void Predictor::StartSomeQueuedResolutions() {
+void Predictor::DeserializeReferrers(const ListValue& referral_list) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ int format_version = -1;
+ if (referral_list.GetSize() > 0 &&
+ referral_list.GetInteger(0, &format_version) &&
+ format_version == PREDICTOR_REFERRER_VERSION) {
+ for (size_t i = 1; i < referral_list.GetSize(); ++i) {
+ ListValue* motivator;
+ if (!referral_list.GetList(i, &motivator)) {
+ NOTREACHED();
+ return;
+ }
+ std::string motivating_url_spec;
+ if (!motivator->GetString(0, &motivating_url_spec)) {
+ NOTREACHED();
+ return;
+ }
- while (!work_queue_.IsEmpty() &&
- pending_lookups_.size() < max_concurrent_dns_lookups_) {
- const GURL url(work_queue_.Pop());
- UrlInfo* info = &results_[url];
- DCHECK(info->HasUrl(url));
- info->SetAssignedState();
-
- if (CongestionControlPerformed(info)) {
- DCHECK(work_queue_.IsEmpty());
- return;
- }
+ Value* subresource_list;
+ if (!motivator->Get(1, &subresource_list)) {
+ NOTREACHED();
+ return;
+ }
- LookupRequest* request = new LookupRequest(this, host_resolver_, url);
- int status = request->Start();
- if (status == net::ERR_IO_PENDING) {
- // Will complete asynchronously.
- pending_lookups_.insert(request);
- peak_pending_lookups_ = std::max(peak_pending_lookups_,
- pending_lookups_.size());
- } else {
- // Completed synchronously (was already cached by HostResolver), or else
- // there was (equivalently) some network error that prevents us from
- // finding the name. Status net::OK means it was "found."
- LookupFinished(request, url, status == net::OK);
- delete request;
+ referrers_[GURL(motivating_url_spec)].Deserialize(*subresource_list);
}
}
}
@@ -1061,8 +678,8 @@ void Predictor::PostIncrementalTrimTask() {
return;
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
- trim_task_factory_->NewRunnableMethod(
- &Predictor::IncrementalTrimReferrers, false),
+ trim_task_factory_.NewRunnableMethod(&Predictor::IncrementalTrimReferrers,
+ false),
kDurationBetweenTrimmingIncrements.InMilliseconds());
}
@@ -1081,9 +698,7 @@ void Predictor::IncrementalTrimReferrers(bool trim_all_now) {
PostIncrementalTrimTask();
}
-// ---------------------- End IO methods. -------------------------------------
-
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
Predictor::HostNameQueue::HostNameQueue() {
}
@@ -1119,69 +734,15 @@ GURL Predictor::HostNameQueue::Pop() {
return url;
}
-//-----------------------------------------------------------------------------
-// Member definitions for InitialObserver class.
-
-Predictor::InitialObserver::InitialObserver() {
+void Predictor::DeserializeReferrersThenDelete(ListValue* referral_list) {
+ DeserializeReferrers(*referral_list);
+ delete referral_list;
}
-Predictor::InitialObserver::~InitialObserver() {
-}
-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 (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(
- base::ListValue* startup_list) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(startup_list);
- startup_list->Clear();
- DCHECK_EQ(0u, startup_list->GetSize());
- startup_list->Append(
- new base::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
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
// static
GURL Predictor::CanonicalizeUrl(const GURL& url) {
@@ -1207,8 +768,5 @@ GURL Predictor::CanonicalizeUrl(const GURL& url) {
return GURL(scheme + "://" + url.host() + colon_plus_port);
}
-void SimpleShutdownPredictor::ShutdownOnUIThread(PrefService* user_prefs) {
- SetShutdown(true);
-}
} // namespace chrome_browser_net
« no previous file with comments | « chrome/browser/net/predictor.h ('k') | chrome/browser/net/predictor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698