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/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
14 #include "base/metrics/sparse_histogram.h" | 14 #include "base/metrics/sparse_histogram.h" |
15 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "base/time/time.h" | 17 #include "base/time/time.h" |
18 #include "chrome/browser/history/history_service_factory.h" | 18 #include "chrome/browser/history/history_service_factory.h" |
19 #include "chrome/browser/predictors/predictor_database.h" | 19 #include "chrome/browser/predictors/predictor_database.h" |
20 #include "chrome/browser/predictors/predictor_database_factory.h" | 20 #include "chrome/browser/predictors/predictor_database_factory.h" |
| 21 #include "chrome/browser/predictors/resource_prefetch_predictor.pb.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_db_task.h" |
27 #include "components/history/core/browser/history_service.h" | 28 #include "components/history/core/browser/history_service.h" |
28 #include "components/mime_util/mime_util.h" | 29 #include "components/mime_util/mime_util.h" |
29 #include "content/public/browser/browser_thread.h" | 30 #include "content/public/browser/browser_thread.h" |
30 #include "content/public/browser/navigation_controller.h" | 31 #include "content/public/browser/navigation_controller.h" |
31 #include "content/public/browser/resource_request_info.h" | 32 #include "content/public/browser/resource_request_info.h" |
32 #include "content/public/browser/web_contents.h" | 33 #include "content/public/browser/web_contents.h" |
33 #include "net/base/mime_util.h" | 34 #include "net/base/mime_util.h" |
34 #include "net/base/network_change_notifier.h" | 35 #include "net/base/network_change_notifier.h" |
35 #include "net/http/http_response_headers.h" | 36 #include "net/http/http_response_headers.h" |
36 #include "net/url_request/url_request.h" | 37 #include "net/url_request/url_request.h" |
37 #include "net/url_request/url_request_context_getter.h" | 38 #include "net/url_request/url_request_context_getter.h" |
38 | 39 |
39 using content::BrowserThread; | 40 using content::BrowserThread; |
| 41 using chrome_browser_predictors::ResourceData; |
40 | 42 |
41 namespace { | 43 namespace { |
42 | 44 |
43 // Sorted by decreasing likelihood according to HTTP archive. | 45 // Sorted by decreasing likelihood according to HTTP archive. |
44 const char* kFontMimeTypes[] = {"font/woff2", | 46 const char* kFontMimeTypes[] = {"font/woff2", |
45 "application/x-font-woff", | 47 "application/x-font-woff", |
46 "application/font-woff", | 48 "application/font-woff", |
47 "application/font-woff2", | 49 "application/font-woff2", |
48 "font/x-woff", | 50 "font/x-woff", |
49 "application/x-font-ttf", | 51 "application/x-font-ttf", |
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 PopulatePrefetcherRequest(iterator->second, prefetch_requests); | 702 PopulatePrefetcherRequest(iterator->second, prefetch_requests); |
701 } | 703 } |
702 } | 704 } |
703 | 705 |
704 return !prefetch_requests->empty(); | 706 return !prefetch_requests->empty(); |
705 } | 707 } |
706 | 708 |
707 void ResourcePrefetchPredictor::PopulatePrefetcherRequest( | 709 void ResourcePrefetchPredictor::PopulatePrefetcherRequest( |
708 const PrefetchData& data, | 710 const PrefetchData& data, |
709 ResourcePrefetcher::RequestVector* requests) { | 711 ResourcePrefetcher::RequestVector* requests) { |
710 for (ResourceRows::const_iterator it = data.resources.begin(); | 712 for (const ResourceData& resource : data.resources) { |
711 it != data.resources.end(); ++it) { | 713 float confidence = |
712 float confidence = static_cast<float>(it->number_of_hits) / | 714 static_cast<float>(resource.number_of_hits()) / |
713 (it->number_of_hits + it->number_of_misses); | 715 (resource.number_of_hits() + resource.number_of_misses()); |
714 if (confidence < config_.min_resource_confidence_to_trigger_prefetch || | 716 if (confidence < config_.min_resource_confidence_to_trigger_prefetch || |
715 it->number_of_hits < config_.min_resource_hits_to_trigger_prefetch) { | 717 resource.number_of_hits() < |
| 718 config_.min_resource_hits_to_trigger_prefetch) { |
716 continue; | 719 continue; |
717 } | 720 } |
718 | 721 |
719 ResourcePrefetcher::Request* req = new ResourcePrefetcher::Request( | 722 ResourcePrefetcher::Request* req = |
720 it->resource_url); | 723 new ResourcePrefetcher::Request(GURL(resource.resource_url())); |
721 requests->push_back(req); | 724 requests->push_back(req); |
722 } | 725 } |
723 } | 726 } |
724 | 727 |
725 void ResourcePrefetchPredictor::StartPrefetching( | 728 void ResourcePrefetchPredictor::StartPrefetching( |
726 const NavigationID& navigation_id) { | 729 const NavigationID& navigation_id) { |
727 if (!prefetch_manager_.get()) // Prefetching not enabled. | 730 if (!prefetch_manager_.get()) // Prefetching not enabled. |
728 return; | 731 return; |
729 | 732 |
730 // Prefer URL based data first. | 733 // Prefer URL based data first. |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
939 } | 942 } |
940 | 943 |
941 void ResourcePrefetchPredictor::LearnNavigation( | 944 void ResourcePrefetchPredictor::LearnNavigation( |
942 const std::string& key, | 945 const std::string& key, |
943 PrefetchKeyType key_type, | 946 PrefetchKeyType key_type, |
944 const std::vector<URLRequestSummary>& new_resources, | 947 const std::vector<URLRequestSummary>& new_resources, |
945 size_t max_data_map_size, | 948 size_t max_data_map_size, |
946 PrefetchDataMap* data_map) { | 949 PrefetchDataMap* data_map) { |
947 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 950 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
948 | 951 |
| 952 using ResourceType = ::chrome_browser_predictors::ResourceData_ResourceType; |
| 953 using Priority = ::chrome_browser_predictors::ResourceData_Priority; |
| 954 |
949 // If the primary key is too long reject it. | 955 // If the primary key is too long reject it. |
950 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength) { | 956 if (key.length() > ResourcePrefetchPredictorTables::kMaxStringLength) { |
951 if (key_type == PREFETCH_KEY_TYPE_HOST) | 957 if (key_type == PREFETCH_KEY_TYPE_HOST) |
952 RecordNavigationEvent(NAVIGATION_EVENT_HOST_TOO_LONG); | 958 RecordNavigationEvent(NAVIGATION_EVENT_HOST_TOO_LONG); |
953 else | 959 else |
954 RecordNavigationEvent(NAVIGATION_EVENT_MAIN_FRAME_URL_TOO_LONG); | 960 RecordNavigationEvent(NAVIGATION_EVENT_MAIN_FRAME_URL_TOO_LONG); |
955 return; | 961 return; |
956 } | 962 } |
957 | 963 |
958 PrefetchDataMap::iterator cache_entry = data_map->find(key); | 964 PrefetchDataMap::iterator cache_entry = data_map->find(key); |
959 if (cache_entry == data_map->end()) { | 965 if (cache_entry == data_map->end()) { |
960 if (data_map->size() >= max_data_map_size) { | 966 if (data_map->size() >= max_data_map_size) { |
961 // The table is full, delete an entry. | 967 // The table is full, delete an entry. |
962 RemoveOldestEntryInPrefetchDataMap(key_type, data_map); | 968 RemoveOldestEntryInPrefetchDataMap(key_type, data_map); |
963 } | 969 } |
964 | 970 |
965 cache_entry = data_map->insert(std::make_pair( | 971 cache_entry = data_map->insert(std::make_pair( |
966 key, PrefetchData(key_type, key))).first; | 972 key, PrefetchData(key_type, key))).first; |
967 cache_entry->second.last_visit = base::Time::Now(); | 973 cache_entry->second.last_visit = base::Time::Now(); |
968 size_t new_resources_size = new_resources.size(); | 974 size_t new_resources_size = new_resources.size(); |
969 std::set<GURL> resources_seen; | 975 std::set<GURL> resources_seen; |
970 for (size_t i = 0; i < new_resources_size; ++i) { | 976 for (size_t i = 0; i < new_resources_size; ++i) { |
971 if (resources_seen.find(new_resources[i].resource_url) != | 977 if (resources_seen.find(new_resources[i].resource_url) != |
972 resources_seen.end()) { | 978 resources_seen.end()) { |
973 continue; | 979 continue; |
974 } | 980 } |
975 ResourceRow row_to_add; | 981 ResourceData resource_to_add; |
976 row_to_add.resource_url = new_resources[i].resource_url; | 982 resource_to_add.set_resource_url(new_resources[i].resource_url.spec()); |
977 row_to_add.resource_type = new_resources[i].resource_type; | 983 resource_to_add.set_resource_type( |
978 row_to_add.number_of_hits = 1; | 984 static_cast<ResourceType>(new_resources[i].resource_type)); |
979 row_to_add.average_position = i + 1; | 985 resource_to_add.set_number_of_hits(1); |
980 row_to_add.priority = new_resources[i].priority; | 986 resource_to_add.set_average_position(i + 1); |
981 row_to_add.has_validators = new_resources[i].has_validators; | 987 resource_to_add.set_priority( |
982 row_to_add.always_revalidate = new_resources[i].always_revalidate; | 988 static_cast<Priority>(new_resources[i].priority)); |
983 cache_entry->second.resources.push_back(row_to_add); | 989 resource_to_add.set_has_validators(new_resources[i].has_validators); |
| 990 resource_to_add.set_always_revalidate(new_resources[i].always_revalidate); |
| 991 cache_entry->second.resources.push_back(resource_to_add); |
984 resources_seen.insert(new_resources[i].resource_url); | 992 resources_seen.insert(new_resources[i].resource_url); |
985 } | 993 } |
986 } else { | 994 } else { |
987 ResourceRows& old_resources = cache_entry->second.resources; | 995 std::vector<ResourceData>& old_resources = cache_entry->second.resources; |
988 cache_entry->second.last_visit = base::Time::Now(); | 996 cache_entry->second.last_visit = base::Time::Now(); |
989 | 997 |
990 // Build indices over the data. | 998 // Build indices over the data. |
991 std::map<GURL, int> new_index, old_index; | 999 std::map<GURL, int> new_index, old_index; |
992 int new_resources_size = static_cast<int>(new_resources.size()); | 1000 int new_resources_size = static_cast<int>(new_resources.size()); |
993 for (int i = 0; i < new_resources_size; ++i) { | 1001 for (int i = 0; i < new_resources_size; ++i) { |
994 const URLRequestSummary& summary = new_resources[i]; | 1002 const URLRequestSummary& summary = new_resources[i]; |
995 // Take the first occurence of every url. | 1003 // Take the first occurence of every url. |
996 if (new_index.find(summary.resource_url) == new_index.end()) | 1004 if (new_index.find(summary.resource_url) == new_index.end()) |
997 new_index[summary.resource_url] = i; | 1005 new_index[summary.resource_url] = i; |
998 } | 1006 } |
999 int old_resources_size = static_cast<int>(old_resources.size()); | 1007 int old_resources_size = static_cast<int>(old_resources.size()); |
1000 for (int i = 0; i < old_resources_size; ++i) { | 1008 for (int i = 0; i < old_resources_size; ++i) { |
1001 const ResourceRow& row = old_resources[i]; | 1009 const ResourceData& resource = old_resources[i]; |
1002 DCHECK(old_index.find(row.resource_url) == old_index.end()); | 1010 GURL resource_url(resource.resource_url()); |
1003 old_index[row.resource_url] = i; | 1011 DCHECK(old_index.find(resource_url) == old_index.end()); |
| 1012 old_index[resource_url] = i; |
1004 } | 1013 } |
1005 | 1014 |
1006 // Go through the old urls and update their hit/miss counts. | 1015 // Go through the old urls and update their hit/miss counts. |
1007 for (int i = 0; i < old_resources_size; ++i) { | 1016 for (int i = 0; i < old_resources_size; ++i) { |
1008 ResourceRow& old_row = old_resources[i]; | 1017 ResourceData& old_resource = old_resources[i]; |
1009 if (new_index.find(old_row.resource_url) == new_index.end()) { | 1018 GURL resource_url(old_resource.resource_url()); |
1010 ++old_row.number_of_misses; | 1019 if (new_index.find(resource_url) == new_index.end()) { |
1011 ++old_row.consecutive_misses; | 1020 old_resource.set_number_of_misses(old_resource.number_of_misses() + 1); |
| 1021 old_resource.set_consecutive_misses(old_resource.consecutive_misses() + |
| 1022 1); |
1012 } else { | 1023 } else { |
1013 const URLRequestSummary& new_row = | 1024 const URLRequestSummary& new_summary = |
1014 new_resources[new_index[old_row.resource_url]]; | 1025 new_resources[new_index[GURL(old_resource.resource_url())]]; |
1015 | 1026 |
1016 // Update the resource type since it could have changed. | 1027 // Update the resource type and priority. |
1017 if (new_row.resource_type != content::RESOURCE_TYPE_LAST_TYPE) | 1028 if (new_summary.resource_type != content::RESOURCE_TYPE_LAST_TYPE) |
1018 old_row.resource_type = new_row.resource_type; | 1029 old_resource.set_resource_type( |
| 1030 static_cast<ResourceType>(new_summary.resource_type)); |
| 1031 old_resource.set_priority(static_cast<Priority>(new_summary.priority)); |
1019 | 1032 |
1020 old_row.priority = new_row.priority; | 1033 int position = new_index[resource_url] + 1; |
1021 | 1034 int total = |
1022 int position = new_index[old_row.resource_url] + 1; | 1035 old_resource.number_of_hits() + old_resource.number_of_misses(); |
1023 int total = old_row.number_of_hits + old_row.number_of_misses; | 1036 old_resource.set_average_position( |
1024 old_row.average_position = | 1037 ((old_resource.average_position() * total) + position) / |
1025 ((old_row.average_position * total) + position) / (total + 1); | 1038 (total + 1)); |
1026 ++old_row.number_of_hits; | 1039 old_resource.set_number_of_hits(old_resource.number_of_hits() + 1); |
1027 old_row.consecutive_misses = 0; | 1040 old_resource.set_consecutive_misses(0); |
1028 } | 1041 } |
1029 } | 1042 } |
1030 | 1043 |
1031 // Add the new ones that we have not seen before. | 1044 // Add the new ones that we have not seen before. |
1032 for (int i = 0; i < new_resources_size; ++i) { | 1045 for (int i = 0; i < new_resources_size; ++i) { |
1033 const URLRequestSummary& summary = new_resources[i]; | 1046 const URLRequestSummary& summary = new_resources[i]; |
1034 if (old_index.find(summary.resource_url) != old_index.end()) | 1047 if (old_index.find(summary.resource_url) != old_index.end()) |
1035 continue; | 1048 continue; |
1036 | 1049 |
1037 // Only need to add new stuff. | 1050 // Only need to add new stuff. |
1038 ResourceRow row_to_add; | 1051 ResourceData resource_to_add; |
1039 row_to_add.resource_url = summary.resource_url; | 1052 resource_to_add.set_resource_url(summary.resource_url.spec()); |
1040 row_to_add.resource_type = summary.resource_type; | 1053 resource_to_add.set_resource_type( |
1041 row_to_add.number_of_hits = 1; | 1054 static_cast<ResourceType>(summary.resource_type)); |
1042 row_to_add.average_position = i + 1; | 1055 resource_to_add.set_number_of_hits(1); |
1043 row_to_add.priority = summary.priority; | 1056 resource_to_add.set_average_position(i + 1); |
1044 row_to_add.has_validators = new_resources[i].has_validators; | 1057 resource_to_add.set_priority(static_cast<Priority>(summary.priority)); |
1045 row_to_add.always_revalidate = new_resources[i].always_revalidate; | 1058 resource_to_add.set_has_validators(new_resources[i].has_validators); |
1046 old_resources.push_back(row_to_add); | 1059 resource_to_add.set_always_revalidate(new_resources[i].always_revalidate); |
| 1060 old_resources.push_back(resource_to_add); |
1047 | 1061 |
1048 // To ensure we dont add the same url twice. | 1062 // To ensure we dont add the same url twice. |
1049 old_index[summary.resource_url] = 0; | 1063 old_index[summary.resource_url] = 0; |
1050 } | 1064 } |
1051 } | 1065 } |
1052 | 1066 |
1053 // Trim and sort the resources after the update. | 1067 // Trim and sort the resources after the update. |
1054 ResourceRows& resources = cache_entry->second.resources; | 1068 std::vector<ResourceData>& resources = cache_entry->second.resources; |
1055 for (ResourceRows::iterator it = resources.begin(); | 1069 for (std::vector<ResourceData>::iterator it = resources.begin(); |
1056 it != resources.end();) { | 1070 it != resources.end();) { |
1057 it->UpdateScore(); | 1071 ResourcePrefetchPredictorTables::UpdateResourceScore(&(*it)); |
1058 if (it->consecutive_misses >= config_.max_consecutive_misses) | 1072 if (it->consecutive_misses() >= config_.max_consecutive_misses) |
1059 it = resources.erase(it); | 1073 it = resources.erase(it); |
1060 else | 1074 else |
1061 ++it; | 1075 ++it; |
1062 } | 1076 } |
1063 ResourcePrefetchPredictorTables::SortResourceRows(&resources); | 1077 ResourcePrefetchPredictorTables::SortResources(&resources); |
1064 if (resources.size() > config_.max_resources_per_entry) | 1078 if (resources.size() > config_.max_resources_per_entry) |
1065 resources.resize(config_.max_resources_per_entry); | 1079 resources.resize(config_.max_resources_per_entry); |
1066 | 1080 |
1067 // If the row has no resources, remove it from the cache and delete the | 1081 // If the row has no resources, remove it from the cache and delete the |
1068 // entry in the database. Else update the database. | 1082 // entry in the database. Else update the database. |
1069 if (resources.empty()) { | 1083 if (resources.empty()) { |
1070 data_map->erase(key); | 1084 data_map->erase(key); |
1071 BrowserThread::PostTask( | 1085 BrowserThread::PostTask( |
1072 BrowserThread::DB, FROM_HERE, | 1086 BrowserThread::DB, FROM_HERE, |
1073 base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint, | 1087 base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint, |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1424 // HistoryService is already loaded. Continue with Initialization. | 1438 // HistoryService is already loaded. Continue with Initialization. |
1425 OnHistoryAndCacheLoaded(); | 1439 OnHistoryAndCacheLoaded(); |
1426 return; | 1440 return; |
1427 } | 1441 } |
1428 DCHECK(!history_service_observer_.IsObserving(history_service)); | 1442 DCHECK(!history_service_observer_.IsObserving(history_service)); |
1429 history_service_observer_.Add(history_service); | 1443 history_service_observer_.Add(history_service); |
1430 return; | 1444 return; |
1431 } | 1445 } |
1432 | 1446 |
1433 } // namespace predictors | 1447 } // namespace predictors |
OLD | NEW |