summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-14 17:53:01 +0000
committertburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-14 17:53:01 +0000
commitdb6c4ea2099370eed9c4f910b847d5bf9df50691 (patch)
treeca444b2bd7e370b5432be4347ad246f0a533d85e
parent129781364dbc2e34b2cd191de368900558a61cc8 (diff)
downloadchromium_src-db6c4ea2099370eed9c4f910b847d5bf9df50691.zip
chromium_src-db6c4ea2099370eed9c4f910b847d5bf9df50691.tar.gz
chromium_src-db6c4ea2099370eed9c4f910b847d5bf9df50691.tar.bz2
Allow multiple local predictor prerenders and make parameters more configurable via Finch trials.
Duplicate of https://codereview.chromium.org/16969003, bug fixed. TBR=gavinp@chromium.org Review URL: https://codereview.chromium.org/17060007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@206437 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/prerender/prerender_contents.cc6
-rw-r--r--chrome/browser/prerender/prerender_field_trial.cc122
-rw-r--r--chrome/browser/prerender/prerender_field_trial.h19
-rw-r--r--chrome/browser/prerender/prerender_handle.cc6
-rw-r--r--chrome/browser/prerender/prerender_handle.h4
-rw-r--r--chrome/browser/prerender/prerender_local_predictor.cc173
-rw-r--r--chrome/browser/prerender/prerender_local_predictor.h22
-rw-r--r--chrome/browser/prerender/prerender_manager.cc2
8 files changed, 250 insertions, 104 deletions
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index ed97704..de1ec58 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/favicon/favicon_tab_helper.h"
#include "chrome/browser/history/history_tab_helper.h"
#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/prerender/prerender_final_status.h"
#include "chrome/browser/prerender/prerender_handle.h"
#include "chrome/browser/prerender/prerender_manager.h"
@@ -267,6 +268,11 @@ void PrerenderContents::StartPrerendering(
if (prerender_manager_->IsControlGroup(experiment_id()))
return;
+ if (origin_ == ORIGIN_LOCAL_PREDICTOR &&
+ IsLocalPredictorPrerenderAlwaysControlEnabled()) {
+ return;
+ }
+
prerendering_has_started_ = true;
prerender_contents_.reset(CreateWebContents(session_storage_namespace));
diff --git a/chrome/browser/prerender/prerender_field_trial.cc b/chrome/browser/prerender/prerender_field_trial.cc
index ea65d49..ca12522 100644
--- a/chrome/browser/prerender/prerender_field_trial.cc
+++ b/chrome/browser/prerender/prerender_field_trial.cc
@@ -9,6 +9,7 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/predictors/autocomplete_action_predictor.h"
#include "chrome/browser/prerender/prerender_manager.h"
@@ -26,17 +27,22 @@ namespace {
const char kOmniboxTrialName[] = "PrerenderFromOmnibox";
int g_omnibox_trial_default_group_number = kint32min;
-const char kLocalPredictorTrialName[] = "PrerenderLocalPredictor";
-const char kLocalPredictorEnabledGroup[] = "Enabled";
-const char kLocalPredictorDisabledGroup[] = "Disabled";
-
-const char kLoggedInPredictorTrialName[] = "PrerenderLoggedInPredictor";
-const char kLoggedInPredictorEnabledGroup[] = "Enabled";
-const char kLoggedInPredictorDisabledGroup[] = "Disabled";
+const char kDisabledGroup[] = "Disabled";
+const char kEnabledGroup[] = "Enabled";
-const char kSideEffectFreeWhitelistTrialName[] = "SideEffectFreeWhitelist";
-const char kSideEffectFreeWhitelistEnabledGroup[] = "Enabled";
-const char kSideEffectFreeWhitelistDisabledGroup[] = "Disabled";
+const char kLocalPredictorTrialName[] = "PrerenderLocalPredictor";
+const char kSideEffectFreeWhitelistTrialName[] =
+ "PrerenderSideEffectFreeWhitelist";
+const char kLocalPredictorPrerenderLaunchTrialName[] =
+ "PrerenderLocalPredictorPrerenderLanch";
+const char kLocalPredictorPrerenderAlwaysControlTrialName[] =
+ "PrerenderLocalPredictorPrerenderAlwaysControl";
+const char kLocalPredictorPrerenderTTLTrialName[] =
+ "PrerenderLocalPredictorPrerenderTTLSeconds";
+const char kLocalPredictorPrerenderPriorityHalfLifeTimeTrialName[] =
+ "PrerenderLocalPredictorPrerenderPriorityHalfLifeTimeSeconds";
+const char kLocalPredictorMaxConcurrentPrerenderTrialName[] =
+ "PrerenderLocalPredictorMaxConcurrentPrerenders";
void SetupPrefetchFieldTrial() {
chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
@@ -151,8 +157,6 @@ void SetupPrerenderFieldTrial() {
void ConfigureOmniboxPrerender();
void ConfigureLocalPredictor();
-void ConfigureLoggedInPredictor();
-void ConfigureSideEffectFreeWhitelist();
void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
enum PrerenderOption {
@@ -210,8 +214,6 @@ void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
ConfigureOmniboxPrerender();
ConfigureLocalPredictor();
- ConfigureLoggedInPredictor();
- ConfigureSideEffectFreeWhitelist();
}
void ConfigureOmniboxPrerender() {
@@ -240,36 +242,8 @@ void ConfigureLocalPredictor() {
}
scoped_refptr<FieldTrial> local_predictor_trial(
FieldTrialList::FactoryGetFieldTrial(
- kLocalPredictorTrialName, 100,
- kLocalPredictorDisabledGroup, 2013, 12, 31, NULL));
- local_predictor_trial->AppendGroup(kLocalPredictorEnabledGroup, 100);
-}
-
-void ConfigureLoggedInPredictor() {
- chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
- if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
- channel == chrome::VersionInfo::CHANNEL_BETA) {
- return;
- }
- scoped_refptr<FieldTrial> logged_in_predictor_trial(
- FieldTrialList::FactoryGetFieldTrial(
- kLoggedInPredictorTrialName, 100,
- kLoggedInPredictorDisabledGroup, 2013, 12, 31, NULL));
- logged_in_predictor_trial->AppendGroup(kLoggedInPredictorEnabledGroup, 100);
-}
-
-void ConfigureSideEffectFreeWhitelist() {
- scoped_refptr<FieldTrial> side_effect_free_whitelist_trial(
- FieldTrialList::FactoryGetFieldTrial(
- kSideEffectFreeWhitelistTrialName, 100,
- kSideEffectFreeWhitelistDisabledGroup, 2013, 12, 31, NULL));
- chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
- if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
- channel == chrome::VersionInfo::CHANNEL_BETA) {
- return;
- }
- side_effect_free_whitelist_trial->AppendGroup(
- kSideEffectFreeWhitelistEnabledGroup, 100);
+ kLocalPredictorTrialName, 100, kDisabledGroup, 2013, 12, 31, NULL));
+ local_predictor_trial->AppendGroup(kEnabledGroup, 100);
}
bool IsOmniboxEnabled(Profile* profile) {
@@ -309,17 +283,67 @@ bool IsLocalPredictorEnabled() {
return false;
}
return base::FieldTrialList::FindFullName(kLocalPredictorTrialName) ==
- kLocalPredictorEnabledGroup;
+ kEnabledGroup;
}
bool IsLoggedInPredictorEnabled() {
- return base::FieldTrialList::FindFullName(kLoggedInPredictorTrialName) ==
- kLoggedInPredictorEnabledGroup;
+ return IsLocalPredictorEnabled();
}
bool IsSideEffectFreeWhitelistEnabled() {
- return base::FieldTrialList::FindFullName(kSideEffectFreeWhitelistTrialName)
- == kSideEffectFreeWhitelistEnabledGroup;
+ return IsLocalPredictorEnabled() &&
+ base::FieldTrialList::FindFullName(kSideEffectFreeWhitelistTrialName) !=
+ kDisabledGroup;
+}
+
+bool IsLocalPredictorPrerenderLaunchEnabled() {
+ return base::FieldTrialList::FindFullName(
+ kLocalPredictorPrerenderLaunchTrialName) !=
+ kDisabledGroup;
}
+bool IsLocalPredictorPrerenderAlwaysControlEnabled() {
+ return base::FieldTrialList::FindFullName(
+ kLocalPredictorPrerenderAlwaysControlTrialName) ==
+ kEnabledGroup;
+}
+
+int GetLocalPredictorTTLSeconds() {
+ int ttl;
+ base::StringToInt(
+ base::FieldTrialList::FindFullName(kLocalPredictorPrerenderTTLTrialName),
+ &ttl);
+ // If the value is outside of 10s or 600s, use a default value of 180s.
+ if (ttl < 10 || ttl > 600)
+ ttl = 180;
+ return ttl;
+}
+
+int GetLocalPredictorPrerenderPriorityHalfLifeTimeSeconds() {
+ int half_life_time;
+ base::StringToInt(
+ base::FieldTrialList::FindFullName(
+ kLocalPredictorPrerenderPriorityHalfLifeTimeTrialName),
+ &half_life_time);
+ // Sanity check: Ensure the half life time is non-negative.
+ if (half_life_time < 0)
+ half_life_time = 0;
+ return half_life_time;
+}
+
+int GetLocalPredictorMaxConcurrentPrerenders() {
+ int num_prerenders;
+ base::StringToInt(
+ base::FieldTrialList::FindFullName(
+ kLocalPredictorMaxConcurrentPrerenderTrialName),
+ &num_prerenders);
+ // Sanity check: Ensure the number of prerenders is at least 1.
+ if (num_prerenders < 1)
+ num_prerenders = 1;
+ // Sanity check: Ensure the number of prerenders is at most 10.
+ if (num_prerenders > 10)
+ num_prerenders = 10;
+ return num_prerenders;
+};
+
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_field_trial.h b/chrome/browser/prerender/prerender_field_trial.h
index 5e80a01..e8ef3aa 100644
--- a/chrome/browser/prerender/prerender_field_trial.h
+++ b/chrome/browser/prerender/prerender_field_trial.h
@@ -30,6 +30,25 @@ bool IsLoggedInPredictorEnabled();
// Returns true iff the side-effect free whitelist is enabled.
bool IsSideEffectFreeWhitelistEnabled();
+// Returns true if the local predictor should actually launch prerenders.
+bool IsLocalPredictorPrerenderLaunchEnabled();
+
+// Returns true if the local predictor should prerender, but only as control
+// group. If the local predictor never launches prerenders, then this setting
+// is irrelevant.
+bool IsLocalPredictorPrerenderAlwaysControlEnabled();
+
+// Returns the TTL to be used for the local predictor.
+int GetLocalPredictorTTLSeconds();
+
+// Returns the half-life time to use to decay local predictor prerender
+// priorities.
+int GetLocalPredictorPrerenderPriorityHalfLifeTimeSeconds();
+
+// Returns the maximum number of concurrent prerenders the local predictor
+// may maintain.
+int GetLocalPredictorMaxConcurrentPrerenders();
+
} // namespace prerender
#endif // CHROME_BROWSER_PRERENDER_PRERENDER_FIELD_TRIAL_H_
diff --git a/chrome/browser/prerender/prerender_handle.cc b/chrome/browser/prerender/prerender_handle.cc
index 1b50ecb..dc4f651 100644
--- a/chrome/browser/prerender/prerender_handle.cc
+++ b/chrome/browser/prerender/prerender_handle.cc
@@ -129,4 +129,10 @@ void PrerenderHandle::OnPrerenderCreatedMatchCompleteReplacement(
replacement->AddObserver(this);
}
+bool PrerenderHandle::RepresentingSamePrerenderAs(
+ PrerenderHandle* other) const {
+ return other && other->prerender_data_.get() && prerender_data_.get()
+ && prerender_data_.get() == other->prerender_data_.get();
+}
+
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_handle.h b/chrome/browser/prerender/prerender_handle.h
index 3e2e946..0a2fae6 100644
--- a/chrome/browser/prerender/prerender_handle.h
+++ b/chrome/browser/prerender/prerender_handle.h
@@ -74,6 +74,10 @@ class PrerenderHandle : public base::NonThreadSafe,
const GURL& url,
const content::SessionStorageNamespace* session_storage_namespace) const;
+ // Returns whether this PrerenderHandle represents the same prerender as
+ // the other PrerenderHandle object specified.
+ bool RepresentingSamePrerenderAs(PrerenderHandle* other) const;
+
private:
friend class PrerenderManager;
diff --git a/chrome/browser/prerender/prerender_local_predictor.cc b/chrome/browser/prerender/prerender_local_predictor.cc
index 2284237..34f1500 100644
--- a/chrome/browser/prerender/prerender_local_predictor.cc
+++ b/chrome/browser/prerender/prerender_local_predictor.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/history/history_db_task.h"
#include "chrome/browser/history/history_service.h"
#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/prerender/prerender_handle.h"
#include "chrome/browser/prerender/prerender_histograms.h"
#include "chrome/browser/prerender/prerender_manager.h"
@@ -179,9 +180,12 @@ const int kMaxVisitHistory = 100 * 1000;
const int kVisitHistoryPruneThreshold = 120 * 1000;
const int kVisitHistoryPruneAmount = 20 * 1000;
-const int kMaxLocalPredictionTimeMs = 180 * 1000;
const int kMinLocalPredictionTimeMs = 500;
+int GetMaxLocalPredictionTimeMs() {
+ return GetLocalPredictorTTLSeconds() * 1000;
+}
+
bool IsBackForward(PageTransition transition) {
return (transition & content::PAGE_TRANSITION_FORWARD_BACK) != 0;
}
@@ -288,6 +292,27 @@ struct PrerenderLocalPredictor::PrerenderProperties {
start_time(start_time) {
}
+ // Default constructor for dummy element
+ PrerenderProperties()
+ : priority(0.0) {
+ }
+
+ double GetCurrentDecayedPriority() {
+ // If we are no longer prerendering, the priority is 0.
+ if (!prerender_handle || !prerender_handle->IsPrerendering())
+ return 0.0;
+ int half_life_time_seconds =
+ GetLocalPredictorPrerenderPriorityHalfLifeTimeSeconds();
+ if (half_life_time_seconds < 1)
+ return priority;
+ double multiple_elapsed =
+ (GetCurrentTime() - actual_start_time).InMillisecondsF() /
+ base::TimeDelta::FromSeconds(half_life_time_seconds).InMillisecondsF();
+ // Decay factor: 2 ^ (-multiple_elapsed)
+ double decay_factor = exp(- multiple_elapsed * log(2.0));
+ return priority * decay_factor;
+ }
+
URLID url_id;
GURL url;
double priority;
@@ -300,17 +325,17 @@ struct PrerenderLocalPredictor::PrerenderProperties {
base::Time start_time;
// The actual time this page was last requested for prerendering.
base::Time actual_start_time;
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(PrerenderProperties);
+ scoped_ptr<PrerenderHandle> prerender_handle;
+ // Indicates whether this prerender would have matched a URL navigated to,
+ // but was not swapped in for some reason.
+ bool would_have_matched;
};
PrerenderLocalPredictor::PrerenderLocalPredictor(
PrerenderManager* prerender_manager)
: prerender_manager_(prerender_manager),
is_visit_database_observer_(false),
- weak_factory_(this),
- current_prerender_would_have_matched_(false) {
+ weak_factory_(this) {
RecordEvent(EVENT_CONSTRUCTED);
if (base::MessageLoop::current()) {
timer_.Start(FROM_HERE,
@@ -350,8 +375,12 @@ PrerenderLocalPredictor::PrerenderLocalPredictor(
PrerenderLocalPredictor::~PrerenderLocalPredictor() {
Shutdown();
- if (prerender_handle_.get())
- prerender_handle_->OnCancel();
+ for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
+ PrerenderProperties* p = issued_prerenders_[i];
+ DCHECK(p != NULL);
+ if (p->prerender_handle)
+ p->prerender_handle->OnCancel();
+ }
}
void PrerenderLocalPredictor::Shutdown() {
@@ -382,7 +411,7 @@ void PrerenderLocalPredictor::OnAddVisit(const history::BriefVisitInfo& info) {
"Prerender.LocalPredictorTimeUntilUsed",
GetCurrentTime() - current_prerender_->actual_start_time,
base::TimeDelta::FromMilliseconds(10),
- base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs),
+ base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs()),
50);
last_swapped_in_prerender_.reset(current_prerender_.release());
RecordEvent(EVENT_ADD_VISIT_PRERENDER_IDENTIFIED);
@@ -391,7 +420,7 @@ void PrerenderLocalPredictor::OnAddVisit(const history::BriefVisitInfo& info) {
return;
RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION);
base::TimeDelta max_age =
- base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs);
+ base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs());
base::TimeDelta min_age =
base::TimeDelta::FromMilliseconds(kMinLocalPredictionTimeMs);
std::set<URLID> next_urls_currently_found;
@@ -629,7 +658,7 @@ bool PrerenderLocalPredictor::IsPrerenderStillValid(
PrerenderLocalPredictor::PrerenderProperties* prerender) const {
return (prerender &&
(prerender->start_time +
- base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs))
+ base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs()))
> GetCurrentTime());
}
@@ -652,11 +681,27 @@ bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord(
}
}
-bool PrerenderLocalPredictor::ShouldReplaceCurrentPrerender(
- double priority) const {
- return (!prerender_handle_.get() ||
- !prerender_handle_->IsPrerendering() ||
- current_prerender_priority_ < priority);
+PrerenderLocalPredictor::PrerenderProperties*
+PrerenderLocalPredictor::GetIssuedPrerenderSlotForPriority(double priority) {
+ int num_prerenders = GetLocalPredictorMaxConcurrentPrerenders();
+ while (static_cast<int>(issued_prerenders_.size()) < num_prerenders)
+ issued_prerenders_.push_back(new PrerenderProperties());
+ PrerenderProperties* lowest_priority_prerender = NULL;
+ for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
+ PrerenderProperties* p = issued_prerenders_[i];
+ DCHECK(p != NULL);
+ if (!p->prerender_handle || !p->prerender_handle->IsPrerendering())
+ return p;
+ double decayed_priority = p->GetCurrentDecayedPriority();
+ if (decayed_priority > priority)
+ continue;
+ if (lowest_priority_prerender == NULL ||
+ lowest_priority_prerender->GetCurrentDecayedPriority() >
+ decayed_priority) {
+ lowest_priority_prerender = p;
+ }
+ }
+ return lowest_priority_prerender;
}
void PrerenderLocalPredictor::ContinuePrerenderCheck(
@@ -667,6 +712,7 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
scoped_ptr<LocalPredictorURLInfo> url_info;
scoped_refptr<SafeBrowsingDatabaseManager> sb_db_manager =
g_browser_process->safe_browsing_service()->database_manager();
+ PrerenderProperties* prerender_properties = NULL;
for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i]));
@@ -684,7 +730,9 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
url_info.reset(NULL);
continue;
}
- if (!ShouldReplaceCurrentPrerender(url_info->priority)) {
+ prerender_properties =
+ GetIssuedPrerenderSlotForPriority(url_info->priority);
+ if (!prerender_properties) {
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW);
url_info.reset(NULL);
continue;
@@ -732,28 +780,58 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
if (!url_info.get())
return;
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER);
- IssuePrerender(session_storage_namespace, size.Pass(),
- url_info.Pass());
+ DCHECK(prerender_properties != NULL);
+ if (IsLocalPredictorPrerenderLaunchEnabled()) {
+ IssuePrerender(session_storage_namespace, size.Pass(),
+ url_info.Pass(), prerender_properties);
+ }
}
void PrerenderLocalPredictor::IssuePrerender(
scoped_refptr<SessionStorageNamespace> session_storage_namespace,
scoped_ptr<gfx::Size> size,
- scoped_ptr<LocalPredictorURLInfo> info) {
+ scoped_ptr<LocalPredictorURLInfo> info,
+ PrerenderProperties* prerender_properties) {
URLID url_id = info->id;
const GURL& url = info->url;
double priority = info->priority;
base::Time current_time = GetCurrentTime();
RecordEvent(EVENT_ISSUING_PRERENDER);
- current_prerender_priority_ = priority;
- scoped_ptr<prerender::PrerenderHandle> old_prerender_handle(
- prerender_handle_.release());
- prerender_handle_.reset(prerender_manager_->AddPrerenderFromLocalPredictor(
- url, session_storage_namespace.get(), *size));
- current_prerender_would_have_matched_ = false;
- if (old_prerender_handle)
- old_prerender_handle->OnCancel();
+ // Issue the prerender and obtain a new handle.
+ scoped_ptr<prerender::PrerenderHandle> new_prerender_handle(
+ prerender_manager_->AddPrerenderFromLocalPredictor(
+ url, session_storage_namespace.get(), *size));
+
+ // Check if this is a duplicate of an existing prerender. If yes, clean up
+ // the new handle.
+ for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
+ PrerenderProperties* p = issued_prerenders_[i];
+ DCHECK(p != NULL);
+ if (new_prerender_handle &&
+ new_prerender_handle->RepresentingSamePrerenderAs(
+ p->prerender_handle.get())) {
+ new_prerender_handle->OnCancel();
+ new_prerender_handle.reset(NULL);
+ break;
+ }
+ }
+
+ if (new_prerender_handle.get()) {
+ // The new prerender does not match any existing prerenders. Update
+ // prerender_properties so that it reflects the new entry.
+ prerender_properties->url_id = url_id;
+ prerender_properties->url = url;
+ prerender_properties->priority = priority;
+ prerender_properties->start_time = current_time;
+ prerender_properties->actual_start_time = current_time;
+ prerender_properties->would_have_matched = false;
+ prerender_properties->prerender_handle.swap(new_prerender_handle);
+ // new_prerender_handle now represents the old previou prerender that we
+ // are replacing. So we need to cancel it.
+ if (new_prerender_handle)
+ new_prerender_handle->OnCancel();
+ }
RecordEvent(EVENT_ADD_VISIT_PRERENDERING);
if (current_prerender_.get() && current_prerender_->url_id == url_id) {
@@ -781,24 +859,39 @@ void PrerenderLocalPredictor::IssuePrerender(
void PrerenderLocalPredictor::OnTabHelperURLSeen(
const GURL& url, WebContents* web_contents) {
RecordEvent(EVENT_TAB_HELPER_URL_SEEN);
- if (current_prerender_would_have_matched_ ||
- !prerender_handle_.get() ||
- !prerender_handle_->Matches(url, NULL)) {
- return;
- }
- RecordEvent(EVENT_TAB_HELPER_URL_SEEN_MATCH);
- if (prerender_handle_->Matches(
- url,
- web_contents->GetController().GetDefaultSessionStorageNamespace())) {
- RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH);
- }
+
// If the namespace matches and the URL matches, we might be able to swap
// in. However, the actual code initating the swapin is in the renderer
// and is checking for other criteria (such as POSTs). There may
// also be conditions when a swapin should happen but does not. By recording
// the two previous events, we can keep an eye on the magnitude of the
// discrepancy.
- current_prerender_would_have_matched_ = true;
+
+ PrerenderProperties* best_matched_prerender = NULL;
+ bool session_storage_namespace_matches = false;
+ for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
+ PrerenderProperties* p = issued_prerenders_[i];
+ DCHECK(p != NULL);
+ if (!p->prerender_handle.get() ||
+ !p->prerender_handle->Matches(url, NULL) ||
+ p->would_have_matched) {
+ continue;
+ }
+ if (!best_matched_prerender || !session_storage_namespace_matches) {
+ best_matched_prerender = p;
+ session_storage_namespace_matches =
+ p->prerender_handle->Matches(
+ url,
+ web_contents->GetController().
+ GetDefaultSessionStorageNamespace());
+ }
+ }
+ if (best_matched_prerender) {
+ RecordEvent(EVENT_TAB_HELPER_URL_SEEN_MATCH);
+ best_matched_prerender->would_have_matched = true;
+ if (session_storage_namespace_matches)
+ RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH);
+ }
}
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_local_predictor.h b/chrome/browser/prerender/prerender_local_predictor.h
index b4098bb..590eeb8 100644
--- a/chrome/browser/prerender/prerender_local_predictor.h
+++ b/chrome/browser/prerender/prerender_local_predictor.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/containers/hash_tables.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/timer.h"
#include "chrome/browser/common/cancelable_request.h"
@@ -123,10 +124,10 @@ class PrerenderLocalPredictor : public history::VisitDatabaseObserver {
void OnLookupURL(scoped_ptr<LocalPredictorURLLookupInfo> info);
- // Returns whether a new prerender of the specified priority should replace
- // the current prerender (based on whether it exists, whether it has expired,
- // and based on what its priority is).
- bool ShouldReplaceCurrentPrerender(double priority) const;
+ // Returns an element of issued_prerenders_, which should be replaced
+ // by a new prerender of the priority indicated, or NULL, if the priority
+ // is too low.
+ PrerenderProperties* GetIssuedPrerenderSlotForPriority(double priority);
void ContinuePrerenderCheck(
scoped_refptr<content::SessionStorageNamespace> session_storage_namespace,
@@ -136,8 +137,8 @@ class PrerenderLocalPredictor : public history::VisitDatabaseObserver {
void IssuePrerender(scoped_refptr<content::SessionStorageNamespace>
session_storage_namespace,
scoped_ptr<gfx::Size> size,
- scoped_ptr<LocalPredictorURLInfo> info);
-
+ scoped_ptr<LocalPredictorURLInfo> info,
+ PrerenderProperties* prerender_properties);
PrerenderManager* prerender_manager_;
base::OneShotTimer<PrerenderLocalPredictor> timer_;
@@ -156,19 +157,12 @@ class PrerenderLocalPredictor : public history::VisitDatabaseObserver {
scoped_ptr<PrerenderProperties> current_prerender_;
scoped_ptr<PrerenderProperties> last_swapped_in_prerender_;
- scoped_ptr<PrerenderHandle> prerender_handle_;
- double current_prerender_priority_;
+ ScopedVector<PrerenderProperties> issued_prerenders_;
base::hash_set<int64> url_whitelist_;
base::WeakPtrFactory<PrerenderLocalPredictor> weak_factory_;
- // Indicates whether the current prerender represented by prerender_handle_
- // matched a load in some tab contents, to shed light on how many prerenders
- // that could have possibily been swapped in were not swapped in. For
- // measurement purposes only.
- bool current_prerender_would_have_matched_;
-
DISALLOW_COPY_AND_ASSIGN(PrerenderLocalPredictor);
};
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 8626461..40fc8e2 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -1205,7 +1205,7 @@ base::TimeTicks PrerenderManager::GetExpiryTimeForNewPrerender(
Origin origin) const {
base::TimeDelta ttl = config_.time_to_live;
if (origin == ORIGIN_LOCAL_PREDICTOR)
- ttl = base::TimeDelta::FromSeconds(180);
+ ttl = base::TimeDelta::FromSeconds(GetLocalPredictorTTLSeconds());
return GetCurrentTimeTicks() + ttl;
}