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

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: surprising test deflake 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);
104 prerender_handle->OnCancel(); 83
84 if (own_prerender_handle)
85 own_prerender_handle->OnCancel();
86
87 StartPrerenders();
105 } 88 }
106 89
107 void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) { 90 void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) {
108 DVLOG(2) << "OnAbandonPrerender, child_id = " << child_id 91 Prerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
109 << ", prerender_id = " << prerender_id; 92 prerender_id);
110 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); 93 if (!prerender || !prerender->handle)
111 IdPairToPrerenderHandleMap::iterator id_to_handle_iter =
112 ids_to_handle_map_.find(child_and_prerender_id);
113 if (id_to_handle_iter == ids_to_handle_map_.end())
114 return; 94 return;
115 PrerenderHandle* prerender_handle = id_to_handle_iter->second; 95 prerender->handle->OnNavigateAway();
116 prerender_handle->OnNavigateAway(); 96
97 // Keep the prerender in |prerenders_|, since it is still running and needs to
98 // be accounted for when tracking slots for StartPrerenders().
117 } 99 }
118 100
119 void PrerenderLinkManager::OnChannelClosing(int child_id) { 101 void PrerenderLinkManager::OnChannelClosing(int child_id) {
120 DVLOG(2) << "OnChannelClosing, child id = " << child_id; 102 std::list<Prerender>::iterator next = prerenders_.begin();
121 const ChildAndPrerenderIdPair child_and_minimum_prerender_id( 103 while (next != prerenders_.end()) {
122 child_id, std::numeric_limits<int>::min()); 104 std::list<Prerender>::iterator it = next;
123 const ChildAndPrerenderIdPair child_and_maximum_prerender_id(
124 child_id, std::numeric_limits<int>::max());
125
126 IdPairToPrerenderHandleMap::iterator
127 it = ids_to_handle_map_.lower_bound(child_and_minimum_prerender_id);
128 IdPairToPrerenderHandleMap::iterator
129 end = ids_to_handle_map_.upper_bound(child_and_maximum_prerender_id);
130 while (it != end) {
131 IdPairToPrerenderHandleMap::iterator next = it;
132 ++next; 105 ++next;
133 106
134 size_t size_before_abandon = ids_to_handle_map_.size(); 107 if (child_id != it->launcher_child_id)
135 OnAbandonPrerender(child_id, it->first.second); 108 continue;
136 DCHECK_EQ(size_before_abandon, ids_to_handle_map_.size()); 109
137 RemovePrerender(it); 110 const size_t size_before_abandon = prerenders_.size();
138 111 OnAbandonPrerender(child_id, it->prerender_id);
139 it = next; 112 DCHECK_EQ(size_before_abandon, prerenders_.size());
140 } 113 RemovePrerender(&(*it));
mmenke 2012/12/17 20:02:23 Erm... This seems to violate the comment at the e
gavinp 2012/12/18 00:44:14 Guh, good point. I moved the remove up into OnAban
114 }
115 }
116
117 PrerenderLinkManager::Prerender::Prerender(int launcher_child_id,
118 int prerender_id,
119 const GURL& url,
120 const content::Referrer& referrer,
121 const gfx::Size& size,
122 int render_view_route_id)
123 : launcher_child_id(launcher_child_id),
124 prerender_id(prerender_id),
125 url(url),
126 referrer(referrer),
127 size(size),
128 render_view_route_id(render_view_route_id),
129 handle(NULL) {
130 }
131
132 PrerenderLinkManager::Prerender::~Prerender() {
133 DCHECK_EQ(static_cast<PrerenderHandle*>(NULL), handle);
141 } 134 }
142 135
143 bool PrerenderLinkManager::IsEmpty() const { 136 bool PrerenderLinkManager::IsEmpty() const {
144 return ids_to_handle_map_.empty(); 137 return prerenders_.empty();
145 } 138 }
146 139
147 void PrerenderLinkManager::RemovePrerender( 140 void PrerenderLinkManager::StartPrerenders() {
148 const IdPairToPrerenderHandleMap::iterator& id_to_handle_iter) { 141 if (is_shutdown_)
149 PrerenderHandle* prerender_handle = id_to_handle_iter->second; 142 return;
150 delete prerender_handle; 143
151 ids_to_handle_map_.erase(id_to_handle_iter); 144 std::set<std::pair<int, int> > launcher_and_prerender_id_set;
152 } 145
153 146 size_t running_count = 0;
154 PrerenderLinkManager::IdPairToPrerenderHandleMap::iterator 147 std::multiset<std::pair<int, int> >
155 PrerenderLinkManager::FindPrerenderHandle( 148 running_launcher_and_render_view_route_set;
156 PrerenderHandle* prerender_handle) { 149
157 for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin(); 150 // Scan the list, counting how many prerenders are running and how many are
158 it != ids_to_handle_map_.end(); ++it) { 151 // running for each launcher.
159 if (it->second == prerender_handle) 152 for (std::list<Prerender>::iterator i = prerenders_.begin();
160 return it; 153 i != prerenders_.end(); ++i) {
161 } 154 if (i->handle) {
162 return ids_to_handle_map_.end(); 155 ++running_count;
156 std::pair<int, int> launcher_and_render_view_route(
157 i->launcher_child_id, i->render_view_route_id);
158 running_launcher_and_render_view_route_set.insert(
159 launcher_and_render_view_route);
160 DCHECK_GE(manager_->config().max_concurrency_per_launcher,
161 running_launcher_and_render_view_route_set.count(
162 launcher_and_render_view_route));
163 }
164
165 std::pair<int, int> launcher_and_prerender_id(i->launcher_child_id,
166 i->prerender_id);
167 DCHECK_EQ(0u,
168 launcher_and_prerender_id_set.count(launcher_and_prerender_id));
169 launcher_and_prerender_id_set.insert(launcher_and_prerender_id);
170 }
mmenke 2012/12/17 18:34:57 Hmm...Multiple prerenders with the same PrerenderC
mmenke 2012/12/17 20:02:23 Also, seems like if we have one active prerender,
gavinp 2012/12/18 00:44:14 Hrm. I was hoping to delay adding handling for dup
mmenke 2012/12/18 17:15:15 Speaking of which, you did switch the omnibox to c
gavinp 2012/12/18 20:15:12 Done.
171 DCHECK_GE(manager_->config().max_concurrency, running_count);
172
173
174 // Scan the list again, starting prerenders as our counts allow.
175 std::list<Prerender>::iterator next = prerenders_.begin();
176 while (next != prerenders_.end()) {
177 std::list<Prerender>::iterator i = next;
178 ++next;
179
180 if (running_count >= manager_->config().max_concurrency ||
181 running_count >= prerenders_.size()) {
182 return;
183 }
184
185 if (i->handle)
186 continue;
187
188 std::pair<int, int> launcher_and_render_view_route(
189 i->launcher_child_id, i->render_view_route_id);
190
191 if (manager_->config().max_concurrency_per_launcher <=
192 running_launcher_and_render_view_route_set.count(
193 launcher_and_render_view_route)) {
194 continue;
195 }
196
197 PrerenderHandle* handle = manager_->AddPrerenderFromLinkRelPrerender(
198 i->launcher_child_id, i->render_view_route_id,
199 i->url, i->referrer, i->size);
200 if (!handle) {
201 prerenders_.erase(i);
202 continue;
203 }
204 i->handle = handle;
205 ++running_count;
206 handle->SetObserver(this);
207 if (handle->IsPrerendering())
208 OnPrerenderStart(handle);
209
210 running_launcher_and_render_view_route_set.insert(
211 launcher_and_render_view_route);
212 }
213 }
214
215 PrerenderLinkManager::Prerender*
216 PrerenderLinkManager::FindByLauncherChildIdAndPrerenderId(int launcher_child_id,
217 int prerender_id) {
218 for (std::list<Prerender>::iterator i = prerenders_.begin();
219 i != prerenders_.end(); ++i) {
220 if (launcher_child_id == i->launcher_child_id &&
221 prerender_id == i->prerender_id) {
222 return &(*i);
223 }
224 }
225 return NULL;
226 }
227
228 PrerenderLinkManager::Prerender*
229 PrerenderLinkManager::FindByPrerenderHandle(PrerenderHandle* prerender_handle) {
230 for (std::list<Prerender>::iterator i = prerenders_.begin();
231 i != prerenders_.end(); ++i) {
232 if (prerender_handle == i->handle)
233 return &(*i);
234 }
235 return NULL;
236 }
237
238 void PrerenderLinkManager::RemovePrerender(Prerender* prerender) {
239 for (std::list<Prerender>::iterator i = prerenders_.begin();
240 i != prerenders_.end(); ++i) {
241 if (&(*i) == prerender) {
242 scoped_ptr<PrerenderHandle> own_handle(i->handle);
243 i->handle = NULL;
mmenke 2012/12/17 20:02:23 Don't think this does anything useful.
gavinp 2012/12/18 00:44:14 There's a DCHECK() in PrerenderListManager::~Prere
mmenke 2012/12/18 17:15:15 Sounds reasonable.
244 prerenders_.erase(i);
245 return;
246 }
247 }
248 NOTREACHED();
249 }
250
251 void PrerenderLinkManager::Shutdown() {
252 is_shutdown_ = true;
163 } 253 }
164 254
165 // In practice, this is always called from either 255 // In practice, this is always called from either
166 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending 256 // PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending
167 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom. 257 // prerender case, from PrerenderHandle::AdoptPrerenderDataFrom.
168 void PrerenderLinkManager::OnPrerenderStart( 258 void PrerenderLinkManager::OnPrerenderStart(
169 PrerenderHandle* prerender_handle) { 259 PrerenderHandle* prerender_handle) {
170 IdPairToPrerenderHandleMap::iterator it = 260 Prerender* prerender = FindByPrerenderHandle(prerender_handle);
171 FindPrerenderHandle(prerender_handle); 261 if (!prerender)
172 DCHECK(it != ids_to_handle_map_.end()); 262 return;
173 const int child_id = it->first.first; 263 Send(prerender->launcher_child_id,
174 const int prerender_id = it->first.second; 264 new PrerenderMsg_OnPrerenderStart(prerender->prerender_id));
175
176 Send(child_id, new PrerenderMsg_OnPrerenderStart(prerender_id));
177 } 265 }
178 266
179 void PrerenderLinkManager::OnPrerenderAddAlias( 267 void PrerenderLinkManager::OnPrerenderAddAlias(
180 PrerenderHandle* prerender_handle, 268 PrerenderHandle* prerender_handle,
181 const GURL& alias_url) { 269 const GURL& alias_url) {
182 IdPairToPrerenderHandleMap::iterator it = 270 Prerender* prerender = FindByPrerenderHandle(prerender_handle);
183 FindPrerenderHandle(prerender_handle); 271 if (!prerender)
184 if (it == ids_to_handle_map_.end())
185 return; 272 return;
186 const int child_id = it->first.first; 273 Send(prerender->launcher_child_id,
187 const int prerender_id = it->first.second; 274 new PrerenderMsg_OnPrerenderAddAlias(prerender->prerender_id,
188 275 alias_url));
189 Send(child_id, new PrerenderMsg_OnPrerenderAddAlias(prerender_id, alias_url));
190 } 276 }
191 277
192 void PrerenderLinkManager::OnPrerenderStop( 278 void PrerenderLinkManager::OnPrerenderStop(
193 PrerenderHandle* prerender_handle) { 279 PrerenderHandle* prerender_handle) {
194 IdPairToPrerenderHandleMap::iterator it = 280 Prerender* prerender = FindByPrerenderHandle(prerender_handle);
195 FindPrerenderHandle(prerender_handle); 281 if (!prerender)
196 if (it == ids_to_handle_map_.end())
197 return; 282 return;
198 const int child_id = it->first.first;
199 const int prerender_id = it->first.second;
200 283
201 Send(child_id, new PrerenderMsg_OnPrerenderStop(prerender_id)); 284 Send(prerender->launcher_child_id,
202 RemovePrerender(it); 285 new PrerenderMsg_OnPrerenderStop(prerender->prerender_id));
286 RemovePrerender(prerender);
287 StartPrerenders();
203 } 288 }
204 289
205 } // namespace prerender 290 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698