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

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

Issue 11551003: Change multi-prerender API to include per launcher slots. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: clear to land Created 7 years, 12 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) 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_link_manager.h" 5 #include "chrome/browser/prerender/prerender_link_manager.h"
6 6
7 #include <limits> 7 #include <limits>
8 #include <set>
8 #include <utility> 9 #include <utility>
9 10
10 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
11 #include "chrome/browser/prerender/prerender_contents.h" 12 #include "chrome/browser/prerender/prerender_contents.h"
12 #include "chrome/browser/prerender/prerender_handle.h" 13 #include "chrome/browser/prerender/prerender_handle.h"
13 #include "chrome/browser/prerender/prerender_manager.h" 14 #include "chrome/browser/prerender/prerender_manager.h"
14 #include "chrome/browser/prerender/prerender_manager_factory.h" 15 #include "chrome/browser/prerender/prerender_manager_factory.h"
15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/common/prerender_messages.h" 17 #include "chrome/common/prerender_messages.h"
17 #include "content/public/browser/render_process_host.h" 18 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_view_host.h" 19 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/session_storage_namespace.h" 20 #include "content/public/browser/session_storage_namespace.h"
20 #include "content/public/common/referrer.h" 21 #include "content/public/common/referrer.h"
21 #include "googleurl/src/gurl.h" 22 #include "googleurl/src/gurl.h"
22 #include "ui/gfx/size.h" 23 #include "ui/gfx/size.h"
23 24
25 using base::TimeDelta;
26 using base::TimeTicks;
24 using content::RenderViewHost; 27 using content::RenderViewHost;
25 using content::SessionStorageNamespace; 28 using content::SessionStorageNamespace;
26 29
27 namespace { 30 namespace {
28 31
29 void Send(int child_id, IPC::Message* raw_message) { 32 void Send(int child_id, IPC::Message* raw_message) {
30 using content::RenderProcessHost; 33 using content::RenderProcessHost;
31 scoped_ptr<IPC::Message> own_message(raw_message); 34 scoped_ptr<IPC::Message> own_message(raw_message);
32 35
33 RenderProcessHost* render_process_host = RenderProcessHost::FromID(child_id); 36 RenderProcessHost* render_process_host = RenderProcessHost::FromID(child_id);
34 if (!render_process_host) 37 if (!render_process_host)
35 return; 38 return;
36 render_process_host->Send(own_message.release()); 39 render_process_host->Send(own_message.release());
37 } 40 }
38 41
39 } // namespace 42 } // namespace
40 43
41 namespace prerender { 44 namespace prerender {
42 45
43 PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager) 46 PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager)
44 : manager_(manager) { 47 : has_shutdown_(false),
48 manager_(manager) {
45 } 49 }
46 50
47 PrerenderLinkManager::~PrerenderLinkManager() { 51 PrerenderLinkManager::~PrerenderLinkManager() {
48 for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin(); 52 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
49 it != ids_to_handle_map_.end(); 53 i != prerenders_.end(); ++i) {
50 ++it) { 54 if (i->handle) {
51 PrerenderHandle* prerender_handle = it->second; 55 DCHECK(!i->handle->IsPrerendering())
52 DCHECK(!prerender_handle->IsPrerendering()) 56 << "All running prerenders should stop at the same time as the "
53 << "All running prerenders should stop at the same time as the " 57 << "PrerenderManager.";
54 << "PrerenderManager."; 58 delete i->handle;
55 delete prerender_handle; 59 i->handle = 0;
56 } 60 }
57 } 61 }
58 62 }
59 bool PrerenderLinkManager::OnAddPrerender(int child_id, 63
64 void PrerenderLinkManager::OnAddPrerender(int launcher_child_id,
60 int prerender_id, 65 int prerender_id,
61 const GURL& url, 66 const GURL& url,
62 const content::Referrer& referrer, 67 const content::Referrer& referrer,
63 const gfx::Size& size, 68 const gfx::Size& size,
64 int render_view_route_id) { 69 int render_view_route_id) {
65 DVLOG(2) << "OnAddPrerender, child_id = " << child_id 70 DCHECK_EQ(static_cast<LinkPrerender*>(NULL),
66 << ", prerender_id = " << prerender_id 71 FindByLauncherChildIdAndPrerenderId(launcher_child_id,
67 << ", url = " << url.spec(); 72 prerender_id));
68 DVLOG(3) << "... referrer url = " << referrer.url.spec() 73 LinkPrerender
69 << ", size = (" << size.width() << ", " << size.height() << ")" 74 prerender(launcher_child_id, prerender_id, url, referrer, size,
70 << ", render_view_route_id = " << render_view_route_id; 75 render_view_route_id, manager_->GetCurrentTimeTicks());
71 76 prerenders_.push_back(prerender);
72 77 StartPrerenders();
73 PrerenderHandle* prerender_handle =
74 manager_->AddPrerenderFromLinkRelPrerender(
75 child_id, render_view_route_id, url, referrer, size);
76 if (!prerender_handle)
77 return false;
78
79 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id);
80 DCHECK_EQ(0u, ids_to_handle_map_.count(child_and_prerender_id));
81 ids_to_handle_map_[child_and_prerender_id] = prerender_handle;
82
83 // If we are given a prerender that is already prerendering, we have missed
84 // the start event.
85 if (prerender_handle->IsPrerendering())
86 OnPrerenderStart(prerender_handle);
87 prerender_handle->SetObserver(this);
88 return true;
89 } 78 }
90 79
91 void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) { 80 void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) {
92 DVLOG(2) << "OnCancelPrerender, child_id = " << child_id 81 LinkPrerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
93 << ", prerender_id = " << prerender_id; 82 prerender_id);
94 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); 83 if (!prerender)
95 IdPairToPrerenderHandleMap::iterator id_to_handle_iter = 84 return;
96 ids_to_handle_map_.find(child_and_prerender_id); 85
97 if (id_to_handle_iter == ids_to_handle_map_.end()) { 86 // Remove the handle from the PrerenderLinkManager before we cancel this
98 DVLOG(5) << "... canceling a prerender that doesn't exist."; 87 // prerender, to avoid reentering the PrerenderLinkManager, sending events to
99 return; 88 // the underlying prerender and making a second erase.
100 } 89 scoped_ptr<PrerenderHandle> own_prerender_handle(prerender->handle);
101 90 prerender->handle = NULL;
102 scoped_ptr<PrerenderHandle> prerender_handle(id_to_handle_iter->second); 91 RemovePrerender(prerender);
103 ids_to_handle_map_.erase(id_to_handle_iter); 92
104 prerender_handle->OnCancel(); 93 if (own_prerender_handle)
105 94 own_prerender_handle->OnCancel();
106 // Because OnCancel() can remove the prerender from the map, we need to 95
107 // consider our iterator invalid. 96 StartPrerenders();
108 id_to_handle_iter = ids_to_handle_map_.find(child_and_prerender_id);
109 if (id_to_handle_iter != ids_to_handle_map_.end())
110 RemovePrerender(id_to_handle_iter);
111 } 97 }
112 98
113 void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) { 99 void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) {
114 DVLOG(2) << "OnAbandonPrerender, child_id = " << child_id 100 LinkPrerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
115 << ", prerender_id = " << prerender_id; 101 prerender_id);
116 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); 102 if (!prerender)
117 IdPairToPrerenderHandleMap::iterator id_to_handle_iter = 103 return;
118 ids_to_handle_map_.find(child_and_prerender_id); 104
119 if (id_to_handle_iter == ids_to_handle_map_.end()) 105 if (!prerender->handle) {
120 return; 106 RemovePrerender(prerender);
121 PrerenderHandle* prerender_handle = id_to_handle_iter->second; 107 return;
122 prerender_handle->OnNavigateAway(); 108 }
109
110 prerender->handle->OnNavigateAway();
111 DCHECK(prerender->handle);
112
113 // If the prerender is not running, remove it from the list so it does not
114 // leak. If it is running, it will send a cancel event when it stops which
115 // will remove it.
116 if (!prerender->handle->IsPrerendering())
117 RemovePrerender(prerender);
123 } 118 }
124 119
125 void PrerenderLinkManager::OnChannelClosing(int child_id) { 120 void PrerenderLinkManager::OnChannelClosing(int child_id) {
126 DVLOG(2) << "OnChannelClosing, child id = " << child_id; 121 std::list<LinkPrerender>::iterator next = prerenders_.begin();
127 const ChildAndPrerenderIdPair child_and_minimum_prerender_id( 122 while (next != prerenders_.end()) {
128 child_id, std::numeric_limits<int>::min()); 123 std::list<LinkPrerender>::iterator it = next;
129 const ChildAndPrerenderIdPair child_and_maximum_prerender_id(
130 child_id, std::numeric_limits<int>::max());
131
132 IdPairToPrerenderHandleMap::iterator
133 it = ids_to_handle_map_.lower_bound(child_and_minimum_prerender_id);
134 IdPairToPrerenderHandleMap::iterator
135 end = ids_to_handle_map_.upper_bound(child_and_maximum_prerender_id);
136 while (it != end) {
137 IdPairToPrerenderHandleMap::iterator next = it;
138 ++next; 124 ++next;
139 125
140 size_t size_before_abandon = ids_to_handle_map_.size(); 126 if (child_id != it->launcher_child_id)
141 OnAbandonPrerender(child_id, it->first.second); 127 continue;
142 DCHECK_EQ(size_before_abandon, ids_to_handle_map_.size()); 128
143 RemovePrerender(it); 129 const size_t running_prerender_count = CountRunningPrerenders();
144 130 OnAbandonPrerender(child_id, it->prerender_id);
145 it = next; 131 DCHECK_EQ(running_prerender_count, CountRunningPrerenders());
146 } 132 }
133 }
134
135 PrerenderLinkManager::LinkPrerender::LinkPrerender(
136 int launcher_child_id,
137 int prerender_id,
138 const GURL& url,
139 const content::Referrer& referrer,
140 const gfx::Size& size,
141 int render_view_route_id,
142 TimeTicks creation_time) : launcher_child_id(launcher_child_id),
143 prerender_id(prerender_id),
144 url(url),
145 referrer(referrer),
146 size(size),
147 render_view_route_id(render_view_route_id),
148 creation_time(creation_time),
149 handle(NULL) {
150 }
151
152 PrerenderLinkManager::LinkPrerender::~LinkPrerender() {
153 DCHECK_EQ(static_cast<PrerenderHandle*>(NULL), handle)
154 << "The PrerenderHandle should be destroyed before its Prerender.";
147 } 155 }
148 156
149 bool PrerenderLinkManager::IsEmpty() const { 157 bool PrerenderLinkManager::IsEmpty() const {
150 return ids_to_handle_map_.empty(); 158 return prerenders_.empty();
151 } 159 }
152 160
153 void PrerenderLinkManager::RemovePrerender( 161 size_t PrerenderLinkManager::CountRunningPrerenders() const {
154 const IdPairToPrerenderHandleMap::iterator& id_to_handle_iter) { 162 size_t retval = 0;
155 PrerenderHandle* prerender_handle = id_to_handle_iter->second; 163 for (std::list<LinkPrerender>::const_iterator i = prerenders_.begin();
156 delete prerender_handle; 164 i != prerenders_.end(); ++i) {
157 ids_to_handle_map_.erase(id_to_handle_iter); 165 if (i->handle && i->handle->IsPrerendering())
158 } 166 ++retval;
159 167 }
160 PrerenderLinkManager::IdPairToPrerenderHandleMap::iterator 168 return retval;
161 PrerenderLinkManager::FindPrerenderHandle( 169 }
162 PrerenderHandle* prerender_handle) { 170
163 for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin(); 171 void PrerenderLinkManager::StartPrerenders() {
164 it != ids_to_handle_map_.end(); ++it) { 172 if (has_shutdown_)
165 if (it->second == prerender_handle) 173 return;
166 return it; 174
167 } 175 size_t total_started_prerender_count = 0;
168 return ids_to_handle_map_.end(); 176 std::multiset<std::pair<int, int> >
177 running_launcher_and_render_view_routes;
178
179 // Scan the list, counting how many prerenders have handles (and so were added
180 // to the PrerenderManager). The count is done for the system as a whole, and
181 // also per launcher.
182 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
183 i != prerenders_.end(); ++i) {
184 if (i->handle) {
185 ++total_started_prerender_count;
186 std::pair<int, int> launcher_and_render_view_route(
187 i->launcher_child_id, i->render_view_route_id);
188 running_launcher_and_render_view_routes.insert(
189 launcher_and_render_view_route);
190 DCHECK_GE(manager_->config().max_link_concurrency_per_launcher,
191 running_launcher_and_render_view_routes.count(
192 launcher_and_render_view_route));
193 }
194
195 DCHECK_EQ(&(*i), FindByLauncherChildIdAndPrerenderId(i->launcher_child_id,
196 i->prerender_id));
197 }
198 DCHECK_GE(manager_->config().max_link_concurrency,
199 total_started_prerender_count);
200 DCHECK_LE(CountRunningPrerenders(), total_started_prerender_count);
201
202 TimeTicks now = manager_->GetCurrentTimeTicks();
203
204 // Scan the list again, starting prerenders as our counts allow.
205 std::list<LinkPrerender>::iterator next = prerenders_.begin();
206 while (next != prerenders_.end()) {
207 std::list<LinkPrerender>::iterator i = next;
208 ++next;
209
210 if (total_started_prerender_count >=
211 manager_->config().max_link_concurrency ||
212 total_started_prerender_count >= prerenders_.size()) {
213 // The system is already at its prerender concurrency limit.
214 return;
215 }
216
217 if (i->handle) {
218 // This prerender has already been added to the prerender manager.
219 continue;
220 }
221
222 TimeDelta prerender_age = now - i->creation_time;
223 if (prerender_age >= manager_->config().max_wait_to_launch) {
224 // This prerender waited too long in the queue before launching.
225 prerenders_.erase(i);
226 continue;
227 }
228
229 std::pair<int, int> launcher_and_render_view_route(
230 i->launcher_child_id, i->render_view_route_id);
231 if (manager_->config().max_link_concurrency_per_launcher <=
232 running_launcher_and_render_view_routes.count(
233 launcher_and_render_view_route)) {
234 // This prerender's launcher is already at its limit.
235 continue;
236 }
237
238 PrerenderHandle* handle = manager_->AddPrerenderFromLinkRelPrerender(
239 i->launcher_child_id, i->render_view_route_id,
240 i->url, i->referrer, i->size);
241 if (!handle) {
242 // This prerender couldn't be launched, it's gone.
243 prerenders_.erase(i);
244 continue;
245 }
246
247 // We have successfully started a new prerender.
248 i->handle = handle;
249 ++total_started_prerender_count;
250 handle->SetObserver(this);
251 if (handle->IsPrerendering())
252 OnPrerenderStart(handle);
253
254 running_launcher_and_render_view_routes.insert(
255 launcher_and_render_view_route);
256 }
257 }
258
259 PrerenderLinkManager::LinkPrerender*
260 PrerenderLinkManager::FindByLauncherChildIdAndPrerenderId(int launcher_child_id,
261 int prerender_id) {
262 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
263 i != prerenders_.end(); ++i) {
264 if (launcher_child_id == i->launcher_child_id &&
265 prerender_id == i->prerender_id) {
266 return &(*i);
267 }
268 }
269 return NULL;
270 }
271
272 PrerenderLinkManager::LinkPrerender*
273 PrerenderLinkManager::FindByPrerenderHandle(PrerenderHandle* prerender_handle) {
274 DCHECK(prerender_handle);
275 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
276 i != prerenders_.end(); ++i) {
277 if (prerender_handle == i->handle)
278 return &(*i);
279 }
280 return NULL;
281 }
282
283 void PrerenderLinkManager::RemovePrerender(LinkPrerender* prerender) {
284 for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
285 i != prerenders_.end(); ++i) {
286 if (&(*i) == prerender) {
287 scoped_ptr<PrerenderHandle> own_handle(i->handle);
288 i->handle = NULL;
289 prerenders_.erase(i);
290 return;
291 }
292 }
293 NOTREACHED();
294 }
295
296 void PrerenderLinkManager::Shutdown() {
297 has_shutdown_ = true;
169 } 298 }
170 299
171 // In practice, this is always called from either 300 // In practice, this is always called from either
172 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending 301 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending
173 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom. 302 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom.
174 void PrerenderLinkManager::OnPrerenderStart( 303 void PrerenderLinkManager::OnPrerenderStart(
175 PrerenderHandle* prerender_handle) { 304 PrerenderHandle* prerender_handle) {
176 IdPairToPrerenderHandleMap::iterator it = 305 LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
177 FindPrerenderHandle(prerender_handle); 306 if (!prerender)
178 DCHECK(it != ids_to_handle_map_.end()); 307 return;
179 const int child_id = it->first.first; 308 Send(prerender->launcher_child_id,
180 const int prerender_id = it->first.second; 309 new PrerenderMsg_OnPrerenderStart(prerender->prerender_id));
181
182 Send(child_id, new PrerenderMsg_OnPrerenderStart(prerender_id));
183 } 310 }
184 311
185 void PrerenderLinkManager::OnPrerenderAddAlias( 312 void PrerenderLinkManager::OnPrerenderAddAlias(
186 PrerenderHandle* prerender_handle, 313 PrerenderHandle* prerender_handle,
187 const GURL& alias_url) { 314 const GURL& alias_url) {
188 IdPairToPrerenderHandleMap::iterator it = 315 LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
189 FindPrerenderHandle(prerender_handle); 316 if (!prerender)
190 if (it == ids_to_handle_map_.end())
191 return; 317 return;
192 const int child_id = it->first.first; 318 Send(prerender->launcher_child_id,
193 const int prerender_id = it->first.second; 319 new PrerenderMsg_OnPrerenderAddAlias(prerender->prerender_id,
194 320 alias_url));
195 Send(child_id, new PrerenderMsg_OnPrerenderAddAlias(prerender_id, alias_url));
196 } 321 }
197 322
198 void PrerenderLinkManager::OnPrerenderStop( 323 void PrerenderLinkManager::OnPrerenderStop(
199 PrerenderHandle* prerender_handle) { 324 PrerenderHandle* prerender_handle) {
200 IdPairToPrerenderHandleMap::iterator it = 325 LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
201 FindPrerenderHandle(prerender_handle); 326 if (!prerender)
202 if (it == ids_to_handle_map_.end())
203 return; 327 return;
204 const int child_id = it->first.first;
205 const int prerender_id = it->first.second;
206 328
207 Send(child_id, new PrerenderMsg_OnPrerenderStop(prerender_id)); 329 Send(prerender->launcher_child_id,
208 RemovePrerender(it); 330 new PrerenderMsg_OnPrerenderStop(prerender->prerender_id));
331 RemovePrerender(prerender);
332 StartPrerenders();
209 } 333 }
210 334
211 } // namespace prerender 335 } // namespace prerender
OLDNEW
« no previous file with comments | « chrome/browser/prerender/prerender_link_manager.h ('k') | chrome/browser/prerender/prerender_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698