Chromium Code Reviews| 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); |
| 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 |
| OLD | NEW |