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

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: guh Created 8 years 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"
(...skipping 16 matching lines...) Expand all
34 if (!render_process_host) 35 if (!render_process_host)
35 return; 36 return;
36 render_process_host->Send(own_message.release()); 37 render_process_host->Send(own_message.release());
37 } 38 }
38 39
39 } // namespace 40 } // namespace
40 41
41 namespace prerender { 42 namespace prerender {
42 43
43 PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager) 44 PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager)
44 : manager_(manager) { 45 : is_shutdown_(false),
46 manager_(manager) {
45 } 47 }
46 48
47 PrerenderLinkManager::~PrerenderLinkManager() { 49 PrerenderLinkManager::~PrerenderLinkManager() {
48 for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin(); 50 for (std::list<Prerender>::iterator i = prerenders_.begin();
49 it != ids_to_handle_map_.end(); 51 i != prerenders_.end(); ++i) {
50 ++it) { 52 if (i->handle) {
51 PrerenderHandle* prerender_handle = it->second; 53 DCHECK(!i->handle->IsPrerendering())
52 DCHECK(!prerender_handle->IsPrerendering()) 54 << "All running prerenders should stop at the same time as the "
53 << "All running prerenders should stop at the same time as the " 55 << "PrerenderManager.";
54 << "PrerenderManager."; 56 delete i->handle;
55 delete prerender_handle; 57 i->handle = 0;
56 } 58 }
57 } 59 }
58 60 }
59 bool PrerenderLinkManager::OnAddPrerender(int child_id, 61
62 void PrerenderLinkManager::OnAddPrerender(int launcher_child_id,
60 int prerender_id, 63 int prerender_id,
61 const GURL& url, 64 const GURL& url,
62 const content::Referrer& referrer, 65 const content::Referrer& referrer,
63 const gfx::Size& size, 66 const gfx::Size& size,
64 int render_view_route_id) { 67 int render_view_route_id) {
65 DVLOG(2) << "OnAddPrerender, child_id = " << child_id 68 Prerender prerender(launcher_child_id, prerender_id, url, referrer, size,
66 << ", prerender_id = " << prerender_id 69 render_view_route_id);
67 << ", url = " << url.spec(); 70 prerenders_.push_back(prerender);
68 DVLOG(3) << "... referrer url = " << referrer.url.spec() 71 StartPrerenders();
69 << ", size = (" << size.width() << ", " << size.height() << ")"
70 << ", render_view_route_id = " << render_view_route_id;
71
72
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 } 72 }
90 73
91 void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) { 74 void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) {
92 DVLOG(2) << "OnCancelPrerender, child_id = " << child_id 75 Prerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
93 << ", prerender_id = " << prerender_id; 76 prerender_id);
94 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); 77 if (!prerender)
95 IdPairToPrerenderHandleMap::iterator id_to_handle_iter =
96 ids_to_handle_map_.find(child_and_prerender_id);
97 if (id_to_handle_iter == ids_to_handle_map_.end()) {
98 DVLOG(5) << "... canceling a prerender that doesn't exist.";
99 return; 78 return;
100 } 79
101 80 scoped_ptr<PrerenderHandle> own_prerender_handle(prerender->handle);
102 scoped_ptr<PrerenderHandle> prerender_handle(id_to_handle_iter->second); 81 prerender->handle = NULL;
103 ids_to_handle_map_.erase(id_to_handle_iter); 82 RemovePrerender(prerender);
mmenke 2012/12/18 17:15:15 Is the goal of all this not to send stop events fo
gavinp 2012/12/18 20:15:12 Done.
104 prerender_handle->OnCancel(); 83
105 84 if (own_prerender_handle)
106 // Because OnCancel() can remove the prerender from the map, we need to 85 own_prerender_handle->OnCancel();
mmenke 2012/12/18 17:15:15 Just a general comment: Think it's rather unfortu
gavinp 2012/12/18 20:15:12 Yes, it is unfortunate. Pulling things into the Li
107 // consider our iterator invalid. 86
108 id_to_handle_iter = ids_to_handle_map_.find(child_and_prerender_id); 87 StartPrerenders();
109 if (id_to_handle_iter != ids_to_handle_map_.end()) 88 }
mmenke 2012/12/18 17:15:15 nit: Remove indent.
gavinp 2012/12/18 20:15:12 Done.
110 RemovePrerender(id_to_handle_iter);
111 }
112 89
113 void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) { 90 void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) {
114 DVLOG(2) << "OnAbandonPrerender, child_id = " << child_id 91 Prerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
115 << ", prerender_id = " << prerender_id; 92 prerender_id);
116 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); 93 if (!prerender || !prerender->handle)
mmenke 2012/12/18 17:15:15 If !prerender->handle, we should still be removing
gavinp 2012/12/18 20:15:12 Added a few more tests walking us through these c
117 IdPairToPrerenderHandleMap::iterator id_to_handle_iter =
118 ids_to_handle_map_.find(child_and_prerender_id);
119 if (id_to_handle_iter == ids_to_handle_map_.end())
120 return; 94 return;
121 PrerenderHandle* prerender_handle = id_to_handle_iter->second; 95 prerender->handle->OnNavigateAway();
122 prerender_handle->OnNavigateAway(); 96
97 // If the prerender is not running, remove it from the list so it does not
98 // leak. If it is running, it will send a cancel event when it stops which
99 // will remove it.
100 if (!prerender->handle || prerender->handle->IsPrerendering())
mmenke 2012/12/18 17:15:15 Why check prernder->handle here? If OnNavigateAwa
gavinp 2012/12/18 20:15:12 Done.
101 RemovePrerender(prerender);
123 } 102 }
124 103
125 void PrerenderLinkManager::OnChannelClosing(int child_id) { 104 void PrerenderLinkManager::OnChannelClosing(int child_id) {
126 DVLOG(2) << "OnChannelClosing, child id = " << child_id; 105 std::list<Prerender>::iterator next = prerenders_.begin();
127 const ChildAndPrerenderIdPair child_and_minimum_prerender_id( 106 while (next != prerenders_.end()) {
128 child_id, std::numeric_limits<int>::min()); 107 std::list<Prerender>::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; 108 ++next;
139 109
140 size_t size_before_abandon = ids_to_handle_map_.size(); 110 if (child_id != it->launcher_child_id)
141 OnAbandonPrerender(child_id, it->first.second); 111 continue;
142 DCHECK_EQ(size_before_abandon, ids_to_handle_map_.size()); 112
143 RemovePrerender(it); 113 const size_t running_prerender_count = CountRunningPrerenders();
144 114 OnAbandonPrerender(child_id, it->prerender_id);
145 it = next; 115 DCHECK_EQ(running_prerender_count, CountRunningPrerenders());
146 } 116 }
117 }
118
119 PrerenderLinkManager::Prerender::Prerender(int launcher_child_id,
120 int prerender_id,
121 const GURL& url,
122 const content::Referrer& referrer,
123 const gfx::Size& size,
124 int render_view_route_id)
125 : launcher_child_id(launcher_child_id),
126 prerender_id(prerender_id),
127 url(url),
128 referrer(referrer),
129 size(size),
130 render_view_route_id(render_view_route_id),
131 handle(NULL) {
132 }
133
134 PrerenderLinkManager::Prerender::~Prerender() {
135 DCHECK_EQ(static_cast<PrerenderHandle*>(NULL), handle);
147 } 136 }
148 137
149 bool PrerenderLinkManager::IsEmpty() const { 138 bool PrerenderLinkManager::IsEmpty() const {
150 return ids_to_handle_map_.empty(); 139 return prerenders_.empty();
151 } 140 }
152 141
153 void PrerenderLinkManager::RemovePrerender( 142 size_t PrerenderLinkManager::CountRunningPrerenders() const {
154 const IdPairToPrerenderHandleMap::iterator& id_to_handle_iter) { 143 size_t retval = 0;
155 PrerenderHandle* prerender_handle = id_to_handle_iter->second; 144 for (std::list<Prerender>::const_iterator i = prerenders_.begin();
156 delete prerender_handle; 145 i != prerenders_.end(); ++i) {
157 ids_to_handle_map_.erase(id_to_handle_iter); 146 if (i->handle && i->handle->IsPrerendering())
158 } 147 ++retval;
159 148 }
160 PrerenderLinkManager::IdPairToPrerenderHandleMap::iterator 149 return retval;
161 PrerenderLinkManager::FindPrerenderHandle( 150 }
162 PrerenderHandle* prerender_handle) { 151
163 for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin(); 152 void PrerenderLinkManager::StartPrerenders() {
164 it != ids_to_handle_map_.end(); ++it) { 153 if (is_shutdown_)
165 if (it->second == prerender_handle) 154 return;
166 return it; 155
167 } 156 std::set<std::pair<int, int> > launcher_and_prerender_id_set;
168 return ids_to_handle_map_.end(); 157
158 size_t running_count = 0;
159 std::multiset<std::pair<int, int> >
160 running_launcher_and_render_view_route_set;
161
162 // Scan the list, counting how many prerenders are running and how many are
163 // running for each launcher.
164 for (std::list<Prerender>::iterator i = prerenders_.begin();
165 i != prerenders_.end(); ++i) {
166 if (i->handle) {
167 ++running_count;
168 std::pair<int, int> launcher_and_render_view_route(
169 i->launcher_child_id, i->render_view_route_id);
170 running_launcher_and_render_view_route_set.insert(
171 launcher_and_render_view_route);
172 DCHECK_GE(manager_->config().max_concurrency_per_launcher,
173 running_launcher_and_render_view_route_set.count(
174 launcher_and_render_view_route));
175 }
176
177 std::pair<int, int> launcher_and_prerender_id(i->launcher_child_id,
178 i->prerender_id);
179 DCHECK_EQ(0u,
180 launcher_and_prerender_id_set.count(launcher_and_prerender_id));
181 launcher_and_prerender_id_set.insert(launcher_and_prerender_id);
182 }
183 DCHECK_GE(manager_->config().max_concurrency, running_count);
184
185
186 // Scan the list again, starting prerenders as our counts allow.
187 std::list<Prerender>::iterator next = prerenders_.begin();
188 while (next != prerenders_.end()) {
189 std::list<Prerender>::iterator i = next;
190 ++next;
mmenke 2012/12/18 17:15:15 Maybe a DCHECK_EQ(CountRunningPrerenders(), runnin
gavinp 2012/12/18 20:15:12 I think it'd DCHECK_LE, right? Some prerenders hav
mmenke 2012/12/28 18:25:33 Correct - I made an incorrect assumption about wha
191
192 if (running_count >= manager_->config().max_concurrency ||
193 running_count >= prerenders_.size()) {
194 return;
195 }
196
197 if (i->handle)
198 continue;
199
200 std::pair<int, int> launcher_and_render_view_route(
201 i->launcher_child_id, i->render_view_route_id);
202
203 if (manager_->config().max_concurrency_per_launcher <=
204 running_launcher_and_render_view_route_set.count(
205 launcher_and_render_view_route)) {
206 continue;
207 }
208
209 PrerenderHandle* handle = manager_->AddPrerenderFromLinkRelPrerender(
210 i->launcher_child_id, i->render_view_route_id,
211 i->url, i->referrer, i->size);
212 if (!handle) {
213 prerenders_.erase(i);
214 continue;
215 }
216 i->handle = handle;
217 ++running_count;
218 handle->SetObserver(this);
219 if (handle->IsPrerendering())
220 OnPrerenderStart(handle);
221
222 running_launcher_and_render_view_route_set.insert(
223 launcher_and_render_view_route);
224 }
225 }
226
227 PrerenderLinkManager::Prerender*
228 PrerenderLinkManager::FindByLauncherChildIdAndPrerenderId(int launcher_child_id,
229 int prerender_id) {
230 for (std::list<Prerender>::iterator i = prerenders_.begin();
231 i != prerenders_.end(); ++i) {
232 if (launcher_child_id == i->launcher_child_id &&
233 prerender_id == i->prerender_id) {
234 return &(*i);
235 }
236 }
237 return NULL;
238 }
239
240 PrerenderLinkManager::Prerender*
241 PrerenderLinkManager::FindByPrerenderHandle(PrerenderHandle* prerender_handle) {
mmenke 2012/12/18 17:15:15 DCHECK(prerender_handle);
gavinp 2012/12/18 20:15:12 Done.
242 for (std::list<Prerender>::iterator i = prerenders_.begin();
243 i != prerenders_.end(); ++i) {
244 if (prerender_handle == i->handle)
245 return &(*i);
246 }
247 return NULL;
248 }
249
250 void PrerenderLinkManager::RemovePrerender(Prerender* prerender) {
251 for (std::list<Prerender>::iterator i = prerenders_.begin();
252 i != prerenders_.end(); ++i) {
253 if (&(*i) == prerender) {
254 scoped_ptr<PrerenderHandle> own_handle(i->handle);
255 i->handle = NULL;
256 prerenders_.erase(i);
257 return;
258 }
259 }
260 NOTREACHED();
261 }
262
263 void PrerenderLinkManager::Shutdown() {
264 is_shutdown_ = true;
169 } 265 }
170 266
171 // In practice, this is always called from either 267 // In practice, this is always called from either
172 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending 268 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending
173 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom. 269 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom.
174 void PrerenderLinkManager::OnPrerenderStart( 270 void PrerenderLinkManager::OnPrerenderStart(
175 PrerenderHandle* prerender_handle) { 271 PrerenderHandle* prerender_handle) {
176 IdPairToPrerenderHandleMap::iterator it = 272 Prerender* prerender = FindByPrerenderHandle(prerender_handle);
177 FindPrerenderHandle(prerender_handle); 273 if (!prerender)
178 DCHECK(it != ids_to_handle_map_.end()); 274 return;
179 const int child_id = it->first.first; 275 Send(prerender->launcher_child_id,
180 const int prerender_id = it->first.second; 276 new PrerenderMsg_OnPrerenderStart(prerender->prerender_id));
181
182 Send(child_id, new PrerenderMsg_OnPrerenderStart(prerender_id));
183 } 277 }
184 278
185 void PrerenderLinkManager::OnPrerenderAddAlias( 279 void PrerenderLinkManager::OnPrerenderAddAlias(
186 PrerenderHandle* prerender_handle, 280 PrerenderHandle* prerender_handle,
187 const GURL& alias_url) { 281 const GURL& alias_url) {
188 IdPairToPrerenderHandleMap::iterator it = 282 Prerender* prerender = FindByPrerenderHandle(prerender_handle);
189 FindPrerenderHandle(prerender_handle); 283 if (!prerender)
190 if (it == ids_to_handle_map_.end())
191 return; 284 return;
192 const int child_id = it->first.first; 285 Send(prerender->launcher_child_id,
193 const int prerender_id = it->first.second; 286 new PrerenderMsg_OnPrerenderAddAlias(prerender->prerender_id,
194 287 alias_url));
195 Send(child_id, new PrerenderMsg_OnPrerenderAddAlias(prerender_id, alias_url));
196 } 288 }
197 289
198 void PrerenderLinkManager::OnPrerenderStop( 290 void PrerenderLinkManager::OnPrerenderStop(
199 PrerenderHandle* prerender_handle) { 291 PrerenderHandle* prerender_handle) {
200 IdPairToPrerenderHandleMap::iterator it = 292 Prerender* prerender = FindByPrerenderHandle(prerender_handle);
201 FindPrerenderHandle(prerender_handle); 293 if (!prerender)
202 if (it == ids_to_handle_map_.end())
203 return; 294 return;
204 const int child_id = it->first.first;
205 const int prerender_id = it->first.second;
206 295
207 Send(child_id, new PrerenderMsg_OnPrerenderStop(prerender_id)); 296 Send(prerender->launcher_child_id,
208 RemovePrerender(it); 297 new PrerenderMsg_OnPrerenderStop(prerender->prerender_id));
298 RemovePrerender(prerender);
299 StartPrerenders();
209 } 300 }
210 301
211 } // namespace prerender 302 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698