diff options
author | msarda@chromium.org <msarda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-18 17:17:33 +0000 |
---|---|---|
committer | msarda@chromium.org <msarda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-18 17:17:33 +0000 |
commit | afecfb73fdbca719e3a861b3255e68f2c3ef8780 (patch) | |
tree | d10462f24aae74062803c782ae05cfbf6819bd41 | |
parent | ac68e24b25c6578e131ba420abeeebddfb7bca0c (diff) | |
download | chromium_src-afecfb73fdbca719e3a861b3255e68f2c3ef8780.zip chromium_src-afecfb73fdbca719e3a861b3255e68f2c3ef8780.tar.gz chromium_src-afecfb73fdbca719e3a861b3255e68f2c3ef8780.tar.bz2 |
Delay bookmarks load while the profile is loading.
This CL adds a new DeferredSequencedtaskRunner that queues up tasks
until a first call to Start is issued. It creates such a task runner for the
execution of bookmarks I/O operations. At profile creation, the bookmarks
task runner is stopped and its execution is started after the profile has
finished loading.
BUG=NONE
Review URL: https://chromiumcodereview.appspot.com/12952005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194956 0039d316-1c4b-4281-b951-d872f2087c98
20 files changed, 558 insertions, 13 deletions
diff --git a/base/base.gyp b/base/base.gyp index 290961e..b026dcb 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -463,6 +463,7 @@ 'debug/trace_event_unittest.cc', 'debug/trace_event_unittest.h', 'debug/trace_event_win_unittest.cc', + 'deferred_sequenced_task_runner_unittest.cc', 'environment_unittest.cc', 'file_util_unittest.cc', 'file_version_info_unittest.cc', diff --git a/base/base.gypi b/base/base.gypi index f26c4c7..164aa23 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -137,6 +137,8 @@ 'debug/trace_event_impl.cc', 'debug/trace_event_impl.h', 'debug/trace_event_win.cc', + 'deferred_sequenced_task_runner.cc', + 'deferred_sequenced_task_runner.h', 'environment.cc', 'environment.h', 'file_descriptor_posix.h', diff --git a/base/deferred_sequenced_task_runner.cc b/base/deferred_sequenced_task_runner.cc new file mode 100644 index 0000000..c96704c --- /dev/null +++ b/base/deferred_sequenced_task_runner.cc @@ -0,0 +1,99 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/deferred_sequenced_task_runner.h" + +#include "base/bind.h" +#include "base/logging.h" + +namespace base { + +DeferredSequencedTaskRunner::DeferredTask::DeferredTask() { +} + +DeferredSequencedTaskRunner::DeferredTask::~DeferredTask() { +} + +DeferredSequencedTaskRunner::DeferredSequencedTaskRunner( + const scoped_refptr<SequencedTaskRunner>& target_task_runner) + : started_(false), + target_task_runner_(target_task_runner) { +} + +DeferredSequencedTaskRunner::~DeferredSequencedTaskRunner() { +} + +bool DeferredSequencedTaskRunner::PostDelayedTask( + const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay) { + AutoLock lock(lock_); + if (started_) { + DCHECK(deferred_tasks_queue_.empty()); + return target_task_runner_->PostDelayedTask(from_here, task, delay); + } + + QueueDeferredTask(from_here, task, delay, false /* is_non_nestable */); + return true; +} + +bool DeferredSequencedTaskRunner::RunsTasksOnCurrentThread() const { + return target_task_runner_->RunsTasksOnCurrentThread(); +} + +bool DeferredSequencedTaskRunner::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay) { + AutoLock lock(lock_); + if (started_) { + DCHECK(deferred_tasks_queue_.empty()); + return target_task_runner_->PostNonNestableDelayedTask(from_here, + task, + delay); + } + QueueDeferredTask(from_here, task, delay, true /* is_non_nestable */); + return true; +} + +void DeferredSequencedTaskRunner::QueueDeferredTask( + const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay, + bool is_non_nestable) { + DeferredTask deferred_task; + deferred_task.posted_from = from_here; + deferred_task.task = task; + deferred_task.delay = delay; + deferred_task.is_non_nestable = is_non_nestable; + deferred_tasks_queue_.push_back(deferred_task); +} + + +void DeferredSequencedTaskRunner::Start() { + AutoLock lock(lock_); + DCHECK(!started_); + started_ = true; + for (std::vector<DeferredTask>::iterator i = deferred_tasks_queue_.begin(); + i != deferred_tasks_queue_.end(); + ++i) { + const DeferredTask& task = *i; + if (task.is_non_nestable) { + target_task_runner_->PostNonNestableDelayedTask(task.posted_from, + task.task, + task.delay); + } else { + target_task_runner_->PostDelayedTask(task.posted_from, + task.task, + task.delay); + } + // Replace the i-th element in the |deferred_tasks_queue_| with an empty + // |DelayedTask| to ensure that |task| is destroyed before the next task + // is posted. + *i = DeferredTask(); + } + deferred_tasks_queue_.clear(); +} + +} // namespace base diff --git a/base/deferred_sequenced_task_runner.h b/base/deferred_sequenced_task_runner.h new file mode 100644 index 0000000..d1cdb43 --- /dev/null +++ b/base/deferred_sequenced_task_runner.h @@ -0,0 +1,79 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_ +#define BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_ + +#include <vector> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/sequenced_task_runner.h" +#include "base/synchronization/lock.h" +#include "base/time.h" +#include "base/tracked_objects.h" + +namespace base { + +// A DeferredSequencedTaskRunner is a subclass of SequencedTaskRunner that +// queues up all requests until the first call to Start() is issued. +class BASE_EXPORT DeferredSequencedTaskRunner : public SequencedTaskRunner { + public: + explicit DeferredSequencedTaskRunner( + const scoped_refptr<SequencedTaskRunner>& target_runner); + + // TaskRunner implementation + virtual bool PostDelayedTask(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay) OVERRIDE; + virtual bool RunsTasksOnCurrentThread() const OVERRIDE; + + // SequencedTaskRunner implementation + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay) OVERRIDE; + + // Start the execution - posts all queued tasks to the target executor. The + // deferred tasks are posted with their initial delay, meaning that the task + // execution delay is actually measured from Start. + // Fails when called a second time. + void Start(); + + private: + struct DeferredTask { + DeferredTask(); + ~DeferredTask(); + + tracked_objects::Location posted_from; + Closure task; + // The delay this task was initially posted with. + TimeDelta delay; + bool is_non_nestable; + }; + + virtual ~DeferredSequencedTaskRunner(); + + // Creates a |Task| object and adds it to |deferred_tasks_queue_|. + void QueueDeferredTask(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay, + bool is_non_nestable); + + // // Protects |started_| and |deferred_tasks_queue_|. + mutable Lock lock_; + + bool started_; + const scoped_refptr<SequencedTaskRunner> target_task_runner_; + std::vector<DeferredTask> deferred_tasks_queue_; + + DISALLOW_COPY_AND_ASSIGN(DeferredSequencedTaskRunner); +}; + +} // namespace base + +#endif // BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_ diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc new file mode 100644 index 0000000..c033ba8 --- /dev/null +++ b/base/deferred_sequenced_task_runner_unittest.cc @@ -0,0 +1,184 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/deferred_sequenced_task_runner.h" + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/threading/non_thread_safe.h" +#include "base/threading/thread.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class DeferredSequencedTaskRunnerTest : public testing::Test, + public base::NonThreadSafe { + public: + class ExecuteTaskOnDestructor : + public base::RefCounted<ExecuteTaskOnDestructor> { + public: + ExecuteTaskOnDestructor( + DeferredSequencedTaskRunnerTest* executor, + int task_id) + : executor_(executor), + task_id_(task_id) { + } + private: + friend class base::RefCounted<ExecuteTaskOnDestructor>; + virtual ~ExecuteTaskOnDestructor() { + executor_->ExecuteTask(task_id_); + } + DeferredSequencedTaskRunnerTest* executor_; + int task_id_; + }; + + void ExecuteTask(int task_id) { + base::AutoLock lock(lock_); + executed_task_ids_.push_back(task_id); + } + + void PostExecuteTask(int task_id) { + runner_->PostTask(FROM_HERE, + base::Bind(&DeferredSequencedTaskRunnerTest::ExecuteTask, + base::Unretained(this), + task_id)); + } + + void StartRunner() { + runner_->Start(); + } + + void DoNothing(ExecuteTaskOnDestructor* object) { + } + + protected: + DeferredSequencedTaskRunnerTest() : + loop_(), + runner_( + new base::DeferredSequencedTaskRunner(loop_.message_loop_proxy())) { + } + + MessageLoop loop_; + scoped_refptr<base::DeferredSequencedTaskRunner> runner_; + mutable base::Lock lock_; + std::vector<int> executed_task_ids_; +}; + +TEST_F(DeferredSequencedTaskRunnerTest, Stopped) { + PostExecuteTask(1); + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); +} + +TEST_F(DeferredSequencedTaskRunnerTest, Start) { + StartRunner(); + PostExecuteTask(1); + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1)); +} + +TEST_F(DeferredSequencedTaskRunnerTest, StartWithMultipleElements) { + StartRunner(); + for (int i = 1; i < 5; ++i) + PostExecuteTask(i); + + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4)); +} + +TEST_F(DeferredSequencedTaskRunnerTest, DeferredStart) { + PostExecuteTask(1); + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); + + StartRunner(); + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1)); + + PostExecuteTask(2); + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2)); +} + +TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleElements) { + for (int i = 1; i < 5; ++i) + PostExecuteTask(i); + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); + + StartRunner(); + for (int i = 5; i < 9; ++i) + PostExecuteTask(i); + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); +} + +TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) { + { + base::Thread thread1("DeferredSequencedTaskRunnerTestThread1"); + base::Thread thread2("DeferredSequencedTaskRunnerTestThread2"); + thread1.Start(); + thread2.Start(); + for (int i = 0; i < 5; ++i) { + thread1.message_loop()->PostTask( + FROM_HERE, + base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask, + base::Unretained(this), + 2 * i)); + thread2.message_loop()->PostTask( + FROM_HERE, + base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask, + base::Unretained(this), + 2 * i + 1)); + if (i == 2) { + thread1.message_loop()->PostTask( + FROM_HERE, + base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner, + base::Unretained(this))); + } + } + } + + loop_.RunUntilIdle(); + EXPECT_THAT(executed_task_ids_, + testing::WhenSorted(testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))); +} + +TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) { + { + base::Thread thread("DeferredSequencedTaskRunnerTestThread"); + thread.Start(); + runner_ = + new base::DeferredSequencedTaskRunner(thread.message_loop_proxy()); + for (int i = 0; i < 5; ++i) { + { + // Use a block to ensure that no reference to |short_lived_object| + // is kept on the main thread after it is posted to |runner_|. + scoped_refptr<ExecuteTaskOnDestructor> short_lived_object = + new ExecuteTaskOnDestructor(this, 2 * i); + runner_->PostTask( + FROM_HERE, + base::Bind(&DeferredSequencedTaskRunnerTest::DoNothing, + base::Unretained(this), + short_lived_object)); + } + // |short_lived_object| with id |2 * i| should be destroyed before the + // task |2 * i + 1| is executed. + PostExecuteTask(2 * i + 1); + } + StartRunner(); + } + + // All |short_lived_object| with id |2 * i| are destroyed before the task + // |2 * i + 1| is executed. + EXPECT_THAT(executed_task_ids_, + testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); +} + +} // namespace diff --git a/chrome/browser/bookmarks/DEPS b/chrome/browser/bookmarks/DEPS index 104e900..4c3d5ac 100644 --- a/chrome/browser/bookmarks/DEPS +++ b/chrome/browser/bookmarks/DEPS @@ -22,6 +22,8 @@ include_rules = [ "!chrome/browser/profiles/profile_dependency_manager.h", "!chrome/browser/profiles/profile_keyed_service.h", "!chrome/browser/profiles/profile_keyed_service_factory.h", + "!chrome/browser/profiles/startup_task_runner_service.h", + "!chrome/browser/profiles/startup_task_runner_service_factory.h", # Do not add to the list of temporarily-allowed dependencies above, # and please do not introduce more #includes of these files. ] diff --git a/chrome/browser/bookmarks/bookmark_model.cc b/chrome/browser/bookmarks/bookmark_model.cc index 150afd4..d23f645 100644 --- a/chrome/browser/bookmarks/bookmark_model.cc +++ b/chrome/browser/bookmarks/bookmark_model.cc @@ -232,7 +232,8 @@ void BookmarkModel::Shutdown() { loaded_signal_.Signal(); } -void BookmarkModel::Load() { +void BookmarkModel::Load( + const scoped_refptr<base::SequencedTaskRunner>& task_runner) { if (store_.get()) { // If the store is non-null, it means Load was already invoked. Load should // only be invoked once. @@ -249,7 +250,7 @@ void BookmarkModel::Load() { content::Source<Profile>(profile_)); // Load the bookmarks. BookmarkStorage notifies us when done. - store_ = new BookmarkStorage(profile_, this, profile_->GetIOTaskRunner()); + store_ = new BookmarkStorage(profile_, this, task_runner); store_->LoadBookmarks(CreateLoadDetails()); } diff --git a/chrome/browser/bookmarks/bookmark_model.h b/chrome/browser/bookmarks/bookmark_model.h index 1d846d7..9853d38 100644 --- a/chrome/browser/bookmarks/bookmark_model.h +++ b/chrome/browser/bookmarks/bookmark_model.h @@ -33,6 +33,10 @@ class BookmarkModelObserver; class BookmarkStorage; class Profile; +namespace base { +class SequencedTaskRunner; +} + namespace bookmark_utils { struct TitleMatch; } @@ -236,7 +240,8 @@ class BookmarkModel : public content::NotificationObserver, // Loads the bookmarks. This is called upon creation of the // BookmarkModel. You need not invoke this directly. - void Load(); + // All load operations will be executed on |task_runner|. + void Load(const scoped_refptr<base::SequencedTaskRunner>& task_runner); // Returns true if the model finished loading. // This is virtual so it can be mocked. diff --git a/chrome/browser/bookmarks/bookmark_model_factory.cc b/chrome/browser/bookmarks/bookmark_model_factory.cc index 1f63b6d..73da8cb 100644 --- a/chrome/browser/bookmarks/bookmark_model_factory.cc +++ b/chrome/browser/bookmarks/bookmark_model_factory.cc @@ -4,11 +4,14 @@ #include "chrome/browser/bookmarks/bookmark_model_factory.h" +#include "base/deferred_sequenced_task_runner.h" #include "base/memory/singleton.h" #include "base/values.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_dependency_manager.h" +#include "chrome/browser/profiles/startup_task_runner_service.h" +#include "chrome/browser/profiles/startup_task_runner_service_factory.h" #include "chrome/common/pref_names.h" #include "components/user_prefs/pref_registry_syncable.h" @@ -38,7 +41,8 @@ BookmarkModelFactory::~BookmarkModelFactory() {} ProfileKeyedService* BookmarkModelFactory::BuildServiceInstanceFor( Profile* profile) const { BookmarkModel* bookmark_model = new BookmarkModel(profile); - bookmark_model->Load(); + bookmark_model->Load(StartupTaskRunnerServiceFactory::GetForProfile(profile)-> + GetBookmarkTaskRunner()); return bookmark_model; } diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index e157d1f..ce4ff02 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/deferred_sequenced_task_runner.h" #include "base/file_util.h" #include "base/files/file_path.h" #include "base/metrics/histogram.h" @@ -25,6 +26,8 @@ #include "chrome/browser/profiles/profile_destroyer.h" #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_metrics.h" +#include "chrome/browser/profiles/startup_task_runner_service.h" +#include "chrome/browser/profiles/startup_task_runner_service_factory.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/ui/browser.h" @@ -847,6 +850,9 @@ void ProfileManager::DoFinalInitForServices(Profile* profile, // initializing the managed flag if necessary). ManagedUserServiceFactory::GetForProfile(profile)->Init(); #endif + // Start the deferred task runners once the profile is loaded. + StartupTaskRunnerServiceFactory::GetForProfile(profile)-> + StartDeferredTaskRunners(); } void ProfileManager::DoFinalInitLogging(Profile* profile) { @@ -1173,12 +1179,17 @@ ProfileManagerWithoutInit::ProfileManagerWithoutInit( } void ProfileManager::RegisterTestingProfile(Profile* profile, - bool add_to_cache) { + bool add_to_cache, + bool start_deferred_task_runners) { RegisterProfile(profile, true); if (add_to_cache) { InitProfileUserPrefs(profile); AddProfileToCache(profile); } + if (start_deferred_task_runners) { + StartupTaskRunnerServiceFactory::GetForProfile(profile)-> + StartDeferredTaskRunners(); + } } void ProfileManager::RunCallbacks(const std::vector<CreateCallback>& callbacks, diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h index a93d457..6cee37b8 100644 --- a/chrome/browser/profiles/profile_manager.h +++ b/chrome/browser/profiles/profile_manager.h @@ -211,10 +211,14 @@ class ProfileManager : public base::NonThreadSafe, // Autoloads profiles if they are running background apps. void AutoloadProfiles(); - // Register and add testing profile to the ProfileManager. Use ONLY in tests. + // Registers and adds testing profile to the ProfileManager. // This allows the creation of Profiles outside of the standard creation path - // for testing. If |addToCache|, add to ProfileInfoCache as well. - void RegisterTestingProfile(Profile* profile, bool addToCache); + // for testing. If |addToCache|, adds to ProfileInfoCache as well. + // If |start_deferred_task_runners|, starts the deferred task runners. + // Use ONLY in tests. + void RegisterTestingProfile(Profile* profile, + bool addToCache, + bool start_deferred_task_runners); const base::FilePath& user_data_dir() const { return user_data_dir_; } diff --git a/chrome/browser/profiles/startup_task_runner_service.cc b/chrome/browser/profiles/startup_task_runner_service.cc new file mode 100644 index 0000000..60407e1 --- /dev/null +++ b/chrome/browser/profiles/startup_task_runner_service.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/profiles/startup_task_runner_service.h" + +#include "base/deferred_sequenced_task_runner.h" +#include "base/logging.h" +#include "chrome/browser/profiles/profile.h" + +StartupTaskRunnerService::StartupTaskRunnerService(Profile* profile) + : profile_(profile) { +} + +StartupTaskRunnerService::~StartupTaskRunnerService() { +} + +scoped_refptr<base::DeferredSequencedTaskRunner> + StartupTaskRunnerService::GetBookmarkTaskRunner() { + DCHECK(CalledOnValidThread()); + if (!bookmark_task_runner_) { + bookmark_task_runner_ = + new base::DeferredSequencedTaskRunner(profile_->GetIOTaskRunner()); + } + return bookmark_task_runner_; +} + +void StartupTaskRunnerService::StartDeferredTaskRunners() { + GetBookmarkTaskRunner()->Start(); +} diff --git a/chrome/browser/profiles/startup_task_runner_service.h b/chrome/browser/profiles/startup_task_runner_service.h new file mode 100644 index 0000000..f6298a3 --- /dev/null +++ b/chrome/browser/profiles/startup_task_runner_service.h @@ -0,0 +1,45 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_H_ +#define CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_H_ + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/threading/non_thread_safe.h" +#include "chrome/browser/profiles/profile_keyed_service.h" + +class Profile; + +namespace base { +class DeferredSequencedTaskRunner; +} // namespace base + +// This service manages the startup task runners. +class StartupTaskRunnerService : public base::NonThreadSafe, + public ProfileKeyedService { + public: + explicit StartupTaskRunnerService(Profile* profile); + virtual ~StartupTaskRunnerService(); + + // Returns sequenced task runner where all bookmarks I/O operations are + // performed. + // This method should only be called from the UI thread. + // Note: Using a separate task runner per profile service gives a better + // management of the sequence in which the task are started in order to avoid + // congestion during start-up (e.g the caller may decide to start loading the + // bookmarks only after the history finished). + scoped_refptr<base::DeferredSequencedTaskRunner> GetBookmarkTaskRunner(); + + // Starts the task runners that are deferred during start-up. + void StartDeferredTaskRunners(); + + private: + Profile* profile_; + scoped_refptr<base::DeferredSequencedTaskRunner> bookmark_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(StartupTaskRunnerService); +}; + +#endif // CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_H_ diff --git a/chrome/browser/profiles/startup_task_runner_service_factory.cc b/chrome/browser/profiles/startup_task_runner_service_factory.cc new file mode 100644 index 0000000..eaff6a8 --- /dev/null +++ b/chrome/browser/profiles/startup_task_runner_service_factory.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/profiles/startup_task_runner_service_factory.h" + +#include "chrome/browser/profiles/profile_dependency_manager.h" +#include "chrome/browser/profiles/startup_task_runner_service.h" + +StartupTaskRunnerServiceFactory::StartupTaskRunnerServiceFactory() + : ProfileKeyedServiceFactory("StartupTaskRunnerServiceFactory", + ProfileDependencyManager::GetInstance()) { +} + +StartupTaskRunnerServiceFactory::~StartupTaskRunnerServiceFactory() {} + +// static +StartupTaskRunnerService* StartupTaskRunnerServiceFactory::GetForProfile( + Profile* profile) { + return static_cast<StartupTaskRunnerService*>( + GetInstance()->GetServiceForProfile(profile, true)); +} + +// static +StartupTaskRunnerServiceFactory* + StartupTaskRunnerServiceFactory::GetInstance() { + return Singleton<StartupTaskRunnerServiceFactory>::get(); +} + +ProfileKeyedService* StartupTaskRunnerServiceFactory::BuildServiceInstanceFor( + Profile* profile) const { + return new StartupTaskRunnerService(profile); +} diff --git a/chrome/browser/profiles/startup_task_runner_service_factory.h b/chrome/browser/profiles/startup_task_runner_service_factory.h new file mode 100644 index 0000000..58bb4db --- /dev/null +++ b/chrome/browser/profiles/startup_task_runner_service_factory.h @@ -0,0 +1,39 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_ + +#include "base/basictypes.h" +#include "base/memory/singleton.h" +#include "chrome/browser/profiles/profile_keyed_service_factory.h" + +class StartupTaskRunnerService; +class PrefRegistrySyncable; +class Profile; + +// Singleton that owns the start-up task runner service. +class StartupTaskRunnerServiceFactory : public ProfileKeyedServiceFactory { + public: + // Returns the instance of StartupTaskRunnerService associated with this + // profile (creating one if none exists). + static StartupTaskRunnerService* GetForProfile(Profile* profile); + + // Returns an instance of the StartupTaskRunnerServiceFactory singleton. + static StartupTaskRunnerServiceFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits<StartupTaskRunnerServiceFactory>; + + StartupTaskRunnerServiceFactory(); + virtual ~StartupTaskRunnerServiceFactory(); + + // ProfileKeyedServiceFactory: + virtual ProfileKeyedService* BuildServiceInstanceFor( + Profile* profile) const OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(StartupTaskRunnerServiceFactory); +}; + +#endif // CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_ diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc index bfa351b..3f3e27b 100644 --- a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc @@ -56,7 +56,7 @@ class HistoryMock : public HistoryService { ProfileKeyedService* BuildBookmarkModel(Profile* profile) { BookmarkModel* bookmark_model = new BookmarkModel(profile); - bookmark_model->Load(); + bookmark_model->Load(profile->GetIOTaskRunner()); return bookmark_model; } @@ -177,7 +177,7 @@ TEST_F(SyncBookmarkDataTypeControllerTest, StartBookmarkModelNotReady) { base::Unretained(&model_load_callback_))); EXPECT_EQ(DataTypeController::MODEL_STARTING, bookmark_dtc_->state()); - bookmark_model_->Load(); + bookmark_model_->Load(profile_.GetIOTaskRunner()); ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model_); EXPECT_EQ(DataTypeController::MODEL_LOADED, bookmark_dtc_->state()); diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index fbe9500..d2facba 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc @@ -231,7 +231,9 @@ Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) { Profile* profile = Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS); - g_browser_process->profile_manager()->RegisterTestingProfile(profile, true); + g_browser_process->profile_manager()->RegisterTestingProfile(profile, + true, + true); return profile; } diff --git a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc index ca14d6e..498919c 100644 --- a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc +++ b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc @@ -25,7 +25,7 @@ void CreateTestingProfile() { CHECK(file_util::CreateDirectory(path)); Profile* profile = Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS); - profile_manager->RegisterTestingProfile(profile, true); + profile_manager->RegisterTestingProfile(profile, true, false); EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles()); } diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 1ea871f..46dda1a 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1536,6 +1536,10 @@ 'browser/profiles/refcounted_profile_keyed_service.h', 'browser/profiles/refcounted_profile_keyed_service_factory.cc', 'browser/profiles/refcounted_profile_keyed_service_factory.h', + 'browser/profiles/startup_task_runner_service.cc', + 'browser/profiles/startup_task_runner_service.h', + 'browser/profiles/startup_task_runner_service_factory.cc', + 'browser/profiles/startup_task_runner_service_factory.h', 'browser/profiles/storage_partition_descriptor.h', 'browser/remove_rows_table_model.h', 'browser/renderer_host/chrome_render_message_filter.cc', diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index fed2377..92e1286 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc @@ -392,7 +392,7 @@ void TestingProfile::DestroyTopSites() { static ProfileKeyedService* BuildBookmarkModel(Profile* profile) { BookmarkModel* bookmark_model = new BookmarkModel(profile); - bookmark_model->Load(); + bookmark_model->Load(profile->GetIOTaskRunner()); return bookmark_model; } |