OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/prerender/prerender_local_predictor.h" | 5 #include "chrome/browser/prerender/prerender_local_predictor.h" |
6 | 6 |
7 #include <ctype.h> | 7 #include <ctype.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <map> | 10 #include <map> |
11 #include <set> | 11 #include <set> |
12 #include <string> | 12 #include <string> |
13 #include <utility> | 13 #include <utility> |
14 | 14 |
15 #include "base/metrics/field_trial.h" | 15 #include "base/metrics/field_trial.h" |
16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
17 #include "base/timer.h" | 17 #include "base/timer.h" |
18 #include "chrome/browser/history/history_database.h" | 18 #include "chrome/browser/history/history_database.h" |
19 #include "chrome/browser/history/history_db_task.h" | 19 #include "chrome/browser/history/history_db_task.h" |
20 #include "chrome/browser/history/history_service.h" | 20 #include "chrome/browser/history/history_service.h" |
21 #include "chrome/browser/history/history_service_factory.h" | 21 #include "chrome/browser/history/history_service_factory.h" |
| 22 #include "chrome/browser/prerender/prerender_handle.h" |
22 #include "chrome/browser/prerender/prerender_histograms.h" | 23 #include "chrome/browser/prerender/prerender_histograms.h" |
23 #include "chrome/browser/prerender/prerender_manager.h" | 24 #include "chrome/browser/prerender/prerender_manager.h" |
24 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
| 26 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
25 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
| 28 #include "content/public/browser/navigation_controller.h" |
| 29 #include "content/public/browser/session_storage_namespace.h" |
| 30 #include "content/public/browser/web_contents.h" |
| 31 #include "content/public/browser/web_contents_view.h" |
26 #include "content/public/common/page_transition_types.h" | 32 #include "content/public/common/page_transition_types.h" |
27 #include "crypto/secure_hash.h" | 33 #include "crypto/secure_hash.h" |
| 34 #include "googleurl/src/url_canon.h" |
28 #include "grit/browser_resources.h" | 35 #include "grit/browser_resources.h" |
29 #include "ui/base/resource/resource_bundle.h" | 36 #include "ui/base/resource/resource_bundle.h" |
30 | 37 |
31 using content::BrowserThread; | 38 using content::BrowserThread; |
32 using content::PageTransition; | 39 using content::PageTransition; |
| 40 using content::SessionStorageNamespace; |
| 41 using content::WebContents; |
33 using history::URLID; | 42 using history::URLID; |
| 43 using predictors::LoggedInPredictorTable; |
| 44 using std::string; |
| 45 using std::vector; |
34 | 46 |
35 namespace prerender { | 47 namespace prerender { |
36 | 48 |
37 namespace { | 49 namespace { |
38 | 50 |
39 static const size_t kURLHashSize = 5; | 51 static const size_t kURLHashSize = 5; |
| 52 static const int kNumPrerenderCandidates = 5; |
| 53 |
| 54 } // namespace |
| 55 |
| 56 // When considering a candidate URL to be prerendered, we need to collect the |
| 57 // data in this struct to make the determination whether we should issue the |
| 58 // prerender or not. |
| 59 struct PrerenderLocalPredictor::LocalPredictorURLInfo { |
| 60 URLID id; |
| 61 GURL url; |
| 62 bool url_lookup_success; |
| 63 bool logged_in; |
| 64 bool logged_in_lookup_ok; |
| 65 double priority; |
| 66 }; |
| 67 |
| 68 // A struct consisting of everything needed for launching a potential prerender |
| 69 // on a navigation: The navigation URL (source) triggering potential prerenders, |
| 70 // and a set of candidate URLs. |
| 71 struct PrerenderLocalPredictor::LocalPredictorURLLookupInfo { |
| 72 LocalPredictorURLInfo source_url_; |
| 73 vector<LocalPredictorURLInfo> candidate_urls_; |
| 74 explicit LocalPredictorURLLookupInfo(URLID source_id) { |
| 75 source_url_.id = source_id; |
| 76 } |
| 77 void MaybeAddCandidateURL(URLID id, double priority) { |
| 78 // TODO(tburkard): clean up this code, potentially using a list or a heap |
| 79 LocalPredictorURLInfo info; |
| 80 info.id = id; |
| 81 info.priority = priority; |
| 82 int insert_pos = candidate_urls_.size(); |
| 83 if (insert_pos < kNumPrerenderCandidates) |
| 84 candidate_urls_.push_back(info); |
| 85 while (insert_pos > 0 && |
| 86 candidate_urls_[insert_pos - 1].priority < info.priority) { |
| 87 if (insert_pos < kNumPrerenderCandidates) |
| 88 candidate_urls_[insert_pos] = candidate_urls_[insert_pos - 1]; |
| 89 insert_pos--; |
| 90 } |
| 91 if (insert_pos < kNumPrerenderCandidates) |
| 92 candidate_urls_[insert_pos] = info; |
| 93 } |
| 94 }; |
| 95 |
| 96 namespace { |
40 | 97 |
41 // Task to lookup the URL for a given URLID. | 98 // Task to lookup the URL for a given URLID. |
42 class GetURLForURLIDTask : public history::HistoryDBTask { | 99 class GetURLForURLIDTask : public history::HistoryDBTask { |
43 public: | 100 public: |
44 GetURLForURLIDTask(URLID url_id, base::Callback<void(const GURL&)> callback) | 101 GetURLForURLIDTask( |
45 : url_id_(url_id), | 102 PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request, |
46 success_(false), | 103 const base::Closure& callback) |
| 104 : request_(request), |
47 callback_(callback), | 105 callback_(callback), |
48 start_time_(base::Time::Now()) { | 106 start_time_(base::Time::Now()) { |
49 } | 107 } |
50 | 108 |
51 virtual bool RunOnDBThread(history::HistoryBackend* backend, | 109 virtual bool RunOnDBThread(history::HistoryBackend* backend, |
52 history::HistoryDatabase* db) OVERRIDE { | 110 history::HistoryDatabase* db) OVERRIDE { |
53 history::URLRow url_row; | 111 DoURLLookup(db, &request_->source_url_); |
54 success_ = db->GetURLRow(url_id_, &url_row); | 112 for (int i = 0; i < static_cast<int>(request_->candidate_urls_.size()); i++) |
55 if (success_) | 113 DoURLLookup(db, &request_->candidate_urls_[i]); |
56 url_ = url_row.url(); | |
57 return true; | 114 return true; |
58 } | 115 } |
59 | 116 |
60 virtual void DoneRunOnMainThread() OVERRIDE { | 117 virtual void DoneRunOnMainThread() OVERRIDE { |
61 if (success_) { | 118 callback_.Run(); |
62 callback_.Run(url_); | 119 UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.LocalPredictorURLLookupTime", |
63 UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.LocalPredictorURLLookupTime", | 120 base::Time::Now() - start_time_, |
64 base::Time::Now() - start_time_, | 121 base::TimeDelta::FromMilliseconds(10), |
65 base::TimeDelta::FromMilliseconds(10), | 122 base::TimeDelta::FromSeconds(10), |
66 base::TimeDelta::FromSeconds(10), | 123 50); |
67 50); | |
68 } | |
69 } | 124 } |
70 | 125 |
71 private: | 126 private: |
72 virtual ~GetURLForURLIDTask() {} | 127 virtual ~GetURLForURLIDTask() {} |
73 | 128 |
74 URLID url_id_; | 129 void DoURLLookup(history::HistoryDatabase* db, |
75 bool success_; | 130 PrerenderLocalPredictor::LocalPredictorURLInfo* request) { |
76 base::Callback<void(const GURL&)> callback_; | 131 history::URLRow url_row; |
| 132 request->url_lookup_success = db->GetURLRow(request->id, &url_row); |
| 133 if (request->url_lookup_success) |
| 134 request->url = url_row.url(); |
| 135 } |
| 136 |
| 137 PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request_; |
| 138 base::Closure callback_; |
77 base::Time start_time_; | 139 base::Time start_time_; |
78 GURL url_; | |
79 DISALLOW_COPY_AND_ASSIGN(GetURLForURLIDTask); | 140 DISALLOW_COPY_AND_ASSIGN(GetURLForURLIDTask); |
80 }; | 141 }; |
81 | 142 |
82 // Task to load history from the visit database on startup. | 143 // Task to load history from the visit database on startup. |
83 class GetVisitHistoryTask : public history::HistoryDBTask { | 144 class GetVisitHistoryTask : public history::HistoryDBTask { |
84 public: | 145 public: |
85 GetVisitHistoryTask(PrerenderLocalPredictor* local_predictor, | 146 GetVisitHistoryTask(PrerenderLocalPredictor* local_predictor, |
86 int max_visits) | 147 int max_visits) |
87 : local_predictor_(local_predictor), | 148 : local_predictor_(local_predictor), |
88 max_visits_(max_visits), | 149 max_visits_(max_visits), |
89 visit_history_(new std::vector<history::BriefVisitInfo>) { | 150 visit_history_(new vector<history::BriefVisitInfo>) { |
90 } | 151 } |
91 | 152 |
92 virtual bool RunOnDBThread(history::HistoryBackend* backend, | 153 virtual bool RunOnDBThread(history::HistoryBackend* backend, |
93 history::HistoryDatabase* db) OVERRIDE { | 154 history::HistoryDatabase* db) OVERRIDE { |
94 db->GetBriefVisitInfoOfMostRecentVisits(max_visits_, visit_history_.get()); | 155 db->GetBriefVisitInfoOfMostRecentVisits(max_visits_, visit_history_.get()); |
95 return true; | 156 return true; |
96 } | 157 } |
97 | 158 |
98 virtual void DoneRunOnMainThread() OVERRIDE { | 159 virtual void DoneRunOnMainThread() OVERRIDE { |
99 local_predictor_->OnGetInitialVisitHistory(visit_history_.Pass()); | 160 local_predictor_->OnGetInitialVisitHistory(visit_history_.Pass()); |
100 } | 161 } |
101 | 162 |
102 private: | 163 private: |
103 virtual ~GetVisitHistoryTask() {} | 164 virtual ~GetVisitHistoryTask() {} |
104 | 165 |
105 PrerenderLocalPredictor* local_predictor_; | 166 PrerenderLocalPredictor* local_predictor_; |
106 int max_visits_; | 167 int max_visits_; |
107 scoped_ptr<std::vector<history::BriefVisitInfo> > visit_history_; | 168 scoped_ptr<vector<history::BriefVisitInfo> > visit_history_; |
108 DISALLOW_COPY_AND_ASSIGN(GetVisitHistoryTask); | 169 DISALLOW_COPY_AND_ASSIGN(GetVisitHistoryTask); |
109 }; | 170 }; |
110 | 171 |
111 // Maximum visit history to retrieve from the visit database. | 172 // Maximum visit history to retrieve from the visit database. |
112 const int kMaxVisitHistory = 100 * 1000; | 173 const int kMaxVisitHistory = 100 * 1000; |
113 | 174 |
114 // Visit history size at which to trigger pruning, and number of items to prune. | 175 // Visit history size at which to trigger pruning, and number of items to prune. |
115 const int kVisitHistoryPruneThreshold = 120 * 1000; | 176 const int kVisitHistoryPruneThreshold = 120 * 1000; |
116 const int kVisitHistoryPruneAmount = 20 * 1000; | 177 const int kVisitHistoryPruneAmount = 20 * 1000; |
117 | 178 |
118 const int kMaxLocalPredictionTimeMs = 300 * 1000; | 179 const int kMaxLocalPredictionTimeMs = 180 * 1000; |
119 const int kMinLocalPredictionTimeMs = 500; | 180 const int kMinLocalPredictionTimeMs = 500; |
120 | 181 |
121 bool IsBackForward(PageTransition transition) { | 182 bool IsBackForward(PageTransition transition) { |
122 return (transition & content::PAGE_TRANSITION_FORWARD_BACK) != 0; | 183 return (transition & content::PAGE_TRANSITION_FORWARD_BACK) != 0; |
123 } | 184 } |
124 | 185 |
125 bool IsHomePage(PageTransition transition) { | 186 bool IsHomePage(PageTransition transition) { |
126 return (transition & content::PAGE_TRANSITION_HOME_PAGE) != 0; | 187 return (transition & content::PAGE_TRANSITION_HOME_PAGE) != 0; |
127 } | 188 } |
128 | 189 |
129 bool IsIntermediateRedirect(PageTransition transition) { | 190 bool IsIntermediateRedirect(PageTransition transition) { |
130 return (transition & content::PAGE_TRANSITION_CHAIN_END) == 0; | 191 return (transition & content::PAGE_TRANSITION_CHAIN_END) == 0; |
131 } | 192 } |
132 | 193 |
133 bool ShouldExcludeTransitionForPrediction(PageTransition transition) { | 194 bool ShouldExcludeTransitionForPrediction(PageTransition transition) { |
134 return IsBackForward(transition) || IsHomePage(transition) || | 195 return IsBackForward(transition) || IsHomePage(transition) || |
135 IsIntermediateRedirect(transition); | 196 IsIntermediateRedirect(transition); |
136 } | 197 } |
137 | 198 |
138 base::Time GetCurrentTime() { | 199 base::Time GetCurrentTime() { |
139 return base::Time::Now(); | 200 return base::Time::Now(); |
140 } | 201 } |
141 | 202 |
142 bool StrCaseStr(std::string haystack, std::string needle) { | 203 bool StringContainsIgnoringCase(string haystack, string needle) { |
143 std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower); | 204 std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower); |
144 std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower); | 205 std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower); |
145 return haystack.find(needle) != std::string::npos; | 206 return haystack.find(needle) != string::npos; |
146 } | 207 } |
147 | 208 |
148 bool IsExtendedRootURL(const GURL& url) { | 209 bool IsExtendedRootURL(const GURL& url) { |
149 const std::string& path = url.path(); | 210 const string& path = url.path(); |
150 return path == "/index.html" || path == "/home.html" || | 211 return path == "/index.html" || path == "/home.html" || |
151 path == "/main.html" || | 212 path == "/main.html" || |
152 path == "/index.htm" || path == "/home.htm" || path == "/main.htm" || | 213 path == "/index.htm" || path == "/home.htm" || path == "/main.htm" || |
153 path == "/index.php" || path == "/home.php" || path == "/main.php" || | 214 path == "/index.php" || path == "/home.php" || path == "/main.php" || |
154 path == "/index.asp" || path == "/home.asp" || path == "/main.asp" || | 215 path == "/index.asp" || path == "/home.asp" || path == "/main.asp" || |
155 path == "/index.py" || path == "/home.py" || path == "/main.py" || | 216 path == "/index.py" || path == "/home.py" || path == "/main.py" || |
156 path == "/index.pl" || path == "/home.pl" || path == "/main.pl"; | 217 path == "/index.pl" || path == "/home.pl" || path == "/main.pl"; |
157 } | 218 } |
158 | 219 |
159 bool IsRootPageURL(const GURL& url) { | 220 bool IsRootPageURL(const GURL& url) { |
160 return (url.path() == "/" || url.path() == "" || IsExtendedRootURL(url)) && | 221 return (url.path() == "/" || url.path() == "" || IsExtendedRootURL(url)) && |
161 (!url.has_query()) && (!url.has_ref()); | 222 (!url.has_query()) && (!url.has_ref()); |
162 } | 223 } |
163 | 224 |
| 225 bool IsLogInURL(const GURL& url) { |
| 226 return StringContainsIgnoringCase(url.spec().c_str(), "login") || |
| 227 StringContainsIgnoringCase(url.spec().c_str(), "signin"); |
| 228 } |
| 229 |
| 230 bool IsLogOutURL(const GURL& url) { |
| 231 return StringContainsIgnoringCase(url.spec().c_str(), "logout") || |
| 232 StringContainsIgnoringCase(url.spec().c_str(), "signout"); |
| 233 } |
| 234 |
164 int64 URLHashToInt64(const unsigned char* data) { | 235 int64 URLHashToInt64(const unsigned char* data) { |
165 COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); | 236 COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); |
166 int64 value = 0; | 237 int64 value = 0; |
167 memcpy(&value, data, kURLHashSize); | 238 memcpy(&value, data, kURLHashSize); |
168 return value; | 239 return value; |
169 } | 240 } |
170 | 241 |
171 int64 GetInt64URLHashForURL(const GURL& url) { | 242 int64 GetInt64URLHashForURL(const GURL& url) { |
172 COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); | 243 COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); |
173 scoped_ptr<crypto::SecureHash> hash( | 244 scoped_ptr<crypto::SecureHash> hash( |
174 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | 245 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
175 int64 hash_value = 0; | 246 int64 hash_value = 0; |
176 const char* url_string = url.spec().c_str(); | 247 const char* url_string = url.spec().c_str(); |
177 hash->Update(url_string, strlen(url_string)); | 248 hash->Update(url_string, strlen(url_string)); |
178 hash->Finish(&hash_value, kURLHashSize); | 249 hash->Finish(&hash_value, kURLHashSize); |
179 return hash_value; | 250 return hash_value; |
180 } | 251 } |
181 | 252 |
| 253 bool URLsIdenticalIgnoringFragments(const GURL& url1, const GURL& url2) { |
| 254 url_canon::Replacements<char> replacement; |
| 255 replacement.ClearRef(); |
| 256 GURL u1 = url1.ReplaceComponents(replacement); |
| 257 GURL u2 = url2.ReplaceComponents(replacement); |
| 258 return (u1 == u2); |
| 259 } |
| 260 |
| 261 void LookupLoggedInStatesOnDBThread( |
| 262 scoped_refptr<LoggedInPredictorTable> logged_in_predictor_table, |
| 263 PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request_) { |
| 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 265 for (int i = 0; i < static_cast<int>(request_->candidate_urls_.size()); i++) { |
| 266 PrerenderLocalPredictor::LocalPredictorURLInfo* info = |
| 267 &request_->candidate_urls_[i]; |
| 268 if (info->url_lookup_success) { |
| 269 logged_in_predictor_table->HasUserLoggedIn( |
| 270 info->url, &info->logged_in, &info->logged_in_lookup_ok); |
| 271 } else { |
| 272 info->logged_in_lookup_ok = false; |
| 273 } |
| 274 } |
| 275 } |
| 276 |
182 } // namespace | 277 } // namespace |
183 | 278 |
184 struct PrerenderLocalPredictor::PrerenderData { | 279 struct PrerenderLocalPredictor::PrerenderProperties { |
185 PrerenderData(URLID url_id, const GURL& url, double priority, | 280 PrerenderProperties(URLID url_id, const GURL& url, double priority, |
186 base::Time start_time) | 281 base::Time start_time) |
187 : url_id(url_id), | 282 : url_id(url_id), |
188 url(url), | 283 url(url), |
189 priority(priority), | 284 priority(priority), |
190 start_time(start_time) { | 285 start_time(start_time) { |
191 } | 286 } |
192 | 287 |
193 URLID url_id; | 288 URLID url_id; |
194 GURL url; | 289 GURL url; |
195 double priority; | 290 double priority; |
196 // For expiration purposes, this is a synthetic start time consisting either | 291 // For expiration purposes, this is a synthetic start time consisting either |
197 // of the actual start time, or of the last time the page was re-requested | 292 // of the actual start time, or of the last time the page was re-requested |
198 // for prerendering - 10 seconds (unless the original request came after | 293 // for prerendering - 10 seconds (unless the original request came after |
199 // that). This is to emulate the effect of re-prerendering a page that is | 294 // that). This is to emulate the effect of re-prerendering a page that is |
200 // about to expire, because it was re-requested for prerendering a second | 295 // about to expire, because it was re-requested for prerendering a second |
201 // time after the actual prerender being kept around. | 296 // time after the actual prerender being kept around. |
202 base::Time start_time; | 297 base::Time start_time; |
203 // The actual time this page was last requested for prerendering. | 298 // The actual time this page was last requested for prerendering. |
204 base::Time actual_start_time; | 299 base::Time actual_start_time; |
205 | 300 |
206 private: | 301 private: |
207 DISALLOW_IMPLICIT_CONSTRUCTORS(PrerenderData); | 302 DISALLOW_IMPLICIT_CONSTRUCTORS(PrerenderProperties); |
208 }; | 303 }; |
209 | 304 |
210 PrerenderLocalPredictor::PrerenderLocalPredictor( | 305 PrerenderLocalPredictor::PrerenderLocalPredictor( |
211 PrerenderManager* prerender_manager) | 306 PrerenderManager* prerender_manager) |
212 : prerender_manager_(prerender_manager), | 307 : prerender_manager_(prerender_manager), |
213 is_visit_database_observer_(false) { | 308 is_visit_database_observer_(false), |
| 309 weak_factory_(this) { |
214 RecordEvent(EVENT_CONSTRUCTED); | 310 RecordEvent(EVENT_CONSTRUCTED); |
215 if (MessageLoop::current()) { | 311 if (MessageLoop::current()) { |
216 timer_.Start(FROM_HERE, | 312 timer_.Start(FROM_HERE, |
217 base::TimeDelta::FromMilliseconds(kInitDelayMs), | 313 base::TimeDelta::FromMilliseconds(kInitDelayMs), |
218 this, | 314 this, |
219 &PrerenderLocalPredictor::Init); | 315 &PrerenderLocalPredictor::Init); |
220 RecordEvent(EVENT_INIT_SCHEDULED); | 316 RecordEvent(EVENT_INIT_SCHEDULED); |
221 } | 317 } |
222 | 318 |
223 static const size_t kChecksumHashSize = 32; | 319 static const size_t kChecksumHashSize = 32; |
(...skipping 19 matching lines...) Expand all Loading... |
243 for (const unsigned char* p = front + kChecksumHashSize; | 339 for (const unsigned char* p = front + kChecksumHashSize; |
244 p < front + size; | 340 p < front + size; |
245 p += kURLHashSize) { | 341 p += kURLHashSize) { |
246 url_whitelist_.insert(URLHashToInt64(p)); | 342 url_whitelist_.insert(URLHashToInt64(p)); |
247 } | 343 } |
248 RecordEvent(EVENT_URL_WHITELIST_OK); | 344 RecordEvent(EVENT_URL_WHITELIST_OK); |
249 } | 345 } |
250 | 346 |
251 PrerenderLocalPredictor::~PrerenderLocalPredictor() { | 347 PrerenderLocalPredictor::~PrerenderLocalPredictor() { |
252 Shutdown(); | 348 Shutdown(); |
| 349 if (prerender_handle_.get()) |
| 350 prerender_handle_->OnCancel(); |
253 } | 351 } |
254 | 352 |
255 void PrerenderLocalPredictor::Shutdown() { | 353 void PrerenderLocalPredictor::Shutdown() { |
256 timer_.Stop(); | 354 timer_.Stop(); |
257 if (is_visit_database_observer_) { | 355 if (is_visit_database_observer_) { |
258 HistoryService* history = GetHistoryIfExists(); | 356 HistoryService* history = GetHistoryIfExists(); |
259 CHECK(history); | 357 CHECK(history); |
260 history->RemoveVisitDatabaseObserver(this); | 358 history->RemoveVisitDatabaseObserver(this); |
261 is_visit_database_observer_ = false; | 359 is_visit_database_observer_ = false; |
262 } | 360 } |
(...skipping 26 matching lines...) Expand all Loading... |
289 return; | 387 return; |
290 RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION); | 388 RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION); |
291 base::TimeDelta max_age = | 389 base::TimeDelta max_age = |
292 base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs); | 390 base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs); |
293 base::TimeDelta min_age = | 391 base::TimeDelta min_age = |
294 base::TimeDelta::FromMilliseconds(kMinLocalPredictionTimeMs); | 392 base::TimeDelta::FromMilliseconds(kMinLocalPredictionTimeMs); |
295 std::set<URLID> next_urls_currently_found; | 393 std::set<URLID> next_urls_currently_found; |
296 std::map<URLID, int> next_urls_num_found; | 394 std::map<URLID, int> next_urls_num_found; |
297 int num_occurrences_of_current_visit = 0; | 395 int num_occurrences_of_current_visit = 0; |
298 base::Time last_visited; | 396 base::Time last_visited; |
299 URLID best_next_url = 0; | 397 scoped_ptr<LocalPredictorURLLookupInfo> lookup_info( |
300 int best_next_url_count = 0; | 398 new LocalPredictorURLLookupInfo(info.url_id)); |
301 const std::vector<history::BriefVisitInfo>& visits = *(visit_history_.get()); | 399 const vector<history::BriefVisitInfo>& visits = *(visit_history_.get()); |
302 for (int i = 0; i < static_cast<int>(visits.size()); i++) { | 400 for (int i = 0; i < static_cast<int>(visits.size()); i++) { |
303 if (!ShouldExcludeTransitionForPrediction(visits[i].transition)) { | 401 if (!ShouldExcludeTransitionForPrediction(visits[i].transition)) { |
304 if (visits[i].url_id == info.url_id) { | 402 if (visits[i].url_id == info.url_id) { |
305 last_visited = visits[i].time; | 403 last_visited = visits[i].time; |
306 num_occurrences_of_current_visit++; | 404 num_occurrences_of_current_visit++; |
307 next_urls_currently_found.clear(); | 405 next_urls_currently_found.clear(); |
308 continue; | 406 continue; |
309 } | 407 } |
310 if (!last_visited.is_null() && | 408 if (!last_visited.is_null() && |
311 last_visited > visits[i].time - max_age && | 409 last_visited > visits[i].time - max_age && |
312 last_visited < visits[i].time - min_age) { | 410 last_visited < visits[i].time - min_age) { |
313 next_urls_currently_found.insert(visits[i].url_id); | 411 next_urls_currently_found.insert(visits[i].url_id); |
314 } | 412 } |
315 } | 413 } |
316 if (i == static_cast<int>(visits.size()) - 1 || | 414 if (i == static_cast<int>(visits.size()) - 1 || |
317 visits[i+1].url_id == info.url_id) { | 415 visits[i+1].url_id == info.url_id) { |
318 for (std::set<URLID>::iterator it = next_urls_currently_found.begin(); | 416 for (std::set<URLID>::iterator it = next_urls_currently_found.begin(); |
319 it != next_urls_currently_found.end(); | 417 it != next_urls_currently_found.end(); |
320 ++it) { | 418 ++it) { |
321 std::pair<std::map<URLID, int>::iterator, bool> insert_ret = | 419 std::pair<std::map<URLID, int>::iterator, bool> insert_ret = |
322 next_urls_num_found.insert(std::pair<URLID, int>(*it, 0)); | 420 next_urls_num_found.insert(std::pair<URLID, int>(*it, 0)); |
323 std::map<URLID, int>::iterator num_found_it = insert_ret.first; | 421 std::map<URLID, int>::iterator num_found_it = insert_ret.first; |
324 num_found_it->second++; | 422 num_found_it->second++; |
325 if (num_found_it->second > best_next_url_count) { | |
326 best_next_url_count = num_found_it->second; | |
327 best_next_url = *it; | |
328 } | |
329 } | 423 } |
330 } | 424 } |
331 } | 425 } |
332 | 426 |
333 // Only consider a candidate next page for prerendering if it was viewed | 427 for (std::map<URLID, int>::const_iterator it = next_urls_num_found.begin(); |
334 // at least twice, and at least 10% of the time. | 428 it != next_urls_num_found.end(); |
335 if (num_occurrences_of_current_visit > 0 && | 429 ++it) { |
336 best_next_url_count > 1 && | 430 // Only consider a candidate next page for prerendering if it was viewed |
337 best_next_url_count * 10 >= num_occurrences_of_current_visit) { | 431 // at least twice, and at least 10% of the time. |
338 RecordEvent(EVENT_ADD_VISIT_IDENTIFIED_PRERENDER_CANDIDATE); | 432 if (num_occurrences_of_current_visit > 0 && |
339 double priority = static_cast<double>(best_next_url_count) / | 433 it->second > 1 && |
340 static_cast<double>(num_occurrences_of_current_visit); | 434 it->second * 10 >= num_occurrences_of_current_visit) { |
341 if (ShouldReplaceCurrentPrerender(priority)) { | 435 RecordEvent(EVENT_ADD_VISIT_IDENTIFIED_PRERENDER_CANDIDATE); |
342 RecordEvent(EVENT_START_URL_LOOKUP); | 436 double priority = static_cast<double>(it->second) / |
343 HistoryService* history = GetHistoryIfExists(); | 437 static_cast<double>(num_occurrences_of_current_visit); |
344 if (history) { | 438 lookup_info->MaybeAddCandidateURL(it->first, priority); |
345 history->ScheduleDBTask( | |
346 new GetURLForURLIDTask( | |
347 best_next_url, | |
348 base::Bind(&PrerenderLocalPredictor::OnLookupURL, | |
349 base::Unretained(this), | |
350 best_next_url, | |
351 priority)), | |
352 &history_db_consumer_); | |
353 } | |
354 } | 439 } |
355 } | 440 } |
| 441 |
| 442 if (lookup_info->candidate_urls_.size() == 0) { |
| 443 RecordEvent(EVENT_NO_PRERENDER_CANDIDATES); |
| 444 return; |
| 445 } |
| 446 |
| 447 RecordEvent(EVENT_START_URL_LOOKUP); |
| 448 HistoryService* history = GetHistoryIfExists(); |
| 449 if (history) { |
| 450 RecordEvent(EVENT_GOT_HISTORY_ISSUING_LOOKUP); |
| 451 LocalPredictorURLLookupInfo* lookup_info_ptr = lookup_info.get(); |
| 452 history->ScheduleDBTask( |
| 453 new GetURLForURLIDTask( |
| 454 lookup_info_ptr, |
| 455 base::Bind(&PrerenderLocalPredictor::OnLookupURL, |
| 456 base::Unretained(this), |
| 457 base::Passed(&lookup_info))), |
| 458 &history_db_consumer_); |
| 459 } |
356 } | 460 } |
357 | 461 |
358 void PrerenderLocalPredictor::OnLookupURL(history::URLID url_id, | 462 void PrerenderLocalPredictor::OnLookupURL( |
359 double priority, | 463 scoped_ptr<LocalPredictorURLLookupInfo> info) { |
360 const GURL& url) { | |
361 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT); | 464 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT); |
362 | 465 |
363 base::Time current_time = GetCurrentTime(); | 466 DCHECK_GE(static_cast<int>(info->candidate_urls_.size()), 1); |
364 if (ShouldReplaceCurrentPrerender(priority)) { | 467 |
365 if (IsRootPageURL(url)) { | 468 if (!info->source_url_.url_lookup_success) { |
366 RecordEvent(EVENT_ADD_VISIT_PRERENDERING); | 469 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_FAILED); |
367 if (current_prerender_.get() && current_prerender_->url_id == url_id) { | 470 return; |
368 RecordEvent(EVENT_ADD_VISIT_PRERENDERING_EXTENDED); | 471 } |
369 if (priority > current_prerender_->priority) | 472 |
370 current_prerender_->priority = priority; | 473 LogCandidateURLStats(info->candidate_urls_[0].url); |
371 // If the prerender already existed, we want to extend it. However, | 474 |
372 // we do not want to set its start_time to the current time to | 475 WebContents* source_web_contents = NULL; |
373 // disadvantage PLT computations when the prerender is swapped in. | 476 |
374 // So we set the new start time to current_time - 10s (since the vast | 477 #if !defined(OS_ANDROID) |
375 // majority of PLTs are < 10s), provided that is not before the actual | 478 // We need to figure out what tab launched the prerender. We do this by |
376 // time the prerender was started (so as to not artificially advantage | 479 // comparing URLs. This may not always work: the URL may occur in two |
377 // the PLT computation). | 480 // tabs, and we pick the wrong one, or the tab we should have picked |
378 base::Time simulated_new_start_time = | 481 // may have navigated elsewhere. Hopefully, this doesn't happen too often, |
379 current_time - base::TimeDelta::FromSeconds(10); | 482 // so we ignore these cases for now. |
380 if (simulated_new_start_time > current_prerender_->start_time) | 483 // TODO(tburkard): Reconsider this, potentially measure it, and fix this |
381 current_prerender_->start_time = simulated_new_start_time; | 484 // in the future. |
382 } else { | 485 for (TabContentsIterator it; !it.done(); it.Next()) { |
383 current_prerender_.reset( | 486 if (it->GetURL() == info->source_url_.url) { |
384 new PrerenderData(url_id, url, priority, current_time)); | 487 source_web_contents = *it; |
385 } | 488 break; |
386 current_prerender_->actual_start_time = current_time; | |
387 } else { | |
388 RecordEvent(EVENT_ADD_VISIT_NOT_ROOTPAGE); | |
389 } | 489 } |
390 } | 490 } |
| 491 #endif |
391 | 492 |
| 493 if (!source_web_contents) { |
| 494 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_SOURCE_WEBCONTENTS_FOUND); |
| 495 return; |
| 496 } |
| 497 |
| 498 scoped_refptr<SessionStorageNamespace> session_storage_namespace = |
| 499 source_web_contents->GetController().GetDefaultSessionStorageNamespace(); |
| 500 |
| 501 gfx::Rect container_bounds; |
| 502 source_web_contents->GetView()->GetContainerBounds(&container_bounds); |
| 503 scoped_ptr<gfx::Size> size(new gfx::Size(container_bounds.size())); |
| 504 |
| 505 scoped_refptr<LoggedInPredictorTable> logged_in_table = |
| 506 prerender_manager_->logged_in_predictor_table(); |
| 507 |
| 508 if (!logged_in_table.get()) { |
| 509 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_LOGGED_IN_TABLE_FOUND); |
| 510 return; |
| 511 } |
| 512 |
| 513 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_ISSUING_LOGGED_IN_LOOKUP); |
| 514 |
| 515 LocalPredictorURLLookupInfo* info_ptr = info.get(); |
| 516 BrowserThread::PostTaskAndReply( |
| 517 BrowserThread::DB, FROM_HERE, |
| 518 base::Bind(&LookupLoggedInStatesOnDBThread, |
| 519 logged_in_table, |
| 520 info_ptr), |
| 521 base::Bind(&PrerenderLocalPredictor::ContinuePrerenderCheck, |
| 522 weak_factory_.GetWeakPtr(), |
| 523 session_storage_namespace, |
| 524 base::Passed(&size), |
| 525 base::Passed(&info))); |
| 526 } |
| 527 |
| 528 void PrerenderLocalPredictor::LogCandidateURLStats(const GURL& url) const { |
392 if (url_whitelist_.count(GetInt64URLHashForURL(url)) > 0) { | 529 if (url_whitelist_.count(GetInt64URLHashForURL(url)) > 0) { |
393 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST); | 530 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST); |
394 if (IsRootPageURL(url)) | 531 if (IsRootPageURL(url)) |
395 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST_ROOT_PAGE); | 532 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST_ROOT_PAGE); |
396 } | 533 } |
397 if (IsRootPageURL(url)) | 534 if (IsRootPageURL(url)) |
398 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE); | 535 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE); |
399 if (IsExtendedRootURL(url)) | 536 if (IsExtendedRootURL(url)) |
400 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_EXTENDED_ROOT_PAGE); | 537 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_EXTENDED_ROOT_PAGE); |
401 if (IsRootPageURL(url) && url.SchemeIs("http")) | 538 if (IsRootPageURL(url) && url.SchemeIs("http")) |
402 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE_HTTP); | 539 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE_HTTP); |
403 if (url.SchemeIs("http")) | 540 if (url.SchemeIs("http")) |
404 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_IS_HTTP); | 541 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_IS_HTTP); |
405 if (url.has_query()) | 542 if (url.has_query()) |
406 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_HAS_QUERY_STRING); | 543 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_HAS_QUERY_STRING); |
407 if (StrCaseStr(url.spec().c_str(), "logout") || | 544 if (IsLogOutURL(url)) |
408 StrCaseStr(url.spec().c_str(), "signout")) | |
409 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGOUT); | 545 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGOUT); |
410 if (StrCaseStr(url.spec().c_str(), "login") || | 546 if (IsLogInURL(url)) |
411 StrCaseStr(url.spec().c_str(), "signin")) | |
412 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGIN); | 547 RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGIN); |
413 } | 548 } |
414 | 549 |
415 void PrerenderLocalPredictor::OnGetInitialVisitHistory( | 550 void PrerenderLocalPredictor::OnGetInitialVisitHistory( |
416 scoped_ptr<std::vector<history::BriefVisitInfo> > visit_history) { | 551 scoped_ptr<vector<history::BriefVisitInfo> > visit_history) { |
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
418 DCHECK(!visit_history_.get()); | 553 DCHECK(!visit_history_.get()); |
419 RecordEvent(EVENT_INIT_SUCCEEDED); | 554 RecordEvent(EVENT_INIT_SUCCEEDED); |
420 // Since the visit history has descending timestamps, we must reverse it. | 555 // Since the visit history has descending timestamps, we must reverse it. |
421 visit_history_.reset(new std::vector<history::BriefVisitInfo>( | 556 visit_history_.reset(new vector<history::BriefVisitInfo>( |
422 visit_history->rbegin(), visit_history->rend())); | 557 visit_history->rbegin(), visit_history->rend())); |
423 } | 558 } |
424 | 559 |
425 HistoryService* PrerenderLocalPredictor::GetHistoryIfExists() const { | 560 HistoryService* PrerenderLocalPredictor::GetHistoryIfExists() const { |
426 Profile* profile = prerender_manager_->profile(); | 561 Profile* profile = prerender_manager_->profile(); |
427 if (!profile) | 562 if (!profile) |
428 return NULL; | 563 return NULL; |
429 return HistoryServiceFactory::GetForProfileWithoutCreating(profile); | 564 return HistoryServiceFactory::GetForProfileWithoutCreating(profile); |
430 } | 565 } |
431 | 566 |
432 void PrerenderLocalPredictor::Init() { | 567 void PrerenderLocalPredictor::Init() { |
433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
434 RecordEvent(EVENT_INIT_STARTED); | 569 RecordEvent(EVENT_INIT_STARTED); |
435 HistoryService* history = GetHistoryIfExists(); | 570 HistoryService* history = GetHistoryIfExists(); |
436 if (history) { | 571 if (history) { |
437 CHECK(!is_visit_database_observer_); | 572 CHECK(!is_visit_database_observer_); |
438 history->ScheduleDBTask( | 573 history->ScheduleDBTask( |
439 new GetVisitHistoryTask(this, kMaxVisitHistory), | 574 new GetVisitHistoryTask(this, kMaxVisitHistory), |
440 &history_db_consumer_); | 575 &history_db_consumer_); |
441 history->AddVisitDatabaseObserver(this); | 576 history->AddVisitDatabaseObserver(this); |
442 is_visit_database_observer_ = true; | 577 is_visit_database_observer_ = true; |
443 } else { | 578 } else { |
444 RecordEvent(EVENT_INIT_FAILED_NO_HISTORY); | 579 RecordEvent(EVENT_INIT_FAILED_NO_HISTORY); |
445 } | 580 } |
446 } | 581 } |
447 | 582 |
448 void PrerenderLocalPredictor::OnPLTEventForURL(const GURL& url, | 583 void PrerenderLocalPredictor::OnPLTEventForURL(const GURL& url, |
449 base::TimeDelta page_load_time) { | 584 base::TimeDelta page_load_time) { |
450 scoped_ptr<PrerenderData> prerender; | 585 scoped_ptr<PrerenderProperties> prerender; |
451 if (DoesPrerenderMatchPLTRecord(last_swapped_in_prerender_.get(), | 586 if (DoesPrerenderMatchPLTRecord(last_swapped_in_prerender_.get(), |
452 url, page_load_time)) { | 587 url, page_load_time)) { |
453 prerender.reset(last_swapped_in_prerender_.release()); | 588 prerender.reset(last_swapped_in_prerender_.release()); |
454 } | 589 } |
455 if (DoesPrerenderMatchPLTRecord(current_prerender_.get(), | 590 if (DoesPrerenderMatchPLTRecord(current_prerender_.get(), |
456 url, page_load_time)) { | 591 url, page_load_time)) { |
457 prerender.reset(current_prerender_.release()); | 592 prerender.reset(current_prerender_.release()); |
458 } | 593 } |
459 if (!prerender.get()) | 594 if (!prerender.get()) |
460 return; | 595 return; |
(...skipping 12 matching lines...) Expand all Loading... |
473 UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingPLT", | 608 UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingPLT", |
474 new_plt, | 609 new_plt, |
475 base::TimeDelta::FromMilliseconds(10), | 610 base::TimeDelta::FromMilliseconds(10), |
476 base::TimeDelta::FromSeconds(60), | 611 base::TimeDelta::FromSeconds(60), |
477 100); | 612 100); |
478 } | 613 } |
479 } | 614 } |
480 } | 615 } |
481 | 616 |
482 bool PrerenderLocalPredictor::IsPrerenderStillValid( | 617 bool PrerenderLocalPredictor::IsPrerenderStillValid( |
483 PrerenderLocalPredictor::PrerenderData* prerender) const { | 618 PrerenderLocalPredictor::PrerenderProperties* prerender) const { |
484 return (prerender && | 619 return (prerender && |
485 (prerender->start_time + | 620 (prerender->start_time + |
486 base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs)) | 621 base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs)) |
487 > GetCurrentTime()); | 622 > GetCurrentTime()); |
488 } | 623 } |
489 | 624 |
490 void PrerenderLocalPredictor::RecordEvent( | 625 void PrerenderLocalPredictor::RecordEvent( |
491 PrerenderLocalPredictor::Event event) const { | 626 PrerenderLocalPredictor::Event event) const { |
492 UMA_HISTOGRAM_ENUMERATION("Prerender.LocalPredictorEvent", | 627 UMA_HISTOGRAM_ENUMERATION("Prerender.LocalPredictorEvent", |
493 event, PrerenderLocalPredictor::EVENT_MAX_VALUE); | 628 event, PrerenderLocalPredictor::EVENT_MAX_VALUE); |
494 } | 629 } |
495 | 630 |
496 bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord( | 631 bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord( |
497 PrerenderData* prerender, const GURL& url, base::TimeDelta plt) const { | 632 PrerenderProperties* prerender, |
| 633 const GURL& url, |
| 634 base::TimeDelta plt) const { |
498 if (prerender && prerender->start_time < GetCurrentTime() - plt) { | 635 if (prerender && prerender->start_time < GetCurrentTime() - plt) { |
499 if (prerender->url.is_empty()) | 636 if (prerender->url.is_empty()) |
500 RecordEvent(EVENT_ERROR_NO_PRERENDER_URL_FOR_PLT); | 637 RecordEvent(EVENT_ERROR_NO_PRERENDER_URL_FOR_PLT); |
501 return (prerender->url == url); | 638 return (prerender->url == url); |
502 } else { | 639 } else { |
503 return false; | 640 return false; |
504 } | 641 } |
505 } | 642 } |
506 | 643 |
507 bool PrerenderLocalPredictor::ShouldReplaceCurrentPrerender( | 644 bool PrerenderLocalPredictor::ShouldReplaceCurrentPrerender( |
508 double priority) const { | 645 double priority) const { |
509 base::TimeDelta max_age = | 646 return (!prerender_handle_.get() || |
510 base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs); | 647 !prerender_handle_->IsPrerendering() || |
511 return (!current_prerender_.get()) || | 648 current_prerender_priority_ < priority); |
512 current_prerender_->priority < priority || | 649 } |
513 current_prerender_->start_time < GetCurrentTime() - max_age; | 650 |
| 651 void PrerenderLocalPredictor::ContinuePrerenderCheck( |
| 652 scoped_refptr<SessionStorageNamespace> session_storage_namespace, |
| 653 scoped_ptr<gfx::Size> size, |
| 654 scoped_ptr<LocalPredictorURLLookupInfo> info) { |
| 655 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_STARTED); |
| 656 scoped_ptr<LocalPredictorURLInfo> url_info; |
| 657 for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) { |
| 658 url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i])); |
| 659 |
| 660 // We need to check whether we can issue a prerender for this URL. |
| 661 // We test a set of conditions. Each condition can either rule out |
| 662 // a prerender (in which case we reset url_info, so that it will not |
| 663 // be prerendered, and we continue, which means try the next candidate |
| 664 // URL), or it can be sufficient to issue the prerender without any |
| 665 // further checks (in which case we just break). |
| 666 // The order of the checks is critical, because it prescribes the logic |
| 667 // we use here to decide what to prerender. |
| 668 if (!url_info->url_lookup_success) { |
| 669 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NO_URL); |
| 670 url_info.reset(NULL); |
| 671 continue; |
| 672 } |
| 673 if (!ShouldReplaceCurrentPrerender(url_info->priority)) { |
| 674 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW); |
| 675 url_info.reset(NULL); |
| 676 continue; |
| 677 } |
| 678 if (URLsIdenticalIgnoringFragments(info->source_url_.url, |
| 679 url_info->url)) { |
| 680 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_URLS_IDENTICAL_BUT_FRAGMENT); |
| 681 url_info.reset(NULL); |
| 682 continue; |
| 683 } |
| 684 if (url_info->url.SchemeIs("https")) { |
| 685 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_HTTPS); |
| 686 url_info.reset(NULL); |
| 687 continue; |
| 688 } |
| 689 if (IsRootPageURL(url_info->url)) { |
| 690 // For root pages, we assume that they are reasonably safe, and we |
| 691 // will just prerender them without any additional checks. |
| 692 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ROOT_PAGE); |
| 693 break; |
| 694 } |
| 695 if (IsLogOutURL(url_info->url)) { |
| 696 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGOUT_URL); |
| 697 url_info.reset(NULL); |
| 698 continue; |
| 699 } |
| 700 if (IsLogInURL(url_info->url)) { |
| 701 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGIN_URL); |
| 702 url_info.reset(NULL); |
| 703 continue; |
| 704 } |
| 705 if (!url_info->logged_in && url_info->logged_in_lookup_ok) { |
| 706 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NOT_LOGGED_IN); |
| 707 break; |
| 708 } |
| 709 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_NOT_PRERENDERING); |
| 710 url_info.reset(NULL); |
| 711 } |
| 712 if (!url_info.get()) |
| 713 return; |
| 714 RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER); |
| 715 IssuePrerender(session_storage_namespace, size.Pass(), |
| 716 url_info.Pass()); |
| 717 } |
| 718 |
| 719 void PrerenderLocalPredictor::IssuePrerender( |
| 720 scoped_refptr<SessionStorageNamespace> session_storage_namespace, |
| 721 scoped_ptr<gfx::Size> size, |
| 722 scoped_ptr<LocalPredictorURLInfo> info) { |
| 723 URLID url_id = info->id; |
| 724 const GURL& url = info->url; |
| 725 double priority = info->priority; |
| 726 base::Time current_time = GetCurrentTime(); |
| 727 RecordEvent(EVENT_ISSUING_PRERENDER); |
| 728 |
| 729 current_prerender_priority_ = priority; |
| 730 scoped_ptr<prerender::PrerenderHandle> old_prerender_handle( |
| 731 prerender_handle_.release()); |
| 732 prerender_handle_.reset(prerender_manager_->AddPrerenderFromLocalPredictor( |
| 733 url, session_storage_namespace.get(), *size)); |
| 734 if (old_prerender_handle) |
| 735 old_prerender_handle->OnCancel(); |
| 736 |
| 737 RecordEvent(EVENT_ADD_VISIT_PRERENDERING); |
| 738 if (current_prerender_.get() && current_prerender_->url_id == url_id) { |
| 739 RecordEvent(EVENT_ADD_VISIT_PRERENDERING_EXTENDED); |
| 740 if (priority > current_prerender_->priority) |
| 741 current_prerender_->priority = priority; |
| 742 // If the prerender already existed, we want to extend it. However, |
| 743 // we do not want to set its start_time to the current time to |
| 744 // disadvantage PLT computations when the prerender is swapped in. |
| 745 // So we set the new start time to current_time - 10s (since the vast |
| 746 // majority of PLTs are < 10s), provided that is not before the actual |
| 747 // time the prerender was started (so as to not artificially advantage |
| 748 // the PLT computation). |
| 749 base::Time simulated_new_start_time = |
| 750 current_time - base::TimeDelta::FromSeconds(10); |
| 751 if (simulated_new_start_time > current_prerender_->start_time) |
| 752 current_prerender_->start_time = simulated_new_start_time; |
| 753 } else { |
| 754 current_prerender_.reset( |
| 755 new PrerenderProperties(url_id, url, priority, current_time)); |
| 756 } |
| 757 current_prerender_->actual_start_time = current_time; |
514 } | 758 } |
515 | 759 |
516 } // namespace prerender | 760 } // namespace prerender |
OLD | NEW |