| 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..543d9ba05fa40f25b06bd159b801af713a11a04e
|
| --- /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);
|
| +}
|
|
|