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

Side by Side Diff: chrome/browser/predictors/resource_prefetch_predictor.cc

Issue 2355273002: Redirect handling in the resource_prefetch_predictor. (Closed)
Patch Set: Revert table names, delete sensitive data, refactor. Created 4 years, 2 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 unified diff | Download patch
OLDNEW
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"
23 #include "chrome/common/chrome_switches.h" 24 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/url_constants.h" 25 #include "chrome/common/url_constants.h"
25 #include "components/history/core/browser/history_database.h" 26 #include "components/history/core/browser/history_database.h"
26 #include "components/history/core/browser/history_db_task.h"
27 #include "components/history/core/browser/history_service.h" 27 #include "components/history/core/browser/history_service.h"
28 #include "components/mime_util/mime_util.h" 28 #include "components/mime_util/mime_util.h"
29 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/navigation_controller.h" 30 #include "content/public/browser/navigation_controller.h"
31 #include "content/public/browser/resource_request_info.h" 31 #include "content/public/browser/resource_request_info.h"
32 #include "content/public/browser/web_contents.h" 32 #include "content/public/browser/web_contents.h"
33 #include "net/base/mime_util.h" 33 #include "net/base/mime_util.h"
34 #include "net/base/network_change_notifier.h" 34 #include "net/base/network_change_notifier.h"
35 #include "net/http/http_response_headers.h" 35 #include "net/http/http_response_headers.h"
36 #include "net/url_request/url_request.h" 36 #include "net/url_request/url_request.h"
(...skipping 21 matching lines...) Expand all
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 } // namespace 64 } // namespace
65 65
66 namespace predictors { 66 namespace predictors {
67 67
68 //////////////////////////////////////////////////////////////////////////////// 68 const int kMaxRedirectsPerEntry = 20;
69 // History lookup task.
70
71 // Used to fetch the visit count for a URL from the History database.
72 class GetUrlVisitCountTask : public history::HistoryDBTask {
73 public:
74 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
75 typedef base::Callback<void(
76 size_t, // Visit count.
77 const NavigationID&,
78 const std::vector<URLRequestSummary>&)> VisitInfoCallback;
79
80 GetUrlVisitCountTask(
81 const NavigationID& navigation_id,
82 std::vector<URLRequestSummary>* requests,
83 VisitInfoCallback callback)
84 : visit_count_(0),
85 navigation_id_(navigation_id),
86 requests_(requests),
87 callback_(callback) {
88 DCHECK(requests_.get());
89 }
90
91 bool RunOnDBThread(history::HistoryBackend* backend,
92 history::HistoryDatabase* db) override {
93 history::URLRow url_row;
94 if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
95 visit_count_ = url_row.visit_count();
96 return true;
97 }
98
99 void DoneRunOnMainThread() override {
100 callback_.Run(visit_count_, navigation_id_, *requests_);
101 }
102
103 private:
104 ~GetUrlVisitCountTask() override {}
105
106 int visit_count_;
107 NavigationID navigation_id_;
108 std::unique_ptr<std::vector<URLRequestSummary>> requests_;
109 VisitInfoCallback callback_;
110
111 DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask);
112 };
113 69
114 //////////////////////////////////////////////////////////////////////////////// 70 ////////////////////////////////////////////////////////////////////////////////
115 // ResourcePrefetchPredictor static functions. 71 // ResourcePrefetchPredictor static functions.
116 72
117 // static 73 // static
118 bool ResourcePrefetchPredictor::ShouldRecordRequest( 74 bool ResourcePrefetchPredictor::ShouldRecordRequest(
119 net::URLRequest* request, 75 net::URLRequest* request,
120 content::ResourceType resource_type) { 76 content::ResourceType resource_type) {
121 const content::ResourceRequestInfo* request_info = 77 const content::ResourceRequestInfo* request_info =
122 content::ResourceRequestInfo::ForRequest(request); 78 content::ResourceRequestInfo::ForRequest(request);
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 [&mime_type](const std::string& mime) { 206 [&mime_type](const std::string& mime) {
251 return net::MatchesMimeType(mime, mime_type); 207 return net::MatchesMimeType(mime, mime_type);
252 }); 208 });
253 if (found) 209 if (found)
254 return content::RESOURCE_TYPE_FONT_RESOURCE; 210 return content::RESOURCE_TYPE_FONT_RESOURCE;
255 } 211 }
256 return fallback; 212 return fallback;
257 } 213 }
258 214
259 //////////////////////////////////////////////////////////////////////////////// 215 ////////////////////////////////////////////////////////////////////////////////
260 // ResourcePrefetchPredictor structs. 216 // ResourcePrefetchPredictor nested types.
261 217
262 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary() 218 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary()
263 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), 219 : resource_type(content::RESOURCE_TYPE_LAST_TYPE),
264 priority(net::IDLE), 220 priority(net::IDLE),
265 was_cached(false), 221 was_cached(false),
266 has_validators(false), 222 has_validators(false),
267 always_revalidate(false) {} 223 always_revalidate(false) {}
268 224
269 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary( 225 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary(
270 const URLRequestSummary& other) 226 const URLRequestSummary& other)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 summary->has_validators = headers->HasValidators(); 267 summary->has_validators = headers->HasValidators();
312 // RFC 2616, section 14.9. 268 // RFC 2616, section 14.9.
313 summary->always_revalidate = 269 summary->always_revalidate =
314 headers->HasHeaderValue("cache-control", "no-cache") || 270 headers->HasHeaderValue("cache-control", "no-cache") ||
315 headers->HasHeaderValue("pragma", "no-cache") || 271 headers->HasHeaderValue("pragma", "no-cache") ||
316 headers->HasHeaderValue("vary", "*"); 272 headers->HasHeaderValue("vary", "*");
317 } 273 }
318 return true; 274 return true;
319 } 275 }
320 276
277 ResourcePrefetchPredictor::GetUrlVisitCountTask::GetUrlVisitCountTask(
278 const NavigationID& navigation_id,
279 std::unique_ptr<PageRequestSummary> summary,
280 VisitInfoCallback callback)
281 : visit_count_(0),
282 navigation_id_(navigation_id),
283 summary_(std::move(summary)),
284 callback_(callback) {
285 DCHECK(summary_.get());
286 }
287
288 bool ResourcePrefetchPredictor::GetUrlVisitCountTask::RunOnDBThread(
289 history::HistoryBackend* backend,
290 history::HistoryDatabase* db) {
291 history::URLRow url_row;
292 if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
293 visit_count_ = url_row.visit_count();
294 return true;
295 }
296
297 void ResourcePrefetchPredictor::GetUrlVisitCountTask::DoneRunOnMainThread() {
298 callback_.Run(visit_count_, navigation_id_, *summary_);
299 }
300
301 ResourcePrefetchPredictor::GetUrlVisitCountTask::~GetUrlVisitCountTask() {}
302
303 ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary(
304 const GURL& i_initial_url)
305 : initial_url(i_initial_url) {}
306
307 ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {}
308
321 //////////////////////////////////////////////////////////////////////////////// 309 ////////////////////////////////////////////////////////////////////////////////
322 // ResourcePrefetchPredictor. 310 // ResourcePrefetchPredictor.
323 311
324 ResourcePrefetchPredictor::ResourcePrefetchPredictor( 312 ResourcePrefetchPredictor::ResourcePrefetchPredictor(
325 const ResourcePrefetchPredictorConfig& config, 313 const ResourcePrefetchPredictorConfig& config,
326 Profile* profile) 314 Profile* profile)
327 : profile_(profile), 315 : profile_(profile),
328 config_(config), 316 config_(config),
329 initialization_state_(NOT_INITIALIZED), 317 initialization_state_(NOT_INITIALIZED),
330 tables_(PredictorDatabaseFactory::GetForProfile(profile) 318 tables_(PredictorDatabaseFactory::GetForProfile(profile)
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 const URLRequestSummary& request) { 395 const URLRequestSummary& request) {
408 DCHECK_CURRENTLY_ON(BrowserThread::UI); 396 DCHECK_CURRENTLY_ON(BrowserThread::UI);
409 DCHECK_EQ(INITIALIZED, initialization_state_); 397 DCHECK_EQ(INITIALIZED, initialization_state_);
410 398
411 StartPrefetching(request.navigation_id); 399 StartPrefetching(request.navigation_id);
412 400
413 // Cleanup older navigations. 401 // Cleanup older navigations.
414 CleanupAbandonedNavigations(request.navigation_id); 402 CleanupAbandonedNavigations(request.navigation_id);
415 403
416 // New empty navigation entry. 404 // New empty navigation entry.
417 inflight_navigations_.insert(std::make_pair( 405 const GURL& initial_url = request.navigation_id.main_frame_url;
418 request.navigation_id, 406 inflight_navigations_.insert(
419 make_linked_ptr(new std::vector<URLRequestSummary>()))); 407 std::make_pair(request.navigation_id,
408 base::MakeUnique<PageRequestSummary>(initial_url)));
420 } 409 }
421 410
422 void ResourcePrefetchPredictor::OnMainFrameResponse( 411 void ResourcePrefetchPredictor::OnMainFrameResponse(
423 const URLRequestSummary& response) { 412 const URLRequestSummary& response) {
424 DCHECK_CURRENTLY_ON(BrowserThread::UI); 413 DCHECK_CURRENTLY_ON(BrowserThread::UI);
425 if (initialization_state_ != INITIALIZED) 414 if (initialization_state_ != INITIALIZED)
426 return; 415 return;
427 416
428 StopPrefetching(response.navigation_id); 417 StopPrefetching(response.navigation_id);
429 } 418 }
430 419
431 void ResourcePrefetchPredictor::OnMainFrameRedirect( 420 void ResourcePrefetchPredictor::OnMainFrameRedirect(
432 const URLRequestSummary& response) { 421 const URLRequestSummary& response) {
433 DCHECK_CURRENTLY_ON(BrowserThread::UI); 422 DCHECK_CURRENTLY_ON(BrowserThread::UI);
434 423
435 // TODO(shishir): There are significant gains to be had here if we can use the
436 // start URL in a redirect chain as the key to start prefetching. We can save
437 // of redirect times considerably assuming that the redirect chains do not
438 // change.
439
440 // Stop any inflight prefetching. Remove the older navigation. 424 // Stop any inflight prefetching. Remove the older navigation.
441 StopPrefetching(response.navigation_id); 425 StopPrefetching(response.navigation_id);
442 inflight_navigations_.erase(response.navigation_id);
443 426
444 // A redirect will not lead to another OnMainFrameRequest call, so record the 427 std::unique_ptr<PageRequestSummary> summary;
445 // redirect url as a new navigation. 428 NavigationMap::iterator nav_it =
429 inflight_navigations_.find(response.navigation_id);
430 if (nav_it != inflight_navigations_.end()) {
431 summary.reset(nav_it->second.release());
432 inflight_navigations_.erase(nav_it);
433 }
446 434
447 // The redirect url may be empty if the URL was invalid. 435 // The redirect url may be empty if the URL was invalid.
448 if (response.redirect_url.is_empty()) 436 if (response.redirect_url.is_empty())
449 return; 437 return;
450 438
439 // If we lost the information about the first hop for some reason.
pasko 2016/09/27 16:21:27 In what circumstances does this happen?
alexilin 2016/09/27 18:11:08 See https://codereview.chromium.org/2355273002/dif
440 if (!summary) {
441 const GURL& initial_url = response.navigation_id.main_frame_url;
442 summary = base::MakeUnique<PageRequestSummary>(initial_url);
443 }
444
445 // A redirect will not lead to another OnMainFrameRequest call, so record the
446 // redirect url as a new navigation id and save the initial url.
451 NavigationID navigation_id(response.navigation_id); 447 NavigationID navigation_id(response.navigation_id);
452 navigation_id.main_frame_url = response.redirect_url; 448 navigation_id.main_frame_url = response.redirect_url;
453 inflight_navigations_.insert(std::make_pair( 449 inflight_navigations_.insert(
454 navigation_id, 450 std::make_pair(navigation_id, std::move(summary)));
455 make_linked_ptr(new std::vector<URLRequestSummary>())));
456 } 451 }
457 452
458 void ResourcePrefetchPredictor::OnSubresourceResponse( 453 void ResourcePrefetchPredictor::OnSubresourceResponse(
459 const URLRequestSummary& response) { 454 const URLRequestSummary& response) {
460 DCHECK_CURRENTLY_ON(BrowserThread::UI); 455 DCHECK_CURRENTLY_ON(BrowserThread::UI);
461 456
462 NavigationMap::const_iterator nav_it = 457 NavigationMap::const_iterator nav_it =
463 inflight_navigations_.find(response.navigation_id); 458 inflight_navigations_.find(response.navigation_id);
464 if (nav_it == inflight_navigations_.end()) { 459 if (nav_it == inflight_navigations_.end()) {
465 return; 460 return;
466 } 461 }
467 462
468 nav_it->second->push_back(response); 463 nav_it->second->subresource_requests.push_back(response);
469 } 464 }
470 465
471 void ResourcePrefetchPredictor::OnNavigationComplete( 466 void ResourcePrefetchPredictor::OnNavigationComplete(
472 const NavigationID& nav_id_without_timing_info) { 467 const NavigationID& nav_id_without_timing_info) {
473 DCHECK_CURRENTLY_ON(BrowserThread::UI); 468 DCHECK_CURRENTLY_ON(BrowserThread::UI);
474 469
475 NavigationMap::iterator nav_it = 470 NavigationMap::iterator nav_it =
476 inflight_navigations_.find(nav_id_without_timing_info); 471 inflight_navigations_.find(nav_id_without_timing_info);
477 if (nav_it == inflight_navigations_.end()) 472 if (nav_it == inflight_navigations_.end())
478 return; 473 return;
479 474
480 const NavigationID navigation_id(nav_it->first); 475 const NavigationID navigation_id(nav_it->first);
481 476
482 // Remove the navigation from the inflight navigations. 477 // Remove the navigation from the inflight navigations.
483 std::vector<URLRequestSummary>* requests = (nav_it->second).release(); 478 std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second);
484 inflight_navigations_.erase(nav_it); 479 inflight_navigations_.erase(nav_it);
485 480
486 // Kick off history lookup to determine if we should record the URL. 481 // Kick off history lookup to determine if we should record the URL.
487 history::HistoryService* history_service = 482 history::HistoryService* history_service =
488 HistoryServiceFactory::GetForProfile(profile_, 483 HistoryServiceFactory::GetForProfile(profile_,
489 ServiceAccessType::EXPLICIT_ACCESS); 484 ServiceAccessType::EXPLICIT_ACCESS);
490 DCHECK(history_service); 485 DCHECK(history_service);
491 history_service->ScheduleDBTask( 486 history_service->ScheduleDBTask(
492 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask( 487 std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask(
493 navigation_id, requests, 488 navigation_id, std::move(summary),
494 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup, 489 base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup,
495 AsWeakPtr()))), 490 AsWeakPtr()))),
496 &history_lookup_consumer_); 491 &history_lookup_consumer_);
497 } 492 }
498 493
499 bool ResourcePrefetchPredictor::GetPrefetchData( 494 bool ResourcePrefetchPredictor::GetPrefetchData(
500 const NavigationID& navigation_id, 495 const NavigationID& navigation_id,
501 std::vector<GURL>* urls, 496 std::vector<GURL>* urls,
502 PrefetchKeyType* key_type) { 497 PrefetchKeyType* key_type) {
503 DCHECK(urls); 498 DCHECK(urls);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 navigation_id)); 574 navigation_id));
580 } 575 }
581 576
582 void ResourcePrefetchPredictor::StartInitialization() { 577 void ResourcePrefetchPredictor::StartInitialization() {
583 DCHECK_CURRENTLY_ON(BrowserThread::UI); 578 DCHECK_CURRENTLY_ON(BrowserThread::UI);
584 579
585 DCHECK_EQ(NOT_INITIALIZED, initialization_state_); 580 DCHECK_EQ(NOT_INITIALIZED, initialization_state_);
586 initialization_state_ = INITIALIZING; 581 initialization_state_ = INITIALIZING;
587 582
588 // Create local caches using the database as loaded. 583 // Create local caches using the database as loaded.
589 std::unique_ptr<PrefetchDataMap> url_data_map(new PrefetchDataMap()); 584 auto url_data_map = base::MakeUnique<PrefetchDataMap>();
590 std::unique_ptr<PrefetchDataMap> host_data_map(new PrefetchDataMap()); 585 auto host_data_map = base::MakeUnique<PrefetchDataMap>();
591 PrefetchDataMap* url_data_ptr = url_data_map.get(); 586 auto url_redirect_data_map = base::MakeUnique<RedirectDataMap>();
592 PrefetchDataMap* host_data_ptr = host_data_map.get(); 587 auto host_redirect_data_map = base::MakeUnique<RedirectDataMap>();
593 588
594 BrowserThread::PostTaskAndReply( 589 BrowserThread::PostTaskAndReply(
595 BrowserThread::DB, FROM_HERE, 590 BrowserThread::DB, FROM_HERE,
596 base::Bind(&ResourcePrefetchPredictorTables::GetAllData, 591 base::Bind(&ResourcePrefetchPredictorTables::GetAllData, tables_,
597 tables_, url_data_ptr, host_data_ptr), 592 url_data_map.get(), host_data_map.get(),
593 url_redirect_data_map.get(), host_redirect_data_map.get()),
598 base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(), 594 base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(),
599 base::Passed(&url_data_map), base::Passed(&host_data_map))); 595 base::Passed(&url_data_map), base::Passed(&host_data_map),
596 base::Passed(&url_redirect_data_map),
597 base::Passed(&host_redirect_data_map)));
600 } 598 }
601 599
602 void ResourcePrefetchPredictor::CreateCaches( 600 void ResourcePrefetchPredictor::CreateCaches(
603 std::unique_ptr<PrefetchDataMap> url_data_map, 601 std::unique_ptr<PrefetchDataMap> url_data_map,
604 std::unique_ptr<PrefetchDataMap> host_data_map) { 602 std::unique_ptr<PrefetchDataMap> host_data_map,
603 std::unique_ptr<RedirectDataMap> url_redirect_data_map,
604 std::unique_ptr<RedirectDataMap> host_redirect_data_map) {
605 DCHECK_CURRENTLY_ON(BrowserThread::UI); 605 DCHECK_CURRENTLY_ON(BrowserThread::UI);
606 606
607 DCHECK_EQ(INITIALIZING, initialization_state_); 607 DCHECK_EQ(INITIALIZING, initialization_state_);
608 DCHECK(!url_table_cache_); 608 DCHECK(!url_table_cache_);
609 DCHECK(!host_table_cache_); 609 DCHECK(!host_table_cache_);
610 DCHECK(!url_redirect_table_cache_);
611 DCHECK(!host_redirect_table_cache_);
610 DCHECK(inflight_navigations_.empty()); 612 DCHECK(inflight_navigations_.empty());
611 613
612 url_table_cache_.reset(url_data_map.release()); 614 url_table_cache_.reset(url_data_map.release());
613 host_table_cache_.reset(host_data_map.release()); 615 host_table_cache_.reset(host_data_map.release());
616 url_redirect_table_cache_.reset(url_redirect_data_map.release());
617 host_redirect_table_cache_.reset(host_redirect_data_map.release());
614 618
615 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount", 619 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount",
616 url_table_cache_->size()); 620 url_table_cache_->size());
617 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HostTableHostCount", 621 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HostTableHostCount",
618 host_table_cache_->size()); 622 host_table_cache_->size());
619 623
620 ConnectToHistoryService(); 624 ConnectToHistoryService();
621 } 625 }
622 626
623 void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() { 627 void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() {
(...skipping 22 matching lines...) Expand all
646 } else { 650 } else {
647 ++it; 651 ++it;
648 } 652 }
649 } 653 }
650 } 654 }
651 655
652 void ResourcePrefetchPredictor::DeleteAllUrls() { 656 void ResourcePrefetchPredictor::DeleteAllUrls() {
653 inflight_navigations_.clear(); 657 inflight_navigations_.clear();
654 url_table_cache_->clear(); 658 url_table_cache_->clear();
655 host_table_cache_->clear(); 659 host_table_cache_->clear();
660 url_redirect_table_cache_->clear();
661 host_redirect_table_cache_->clear();
656 662
657 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 663 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
658 base::Bind(&ResourcePrefetchPredictorTables::DeleteAllData, tables_)); 664 base::Bind(&ResourcePrefetchPredictorTables::DeleteAllData, tables_));
659 } 665 }
660 666
661 void ResourcePrefetchPredictor::DeleteUrls(const history::URLRows& urls) { 667 void ResourcePrefetchPredictor::DeleteUrls(const history::URLRows& urls) {
662 // Check all the urls in the database and pick out the ones that are present 668 // Check all the urls in the database and pick out the ones that are present
663 // in the cache. 669 // in the cache.
664 std::vector<std::string> urls_to_delete, hosts_to_delete; 670 std::vector<std::string> urls_to_delete, hosts_to_delete;
671 std::vector<std::string> url_redirects_to_delete, host_redirects_to_delete;
665 672
666 for (const auto& it : urls) { 673 for (const auto& it : urls) {
667 const std::string& url_spec = it.url().spec(); 674 const std::string& url_spec = it.url().spec();
668 if (url_table_cache_->find(url_spec) != url_table_cache_->end()) { 675 if (url_table_cache_->find(url_spec) != url_table_cache_->end()) {
669 urls_to_delete.push_back(url_spec); 676 urls_to_delete.push_back(url_spec);
670 url_table_cache_->erase(url_spec); 677 url_table_cache_->erase(url_spec);
671 } 678 }
672 679
680 if (url_redirect_table_cache_->find(url_spec) !=
681 url_redirect_table_cache_->end()) {
682 url_redirects_to_delete.push_back(url_spec);
683 url_redirect_table_cache_->erase(url_spec);
684 }
685
673 const std::string& host = it.url().host(); 686 const std::string& host = it.url().host();
674 if (host_table_cache_->find(host) != host_table_cache_->end()) { 687 if (host_table_cache_->find(host) != host_table_cache_->end()) {
675 hosts_to_delete.push_back(host); 688 hosts_to_delete.push_back(host);
676 host_table_cache_->erase(host); 689 host_table_cache_->erase(host);
677 } 690 }
691
692 if (host_redirect_table_cache_->find(host) !=
693 host_redirect_table_cache_->end()) {
694 host_redirects_to_delete.push_back(host);
695 host_redirect_table_cache_->erase(host);
696 }
678 } 697 }
679 698
680 if (!urls_to_delete.empty() || !hosts_to_delete.empty()) { 699 if (!urls_to_delete.empty() || !hosts_to_delete.empty()) {
681 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 700 BrowserThread::PostTask(
682 base::Bind(&ResourcePrefetchPredictorTables::DeleteData, 701 BrowserThread::DB, FROM_HERE,
683 tables_, 702 base::Bind(&ResourcePrefetchPredictorTables::DeleteResourceData,
684 urls_to_delete, 703 tables_, urls_to_delete, hosts_to_delete));
685 hosts_to_delete)); 704 }
705
706 if (!url_redirects_to_delete.empty() || !host_redirects_to_delete.empty()) {
707 BrowserThread::PostTask(
708 BrowserThread::DB, FROM_HERE,
709 base::Bind(&ResourcePrefetchPredictorTables::DeleteRedirectData,
710 tables_, url_redirects_to_delete, host_redirects_to_delete));
686 } 711 }
687 } 712 }
688 713
689 void ResourcePrefetchPredictor::RemoveOldestEntryInPrefetchDataMap( 714 void ResourcePrefetchPredictor::RemoveOldestEntryInPrefetchDataMap(
690 PrefetchKeyType key_type, 715 PrefetchKeyType key_type,
691 PrefetchDataMap* data_map) { 716 PrefetchDataMap* data_map) {
692 if (data_map->empty()) 717 if (data_map->empty())
693 return; 718 return;
694 719
695 base::Time oldest_time; 720 base::Time oldest_time;
696 std::string key_to_delete; 721 std::string key_to_delete;
697 for (PrefetchDataMap::iterator it = data_map->begin(); 722 for (PrefetchDataMap::iterator it = data_map->begin();
698 it != data_map->end(); ++it) { 723 it != data_map->end(); ++it) {
699 if (key_to_delete.empty() || it->second.last_visit < oldest_time) { 724 if (key_to_delete.empty() || it->second.last_visit < oldest_time) {
700 key_to_delete = it->first; 725 key_to_delete = it->first;
701 oldest_time = it->second.last_visit; 726 oldest_time = it->second.last_visit;
702 } 727 }
703 } 728 }
704 729
705 data_map->erase(key_to_delete); 730 data_map->erase(key_to_delete);
706 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 731 BrowserThread::PostTask(
707 base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint, 732 BrowserThread::DB, FROM_HERE,
708 tables_, 733 base::Bind(
709 key_to_delete, 734 &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
710 key_type)); 735 tables_, key_to_delete, key_type));
736 }
737
738 void ResourcePrefetchPredictor::RemoveOldestEntryInRedirectDataMap(
739 PrefetchKeyType key_type,
740 RedirectDataMap* data_map) {
741 if (data_map->empty())
742 return;
743
744 uint64_t oldest_time;
745 std::string key_to_delete;
746 for (const auto& kv : *data_map) {
747 const RedirectData& data = kv.second;
748 if (key_to_delete.empty() || data.last_visit_time() < oldest_time) {
749 key_to_delete = data.primary_key();
750 oldest_time = data.last_visit_time();
751 }
752 }
753
754 data_map->erase(key_to_delete);
755 BrowserThread::PostTask(
756 BrowserThread::DB, FROM_HERE,
757 base::Bind(
758 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
759 tables_, key_to_delete, key_type));
711 } 760 }
712 761
713 void ResourcePrefetchPredictor::OnVisitCountLookup( 762 void ResourcePrefetchPredictor::OnVisitCountLookup(
714 size_t visit_count, 763 size_t visit_count,
715 const NavigationID& navigation_id, 764 const NavigationID& navigation_id,
716 const std::vector<URLRequestSummary>& requests) { 765 const PageRequestSummary& summary) {
717 DCHECK_CURRENTLY_ON(BrowserThread::UI); 766 DCHECK_CURRENTLY_ON(BrowserThread::UI);
718 767
719 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl", 768 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl",
720 visit_count); 769 visit_count);
721 770
722 // URL level data - merge only if we are already saving the data, or we it 771 // TODO(alexilin) make only one request to DB thread.
pasko 2016/09/27 16:21:27 TODO(alexilin):
alexilin 2016/09/27 18:11:08 Done.
772
773 // URL level data - merge only if we already saved the data, or it
723 // meets the cutoff requirement. 774 // meets the cutoff requirement.
724 const std::string url_spec = navigation_id.main_frame_url.spec(); 775 const std::string url_spec = navigation_id.main_frame_url.spec();
725 bool already_tracking = url_table_cache_->find(url_spec) != 776 bool already_tracking = url_table_cache_->find(url_spec) !=
726 url_table_cache_->end(); 777 url_table_cache_->end();
727 bool should_track_url = already_tracking || 778 bool should_track_url = already_tracking ||
728 (visit_count >= config_.min_url_visit_count); 779 (visit_count >= config_.min_url_visit_count);
729 780
730 if (should_track_url && config_.IsURLLearningEnabled()) { 781 if (should_track_url && config_.IsURLLearningEnabled()) {
731 LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL, requests, 782 LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL,
732 config_.max_urls_to_track, url_table_cache_.get()); 783 summary.subresource_requests, config_.max_urls_to_track,
784 url_table_cache_.get(), summary.initial_url.spec(),
785 url_redirect_table_cache_.get());
733 } 786 }
734 787
735 // Host level data - no cutoff, always learn the navigation if enabled. 788 // Host level data - no cutoff, always learn the navigation if enabled.
736 if (config_.IsHostLearningEnabled()) { 789 if (config_.IsHostLearningEnabled()) {
737 LearnNavigation(navigation_id.main_frame_url.host(), 790 const std::string host = navigation_id.main_frame_url.host();
738 PREFETCH_KEY_TYPE_HOST, 791 LearnNavigation(host, PREFETCH_KEY_TYPE_HOST, summary.subresource_requests,
739 requests, 792 config_.max_hosts_to_track, host_table_cache_.get(),
740 config_.max_hosts_to_track, 793 summary.initial_url.host(),
741 host_table_cache_.get()); 794 host_redirect_table_cache_.get());
742 } 795 }
743 } 796 }
744 797
745 void ResourcePrefetchPredictor::LearnNavigation( 798 void ResourcePrefetchPredictor::LearnNavigation(
746 const std::string& key, 799 const std::string& key,
747 PrefetchKeyType key_type, 800 PrefetchKeyType key_type,
748 const std::vector<URLRequestSummary>& new_resources, 801 const std::vector<URLRequestSummary>& new_resources,
749 size_t max_data_map_size, 802 size_t max_data_map_size,
750 PrefetchDataMap* data_map) { 803 PrefetchDataMap* data_map,
804 const std::string& key_before_redirects,
805 RedirectDataMap* redirect_map) {
751 DCHECK_CURRENTLY_ON(BrowserThread::UI); 806 DCHECK_CURRENTLY_ON(BrowserThread::UI);
752 807
753 // If the primary key is too long reject it. 808 // If the primary key is too long reject it.
754 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength) 809 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength)
755 return; 810 return;
756 811
757 PrefetchDataMap::iterator cache_entry = data_map->find(key); 812 PrefetchDataMap::iterator cache_entry = data_map->find(key);
758 if (cache_entry == data_map->end()) { 813 if (cache_entry == data_map->end()) {
759 if (data_map->size() >= max_data_map_size) { 814 // If the table is full, delete an entry.
760 // The table is full, delete an entry. 815 if (data_map->size() >= max_data_map_size)
761 RemoveOldestEntryInPrefetchDataMap(key_type, data_map); 816 RemoveOldestEntryInPrefetchDataMap(key_type, data_map);
762 }
763 817
764 cache_entry = data_map->insert(std::make_pair( 818 cache_entry = data_map->insert(std::make_pair(
765 key, PrefetchData(key_type, key))).first; 819 key, PrefetchData(key_type, key))).first;
766 cache_entry->second.last_visit = base::Time::Now(); 820 cache_entry->second.last_visit = base::Time::Now();
767 size_t new_resources_size = new_resources.size(); 821 size_t new_resources_size = new_resources.size();
768 std::set<GURL> resources_seen; 822 std::set<GURL> resources_seen;
769 for (size_t i = 0; i < new_resources_size; ++i) { 823 for (size_t i = 0; i < new_resources_size; ++i) {
770 if (resources_seen.find(new_resources[i].resource_url) != 824 if (resources_seen.find(new_resources[i].resource_url) !=
771 resources_seen.end()) { 825 resources_seen.end()) {
772 continue; 826 continue;
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
872 ResourcePrefetchPredictorTables::SortResources(&resources); 926 ResourcePrefetchPredictorTables::SortResources(&resources);
873 if (resources.size() > config_.max_resources_per_entry) 927 if (resources.size() > config_.max_resources_per_entry)
874 resources.resize(config_.max_resources_per_entry); 928 resources.resize(config_.max_resources_per_entry);
875 929
876 // If the row has no resources, remove it from the cache and delete the 930 // If the row has no resources, remove it from the cache and delete the
877 // entry in the database. Else update the database. 931 // entry in the database. Else update the database.
878 if (resources.empty()) { 932 if (resources.empty()) {
879 data_map->erase(key); 933 data_map->erase(key);
880 BrowserThread::PostTask( 934 BrowserThread::PostTask(
881 BrowserThread::DB, FROM_HERE, 935 BrowserThread::DB, FROM_HERE,
882 base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint, 936 base::Bind(
883 tables_, 937 &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
884 key, 938 tables_, key, key_type));
885 key_type));
886 } else { 939 } else {
887 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; 940 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
888 PrefetchData empty_data( 941 PrefetchData empty_data(
889 !is_host ? PREFETCH_KEY_TYPE_HOST : PREFETCH_KEY_TYPE_URL, 942 !is_host ? PREFETCH_KEY_TYPE_HOST : PREFETCH_KEY_TYPE_URL,
890 std::string()); 943 std::string());
944 RedirectData empty_redirect_data;
891 const PrefetchData& host_data = is_host ? cache_entry->second : empty_data; 945 const PrefetchData& host_data = is_host ? cache_entry->second : empty_data;
892 const PrefetchData& url_data = is_host ? empty_data : cache_entry->second; 946 const PrefetchData& url_data = is_host ? empty_data : cache_entry->second;
893 BrowserThread::PostTask( 947 BrowserThread::PostTask(
894 BrowserThread::DB, FROM_HERE, 948 BrowserThread::DB, FROM_HERE,
895 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, 949 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
896 tables_, 950 url_data, host_data, empty_redirect_data,
897 url_data, 951 empty_redirect_data));
898 host_data)); 952 }
953
954 if (key != key_before_redirects) {
955 LearnRedirect(key_before_redirects, key_type, key, max_data_map_size,
956 redirect_map);
899 } 957 }
900 } 958 }
901 959
960 void ResourcePrefetchPredictor::LearnRedirect(const std::string& key,
961 PrefetchKeyType key_type,
962 const std::string& final_redirect,
963 size_t max_redirect_map_size,
964 RedirectDataMap* redirect_map) {
965 DCHECK_CURRENTLY_ON(BrowserThread::UI);
966
967 RedirectDataMap::iterator cache_entry = redirect_map->find(key);
968 if (cache_entry == redirect_map->end()) {
969 if (redirect_map->size() >= max_redirect_map_size)
970 RemoveOldestEntryInRedirectDataMap(key_type, redirect_map);
971
972 RedirectData new_data;
973 new_data.set_primary_key(key);
974 cache_entry = redirect_map->insert(std::make_pair(key, new_data)).first;
975 cache_entry->second.set_last_visit_time(
976 base::Time::Now().ToInternalValue());
977 RedirectStat* redirect_to_add =
978 cache_entry->second.add_redirect_endpoints();
979 redirect_to_add->set_url(final_redirect);
980 redirect_to_add->set_number_of_hits(1);
981 } else {
982 bool need_to_add = true;
983 cache_entry->second.set_last_visit_time(
984 base::Time::Now().ToInternalValue());
985
986 for (RedirectStat& redirect :
987 *(cache_entry->second.mutable_redirect_endpoints())) {
988 if (redirect.url() == final_redirect) {
989 need_to_add = false;
990 redirect.set_number_of_hits(redirect.number_of_hits() + 1);
991 redirect.set_consecutive_misses(0);
992 } else {
993 redirect.set_number_of_misses(redirect.number_of_misses() + 1);
994 redirect.set_consecutive_misses(redirect.consecutive_misses() + 1);
995 }
996 }
997
998 if (need_to_add) {
999 RedirectStat* redirect_to_add =
1000 cache_entry->second.add_redirect_endpoints();
1001 redirect_to_add->set_url(final_redirect);
1002 redirect_to_add->set_number_of_hits(1);
1003 }
1004 }
1005
1006 // Trim and sort redirects after update.
1007 std::vector<RedirectStat> redirects;
1008 redirects.reserve(cache_entry->second.redirect_endpoints_size());
1009 for (const RedirectStat& redirect :
1010 cache_entry->second.redirect_endpoints()) {
1011 if (redirect.consecutive_misses() < config_.max_consecutive_misses)
1012 redirects.push_back(redirect);
1013 }
1014 ResourcePrefetchPredictorTables::SortRedirects(&redirects);
1015
1016 if (redirects.size() > kMaxRedirectsPerEntry)
1017 redirects.resize(kMaxRedirectsPerEntry);
1018
1019 cache_entry->second.clear_redirect_endpoints();
1020 for (const RedirectStat& redirect : redirects)
1021 cache_entry->second.add_redirect_endpoints()->CopyFrom(redirect);
1022
1023 if (redirects.empty()) {
1024 redirect_map->erase(cache_entry);
1025 BrowserThread::PostTask(
1026 BrowserThread::DB, FROM_HERE,
1027 base::Bind(
1028 &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
1029 tables_, key, key_type));
1030 } else {
1031 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
1032 RedirectData empty_redirect_data;
1033 PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
1034 PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
1035 const RedirectData& host_redirect_data =
1036 is_host ? cache_entry->second : empty_redirect_data;
1037 const RedirectData& url_redirect_data =
1038 is_host ? empty_redirect_data : cache_entry->second;
1039 BrowserThread::PostTask(
1040 BrowserThread::DB, FROM_HERE,
1041 base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
1042 empty_url_data, empty_host_data, url_redirect_data,
1043 host_redirect_data));
1044 }
1045 }
1046
902 void ResourcePrefetchPredictor::OnURLsDeleted( 1047 void ResourcePrefetchPredictor::OnURLsDeleted(
903 history::HistoryService* history_service, 1048 history::HistoryService* history_service,
904 bool all_history, 1049 bool all_history,
905 bool expired, 1050 bool expired,
906 const history::URLRows& deleted_rows, 1051 const history::URLRows& deleted_rows,
907 const std::set<GURL>& favicon_urls) { 1052 const std::set<GURL>& favicon_urls) {
908 DCHECK_CURRENTLY_ON(BrowserThread::UI); 1053 DCHECK_CURRENTLY_ON(BrowserThread::UI);
909 if (INITIALIZED != initialization_state_) 1054 if (INITIALIZED != initialization_state_)
910 return; 1055 return;
911 1056
(...skipping 27 matching lines...) Expand all
939 // HistoryService is already loaded. Continue with Initialization. 1084 // HistoryService is already loaded. Continue with Initialization.
940 OnHistoryAndCacheLoaded(); 1085 OnHistoryAndCacheLoaded();
941 return; 1086 return;
942 } 1087 }
943 DCHECK(!history_service_observer_.IsObserving(history_service)); 1088 DCHECK(!history_service_observer_.IsObserving(history_service));
944 history_service_observer_.Add(history_service); 1089 history_service_observer_.Add(history_service);
945 return; 1090 return;
946 } 1091 }
947 1092
948 } // namespace predictors 1093 } // namespace predictors
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698