diff options
author | marja@chromium.org <marja@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-23 08:39:40 +0000 |
---|---|---|
committer | marja@chromium.org <marja@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-23 08:39:40 +0000 |
commit | f9df1df061b3909e82a5a7fd6deadd124effbb26 (patch) | |
tree | 65a960ec6e92fa534d5c62e8248e079c9361ea2d /chrome/browser/sessions | |
parent | 23448fa1eb4fd09931120b4c1fc3abb71d864a15 (diff) | |
download | chromium_src-f9df1df061b3909e82a5a7fd6deadd124effbb26.zip chromium_src-f9df1df061b3909e82a5a7fd6deadd124effbb26.tar.gz chromium_src-f9df1df061b3909e82a5a7fd6deadd124effbb26.tar.bz2 |
Session restore: Use the same TabLoader for all profiles.
When several profiles are restored at the same time, this decreases
the number of tabs loading in parallel.
BUG=124235
TEST=NONE
Review URL: http://codereview.chromium.org/10122007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133411 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sessions')
-rw-r--r-- | chrome/browser/sessions/session_restore.cc | 83 |
1 files changed, 61 insertions, 22 deletions
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index 4ae6876..79fc1cb 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc @@ -54,6 +54,9 @@ using content::WebContents; namespace { class SessionRestoreImpl; +class TabLoader; + +TabLoader* shared_tab_loader = NULL; // Pointers to SessionRestoreImpls which are currently restoring the session. std::set<SessionRestoreImpl*>* active_session_restorers = NULL; @@ -67,15 +70,23 @@ static const int kInitialDelayTimerMS = 100; // tabs. New tabs are loaded after the current tab finishes loading, or a delay // is reached (initially kInitialDelayTimerMS). If the delay is reached before // a tab finishes loading a new tab is loaded and the time of the delay -// doubled. When all tabs are loading TabLoader deletes itself. +// doubled. +// +// TabLoader keeps a reference to itself when it's loading. When it has finished +// loading, it drops the reference. If another profile is restored while the +// TabLoader is loading, it will schedule its tabs to get loaded by the same +// TabLoader. When doing the scheduling, it holds a reference to the TabLoader. // // This is not part of SessionRestoreImpl so that synchronous destruction // of SessionRestoreImpl doesn't have timing problems. class TabLoader : public content::NotificationObserver, - public net::NetworkChangeNotifier::OnlineStateObserver { + public net::NetworkChangeNotifier::OnlineStateObserver, + public base::RefCounted<TabLoader> { public: - explicit TabLoader(base::TimeTicks restore_started); - virtual ~TabLoader(); + // Retrieves a pointer to the TabLoader instance shared between profiles, or + // creates a new TabLoader if it doesn't exist. If a TabLoader is created, its + // starting timestamp is set to |restore_started|. + static TabLoader* GetTabLoader(base::TimeTicks restore_started); // Schedules a tab for loading. void ScheduleLoad(NavigationController* controller); @@ -90,10 +101,15 @@ class TabLoader : public content::NotificationObserver, void StartLoading(); private: + friend class base::RefCounted<TabLoader>; + typedef std::set<NavigationController*> TabsLoading; typedef std::list<NavigationController*> TabsToLoad; typedef std::set<RenderWidgetHost*> RenderWidgetHostSet; + explicit TabLoader(base::TimeTicks restore_started); + virtual ~TabLoader(); + // Loads the next tab. If there are no more tabs to load this deletes itself, // otherwise |force_load_timer_| is restarted. void LoadNextTab(); @@ -162,22 +178,18 @@ class TabLoader : public content::NotificationObserver, // Max number of tabs that were loaded in parallel (for metrics). size_t max_parallel_tab_loads_; + // For keeping TabLoader alive while it's loading even if no + // SessionRestoreImpls reference it. + scoped_refptr<TabLoader> this_retainer_; + DISALLOW_COPY_AND_ASSIGN(TabLoader); }; -TabLoader::TabLoader(base::TimeTicks restore_started) - : force_load_delay_(kInitialDelayTimerMS), - loading_(false), - got_first_paint_(false), - tab_count_(0), - restore_started_(restore_started), - max_parallel_tab_loads_(0) { -} - -TabLoader::~TabLoader() { - DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && - tabs_loading_.empty() && tabs_to_load_.empty()); - net::NetworkChangeNotifier::RemoveOnlineStateObserver(this); +// static +TabLoader* TabLoader::GetTabLoader(base::TimeTicks restore_started) { + if (!shared_tab_loader) + shared_tab_loader = new TabLoader(restore_started); + return shared_tab_loader; } void TabLoader::ScheduleLoad(NavigationController* controller) { @@ -200,8 +212,15 @@ void TabLoader::TabIsLoading(NavigationController* controller) { } void TabLoader::StartLoading() { + // When multiple profiles are using the same TabLoader, another profile might + // already have started loading. In that case, the tabs scheduled for loading + // by this profile are already in the loading queue, and they will get loaded + // eventually. + if (loading_) + return; registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_PAINT, content::NotificationService::AllSources()); + this_retainer_ = this; #if defined(OS_CHROMEOS) if (!net::NetworkChangeNotifier::IsOffline()) { loading_ = true; @@ -215,6 +234,22 @@ void TabLoader::StartLoading() { #endif } +TabLoader::TabLoader(base::TimeTicks restore_started) + : force_load_delay_(kInitialDelayTimerMS), + loading_(false), + got_first_paint_(false), + tab_count_(0), + restore_started_(restore_started), + max_parallel_tab_loads_(0) { +} + +TabLoader::~TabLoader() { + DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && + tabs_loading_.empty() && tabs_to_load_.empty()); + net::NetworkChangeNotifier::RemoveOnlineStateObserver(this); + shared_tab_loader = NULL; +} + void TabLoader::LoadNextTab() { if (!tabs_to_load_.empty()) { NavigationController* tab = tabs_to_load_.front(); @@ -325,10 +360,13 @@ void TabLoader::Observe(int type, default: NOTREACHED() << "Unknown notification received:" << type; } - // Delete ourselves when we're not waiting for any more notifications. + // Delete ourselves when we're not waiting for any more notifications. If this + // was not the last reference, a SessionRestoreImpl holding a reference will + // eventually call StartLoading (which assigns this_retainer_), or drop the + // reference without initiating a load. if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && tabs_loading_.empty() && tabs_to_load_.empty()) - delete this; + this_retainer_ = NULL; } void TabLoader::OnOnlineStateChanged(bool online) { @@ -596,7 +634,7 @@ class SessionRestoreImpl : public content::NotificationObserver { private: // Invoked when beginning to create new tabs. Resets the tab_loader_. void StartTabCreation() { - tab_loader_.reset(new TabLoader(restore_started_)); + tab_loader_ = TabLoader::GetTabLoader(restore_started_); } // Invoked when done with creating all the tabs/browsers. @@ -625,7 +663,8 @@ class SessionRestoreImpl : public content::NotificationObserver { if (succeeded) { DCHECK(tab_loader_.get()); // TabLoader deletes itself when done loading. - tab_loader_.release()->StartLoading(); + tab_loader_->StartLoading(); + tab_loader_ = NULL; } if (!synchronous_) { @@ -943,7 +982,7 @@ class SessionRestoreImpl : public content::NotificationObserver { CancelableRequestConsumer request_consumer_; // Responsible for loading the tabs. - scoped_ptr<TabLoader> tab_loader_; + scoped_refptr<TabLoader> tab_loader_; // When synchronous we run a nested message loop. To avoid creating windows // from the nested message loop (which can make exiting the nested message |