| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/predictors/resource_prefetch_predictor.h" | 5 #include "chrome/browser/predictors/resource_prefetch_predictor.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 "application/font-sfnt", | 54 "application/font-sfnt", |
| 55 "application/font-ttf"}; | 55 "application/font-ttf"}; |
| 56 | 56 |
| 57 // For reporting events of interest that are not tied to any navigation. | 57 // For reporting events of interest that are not tied to any navigation. |
| 58 enum ReportingEvent { | 58 enum ReportingEvent { |
| 59 REPORTING_EVENT_ALL_HISTORY_CLEARED = 0, | 59 REPORTING_EVENT_ALL_HISTORY_CLEARED = 0, |
| 60 REPORTING_EVENT_PARTIAL_HISTORY_CLEARED = 1, | 60 REPORTING_EVENT_PARTIAL_HISTORY_CLEARED = 1, |
| 61 REPORTING_EVENT_COUNT = 2 | 61 REPORTING_EVENT_COUNT = 2 |
| 62 }; | 62 }; |
| 63 | 63 |
| 64 float ComputeRedirectConfidence(const predictors::RedirectStat& redirect) { |
| 65 return (redirect.number_of_hits() + 0.0) / |
| 66 (redirect.number_of_hits() + redirect.number_of_misses()); |
| 67 } |
| 68 |
| 64 } // namespace | 69 } // namespace |
| 65 | 70 |
| 66 namespace predictors { | 71 namespace predictors { |
| 67 | 72 |
| 68 //////////////////////////////////////////////////////////////////////////////// | 73 //////////////////////////////////////////////////////////////////////////////// |
| 69 // ResourcePrefetchPredictor static functions. | 74 // ResourcePrefetchPredictor static functions. |
| 70 | 75 |
| 71 // static | 76 // static |
| 72 bool ResourcePrefetchPredictor::ShouldRecordRequest( | 77 bool ResourcePrefetchPredictor::ShouldRecordRequest( |
| 73 net::URLRequest* request, | 78 net::URLRequest* request, |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 std::any_of(std::begin(kFontMimeTypes), std::end(kFontMimeTypes), | 208 std::any_of(std::begin(kFontMimeTypes), std::end(kFontMimeTypes), |
| 204 [&mime_type](const std::string& mime) { | 209 [&mime_type](const std::string& mime) { |
| 205 return net::MatchesMimeType(mime, mime_type); | 210 return net::MatchesMimeType(mime, mime_type); |
| 206 }); | 211 }); |
| 207 if (found) | 212 if (found) |
| 208 return content::RESOURCE_TYPE_FONT_RESOURCE; | 213 return content::RESOURCE_TYPE_FONT_RESOURCE; |
| 209 } | 214 } |
| 210 return fallback; | 215 return fallback; |
| 211 } | 216 } |
| 212 | 217 |
| 218 // static |
| 219 bool ResourcePrefetchPredictor::GetRedirectEndpoint( |
| 220 const std::string& first_redirect, |
| 221 const RedirectDataMap& redirect_data_map, |
| 222 std::string* final_redirect) { |
| 223 DCHECK(final_redirect); |
| 224 |
| 225 RedirectDataMap::const_iterator it = redirect_data_map.find(first_redirect); |
| 226 if (it == redirect_data_map.end()) |
| 227 return false; |
| 228 |
| 229 const RedirectData& redirect_data = it->second; |
| 230 auto best_redirect = std::max_element( |
| 231 redirect_data.redirect_endpoints().begin(), |
| 232 redirect_data.redirect_endpoints().end(), |
| 233 [](const RedirectStat& x, const RedirectStat& y) { |
| 234 return ComputeRedirectConfidence(x) < ComputeRedirectConfidence(y); |
| 235 }); |
| 236 |
| 237 const float kMinRedirectConfidenceToTriggerPrefetch = 0.7f; |
| 238 const int kMinRedirectHitsToTriggerPrefetch = 2; |
| 239 |
| 240 if (best_redirect == redirect_data.redirect_endpoints().end() || |
| 241 ComputeRedirectConfidence(*best_redirect) < |
| 242 kMinRedirectConfidenceToTriggerPrefetch || |
| 243 best_redirect->number_of_hits() < kMinRedirectHitsToTriggerPrefetch) |
| 244 return false; |
| 245 |
| 246 *final_redirect = best_redirect->url(); |
| 247 return true; |
| 248 } |
| 249 |
| 213 //////////////////////////////////////////////////////////////////////////////// | 250 //////////////////////////////////////////////////////////////////////////////// |
| 214 // ResourcePrefetchPredictor nested types. | 251 // ResourcePrefetchPredictor nested types. |
| 215 | 252 |
| 216 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary() | 253 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary() |
| 217 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), | 254 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), |
| 218 priority(net::IDLE), | 255 priority(net::IDLE), |
| 219 was_cached(false), | 256 was_cached(false), |
| 220 has_validators(false), | 257 has_validators(false), |
| 221 always_revalidate(false) {} | 258 always_revalidate(false) {} |
| 222 | 259 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 if (initialization_state_ != INITIALIZED) | 449 if (initialization_state_ != INITIALIZED) |
| 413 return; | 450 return; |
| 414 | 451 |
| 415 StopPrefetching(response.navigation_id.main_frame_url); | 452 StopPrefetching(response.navigation_id.main_frame_url); |
| 416 } | 453 } |
| 417 | 454 |
| 418 void ResourcePrefetchPredictor::OnMainFrameRedirect( | 455 void ResourcePrefetchPredictor::OnMainFrameRedirect( |
| 419 const URLRequestSummary& response) { | 456 const URLRequestSummary& response) { |
| 420 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 457 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 421 | 458 |
| 422 // Stop any inflight prefetching. Remove the older navigation. | |
| 423 StopPrefetching(response.navigation_id.main_frame_url); | |
| 424 | |
| 425 std::unique_ptr<PageRequestSummary> summary; | 459 std::unique_ptr<PageRequestSummary> summary; |
| 426 NavigationMap::iterator nav_it = | 460 NavigationMap::iterator nav_it = |
| 427 inflight_navigations_.find(response.navigation_id); | 461 inflight_navigations_.find(response.navigation_id); |
| 428 if (nav_it != inflight_navigations_.end()) { | 462 if (nav_it != inflight_navigations_.end()) { |
| 429 summary.reset(nav_it->second.release()); | 463 summary.reset(nav_it->second.release()); |
| 430 inflight_navigations_.erase(nav_it); | 464 inflight_navigations_.erase(nav_it); |
| 431 } | 465 } |
| 432 | 466 |
| 433 // The redirect url may be empty if the URL was invalid. | 467 // The redirect url may be empty if the URL was invalid. |
| 434 if (response.redirect_url.is_empty()) | 468 if (response.redirect_url.is_empty()) |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask( | 519 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask( |
| 486 navigation_id, std::move(summary), | 520 navigation_id, std::move(summary), |
| 487 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup, | 521 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup, |
| 488 AsWeakPtr()))), | 522 AsWeakPtr()))), |
| 489 &history_lookup_consumer_); | 523 &history_lookup_consumer_); |
| 490 } | 524 } |
| 491 | 525 |
| 492 bool ResourcePrefetchPredictor::GetPrefetchData(const GURL& main_frame_url, | 526 bool ResourcePrefetchPredictor::GetPrefetchData(const GURL& main_frame_url, |
| 493 std::vector<GURL>* urls) { | 527 std::vector<GURL>* urls) { |
| 494 DCHECK(urls); | 528 DCHECK(urls); |
| 495 | 529 DCHECK(urls->empty()); |
| 496 bool use_url_data = config_.IsPrefetchingEnabled(profile_) ? | 530 bool use_url_data = config_.IsPrefetchingEnabled(profile_) ? |
| 497 config_.IsURLPrefetchingEnabled(profile_) : | 531 config_.IsURLPrefetchingEnabled(profile_) : |
| 498 config_.IsURLLearningEnabled(); | 532 config_.IsURLLearningEnabled(); |
| 499 if (use_url_data) { | |
| 500 PrefetchDataMap::const_iterator iterator = | |
| 501 url_table_cache_->find(main_frame_url.spec()); | |
| 502 if (iterator != url_table_cache_->end()) | |
| 503 PopulatePrefetcherRequest(iterator->second, urls); | |
| 504 } | |
| 505 if (!urls->empty()) | |
| 506 return true; | |
| 507 | |
| 508 bool use_host_data = config_.IsPrefetchingEnabled(profile_) ? | 533 bool use_host_data = config_.IsPrefetchingEnabled(profile_) ? |
| 509 config_.IsHostPrefetchingEnabled(profile_) : | 534 config_.IsHostPrefetchingEnabled(profile_) : |
| 510 config_.IsHostLearningEnabled(); | 535 config_.IsHostLearningEnabled(); |
| 511 if (use_host_data) { | 536 |
| 512 PrefetchDataMap::const_iterator iterator = | 537 // Fetch URLs based on a redirect endpoint for URL/host first. |
| 513 host_table_cache_->find(main_frame_url.host()); | 538 std::string redirect_endpoint; |
| 514 if (iterator != host_table_cache_->end()) | 539 if (use_url_data && |
| 515 PopulatePrefetcherRequest(iterator->second, urls); | 540 GetRedirectEndpoint(main_frame_url.spec(), *url_redirect_table_cache_, |
| 541 &redirect_endpoint) && |
| 542 PopulatePrefetcherRequest(redirect_endpoint, *url_table_cache_, urls)) { |
| 543 return true; |
| 516 } | 544 } |
| 517 | 545 |
| 518 return !urls->empty(); | 546 if (use_host_data && |
| 547 GetRedirectEndpoint(main_frame_url.host(), *host_redirect_table_cache_, |
| 548 &redirect_endpoint) && |
| 549 PopulatePrefetcherRequest(redirect_endpoint, *host_table_cache_, urls)) { |
| 550 return true; |
| 551 } |
| 552 |
| 553 // Fallback to fetching URLs based on the incoming URL/host. |
| 554 if (use_url_data && PopulatePrefetcherRequest(main_frame_url.spec(), |
| 555 *url_table_cache_, urls)) { |
| 556 return true; |
| 557 } |
| 558 |
| 559 return use_host_data && PopulatePrefetcherRequest(main_frame_url.host(), |
| 560 *host_table_cache_, urls); |
| 519 } | 561 } |
| 520 | 562 |
| 521 void ResourcePrefetchPredictor::PopulatePrefetcherRequest( | 563 bool ResourcePrefetchPredictor::PopulatePrefetcherRequest( |
| 522 const PrefetchData& data, | 564 const std::string& main_frame_key, |
| 565 const PrefetchDataMap& data_map, |
| 523 std::vector<GURL>* urls) { | 566 std::vector<GURL>* urls) { |
| 524 for (const ResourceData& resource : data.resources()) { | 567 DCHECK(urls); |
| 568 PrefetchDataMap::const_iterator it = data_map.find(main_frame_key); |
| 569 if (it == data_map.end()) |
| 570 return false; |
| 571 |
| 572 size_t initial_size = urls->size(); |
| 573 for (const ResourceData& resource : it->second.resources()) { |
| 525 float confidence = | 574 float confidence = |
| 526 static_cast<float>(resource.number_of_hits()) / | 575 static_cast<float>(resource.number_of_hits()) / |
| 527 (resource.number_of_hits() + resource.number_of_misses()); | 576 (resource.number_of_hits() + resource.number_of_misses()); |
| 528 if (confidence < config_.min_resource_confidence_to_trigger_prefetch || | 577 if (confidence < config_.min_resource_confidence_to_trigger_prefetch || |
| 529 resource.number_of_hits() < | 578 resource.number_of_hits() < |
| 530 config_.min_resource_hits_to_trigger_prefetch) { | 579 config_.min_resource_hits_to_trigger_prefetch) |
| 531 continue; | 580 continue; |
| 532 } | |
| 533 | 581 |
| 534 urls->push_back(GURL(resource.resource_url())); | 582 urls->push_back(GURL(resource.resource_url())); |
| 535 } | 583 } |
| 584 |
| 585 return urls->size() > initial_size; |
| 536 } | 586 } |
| 537 | 587 |
| 538 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url) { | 588 void ResourcePrefetchPredictor::StartPrefetching(const GURL& url) { |
| 539 if (!prefetch_manager_.get()) // Prefetching not enabled. | 589 if (!prefetch_manager_.get()) // Prefetching not enabled. |
| 540 return; | 590 return; |
| 541 | 591 |
| 542 std::vector<GURL> subresource_urls; | 592 std::vector<GURL> subresource_urls; |
| 543 if (!GetPrefetchData(url, &subresource_urls)) { | 593 if (!GetPrefetchData(url, &subresource_urls)) { |
| 544 // No prefetching data at host or URL level. | 594 // No prefetching data at host or URL level. |
| 545 return; | 595 return; |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 993 } | 1043 } |
| 994 | 1044 |
| 995 if (need_to_add) { | 1045 if (need_to_add) { |
| 996 RedirectStat* redirect_to_add = data.add_redirect_endpoints(); | 1046 RedirectStat* redirect_to_add = data.add_redirect_endpoints(); |
| 997 redirect_to_add->set_url(final_redirect); | 1047 redirect_to_add->set_url(final_redirect); |
| 998 redirect_to_add->set_number_of_hits(1); | 1048 redirect_to_add->set_number_of_hits(1); |
| 999 } | 1049 } |
| 1000 } | 1050 } |
| 1001 | 1051 |
| 1002 RedirectData& data = cache_entry->second; | 1052 RedirectData& data = cache_entry->second; |
| 1003 // Trim and sort the redirects after the update. | 1053 // Trim the redirects after the update. |
| 1004 ResourcePrefetchPredictorTables::TrimRedirects( | 1054 ResourcePrefetchPredictorTables::TrimRedirects( |
| 1005 &data, config_.max_consecutive_misses); | 1055 &data, config_.max_consecutive_misses); |
| 1006 ResourcePrefetchPredictorTables::SortRedirects(&data); | |
| 1007 | 1056 |
| 1008 if (data.redirect_endpoints_size() == 0) { | 1057 if (data.redirect_endpoints_size() == 0) { |
| 1009 redirect_map->erase(cache_entry); | 1058 redirect_map->erase(cache_entry); |
| 1010 BrowserThread::PostTask( | 1059 BrowserThread::PostTask( |
| 1011 BrowserThread::DB, FROM_HERE, | 1060 BrowserThread::DB, FROM_HERE, |
| 1012 base::Bind( | 1061 base::Bind( |
| 1013 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint, | 1062 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint, |
| 1014 tables_, key, key_type)); | 1063 tables_, key, key_type)); |
| 1015 } else { | 1064 } else { |
| 1016 RedirectData empty_redirect_data; | 1065 RedirectData empty_redirect_data; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1068 // HistoryService is already loaded. Continue with Initialization. | 1117 // HistoryService is already loaded. Continue with Initialization. |
| 1069 OnHistoryAndCacheLoaded(); | 1118 OnHistoryAndCacheLoaded(); |
| 1070 return; | 1119 return; |
| 1071 } | 1120 } |
| 1072 DCHECK(!history_service_observer_.IsObserving(history_service)); | 1121 DCHECK(!history_service_observer_.IsObserving(history_service)); |
| 1073 history_service_observer_.Add(history_service); | 1122 history_service_observer_.Add(history_service); |
| 1074 return; | 1123 return; |
| 1075 } | 1124 } |
| 1076 | 1125 |
| 1077 } // namespace predictors | 1126 } // namespace predictors |
| OLD | NEW |