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

Side by Side Diff: chrome/browser/prerender/prerender_manager.cc

Issue 6625066: Add pending preloads indexed by routing id. Start preloading once we navigate. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fetch/merge Created 9 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_manager.h" 5 #include "chrome/browser/prerender/prerender_manager.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "base/time.h" 9 #include "base/time.h"
10 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 53
54 struct PrerenderManager::PrerenderContentsData { 54 struct PrerenderManager::PrerenderContentsData {
55 PrerenderContents* contents_; 55 PrerenderContents* contents_;
56 base::Time start_time_; 56 base::Time start_time_;
57 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) 57 PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
58 : contents_(contents), 58 : contents_(contents),
59 start_time_(start_time) { 59 start_time_(start_time) {
60 } 60 }
61 }; 61 };
62 62
63 struct PrerenderManager::PendingContentsData {
64 PendingContentsData(const GURL& url, const std::vector<GURL>& alias_urls,
65 const GURL& referrer)
66 : url_(url), alias_urls_(alias_urls), referrer_(referrer) { }
67 ~PendingContentsData() {}
68 GURL url_;
69 std::vector<GURL> alias_urls_;
70 GURL referrer_;
71 };
72
73
63 PrerenderManager::PrerenderManager(Profile* profile) 74 PrerenderManager::PrerenderManager(Profile* profile)
64 : profile_(profile), 75 : profile_(profile),
65 max_prerender_age_(base::TimeDelta::FromSeconds( 76 max_prerender_age_(base::TimeDelta::FromSeconds(
66 kDefaultMaxPrerenderAgeSeconds)), 77 kDefaultMaxPrerenderAgeSeconds)),
67 max_elements_(kDefaultMaxPrerenderElements), 78 max_elements_(kDefaultMaxPrerenderElements),
68 prerender_contents_factory_(PrerenderContents::CreateFactory()) { 79 prerender_contents_factory_(PrerenderContents::CreateFactory()) {
69 } 80 }
70 81
71 PrerenderManager::~PrerenderManager() { 82 PrerenderManager::~PrerenderManager() {
72 while (!prerender_list_.empty()) { 83 while (!prerender_list_.empty()) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 while (prerender_list_.size() > max_elements_) { 121 while (prerender_list_.size() > max_elements_) {
111 data = prerender_list_.front(); 122 data = prerender_list_.front();
112 prerender_list_.pop_front(); 123 prerender_list_.pop_front();
113 data.contents_->set_final_status(FINAL_STATUS_EVICTED); 124 data.contents_->set_final_status(FINAL_STATUS_EVICTED);
114 delete data.contents_; 125 delete data.contents_;
115 } 126 }
116 StartSchedulingPeriodicCleanups(); 127 StartSchedulingPeriodicCleanups();
117 return true; 128 return true;
118 } 129 }
119 130
131 void PrerenderManager::AddPendingPreload(
132 const std::pair<int,int>& child_route_id_pair,
133 const GURL& url,
134 const std::vector<GURL>& alias_urls,
135 const GURL& referrer) {
136 // Check if this is coming from a valid prerender rvh.
137
138 bool is_valid_prerender = false;
139 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
140 it != prerender_list_.end(); ++it) {
141 PrerenderContents* pc = it->contents_;
142
143 int child_id;
144 int route_id;
145 bool has_child_id = pc->child_id(&child_id);
cbentzel 2011/03/21 19:46:04 Probably not important, but you could do if (pc->
dominich 2011/03/21 20:25:51 Short-circuited, but slightly differently to retai
146 bool has_route_id = pc->route_id(&route_id);
147
148 if (has_child_id && has_route_id &&
149 child_id == child_route_id_pair.first &&
150 route_id == child_route_id_pair.second) {
151 is_valid_prerender = true;
152 break;
153 }
154 }
155
156 // If not, we could check to see if the RenderViewHost specified by the
157 // child_route_id_pair exists and if so just start prerendering, as this
158 // suggests that the link was clicked, though this might prerender something
159 // that the user has already navigated away from. For now, we'll be
160 // conservative and skip the prerender which will mean some prerender requests
161 // from prerendered pages will be missed if the user navigates quickly.
162 if (!is_valid_prerender) {
163 RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED);
164 return;
165 }
166
167 PendingPrerenderList::iterator it =
168 pending_prerender_list_.find(child_route_id_pair);
169 if (it == pending_prerender_list_.end()) {
170 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair,
171 std::vector<PendingContentsData>());
172 it = pending_prerender_list_.insert(el).first;
173 }
174
175 it->second.push_back(PendingContentsData(url, alias_urls, referrer));
176 }
177
120 void PrerenderManager::DeleteOldEntries() { 178 void PrerenderManager::DeleteOldEntries() {
121 while (!prerender_list_.empty()) { 179 while (!prerender_list_.empty()) {
122 PrerenderContentsData data = prerender_list_.front(); 180 PrerenderContentsData data = prerender_list_.front();
123 if (IsPrerenderElementFresh(data.start_time_)) 181 if (IsPrerenderElementFresh(data.start_time_))
124 return; 182 return;
125 prerender_list_.pop_front(); 183 prerender_list_.pop_front();
126 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); 184 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT);
127 delete data.contents_; 185 delete data.contents_;
128 } 186 }
129 if (prerender_list_.empty()) 187 if (prerender_list_.empty())
(...skipping 27 matching lines...) Expand all
157 // be showing a prerendered contents, but otherwise, don't do anything. 215 // be showing a prerendered contents, but otherwise, don't do anything.
158 if (!pc->prerendering_has_started()) { 216 if (!pc->prerendering_has_started()) {
159 MarkTabContentsAsWouldBePrerendered(tc); 217 MarkTabContentsAsWouldBePrerendered(tc);
160 return false; 218 return false;
161 } 219 }
162 220
163 if (!pc->load_start_time().is_null()) 221 if (!pc->load_start_time().is_null())
164 RecordTimeUntilUsed(base::TimeTicks::Now() - pc->load_start_time()); 222 RecordTimeUntilUsed(base::TimeTicks::Now() - pc->load_start_time());
165 pc->set_final_status(FINAL_STATUS_USED); 223 pc->set_final_status(FINAL_STATUS_USED);
166 224
225 int child_id;
226 int route_id;
227 CHECK(pc->child_id(&child_id));
cbentzel 2011/03/21 19:46:04 CHECK is probably OK here, although I'd hate to cr
dominich 2011/03/21 20:25:51 I considered that, but I wasn't sure what an inval
mmenke 2011/03/21 21:18:57 I've seen -1 used to check for invalid elsewhere,
228 CHECK(pc->route_id(&route_id));
229
167 RenderViewHost* rvh = pc->render_view_host(); 230 RenderViewHost* rvh = pc->render_view_host();
168 // RenderViewHosts in PrerenderContents start out hidden. 231 // RenderViewHosts in PrerenderContents start out hidden.
169 // Since we are actually using it now, restore it. 232 // Since we are actually using it now, restore it.
170 rvh->WasRestored(); 233 rvh->WasRestored();
171 pc->set_render_view_host(NULL); 234 pc->set_render_view_host(NULL);
172 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); 235 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id()));
173 tc->SwapInRenderViewHost(rvh); 236 tc->SwapInRenderViewHost(rvh);
174 MarkTabContentsAsPrerendered(tc); 237 MarkTabContentsAsPrerendered(tc);
175 238
239 // See if we have any pending prerender requests for this routing id and start
240 // the preload if we do.
241 std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
242 PendingPrerenderList::iterator pending_it =
243 pending_prerender_list_.find(child_route_pair);
244 if (pending_it != pending_prerender_list_.end()) {
245 for (std::vector<PendingContentsData>::iterator content_it =
246 pending_it->second.begin();
247 content_it != pending_it->second.end(); ++content_it) {
248 AddPreload(content_it->url_, content_it->alias_urls_,
249 content_it->referrer_);
250 }
251 pending_prerender_list_.erase(pending_it);
252 }
253
176 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); 254 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params();
177 if (p != NULL) 255 if (p != NULL)
178 tc->DidNavigate(rvh, *p); 256 tc->DidNavigate(rvh, *p);
179 257
180 string16 title = pc->title(); 258 string16 title = pc->title();
181 if (!title.empty()) 259 if (!title.empty())
182 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title)); 260 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title));
183 261
184 GURL icon_url = pc->icon_url(); 262 GURL icon_url = pc->icon_url();
185 if (!icon_url.is_empty()) 263 if (!icon_url.is_empty())
186 tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), icon_url); 264 tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), icon_url);
187 265
188 if (pc->has_stopped_loading()) 266 if (pc->has_stopped_loading())
189 tc->DidStopLoading(); 267 tc->DidStopLoading();
190 268
191 return true; 269 return true;
192 } 270 }
193 271
194 void PrerenderManager::RemoveEntry(PrerenderContents* entry) { 272 void PrerenderManager::RemoveEntry(PrerenderContents* entry) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
196 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); 274 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
197 it != prerender_list_.end(); 275 it != prerender_list_.end();
198 ++it) { 276 ++it) {
199 if (it->contents_ == entry) { 277 if (it->contents_ == entry) {
278 RemovePendingPreload(entry);
200 prerender_list_.erase(it); 279 prerender_list_.erase(it);
201 break; 280 break;
202 } 281 }
203 } 282 }
204 DeleteOldEntries(); 283 DeleteOldEntries();
205 } 284 }
206 285
207 base::Time PrerenderManager::GetCurrentTime() const { 286 base::Time PrerenderManager::GetCurrentTime() const {
208 return base::Time::Now(); 287 return base::Time::Now();
209 } 288 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); 352 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
274 it != prerender_list_.end(); 353 it != prerender_list_.end();
275 ++it) { 354 ++it) {
276 if (it->contents_->MatchesURL(url)) 355 if (it->contents_->MatchesURL(url))
277 return it->contents_; 356 return it->contents_;
278 } 357 }
279 // Entry not found. 358 // Entry not found.
280 return NULL; 359 return NULL;
281 } 360 }
282 361
362 PrerenderManager::PendingContentsData*
363 PrerenderManager::FindPendingEntry(const GURL& url) {
364 for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin();
365 map_it != pending_prerender_list_.end();
366 ++map_it) {
367 for (std::vector<PendingContentsData>::iterator content_it =
368 map_it->second.begin();
369 content_it != map_it->second.end();
370 ++content_it) {
371 if (content_it->url_ == url) {
372 return &(*content_it);
373 }
374 }
375 }
376
377 return NULL;
378 }
379
283 // static 380 // static
284 void PrerenderManager::RecordPrefetchTagObserved() { 381 void PrerenderManager::RecordPrefetchTagObserved() {
285 // Ensure that we are in the UI thread, and post to the UI thread if 382 // Ensure that we are in the UI thread, and post to the UI thread if
286 // necessary. 383 // necessary.
287 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 384 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
288 BrowserThread::PostTask( 385 BrowserThread::PostTask(
289 BrowserThread::UI, 386 BrowserThread::UI,
290 FROM_HERE, 387 FROM_HERE,
291 NewRunnableFunction( 388 NewRunnableFunction(
292 &PrerenderManager::RecordPrefetchTagObservedOnUIThread)); 389 &PrerenderManager::RecordPrefetchTagObservedOnUIThread));
293 } else { 390 } else {
294 RecordPrefetchTagObservedOnUIThread(); 391 RecordPrefetchTagObservedOnUIThread();
295 } 392 }
296 } 393 }
297 394
298 // static 395 // static
299 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { 396 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() {
300 // Once we get here, we have to be on the UI thread. 397 // Once we get here, we have to be on the UI thread.
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
302 399
303 // If we observe multiple tags within the 30 second window, we will still 400 // If we observe multiple tags within the 30 second window, we will still
304 // reset the window to begin at the most recent occurrence, so that we will 401 // reset the window to begin at the most recent occurrence, so that we will
305 // always be in a window in the 30 seconds from each occurrence. 402 // always be in a window in the 30 seconds from each occurrence.
306 last_prefetch_seen_time_ = base::TimeTicks::Now(); 403 last_prefetch_seen_time_ = base::TimeTicks::Now();
307 } 404 }
308 405
406 void PrerenderManager::RemovePendingPreload(PrerenderContents* entry) {
407 RenderViewHost* rvh = entry->render_view_host();
cbentzel 2011/03/21 19:46:04 You could remove the rvh here, remove the CHECK's
dominich 2011/03/21 20:25:51 Done.
408
409 // If the entry doesn't have a RenderViewHost then it didn't start
410 // prerendering and there shouldn't be any pending preloads to remove.
411 if (rvh == NULL)
412 return;
413
414 int child_id;
415 int route_id;
416 CHECK(entry->child_id(&child_id));
417 CHECK(entry->route_id(&route_id));
418
419 std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
420 pending_prerender_list_.erase(child_route_pair);
421 }
422
309 // static 423 // static
310 bool PrerenderManager::ShouldRecordWindowedPPLT() { 424 bool PrerenderManager::ShouldRecordWindowedPPLT() {
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312 if (last_prefetch_seen_time_.is_null()) 426 if (last_prefetch_seen_time_.is_null())
313 return false; 427 return false;
314 base::TimeDelta elapsed_time = 428 base::TimeDelta elapsed_time =
315 base::TimeTicks::Now() - last_prefetch_seen_time_; 429 base::TimeTicks::Now() - last_prefetch_seen_time_;
316 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); 430 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds);
317 } 431 }
318 432
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 476
363 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { 477 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const {
364 return prerendered_tc_set_.count(tc) > 0; 478 return prerendered_tc_set_.count(tc) > 0;
365 } 479 }
366 480
367 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const { 481 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const {
368 return would_be_prerendered_tc_set_.count(tc) > 0; 482 return would_be_prerendered_tc_set_.count(tc) > 0;
369 } 483 }
370 484
371 } // namespace prerender 485 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698