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_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 Loading... | |
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 |
OLD | NEW |