Commit fc6a8273 authored by droger's avatar droger Committed by Commit bot

[NoStatePrefetch] Cancel repeated prefetches with FINAL_STATUS_DUPLICATE

As opposed to a full prerender, a prefetch could be repeated relatively soon.
This CL prevent this by detecting repeated prefetches and cancelling them with
FINAL_STATUS_DUPLICATE.

The threshold used is net::HttpCache::kPrefetchReuseMins (5 minutes), which
should roughly match what is happening for full prerenders.

Review-Url: https://codereview.chromium.org/2614473002
Cr-Commit-Position: refs/heads/master@{#441397}
parent 4a0c0947
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/url_constants.h" #include "content/public/common/url_constants.h"
#include "extensions/common/constants.h" #include "extensions/common/constants.h"
#include "net/http/http_cache.h"
#include "net/http/http_request_headers.h" #include "net/http/http_request_headers.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
...@@ -575,6 +576,7 @@ void PrerenderManager::RecordNoStateFirstContentfulPaint(const GURL& url, ...@@ -575,6 +576,7 @@ void PrerenderManager::RecordNoStateFirstContentfulPaint(const GURL& url,
base::TimeDelta prefetch_age; base::TimeDelta prefetch_age;
Origin origin; Origin origin;
GetPrefetchInformation(url, &prefetch_age, &origin); GetPrefetchInformation(url, &prefetch_age, &origin);
OnPrefetchUsed(url);
histograms_->RecordPrefetchFirstContentfulPaintTime( histograms_->RecordPrefetchFirstContentfulPaintTime(
origin, is_no_store, was_hidden, time, prefetch_age); origin, is_no_store, was_hidden, time, prefetch_age);
...@@ -599,8 +601,8 @@ void PrerenderManager::RecordPrerenderFirstContentfulPaint( ...@@ -599,8 +601,8 @@ void PrerenderManager::RecordPrerenderFirstContentfulPaint(
base::TimeDelta prefetch_age; base::TimeDelta prefetch_age;
// The origin at prefetch is superceeded by the tab_helper origin for the // The origin at prefetch is superceeded by the tab_helper origin for the
// histogram recording, below. // histogram recording, below.
Origin unused_origin; GetPrefetchInformation(url, &prefetch_age, nullptr);
GetPrefetchInformation(url, &prefetch_age, &unused_origin); OnPrefetchUsed(url);
base::TimeTicks swap_ticks = tab_helper->swap_ticks(); base::TimeTicks swap_ticks = tab_helper->swap_ticks();
bool fcp_recorded = false; bool fcp_recorded = false;
...@@ -939,8 +941,18 @@ std::unique_ptr<PrerenderHandle> PrerenderManager::AddPrerender( ...@@ -939,8 +941,18 @@ std::unique_ptr<PrerenderHandle> PrerenderManager::AddPrerender(
return nullptr; return nullptr;
} }
if (PrerenderData* preexisting_prerender_data = if (IsNoStatePrefetch(origin)) {
FindPrerenderData(url, session_storage_namespace)) { base::TimeDelta prefetch_age;
GetPrefetchInformation(url, &prefetch_age, nullptr);
if (!prefetch_age.is_zero() &&
prefetch_age <
base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins)) {
RecordFinalStatusWithoutCreatingPrerenderContents(url, origin,
FINAL_STATUS_DUPLICATE);
return nullptr;
}
} else if (PrerenderData* preexisting_prerender_data =
FindPrerenderData(url, session_storage_namespace)) {
RecordFinalStatusWithoutCreatingPrerenderContents( RecordFinalStatusWithoutCreatingPrerenderContents(
url, origin, FINAL_STATUS_DUPLICATE); url, origin, FINAL_STATUS_DUPLICATE);
return base::WrapUnique(new PrerenderHandle(preexisting_prerender_data)); return base::WrapUnique(new PrerenderHandle(preexisting_prerender_data));
...@@ -1192,19 +1204,22 @@ void PrerenderManager::GetPrefetchInformation(const GURL& url, ...@@ -1192,19 +1204,22 @@ void PrerenderManager::GetPrefetchInformation(const GURL& url,
base::TimeDelta* prefetch_age, base::TimeDelta* prefetch_age,
Origin* origin) { Origin* origin) {
DCHECK(prefetch_age); DCHECK(prefetch_age);
DCHECK(origin);
CleanUpOldNavigations(&prefetches_, base::TimeDelta::FromMinutes(30)); CleanUpOldNavigations(&prefetches_, base::TimeDelta::FromMinutes(30));
*prefetch_age = base::TimeDelta(); *prefetch_age = base::TimeDelta();
*origin = ORIGIN_NONE; if (origin)
*origin = ORIGIN_NONE;
for (auto it = prefetches_.crbegin(); it != prefetches_.crend(); ++it) { for (auto it = prefetches_.crbegin(); it != prefetches_.crend(); ++it) {
if (it->url == url) { if (it->url == url) {
*prefetch_age = GetCurrentTimeTicks() - it->time; *prefetch_age = GetCurrentTimeTicks() - it->time;
*origin = it->origin; if (origin)
*origin = it->origin;
break; break;
} }
} }
}
void PrerenderManager::OnPrefetchUsed(const GURL& url) {
// Loading a prefetched URL resets the revalidation bypass. Remove all // Loading a prefetched URL resets the revalidation bypass. Remove all
// matching urls from the prefetch list for more accurate metrics. // matching urls from the prefetch list for more accurate metrics.
prefetches_.erase( prefetches_.erase(
......
...@@ -540,10 +540,15 @@ class PrerenderManager : public content::NotificationObserver, ...@@ -540,10 +540,15 @@ class PrerenderManager : public content::NotificationObserver,
void DeleteOldWebContents(); void DeleteOldWebContents();
// Get information associated with a possible prefetch of |url|. // Get information associated with a possible prefetch of |url|.
// |origin| may be null, in which case the origin is not returned.
void GetPrefetchInformation(const GURL& url, void GetPrefetchInformation(const GURL& url,
base::TimeDelta* prefetch_age, base::TimeDelta* prefetch_age,
Origin* origin); Origin* origin);
// Called when a prefetch has been used. Prefetches avoid cache revalidation
// only once.
void OnPrefetchUsed(const GURL& url);
// Cleans up old NavigationRecord's. // Cleans up old NavigationRecord's.
void CleanUpOldNavigations(std::vector<NavigationRecord>* navigations, void CleanUpOldNavigations(std::vector<NavigationRecord>* navigations,
base::TimeDelta max_age); base::TimeDelta max_age);
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/test/test_browser_thread.h" #include "content/public/test/test_browser_thread.h"
#include "net/base/network_change_notifier.h" #include "net/base/network_change_notifier.h"
#include "net/http/http_cache.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
...@@ -781,6 +782,37 @@ TEST_F(PrerenderTest, LinkManagerNavigateAwayLaunchAnother) { ...@@ -781,6 +782,37 @@ TEST_F(PrerenderTest, LinkManagerNavigateAwayLaunchAnother) {
prerender_manager()->FindEntry(second_url)); prerender_manager()->FindEntry(second_url));
} }
// Prefetching the same URL twice during |time_to_live| results in a duplicate
// and is aborted.
TEST_F(PrerenderTest, NoStatePrefetchDuplicate) {
const GURL kUrl("http://www.google.com/");
RestorePrerenderMode restore_prerender_mode;
prerender_manager()->SetMode(
PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH);
base::SimpleTestTickClock* tick_clock =
OverridePrerenderManagerTimeTicks(prerender_manager());
// Prefetch the url once.
prerender_manager()->CreateNextPrerenderContents(
kUrl, ORIGIN_OMNIBOX, FINAL_STATUS_MANAGER_SHUTDOWN);
EXPECT_TRUE(
prerender_manager()->AddPrerenderFromOmnibox(kUrl, nullptr, gfx::Size()));
prerender_manager()->CreateNextPrerenderContents(
kUrl, ORIGIN_OMNIBOX, FINAL_STATUS_MANAGER_SHUTDOWN);
// Prefetching again before time_to_live aborts, because it is a duplicate.
tick_clock->Advance(base::TimeDelta::FromSeconds(1));
EXPECT_FALSE(
prerender_manager()->AddPrerenderFromOmnibox(kUrl, nullptr, gfx::Size()));
// Prefetching after time_to_live succeeds.
tick_clock->Advance(
base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins));
EXPECT_TRUE(
prerender_manager()->AddPrerenderFromOmnibox(kUrl, nullptr, gfx::Size()));
}
// Make sure that if we prerender more requests than we support, that we launch // Make sure that if we prerender more requests than we support, that we launch
// them in the order given up until we reach MaxConcurrency, at which point we // them in the order given up until we reach MaxConcurrency, at which point we
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment