blob: cd188cb4f6ed22be35d73750a5b0077cd92ba43b [file] [log] [blame]
// 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 "components/webdata/common/web_database_service.h"
#include <stddef.h>
#include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/webdata/common/web_data_request_manager.h"
#include "components/webdata/common/web_data_results.h"
#include "components/webdata/common/web_data_service_consumer.h"
#include "components/webdata/common/web_database_backend.h"
using base::Bind;
using base::FilePath;
// Receives messages from the backend on the DB sequence, posts them to
// WebDatabaseService on the UI sequence.
class WebDatabaseService::BackendDelegate
: public WebDatabaseBackend::Delegate {
public:
BackendDelegate(const base::WeakPtr<WebDatabaseService>& web_database_service)
: web_database_service_(web_database_service),
callback_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
void DBLoaded(sql::InitStatus status,
const std::string& diagnostics) override {
callback_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&WebDatabaseService::OnDatabaseLoadDone,
web_database_service_, status, diagnostics));
}
private:
const base::WeakPtr<WebDatabaseService> web_database_service_;
scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
};
WebDatabaseService::WebDatabaseService(
const base::FilePath& path,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> db_task_runner)
: base::RefCountedDeleteOnSequence<WebDatabaseService>(ui_task_runner),
path_(path),
db_loaded_(false),
db_task_runner_(db_task_runner),
weak_ptr_factory_(this) {
DCHECK(ui_task_runner->RunsTasksInCurrentSequence());
DCHECK(db_task_runner_);
}
WebDatabaseService::~WebDatabaseService() {
}
void WebDatabaseService::AddTable(std::unique_ptr<WebDatabaseTable> table) {
if (!web_db_backend_) {
web_db_backend_ = new WebDatabaseBackend(
path_, new BackendDelegate(weak_ptr_factory_.GetWeakPtr()),
db_task_runner_);
}
web_db_backend_->AddTable(std::move(table));
}
void WebDatabaseService::LoadDatabase() {
DCHECK(web_db_backend_);
db_task_runner_->PostTask(
FROM_HERE, BindOnce(&WebDatabaseBackend::InitDatabase, web_db_backend_));
}
void WebDatabaseService::ShutdownDatabase() {
db_loaded_ = false;
loaded_callbacks_.clear();
error_callbacks_.clear();
weak_ptr_factory_.InvalidateWeakPtrs();
if (!web_db_backend_)
return;
db_task_runner_->PostTask(
FROM_HERE,
BindOnce(&WebDatabaseBackend::ShutdownDatabase, web_db_backend_));
}
WebDatabase* WebDatabaseService::GetDatabaseOnDB() const {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
return web_db_backend_ ? web_db_backend_->database() : nullptr;
}
scoped_refptr<WebDatabaseBackend> WebDatabaseService::GetBackend() const {
return web_db_backend_;
}
void WebDatabaseService::ScheduleDBTask(const base::Location& from_here,
const WriteTask& task) {
DCHECK(web_db_backend_);
std::unique_ptr<WebDataRequest> request =
web_db_backend_->request_manager()->NewRequest(nullptr);
db_task_runner_->PostTask(
from_here, BindOnce(&WebDatabaseBackend::DBWriteTaskWrapper,
web_db_backend_, task, std::move(request)));
}
WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult(
const base::Location& from_here,
const ReadTask& task,
WebDataServiceConsumer* consumer) {
DCHECK(consumer);
DCHECK(web_db_backend_);
std::unique_ptr<WebDataRequest> request =
web_db_backend_->request_manager()->NewRequest(consumer);
WebDataServiceBase::Handle handle = request->GetHandle();
db_task_runner_->PostTask(
from_here, BindOnce(&WebDatabaseBackend::DBReadTaskWrapper,
web_db_backend_, task, std::move(request)));
return handle;
}
void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) {
if (!web_db_backend_)
return;
web_db_backend_->request_manager()->CancelRequest(h);
}
void WebDatabaseService::RegisterDBLoadedCallback(
const DBLoadedCallback& callback) {
loaded_callbacks_.push_back(callback);
}
void WebDatabaseService::RegisterDBErrorCallback(
const DBLoadErrorCallback& callback) {
error_callbacks_.push_back(callback);
}
void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status,
const std::string& diagnostics) {
// The INIT_OK_WITH_DATA_LOSS status is an initialization success but with
// suspected data loss, so we also run the error callbacks.
if (status != sql::INIT_OK) {
// Notify that the database load failed.
while (!error_callbacks_.empty()) {
// The profile error callback is a message box that runs in a nested run
// loop. While it's being displayed, other OnDatabaseLoadDone() will run
// (posted from WebDatabaseBackend::Delegate::DBLoaded()). We need to make
// sure that after the callback running the message box returns, it checks
// |error_callbacks_| before it accesses it.
DBLoadErrorCallback error_callback = error_callbacks_.back();
error_callbacks_.pop_back();
if (!error_callback.is_null())
error_callback.Run(status, diagnostics);
}
}
if (status == sql::INIT_OK || status == sql::INIT_OK_WITH_DATA_LOSS) {
db_loaded_ = true;
while (!loaded_callbacks_.empty()) {
DBLoadedCallback loaded_callback = loaded_callbacks_.back();
loaded_callbacks_.pop_back();
if (!loaded_callback.is_null())
loaded_callback.Run();
}
}
}