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

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: Fixing leak by checking for a valid Prerender source 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 46
47 struct PrerenderManager::PrerenderContentsData { 47 struct PrerenderManager::PrerenderContentsData {
48 PrerenderContents* contents_; 48 PrerenderContents* contents_;
49 base::Time start_time_; 49 base::Time start_time_;
50 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) 50 PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
51 : contents_(contents), 51 : contents_(contents),
52 start_time_(start_time) { 52 start_time_(start_time) {
53 } 53 }
54 }; 54 };
55 55
56 struct PrerenderManager::PendingContentsData {
57 PendingContentsData(const GURL& url, const std::vector<GURL>& alias_urls,
58 const GURL& referrer)
59 : url_(url), alias_urls_(alias_urls), referrer_(referrer) { }
60 ~PendingContentsData() {}
61 GURL url_;
62 std::vector<GURL> alias_urls_;
63 GURL referrer_;
64 };
65
66
56 PrerenderManager::PrerenderManager(Profile* profile) 67 PrerenderManager::PrerenderManager(Profile* profile)
57 : profile_(profile), 68 : profile_(profile),
58 max_prerender_age_(base::TimeDelta::FromSeconds( 69 max_prerender_age_(base::TimeDelta::FromSeconds(
59 kDefaultMaxPrerenderAgeSeconds)), 70 kDefaultMaxPrerenderAgeSeconds)),
60 max_elements_(kDefaultMaxPrerenderElements), 71 max_elements_(kDefaultMaxPrerenderElements),
61 prerender_contents_factory_(PrerenderContents::CreateFactory()) { 72 prerender_contents_factory_(PrerenderContents::CreateFactory()) {
62 } 73 }
63 74
64 PrerenderManager::~PrerenderManager() { 75 PrerenderManager::~PrerenderManager() {
65 while (!prerender_list_.empty()) { 76 while (!prerender_list_.empty()) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 while (prerender_list_.size() > max_elements_) { 111 while (prerender_list_.size() > max_elements_) {
101 data = prerender_list_.front(); 112 data = prerender_list_.front();
102 prerender_list_.pop_front(); 113 prerender_list_.pop_front();
103 data.contents_->set_final_status(FINAL_STATUS_EVICTED); 114 data.contents_->set_final_status(FINAL_STATUS_EVICTED);
104 delete data.contents_; 115 delete data.contents_;
105 } 116 }
106 StartSchedulingPeriodicCleanups(); 117 StartSchedulingPeriodicCleanups();
107 return true; 118 return true;
108 } 119 }
109 120
121 void PrerenderManager::AddPendingPreload(
122 const std::pair<int,int>& child_route_id_pair,
123 const GURL& url,
124 const std::vector<GURL>& alias_urls,
125 const GURL& referrer) {
126 // Check if this is coming from a valid prerender rvh.
127 bool is_valid_prerender = false;
128 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
129 it != prerender_list_.end(); ++it) {
cbentzel 2011/03/18 18:35:43 This is a pretty subtle case. Could you add a test
dominich 2011/03/21 16:36:11 Done.
130 PrerenderContents* pc = it->contents_;
131 const RenderViewHost* rvh = pc->render_view_host();
132 if (rvh &&
133 rvh->process() &&
cbentzel 2011/03/18 18:35:43 You don't check for process() in RemovePendingPrel
dominich 2011/03/21 16:36:11 Actually no - I checked that when I wrote RemovePe
134 rvh->process()->id() == child_route_id_pair.first &&
135 rvh->routing_id() == child_route_id_pair.second) {
136 is_valid_prerender = true;
137 break;
138 }
139 }
140
141 // If not, we could check to see if the RenderViewHost specified by the
142 // child_route_id_pair exists and if so just start prerendering, as this
143 // suggests that the link was clicked, though this might prerender something
144 // that the user has already navigated away from. For now, we'll be
145 // conservative and skip the prerender which will mean some prerender requests
146 // from prerendered pages will be missed if the user navigates quickly.
cbentzel 2011/03/18 18:35:43 Should you add a FINAL_STATUS entry here? This is
dominich 2011/03/21 16:36:11 I thought about it, but we're not creating the pre
147 if (!is_valid_prerender)
cbentzel 2011/03/18 18:35:43 Thanks for the comment here.
148 return;
149
150 PendingPrerenderList::iterator it =
151 pending_prerender_list_.find(child_route_id_pair);
152 if (it == pending_prerender_list_.end()) {
153 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair,
154 std::vector<PendingContentsData>());
155 it = pending_prerender_list_.insert(el).first;
156 }
157
158 it->second.push_back(PendingContentsData(url, alias_urls, referrer));
159 }
160
110 void PrerenderManager::DeleteOldEntries() { 161 void PrerenderManager::DeleteOldEntries() {
111 while (!prerender_list_.empty()) { 162 while (!prerender_list_.empty()) {
112 PrerenderContentsData data = prerender_list_.front(); 163 PrerenderContentsData data = prerender_list_.front();
113 if (IsPrerenderElementFresh(data.start_time_)) 164 if (IsPrerenderElementFresh(data.start_time_))
114 return; 165 return;
115 prerender_list_.pop_front(); 166 prerender_list_.pop_front();
116 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); 167 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT);
117 delete data.contents_; 168 delete data.contents_;
118 } 169 }
119 if (prerender_list_.empty()) 170 if (prerender_list_.empty())
(...skipping 28 matching lines...) Expand all
148 199
149 RenderViewHost* rvh = pc->render_view_host(); 200 RenderViewHost* rvh = pc->render_view_host();
150 // RenderViewHosts in PrerenderContents start out hidden. 201 // RenderViewHosts in PrerenderContents start out hidden.
151 // Since we are actually using it now, restore it. 202 // Since we are actually using it now, restore it.
152 rvh->WasRestored(); 203 rvh->WasRestored();
153 pc->set_render_view_host(NULL); 204 pc->set_render_view_host(NULL);
154 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); 205 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id()));
155 tc->SwapInRenderViewHost(rvh); 206 tc->SwapInRenderViewHost(rvh);
156 MarkTabContentsAsPrerendered(tc); 207 MarkTabContentsAsPrerendered(tc);
157 208
209 // See if we have any pending prerender requests for this routing id and start
210 // the preload if we do.
211 std::pair<int, int> child_route_pair = std::make_pair(rvh->process()->id(),
212 rvh->routing_id());
213 PendingPrerenderList::iterator pending_it =
214 pending_prerender_list_.find(child_route_pair);
215 if (pending_it != pending_prerender_list_.end()) {
216 for (std::vector<PendingContentsData>::iterator content_it =
217 pending_it->second.begin();
218 content_it != pending_it->second.end(); ++content_it) {
219 AddPreload(content_it->url_, content_it->alias_urls_,
220 content_it->referrer_);
221 }
222 pending_prerender_list_.erase(pending_it);
223 }
224
158 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); 225 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params();
159 if (p != NULL) 226 if (p != NULL)
160 tc->DidNavigate(rvh, *p); 227 tc->DidNavigate(rvh, *p);
161 228
162 string16 title = pc->title(); 229 string16 title = pc->title();
163 if (!title.empty()) 230 if (!title.empty())
164 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title)); 231 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title));
165 232
166 GURL icon_url = pc->icon_url(); 233 GURL icon_url = pc->icon_url();
167 if (!icon_url.is_empty()) 234 if (!icon_url.is_empty())
168 tc->fav_icon_helper().OnUpdateFavIconURL(pc->page_id(), icon_url); 235 tc->fav_icon_helper().OnUpdateFavIconURL(pc->page_id(), icon_url);
169 236
170 if (pc->has_stopped_loading()) 237 if (pc->has_stopped_loading())
171 tc->DidStopLoading(); 238 tc->DidStopLoading();
172 239
173 return true; 240 return true;
174 } 241 }
175 242
176 void PrerenderManager::RemoveEntry(PrerenderContents* entry) { 243 void PrerenderManager::RemoveEntry(PrerenderContents* entry) {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
178 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); 245 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
179 it != prerender_list_.end(); 246 it != prerender_list_.end();
180 ++it) { 247 ++it) {
181 if (it->contents_ == entry) { 248 if (it->contents_ == entry) {
249 RemovePendingPreload(entry);
182 prerender_list_.erase(it); 250 prerender_list_.erase(it);
183 break; 251 break;
184 } 252 }
185 } 253 }
186 DeleteOldEntries(); 254 DeleteOldEntries();
187 } 255 }
188 256
189 base::Time PrerenderManager::GetCurrentTime() const { 257 base::Time PrerenderManager::GetCurrentTime() const {
190 return base::Time::Now(); 258 return base::Time::Now();
191 } 259 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); 302 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
235 it != prerender_list_.end(); 303 it != prerender_list_.end();
236 ++it) { 304 ++it) {
237 if (it->contents_->MatchesURL(url)) 305 if (it->contents_->MatchesURL(url))
238 return it->contents_; 306 return it->contents_;
239 } 307 }
240 // Entry not found. 308 // Entry not found.
241 return NULL; 309 return NULL;
242 } 310 }
243 311
312 PrerenderManager::PendingContentsData*
313 PrerenderManager::FindPendingEntry(const GURL& url) {
314 for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin();
315 map_it != pending_prerender_list_.end();
316 ++map_it) {
317 for (std::vector<PendingContentsData>::iterator content_it =
318 map_it->second.begin();
319 content_it != map_it->second.end();
320 ++content_it) {
321 if (content_it->url_ == url)
322 return &(*content_it);
323 }
324 }
325
326 return NULL;
327 }
328
244 // static 329 // static
245 void PrerenderManager::RecordPrefetchTagObserved() { 330 void PrerenderManager::RecordPrefetchTagObserved() {
246 // Ensure that we are in the UI thread, and post to the UI thread if 331 // Ensure that we are in the UI thread, and post to the UI thread if
247 // necessary. 332 // necessary.
248 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 333 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
249 BrowserThread::PostTask( 334 BrowserThread::PostTask(
250 BrowserThread::UI, 335 BrowserThread::UI,
251 FROM_HERE, 336 FROM_HERE,
252 NewRunnableFunction( 337 NewRunnableFunction(
253 &PrerenderManager::RecordPrefetchTagObservedOnUIThread)); 338 &PrerenderManager::RecordPrefetchTagObservedOnUIThread));
254 } else { 339 } else {
255 RecordPrefetchTagObservedOnUIThread(); 340 RecordPrefetchTagObservedOnUIThread();
256 } 341 }
257 } 342 }
258 343
259 // static 344 // static
260 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { 345 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() {
261 // Once we get here, we have to be on the UI thread. 346 // Once we get here, we have to be on the UI thread.
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
263 348
264 // If we observe multiple tags within the 30 second window, we will still 349 // If we observe multiple tags within the 30 second window, we will still
265 // reset the window to begin at the most recent occurrence, so that we will 350 // reset the window to begin at the most recent occurrence, so that we will
266 // always be in a window in the 30 seconds from each occurrence. 351 // always be in a window in the 30 seconds from each occurrence.
267 last_prefetch_seen_time_ = base::TimeTicks::Now(); 352 last_prefetch_seen_time_ = base::TimeTicks::Now();
268 } 353 }
269 354
355 void PrerenderManager::RemovePendingPreload(PrerenderContents* entry) {
cbentzel 2011/03/18 18:35:43 can |entry| be const?
dominich 2011/03/21 16:36:11 no - render_view_host() is not const. Is there pr
356 RenderViewHost* rvh = entry->render_view_host();
357
358 // If the entry doesn't have a RenderViewHost then it didn't start
359 // prerendering and there shouldn't be any pending preloads to remove.
360 if (rvh == NULL)
361 return;
362
363 std::pair<int, int> child_route_pair = std::make_pair(rvh->process()->id(),
364 rvh->routing_id());
365 pending_prerender_list_.erase(child_route_pair);
366 }
367
270 // static 368 // static
271 bool PrerenderManager::ShouldRecordWindowedPPLT() { 369 bool PrerenderManager::ShouldRecordWindowedPPLT() {
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
273 if (last_prefetch_seen_time_.is_null()) 371 if (last_prefetch_seen_time_.is_null())
274 return false; 372 return false;
275 base::TimeDelta elapsed_time = 373 base::TimeDelta elapsed_time =
276 base::TimeTicks::Now() - last_prefetch_seen_time_; 374 base::TimeTicks::Now() - last_prefetch_seen_time_;
277 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); 375 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds);
278 } 376 }
279 377
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 412
315 void PrerenderManager::MarkTabContentsAsNotPrerendered(TabContents* tc) { 413 void PrerenderManager::MarkTabContentsAsNotPrerendered(TabContents* tc) {
316 prerendered_tc_set_.erase(tc); 414 prerendered_tc_set_.erase(tc);
317 } 415 }
318 416
319 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { 417 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const {
320 return prerendered_tc_set_.count(tc) > 0; 418 return prerendered_tc_set_.count(tc) > 0;
321 } 419 }
322 420
323 } // namespace prerender 421 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698