summaryrefslogtreecommitdiffstats
path: root/webkit/support
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/support')
-rw-r--r--webkit/support/simple_database_system.cc257
-rw-r--r--webkit/support/simple_database_system.h73
2 files changed, 209 insertions, 121 deletions
diff --git a/webkit/support/simple_database_system.cc b/webkit/support/simple_database_system.cc
index 6c00d6c..62bd03e 100644
--- a/webkit/support/simple_database_system.cc
+++ b/webkit/support/simple_database_system.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -7,6 +7,8 @@
#include "base/auto_reset.h"
#include "base/file_util.h"
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/utf_string_conversions.h"
#include "third_party/sqlite/sqlite3.h"
@@ -27,91 +29,138 @@ SimpleDatabaseSystem* SimpleDatabaseSystem::GetInstance() {
}
SimpleDatabaseSystem::SimpleDatabaseSystem()
- : waiting_for_dbs_to_close_(false) {
+ : db_thread_("SimpleDBThread"),
+ open_connections_(new webkit_database::DatabaseConnectionsWrapper) {
+ DCHECK(!instance_);
+ instance_ = this;
CHECK(temp_dir_.CreateUniqueTempDir());
db_tracker_ = new DatabaseTracker(temp_dir_.path(), false, NULL);
db_tracker_->AddObserver(this);
- DCHECK(!instance_);
- instance_ = this;
+ db_thread_.Start();
+ db_thread_proxy_ = db_thread_.message_loop_proxy();
}
SimpleDatabaseSystem::~SimpleDatabaseSystem() {
- db_tracker_->RemoveObserver(this);
+ base::WaitableEvent done_event(false, false);
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::ThreadCleanup,
+ &done_event));
+ done_event.Wait();
instance_ = NULL;
}
+void SimpleDatabaseSystem::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, &SimpleDatabaseSystem::DatabaseOpened,
+ origin_identifier,
+ database_name, database.displayName(),
+ database.estimatedSize()));
+}
+
+void SimpleDatabaseSystem::databaseModified(
+ const WebKit::WebDatabase& database) {
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::DatabaseModified,
+ database.securityOrigin().databaseIdentifier(),
+ database.name()));
+}
+
+void SimpleDatabaseSystem::databaseClosed(const WebKit::WebDatabase& database) {
+ string16 origin_identifier = database.securityOrigin().databaseIdentifier();
+ string16 database_name = database.name();
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::DatabaseClosed,
+ origin_identifier, database_name));
+}
+
base::PlatformFile SimpleDatabaseSystem::OpenFile(
const string16& vfs_file_name, int desired_flags) {
- base::PlatformFile file_handle = base::kInvalidPlatformFileValue;
- 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);
- }
-
- return file_handle;
+ base::PlatformFile result = base::kInvalidPlatformFileValue;
+ base::WaitableEvent done_event(false, false);
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::VfsOpenFile,
+ vfs_file_name, desired_flags,
+ &result, &done_event));
+ done_event.Wait();
+ return result;
}
int SimpleDatabaseSystem::DeleteFile(
const string16& vfs_file_name, bool sync_dir) {
- // 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;
- int error_code = SQLITE_OK;
- FilePath file_name = GetFullFilePathForVfsFile(vfs_file_name);
- do {
- error_code = VfsBackend::DeleteFile(file_name, sync_dir);
- } while ((++num_retries < kNumDeleteRetries) &&
- (error_code == SQLITE_IOERR_DELETE) &&
- (base::PlatformThread::Sleep(10), 1));
+ int result = SQLITE_OK;
+ base::WaitableEvent done_event(false, false);
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::VfsDeleteFile,
+ vfs_file_name, sync_dir,
+ &result, &done_event));
+ done_event.Wait();
+ return result;
+}
- return error_code;
+uint32 SimpleDatabaseSystem::GetFileAttributes(const string16& vfs_file_name) {
+ uint32 result = 0;
+ base::WaitableEvent done_event(false, false);
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::VfsGetFileAttributes,
+ vfs_file_name, &result, &done_event));
+ done_event.Wait();
+ return result;
}
-long SimpleDatabaseSystem::GetFileAttributes(const string16& vfs_file_name) {
- return VfsBackend::GetFileAttributes(
- GetFullFilePathForVfsFile(vfs_file_name));
+int64 SimpleDatabaseSystem::GetFileSize(const string16& vfs_file_name) {
+ int64 result = 0;
+ base::WaitableEvent done_event(false, false);
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::VfsGetFileSize,
+ vfs_file_name, &result, &done_event));
+ done_event.Wait();
+ return result;
+}
+
+void SimpleDatabaseSystem::ClearAllDatabases() {
+ open_connections_->WaitForAllDatabasesToClose();
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::ResetTracker));
}
-long long SimpleDatabaseSystem::GetFileSize(const string16& vfs_file_name) {
- return VfsBackend::GetFileSize(GetFullFilePathForVfsFile(vfs_file_name));
+void SimpleDatabaseSystem::SetDatabaseQuota(int64 quota) {
+ if (!db_thread_proxy_->BelongsToCurrentThread()) {
+ db_thread_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &SimpleDatabaseSystem::SetDatabaseQuota,
+ quota));
+ return;
+ }
+ db_tracker_->SetDefaultQuota(quota);
}
void SimpleDatabaseSystem::DatabaseOpened(const string16& origin_identifier,
const string16& database_name,
const string16& description,
int64 estimated_size) {
+ DCHECK(db_thread_proxy_->BelongsToCurrentThread());
int64 database_size = 0;
int64 space_available = 0;
- database_connections_.AddConnection(origin_identifier, database_name);
- db_tracker_->DatabaseOpened(origin_identifier, database_name, description,
- estimated_size, &database_size, &space_available);
- SetFullFilePathsForVfsFile(origin_identifier, database_name);
-
+ db_tracker_->DatabaseOpened(
+ origin_identifier, database_name, description,
+ estimated_size, &database_size, &space_available);
OnDatabaseSizeChanged(origin_identifier, database_name,
database_size, space_available);
}
void SimpleDatabaseSystem::DatabaseModified(const string16& origin_identifier,
const string16& database_name) {
- DCHECK(database_connections_.IsDatabaseOpened(
- origin_identifier, database_name));
+ DCHECK(db_thread_proxy_->BelongsToCurrentThread());
db_tracker_->DatabaseModified(origin_identifier, database_name);
}
void SimpleDatabaseSystem::DatabaseClosed(const string16& origin_identifier,
const string16& database_name) {
- DCHECK(database_connections_.IsDatabaseOpened(
- origin_identifier, database_name));
+ DCHECK(db_thread_proxy_->BelongsToCurrentThread());
db_tracker_->DatabaseClosed(origin_identifier, database_name);
- database_connections_.RemoveConnection(origin_identifier, database_name);
-
- if (waiting_for_dbs_to_close_ && database_connections_.IsEmpty())
- MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ open_connections_->RemoveOpenConnection(origin_identifier, database_name);
}
void SimpleDatabaseSystem::OnDatabaseSizeChanged(
@@ -119,75 +168,95 @@ void SimpleDatabaseSystem::OnDatabaseSizeChanged(
const string16& database_name,
int64 database_size,
int64 space_available) {
- if (database_connections_.IsOriginUsed(origin_identifier)) {
- WebKit::WebDatabase::updateDatabaseSize(
- origin_identifier, database_name, database_size, space_available);
- }
+ 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(
+ origin_identifier, database_name, database_size, space_available);
}
void SimpleDatabaseSystem::OnDatabaseScheduledForDeletion(
const string16& origin_identifier,
const string16& database_name) {
+ 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::closeDatabaseImmediately(
origin_identifier, database_name);
}
-void SimpleDatabaseSystem::databaseOpened(const WebKit::WebDatabase& database) {
- DatabaseOpened(database.securityOrigin().databaseIdentifier(),
- database.name(), database.displayName(),
- database.estimatedSize());
-}
-
-void SimpleDatabaseSystem::databaseModified(
- const WebKit::WebDatabase& database) {
- DatabaseModified(database.securityOrigin().databaseIdentifier(),
- database.name());
-}
-
-void SimpleDatabaseSystem::databaseClosed(const WebKit::WebDatabase& database) {
- DatabaseClosed(database.securityOrigin().databaseIdentifier(),
- database.name());
+void SimpleDatabaseSystem::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();
}
-void SimpleDatabaseSystem::ClearAllDatabases() {
- // Wait for all databases to be closed.
- if (!database_connections_.IsEmpty()) {
- AutoReset<bool> waiting_for_dbs_auto_reset(
- &waiting_for_dbs_to_close_, true);
- MessageLoop::ScopedNestableTaskAllower nestable(MessageLoop::current());
- MessageLoop::current()->Run();
- }
+void SimpleDatabaseSystem::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));
- db_tracker_->CloseTrackerDatabaseAndClearCaches();
- file_util::Delete(db_tracker_->DatabaseDirectory(), true);
- file_names_.clear();
+ done_event->Signal();
}
-void SimpleDatabaseSystem::SetDatabaseQuota(int64 quota) {
- db_tracker_->SetDefaultQuota(quota);
+void SimpleDatabaseSystem::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();
}
-void SimpleDatabaseSystem::SetFullFilePathsForVfsFile(
- const string16& origin_identifier,
- const string16& database_name) {
- string16 vfs_file_name = origin_identifier + ASCIIToUTF16("/") +
- database_name + ASCIIToUTF16("#");
- FilePath file_name =
- DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
-
- base::AutoLock file_names_auto_lock(file_names_lock_);
- file_names_[vfs_file_name] = file_name;
- DCHECK(file_name.Extension().empty());
- file_names_[vfs_file_name + ASCIIToUTF16("-journal")] =
- file_name.InsertBeforeExtensionASCII("-journal");
+void SimpleDatabaseSystem::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();
}
FilePath SimpleDatabaseSystem::GetFullFilePathForVfsFile(
const string16& vfs_file_name) {
+ DCHECK(db_thread_proxy_->BelongsToCurrentThread());
if (vfs_file_name.empty()) // temp file, used for vacuuming
return FilePath();
+ return DatabaseUtil::GetFullFilePathForVfsFile(
+ db_tracker_.get(), vfs_file_name);
+}
+
+void SimpleDatabaseSystem::ResetTracker() {
+ DCHECK(db_thread_proxy_->BelongsToCurrentThread());
+ db_tracker_->CloseTrackerDatabaseAndClearCaches();
+ file_util::Delete(db_tracker_->DatabaseDirectory(), true);
+}
- base::AutoLock file_names_auto_lock(file_names_lock_);
- DCHECK(file_names_.find(vfs_file_name) != file_names_.end());
- return file_names_[vfs_file_name];
+void SimpleDatabaseSystem::ThreadCleanup(base::WaitableEvent* done_event) {
+ ResetTracker();
+ db_tracker_->RemoveObserver(this);
+ db_tracker_ = NULL;
+ done_event->Signal();
}
+
diff --git a/webkit/support/simple_database_system.h b/webkit/support/simple_database_system.h
index 63cc892..02bb66a 100644
--- a/webkit/support/simple_database_system.h
+++ b/webkit/support/simple_database_system.h
@@ -12,24 +12,45 @@
#include "base/platform_file.h"
#include "base/string16.h"
#include "base/synchronization/lock.h"
+#include "base/task.h"
+#include "base/threading/thread.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabaseObserver.h"
#include "webkit/database/database_connections.h"
#include "webkit/database/database_tracker.h"
+namespace base {
+class MessageLoopProxy;
+class WaitableEvent;
+}
+
class SimpleDatabaseSystem : public webkit_database::DatabaseTracker::Observer,
public WebKit::WebDatabaseObserver {
public:
static SimpleDatabaseSystem* GetInstance();
+
SimpleDatabaseSystem();
~SimpleDatabaseSystem();
- // VFS functions
+ // WebDatabaseObserver implementation, these are called on the script
+ // execution context thread on which the database is opened. This may be
+ // the main thread or background WebWorker threads.
+ virtual void databaseOpened(const WebKit::WebDatabase& database);
+ virtual void databaseModified(const WebKit::WebDatabase& database);
+ virtual void databaseClosed(const WebKit::WebDatabase& database);
+
+ // SQLite VFS related methods, these are called on webcore's
+ // background database threads via the WebKitClient impl.
base::PlatformFile OpenFile(const string16& vfs_file_name, int desired_flags);
int DeleteFile(const string16& vfs_file_name, bool sync_dir);
- long GetFileAttributes(const string16& vfs_file_name);
- long long GetFileSize(const string16& vfs_file_name);
+ uint32 GetFileAttributes(const string16& vfs_file_name);
+ int64 GetFileSize(const string16& vfs_file_name);
- // database tracker functions
+ // For use by LayoutTestController, called on the main thread.
+ void ClearAllDatabases();
+ void SetDatabaseQuota(int64 quota);
+
+ private:
+ // Used by our WebDatabaseObserver impl, only called on the db_thread
void DatabaseOpened(const string16& origin_identifier,
const string16& database_name,
const string16& description,
@@ -47,38 +68,36 @@ class SimpleDatabaseSystem : public webkit_database::DatabaseTracker::Observer,
virtual void OnDatabaseScheduledForDeletion(const string16& origin_identifier,
const string16& database_name);
- // WebDatabaseObserver implementation
- virtual void databaseOpened(const WebKit::WebDatabase& database);
- virtual void databaseModified(const WebKit::WebDatabase& database);
- virtual void databaseClosed(const WebKit::WebDatabase& database);
-
- void ClearAllDatabases();
- void SetDatabaseQuota(int64 quota);
+ // Used by our public SQLite VFS methods, only called on the db_thread.
+ void VfsOpenFile(const string16& vfs_file_name, int desired_flags,
+ base::PlatformFile* result, base::WaitableEvent* done_event);
+ void VfsDeleteFile(const string16& vfs_file_name, bool sync_dir,
+ int* result, base::WaitableEvent* done_event);
+ void VfsGetFileAttributes(const string16& vfs_file_name,
+ uint32* result, base::WaitableEvent* done_event);
+ void VfsGetFileSize(const string16& vfs_file_name,
+ int64* result, base::WaitableEvent* done_event);
- private:
- // The calls that come from the database tracker run on the main thread.
- // Therefore, we can only call DatabaseUtil::GetFullFilePathForVfsFile()
- // on the main thread. However, the VFS calls run on the DB thread and
- // they need to crack VFS file paths. To resolve this problem, we store
- // a map of vfs_file_names to file_paths. The map is updated on the main
- // thread on each DatabaseOpened() call that comes from the database
- // tracker, and is read on the DB thread by each VFS call.
- void SetFullFilePathsForVfsFile(const string16& origin_identifier,
- const string16& database_name);
FilePath GetFullFilePathForVfsFile(const string16& vfs_file_name);
- static SimpleDatabaseSystem* instance_;
-
- bool waiting_for_dbs_to_close_;
+ void ResetTracker();
+ void ThreadCleanup(base::WaitableEvent* done_event);
+ // Where the tracker database file and per origin database files reside.
ScopedTempDir temp_dir_;
+ // All access to the db_tracker (except for its construction) and
+ // vfs operations are serialized on a background thread.
+ base::Thread db_thread_;
+ scoped_refptr<base::MessageLoopProxy> db_thread_proxy_;
scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
- base::Lock file_names_lock_;
- base::hash_map<string16, FilePath> file_names_;
+ // Data members to support waiting for all connections to be closed.
+ scoped_refptr<webkit_database::DatabaseConnectionsWrapper> open_connections_;
- webkit_database::DatabaseConnections database_connections_;
+ static SimpleDatabaseSystem* instance_;
};
+DISABLE_RUNNABLE_METHOD_REFCOUNT(SimpleDatabaseSystem);
+
#endif // WEBKIT_SUPPORT_SIMPLE_DATABASE_SYSTEM_H_