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

Unified Diff: chrome/browser/predictors/resource_prefetch_predictor.cc

Issue 2355273002: Redirect handling in the resource_prefetch_predictor. (Closed)
Patch Set: Fix compilation complaints. Created 4 years, 3 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/predictors/resource_prefetch_predictor.cc
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index b34cd78126fae9cf632946fd88945263ead4bb1a..bc8013823e45f315042e702e7e876b2c08fe3aae 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -10,6 +10,7 @@
#include "base/command_line.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_number_conversions.h"
@@ -23,7 +24,6 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "components/history/core/browser/history_database.h"
-#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
#include "components/mime_util/mime_util.h"
#include "content/public/browser/browser_thread.h"
@@ -66,52 +66,6 @@ enum ReportingEvent {
namespace predictors {
////////////////////////////////////////////////////////////////////////////////
-// History lookup task.
-
-// Used to fetch the visit count for a URL from the History database.
-class GetUrlVisitCountTask : public history::HistoryDBTask {
- public:
- typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
- typedef base::Callback<void(
- size_t, // Visit count.
- const NavigationID&,
- const std::vector<URLRequestSummary>&)> VisitInfoCallback;
-
- GetUrlVisitCountTask(
- const NavigationID& navigation_id,
- std::vector<URLRequestSummary>* requests,
- VisitInfoCallback callback)
- : visit_count_(0),
- navigation_id_(navigation_id),
- requests_(requests),
- callback_(callback) {
- DCHECK(requests_.get());
- }
-
- bool RunOnDBThread(history::HistoryBackend* backend,
- history::HistoryDatabase* db) override {
- history::URLRow url_row;
- if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
- visit_count_ = url_row.visit_count();
- return true;
- }
-
- void DoneRunOnMainThread() override {
- callback_.Run(visit_count_, navigation_id_, *requests_);
- }
-
- private:
- ~GetUrlVisitCountTask() override {}
-
- int visit_count_;
- NavigationID navigation_id_;
- std::unique_ptr<std::vector<URLRequestSummary>> requests_;
- VisitInfoCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask);
-};
-
-////////////////////////////////////////////////////////////////////////////////
// ResourcePrefetchPredictor static functions.
// static
@@ -257,7 +211,7 @@ content::ResourceType ResourcePrefetchPredictor::GetResourceTypeFromMimeType(
}
////////////////////////////////////////////////////////////////////////////////
-// ResourcePrefetchPredictor structs.
+// ResourcePrefetchPredictor nested types.
ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary()
: resource_type(content::RESOURCE_TYPE_LAST_TYPE),
@@ -318,6 +272,38 @@ bool ResourcePrefetchPredictor::URLRequestSummary::SummarizeResponse(
return true;
}
+ResourcePrefetchPredictor::GetUrlVisitCountTask::GetUrlVisitCountTask(
+ const NavigationID& navigation_id,
+ std::unique_ptr<PageRequestSummary> summary,
+ VisitInfoCallback callback)
+ : visit_count_(0),
+ navigation_id_(navigation_id),
+ summary_(std::move(summary)),
+ callback_(callback) {
+ DCHECK(summary_.get());
+}
+
+bool ResourcePrefetchPredictor::GetUrlVisitCountTask::RunOnDBThread(
+ history::HistoryBackend* backend,
+ history::HistoryDatabase* db) {
+ history::URLRow url_row;
+ if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
+ visit_count_ = url_row.visit_count();
+ return true;
+}
+
+void ResourcePrefetchPredictor::GetUrlVisitCountTask::DoneRunOnMainThread() {
+ callback_.Run(visit_count_, navigation_id_, *summary_);
+}
+
+ResourcePrefetchPredictor::GetUrlVisitCountTask::~GetUrlVisitCountTask() {}
+
+ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary(
+ const GURL& i_initial_url)
+ : initial_url(i_initial_url) {}
+
+ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {}
+
////////////////////////////////////////////////////////////////////////////////
// ResourcePrefetchPredictor.
@@ -414,9 +400,10 @@ void ResourcePrefetchPredictor::OnMainFrameRequest(
CleanupAbandonedNavigations(request.navigation_id);
// New empty navigation entry.
- inflight_navigations_.insert(std::make_pair(
- request.navigation_id,
- make_linked_ptr(new std::vector<URLRequestSummary>())));
+ const GURL& initial_url = request.navigation_id.main_frame_url;
+ inflight_navigations_.insert(
+ std::make_pair(request.navigation_id,
+ base::MakeUnique<PageRequestSummary>(initial_url)));
}
void ResourcePrefetchPredictor::OnMainFrameResponse(
@@ -432,27 +419,33 @@ void ResourcePrefetchPredictor::OnMainFrameRedirect(
const URLRequestSummary& response) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // TODO(shishir): There are significant gains to be had here if we can use the
- // start URL in a redirect chain as the key to start prefetching. We can save
- // of redirect times considerably assuming that the redirect chains do not
- // change.
-
// Stop any inflight prefetching. Remove the older navigation.
StopPrefetching(response.navigation_id);
- inflight_navigations_.erase(response.navigation_id);
- // A redirect will not lead to another OnMainFrameRequest call, so record the
- // redirect url as a new navigation.
+ std::unique_ptr<PageRequestSummary> summary;
+ NavigationMap::iterator nav_it =
+ inflight_navigations_.find(response.navigation_id);
+ if (nav_it != inflight_navigations_.end()) {
+ summary.reset(nav_it->second.release());
+ inflight_navigations_.erase(nav_it);
+ }
// The redirect url may be empty if the URL was invalid.
if (response.redirect_url.is_empty())
return;
+ // If we lost the information about the first hop for some reason.
+ if (!summary) {
+ const GURL& initial_url = response.navigation_id.main_frame_url;
+ summary = base::MakeUnique<PageRequestSummary>(initial_url);
+ }
+
+ // A redirect will not lead to another OnMainFrameRequest call, so record the
+ // redirect url as a new navigation id and save the initial url.
NavigationID navigation_id(response.navigation_id);
navigation_id.main_frame_url = response.redirect_url;
- inflight_navigations_.insert(std::make_pair(
- navigation_id,
- make_linked_ptr(new std::vector<URLRequestSummary>())));
+ inflight_navigations_.insert(
+ std::make_pair(navigation_id, std::move(summary)));
}
void ResourcePrefetchPredictor::OnSubresourceResponse(
@@ -465,7 +458,7 @@ void ResourcePrefetchPredictor::OnSubresourceResponse(
return;
}
- nav_it->second->push_back(response);
+ nav_it->second->subresource_requests.push_back(response);
}
void ResourcePrefetchPredictor::OnNavigationComplete(
@@ -480,7 +473,7 @@ void ResourcePrefetchPredictor::OnNavigationComplete(
const NavigationID navigation_id(nav_it->first);
// Remove the navigation from the inflight navigations.
- std::vector<URLRequestSummary>* requests = (nav_it->second).release();
+ std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second);
inflight_navigations_.erase(nav_it);
// Kick off history lookup to determine if we should record the URL.
@@ -490,7 +483,7 @@ void ResourcePrefetchPredictor::OnNavigationComplete(
DCHECK(history_service);
history_service->ScheduleDBTask(
std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask(
- navigation_id, requests,
+ navigation_id, std::move(summary),
base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup,
AsWeakPtr()))),
&history_lookup_consumer_);
@@ -586,31 +579,40 @@ void ResourcePrefetchPredictor::StartInitialization() {
initialization_state_ = INITIALIZING;
// Create local caches using the database as loaded.
- std::unique_ptr<PrefetchDataMap> url_data_map(new PrefetchDataMap());
- std::unique_ptr<PrefetchDataMap> host_data_map(new PrefetchDataMap());
- PrefetchDataMap* url_data_ptr = url_data_map.get();
- PrefetchDataMap* host_data_ptr = host_data_map.get();
Reid Kleckner 2016/09/29 23:42:23 Removing the raw pointer local variables here is w
+ auto url_data_map = base::MakeUnique<PrefetchDataMap>();
+ auto host_data_map = base::MakeUnique<PrefetchDataMap>();
+ auto url_redirect_data_map = base::MakeUnique<RedirectDataMap>();
+ auto host_redirect_data_map = base::MakeUnique<RedirectDataMap>();
BrowserThread::PostTaskAndReply(
BrowserThread::DB, FROM_HERE,
- base::Bind(&ResourcePrefetchPredictorTables::GetAllData,
- tables_, url_data_ptr, host_data_ptr),
+ base::Bind(&ResourcePrefetchPredictorTables::GetAllData, tables_,
+ url_data_map.get(), host_data_map.get(),
+ url_redirect_data_map.get(), host_redirect_data_map.get()),
base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(),
- base::Passed(&url_data_map), base::Passed(&host_data_map)));
+ base::Passed(&url_data_map), base::Passed(&host_data_map),
+ base::Passed(&url_redirect_data_map),
+ base::Passed(&host_redirect_data_map)));
}
void ResourcePrefetchPredictor::CreateCaches(
std::unique_ptr<PrefetchDataMap> url_data_map,
- std::unique_ptr<PrefetchDataMap> host_data_map) {
+ std::unique_ptr<PrefetchDataMap> host_data_map,
+ std::unique_ptr<RedirectDataMap> url_redirect_data_map,
+ std::unique_ptr<RedirectDataMap> host_redirect_data_map) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(INITIALIZING, initialization_state_);
DCHECK(!url_table_cache_);
DCHECK(!host_table_cache_);
+ DCHECK(!url_redirect_table_cache_);
+ DCHECK(!host_redirect_table_cache_);
DCHECK(inflight_navigations_.empty());
url_table_cache_ = std::move(url_data_map);
host_table_cache_ = std::move(host_data_map);
+ url_redirect_table_cache_ = std::move(url_redirect_data_map);
+ host_redirect_table_cache_ = std::move(host_redirect_data_map);
UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount",
url_table_cache_->size());
@@ -653,6 +655,8 @@ void ResourcePrefetchPredictor::DeleteAllUrls() {
inflight_navigations_.clear();
url_table_cache_->clear();
host_table_cache_->clear();
+ url_redirect_table_cache_->clear();
+ host_redirect_table_cache_->clear();
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::Bind(&ResourcePrefetchPredictorTables::DeleteAllData, tables_));
@@ -662,6 +666,7 @@ void ResourcePrefetchPredictor::DeleteUrls(const history::URLRows& urls) {
// Check all the urls in the database and pick out the ones that are present
// in the cache.
std::vector<std::string> urls_to_delete, hosts_to_delete;
+ std::vector<std::string> url_redirects_to_delete, host_redirects_to_delete;
for (const auto& it : urls) {
const std::string& url_spec = it.url().spec();
@@ -670,19 +675,37 @@ void ResourcePrefetchPredictor::DeleteUrls(const history::URLRows& urls) {
url_table_cache_->erase(url_spec);
}
+ if (url_redirect_table_cache_->find(url_spec) !=
+ url_redirect_table_cache_->end()) {
+ url_redirects_to_delete.push_back(url_spec);
+ url_redirect_table_cache_->erase(url_spec);
+ }
+
const std::string& host = it.url().host();
if (host_table_cache_->find(host) != host_table_cache_->end()) {
hosts_to_delete.push_back(host);
host_table_cache_->erase(host);
}
+
+ if (host_redirect_table_cache_->find(host) !=
+ host_redirect_table_cache_->end()) {
+ host_redirects_to_delete.push_back(host);
+ host_redirect_table_cache_->erase(host);
+ }
}
if (!urls_to_delete.empty() || !hosts_to_delete.empty()) {
- BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
- base::Bind(&ResourcePrefetchPredictorTables::DeleteData,
- tables_,
- urls_to_delete,
- hosts_to_delete));
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(&ResourcePrefetchPredictorTables::DeleteResourceData,
+ tables_, urls_to_delete, hosts_to_delete));
+ }
+
+ if (!url_redirects_to_delete.empty() || !host_redirects_to_delete.empty()) {
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(&ResourcePrefetchPredictorTables::DeleteRedirectData,
+ tables_, url_redirects_to_delete, host_redirects_to_delete));
}
}
@@ -703,23 +726,49 @@ void ResourcePrefetchPredictor::RemoveOldestEntryInPrefetchDataMap(
}
data_map->erase(key_to_delete);
- BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
- base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint,
- tables_,
- key_to_delete,
- key_type));
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(
+ &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
+ tables_, key_to_delete, key_type));
+}
+
+void ResourcePrefetchPredictor::RemoveOldestEntryInRedirectDataMap(
+ PrefetchKeyType key_type,
+ RedirectDataMap* data_map) {
+ if (data_map->empty())
+ return;
+
+ uint64_t oldest_time = UINT64_MAX;
+ std::string key_to_delete;
+ for (const auto& kv : *data_map) {
+ const RedirectData& data = kv.second;
+ if (key_to_delete.empty() || data.last_visit_time() < oldest_time) {
+ key_to_delete = data.primary_key();
+ oldest_time = data.last_visit_time();
+ }
+ }
+
+ data_map->erase(key_to_delete);
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(
+ &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
+ tables_, key_to_delete, key_type));
}
void ResourcePrefetchPredictor::OnVisitCountLookup(
size_t visit_count,
const NavigationID& navigation_id,
- const std::vector<URLRequestSummary>& requests) {
+ const PageRequestSummary& summary) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl",
visit_count);
- // URL level data - merge only if we are already saving the data, or we it
+ // TODO(alexilin): make only one request to DB thread.
+
+ // URL level data - merge only if we already saved the data, or it
// meets the cutoff requirement.
const std::string url_spec = navigation_id.main_frame_url.spec();
bool already_tracking = url_table_cache_->find(url_spec) !=
@@ -728,17 +777,19 @@ void ResourcePrefetchPredictor::OnVisitCountLookup(
(visit_count >= config_.min_url_visit_count);
if (should_track_url && config_.IsURLLearningEnabled()) {
- LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL, requests,
- config_.max_urls_to_track, url_table_cache_.get());
+ LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL,
+ summary.subresource_requests, config_.max_urls_to_track,
+ url_table_cache_.get(), summary.initial_url.spec(),
+ url_redirect_table_cache_.get());
}
// Host level data - no cutoff, always learn the navigation if enabled.
if (config_.IsHostLearningEnabled()) {
- LearnNavigation(navigation_id.main_frame_url.host(),
- PREFETCH_KEY_TYPE_HOST,
- requests,
- config_.max_hosts_to_track,
- host_table_cache_.get());
+ const std::string host = navigation_id.main_frame_url.host();
+ LearnNavigation(host, PREFETCH_KEY_TYPE_HOST, summary.subresource_requests,
+ config_.max_hosts_to_track, host_table_cache_.get(),
+ summary.initial_url.host(),
+ host_redirect_table_cache_.get());
}
}
@@ -747,7 +798,9 @@ void ResourcePrefetchPredictor::LearnNavigation(
PrefetchKeyType key_type,
const std::vector<URLRequestSummary>& new_resources,
size_t max_data_map_size,
- PrefetchDataMap* data_map) {
+ PrefetchDataMap* data_map,
+ const std::string& key_before_redirects,
+ RedirectDataMap* redirect_map) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// If the primary key is too long reject it.
@@ -756,10 +809,9 @@ void ResourcePrefetchPredictor::LearnNavigation(
PrefetchDataMap::iterator cache_entry = data_map->find(key);
if (cache_entry == data_map->end()) {
- if (data_map->size() >= max_data_map_size) {
- // The table is full, delete an entry.
+ // If the table is full, delete an entry.
+ if (data_map->size() >= max_data_map_size)
RemoveOldestEntryInPrefetchDataMap(key_type, data_map);
- }
cache_entry = data_map->insert(std::make_pair(
key, PrefetchData(key_type, key))).first;
@@ -879,23 +931,111 @@ void ResourcePrefetchPredictor::LearnNavigation(
data_map->erase(key);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
- base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint,
- tables_,
- key,
- key_type));
+ base::Bind(
+ &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
+ tables_, key, key_type));
} else {
bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
PrefetchData empty_data(
!is_host ? PREFETCH_KEY_TYPE_HOST : PREFETCH_KEY_TYPE_URL,
std::string());
+ RedirectData empty_redirect_data;
const PrefetchData& host_data = is_host ? cache_entry->second : empty_data;
const PrefetchData& url_data = is_host ? empty_data : cache_entry->second;
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
- base::Bind(&ResourcePrefetchPredictorTables::UpdateData,
- tables_,
- url_data,
- host_data));
+ base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
+ url_data, host_data, empty_redirect_data,
+ empty_redirect_data));
+ }
+
+ if (key != key_before_redirects) {
+ LearnRedirect(key_before_redirects, key_type, key, max_data_map_size,
+ redirect_map);
+ }
+}
+
+void ResourcePrefetchPredictor::LearnRedirect(const std::string& key,
+ PrefetchKeyType key_type,
+ const std::string& final_redirect,
+ size_t max_redirect_map_size,
+ RedirectDataMap* redirect_map) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ RedirectDataMap::iterator cache_entry = redirect_map->find(key);
+ if (cache_entry == redirect_map->end()) {
+ if (redirect_map->size() >= max_redirect_map_size)
+ RemoveOldestEntryInRedirectDataMap(key_type, redirect_map);
+
+ RedirectData new_data;
+ new_data.set_primary_key(key);
+ cache_entry = redirect_map->insert(std::make_pair(key, new_data)).first;
+ cache_entry->second.set_last_visit_time(
+ base::Time::Now().ToInternalValue());
+ RedirectStat* redirect_to_add =
+ cache_entry->second.add_redirect_endpoints();
+ redirect_to_add->set_url(final_redirect);
+ redirect_to_add->set_number_of_hits(1);
+ } else {
+ bool need_to_add = true;
+ cache_entry->second.set_last_visit_time(
+ base::Time::Now().ToInternalValue());
+
+ for (RedirectStat& redirect :
+ *(cache_entry->second.mutable_redirect_endpoints())) {
+ if (redirect.url() == final_redirect) {
+ need_to_add = false;
+ redirect.set_number_of_hits(redirect.number_of_hits() + 1);
+ redirect.set_consecutive_misses(0);
+ } else {
+ redirect.set_number_of_misses(redirect.number_of_misses() + 1);
+ redirect.set_consecutive_misses(redirect.consecutive_misses() + 1);
+ }
+ }
+
+ if (need_to_add) {
+ RedirectStat* redirect_to_add =
+ cache_entry->second.add_redirect_endpoints();
+ redirect_to_add->set_url(final_redirect);
+ redirect_to_add->set_number_of_hits(1);
+ }
+ }
+
+ // Trim and sort redirects after update.
+ std::vector<RedirectStat> redirects;
+ redirects.reserve(cache_entry->second.redirect_endpoints_size());
+ for (const RedirectStat& redirect :
+ cache_entry->second.redirect_endpoints()) {
+ if (redirect.consecutive_misses() < config_.max_consecutive_misses)
+ redirects.push_back(redirect);
+ }
+ ResourcePrefetchPredictorTables::SortRedirects(&redirects);
+
+ cache_entry->second.clear_redirect_endpoints();
+ for (const RedirectStat& redirect : redirects)
+ cache_entry->second.add_redirect_endpoints()->CopyFrom(redirect);
+
+ if (redirects.empty()) {
+ redirect_map->erase(cache_entry);
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(
+ &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
+ tables_, key, key_type));
+ } else {
+ bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+ RedirectData empty_redirect_data;
+ PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
+ PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
+ const RedirectData& host_redirect_data =
+ is_host ? cache_entry->second : empty_redirect_data;
+ const RedirectData& url_redirect_data =
+ is_host ? empty_redirect_data : cache_entry->second;
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
+ empty_url_data, empty_host_data, url_redirect_data,
+ host_redirect_data));
}
}
« no previous file with comments | « chrome/browser/predictors/resource_prefetch_predictor.h ('k') | chrome/browser/predictors/resource_prefetch_predictor.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698