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

Unified 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 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/prerender/prerender_link_manager.cc
diff --git a/chrome/browser/prerender/prerender_link_manager.cc b/chrome/browser/prerender/prerender_link_manager.cc
index da68f892f2c793cbf602a75554e4404cdc2f715b..89b228eadf893a01d742dba1d1e559fe8af46612 100644
--- a/chrome/browser/prerender/prerender_link_manager.cc
+++ b/chrome/browser/prerender/prerender_link_manager.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/prerender/prerender_link_manager.h"
#include <limits>
+#include <set>
#include <utility>
#include "base/memory/scoped_ptr.h"
@@ -21,6 +22,8 @@
#include "googleurl/src/gurl.h"
#include "ui/gfx/size.h"
+using base::TimeDelta;
+using base::TimeTicks;
using content::RenderViewHost;
using content::SessionStorageNamespace;
@@ -41,131 +44,257 @@ void Send(int child_id, IPC::Message* raw_message) {
namespace prerender {
PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager)
- : manager_(manager) {
+ : has_shutdown_(false),
+ manager_(manager) {
}
PrerenderLinkManager::~PrerenderLinkManager() {
- for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin();
- it != ids_to_handle_map_.end();
- ++it) {
- PrerenderHandle* prerender_handle = it->second;
- DCHECK(!prerender_handle->IsPrerendering())
- << "All running prerenders should stop at the same time as the "
- << "PrerenderManager.";
- delete prerender_handle;
+ for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
+ i != prerenders_.end(); ++i) {
+ if (i->handle) {
+ DCHECK(!i->handle->IsPrerendering())
+ << "All running prerenders should stop at the same time as the "
+ << "PrerenderManager.";
+ delete i->handle;
+ i->handle = 0;
+ }
}
}
-bool PrerenderLinkManager::OnAddPrerender(int child_id,
+void PrerenderLinkManager::OnAddPrerender(int launcher_child_id,
int prerender_id,
const GURL& url,
const content::Referrer& referrer,
const gfx::Size& size,
int render_view_route_id) {
- DVLOG(2) << "OnAddPrerender, child_id = " << child_id
- << ", prerender_id = " << prerender_id
- << ", url = " << url.spec();
- DVLOG(3) << "... referrer url = " << referrer.url.spec()
- << ", size = (" << size.width() << ", " << size.height() << ")"
- << ", render_view_route_id = " << render_view_route_id;
-
-
- PrerenderHandle* prerender_handle =
- manager_->AddPrerenderFromLinkRelPrerender(
- child_id, render_view_route_id, url, referrer, size);
- if (!prerender_handle)
- return false;
-
- const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id);
- DCHECK_EQ(0u, ids_to_handle_map_.count(child_and_prerender_id));
- ids_to_handle_map_[child_and_prerender_id] = prerender_handle;
-
- // If we are given a prerender that is already prerendering, we have missed
- // the start event.
- if (prerender_handle->IsPrerendering())
- OnPrerenderStart(prerender_handle);
- prerender_handle->SetObserver(this);
- return true;
+ DCHECK_EQ(static_cast<LinkPrerender*>(NULL),
+ FindByLauncherChildIdAndPrerenderId(launcher_child_id,
+ prerender_id));
+ LinkPrerender
+ prerender(launcher_child_id, prerender_id, url, referrer, size,
+ render_view_route_id, manager_->GetCurrentTimeTicks());
+ prerenders_.push_back(prerender);
+ StartPrerenders();
}
void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) {
- DVLOG(2) << "OnCancelPrerender, child_id = " << child_id
- << ", prerender_id = " << prerender_id;
- const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id);
- IdPairToPrerenderHandleMap::iterator id_to_handle_iter =
- ids_to_handle_map_.find(child_and_prerender_id);
- if (id_to_handle_iter == ids_to_handle_map_.end()) {
- DVLOG(5) << "... canceling a prerender that doesn't exist.";
+ LinkPrerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
+ prerender_id);
+ if (!prerender)
return;
- }
- scoped_ptr<PrerenderHandle> prerender_handle(id_to_handle_iter->second);
- ids_to_handle_map_.erase(id_to_handle_iter);
- prerender_handle->OnCancel();
+ // Remove the handle from the PrerenderLinkManager before we cancel this
+ // prerender, to avoid reentering the PrerenderLinkManager, sending events to
+ // the underlying prerender and making a second erase.
+ scoped_ptr<PrerenderHandle> own_prerender_handle(prerender->handle);
+ prerender->handle = NULL;
+ RemovePrerender(prerender);
- // Because OnCancel() can remove the prerender from the map, we need to
- // consider our iterator invalid.
- id_to_handle_iter = ids_to_handle_map_.find(child_and_prerender_id);
- if (id_to_handle_iter != ids_to_handle_map_.end())
- RemovePrerender(id_to_handle_iter);
+ if (own_prerender_handle)
+ own_prerender_handle->OnCancel();
+
+ StartPrerenders();
}
void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) {
- DVLOG(2) << "OnAbandonPrerender, child_id = " << child_id
- << ", prerender_id = " << prerender_id;
- const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id);
- IdPairToPrerenderHandleMap::iterator id_to_handle_iter =
- ids_to_handle_map_.find(child_and_prerender_id);
- if (id_to_handle_iter == ids_to_handle_map_.end())
+ LinkPrerender* prerender = FindByLauncherChildIdAndPrerenderId(child_id,
+ prerender_id);
+ if (!prerender)
+ return;
+
+ if (!prerender->handle) {
+ RemovePrerender(prerender);
return;
- PrerenderHandle* prerender_handle = id_to_handle_iter->second;
- prerender_handle->OnNavigateAway();
+ }
+
+ prerender->handle->OnNavigateAway();
+ DCHECK(prerender->handle);
+
+ // If the prerender is not running, remove it from the list so it does not
+ // leak. If it is running, it will send a cancel event when it stops which
+ // will remove it.
+ if (!prerender->handle->IsPrerendering())
+ RemovePrerender(prerender);
}
void PrerenderLinkManager::OnChannelClosing(int child_id) {
- DVLOG(2) << "OnChannelClosing, child id = " << child_id;
- const ChildAndPrerenderIdPair child_and_minimum_prerender_id(
- child_id, std::numeric_limits<int>::min());
- const ChildAndPrerenderIdPair child_and_maximum_prerender_id(
- child_id, std::numeric_limits<int>::max());
-
- IdPairToPrerenderHandleMap::iterator
- it = ids_to_handle_map_.lower_bound(child_and_minimum_prerender_id);
- IdPairToPrerenderHandleMap::iterator
- end = ids_to_handle_map_.upper_bound(child_and_maximum_prerender_id);
- while (it != end) {
- IdPairToPrerenderHandleMap::iterator next = it;
+ std::list<LinkPrerender>::iterator next = prerenders_.begin();
+ while (next != prerenders_.end()) {
+ std::list<LinkPrerender>::iterator it = next;
++next;
- size_t size_before_abandon = ids_to_handle_map_.size();
- OnAbandonPrerender(child_id, it->first.second);
- DCHECK_EQ(size_before_abandon, ids_to_handle_map_.size());
- RemovePrerender(it);
+ if (child_id != it->launcher_child_id)
+ continue;
- it = next;
+ const size_t running_prerender_count = CountRunningPrerenders();
+ OnAbandonPrerender(child_id, it->prerender_id);
+ DCHECK_EQ(running_prerender_count, CountRunningPrerenders());
}
}
+PrerenderLinkManager::LinkPrerender::LinkPrerender(
+ int launcher_child_id,
+ int prerender_id,
+ const GURL& url,
+ const content::Referrer& referrer,
+ const gfx::Size& size,
+ int render_view_route_id,
+ TimeTicks creation_time) : launcher_child_id(launcher_child_id),
+ prerender_id(prerender_id),
+ url(url),
+ referrer(referrer),
+ size(size),
+ render_view_route_id(render_view_route_id),
+ creation_time(creation_time),
+ handle(NULL) {
+}
+
+PrerenderLinkManager::LinkPrerender::~LinkPrerender() {
+ DCHECK_EQ(static_cast<PrerenderHandle*>(NULL), handle)
+ << "The PrerenderHandle should be destroyed before its Prerender.";
+}
+
bool PrerenderLinkManager::IsEmpty() const {
- return ids_to_handle_map_.empty();
+ return prerenders_.empty();
}
-void PrerenderLinkManager::RemovePrerender(
- const IdPairToPrerenderHandleMap::iterator& id_to_handle_iter) {
- PrerenderHandle* prerender_handle = id_to_handle_iter->second;
- delete prerender_handle;
- ids_to_handle_map_.erase(id_to_handle_iter);
+size_t PrerenderLinkManager::CountRunningPrerenders() const {
+ size_t retval = 0;
+ for (std::list<LinkPrerender>::const_iterator i = prerenders_.begin();
+ i != prerenders_.end(); ++i) {
+ if (i->handle && i->handle->IsPrerendering())
+ ++retval;
+ }
+ return retval;
}
-PrerenderLinkManager::IdPairToPrerenderHandleMap::iterator
-PrerenderLinkManager::FindPrerenderHandle(
- PrerenderHandle* prerender_handle) {
- for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin();
- it != ids_to_handle_map_.end(); ++it) {
- if (it->second == prerender_handle)
- return it;
+void PrerenderLinkManager::StartPrerenders() {
+ if (has_shutdown_)
+ return;
+
+ size_t total_started_prerender_count = 0;
+ std::multiset<std::pair<int, int> >
+ running_launcher_and_render_view_routes;
+
+ // Scan the list, counting how many prerenders have handles (and so were added
+ // to the PrerenderManager). The count is done for the system as a whole, and
+ // also per launcher.
+ for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
+ i != prerenders_.end(); ++i) {
+ if (i->handle) {
+ ++total_started_prerender_count;
+ std::pair<int, int> launcher_and_render_view_route(
+ i->launcher_child_id, i->render_view_route_id);
+ running_launcher_and_render_view_routes.insert(
+ launcher_and_render_view_route);
+ DCHECK_GE(manager_->config().max_link_concurrency_per_launcher,
+ running_launcher_and_render_view_routes.count(
+ launcher_and_render_view_route));
+ }
+
+ DCHECK_EQ(&(*i), FindByLauncherChildIdAndPrerenderId(i->launcher_child_id,
+ i->prerender_id));
+ }
+ DCHECK_GE(manager_->config().max_link_concurrency,
+ total_started_prerender_count);
+ DCHECK_LE(CountRunningPrerenders(), total_started_prerender_count);
+
+ TimeTicks now = manager_->GetCurrentTimeTicks();
+
+ // Scan the list again, starting prerenders as our counts allow.
+ std::list<LinkPrerender>::iterator next = prerenders_.begin();
+ while (next != prerenders_.end()) {
+ std::list<LinkPrerender>::iterator i = next;
+ ++next;
+
+ if (total_started_prerender_count >=
+ manager_->config().max_link_concurrency ||
+ total_started_prerender_count >= prerenders_.size()) {
+ // The system is already at its prerender concurrency limit.
+ return;
+ }
+
+ if (i->handle) {
+ // This prerender has already been added to the prerender manager.
+ continue;
+ }
+
+ TimeDelta prerender_age = now - i->creation_time;
+ if (prerender_age >= manager_->config().max_wait_to_launch) {
+ // This prerender waited too long in the queue before launching.
+ prerenders_.erase(i);
+ continue;
+ }
+
+ std::pair<int, int> launcher_and_render_view_route(
+ i->launcher_child_id, i->render_view_route_id);
+ if (manager_->config().max_link_concurrency_per_launcher <=
+ running_launcher_and_render_view_routes.count(
+ launcher_and_render_view_route)) {
+ // This prerender's launcher is already at its limit.
+ continue;
+ }
+
+ PrerenderHandle* handle = manager_->AddPrerenderFromLinkRelPrerender(
+ i->launcher_child_id, i->render_view_route_id,
+ i->url, i->referrer, i->size);
+ if (!handle) {
+ // This prerender couldn't be launched, it's gone.
+ prerenders_.erase(i);
+ continue;
+ }
+
+ // We have successfully started a new prerender.
+ i->handle = handle;
+ ++total_started_prerender_count;
+ handle->SetObserver(this);
+ if (handle->IsPrerendering())
+ OnPrerenderStart(handle);
+
+ running_launcher_and_render_view_routes.insert(
+ launcher_and_render_view_route);
}
- return ids_to_handle_map_.end();
+}
+
+PrerenderLinkManager::LinkPrerender*
+PrerenderLinkManager::FindByLauncherChildIdAndPrerenderId(int launcher_child_id,
+ int prerender_id) {
+ for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
+ i != prerenders_.end(); ++i) {
+ if (launcher_child_id == i->launcher_child_id &&
+ prerender_id == i->prerender_id) {
+ return &(*i);
+ }
+ }
+ return NULL;
+}
+
+PrerenderLinkManager::LinkPrerender*
+PrerenderLinkManager::FindByPrerenderHandle(PrerenderHandle* prerender_handle) {
+ DCHECK(prerender_handle);
+ for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
+ i != prerenders_.end(); ++i) {
+ if (prerender_handle == i->handle)
+ return &(*i);
+ }
+ return NULL;
+}
+
+void PrerenderLinkManager::RemovePrerender(LinkPrerender* prerender) {
+ for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
+ i != prerenders_.end(); ++i) {
+ if (&(*i) == prerender) {
+ scoped_ptr<PrerenderHandle> own_handle(i->handle);
+ i->handle = NULL;
+ prerenders_.erase(i);
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+void PrerenderLinkManager::Shutdown() {
+ has_shutdown_ = true;
}
// In practice, this is always called from either
@@ -173,39 +302,34 @@ PrerenderLinkManager::FindPrerenderHandle(
// prerender case, from PrerenderHandle::AdoptPrerenderDataFrom.
void PrerenderLinkManager::OnPrerenderStart(
PrerenderHandle* prerender_handle) {
- IdPairToPrerenderHandleMap::iterator it =
- FindPrerenderHandle(prerender_handle);
- DCHECK(it != ids_to_handle_map_.end());
- const int child_id = it->first.first;
- const int prerender_id = it->first.second;
-
- Send(child_id, new PrerenderMsg_OnPrerenderStart(prerender_id));
+ LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
+ if (!prerender)
+ return;
+ Send(prerender->launcher_child_id,
+ new PrerenderMsg_OnPrerenderStart(prerender->prerender_id));
}
void PrerenderLinkManager::OnPrerenderAddAlias(
PrerenderHandle* prerender_handle,
const GURL& alias_url) {
- IdPairToPrerenderHandleMap::iterator it =
- FindPrerenderHandle(prerender_handle);
- if (it == ids_to_handle_map_.end())
+ LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
+ if (!prerender)
return;
- const int child_id = it->first.first;
- const int prerender_id = it->first.second;
-
- Send(child_id, new PrerenderMsg_OnPrerenderAddAlias(prerender_id, alias_url));
+ Send(prerender->launcher_child_id,
+ new PrerenderMsg_OnPrerenderAddAlias(prerender->prerender_id,
+ alias_url));
}
void PrerenderLinkManager::OnPrerenderStop(
PrerenderHandle* prerender_handle) {
- IdPairToPrerenderHandleMap::iterator it =
- FindPrerenderHandle(prerender_handle);
- if (it == ids_to_handle_map_.end())
+ LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
+ if (!prerender)
return;
- const int child_id = it->first.first;
- const int prerender_id = it->first.second;
- Send(child_id, new PrerenderMsg_OnPrerenderStop(prerender_id));
- RemovePrerender(it);
+ Send(prerender->launcher_child_id,
+ new PrerenderMsg_OnPrerenderStop(prerender->prerender_id));
+ RemovePrerender(prerender);
+ StartPrerenders();
}
} // namespace prerender
« 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