diff options
Diffstat (limited to 'webkit/support')
-rw-r--r-- | webkit/support/simple_database_system.cc | 257 | ||||
-rw-r--r-- | webkit/support/simple_database_system.h | 73 |
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_ |