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 @@
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
#include "net/http/http_cache.h"
#include "net/http/http_request_headers.h"
#include "ui/gfx/geometry/rect.h"
......@@ -575,6 +576,7 @@ void PrerenderManager::RecordNoStateFirstContentfulPaint(const GURL& url,
base::TimeDelta prefetch_age;
Origin origin;
GetPrefetchInformation(url, &prefetch_age, &origin);
OnPrefetchUsed(url);
histograms_->RecordPrefetchFirstContentfulPaintTime(
origin, is_no_store, was_hidden, time, prefetch_age);
......@@ -599,8 +601,8 @@ void PrerenderManager::RecordPrerenderFirstContentfulPaint(
base::TimeDelta prefetch_age;
// The origin at prefetch is superceeded by the tab_helper origin for the
// histogram recording, below.
Origin unused_origin;
GetPrefetchInformation(url, &prefetch_age, &unused_origin);
GetPrefetchInformation(url, &prefetch_age, nullptr);
OnPrefetchUsed(url);
base::TimeTicks swap_ticks = tab_helper->swap_ticks();
bool fcp_recorded = false;
......@@ -939,7 +941,17 @@ std::unique_ptr<PrerenderHandle> PrerenderManager::AddPrerender(
return nullptr;
}
if (PrerenderData* preexisting_prerender_data =
if (IsNoStatePrefetch(origin)) {
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(
url, origin, FINAL_STATUS_DUPLICATE);
......@@ -1192,19 +1204,22 @@ void PrerenderManager::GetPrefetchInformation(const GURL& url,
base::TimeDelta* prefetch_age,
Origin* origin) {
DCHECK(prefetch_age);
DCHECK(origin);
CleanUpOldNavigations(&prefetches_, base::TimeDelta::FromMinutes(30));
*prefetch_age = base::TimeDelta();
if (origin)
*origin = ORIGIN_NONE;
for (auto it = prefetches_.crbegin(); it != prefetches_.crend(); ++it) {
if (it->url == url) {
*prefetch_age = GetCurrentTimeTicks() - it->time;
if (origin)
*origin = it->origin;
break;
}
}
}
void PrerenderManager::OnPrefetchUsed(const GURL& url) {
// Loading a prefetched URL resets the revalidation bypass. Remove all
// matching urls from the prefetch list for more accurate metrics.
prefetches_.erase(
......
......@@ -540,10 +540,15 @@ class PrerenderManager : public content::NotificationObserver,
void DeleteOldWebContents();
// 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,
base::TimeDelta* prefetch_age,
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.
void CleanUpOldNavigations(std::vector<NavigationRecord>* navigations,
base::TimeDelta max_age);
......
......@@ -38,6 +38,7 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/test/test_browser_thread.h"
#include "net/base/network_change_notifier.h"
#include "net/http/http_cache.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
......@@ -781,6 +782,37 @@ TEST_F(PrerenderTest, LinkManagerNavigateAwayLaunchAnother) {
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
// 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