Chromium Code Reviews| Index: chrome/browser/webdata/web_database_service.cc |
| diff --git a/chrome/browser/webdata/web_database_service.cc b/chrome/browser/webdata/web_database_service.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6cbb3820727088e779c33210917ff1b4f80531b8 |
| --- /dev/null |
| +++ b/chrome/browser/webdata/web_database_service.cc |
| @@ -0,0 +1,268 @@ |
| +// 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; |
| + |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// |
| +// WebDatabaseServiceInternal implementation. |
| +// |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +// Refcounted to allow asynchronous destruction on the DB thread. |
| +class WebDatabaseServiceInternal |
| + : public base::RefCountedThreadSafe<WebDatabaseServiceInternal, |
| + BrowserThread::DeleteOnDBThread> { |
| + public: |
| + explicit WebDatabaseServiceInternal(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<WebDatabaseServiceInternal>; |
| + |
| + virtual ~WebDatabaseServiceInternal(); |
| + |
| + // 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(WebDatabaseServiceInternal); |
| +}; |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// |
| +// WebDatabaseServiceInternal implementation. |
| +// |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +WebDatabaseServiceInternal::WebDatabaseServiceInternal(const FilePath& path) |
| + : db_path_(path), |
| + request_manager_(new WebDataRequestManager()), |
| + init_status_(sql::INIT_FAILURE), |
| + init_complete_(false), |
| + app_locale_(AutofillCountry::ApplicationLocale()) { |
| +} |
| + |
| +void WebDatabaseServiceInternal::InitDatabaseWithCallback( |
| + const WebDatabaseService::InitCallback& callback) { |
| + if (!callback.is_null()) { |
| + callback.Run(LoadDatabaseIfNecessary()); |
| + } |
| +} |
| + |
| +sql::InitStatus WebDatabaseServiceInternal::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 WebDatabaseServiceInternal::ShutdownDatabase(bool should_reinit) { |
| + if (db_.get() && init_status_ == sql::INIT_OK) |
|
dhollowa
2013/03/15 23:50:31
if(db_ &&...
Cait (Slow)
2013/03/16 21:34:22
Done.
|
| + 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 WebDatabaseServiceInternal::DBWriteTaskWrapper( |
| + const WebDatabaseService::WriteTask& task, |
| + scoped_ptr<WebDataRequest> request) { |
| + LoadDatabaseIfNecessary(); |
| + if (db_.get() && init_status_ == sql::INIT_OK && !request->IsCancelled()) { |
|
dhollowa
2013/03/15 23:50:31
if(db_ &&...
Cait (Slow)
2013/03/16 21:34:22
Done.
|
| + WebDatabase::State state = task.Run(db_.get()); |
| + if (state == WebDatabase::COMMIT_NEEDED) |
| + Commit(); |
| + } |
| + request_manager_->RequestCompleted(request.Pass()); |
| +} |
| + |
| +void WebDatabaseServiceInternal::DBReadTaskWrapper( |
| + const WebDatabaseService::ReadTask& task, |
| + scoped_ptr<WebDataRequest> request) { |
| + LoadDatabaseIfNecessary(); |
| + if (db_.get() && init_status_ == sql::INIT_OK && !request->IsCancelled()) { |
|
dhollowa
2013/03/15 23:50:31
if(db_ &&...
Cait (Slow)
2013/03/16 21:34:22
Done.
|
| + request->SetResult(task.Run(db_.get()).Pass()); |
| + } |
| + request_manager_->RequestCompleted(request.Pass()); |
| +} |
| + |
| +WebDatabaseServiceInternal::~WebDatabaseServiceInternal() { |
| + ShutdownDatabase(false); |
| +} |
| + |
| +void WebDatabaseServiceInternal::Commit() { |
| + if (db_.get() && init_status_ == sql::INIT_OK) { |
|
dhollowa
2013/03/15 23:50:31
if(db_ &&...
Cait (Slow)
2013/03/16 21:34:22
Done.
|
| + db_->CommitTransaction(); |
|
dhollowa
2013/03/15 23:50:31
nit: Indent
Cait (Slow)
2013/03/16 21:34:22
Done.
|
| + 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 (!wdbs_internal_) |
| + wdbs_internal_ = new WebDatabaseServiceInternal(path_); |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::DB, |
| + FROM_HERE, |
| + Bind(&WebDatabaseServiceInternal::InitDatabaseWithCallback, |
| + wdbs_internal_, callback)); |
| +} |
| + |
| +void WebDatabaseService::UnloadDatabase() { |
| + if (!wdbs_internal_) |
| + return; |
| + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
| + Bind(&WebDatabaseServiceInternal::ShutdownDatabase, |
| + wdbs_internal_, true)); |
| +} |
| + |
| +void WebDatabaseService::ShutdownDatabase() { |
| + if (!wdbs_internal_) |
| + return; |
| + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
| + Bind(&WebDatabaseServiceInternal::ShutdownDatabase, |
| + wdbs_internal_, false)); |
| +} |
| + |
| +WebDatabase* WebDatabaseService::GetDatabaseOnDB() const { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| + if (!wdbs_internal_) |
| + return NULL; |
| + return wdbs_internal_->database(); |
| +} |
| + |
| +void WebDatabaseService::ScheduleDBTask( |
| + const tracked_objects::Location& from_here, |
|
dhollowa
2013/03/15 23:50:31
nit: Indent
Cait (Slow)
2013/03/16 21:34:22
Done.
|
| + const WriteTask& task) { |
| + if (!wdbs_internal_) { |
| + NOTREACHED() << "Task scheduled after Shutdown()"; |
| + return; |
| + } |
| + |
| + scoped_ptr<WebDataRequest> request( |
| + new WebDataRequest(NULL, wdbs_internal_->request_manager())); |
| + |
| + BrowserThread::PostTask(BrowserThread::DB, from_here, |
| + Bind(&WebDatabaseServiceInternal::DBWriteTaskWrapper, wdbs_internal_, |
| + task, base::Passed(&request))); |
| +} |
| + |
| +WebDataService::Handle WebDatabaseService::ScheduleDBTaskWithResult( |
| + const tracked_objects::Location& from_here, |
|
dhollowa
2013/03/15 23:50:31
nit: Indent
Cait (Slow)
2013/03/16 21:34:22
Done.
|
| + const ReadTask& task, |
| + WebDataServiceConsumer* consumer) { |
| + DCHECK(consumer); |
| + WebDataService::Handle handle = 0; |
| + |
| + if (!wdbs_internal_) { |
| + NOTREACHED() << "Task scheduled after Shutdown()"; |
| + return handle; |
| + } |
| + |
| + scoped_ptr<WebDataRequest> request( |
| + new WebDataRequest(consumer, wdbs_internal_->request_manager())); |
| + handle = request->GetHandle(); |
| + |
| + BrowserThread::PostTask(BrowserThread::DB, from_here, |
| + Bind(&WebDatabaseServiceInternal::DBReadTaskWrapper, wdbs_internal_, |
| + task, base::Passed(&request))); |
| + |
| + return handle; |
| +} |
| + |
| +void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) { |
| + if (!wdbs_internal_) |
| + return; |
| + wdbs_internal_->request_manager()->CancelRequest(h); |
| +} |