diff options
author | caitkp@chromium.org <caitkp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-19 03:18:46 +0000 |
---|---|---|
committer | caitkp@chromium.org <caitkp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-19 03:18:46 +0000 |
commit | 8b390a6d541c0e0700f795d7a76e21ac168f4ab9 (patch) | |
tree | e3260779d27281c9f508fcafd7f3633b17be7ce8 | |
parent | d7e70c88f9a98b0475fdd9860c162cd54c0b9692 (diff) | |
download | chromium_src-8b390a6d541c0e0700f795d7a76e21ac168f4ab9.zip chromium_src-8b390a6d541c0e0700f795d7a76e21ac168f4ab9.tar.gz chromium_src-8b390a6d541c0e0700f795d7a76e21ac168f4ab9.tar.bz2 |
Second try at splitting WebDataService (minus ownership changes)
Split Database handling into a separate class, but keep it owned by WebDataService, to avoid it disappearing out from under us (crbug.com/181628).
TBR=ben@chromium.org,sky@chromium.org
TEST= unit_tests
BUG=181277
COLLABORATOR=joi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/12871006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188935 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/password_manager/password_store_win_unittest.cc | 3 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_service_test_util.cc | 116 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_service_test_util.h | 6 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_service_unittest.cc | 3 | ||||
-rw-r--r-- | chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service.cc | 512 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service.h | 195 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service_factory.cc | 3 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service_unittest.cc | 5 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service_win.cc | 36 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database.h | 4 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database_service.cc | 262 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database_service.h | 94 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/test/base/testing_profile.cc | 4 |
15 files changed, 726 insertions, 523 deletions
diff --git a/chrome/browser/password_manager/password_store_win_unittest.cc b/chrome/browser/password_manager/password_store_win_unittest.cc index 2528ba5..af88968 100644 --- a/chrome/browser/password_manager/password_store_win_unittest.cc +++ b/chrome/browser/password_manager/password_store_win_unittest.cc @@ -115,7 +115,8 @@ class PasswordStoreWinTest : public testing::Test { ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append( FILE_PATH_LITERAL("login_test")))); wds_ = new WebDataService(); - ASSERT_TRUE(wds_->Init(temp_dir_.path())); + base::FilePath path = temp_dir_.path().AppendASCII("web_data_test"); + wds_->Init(path); } virtual void TearDown() { diff --git a/chrome/browser/search_engines/template_url_service_test_util.cc b/chrome/browser/search_engines/template_url_service_test_util.cc index 244046e..ba19b0a 100644 --- a/chrome/browser/search_engines/template_url_service_test_util.cc +++ b/chrome/browser/search_engines/template_url_service_test_util.cc @@ -5,7 +5,6 @@ #include "chrome/browser/search_engines/template_url_service_test_util.h" #include "base/bind.h" -#include "base/files/scoped_temp_dir.h" #include "base/message_loop.h" #include "base/path_service.h" #include "base/synchronization/waitable_event.h" @@ -53,35 +52,6 @@ static void WaitForThreadToProcessRequests(BrowserThread::ID identifier) { } // namespace -// Subclass the TestingProfile so that it can return a WebDataService. -class TemplateURLServiceTestingProfile : public TestingProfile { - public: - TemplateURLServiceTestingProfile() - : TestingProfile(), - db_thread_(BrowserThread::DB), - io_thread_(BrowserThread::IO) { - } - - void SetUp(); - void TearDown(); - - // Starts the I/O thread. This isn't done automatically because not every test - // needs this. - void StartIOThread() { - io_thread_.StartIOThread(); - } - - static scoped_refptr<RefcountedProfileKeyedService> - GetWebDataServiceForTemplateURLServiceTestingProfile(Profile* profile); - - private: - scoped_refptr<WebDataService> service_; - base::ScopedTempDir temp_dir_; - content::TestBrowserThread db_thread_; - content::TestBrowserThread io_thread_; -}; - - // Trivial subclass of TemplateURLService that records the last invocation of // SetKeywordSearchTermsForURL. class TestingTemplateURLService : public TemplateURLService { @@ -113,21 +83,38 @@ class TestingTemplateURLService : public TemplateURLService { DISALLOW_COPY_AND_ASSIGN(TestingTemplateURLService); }; -void TemplateURLServiceTestingProfile::SetUp() { +TemplateURLServiceTestUtil::TemplateURLServiceTestUtil() + : ui_thread_(BrowserThread::UI, &message_loop_), + db_thread_(BrowserThread::DB), + io_thread_(BrowserThread::IO), + changed_count_(0) { +} + +TemplateURLServiceTestUtil::~TemplateURLServiceTestUtil() { +} + +void TemplateURLServiceTestUtil::SetUp() { + profile_.reset(new TestingProfile()); db_thread_.Start(); + profile_->CreateWebDataService(); - // Make unique temp directory. - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + TemplateURLService* service = static_cast<TemplateURLService*>( + TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( + profile_.get(), TestingTemplateURLService::Build)); + service->AddObserver(this); - base::FilePath path = temp_dir_.path().AppendASCII("TestDataService.db"); - service_ = new WebDataService; - ASSERT_TRUE(service_->InitWithPath(path)); +#if defined(OS_CHROMEOS) + google_util::chromeos::ClearBrandForCurrentSession(); +#endif } -void TemplateURLServiceTestingProfile::TearDown() { - // Clear the request context so it will get deleted. This should be done - // before shutting down the I/O thread to avoid memory leaks. - ResetRequestContext(); +void TemplateURLServiceTestUtil::TearDown() { + if (profile_.get()) { + // Clear the request context so it will get deleted. This should be done + // before shutting down the I/O thread to avoid memory leaks. + profile_->ResetRequestContext(); + profile_.reset(); + } // Wait for the delete of the request context to happen. if (io_thread_.IsRunning()) @@ -136,11 +123,6 @@ void TemplateURLServiceTestingProfile::TearDown() { // The I/O thread must be shutdown before the DB thread. io_thread_.Stop(); - // Clean up the test directory. - if (service_.get()) { - service_->ShutdownOnUIThread(); - service_ = NULL; - } // Note that we must ensure the DB thread is stopped after WDS // shutdown (so it can commit pending transactions) but before // deleting the test profile directory, otherwise we may not be @@ -151,47 +133,10 @@ void TemplateURLServiceTestingProfile::TearDown() { BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done))); done.Wait(); + MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + MessageLoop::current()->Run(); db_thread_.Stop(); -} - -scoped_refptr<RefcountedProfileKeyedService> -TemplateURLServiceTestingProfile:: - GetWebDataServiceForTemplateURLServiceTestingProfile(Profile* profile) { - TemplateURLServiceTestingProfile* test_profile = - reinterpret_cast<TemplateURLServiceTestingProfile*>(profile); - return test_profile->service_; -} - -TemplateURLServiceTestUtil::TemplateURLServiceTestUtil() - : ui_thread_(BrowserThread::UI, &message_loop_), - changed_count_(0) { -} - -TemplateURLServiceTestUtil::~TemplateURLServiceTestUtil() { -} - -void TemplateURLServiceTestUtil::SetUp() { - profile_.reset(new TemplateURLServiceTestingProfile()); - WebDataServiceFactory::GetInstance()->SetTestingFactory( - profile_.get(), TemplateURLServiceTestingProfile:: - GetWebDataServiceForTemplateURLServiceTestingProfile); - profile_->SetUp(); - TemplateURLService* service = static_cast<TemplateURLService*>( - TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile_.get(), TestingTemplateURLService::Build)); - service->AddObserver(this); - -#if defined(OS_CHROMEOS) - google_util::chromeos::ClearBrandForCurrentSession(); -#endif -} - -void TemplateURLServiceTestUtil::TearDown() { - if (profile_.get()) { - profile_->TearDown(); - profile_.reset(); - } UIThreadSearchTermsData::SetGoogleBaseURL(std::string()); // Flush the message loop to make application verifiers happy. @@ -233,6 +178,7 @@ void TemplateURLServiceTestUtil::ChangeModelToLoadState() { model()->service_ = WebDataServiceFactory::GetForProfile( profile_.get(), Profile::EXPLICIT_ACCESS); + BlockTillServiceProcessesRequests(); } void TemplateURLServiceTestUtil::ClearModel() { @@ -330,7 +276,7 @@ TestingProfile* TemplateURLServiceTestUtil::profile() const { } void TemplateURLServiceTestUtil::StartIOThread() { - profile_->StartIOThread(); + io_thread_.StartIOThread(); } void TemplateURLServiceTestUtil::PumpLoop() { diff --git a/chrome/browser/search_engines/template_url_service_test_util.h b/chrome/browser/search_engines/template_url_service_test_util.h index ae4fe36..f903e26 100644 --- a/chrome/browser/search_engines/template_url_service_test_util.h +++ b/chrome/browser/search_engines/template_url_service_test_util.h @@ -18,7 +18,7 @@ class GURL; class TemplateURLService; -class TemplateURLServiceTestingProfile; +class TestingProfile; class TestingTemplateURLService; class TestingProfile; class WebDataService; @@ -112,7 +112,9 @@ class TemplateURLServiceTestUtil : public TemplateURLServiceObserver { // Needed to make the DeleteOnUIThread trait of WebDataService work // properly. content::TestBrowserThread ui_thread_; - scoped_ptr<TemplateURLServiceTestingProfile> profile_; + content::TestBrowserThread db_thread_; + content::TestBrowserThread io_thread_; + scoped_ptr<TestingProfile> profile_; int changed_count_; DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceTestUtil); diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc index 8c35473..9adafe7 100644 --- a/chrome/browser/search_engines/template_url_service_unittest.cc +++ b/chrome/browser/search_engines/template_url_service_unittest.cc @@ -1311,8 +1311,7 @@ TEST_F(TemplateURLServiceTest, FailedInit) { scoped_refptr<WebDataService> web_service = WebDataServiceFactory::GetForProfile(test_util_.profile(), Profile::EXPLICIT_ACCESS); - web_service->UnloadDatabase(); - web_service->set_failed_init(true); + web_service->ShutdownDatabase(); test_util_.ResetModel(false); model()->Load(); diff --git a/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc b/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc index b7cbb3e..978c329 100644 --- a/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc @@ -128,7 +128,6 @@ TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceNotReady) { WillOnce(MakeSharedChangeProcessor()); EXPECT_CALL(model_load_callback_, Run(_, _)); - EXPECT_FALSE(syncable_service_.syncing()); search_engine_dtc_->LoadModels( base::Bind(&ModelLoadCallbackMock::Run, @@ -142,6 +141,9 @@ TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceNotReady) { content::Source<TemplateURLService>(test_util_.model()), content::NotificationService::NoDetails()); EXPECT_EQ(DataTypeController::MODEL_LOADED, search_engine_dtc_->state()); + + // Wait until WebDB is loaded before we shut it down. + test_util_.BlockTillServiceProcessesRequests(); } TEST_F(SyncSearchEngineDataTypeControllerTest, StartFirstRun) { diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc index c5976af..edf8827 100644 --- a/chrome/browser/webdata/web_data_service.cc +++ b/chrome/browser/webdata/web_data_service.cc @@ -22,7 +22,7 @@ #include "chrome/browser/webdata/logins_table.h" #include "chrome/browser/webdata/token_service_table.h" #include "chrome/browser/webdata/web_apps_table.h" -#include "chrome/browser/webdata/web_database.h" +#include "chrome/browser/webdata/web_database_service.h" #include "chrome/browser/webdata/web_intents_table.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_notification_types.h" @@ -78,15 +78,9 @@ WDKeywordsResult::WDKeywordsResult() WDKeywordsResult::~WDKeywordsResult() {} WebDataService::WebDataService() - : is_running_(false), - db_(NULL), - request_manager_(new WebDataRequestManager()), - app_locale_(AutofillCountry::ApplicationLocale()), + : db_loaded_(false), autocomplete_syncable_service_(NULL), - autofill_profile_syncable_service_(NULL), - failed_init_(false), - should_commit_(false), - main_loop_(MessageLoop::current()) { + autofill_profile_syncable_service_(NULL) { // WebDataService requires DB thread if instantiated. // Set WebDataServiceFactory::GetInstance()->SetTestingFactory(&profile, NULL) // if you do not want to instantiate WebDataService in your test. @@ -108,27 +102,36 @@ void WebDataService::NotifyOfMultipleAutofillChanges( } void WebDataService::ShutdownOnUIThread() { - ScheduleTask(FROM_HERE, - Bind(&WebDataService::ShutdownSyncableServices, this)); - UnloadDatabase(); + db_loaded_ = false; + ShutdownDatabase(); + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, + Bind(&WebDataService::ShutdownSyncableServices, this)); } -bool WebDataService::Init(const base::FilePath& profile_path) { - base::FilePath path = profile_path; - path = path.Append(chrome::kWebDataFilename); - return InitWithPath(path); -} +void WebDataService::Init(const base::FilePath& path) { + wdbs_.reset(new WebDatabaseService(path)); + wdbs_->LoadDatabase(Bind(&WebDataService::DatabaseInitOnDB, this)); -bool WebDataService::IsRunning() const { - return is_running_; + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, + Bind(&WebDataService::InitializeSyncableServices, this)); } void WebDataService::UnloadDatabase() { - ScheduleTask(FROM_HERE, Bind(&WebDataService::ShutdownDatabase, this)); + if (!wdbs_) + return; + wdbs_->UnloadDatabase(); +} + +void WebDataService::ShutdownDatabase() { + if (!wdbs_) + return; + wdbs_->ShutdownDatabase(); } void WebDataService::CancelRequest(Handle h) { - request_manager_->CancelRequest(h); + if (!wdbs_) + return; + wdbs_->CancelRequest(h); } content::NotificationSource WebDataService::GetNotificationSource() { @@ -136,12 +139,13 @@ content::NotificationSource WebDataService::GetNotificationSource() { } bool WebDataService::IsDatabaseLoaded() { - return db_ != NULL; + return db_loaded_; } WebDatabase* WebDataService::GetDatabase() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); - return db_; + if (!wdbs_) + return NULL; + return wdbs_->GetDatabaseOnDB(); } ////////////////////////////////////////////////////////////////////////////// @@ -151,34 +155,34 @@ WebDatabase* WebDataService::GetDatabase() { ////////////////////////////////////////////////////////////////////////////// void WebDataService::AddKeyword(const TemplateURLData& data) { - ScheduleDBTask( + wdbs_->ScheduleDBTask( FROM_HERE, Bind(&WebDataService::AddKeywordImpl, this, data)); } void WebDataService::RemoveKeyword(TemplateURLID id) { - ScheduleDBTask( + wdbs_->ScheduleDBTask( FROM_HERE, Bind(&WebDataService::RemoveKeywordImpl, this, id)); } void WebDataService::UpdateKeyword(const TemplateURLData& data) { - ScheduleDBTask( + wdbs_->ScheduleDBTask( FROM_HERE, Bind(&WebDataService::UpdateKeywordImpl, this, data)); } WebDataService::Handle WebDataService::GetKeywords( WebDataServiceConsumer* consumer) { - return ScheduleDBTaskWithResult(FROM_HERE, + return wdbs_->ScheduleDBTaskWithResult(FROM_HERE, Bind(&WebDataService::GetKeywordsImpl, this), consumer); } void WebDataService::SetDefaultSearchProvider(const TemplateURL* url) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::SetDefaultSearchProviderImpl, this, url ? url->id() : 0)); } void WebDataService::SetBuiltinKeywordVersion(int version) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::SetBuiltinKeywordVersionImpl, this, version)); } @@ -190,26 +194,25 @@ void WebDataService::SetBuiltinKeywordVersion(int version) { void WebDataService::SetWebAppImage(const GURL& app_url, const SkBitmap& image) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::SetWebAppImageImpl, this, app_url, image)); } void WebDataService::SetWebAppHasAllImages(const GURL& app_url, bool has_all_images) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::SetWebAppHasAllImagesImpl, this, app_url, has_all_images)); } void WebDataService::RemoveWebApp(const GURL& app_url) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::RemoveWebAppImpl, this, app_url)); } WebDataService::Handle WebDataService::GetWebAppImages( - const GURL& app_url, - WebDataServiceConsumer* consumer) { - return ScheduleDBTaskWithResult(FROM_HERE, + const GURL& app_url, WebDataServiceConsumer* consumer) { + return wdbs_->ScheduleDBTaskWithResult(FROM_HERE, Bind(&WebDataService::GetWebAppImagesImpl, this, app_url), consumer); } @@ -221,18 +224,19 @@ WebDataService::Handle WebDataService::GetWebAppImages( void WebDataService::SetTokenForService(const std::string& service, const std::string& token) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::SetTokenForServiceImpl, this, service, token)); } void WebDataService::RemoveAllTokens() { - ScheduleDBTask(FROM_HERE, Bind(&WebDataService::RemoveAllTokensImpl, this)); + wdbs_->ScheduleDBTask(FROM_HERE, + Bind(&WebDataService::RemoveAllTokensImpl, this)); } // Null on failure. Success is WDResult<std::string> WebDataService::Handle WebDataService::GetAllTokens( WebDataServiceConsumer* consumer) { - return ScheduleDBTaskWithResult(FROM_HERE, + return wdbs_->ScheduleDBTaskWithResult(FROM_HERE, Bind(&WebDataService::GetAllTokensImpl, this), consumer); } @@ -244,145 +248,125 @@ WebDataService::Handle WebDataService::GetAllTokens( void WebDataService::AddFormFields( const std::vector<FormFieldData>& fields) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::AddFormElementsImpl, this, fields)); } WebDataService::Handle WebDataService::GetFormValuesForElementName( const string16& name, const string16& prefix, int limit, WebDataServiceConsumer* consumer) { - return ScheduleDBTaskWithResult(FROM_HERE, + return wdbs_->ScheduleDBTaskWithResult(FROM_HERE, Bind(&WebDataService::GetFormValuesForElementNameImpl, - this, name, prefix, limit), - consumer); + this, name, prefix, limit), consumer); } void WebDataService::RemoveFormElementsAddedBetween(const Time& delete_begin, const Time& delete_end) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::RemoveFormElementsAddedBetweenImpl, this, delete_begin, delete_end)); } void WebDataService::RemoveExpiredFormElements() { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::RemoveExpiredFormElementsImpl, this)); } void WebDataService::RemoveFormValueForElementName( const string16& name, const string16& value) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::RemoveFormValueForElementNameImpl, this, name, value)); } void WebDataService::AddAutofillProfile(const AutofillProfile& profile) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::AddAutofillProfileImpl, this, profile)); } void WebDataService::UpdateAutofillProfile(const AutofillProfile& profile) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::UpdateAutofillProfileImpl, this, profile)); } void WebDataService::RemoveAutofillProfile(const std::string& guid) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::RemoveAutofillProfileImpl, this, guid)); } WebDataService::Handle WebDataService::GetAutofillProfiles( WebDataServiceConsumer* consumer) { - return ScheduleDBTaskWithResult(FROM_HERE, + return wdbs_->ScheduleDBTaskWithResult(FROM_HERE, Bind(&WebDataService::GetAutofillProfilesImpl, this), consumer); } void WebDataService::AddCreditCard(const CreditCard& credit_card) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::AddCreditCardImpl, this, credit_card)); } void WebDataService::UpdateCreditCard(const CreditCard& credit_card) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::UpdateCreditCardImpl, this, credit_card)); } void WebDataService::RemoveCreditCard(const std::string& guid) { - ScheduleDBTask(FROM_HERE, + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&WebDataService::RemoveCreditCardImpl, this, guid)); } WebDataService::Handle WebDataService::GetCreditCards( WebDataServiceConsumer* consumer) { - return ScheduleDBTaskWithResult(FROM_HERE, + return wdbs_->ScheduleDBTaskWithResult(FROM_HERE, Bind(&WebDataService::GetCreditCardsImpl, this), consumer); } void WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetween( const Time& delete_begin, const Time& delete_end) { - ScheduleDBTask(FROM_HERE, Bind( + wdbs_->ScheduleDBTask(FROM_HERE, Bind( &WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl, this, delete_begin, delete_end)); } WebDataService::~WebDataService() { - if (is_running_ && db_) { - NOTREACHED() << "WebDataService dtor called without Shutdown"; - } -} - -bool WebDataService::InitWithPath(const base::FilePath& path) { - path_ = path; - is_running_ = true; - - ScheduleTask(FROM_HERE, - Bind(&WebDataService::InitializeDatabaseIfNecessary, this)); - ScheduleTask(FROM_HERE, - Bind(&WebDataService::InitializeSyncableServices, this)); - return true; + wdbs_.reset(); + DCHECK(!autocomplete_syncable_service_); + DCHECK(!autofill_profile_syncable_service_); } //////////////////////////////////////////////////////////////////////////////// // -// The following methods are executed in Chrome_WebDataThread. +// The following methods are executed on the DB thread. // //////////////////////////////////////////////////////////////////////////////// -void WebDataService::DBInitFailed(sql::InitStatus init_status) { +void WebDataService::DBInitFailed(sql::InitStatus sql_status) { ShowProfileErrorDialog( - (init_status == sql::INIT_FAILURE) ? + (sql_status == sql::INIT_FAILURE) ? IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR); } -void WebDataService::InitializeDatabaseIfNecessary() { - if (db_ || failed_init_ || path_.empty()) - return; +void WebDataService::NotifyDatabaseLoadedOnUIThread() { + db_loaded_ = true; + // Notify that the database has been initialized. + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_WEB_DATABASE_LOADED, + content::Source<WebDataService>(this), + content::NotificationService::NoDetails()); +} - // In the rare case where the db fails to initialize a dialog may get shown - // that blocks the caller, yet allows other messages through. For this reason - // we only set db_ to the created database if creation is successful. That - // way other methods won't do anything as db_ is still NULL. - WebDatabase* db = new WebDatabase(); - sql::InitStatus init_status = db->Init(path_, app_locale_); - if (init_status != sql::INIT_OK) { - LOG(ERROR) << "Cannot initialize the web database: " << init_status; - failed_init_ = true; - delete db; - if (main_loop_) { - main_loop_->PostTask( - FROM_HERE, - base::Bind(&WebDataService::DBInitFailed, this, init_status)); - } - return; +void WebDataService::DatabaseInitOnDB(sql::InitStatus status) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + if (status == sql::INIT_OK) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&WebDataService::NotifyDatabaseLoadedOnUIThread, this)); + } else { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&WebDataService::DBInitFailed, this, status)); } - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&WebDataService::NotifyDatabaseLoadedOnUIThread, this)); - - db_ = db; - db_->BeginTransaction(); } void WebDataService::InitializeSyncableServices() { @@ -394,24 +378,6 @@ void WebDataService::InitializeSyncableServices() { autofill_profile_syncable_service_ = new AutofillProfileSyncableService(this); } -void WebDataService::NotifyDatabaseLoadedOnUIThread() { - // Notify that the database has been initialized. - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_WEB_DATABASE_LOADED, - content::Source<WebDataService>(this), - content::NotificationService::NoDetails()); -} - -void WebDataService::ShutdownDatabase() { - should_commit_ = false; - - if (db_) { - db_->CommitTransaction(); - delete db_; - db_ = NULL; - } -} - void WebDataService::ShutdownSyncableServices() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); @@ -421,132 +387,61 @@ void WebDataService::ShutdownSyncableServices() { autofill_profile_syncable_service_ = NULL; } -void WebDataService::Commit() { - if (should_commit_) { - should_commit_ = false; - - if (db_) { - db_->CommitTransaction(); - db_->BeginTransaction(); - } - } -} - -void WebDataService::ScheduleTask(const tracked_objects::Location& from_here, - const base::Closure& task) { - if (is_running_) - BrowserThread::PostTask(BrowserThread::DB, from_here, task); - else - NOTREACHED() << "Task scheduled after Shutdown()"; -} - -void WebDataService::ScheduleDBTask( - const tracked_objects::Location& from_here, - const base::Closure& task) { - scoped_ptr<WebDataRequest> request( - new WebDataRequest(NULL, request_manager_.get())); - if (is_running_) { - BrowserThread::PostTask(BrowserThread::DB, from_here, - base::Bind(&WebDataService::DBTaskWrapper, this, task, - base::Passed(&request))); - } else { - NOTREACHED() << "Task scheduled after Shutdown()"; - } -} - -WebDataService::Handle WebDataService::ScheduleDBTaskWithResult( - const tracked_objects::Location& from_here, - const ResultTask& task, - WebDataServiceConsumer* consumer) { - DCHECK(consumer); - scoped_ptr<WebDataRequest> request( - new WebDataRequest(consumer, request_manager_.get())); - WebDataService::Handle handle = request->GetHandle(); - if (is_running_) { - BrowserThread::PostTask(BrowserThread::DB, from_here, - base::Bind(&WebDataService::DBResultTaskWrapper, this, task, - base::Passed(&request))); - } else { - NOTREACHED() << "Task scheduled after Shutdown()"; - } - return handle; -} - -void WebDataService::DBTaskWrapper(const base::Closure& task, - scoped_ptr<WebDataRequest> request) { - InitializeDatabaseIfNecessary(); - if (db_ && !request->IsCancelled()) { - task.Run(); - } - request_manager_->RequestCompleted(request.Pass()); -} - -void WebDataService::DBResultTaskWrapper(const ResultTask& task, - scoped_ptr<WebDataRequest> request) { - InitializeDatabaseIfNecessary(); - if (db_ && !request->IsCancelled()) { - request->SetResult(task.Run()); - } - request_manager_->RequestCompleted(request.Pass()); -} - -void WebDataService::ScheduleCommit() { - if (should_commit_ == false) { - should_commit_ = true; - ScheduleTask(FROM_HERE, Bind(&WebDataService::Commit, this)); - } -} - //////////////////////////////////////////////////////////////////////////////// // // Keywords implementation. // //////////////////////////////////////////////////////////////////////////////// -void WebDataService::AddKeywordImpl(const TemplateURLData& data) { - db_->GetKeywordTable()->AddKeyword(data); - ScheduleCommit(); +WebDatabase::State WebDataService::AddKeywordImpl( + const TemplateURLData& data, WebDatabase* db) { + db->GetKeywordTable()->AddKeyword(data); + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::RemoveKeywordImpl(TemplateURLID id) { +WebDatabase::State WebDataService::RemoveKeywordImpl( + TemplateURLID id, WebDatabase* db) { DCHECK(id); - db_->GetKeywordTable()->RemoveKeyword(id); - ScheduleCommit(); + db->GetKeywordTable()->RemoveKeyword(id); + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::UpdateKeywordImpl(const TemplateURLData& data) { - if (!db_->GetKeywordTable()->UpdateKeyword(data)) { +WebDatabase::State WebDataService::UpdateKeywordImpl( + const TemplateURLData& data, WebDatabase* db) { + if (!db->GetKeywordTable()->UpdateKeyword(data)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } -scoped_ptr<WDTypedResult> WebDataService::GetKeywordsImpl() { +scoped_ptr<WDTypedResult> WebDataService::GetKeywordsImpl(WebDatabase* db) { WDKeywordsResult result; - db_->GetKeywordTable()->GetKeywords(&result.keywords); + db->GetKeywordTable()->GetKeywords(&result.keywords); result.default_search_provider_id = - db_->GetKeywordTable()->GetDefaultSearchProviderID(); + db->GetKeywordTable()->GetDefaultSearchProviderID(); result.builtin_keyword_version = - db_->GetKeywordTable()->GetBuiltinKeywordVersion(); + db->GetKeywordTable()->GetBuiltinKeywordVersion(); return scoped_ptr<WDTypedResult>( new WDResult<WDKeywordsResult>(KEYWORDS_RESULT, result)); } -void WebDataService::SetDefaultSearchProviderImpl(TemplateURLID id) { - if (!db_->GetKeywordTable()->SetDefaultSearchProviderID(id)) { +WebDatabase::State WebDataService::SetDefaultSearchProviderImpl( + TemplateURLID id, WebDatabase* db) { + if (!db->GetKeywordTable()->SetDefaultSearchProviderID(id)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::SetBuiltinKeywordVersionImpl(int version) { - if (!db_->GetKeywordTable()->SetBuiltinKeywordVersion(version)) { +WebDatabase::State WebDataService::SetBuiltinKeywordVersionImpl( + int version, WebDatabase* db) { + if (!db->GetKeywordTable()->SetBuiltinKeywordVersion(version)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } //////////////////////////////////////////////////////////////////////////////// @@ -555,29 +450,30 @@ void WebDataService::SetBuiltinKeywordVersionImpl(int version) { // //////////////////////////////////////////////////////////////////////////////// -void WebDataService::SetWebAppImageImpl( - const GURL& app_url, const SkBitmap& image) { - db_->GetWebAppsTable()->SetWebAppImage(app_url, image); - ScheduleCommit(); +WebDatabase::State WebDataService::SetWebAppImageImpl( + const GURL& app_url, const SkBitmap& image, WebDatabase* db) { + db->GetWebAppsTable()->SetWebAppImage(app_url, image); + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::SetWebAppHasAllImagesImpl( - const GURL& app_url, bool has_all_images) { - db_->GetWebAppsTable()->SetWebAppHasAllImages(app_url, has_all_images); - ScheduleCommit(); +WebDatabase::State WebDataService::SetWebAppHasAllImagesImpl( + const GURL& app_url, bool has_all_images, WebDatabase* db) { + db->GetWebAppsTable()-> + SetWebAppHasAllImages(app_url, has_all_images); + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::RemoveWebAppImpl(const GURL& app_url) { - db_->GetWebAppsTable()->RemoveWebApp(app_url); - ScheduleCommit(); +WebDatabase::State WebDataService::RemoveWebAppImpl( + const GURL& app_url, WebDatabase* db) { + db->GetWebAppsTable()->RemoveWebApp(app_url); + return WebDatabase::COMMIT_NEEDED; } scoped_ptr<WDTypedResult> WebDataService::GetWebAppImagesImpl( - const GURL& app_url) { + const GURL& app_url, WebDatabase* db) { WDAppImagesResult result; - result.has_all_images = - db_->GetWebAppsTable()->GetWebAppHasAllImages(app_url); - db_->GetWebAppsTable()->GetWebAppImages(app_url, &result.images); + result.has_all_images = db->GetWebAppsTable()->GetWebAppHasAllImages(app_url); + db->GetWebAppsTable()->GetWebAppImages(app_url, &result.images); return scoped_ptr<WDTypedResult>( new WDResult<WDAppImagesResult>(WEB_APP_IMAGES, result)); } @@ -588,22 +484,24 @@ scoped_ptr<WDTypedResult> WebDataService::GetWebAppImagesImpl( // //////////////////////////////////////////////////////////////////////////////// -void WebDataService::RemoveAllTokensImpl() { - if (db_->GetTokenServiceTable()->RemoveAllTokens()) { - ScheduleCommit(); +WebDatabase::State WebDataService::RemoveAllTokensImpl(WebDatabase* db) { + if (db->GetTokenServiceTable()->RemoveAllTokens()) { + return WebDatabase::COMMIT_NEEDED; } + return WebDatabase::COMMIT_NOT_NEEDED; } -void WebDataService::SetTokenForServiceImpl(const std::string& service, - const std::string& token) { - if (db_->GetTokenServiceTable()->SetTokenForService(service, token)) { - ScheduleCommit(); +WebDatabase::State WebDataService::SetTokenForServiceImpl( + const std::string& service, const std::string& token, WebDatabase* db) { + if (db->GetTokenServiceTable()->SetTokenForService(service, token)) { + return WebDatabase::COMMIT_NEEDED; } + return WebDatabase::COMMIT_NOT_NEEDED; } -scoped_ptr<WDTypedResult> WebDataService::GetAllTokensImpl() { +scoped_ptr<WDTypedResult> WebDataService::GetAllTokensImpl(WebDatabase* db) { std::map<std::string, std::string> map; - db_->GetTokenServiceTable()->GetAllTokens(&map); + db->GetTokenServiceTable()->GetAllTokens(&map); return scoped_ptr<WDTypedResult>( new WDResult<std::map<std::string, std::string> >(TOKEN_RESULT, map)); } @@ -614,14 +512,13 @@ scoped_ptr<WDTypedResult> WebDataService::GetAllTokensImpl() { // //////////////////////////////////////////////////////////////////////////////// -void WebDataService::AddFormElementsImpl( - const std::vector<FormFieldData>& fields) { +WebDatabase::State WebDataService::AddFormElementsImpl( + const std::vector<FormFieldData>& fields, WebDatabase* db) { AutofillChangeList changes; - if (!db_->GetAutofillTable()->AddFormFieldValues(fields, &changes)) { + if (!db->GetAutofillTable()->AddFormFieldValues(fields, &changes)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); // Post the notifications including the list of affected keys. // This is sent here so that work resulting from this notification will be @@ -630,21 +527,25 @@ void WebDataService::AddFormElementsImpl( chrome::NOTIFICATION_AUTOFILL_ENTRIES_CHANGED, content::Source<WebDataService>(this), content::Details<AutofillChangeList>(&changes)); + + return WebDatabase::COMMIT_NEEDED; } scoped_ptr<WDTypedResult> WebDataService::GetFormValuesForElementNameImpl( - const string16& name, const string16& prefix, int limit) { + const string16& name, const string16& prefix, int limit, WebDatabase* db) { std::vector<string16> values; - db_->GetAutofillTable()->GetFormValuesForElementName( + db->GetAutofillTable()->GetFormValuesForElementName( name, prefix, &values, limit); return scoped_ptr<WDTypedResult>( new WDResult<std::vector<string16> >(AUTOFILL_VALUE_RESULT, values)); } -void WebDataService::RemoveFormElementsAddedBetweenImpl( - const base::Time& delete_begin, const base::Time& delete_end) { +WebDatabase::State WebDataService::RemoveFormElementsAddedBetweenImpl( + const base::Time& delete_begin, const base::Time& delete_end, + WebDatabase* db) { AutofillChangeList changes; - if (db_->GetAutofillTable()->RemoveFormElementsAddedBetween( + + if (db->GetAutofillTable()->RemoveFormElementsAddedBetween( delete_begin, delete_end, &changes)) { if (!changes.empty()) { // Post the notifications including the list of affected keys. @@ -655,14 +556,16 @@ void WebDataService::RemoveFormElementsAddedBetweenImpl( content::Source<WebDataService>(this), content::Details<AutofillChangeList>(&changes)); } - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } + return WebDatabase::COMMIT_NOT_NEEDED; } -void WebDataService::RemoveExpiredFormElementsImpl() { +WebDatabase::State WebDataService::RemoveExpiredFormElementsImpl( + WebDatabase* db) { AutofillChangeList changes; - if (db_->GetAutofillTable()->RemoveExpiredFormElements(&changes)) { + if (db->GetAutofillTable()->RemoveExpiredFormElements(&changes)) { if (!changes.empty()) { // Post the notifications including the list of affected keys. // This is sent here so that work resulting from this notification @@ -672,33 +575,36 @@ void WebDataService::RemoveExpiredFormElementsImpl() { content::Source<WebDataService>(this), content::Details<AutofillChangeList>(&changes)); } - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } + return WebDatabase::COMMIT_NOT_NEEDED; } -void WebDataService::RemoveFormValueForElementNameImpl( - const string16& name, const string16& value) { +WebDatabase::State WebDataService::RemoveFormValueForElementNameImpl( + const string16& name, const string16& value, WebDatabase* db) { - if (db_->GetAutofillTable()->RemoveFormElement(name, value)) { + if (db->GetAutofillTable()->RemoveFormElement(name, value)) { AutofillChangeList changes; changes.push_back(AutofillChange(AutofillChange::REMOVE, AutofillKey(name, value))); - ScheduleCommit(); // Post the notifications including the list of affected keys. content::NotificationService::current()->Notify( chrome::NOTIFICATION_AUTOFILL_ENTRIES_CHANGED, content::Source<WebDataService>(this), content::Details<AutofillChangeList>(&changes)); + + return WebDatabase::COMMIT_NEEDED; } + return WebDatabase::COMMIT_NOT_NEEDED; } -void WebDataService::AddAutofillProfileImpl(const AutofillProfile& profile) { - if (!db_->GetAutofillTable()->AddAutofillProfile(profile)) { +WebDatabase::State WebDataService::AddAutofillProfileImpl( + const AutofillProfile& profile, WebDatabase* db) { + if (!db->GetAutofillTable()->AddAutofillProfile(profile)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); // Send GUID-based notification. AutofillProfileChange change(AutofillProfileChange::ADD, @@ -707,24 +613,26 @@ void WebDataService::AddAutofillProfileImpl(const AutofillProfile& profile) { chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED, content::Source<WebDataService>(this), content::Details<AutofillProfileChange>(&change)); + + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::UpdateAutofillProfileImpl(const AutofillProfile& profile) { +WebDatabase::State WebDataService::UpdateAutofillProfileImpl( + const AutofillProfile& profile, WebDatabase* db) { // Only perform the update if the profile exists. It is currently // valid to try to update a missing profile. We simply drop the write and // the caller will detect this on the next refresh. AutofillProfile* original_profile = NULL; - if (!db_->GetAutofillTable()->GetAutofillProfile(profile.guid(), - &original_profile)) { - return; + if (!db->GetAutofillTable()->GetAutofillProfile(profile.guid(), + &original_profile)) { + return WebDatabase::COMMIT_NOT_NEEDED; } scoped_ptr<AutofillProfile> scoped_profile(original_profile); - if (!db_->GetAutofillTable()->UpdateAutofillProfileMulti(profile)) { + if (!db->GetAutofillTable()->UpdateAutofillProfileMulti(profile)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NEEDED; } - ScheduleCommit(); // Send GUID-based notification. AutofillProfileChange change(AutofillProfileChange::UPDATE, @@ -733,21 +641,23 @@ void WebDataService::UpdateAutofillProfileImpl(const AutofillProfile& profile) { chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED, content::Source<WebDataService>(this), content::Details<AutofillProfileChange>(&change)); + + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::RemoveAutofillProfileImpl(const std::string& guid) { +WebDatabase::State WebDataService::RemoveAutofillProfileImpl( + const std::string& guid, WebDatabase* db) { AutofillProfile* profile = NULL; - if (!db_->GetAutofillTable()->GetAutofillProfile(guid, &profile)) { + if (!db->GetAutofillTable()->GetAutofillProfile(guid, &profile)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } scoped_ptr<AutofillProfile> scoped_profile(profile); - if (!db_->GetAutofillTable()->RemoveAutofillProfile(guid)) { + if (!db->GetAutofillTable()->RemoveAutofillProfile(guid)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); // Send GUID-based notification. AutofillProfileChange change(AutofillProfileChange::REMOVE, guid, NULL); @@ -755,11 +665,14 @@ void WebDataService::RemoveAutofillProfileImpl(const std::string& guid) { chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED, content::Source<WebDataService>(this), content::Details<AutofillProfileChange>(&change)); + + return WebDatabase::COMMIT_NEEDED; } -scoped_ptr<WDTypedResult> WebDataService::GetAutofillProfilesImpl() { +scoped_ptr<WDTypedResult> WebDataService::GetAutofillProfilesImpl( + WebDatabase* db) { std::vector<AutofillProfile*> profiles; - db_->GetAutofillTable()->GetAutofillProfiles(&profiles); + db->GetAutofillTable()->GetAutofillProfiles(&profiles); return scoped_ptr<WDTypedResult>( new WDDestroyableResult<std::vector<AutofillProfile*> >( AUTOFILL_PROFILES_RESULT, @@ -768,42 +681,46 @@ scoped_ptr<WDTypedResult> WebDataService::GetAutofillProfilesImpl() { base::Unretained(this)))); } -void WebDataService::AddCreditCardImpl(const CreditCard& credit_card) { - if (!db_->GetAutofillTable()->AddCreditCard(credit_card)) { +WebDatabase::State WebDataService::AddCreditCardImpl( + const CreditCard& credit_card, WebDatabase* db) { + if (!db->GetAutofillTable()->AddCreditCard(credit_card)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); + + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::UpdateCreditCardImpl(const CreditCard& credit_card) { +WebDatabase::State WebDataService::UpdateCreditCardImpl( + const CreditCard& credit_card, WebDatabase* db) { // It is currently valid to try to update a missing profile. We simply drop // the write and the caller will detect this on the next refresh. CreditCard* original_credit_card = NULL; - if (!db_->GetAutofillTable()->GetCreditCard(credit_card.guid(), - &original_credit_card)) { - return; + if (!db->GetAutofillTable()->GetCreditCard(credit_card.guid(), + &original_credit_card)) { + return WebDatabase::COMMIT_NOT_NEEDED; } scoped_ptr<CreditCard> scoped_credit_card(original_credit_card); - if (!db_->GetAutofillTable()->UpdateCreditCard(credit_card)) { + if (!db->GetAutofillTable()->UpdateCreditCard(credit_card)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } -void WebDataService::RemoveCreditCardImpl(const std::string& guid) { - if (!db_->GetAutofillTable()->RemoveCreditCard(guid)) { +WebDatabase::State WebDataService::RemoveCreditCardImpl( + const std::string& guid, WebDatabase* db) { + if (!db->GetAutofillTable()->RemoveCreditCard(guid)) { NOTREACHED(); - return; + return WebDatabase::COMMIT_NOT_NEEDED; } - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } -scoped_ptr<WDTypedResult> WebDataService::GetCreditCardsImpl() { +scoped_ptr<WDTypedResult> WebDataService::GetCreditCardsImpl(WebDatabase* db) { std::vector<CreditCard*> credit_cards; - db_->GetAutofillTable()->GetCreditCards(&credit_cards); + db->GetAutofillTable()->GetCreditCards(&credit_cards); return scoped_ptr<WDTypedResult>( new WDDestroyableResult<std::vector<CreditCard*> >( AUTOFILL_CREDITCARDS_RESULT, @@ -812,11 +729,13 @@ scoped_ptr<WDTypedResult> WebDataService::GetCreditCardsImpl() { base::Unretained(this)))); } -void WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl( - const base::Time& delete_begin, const base::Time& delete_end) { +WebDatabase::State +WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl( + const base::Time& delete_begin, const base::Time& delete_end, + WebDatabase* db) { std::vector<std::string> profile_guids; std::vector<std::string> credit_card_guids; - if (db_->GetAutofillTable()-> + if (db->GetAutofillTable()-> RemoveAutofillProfilesAndCreditCardsModifiedBetween( delete_begin, delete_end, @@ -833,8 +752,9 @@ void WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl( } // Note: It is the caller's responsibility to post notifications for any // changes, e.g. by calling the Refresh() method of PersonalDataManager. - ScheduleCommit(); + return WebDatabase::COMMIT_NEEDED; } + return WebDatabase::COMMIT_NOT_NEEDED; } AutofillProfileSyncableService* diff --git a/chrome/browser/webdata/web_data_service.h b/chrome/browser/webdata/web_data_service.h index 3dfe4a2..f66d9dc 100644 --- a/chrome/browser/webdata/web_data_service.h +++ b/chrome/browser/webdata/web_data_service.h @@ -28,6 +28,7 @@ #include "chrome/browser/search_engines/template_url_id.h" #include "chrome/browser/webdata/keyword_table.h" #include "chrome/browser/webdata/web_data_request_manager.h" +#include "chrome/browser/webdata/web_database.h" #include "content/public/browser/browser_thread.h" #include "sql/init_status.h" @@ -42,7 +43,7 @@ struct IE7PasswordInfo; class MessageLoop; class Profile; class SkBitmap; -class WebDatabase; +class WebDatabaseService; namespace base { class Thread; @@ -129,18 +130,23 @@ class WebDataService // call. virtual void ShutdownOnUIThread() OVERRIDE; - // Initializes the web data service. Returns false on failure - // Takes the path of the profile directory as its argument. - bool Init(const base::FilePath& profile_path); - - // Returns false if Shutdown() has been called. - bool IsRunning() const; + // Initializes the web data service. + void Init(const base::FilePath& path); // Unloads the database without actually shutting down the service. This can // be used to temporarily reduce the browser process' memory footprint. void UnloadDatabase(); + // Unloads the database permanently and shuts down service. + void ShutdownDatabase(); + + // Returns true if the database load has completetd successfully, and + // ShutdownOnUIThread has not yet been called. virtual bool IsDatabaseLoaded(); + + // Returns a pointer to the DB (used by SyncableServices). May return NULL if + // the database is not loaded or otherwise unavailable. Must be called on + // DBThread. virtual WebDatabase* GetDatabase(); ////////////////////////////////////////////////////////////////////////////// @@ -320,11 +326,6 @@ class WebDataService virtual AutocompleteSyncableService* GetAutocompleteSyncableService() const; - // Testing -#ifdef UNIT_TEST - void set_failed_init(bool value) { failed_init_ = value; } -#endif - protected: friend class TemplateURLServiceTest; friend class TemplateURLServiceTestingProfile; @@ -333,9 +334,6 @@ class WebDataService virtual ~WebDataService(); - // This is invoked by the unit test; path is the path of the Web Data file. - bool InitWithPath(const base::FilePath& path); - ////////////////////////////////////////////////////////////////////////////// // // The following methods are only invoked in the web data service thread. @@ -346,59 +344,31 @@ class WebDataService content::BrowserThread::UI>; friend class base::DeleteHelper<WebDataService>; - // Invoked on the main thread if initializing the db fails. - void DBInitFailed(sql::InitStatus init_status); - - // Initialize the database, if it hasn't already been initialized. - void InitializeDatabaseIfNecessary(); - // Initialize any syncable services. void InitializeSyncableServices(); - // The notification method. - void NotifyDatabaseLoadedOnUIThread(); - - // Commit any pending transaction and deletes the database. - void ShutdownDatabase(); - // Deletes the syncable services. void ShutdownSyncableServices(); - // Commit the current transaction and creates a new one. - void Commit(); - - // Schedule a task on our worker thread. - void ScheduleTask(const tracked_objects::Location& from_here, - const base::Closure& task); - - void ScheduleDBTask(const tracked_objects::Location& from_here, - const base::Closure& task); - - WebDataService::Handle ScheduleDBTaskWithResult( - const tracked_objects::Location& from_here, - const ResultTask& task, - WebDataServiceConsumer* consumer); - - void DBTaskWrapper(const base::Closure& task, - scoped_ptr<WebDataRequest> request); - - void DBResultTaskWrapper(const ResultTask& task, - scoped_ptr<WebDataRequest> request); - - // Schedule a commit if one is not already pending. - void ScheduleCommit(); + void DBInitFailed(sql::InitStatus sql_status); + void NotifyDatabaseLoadedOnUIThread(); + void DatabaseInitOnDB(sql::InitStatus status); ////////////////////////////////////////////////////////////////////////////// // // Keywords. // ////////////////////////////////////////////////////////////////////////////// - void AddKeywordImpl(const TemplateURLData& data); - void RemoveKeywordImpl(TemplateURLID id); - void UpdateKeywordImpl(const TemplateURLData& data); - scoped_ptr<WDTypedResult> GetKeywordsImpl(); - void SetDefaultSearchProviderImpl(TemplateURLID r); - void SetBuiltinKeywordVersionImpl(int version); + WebDatabase::State AddKeywordImpl( + const TemplateURLData& data, WebDatabase* db); + WebDatabase::State RemoveKeywordImpl( + TemplateURLID id, WebDatabase* db); + WebDatabase::State UpdateKeywordImpl( + const TemplateURLData& data, WebDatabase* db); + scoped_ptr<WDTypedResult> GetKeywordsImpl(WebDatabase* db); + WebDatabase::State SetDefaultSearchProviderImpl( + TemplateURLID r, WebDatabase* db); + WebDatabase::State SetBuiltinKeywordVersionImpl(int version, WebDatabase* db); ////////////////////////////////////////////////////////////////////////////// // @@ -406,10 +376,13 @@ class WebDataService // ////////////////////////////////////////////////////////////////////////////// - void SetWebAppImageImpl(const GURL& app_url, const SkBitmap& image); - void SetWebAppHasAllImagesImpl(const GURL& app_url, bool has_all_images); - void RemoveWebAppImpl(const GURL& app_url); - scoped_ptr<WDTypedResult> GetWebAppImagesImpl(const GURL& app_url); + WebDatabase::State SetWebAppImageImpl(const GURL& app_url, + const SkBitmap& image, WebDatabase* db); + WebDatabase::State SetWebAppHasAllImagesImpl(const GURL& app_url, + bool has_all_images, WebDatabase* db); + WebDatabase::State RemoveWebAppImpl(const GURL& app_url, WebDatabase* db); + scoped_ptr<WDTypedResult> GetWebAppImagesImpl( + const GURL& app_url, WebDatabase* db); #if defined(ENABLE_WEB_INTENTS) ////////////////////////////////////////////////////////////////////////////// @@ -417,18 +390,20 @@ class WebDataService // Web Intents. // ////////////////////////////////////////////////////////////////////////////// - void AddWebIntentServiceImpl( + WebDatabase::State AddWebIntentServiceImpl( const webkit_glue::WebIntentServiceData& service); - void RemoveWebIntentServiceImpl( + WebDatabase::State RemoveWebIntentServiceImpl( const webkit_glue::WebIntentServiceData& service); scoped_ptr<WDTypedResult> GetWebIntentServicesImpl(const string16& action); scoped_ptr<WDTypedResult> GetWebIntentServicesForURLImpl( const string16& service_url); scoped_ptr<WDTypedResult> GetAllWebIntentServicesImpl(); - void AddDefaultWebIntentServiceImpl(const DefaultWebIntentService& service); - void RemoveDefaultWebIntentServiceImpl( + WebDatabase::State AddDefaultWebIntentServiceImpl( + const DefaultWebIntentService& service); + WebDatabase::State RemoveDefaultWebIntentServiceImpl( const DefaultWebIntentService& service); - void RemoveWebIntentServiceDefaultsImpl(const GURL& service_url); + WebDatabase::State RemoveWebIntentServiceDefaultsImpl( + const GURL& service_url); scoped_ptr<WDTypedResult> GetDefaultWebIntentServicesForActionImpl( const string16& action); scoped_ptr<WDTypedResult> GetAllDefaultWebIntentServicesImpl(); @@ -440,10 +415,10 @@ class WebDataService // ////////////////////////////////////////////////////////////////////////////// - void RemoveAllTokensImpl(); - void SetTokenForServiceImpl(const std::string& service, - const std::string& token); - scoped_ptr<WDTypedResult> GetAllTokensImpl(); + WebDatabase::State RemoveAllTokensImpl(WebDatabase* db); + WebDatabase::State SetTokenForServiceImpl(const std::string& service, + const std::string& token, WebDatabase* db); + scoped_ptr<WDTypedResult> GetAllTokensImpl(WebDatabase* db); #if defined(OS_WIN) ////////////////////////////////////////////////////////////////////////////// @@ -451,9 +426,12 @@ class WebDataService // Password manager. // ////////////////////////////////////////////////////////////////////////////// - void AddIE7LoginImpl(const IE7PasswordInfo& info); - void RemoveIE7LoginImpl(const IE7PasswordInfo& info); - scoped_ptr<WDTypedResult> GetIE7LoginImpl(const IE7PasswordInfo& info); + WebDatabase::State AddIE7LoginImpl( + const IE7PasswordInfo& info, WebDatabase* db); + WebDatabase::State RemoveIE7LoginImpl( + const IE7PasswordInfo& info, WebDatabase* db); + scoped_ptr<WDTypedResult> GetIE7LoginImpl( + const IE7PasswordInfo& info, WebDatabase* db); #endif // defined(OS_WIN) ////////////////////////////////////////////////////////////////////////////// @@ -461,47 +439,44 @@ class WebDataService // Autofill. // ////////////////////////////////////////////////////////////////////////////// - void AddFormElementsImpl(const std::vector<FormFieldData>& fields); + WebDatabase::State AddFormElementsImpl( + const std::vector<FormFieldData>& fields, WebDatabase* db); scoped_ptr<WDTypedResult> GetFormValuesForElementNameImpl( - const string16& name, const string16& prefix, int limit); - void RemoveFormElementsAddedBetweenImpl( - const base::Time& delete_begin, const base::Time& delete_end); - void RemoveExpiredFormElementsImpl(); - void RemoveFormValueForElementNameImpl(const string16& name, - const string16& value); - void AddAutofillProfileImpl(const AutofillProfile& profile); - void UpdateAutofillProfileImpl(const AutofillProfile& profile); - void RemoveAutofillProfileImpl(const std::string& guid); - scoped_ptr<WDTypedResult> GetAutofillProfilesImpl(); - void AddCreditCardImpl(const CreditCard& credit_card); - void UpdateCreditCardImpl(const CreditCard& credit_card); - void RemoveCreditCardImpl(const std::string& guid); - scoped_ptr<WDTypedResult> GetCreditCardsImpl(); - void RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl( - const base::Time& delete_begin, const base::Time& delete_end); + const string16& name, const string16& prefix, int limit, WebDatabase* db); + WebDatabase::State RemoveFormElementsAddedBetweenImpl( + const base::Time& delete_begin, const base::Time& delete_end, + WebDatabase* db); + WebDatabase::State RemoveExpiredFormElementsImpl(WebDatabase* db); + WebDatabase::State RemoveFormValueForElementNameImpl( + const string16& name, const string16& value, WebDatabase* db); + WebDatabase::State AddAutofillProfileImpl( + const AutofillProfile& profile, WebDatabase* db); + WebDatabase::State UpdateAutofillProfileImpl( + const AutofillProfile& profile, WebDatabase* db); + WebDatabase::State RemoveAutofillProfileImpl( + const std::string& guid, WebDatabase* db); + scoped_ptr<WDTypedResult> GetAutofillProfilesImpl(WebDatabase* db); + WebDatabase::State AddCreditCardImpl( + const CreditCard& credit_card, WebDatabase* db); + WebDatabase::State UpdateCreditCardImpl( + const CreditCard& credit_card, WebDatabase* db); + WebDatabase::State RemoveCreditCardImpl( + const std::string& guid, WebDatabase* db); + scoped_ptr<WDTypedResult> GetCreditCardsImpl(WebDatabase* db); + WebDatabase::State RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl( + const base::Time& delete_begin, const base::Time& delete_end, + WebDatabase* db); // Callbacks to ensure that sensitive info is destroyed if request is // cancelled. void DestroyAutofillProfileResult(const WDTypedResult* result); void DestroyAutofillCreditCardResult(const WDTypedResult* result); - // True once initialization has started. - bool is_running_; + // Our database service. + scoped_ptr<WebDatabaseService> wdbs_; - // The path with which to initialize the database. - base::FilePath path_; - - // Our database. We own the |db_|, but don't use a |scoped_ptr| because the - // |db_| lifetime must be managed on the database thread. - WebDatabase* db_; - - // Keeps track of all pending requests made to the db. - scoped_refptr<WebDataRequestManager> request_manager_; - - // The application locale. The locale is needed for some database migrations, - // and must be read on the UI thread. It's cached here so that we can pass it - // to the migration code on the DB thread. - const std::string app_locale_; + // True if we've received a notification that the WebDatabase has loaded. + bool db_loaded_; // Syncable services for the database data. We own the services, but don't // use |scoped_ptr|s because the lifetimes must be managed on the database @@ -511,16 +486,6 @@ class WebDataService AutocompleteSyncableService* autocomplete_syncable_service_; AutofillProfileSyncableService* autofill_profile_syncable_service_; - // Whether the database failed to initialize. We use this to avoid - // continually trying to reinit. - bool failed_init_; - - // Whether we should commit the database. - bool should_commit_; - - // MessageLoop the WebDataService is created on. - MessageLoop* main_loop_; - DISALLOW_COPY_AND_ASSIGN(WebDataService); }; diff --git a/chrome/browser/webdata/web_data_service_factory.cc b/chrome/browser/webdata/web_data_service_factory.cc index a73a76c..4d54619 100644 --- a/chrome/browser/webdata/web_data_service_factory.cc +++ b/chrome/browser/webdata/web_data_service_factory.cc @@ -85,8 +85,7 @@ WebDataServiceFactory::BuildServiceInstanceFor(Profile* profile) const { path = path.Append(chrome::kWebDataFilename); scoped_refptr<WebDataService> wds(new WebDataService()); - if (!wds->Init(profile->GetPath())) - NOTREACHED(); + wds->Init(path); return wds.get(); } diff --git a/chrome/browser/webdata/web_data_service_unittest.cc b/chrome/browser/webdata/web_data_service_unittest.cc index 08b7b7b..c61882f 100644 --- a/chrome/browser/webdata/web_data_service_unittest.cc +++ b/chrome/browser/webdata/web_data_service_unittest.cc @@ -77,7 +77,8 @@ class WebDataServiceTest : public testing::Test { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); wds_ = new WebDataService(); - wds_->Init(temp_dir_.path()); + base::FilePath path = temp_dir_.path().AppendASCII("TestWebDB"); + wds_->Init(path); } virtual void TearDown() { @@ -85,9 +86,9 @@ class WebDataServiceTest : public testing::Test { wds_ = NULL; WaitForDatabaseThread(); - db_thread_.Stop(); MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); MessageLoop::current()->Run(); + db_thread_.Stop(); } void WaitForDatabaseThread() { diff --git a/chrome/browser/webdata/web_data_service_win.cc b/chrome/browser/webdata/web_data_service_win.cc index 00a34e6..e0e1624 100644 --- a/chrome/browser/webdata/web_data_service_win.cc +++ b/chrome/browser/webdata/web_data_service_win.cc @@ -2,46 +2,50 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/webdata/logins_table.h" #include "chrome/browser/webdata/web_data_service.h" #include "base/bind.h" #include "chrome/browser/password_manager/ie7_password.h" -#include "chrome/browser/webdata/web_database.h" +#include "chrome/browser/webdata/logins_table.h" +#include "chrome/browser/webdata/web_database_service.h" using base::Bind; void WebDataService::AddIE7Login(const IE7PasswordInfo& info) { - ScheduleDBTask(FROM_HERE, - Bind(&WebDataService::AddIE7LoginImpl, this, info)); + wdbs_->ScheduleDBTask( + FROM_HERE, Bind(&WebDataService::AddIE7LoginImpl, this, info)); } void WebDataService::RemoveIE7Login(const IE7PasswordInfo& info) { - ScheduleDBTask(FROM_HERE, - Bind(&WebDataService::RemoveIE7LoginImpl, this, info)); + wdbs_->ScheduleDBTask( + FROM_HERE, Bind(&WebDataService::RemoveIE7LoginImpl, this, info)); } WebDataService::Handle WebDataService::GetIE7Login( const IE7PasswordInfo& info, WebDataServiceConsumer* consumer) { - return ScheduleDBTaskWithResult(FROM_HERE, - Bind(&WebDataService::GetIE7LoginImpl, this, info), consumer); + return wdbs_->ScheduleDBTaskWithResult( + FROM_HERE, Bind(&WebDataService::GetIE7LoginImpl, this, info), consumer); } -void WebDataService::AddIE7LoginImpl(const IE7PasswordInfo& info) { - if (db_->GetLoginsTable()->AddIE7Login(info)) - ScheduleCommit(); +WebDatabase::State WebDataService::AddIE7LoginImpl( + const IE7PasswordInfo& info, WebDatabase* db) { + if (db->GetLoginsTable()->AddIE7Login(info)) + return WebDatabase::COMMIT_NEEDED; + return WebDatabase::COMMIT_NOT_NEEDED; } -void WebDataService::RemoveIE7LoginImpl(const IE7PasswordInfo& info) { - if (db_->GetLoginsTable()->RemoveIE7Login(info)) - ScheduleCommit(); +WebDatabase::State WebDataService::RemoveIE7LoginImpl( + const IE7PasswordInfo& info, WebDatabase* db) { + if (db->GetLoginsTable()->RemoveIE7Login(info)) + return WebDatabase::COMMIT_NEEDED; + return WebDatabase::COMMIT_NOT_NEEDED; } scoped_ptr<WDTypedResult> WebDataService::GetIE7LoginImpl( - const IE7PasswordInfo& info) { + const IE7PasswordInfo& info, WebDatabase* db) { IE7PasswordInfo result; - db_->GetLoginsTable()->GetIE7Login(info, &result); + db->GetLoginsTable()->GetIE7Login(info, &result); return scoped_ptr<WDTypedResult>( new WDResult<IE7PasswordInfo>(PASSWORD_IE7_RESULT, result)); } diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h index 744741b..6a24985 100644 --- a/chrome/browser/webdata/web_database.h +++ b/chrome/browser/webdata/web_database.h @@ -30,6 +30,10 @@ class NotificationService; // This class manages a SQLite database that stores various web page meta data. class WebDatabase { public: + enum State { + COMMIT_NOT_NEEDED, + COMMIT_NEEDED + }; // Exposed publicly so the keyword table can access it. static const int kCurrentVersionNumber; diff --git a/chrome/browser/webdata/web_database_service.cc b/chrome/browser/webdata/web_database_service.cc new file mode 100644 index 0000000..543d9ba --- /dev/null +++ b/chrome/browser/webdata/web_database_service.cc @@ -0,0 +1,262 @@ +// Copyright 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/webdata/web_database_service.h" + +#include "base/bind.h" +#include "base/location.h" +#include "chrome/browser/api/webdata/web_data_results.h" +#include "chrome/browser/api/webdata/web_data_service_consumer.h" +#include "chrome/browser/webdata/web_data_request_manager.h" +#include "chrome/browser/webdata/web_data_service.h" +// TODO(caitkp): Remove this autofill dependency. +#include "components/autofill/browser/autofill_country.h" + +using base::Bind; +using base::FilePath; +using content::BrowserThread; + + +//////////////////////////////////////////////////////////////////////////////// +// +// WebDataServiceBackend implementation. +// +//////////////////////////////////////////////////////////////////////////////// + +// Refcounted to allow asynchronous destruction on the DB thread. +class WebDataServiceBackend + : public base::RefCountedThreadSafe<WebDataServiceBackend, + BrowserThread::DeleteOnDBThread> { + public: + explicit WebDataServiceBackend(const FilePath& path); + + // Initializes the database and notifies caller via callback when complete. + // Callback is called synchronously. + void InitDatabaseWithCallback( + const WebDatabaseService::InitCallback& callback); + + // Opens the database file from the profile path if an init has not yet been + // attempted. Separated from the constructor to ease construction/destruction + // of this object on one thread but database access on the DB thread. Returns + // the status of the database. + sql::InitStatus LoadDatabaseIfNecessary(); + + // Shuts down database. |should_reinit| tells us whether or not it should be + // possible to re-initialize the DB after the shutdown. + void ShutdownDatabase(bool should_reinit); + + // Task wrappers to run database tasks. + void DBWriteTaskWrapper( + const WebDatabaseService::WriteTask& task, + scoped_ptr<WebDataRequest> request); + void DBReadTaskWrapper( + const WebDatabaseService::ReadTask& task, + scoped_ptr<WebDataRequest> request); + + const scoped_refptr<WebDataRequestManager>& request_manager() { + return request_manager_; + } + + WebDatabase* database() { return db_.get(); } + + private: + friend struct BrowserThread::DeleteOnThread<BrowserThread::DB>; + friend class base::DeleteHelper<WebDataServiceBackend>; + + virtual ~WebDataServiceBackend(); + + // Commit the current transaction. + void Commit(); + + // Path to database file. + FilePath db_path_; + + scoped_ptr<WebDatabase> db_; + + // Keeps track of all pending requests made to the db. + scoped_refptr<WebDataRequestManager> request_manager_; + + // State of database initialization. Used to prevent the executing of tasks + // before the db is ready. + sql::InitStatus init_status_; + + // True if an attempt has been made to load the database (even if the attempt + // fails), used to avoid continually trying to reinit if the db init fails. + bool init_complete_; + + // The application locale. The locale is needed for some database migrations, + // and must be read on the UI thread. It's cached here so that we can pass it + // to the migration code on the DB thread. + const std::string app_locale_; + + DISALLOW_COPY_AND_ASSIGN(WebDataServiceBackend); +}; + +WebDataServiceBackend::WebDataServiceBackend(const FilePath& path) + : db_path_(path), + request_manager_(new WebDataRequestManager()), + init_status_(sql::INIT_FAILURE), + init_complete_(false), + app_locale_(AutofillCountry::ApplicationLocale()) { +} + +void WebDataServiceBackend::InitDatabaseWithCallback( + const WebDatabaseService::InitCallback& callback) { + if (!callback.is_null()) { + callback.Run(LoadDatabaseIfNecessary()); + } +} + +sql::InitStatus WebDataServiceBackend::LoadDatabaseIfNecessary() { + if (init_complete_ || db_path_.empty()) { + return init_status_; + } + init_complete_ = true; + db_.reset(new WebDatabase()); + init_status_ = db_->Init(db_path_, app_locale_); + if (init_status_ != sql::INIT_OK) { + LOG(ERROR) << "Cannot initialize the web database: " << init_status_; + db_.reset(NULL); + return init_status_; + } + + db_->BeginTransaction(); + return init_status_; +} + +void WebDataServiceBackend::ShutdownDatabase(bool should_reinit) { + if (db_ && init_status_ == sql::INIT_OK) + db_->CommitTransaction(); + db_.reset(NULL); + init_complete_ = !should_reinit; // Setting init_complete_ to true will ensure + // that the init sequence is not re-run. + + init_status_ = sql::INIT_FAILURE; +} + +void WebDataServiceBackend::DBWriteTaskWrapper( + const WebDatabaseService::WriteTask& task, + scoped_ptr<WebDataRequest> request) { + LoadDatabaseIfNecessary(); + if (db_ && init_status_ == sql::INIT_OK && !request->IsCancelled()) { + WebDatabase::State state = task.Run(db_.get()); + if (state == WebDatabase::COMMIT_NEEDED) + Commit(); + } + request_manager_->RequestCompleted(request.Pass()); +} + +void WebDataServiceBackend::DBReadTaskWrapper( + const WebDatabaseService::ReadTask& task, + scoped_ptr<WebDataRequest> request) { + LoadDatabaseIfNecessary(); + if (db_ && init_status_ == sql::INIT_OK && !request->IsCancelled()) { + request->SetResult(task.Run(db_.get()).Pass()); + } + request_manager_->RequestCompleted(request.Pass()); +} + +WebDataServiceBackend::~WebDataServiceBackend() { + ShutdownDatabase(false); +} + +void WebDataServiceBackend::Commit() { + if (db_ && init_status_ == sql::INIT_OK) { + db_->CommitTransaction(); + db_->BeginTransaction(); + } else { + NOTREACHED() << "Commit scheduled after Shutdown()"; + } +} + +//////////////////////////////////////////////////////////////////////////////// +WebDatabaseService::WebDatabaseService(const base::FilePath& path) + : path_(path) { + // WebDatabaseService should be instantiated on UI thread. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // WebDatabaseService requires DB thread if instantiated. + DCHECK(BrowserThread::IsWellKnownThread(BrowserThread::DB)); +} + +WebDatabaseService::~WebDatabaseService() { +} + +void WebDatabaseService::LoadDatabase(const InitCallback& callback) { + if (!wds_backend_) + wds_backend_ = new WebDataServiceBackend(path_); + + BrowserThread::PostTask( + BrowserThread::DB, + FROM_HERE, + Bind(&WebDataServiceBackend::InitDatabaseWithCallback, + wds_backend_, callback)); +} + +void WebDatabaseService::UnloadDatabase() { + if (!wds_backend_) + return; + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, + Bind(&WebDataServiceBackend::ShutdownDatabase, + wds_backend_, true)); +} + +void WebDatabaseService::ShutdownDatabase() { + if (!wds_backend_) + return; + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, + Bind(&WebDataServiceBackend::ShutdownDatabase, + wds_backend_, false)); +} + +WebDatabase* WebDatabaseService::GetDatabaseOnDB() const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + if (!wds_backend_) + return NULL; + return wds_backend_->database(); +} + +void WebDatabaseService::ScheduleDBTask( + const tracked_objects::Location& from_here, + const WriteTask& task) { + if (!wds_backend_) { + NOTREACHED() << "Task scheduled after Shutdown()"; + return; + } + + scoped_ptr<WebDataRequest> request( + new WebDataRequest(NULL, wds_backend_->request_manager())); + + BrowserThread::PostTask(BrowserThread::DB, from_here, + Bind(&WebDataServiceBackend::DBWriteTaskWrapper, wds_backend_, + task, base::Passed(&request))); +} + +WebDataService::Handle WebDatabaseService::ScheduleDBTaskWithResult( + const tracked_objects::Location& from_here, + const ReadTask& task, + WebDataServiceConsumer* consumer) { + DCHECK(consumer); + WebDataService::Handle handle = 0; + + if (!wds_backend_) { + NOTREACHED() << "Task scheduled after Shutdown()"; + return handle; + } + + scoped_ptr<WebDataRequest> request( + new WebDataRequest(consumer, wds_backend_->request_manager())); + handle = request->GetHandle(); + + BrowserThread::PostTask(BrowserThread::DB, from_here, + Bind(&WebDataServiceBackend::DBReadTaskWrapper, wds_backend_, + task, base::Passed(&request))); + + return handle; +} + +void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) { + if (!wds_backend_) + return; + wds_backend_->request_manager()->CancelRequest(h); +} diff --git a/chrome/browser/webdata/web_database_service.h b/chrome/browser/webdata/web_database_service.h new file mode 100644 index 0000000..75a4f4d --- /dev/null +++ b/chrome/browser/webdata/web_database_service.h @@ -0,0 +1,94 @@ +// Copyright 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. + +// Chromium settings and storage represent user-selected preferences and +// information and MUST not be extracted, overwritten or modified except +// through Chromium defined APIs. + +#ifndef CHROME_BROWSER_WEBDATA_WEB_DATABASE_SERVICE_H_ +#define CHROME_BROWSER_WEBDATA_WEB_DATABASE_SERVICE_H_ + +#include "base/basictypes.h" +#include "base/callback_forward.h" +#include "base/compiler_specific.h" +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/api/webdata/web_data_service_base.h" +#include "chrome/browser/webdata/web_database.h" + +class WebDataServiceBackend; +class WebDataRequestManager; + +namespace content { +class BrowserContext; +} + +namespace tracked_objects { +class Location; +} + +class WDTypedResult; +class WebDataServiceConsumer; + + +//////////////////////////////////////////////////////////////////////////////// +// +// WebDatabaseService defines the interface to a generic data repository +// responsible for controlling access to the web database (metadata associated +// with web pages). +// +//////////////////////////////////////////////////////////////////////////////// + +class WebDatabaseService { + public: + typedef base::Callback<scoped_ptr<WDTypedResult>(WebDatabase*)> ReadTask; + typedef base::Callback<WebDatabase::State(WebDatabase*)> WriteTask; + typedef base::Callback<void(sql::InitStatus)> InitCallback; + + // Takes the path to the WebDatabase file. + explicit WebDatabaseService(const base::FilePath& path); + + virtual ~WebDatabaseService(); + + // Initializes the web database service. Takes a callback which will return + // the status of the DB after the init. + virtual void LoadDatabase(const InitCallback& callback); + + // Unloads the database without actually shutting down the service. This can + // be used to temporarily reduce the browser process' memory footprint. + virtual void UnloadDatabase(); + + // Unloads database and will not reload. + virtual void ShutdownDatabase(); + + // Gets a ptr to the WebDatabase (owned by WebDatabaseService). + // TODO(caitkp): remove this method once SyncServices no longer depend on it. + virtual WebDatabase* GetDatabaseOnDB() const; + + // Schedule an update/write task on the DB thread. + virtual void ScheduleDBTask( + const tracked_objects::Location& from_here, + const WriteTask& task); + + // Schedule a read task on the DB thread. + virtual WebDataServiceBase::Handle ScheduleDBTaskWithResult( + const tracked_objects::Location& from_here, + const ReadTask& task, + WebDataServiceConsumer* consumer); + + // Cancel an existing request for a task on the DB thread. + // TODO(caitkp): Think about moving the definition of the Handle type to + // somewhere else. + virtual void CancelRequest(WebDataServiceBase::Handle h); + + private: + base::FilePath path_; + + // The primary owner is |WebDatabaseService| but is refcounted because + // PostTask on DB thread may outlive us. + scoped_refptr<WebDataServiceBackend> wds_backend_; +}; + +#endif // CHROME_BROWSER_WEBDATA_WEB_DATABASE_SERVICE_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index bb283fb..68e160f 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2108,6 +2108,8 @@ 'browser/webdata/token_service_table.h', 'browser/webdata/web_apps_table.cc', 'browser/webdata/web_apps_table.h', + 'browser/webdata/web_database_service.cc', + 'browser/webdata/web_database_service.h', 'browser/webdata/web_data_request_manager.cc', 'browser/webdata/web_data_request_manager.h', 'browser/webdata/web_data_service.cc', diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index a10f39a..5142f3e 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc @@ -422,9 +422,11 @@ void TestingProfile::CreateBookmarkModel(bool delete_file) { static scoped_refptr<RefcountedProfileKeyedService> BuildWebDataService( Profile* profile) { + base::FilePath path = profile->GetPath(); + path = path.Append(chrome::kWebDataFilename); WebDataService* web_data_service = new WebDataService(); if (web_data_service) - web_data_service->Init(profile->GetPath()); + web_data_service->Init(path); return web_data_service; } |