diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-01 20:40:35 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-01 20:40:35 +0000 |
commit | 1d4dbdeaa23f3459fb710c8b2fe4d444266d952a (patch) | |
tree | 94064bd57faaba18d1ee7a9fe514628f58a6be55 /webkit/support | |
parent | 228d0659a51d0581c743b5b81921d43c7fd81e35 (diff) | |
download | chromium_src-1d4dbdeaa23f3459fb710c8b2fe4d444266d952a.zip chromium_src-1d4dbdeaa23f3459fb710c8b2fe4d444266d952a.tar.gz chromium_src-1d4dbdeaa23f3459fb710c8b2fe4d444266d952a.tar.bz2 |
Changes to WebDatabaseObserverImpl and SimpleDatabaseSystem required to have a chance of working properly with v8 isolates. With isolates the database related interfaces will be called on multiple threads and the previous impl was not put together with that in mind.
BUG=none
TEST=existing tests pass (no way to test with isolates yet)
Review URL: http://codereview.chromium.org/6677088
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80218 0039d316-1c4b-4281-b951-d872f2087c98
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_ |