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

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

Issue 2355273002: Redirect handling in the resource_prefetch_predictor. (Closed)
Patch Set: Minor changes 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 c7645ff22b31e0b95019bc73d2c89f986e5b62fc..6e9fa501fc9c64bc584265739b30bcf89f742398 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"
@@ -65,6 +66,8 @@ enum ReportingEvent {
namespace predictors {
+const int kMaxRedirectsPerEntry = 20;
+
////////////////////////////////////////////////////////////////////////////////
// History lookup task.
@@ -72,20 +75,20 @@ namespace predictors {
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)
+ typedef ResourcePrefetchPredictor::Navigation Navigation;
+ typedef base::Callback<void(size_t, // Visit count.
+ const NavigationID&,
+ const Navigation&)>
+ VisitInfoCallback;
+
+ GetUrlVisitCountTask(const NavigationID& navigation_id,
+ std::unique_ptr<Navigation> navigation,
+ VisitInfoCallback callback)
: visit_count_(0),
navigation_id_(navigation_id),
- requests_(requests),
+ navigation_(std::move(navigation)),
callback_(callback) {
- DCHECK(requests_.get());
+ DCHECK(navigation_.get());
}
bool RunOnDBThread(history::HistoryBackend* backend,
@@ -97,7 +100,7 @@ class GetUrlVisitCountTask : public history::HistoryDBTask {
}
void DoneRunOnMainThread() override {
- callback_.Run(visit_count_, navigation_id_, *requests_);
+ callback_.Run(visit_count_, navigation_id_, *navigation_);
}
private:
@@ -105,7 +108,7 @@ class GetUrlVisitCountTask : public history::HistoryDBTask {
int visit_count_;
NavigationID navigation_id_;
- std::unique_ptr<std::vector<URLRequestSummary>> requests_;
+ std::unique_ptr<Navigation> navigation_;
VisitInfoCallback callback_;
DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask);
@@ -281,6 +284,11 @@ ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary(
ResourcePrefetchPredictor::URLRequestSummary::~URLRequestSummary() {
}
+ResourcePrefetchPredictor::Navigation::Navigation(const GURL& i_initial_url)
+ : initial_url(i_initial_url) {}
+
+ResourcePrefetchPredictor::Navigation::~Navigation() {}
+
// static
bool ResourcePrefetchPredictor::URLRequestSummary::SummarizeResponse(
const net::URLRequest& request,
@@ -437,9 +445,9 @@ void ResourcePrefetchPredictor::OnMainFrameRequest(
CleanupAbandonedNavigations(request.navigation_id);
// New empty navigation entry.
+ const GURL& initial_url = request.navigation_id.main_frame_url;
inflight_navigations_.insert(std::make_pair(
- request.navigation_id,
- make_linked_ptr(new std::vector<URLRequestSummary>())));
+ request.navigation_id, base::MakeUnique<Navigation>(initial_url)));
}
void ResourcePrefetchPredictor::OnMainFrameResponse(
@@ -462,7 +470,14 @@ void ResourcePrefetchPredictor::OnMainFrameRedirect(
// Stop any inflight prefetching. Remove the older navigation.
StopPrefetching(response.navigation_id);
- inflight_navigations_.erase(response.navigation_id);
+
+ std::unique_ptr<Navigation> navigation;
+ NavigationMap::iterator nav_it =
+ inflight_navigations_.find(response.navigation_id);
+ if (nav_it != inflight_navigations_.end()) {
+ navigation.reset(nav_it->second.release());
+ inflight_navigations_.erase(nav_it);
+ }
// A redirect will not lead to another OnMainFrameRequest call, so record the
// redirect url as a new navigation.
@@ -471,11 +486,14 @@ void ResourcePrefetchPredictor::OnMainFrameRedirect(
if (response.redirect_url.is_empty())
return;
+ // If we lost information about first hop for some reason
Benoit L 2016/09/26 11:18:36 I'm not entirely sure about what should be done he
alexilin 2016/09/26 12:14:54 It could happen in some rare cases, for example, t
Benoit L 2016/09/27 09:55:06 Ok, thanks. Only a nit then: // If we lost the in
alexilin 2016/09/27 14:52:45 Thanks! Done.
+ if (!navigation)
+ navigation.reset(new Navigation(response.navigation_id.main_frame_url));
pasko 2016/09/22 14:27:09 why not MakeUnique here as well?
alexilin 2016/09/22 16:48:19 How to connect unique_ptr::reset() with MakeUnique
pasko 2016/09/26 12:28:15 navigation = MakeUnique<Navigation>(...)?
alexilin 2016/09/26 15:38:28 There will be one extra construction of unique_ptr
pasko 2016/09/26 15:58:22 I "think" on-stack unique_ptr constructors have al
alexilin 2016/09/27 14:52:45 Done.
+
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(navigation)));
}
void ResourcePrefetchPredictor::OnSubresourceResponse(
@@ -488,7 +506,7 @@ void ResourcePrefetchPredictor::OnSubresourceResponse(
return;
}
- nav_it->second->push_back(response);
+ nav_it->second->subresource_requests.push_back(response);
}
void ResourcePrefetchPredictor::OnNavigationComplete(
@@ -503,7 +521,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<Navigation> navigation = std::move(nav_it->second);
inflight_navigations_.erase(nav_it);
// Kick off history lookup to determine if we should record the URL.
@@ -513,7 +531,7 @@ void ResourcePrefetchPredictor::OnNavigationComplete(
DCHECK(history_service);
history_service->ScheduleDBTask(
std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask(
- navigation_id, requests,
+ navigation_id, std::move(navigation),
base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup,
AsWeakPtr()))),
&history_lookup_consumer_);
@@ -618,29 +636,43 @@ void ResourcePrefetchPredictor::StartInitialization() {
// Create local caches using the database as loaded.
std::unique_ptr<PrefetchDataMap> url_data_map(new PrefetchDataMap());
Benoit L 2016/09/26 11:18:36 nit: Can you use MakeUnique, here and below? auto
alexilin 2016/09/26 12:14:54 Done.
std::unique_ptr<PrefetchDataMap> host_data_map(new PrefetchDataMap());
+ std::unique_ptr<RedirectDataMap> url_redirect_data_map(new RedirectDataMap());
+ std::unique_ptr<RedirectDataMap> host_redirect_data_map(
+ new RedirectDataMap());
PrefetchDataMap* url_data_ptr = url_data_map.get();
PrefetchDataMap* host_data_ptr = host_data_map.get();
+ RedirectDataMap* url_redirect_data_ptr = url_redirect_data_map.get();
Benoit L 2016/09/26 11:18:36 nit: you can directly call .get() below.
alexilin 2016/09/26 12:14:54 Done.
+ RedirectDataMap* host_redirect_data_ptr = host_redirect_data_map.get();
BrowserThread::PostTaskAndReply(
BrowserThread::DB, FROM_HERE,
- base::Bind(&ResourcePrefetchPredictorTables::GetAllData,
- tables_, url_data_ptr, host_data_ptr),
+ base::Bind(&ResourcePrefetchPredictorTables::GetAllData, tables_,
+ url_data_ptr, host_data_ptr, url_redirect_data_ptr,
+ host_redirect_data_ptr),
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_.reset(url_data_map.release());
host_table_cache_.reset(host_data_map.release());
+ url_redirect_table_cache_.reset(url_redirect_data_map.release());
+ host_redirect_table_cache_.reset(host_redirect_data_map.release());
UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount",
url_table_cache_->size());
@@ -717,11 +749,10 @@ void ResourcePrefetchPredictor::DeleteUrls(const history::URLRows& urls) {
}
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));
}
}
@@ -742,22 +773,48 @@ 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;
+ 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 Navigation& navigation) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl",
visit_count);
+ // TODO(alexilin) make only one request to DB thread
+
// URL level data - merge only if we are already saving the data, or we it
// meets the cutoff requirement.
const std::string url_spec = navigation_id.main_frame_url.spec();
@@ -767,17 +824,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,
+ navigation.subresource_requests, config_.max_urls_to_track,
+ url_table_cache_.get(), navigation.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,
+ navigation.subresource_requests, config_.max_hosts_to_track,
+ host_table_cache_.get(), navigation.initial_url.host(),
+ host_redirect_table_cache_.get());
}
// Remove the navigation from the results map.
@@ -789,7 +848,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& redirect_origin_key,
+ RedirectDataMap* redirect_map) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// If the primary key is too long reject it.
@@ -798,10 +859,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;
@@ -921,23 +981,110 @@ 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 != redirect_origin_key) {
+ LearnRedirect(redirect_origin_key, 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_redirects();
+ 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_redirects())) {
+ 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_redirects();
+ 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.redirects_size());
+ for (const RedirectStat& redirect : cache_entry->second.redirects()) {
+ if (redirect.consecutive_misses() < config_.max_consecutive_misses)
+ redirects.push_back(redirect);
+ }
+ ResourcePrefetchPredictorTables::SortRedirects(&redirects);
+
+ if (redirects.size() > kMaxRedirectsPerEntry)
+ redirects.resize(kMaxRedirectsPerEntry);
+
+ cache_entry->second.clear_redirects();
+ for (const RedirectStat& redirect : redirects)
+ cache_entry->second.add_redirects()->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));
}
}

Powered by Google App Engine
This is Rietveld 408576698