2011-04-05 18:17:33 +02:00
|
|
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
2010-10-22 02:13:43 +02:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
2010-10-03 23:04:50 +02:00
|
|
|
|
|
|
|
#include "browser_database_system.h"
|
|
|
|
|
|
|
|
#include "base/auto_reset.h"
|
|
|
|
#include "base/file_util.h"
|
|
|
|
#include "base/message_loop.h"
|
2011-04-05 18:17:33 +02:00
|
|
|
#include "base/message_loop_proxy.h"
|
|
|
|
#include "base/synchronization/waitable_event.h"
|
2011-01-07 22:34:20 +01:00
|
|
|
#include "base/threading/platform_thread.h"
|
2010-10-03 23:04:50 +02:00
|
|
|
#include "base/utf_string_conversions.h"
|
|
|
|
#include "third_party/sqlite/sqlite3.h"
|
2011-02-15 19:07:24 +01:00
|
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h"
|
|
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
|
2010-10-03 23:04:50 +02:00
|
|
|
#include "webkit/database/database_util.h"
|
|
|
|
#include "webkit/database/vfs_backend.h"
|
|
|
|
|
|
|
|
using webkit_database::DatabaseTracker;
|
|
|
|
using webkit_database::DatabaseUtil;
|
2011-07-03 02:03:30 +02:00
|
|
|
using webkit_database::OriginInfo;
|
2010-10-03 23:04:50 +02:00
|
|
|
using webkit_database::VfsBackend;
|
|
|
|
|
|
|
|
BrowserDatabaseSystem* BrowserDatabaseSystem::instance_ = NULL;
|
|
|
|
|
|
|
|
BrowserDatabaseSystem* BrowserDatabaseSystem::GetInstance() {
|
|
|
|
DCHECK(instance_);
|
|
|
|
return instance_;
|
|
|
|
}
|
|
|
|
|
|
|
|
BrowserDatabaseSystem::BrowserDatabaseSystem()
|
2011-05-16 18:56:12 +02:00
|
|
|
: db_thread_("BrowserDBThread"),
|
2011-07-03 02:03:30 +02:00
|
|
|
quota_per_origin_(5 * 1024 * 1024),
|
2011-04-05 18:17:33 +02:00
|
|
|
open_connections_(new webkit_database::DatabaseConnectionsWrapper) {
|
2010-10-03 23:04:50 +02:00
|
|
|
DCHECK(!instance_);
|
|
|
|
instance_ = this;
|
2011-04-05 18:17:33 +02:00
|
|
|
CHECK(temp_dir_.CreateUniqueTempDir());
|
2011-05-16 18:56:12 +02:00
|
|
|
db_tracker_ = new DatabaseTracker(temp_dir_.path(), false, NULL, NULL, NULL);
|
2011-04-05 18:17:33 +02:00
|
|
|
db_tracker_->AddObserver(this);
|
|
|
|
db_thread_.Start();
|
|
|
|
db_thread_proxy_ = db_thread_.message_loop_proxy();
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BrowserDatabaseSystem::~BrowserDatabaseSystem() {
|
2011-04-05 18:17:33 +02:00
|
|
|
base::WaitableEvent done_event(false, false);
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::ThreadCleanup,
|
|
|
|
&done_event));
|
|
|
|
done_event.Wait();
|
2010-10-03 23:04:50 +02:00
|
|
|
instance_ = NULL;
|
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::databaseOpened(const WebKit::WebDatabase& database) {
|
|
|
|
string16 origin_identifier = database.securityOrigin().databaseIdentifier();
|
|
|
|
string16 database_name = database.name();
|
|
|
|
open_connections_->AddOpenConnection(origin_identifier, database_name);
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::DatabaseOpened,
|
|
|
|
origin_identifier,
|
|
|
|
database_name, database.displayName(),
|
|
|
|
database.estimatedSize()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserDatabaseSystem::databaseModified(
|
|
|
|
const WebKit::WebDatabase& database) {
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::DatabaseModified,
|
|
|
|
database.securityOrigin().databaseIdentifier(),
|
|
|
|
database.name()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserDatabaseSystem::databaseClosed(const WebKit::WebDatabase& database) {
|
|
|
|
string16 origin_identifier = database.securityOrigin().databaseIdentifier();
|
|
|
|
string16 database_name = database.name();
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::DatabaseClosed,
|
|
|
|
origin_identifier, database_name));
|
|
|
|
}
|
|
|
|
|
2010-10-03 23:04:50 +02:00
|
|
|
base::PlatformFile BrowserDatabaseSystem::OpenFile(
|
2010-10-22 02:13:43 +02:00
|
|
|
const string16& vfs_file_name, int desired_flags) {
|
2011-04-05 18:17:33 +02:00
|
|
|
base::PlatformFile result = base::kInvalidPlatformFileValue;
|
|
|
|
base::WaitableEvent done_event(false, false);
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::VfsOpenFile,
|
|
|
|
vfs_file_name, desired_flags,
|
|
|
|
&result, &done_event));
|
|
|
|
done_event.Wait();
|
|
|
|
return result;
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int BrowserDatabaseSystem::DeleteFile(
|
|
|
|
const string16& vfs_file_name, bool sync_dir) {
|
2011-04-05 18:17:33 +02:00
|
|
|
int result = SQLITE_OK;
|
|
|
|
base::WaitableEvent done_event(false, false);
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::VfsDeleteFile,
|
|
|
|
vfs_file_name, sync_dir,
|
|
|
|
&result, &done_event));
|
|
|
|
done_event.Wait();
|
|
|
|
return result;
|
|
|
|
}
|
2010-10-03 23:04:50 +02:00
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
uint32 BrowserDatabaseSystem::GetFileAttributes(const string16& vfs_file_name) {
|
|
|
|
uint32 result = 0;
|
|
|
|
base::WaitableEvent done_event(false, false);
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::VfsGetFileAttributes,
|
|
|
|
vfs_file_name, &result, &done_event));
|
|
|
|
done_event.Wait();
|
|
|
|
return result;
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
int64 BrowserDatabaseSystem::GetFileSize(const string16& vfs_file_name) {
|
|
|
|
int64 result = 0;
|
|
|
|
base::WaitableEvent done_event(false, false);
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::VfsGetFileSize,
|
|
|
|
vfs_file_name, &result, &done_event));
|
|
|
|
done_event.Wait();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-07-03 02:03:30 +02:00
|
|
|
int64 BrowserDatabaseSystem::GetSpaceAvailable(
|
|
|
|
const string16& origin_identifier) {
|
|
|
|
int64 result = 0;
|
|
|
|
base::WaitableEvent done_event(false, false);
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::VfsGetSpaceAvailable,
|
|
|
|
origin_identifier, &result, &done_event));
|
|
|
|
done_event.Wait();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::ClearAllDatabases() {
|
|
|
|
open_connections_->WaitForAllDatabasesToClose();
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::ResetTracker));
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::SetDatabaseQuota(int64 quota) {
|
|
|
|
if (!db_thread_proxy_->BelongsToCurrentThread()) {
|
|
|
|
db_thread_proxy_->PostTask(FROM_HERE,
|
|
|
|
NewRunnableMethod(this, &BrowserDatabaseSystem::SetDatabaseQuota,
|
|
|
|
quota));
|
|
|
|
return;
|
|
|
|
}
|
2011-07-03 02:03:30 +02:00
|
|
|
quota_per_origin_ = quota;
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserDatabaseSystem::DatabaseOpened(const string16& origin_identifier,
|
|
|
|
const string16& database_name,
|
|
|
|
const string16& description,
|
|
|
|
int64 estimated_size) {
|
2011-04-05 18:17:33 +02:00
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
2010-10-03 23:04:50 +02:00
|
|
|
int64 database_size = 0;
|
2011-04-05 18:17:33 +02:00
|
|
|
db_tracker_->DatabaseOpened(
|
|
|
|
origin_identifier, database_name, description,
|
2011-07-03 02:03:30 +02:00
|
|
|
estimated_size, &database_size);
|
2010-10-03 23:04:50 +02:00
|
|
|
OnDatabaseSizeChanged(origin_identifier, database_name,
|
2011-07-03 02:03:30 +02:00
|
|
|
database_size);
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserDatabaseSystem::DatabaseModified(const string16& origin_identifier,
|
|
|
|
const string16& database_name) {
|
2011-04-05 18:17:33 +02:00
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
2010-10-03 23:04:50 +02:00
|
|
|
db_tracker_->DatabaseModified(origin_identifier, database_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserDatabaseSystem::DatabaseClosed(const string16& origin_identifier,
|
|
|
|
const string16& database_name) {
|
2011-04-05 18:17:33 +02:00
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
2010-10-03 23:04:50 +02:00
|
|
|
db_tracker_->DatabaseClosed(origin_identifier, database_name);
|
2011-04-05 18:17:33 +02:00
|
|
|
open_connections_->RemoveOpenConnection(origin_identifier, database_name);
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserDatabaseSystem::OnDatabaseSizeChanged(
|
|
|
|
const string16& origin_identifier,
|
|
|
|
const string16& database_name,
|
2011-07-03 02:03:30 +02:00
|
|
|
int64 database_size) {
|
2011-04-05 18:17:33 +02:00
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
// We intentionally call into webkit on our background db_thread_
|
|
|
|
// to better emulate what happens in chrome where this method is
|
|
|
|
// invoked on the background ipc thread.
|
|
|
|
WebKit::WebDatabase::updateDatabaseSize(
|
2011-07-03 02:03:30 +02:00
|
|
|
origin_identifier, database_name, database_size);
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserDatabaseSystem::OnDatabaseScheduledForDeletion(
|
|
|
|
const string16& origin_identifier,
|
|
|
|
const string16& database_name) {
|
2011-04-05 18:17:33 +02:00
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
// We intentionally call into webkit on our background db_thread_
|
|
|
|
// to better emulate what happens in chrome where this method is
|
|
|
|
// invoked on the background ipc thread.
|
2010-10-03 23:04:50 +02:00
|
|
|
WebKit::WebDatabase::closeDatabaseImmediately(
|
|
|
|
origin_identifier, database_name);
|
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::VfsOpenFile(
|
|
|
|
const string16& vfs_file_name, int desired_flags,
|
|
|
|
base::PlatformFile* file_handle, base::WaitableEvent* done_event ) {
|
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
FilePath file_name = GetFullFilePathForVfsFile(vfs_file_name);
|
|
|
|
if (file_name.empty()) {
|
|
|
|
VfsBackend::OpenTempFileInDirectory(
|
|
|
|
db_tracker_->DatabaseDirectory(), desired_flags, file_handle);
|
|
|
|
} else {
|
|
|
|
VfsBackend::OpenFile(file_name, desired_flags, file_handle);
|
|
|
|
}
|
|
|
|
done_event->Signal();
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::VfsDeleteFile(
|
|
|
|
const string16& vfs_file_name, bool sync_dir,
|
|
|
|
int* result, base::WaitableEvent* done_event) {
|
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
// We try to delete the file multiple times, because that's what the default
|
|
|
|
// VFS does (apparently deleting a file can sometimes fail on Windows).
|
|
|
|
// We sleep for 10ms between retries for the same reason.
|
|
|
|
const int kNumDeleteRetries = 3;
|
|
|
|
int num_retries = 0;
|
|
|
|
*result = SQLITE_OK;
|
|
|
|
FilePath file_name = GetFullFilePathForVfsFile(vfs_file_name);
|
|
|
|
do {
|
|
|
|
*result = VfsBackend::DeleteFile(file_name, sync_dir);
|
|
|
|
} while ((++num_retries < kNumDeleteRetries) &&
|
|
|
|
(*result == SQLITE_IOERR_DELETE) &&
|
|
|
|
(base::PlatformThread::Sleep(10), 1));
|
2010-10-03 23:04:50 +02:00
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
done_event->Signal();
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::VfsGetFileAttributes(
|
|
|
|
const string16& vfs_file_name,
|
|
|
|
uint32* result, base::WaitableEvent* done_event) {
|
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
*result = VfsBackend::GetFileAttributes(
|
|
|
|
GetFullFilePathForVfsFile(vfs_file_name));
|
|
|
|
done_event->Signal();
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::VfsGetFileSize(
|
|
|
|
const string16& vfs_file_name,
|
|
|
|
int64* result, base::WaitableEvent* done_event) {
|
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
*result = VfsBackend::GetFileSize(GetFullFilePathForVfsFile(vfs_file_name));
|
|
|
|
done_event->Signal();
|
2010-10-03 23:04:50 +02:00
|
|
|
}
|
|
|
|
|
2011-07-03 02:03:30 +02:00
|
|
|
void BrowserDatabaseSystem::VfsGetSpaceAvailable(
|
|
|
|
const string16& origin_identifier,
|
|
|
|
int64* result, base::WaitableEvent* done_event) {
|
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
// This method isn't actually part of the "vfs" interface, but it is
|
|
|
|
// used from within webcore and handled here in the same fashion.
|
|
|
|
OriginInfo info;
|
|
|
|
if (db_tracker_->GetOriginInfo(origin_identifier, &info)) {
|
|
|
|
int64 space_available = quota_per_origin_ - info.TotalSize();
|
|
|
|
*result = space_available < 0 ? 0 : space_available;
|
|
|
|
} else {
|
|
|
|
NOTREACHED();
|
|
|
|
*result = 0;
|
|
|
|
}
|
|
|
|
done_event->Signal();
|
|
|
|
}
|
|
|
|
|
2010-10-03 23:04:50 +02:00
|
|
|
FilePath BrowserDatabaseSystem::GetFullFilePathForVfsFile(
|
|
|
|
const string16& vfs_file_name) {
|
2011-04-05 18:17:33 +02:00
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
2010-10-22 02:13:43 +02:00
|
|
|
if (vfs_file_name.empty()) // temp file, used for vacuuming
|
|
|
|
return FilePath();
|
2011-04-05 18:17:33 +02:00
|
|
|
return DatabaseUtil::GetFullFilePathForVfsFile(
|
|
|
|
db_tracker_.get(), vfs_file_name);
|
|
|
|
}
|
2010-10-22 02:13:43 +02:00
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::ResetTracker() {
|
|
|
|
DCHECK(db_thread_proxy_->BelongsToCurrentThread());
|
|
|
|
db_tracker_->CloseTrackerDatabaseAndClearCaches();
|
|
|
|
file_util::Delete(db_tracker_->DatabaseDirectory(), true);
|
|
|
|
}
|
2010-11-17 18:28:32 +01:00
|
|
|
|
2011-04-05 18:17:33 +02:00
|
|
|
void BrowserDatabaseSystem::ThreadCleanup(base::WaitableEvent* done_event) {
|
|
|
|
ResetTracker();
|
|
|
|
db_tracker_->RemoveObserver(this);
|
|
|
|
db_tracker_ = NULL;
|
|
|
|
done_event->Signal();
|
2010-10-22 02:13:43 +02:00
|
|
|
}
|
2011-04-05 18:17:33 +02:00
|
|
|
|