Chromium Code Reviews| 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 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/memory/ptr_util.h" | |
| 13 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/metrics/sparse_histogram.h" | 15 #include "base/metrics/sparse_histogram.h" |
| 15 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 17 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 18 #include "chrome/browser/history/history_service_factory.h" | 19 #include "chrome/browser/history/history_service_factory.h" |
| 19 #include "chrome/browser/predictors/predictor_database.h" | 20 #include "chrome/browser/predictors/predictor_database.h" |
| 20 #include "chrome/browser/predictors/predictor_database_factory.h" | 21 #include "chrome/browser/predictors/predictor_database_factory.h" |
| 21 #include "chrome/browser/predictors/resource_prefetcher_manager.h" | 22 #include "chrome/browser/predictors/resource_prefetcher_manager.h" |
| 22 #include "chrome/browser/profiles/profile.h" | 23 #include "chrome/browser/profiles/profile.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 58 enum ReportingEvent { | 59 enum ReportingEvent { |
| 59 REPORTING_EVENT_ALL_HISTORY_CLEARED = 0, | 60 REPORTING_EVENT_ALL_HISTORY_CLEARED = 0, |
| 60 REPORTING_EVENT_PARTIAL_HISTORY_CLEARED = 1, | 61 REPORTING_EVENT_PARTIAL_HISTORY_CLEARED = 1, |
| 61 REPORTING_EVENT_COUNT = 2 | 62 REPORTING_EVENT_COUNT = 2 |
| 62 }; | 63 }; |
| 63 | 64 |
| 64 } // namespace | 65 } // namespace |
| 65 | 66 |
| 66 namespace predictors { | 67 namespace predictors { |
| 67 | 68 |
| 69 const int kMaxRedirectsPerEntry = 20; | |
| 70 | |
| 68 //////////////////////////////////////////////////////////////////////////////// | 71 //////////////////////////////////////////////////////////////////////////////// |
| 69 // History lookup task. | 72 // History lookup task. |
| 70 | 73 |
| 71 // Used to fetch the visit count for a URL from the History database. | 74 // Used to fetch the visit count for a URL from the History database. |
| 72 class GetUrlVisitCountTask : public history::HistoryDBTask { | 75 class GetUrlVisitCountTask : public history::HistoryDBTask { |
| 73 public: | 76 public: |
| 74 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary; | 77 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary; |
| 75 typedef base::Callback<void( | 78 typedef ResourcePrefetchPredictor::Navigation Navigation; |
| 76 size_t, // Visit count. | 79 typedef base::Callback<void(size_t, // Visit count. |
| 77 const NavigationID&, | 80 const NavigationID&, |
| 78 const std::vector<URLRequestSummary>&)> VisitInfoCallback; | 81 const Navigation&)> |
| 82 VisitInfoCallback; | |
| 79 | 83 |
| 80 GetUrlVisitCountTask( | 84 GetUrlVisitCountTask(const NavigationID& navigation_id, |
| 81 const NavigationID& navigation_id, | 85 std::unique_ptr<Navigation> navigation, |
| 82 std::vector<URLRequestSummary>* requests, | 86 VisitInfoCallback callback) |
| 83 VisitInfoCallback callback) | |
| 84 : visit_count_(0), | 87 : visit_count_(0), |
| 85 navigation_id_(navigation_id), | 88 navigation_id_(navigation_id), |
| 86 requests_(requests), | 89 navigation_(std::move(navigation)), |
| 87 callback_(callback) { | 90 callback_(callback) { |
| 88 DCHECK(requests_.get()); | 91 DCHECK(navigation_.get()); |
| 89 } | 92 } |
| 90 | 93 |
| 91 bool RunOnDBThread(history::HistoryBackend* backend, | 94 bool RunOnDBThread(history::HistoryBackend* backend, |
| 92 history::HistoryDatabase* db) override { | 95 history::HistoryDatabase* db) override { |
| 93 history::URLRow url_row; | 96 history::URLRow url_row; |
| 94 if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row)) | 97 if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row)) |
| 95 visit_count_ = url_row.visit_count(); | 98 visit_count_ = url_row.visit_count(); |
| 96 return true; | 99 return true; |
| 97 } | 100 } |
| 98 | 101 |
| 99 void DoneRunOnMainThread() override { | 102 void DoneRunOnMainThread() override { |
| 100 callback_.Run(visit_count_, navigation_id_, *requests_); | 103 callback_.Run(visit_count_, navigation_id_, *navigation_); |
| 101 } | 104 } |
| 102 | 105 |
| 103 private: | 106 private: |
| 104 ~GetUrlVisitCountTask() override {} | 107 ~GetUrlVisitCountTask() override {} |
| 105 | 108 |
| 106 int visit_count_; | 109 int visit_count_; |
| 107 NavigationID navigation_id_; | 110 NavigationID navigation_id_; |
| 108 std::unique_ptr<std::vector<URLRequestSummary>> requests_; | 111 std::unique_ptr<Navigation> navigation_; |
| 109 VisitInfoCallback callback_; | 112 VisitInfoCallback callback_; |
| 110 | 113 |
| 111 DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask); | 114 DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask); |
| 112 }; | 115 }; |
| 113 | 116 |
| 114 //////////////////////////////////////////////////////////////////////////////// | 117 //////////////////////////////////////////////////////////////////////////////// |
| 115 // ResourcePrefetchPredictor static functions. | 118 // ResourcePrefetchPredictor static functions. |
| 116 | 119 |
| 117 // static | 120 // static |
| 118 bool ResourcePrefetchPredictor::ShouldRecordRequest( | 121 bool ResourcePrefetchPredictor::ShouldRecordRequest( |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 priority(other.priority), | 277 priority(other.priority), |
| 275 mime_type(other.mime_type), | 278 mime_type(other.mime_type), |
| 276 was_cached(other.was_cached), | 279 was_cached(other.was_cached), |
| 277 redirect_url(other.redirect_url), | 280 redirect_url(other.redirect_url), |
| 278 has_validators(other.has_validators), | 281 has_validators(other.has_validators), |
| 279 always_revalidate(other.always_revalidate) {} | 282 always_revalidate(other.always_revalidate) {} |
| 280 | 283 |
| 281 ResourcePrefetchPredictor::URLRequestSummary::~URLRequestSummary() { | 284 ResourcePrefetchPredictor::URLRequestSummary::~URLRequestSummary() { |
| 282 } | 285 } |
| 283 | 286 |
| 287 ResourcePrefetchPredictor::Navigation::Navigation(const GURL& i_initial_url) | |
| 288 : initial_url(i_initial_url) {} | |
| 289 | |
| 290 ResourcePrefetchPredictor::Navigation::~Navigation() {} | |
| 291 | |
| 284 // static | 292 // static |
| 285 bool ResourcePrefetchPredictor::URLRequestSummary::SummarizeResponse( | 293 bool ResourcePrefetchPredictor::URLRequestSummary::SummarizeResponse( |
| 286 const net::URLRequest& request, | 294 const net::URLRequest& request, |
| 287 URLRequestSummary* summary) { | 295 URLRequestSummary* summary) { |
| 288 const content::ResourceRequestInfo* info = | 296 const content::ResourceRequestInfo* info = |
| 289 content::ResourceRequestInfo::ForRequest(&request); | 297 content::ResourceRequestInfo::ForRequest(&request); |
| 290 if (!info) | 298 if (!info) |
| 291 return false; | 299 return false; |
| 292 | 300 |
| 293 int render_process_id, render_frame_id; | 301 int render_process_id, render_frame_id; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 430 const URLRequestSummary& request) { | 438 const URLRequestSummary& request) { |
| 431 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 439 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 432 DCHECK_EQ(INITIALIZED, initialization_state_); | 440 DCHECK_EQ(INITIALIZED, initialization_state_); |
| 433 | 441 |
| 434 StartPrefetching(request.navigation_id); | 442 StartPrefetching(request.navigation_id); |
| 435 | 443 |
| 436 // Cleanup older navigations. | 444 // Cleanup older navigations. |
| 437 CleanupAbandonedNavigations(request.navigation_id); | 445 CleanupAbandonedNavigations(request.navigation_id); |
| 438 | 446 |
| 439 // New empty navigation entry. | 447 // New empty navigation entry. |
| 448 const GURL& initial_url = request.navigation_id.main_frame_url; | |
| 440 inflight_navigations_.insert(std::make_pair( | 449 inflight_navigations_.insert(std::make_pair( |
| 441 request.navigation_id, | 450 request.navigation_id, base::MakeUnique<Navigation>(initial_url))); |
| 442 make_linked_ptr(new std::vector<URLRequestSummary>()))); | |
| 443 } | 451 } |
| 444 | 452 |
| 445 void ResourcePrefetchPredictor::OnMainFrameResponse( | 453 void ResourcePrefetchPredictor::OnMainFrameResponse( |
| 446 const URLRequestSummary& response) { | 454 const URLRequestSummary& response) { |
| 447 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 455 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 448 if (initialization_state_ != INITIALIZED) | 456 if (initialization_state_ != INITIALIZED) |
| 449 return; | 457 return; |
| 450 | 458 |
| 451 StopPrefetching(response.navigation_id); | 459 StopPrefetching(response.navigation_id); |
| 452 } | 460 } |
| 453 | 461 |
| 454 void ResourcePrefetchPredictor::OnMainFrameRedirect( | 462 void ResourcePrefetchPredictor::OnMainFrameRedirect( |
| 455 const URLRequestSummary& response) { | 463 const URLRequestSummary& response) { |
| 456 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 464 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 457 | 465 |
| 458 // TODO(shishir): There are significant gains to be had here if we can use the | 466 // TODO(shishir): There are significant gains to be had here if we can use the |
| 459 // start URL in a redirect chain as the key to start prefetching. We can save | 467 // start URL in a redirect chain as the key to start prefetching. We can save |
| 460 // of redirect times considerably assuming that the redirect chains do not | 468 // of redirect times considerably assuming that the redirect chains do not |
| 461 // change. | 469 // change. |
| 462 | 470 |
| 463 // Stop any inflight prefetching. Remove the older navigation. | 471 // Stop any inflight prefetching. Remove the older navigation. |
| 464 StopPrefetching(response.navigation_id); | 472 StopPrefetching(response.navigation_id); |
| 465 inflight_navigations_.erase(response.navigation_id); | 473 |
| 474 std::unique_ptr<Navigation> navigation; | |
| 475 NavigationMap::iterator nav_it = | |
| 476 inflight_navigations_.find(response.navigation_id); | |
| 477 if (nav_it != inflight_navigations_.end()) { | |
| 478 navigation.reset(nav_it->second.release()); | |
| 479 inflight_navigations_.erase(nav_it); | |
| 480 } | |
| 466 | 481 |
| 467 // A redirect will not lead to another OnMainFrameRequest call, so record the | 482 // A redirect will not lead to another OnMainFrameRequest call, so record the |
| 468 // redirect url as a new navigation. | 483 // redirect url as a new navigation. |
| 469 | 484 |
| 470 // The redirect url may be empty if the URL was invalid. | 485 // The redirect url may be empty if the URL was invalid. |
| 471 if (response.redirect_url.is_empty()) | 486 if (response.redirect_url.is_empty()) |
| 472 return; | 487 return; |
| 473 | 488 |
| 489 // 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.
| |
| 490 if (!navigation) | |
| 491 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.
| |
| 492 | |
| 474 NavigationID navigation_id(response.navigation_id); | 493 NavigationID navigation_id(response.navigation_id); |
| 475 navigation_id.main_frame_url = response.redirect_url; | 494 navigation_id.main_frame_url = response.redirect_url; |
| 476 inflight_navigations_.insert(std::make_pair( | 495 inflight_navigations_.insert( |
| 477 navigation_id, | 496 std::make_pair(navigation_id, std::move(navigation))); |
| 478 make_linked_ptr(new std::vector<URLRequestSummary>()))); | |
| 479 } | 497 } |
| 480 | 498 |
| 481 void ResourcePrefetchPredictor::OnSubresourceResponse( | 499 void ResourcePrefetchPredictor::OnSubresourceResponse( |
| 482 const URLRequestSummary& response) { | 500 const URLRequestSummary& response) { |
| 483 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 501 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 484 | 502 |
| 485 NavigationMap::const_iterator nav_it = | 503 NavigationMap::const_iterator nav_it = |
| 486 inflight_navigations_.find(response.navigation_id); | 504 inflight_navigations_.find(response.navigation_id); |
| 487 if (nav_it == inflight_navigations_.end()) { | 505 if (nav_it == inflight_navigations_.end()) { |
| 488 return; | 506 return; |
| 489 } | 507 } |
| 490 | 508 |
| 491 nav_it->second->push_back(response); | 509 nav_it->second->subresource_requests.push_back(response); |
| 492 } | 510 } |
| 493 | 511 |
| 494 void ResourcePrefetchPredictor::OnNavigationComplete( | 512 void ResourcePrefetchPredictor::OnNavigationComplete( |
| 495 const NavigationID& nav_id_without_timing_info) { | 513 const NavigationID& nav_id_without_timing_info) { |
| 496 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 514 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 497 | 515 |
| 498 NavigationMap::iterator nav_it = | 516 NavigationMap::iterator nav_it = |
| 499 inflight_navigations_.find(nav_id_without_timing_info); | 517 inflight_navigations_.find(nav_id_without_timing_info); |
| 500 if (nav_it == inflight_navigations_.end()) | 518 if (nav_it == inflight_navigations_.end()) |
| 501 return; | 519 return; |
| 502 | 520 |
| 503 const NavigationID navigation_id(nav_it->first); | 521 const NavigationID navigation_id(nav_it->first); |
| 504 | 522 |
| 505 // Remove the navigation from the inflight navigations. | 523 // Remove the navigation from the inflight navigations. |
| 506 std::vector<URLRequestSummary>* requests = (nav_it->second).release(); | 524 std::unique_ptr<Navigation> navigation = std::move(nav_it->second); |
| 507 inflight_navigations_.erase(nav_it); | 525 inflight_navigations_.erase(nav_it); |
| 508 | 526 |
| 509 // Kick off history lookup to determine if we should record the URL. | 527 // Kick off history lookup to determine if we should record the URL. |
| 510 history::HistoryService* history_service = | 528 history::HistoryService* history_service = |
| 511 HistoryServiceFactory::GetForProfile(profile_, | 529 HistoryServiceFactory::GetForProfile(profile_, |
| 512 ServiceAccessType::EXPLICIT_ACCESS); | 530 ServiceAccessType::EXPLICIT_ACCESS); |
| 513 DCHECK(history_service); | 531 DCHECK(history_service); |
| 514 history_service->ScheduleDBTask( | 532 history_service->ScheduleDBTask( |
| 515 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask( | 533 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask( |
| 516 navigation_id, requests, | 534 navigation_id, std::move(navigation), |
| 517 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup, | 535 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup, |
| 518 AsWeakPtr()))), | 536 AsWeakPtr()))), |
| 519 &history_lookup_consumer_); | 537 &history_lookup_consumer_); |
| 520 } | 538 } |
| 521 | 539 |
| 522 bool ResourcePrefetchPredictor::GetPrefetchData( | 540 bool ResourcePrefetchPredictor::GetPrefetchData( |
| 523 const NavigationID& navigation_id, | 541 const NavigationID& navigation_id, |
| 524 ResourcePrefetcher::RequestVector* prefetch_requests, | 542 ResourcePrefetcher::RequestVector* prefetch_requests, |
| 525 PrefetchKeyType* key_type) { | 543 PrefetchKeyType* key_type) { |
| 526 DCHECK(prefetch_requests); | 544 DCHECK(prefetch_requests); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 609 navigation_id)); | 627 navigation_id)); |
| 610 } | 628 } |
| 611 | 629 |
| 612 void ResourcePrefetchPredictor::StartInitialization() { | 630 void ResourcePrefetchPredictor::StartInitialization() { |
| 613 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 631 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 614 | 632 |
| 615 DCHECK_EQ(NOT_INITIALIZED, initialization_state_); | 633 DCHECK_EQ(NOT_INITIALIZED, initialization_state_); |
| 616 initialization_state_ = INITIALIZING; | 634 initialization_state_ = INITIALIZING; |
| 617 | 635 |
| 618 // Create local caches using the database as loaded. | 636 // Create local caches using the database as loaded. |
| 619 std::unique_ptr<PrefetchDataMap> url_data_map(new PrefetchDataMap()); | 637 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.
| |
| 620 std::unique_ptr<PrefetchDataMap> host_data_map(new PrefetchDataMap()); | 638 std::unique_ptr<PrefetchDataMap> host_data_map(new PrefetchDataMap()); |
| 639 std::unique_ptr<RedirectDataMap> url_redirect_data_map(new RedirectDataMap()); | |
| 640 std::unique_ptr<RedirectDataMap> host_redirect_data_map( | |
| 641 new RedirectDataMap()); | |
| 621 PrefetchDataMap* url_data_ptr = url_data_map.get(); | 642 PrefetchDataMap* url_data_ptr = url_data_map.get(); |
| 622 PrefetchDataMap* host_data_ptr = host_data_map.get(); | 643 PrefetchDataMap* host_data_ptr = host_data_map.get(); |
| 644 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.
| |
| 645 RedirectDataMap* host_redirect_data_ptr = host_redirect_data_map.get(); | |
| 623 | 646 |
| 624 BrowserThread::PostTaskAndReply( | 647 BrowserThread::PostTaskAndReply( |
| 625 BrowserThread::DB, FROM_HERE, | 648 BrowserThread::DB, FROM_HERE, |
| 626 base::Bind(&ResourcePrefetchPredictorTables::GetAllData, | 649 base::Bind(&ResourcePrefetchPredictorTables::GetAllData, tables_, |
| 627 tables_, url_data_ptr, host_data_ptr), | 650 url_data_ptr, host_data_ptr, url_redirect_data_ptr, |
| 651 host_redirect_data_ptr), | |
| 628 base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(), | 652 base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(), |
| 629 base::Passed(&url_data_map), base::Passed(&host_data_map))); | 653 base::Passed(&url_data_map), base::Passed(&host_data_map), |
| 654 base::Passed(&url_redirect_data_map), | |
| 655 base::Passed(&host_redirect_data_map))); | |
| 630 } | 656 } |
| 631 | 657 |
| 632 void ResourcePrefetchPredictor::CreateCaches( | 658 void ResourcePrefetchPredictor::CreateCaches( |
| 633 std::unique_ptr<PrefetchDataMap> url_data_map, | 659 std::unique_ptr<PrefetchDataMap> url_data_map, |
| 634 std::unique_ptr<PrefetchDataMap> host_data_map) { | 660 std::unique_ptr<PrefetchDataMap> host_data_map, |
| 661 std::unique_ptr<RedirectDataMap> url_redirect_data_map, | |
| 662 std::unique_ptr<RedirectDataMap> host_redirect_data_map) { | |
| 635 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 663 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 636 | 664 |
| 637 DCHECK_EQ(INITIALIZING, initialization_state_); | 665 DCHECK_EQ(INITIALIZING, initialization_state_); |
| 638 DCHECK(!url_table_cache_); | 666 DCHECK(!url_table_cache_); |
| 639 DCHECK(!host_table_cache_); | 667 DCHECK(!host_table_cache_); |
| 668 DCHECK(!url_redirect_table_cache_); | |
| 669 DCHECK(!host_redirect_table_cache_); | |
| 640 DCHECK(inflight_navigations_.empty()); | 670 DCHECK(inflight_navigations_.empty()); |
| 641 | 671 |
| 642 url_table_cache_.reset(url_data_map.release()); | 672 url_table_cache_.reset(url_data_map.release()); |
| 643 host_table_cache_.reset(host_data_map.release()); | 673 host_table_cache_.reset(host_data_map.release()); |
| 674 url_redirect_table_cache_.reset(url_redirect_data_map.release()); | |
| 675 host_redirect_table_cache_.reset(host_redirect_data_map.release()); | |
| 644 | 676 |
| 645 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount", | 677 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount", |
| 646 url_table_cache_->size()); | 678 url_table_cache_->size()); |
| 647 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HostTableHostCount", | 679 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HostTableHostCount", |
| 648 host_table_cache_->size()); | 680 host_table_cache_->size()); |
| 649 | 681 |
| 650 ConnectToHistoryService(); | 682 ConnectToHistoryService(); |
| 651 } | 683 } |
| 652 | 684 |
| 653 void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() { | 685 void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 710 } | 742 } |
| 711 | 743 |
| 712 const std::string& host = it.url().host(); | 744 const std::string& host = it.url().host(); |
| 713 if (host_table_cache_->find(host) != host_table_cache_->end()) { | 745 if (host_table_cache_->find(host) != host_table_cache_->end()) { |
| 714 hosts_to_delete.push_back(host); | 746 hosts_to_delete.push_back(host); |
| 715 host_table_cache_->erase(host); | 747 host_table_cache_->erase(host); |
| 716 } | 748 } |
| 717 } | 749 } |
| 718 | 750 |
| 719 if (!urls_to_delete.empty() || !hosts_to_delete.empty()) { | 751 if (!urls_to_delete.empty() || !hosts_to_delete.empty()) { |
| 720 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | 752 BrowserThread::PostTask( |
| 721 base::Bind(&ResourcePrefetchPredictorTables::DeleteData, | 753 BrowserThread::DB, FROM_HERE, |
| 722 tables_, | 754 base::Bind(&ResourcePrefetchPredictorTables::DeleteResourceData, |
| 723 urls_to_delete, | 755 tables_, urls_to_delete, hosts_to_delete)); |
| 724 hosts_to_delete)); | |
| 725 } | 756 } |
| 726 } | 757 } |
| 727 | 758 |
| 728 void ResourcePrefetchPredictor::RemoveOldestEntryInPrefetchDataMap( | 759 void ResourcePrefetchPredictor::RemoveOldestEntryInPrefetchDataMap( |
| 729 PrefetchKeyType key_type, | 760 PrefetchKeyType key_type, |
| 730 PrefetchDataMap* data_map) { | 761 PrefetchDataMap* data_map) { |
| 731 if (data_map->empty()) | 762 if (data_map->empty()) |
| 732 return; | 763 return; |
| 733 | 764 |
| 734 base::Time oldest_time; | 765 base::Time oldest_time; |
| 735 std::string key_to_delete; | 766 std::string key_to_delete; |
| 736 for (PrefetchDataMap::iterator it = data_map->begin(); | 767 for (PrefetchDataMap::iterator it = data_map->begin(); |
| 737 it != data_map->end(); ++it) { | 768 it != data_map->end(); ++it) { |
| 738 if (key_to_delete.empty() || it->second.last_visit < oldest_time) { | 769 if (key_to_delete.empty() || it->second.last_visit < oldest_time) { |
| 739 key_to_delete = it->first; | 770 key_to_delete = it->first; |
| 740 oldest_time = it->second.last_visit; | 771 oldest_time = it->second.last_visit; |
| 741 } | 772 } |
| 742 } | 773 } |
| 743 | 774 |
| 744 data_map->erase(key_to_delete); | 775 data_map->erase(key_to_delete); |
| 745 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, | 776 BrowserThread::PostTask( |
| 746 base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint, | 777 BrowserThread::DB, FROM_HERE, |
| 747 tables_, | 778 base::Bind( |
| 748 key_to_delete, | 779 &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint, |
| 749 key_type)); | 780 tables_, key_to_delete, key_type)); |
| 781 } | |
| 782 | |
| 783 void ResourcePrefetchPredictor::RemoveOldestEntryInRedirectDataMap( | |
| 784 PrefetchKeyType key_type, | |
| 785 RedirectDataMap* data_map) { | |
| 786 if (data_map->empty()) | |
| 787 return; | |
| 788 | |
| 789 uint64_t oldest_time; | |
| 790 std::string key_to_delete; | |
| 791 for (const auto& kv : *data_map) { | |
| 792 const RedirectData& data = kv.second; | |
| 793 if (key_to_delete.empty() || data.last_visit_time() < oldest_time) { | |
| 794 key_to_delete = data.primary_key(); | |
| 795 oldest_time = data.last_visit_time(); | |
| 796 } | |
| 797 } | |
| 798 | |
| 799 data_map->erase(key_to_delete); | |
| 800 BrowserThread::PostTask( | |
| 801 BrowserThread::DB, FROM_HERE, | |
| 802 base::Bind( | |
| 803 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint, | |
| 804 tables_, key_to_delete, key_type)); | |
| 750 } | 805 } |
| 751 | 806 |
| 752 void ResourcePrefetchPredictor::OnVisitCountLookup( | 807 void ResourcePrefetchPredictor::OnVisitCountLookup( |
| 753 size_t visit_count, | 808 size_t visit_count, |
| 754 const NavigationID& navigation_id, | 809 const NavigationID& navigation_id, |
| 755 const std::vector<URLRequestSummary>& requests) { | 810 const Navigation& navigation) { |
| 756 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 811 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 757 | 812 |
| 758 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl", | 813 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl", |
| 759 visit_count); | 814 visit_count); |
| 760 | 815 |
| 816 // TODO(alexilin) make only one request to DB thread | |
| 817 | |
| 761 // URL level data - merge only if we are already saving the data, or we it | 818 // URL level data - merge only if we are already saving the data, or we it |
| 762 // meets the cutoff requirement. | 819 // meets the cutoff requirement. |
| 763 const std::string url_spec = navigation_id.main_frame_url.spec(); | 820 const std::string url_spec = navigation_id.main_frame_url.spec(); |
| 764 bool already_tracking = url_table_cache_->find(url_spec) != | 821 bool already_tracking = url_table_cache_->find(url_spec) != |
| 765 url_table_cache_->end(); | 822 url_table_cache_->end(); |
| 766 bool should_track_url = already_tracking || | 823 bool should_track_url = already_tracking || |
| 767 (visit_count >= config_.min_url_visit_count); | 824 (visit_count >= config_.min_url_visit_count); |
| 768 | 825 |
| 769 if (should_track_url && config_.IsURLLearningEnabled()) { | 826 if (should_track_url && config_.IsURLLearningEnabled()) { |
| 770 LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL, requests, | 827 LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL, |
| 771 config_.max_urls_to_track, url_table_cache_.get()); | 828 navigation.subresource_requests, config_.max_urls_to_track, |
| 829 url_table_cache_.get(), navigation.initial_url.spec(), | |
| 830 url_redirect_table_cache_.get()); | |
| 772 } | 831 } |
| 773 | 832 |
| 774 // Host level data - no cutoff, always learn the navigation if enabled. | 833 // Host level data - no cutoff, always learn the navigation if enabled. |
| 775 if (config_.IsHostLearningEnabled()) { | 834 if (config_.IsHostLearningEnabled()) { |
| 776 LearnNavigation(navigation_id.main_frame_url.host(), | 835 const std::string host = navigation_id.main_frame_url.host(); |
| 777 PREFETCH_KEY_TYPE_HOST, | 836 LearnNavigation(host, PREFETCH_KEY_TYPE_HOST, |
| 778 requests, | 837 navigation.subresource_requests, config_.max_hosts_to_track, |
| 779 config_.max_hosts_to_track, | 838 host_table_cache_.get(), navigation.initial_url.host(), |
| 780 host_table_cache_.get()); | 839 host_redirect_table_cache_.get()); |
| 781 } | 840 } |
| 782 | 841 |
| 783 // Remove the navigation from the results map. | 842 // Remove the navigation from the results map. |
| 784 results_map_.erase(navigation_id); | 843 results_map_.erase(navigation_id); |
| 785 } | 844 } |
| 786 | 845 |
| 787 void ResourcePrefetchPredictor::LearnNavigation( | 846 void ResourcePrefetchPredictor::LearnNavigation( |
| 788 const std::string& key, | 847 const std::string& key, |
| 789 PrefetchKeyType key_type, | 848 PrefetchKeyType key_type, |
| 790 const std::vector<URLRequestSummary>& new_resources, | 849 const std::vector<URLRequestSummary>& new_resources, |
| 791 size_t max_data_map_size, | 850 size_t max_data_map_size, |
| 792 PrefetchDataMap* data_map) { | 851 PrefetchDataMap* data_map, |
| 852 const std::string& redirect_origin_key, | |
| 853 RedirectDataMap* redirect_map) { | |
| 793 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 854 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 794 | 855 |
| 795 // If the primary key is too long reject it. | 856 // If the primary key is too long reject it. |
| 796 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength) | 857 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength) |
| 797 return; | 858 return; |
| 798 | 859 |
| 799 PrefetchDataMap::iterator cache_entry = data_map->find(key); | 860 PrefetchDataMap::iterator cache_entry = data_map->find(key); |
| 800 if (cache_entry == data_map->end()) { | 861 if (cache_entry == data_map->end()) { |
| 801 if (data_map->size() >= max_data_map_size) { | 862 // If the table is full, delete an entry. |
| 802 // The table is full, delete an entry. | 863 if (data_map->size() >= max_data_map_size) |
| 803 RemoveOldestEntryInPrefetchDataMap(key_type, data_map); | 864 RemoveOldestEntryInPrefetchDataMap(key_type, data_map); |
| 804 } | |
| 805 | 865 |
| 806 cache_entry = data_map->insert(std::make_pair( | 866 cache_entry = data_map->insert(std::make_pair( |
| 807 key, PrefetchData(key_type, key))).first; | 867 key, PrefetchData(key_type, key))).first; |
| 808 cache_entry->second.last_visit = base::Time::Now(); | 868 cache_entry->second.last_visit = base::Time::Now(); |
| 809 size_t new_resources_size = new_resources.size(); | 869 size_t new_resources_size = new_resources.size(); |
| 810 std::set<GURL> resources_seen; | 870 std::set<GURL> resources_seen; |
| 811 for (size_t i = 0; i < new_resources_size; ++i) { | 871 for (size_t i = 0; i < new_resources_size; ++i) { |
| 812 if (resources_seen.find(new_resources[i].resource_url) != | 872 if (resources_seen.find(new_resources[i].resource_url) != |
| 813 resources_seen.end()) { | 873 resources_seen.end()) { |
| 814 continue; | 874 continue; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 914 ResourcePrefetchPredictorTables::SortResources(&resources); | 974 ResourcePrefetchPredictorTables::SortResources(&resources); |
| 915 if (resources.size() > config_.max_resources_per_entry) | 975 if (resources.size() > config_.max_resources_per_entry) |
| 916 resources.resize(config_.max_resources_per_entry); | 976 resources.resize(config_.max_resources_per_entry); |
| 917 | 977 |
| 918 // If the row has no resources, remove it from the cache and delete the | 978 // If the row has no resources, remove it from the cache and delete the |
| 919 // entry in the database. Else update the database. | 979 // entry in the database. Else update the database. |
| 920 if (resources.empty()) { | 980 if (resources.empty()) { |
| 921 data_map->erase(key); | 981 data_map->erase(key); |
| 922 BrowserThread::PostTask( | 982 BrowserThread::PostTask( |
| 923 BrowserThread::DB, FROM_HERE, | 983 BrowserThread::DB, FROM_HERE, |
| 924 base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint, | 984 base::Bind( |
| 925 tables_, | 985 &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint, |
| 926 key, | 986 tables_, key, key_type)); |
| 927 key_type)); | |
| 928 } else { | 987 } else { |
| 929 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; | 988 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; |
| 930 PrefetchData empty_data( | 989 PrefetchData empty_data( |
| 931 !is_host ? PREFETCH_KEY_TYPE_HOST : PREFETCH_KEY_TYPE_URL, | 990 !is_host ? PREFETCH_KEY_TYPE_HOST : PREFETCH_KEY_TYPE_URL, |
| 932 std::string()); | 991 std::string()); |
| 992 RedirectData empty_redirect_data; | |
| 933 const PrefetchData& host_data = is_host ? cache_entry->second : empty_data; | 993 const PrefetchData& host_data = is_host ? cache_entry->second : empty_data; |
| 934 const PrefetchData& url_data = is_host ? empty_data : cache_entry->second; | 994 const PrefetchData& url_data = is_host ? empty_data : cache_entry->second; |
| 935 BrowserThread::PostTask( | 995 BrowserThread::PostTask( |
| 936 BrowserThread::DB, FROM_HERE, | 996 BrowserThread::DB, FROM_HERE, |
| 937 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, | 997 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_, |
| 938 tables_, | 998 url_data, host_data, empty_redirect_data, |
| 939 url_data, | 999 empty_redirect_data)); |
| 940 host_data)); | 1000 } |
| 1001 | |
| 1002 if (key != redirect_origin_key) { | |
| 1003 LearnRedirect(redirect_origin_key, key_type, key, max_data_map_size, | |
| 1004 redirect_map); | |
| 941 } | 1005 } |
| 942 } | 1006 } |
| 943 | 1007 |
| 1008 void ResourcePrefetchPredictor::LearnRedirect(const std::string& key, | |
| 1009 PrefetchKeyType key_type, | |
| 1010 const std::string& final_redirect, | |
| 1011 size_t max_redirect_map_size, | |
| 1012 RedirectDataMap* redirect_map) { | |
| 1013 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 1014 | |
| 1015 RedirectDataMap::iterator cache_entry = redirect_map->find(key); | |
| 1016 if (cache_entry == redirect_map->end()) { | |
| 1017 if (redirect_map->size() >= max_redirect_map_size) | |
| 1018 RemoveOldestEntryInRedirectDataMap(key_type, redirect_map); | |
| 1019 | |
| 1020 RedirectData new_data; | |
| 1021 new_data.set_primary_key(key); | |
| 1022 cache_entry = redirect_map->insert(std::make_pair(key, new_data)).first; | |
| 1023 cache_entry->second.set_last_visit_time( | |
| 1024 base::Time::Now().ToInternalValue()); | |
| 1025 RedirectStat* redirect_to_add = cache_entry->second.add_redirects(); | |
| 1026 redirect_to_add->set_url(final_redirect); | |
| 1027 redirect_to_add->set_number_of_hits(1); | |
| 1028 } else { | |
| 1029 bool need_to_add = true; | |
| 1030 cache_entry->second.set_last_visit_time( | |
| 1031 base::Time::Now().ToInternalValue()); | |
| 1032 | |
| 1033 for (RedirectStat& redirect : *(cache_entry->second.mutable_redirects())) { | |
| 1034 if (redirect.url() == final_redirect) { | |
| 1035 need_to_add = false; | |
| 1036 redirect.set_number_of_hits(redirect.number_of_hits() + 1); | |
| 1037 redirect.set_consecutive_misses(0); | |
| 1038 } else { | |
| 1039 redirect.set_number_of_misses(redirect.number_of_misses() + 1); | |
| 1040 redirect.set_consecutive_misses(redirect.consecutive_misses() + 1); | |
| 1041 } | |
| 1042 } | |
| 1043 | |
| 1044 if (need_to_add) { | |
| 1045 RedirectStat* redirect_to_add = cache_entry->second.add_redirects(); | |
| 1046 redirect_to_add->set_url(final_redirect); | |
| 1047 redirect_to_add->set_number_of_hits(1); | |
| 1048 } | |
| 1049 } | |
| 1050 | |
| 1051 // Trim and sort redirects after update. | |
| 1052 std::vector<RedirectStat> redirects; | |
| 1053 redirects.reserve(cache_entry->second.redirects_size()); | |
| 1054 for (const RedirectStat& redirect : cache_entry->second.redirects()) { | |
| 1055 if (redirect.consecutive_misses() < config_.max_consecutive_misses) | |
| 1056 redirects.push_back(redirect); | |
| 1057 } | |
| 1058 ResourcePrefetchPredictorTables::SortRedirects(&redirects); | |
| 1059 | |
| 1060 if (redirects.size() > kMaxRedirectsPerEntry) | |
| 1061 redirects.resize(kMaxRedirectsPerEntry); | |
| 1062 | |
| 1063 cache_entry->second.clear_redirects(); | |
| 1064 for (const RedirectStat& redirect : redirects) | |
| 1065 cache_entry->second.add_redirects()->CopyFrom(redirect); | |
| 1066 | |
| 1067 if (redirects.empty()) { | |
| 1068 redirect_map->erase(cache_entry); | |
| 1069 BrowserThread::PostTask( | |
| 1070 BrowserThread::DB, FROM_HERE, | |
| 1071 base::Bind( | |
| 1072 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint, | |
| 1073 tables_, key, key_type)); | |
| 1074 } else { | |
| 1075 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; | |
| 1076 RedirectData empty_redirect_data; | |
| 1077 PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string()); | |
| 1078 PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string()); | |
| 1079 const RedirectData& host_redirect_data = | |
| 1080 is_host ? cache_entry->second : empty_redirect_data; | |
| 1081 const RedirectData& url_redirect_data = | |
| 1082 is_host ? empty_redirect_data : cache_entry->second; | |
| 1083 BrowserThread::PostTask( | |
| 1084 BrowserThread::DB, FROM_HERE, | |
| 1085 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_, | |
| 1086 empty_url_data, empty_host_data, url_redirect_data, | |
| 1087 host_redirect_data)); | |
| 1088 } | |
| 1089 } | |
| 1090 | |
| 944 void ResourcePrefetchPredictor::OnURLsDeleted( | 1091 void ResourcePrefetchPredictor::OnURLsDeleted( |
| 945 history::HistoryService* history_service, | 1092 history::HistoryService* history_service, |
| 946 bool all_history, | 1093 bool all_history, |
| 947 bool expired, | 1094 bool expired, |
| 948 const history::URLRows& deleted_rows, | 1095 const history::URLRows& deleted_rows, |
| 949 const std::set<GURL>& favicon_urls) { | 1096 const std::set<GURL>& favicon_urls) { |
| 950 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1097 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 951 if (INITIALIZED != initialization_state_) | 1098 if (INITIALIZED != initialization_state_) |
| 952 return; | 1099 return; |
| 953 | 1100 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 981 // HistoryService is already loaded. Continue with Initialization. | 1128 // HistoryService is already loaded. Continue with Initialization. |
| 982 OnHistoryAndCacheLoaded(); | 1129 OnHistoryAndCacheLoaded(); |
| 983 return; | 1130 return; |
| 984 } | 1131 } |
| 985 DCHECK(!history_service_observer_.IsObserving(history_service)); | 1132 DCHECK(!history_service_observer_.IsObserving(history_service)); |
| 986 history_service_observer_.Add(history_service); | 1133 history_service_observer_.Add(history_service); |
| 987 return; | 1134 return; |
| 988 } | 1135 } |
| 989 | 1136 |
| 990 } // namespace predictors | 1137 } // namespace predictors |
| OLD | NEW |