summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-01 20:40:35 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-01 20:40:35 +0000
commit1d4dbdeaa23f3459fb710c8b2fe4d444266d952a (patch)
tree94064bd57faaba18d1ee7a9fe514628f58a6be55
parent228d0659a51d0581c743b5b81921d43c7fd81e35 (diff)
downloadchromium_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
-rw-r--r--chrome/renderer/render_thread.h6
-rw-r--r--content/common/web_database_observer_impl.cc19
-rw-r--r--content/common/web_database_observer_impl.h9
-rw-r--r--webkit/database/database_connections.cc54
-rw-r--r--webkit/database/database_connections.h36
-rw-r--r--webkit/database/database_connections_unittest.cc79
-rw-r--r--webkit/support/simple_database_system.cc257
-rw-r--r--webkit/support/simple_database_system.h73
-rw-r--r--webkit/tools/test_shell/test_shell.gypi1
9 files changed, 393 insertions, 141 deletions
diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h
index c2e78e6..2d9f051 100644
--- a/chrome/renderer/render_thread.h
+++ b/chrome/renderer/render_thread.h
@@ -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.
@@ -329,13 +329,15 @@ class RenderThread : public RenderThreadBase,
scoped_ptr<RendererHistogramSnapshots> histogram_snapshots_;
scoped_ptr<RendererWebKitClientImpl> webkit_client_;
scoped_ptr<WebKit::WebStorageEventDispatcher> dom_storage_event_dispatcher_;
- scoped_ptr<WebDatabaseObserverImpl> web_database_observer_impl_;
scoped_ptr<SpellCheck> spellchecker_;
// Used on the renderer and IPC threads.
scoped_refptr<DBMessageFilter> db_message_filter_;
scoped_refptr<CookieMessageFilter> cookie_message_filter_;
+ // Used on multiple script execution context threads.
+ scoped_ptr<WebDatabaseObserverImpl> web_database_observer_impl_;
+
#if defined(OS_POSIX)
scoped_refptr<IPC::ChannelProxy::MessageFilter>
suicide_on_channel_error_filter_;
diff --git a/content/common/web_database_observer_impl.cc b/content/common/web_database_observer_impl.cc
index 37c3e2c..be3c8ca 100644
--- a/content/common/web_database_observer_impl.cc
+++ b/content/common/web_database_observer_impl.cc
@@ -4,8 +4,6 @@
#include "content/common/web_database_observer_impl.h"
-#include "base/auto_reset.h"
-#include "base/message_loop.h"
#include "base/string16.h"
#include "content/common/database_messages.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h"
@@ -14,17 +12,20 @@
WebDatabaseObserverImpl::WebDatabaseObserverImpl(
IPC::Message::Sender* sender)
: sender_(sender),
- waiting_for_dbs_to_close_(false) {
+ open_connections_(new webkit_database::DatabaseConnectionsWrapper) {
+}
+
+WebDatabaseObserverImpl::~WebDatabaseObserverImpl() {
}
void WebDatabaseObserverImpl::databaseOpened(
const WebKit::WebDatabase& database) {
string16 origin_identifier = database.securityOrigin().databaseIdentifier();
string16 database_name = database.name();
+ open_connections_->AddOpenConnection(origin_identifier, database_name);
sender_->Send(new DatabaseHostMsg_Opened(
origin_identifier, database_name,
database.displayName(), database.estimatedSize()));
- database_connections_.AddConnection(origin_identifier, database_name);
}
void WebDatabaseObserverImpl::databaseModified(
@@ -39,15 +40,9 @@ void WebDatabaseObserverImpl::databaseClosed(
string16 database_name = database.name();
sender_->Send(new DatabaseHostMsg_Closed(
origin_identifier, database_name));
- database_connections_.RemoveConnection(origin_identifier, database_name);
- if (waiting_for_dbs_to_close_ && database_connections_.IsEmpty())
- MessageLoop::current()->Quit();
+ open_connections_->RemoveOpenConnection(origin_identifier, database_name);
}
void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() {
- 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();
- }
+ open_connections_->WaitForAllDatabasesToClose();
}
diff --git a/content/common/web_database_observer_impl.h b/content/common/web_database_observer_impl.h
index 442a7af..a79ee6f 100644
--- a/content/common/web_database_observer_impl.h
+++ b/content/common/web_database_observer_impl.h
@@ -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.
@@ -6,6 +6,7 @@
#define CONTENT_COMMON_WEB_DATABASE_OBSERVER_IMPL_H_
#pragma once
+#include "base/memory/ref_counted.h"
#include "ipc/ipc_message.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabaseObserver.h"
#include "webkit/database/database_connections.h"
@@ -13,7 +14,8 @@
class WebDatabaseObserverImpl : public WebKit::WebDatabaseObserver {
public:
explicit WebDatabaseObserverImpl(IPC::Message::Sender* sender);
- virtual ~WebDatabaseObserverImpl() {}
+ virtual ~WebDatabaseObserverImpl();
+
virtual void databaseOpened(const WebKit::WebDatabase& database);
virtual void databaseModified(const WebKit::WebDatabase& database);
virtual void databaseClosed(const WebKit::WebDatabase& database);
@@ -22,8 +24,7 @@ class WebDatabaseObserverImpl : public WebKit::WebDatabaseObserver {
private:
IPC::Message::Sender* sender_;
- bool waiting_for_dbs_to_close_;
- webkit_database::DatabaseConnections database_connections_;
+ scoped_refptr<webkit_database::DatabaseConnectionsWrapper> open_connections_;
};
#endif // CONTENT_COMMON_WEB_DATABASE_OBSERVER_IMPL_H_
diff --git a/webkit/database/database_connections.cc b/webkit/database/database_connections.cc
index 05efb1e..612f73b4 100644
--- a/webkit/database/database_connections.cc
+++ b/webkit/database/database_connections.cc
@@ -1,10 +1,13 @@
-// Copyright (c) 2009 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.
#include "webkit/database/database_connections.h"
+#include "base/auto_reset.h"
#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
namespace webkit_database {
@@ -84,4 +87,53 @@ void DatabaseConnections::RemoveConnectionsHelper(
}
}
+DatabaseConnectionsWrapper::DatabaseConnectionsWrapper()
+ : waiting_for_dbs_to_close_(false),
+ main_thread_(base::MessageLoopProxy::CreateForCurrentThread()) {
+}
+
+DatabaseConnectionsWrapper::~DatabaseConnectionsWrapper() {
+}
+
+void DatabaseConnectionsWrapper::WaitForAllDatabasesToClose() {
+ // We assume that new databases won't be open while we're waiting.
+ DCHECK(main_thread_->BelongsToCurrentThread());
+ if (HasOpenConnections()) {
+ AutoReset<bool> auto_reset(&waiting_for_dbs_to_close_, true);
+ MessageLoop::ScopedNestableTaskAllower nestable(MessageLoop::current());
+ MessageLoop::current()->Run();
+ }
+}
+
+bool DatabaseConnectionsWrapper::HasOpenConnections() {
+ DCHECK(main_thread_->BelongsToCurrentThread());
+ base::AutoLock auto_lock(open_connections_lock_);
+ return !open_connections_.IsEmpty();
+}
+
+void DatabaseConnectionsWrapper::AddOpenConnection(
+ const string16& origin_identifier,
+ const string16& database_name) {
+ // We add to the collection immediately on any thread.
+ base::AutoLock auto_lock(open_connections_lock_);
+ open_connections_.AddConnection(origin_identifier, database_name);
+}
+
+void DatabaseConnectionsWrapper::RemoveOpenConnection(
+ const string16& origin_identifier,
+ const string16& database_name) {
+ // But only remove from the collection on the main thread
+ // so we can handle the waiting_for_dbs_to_close_ case.
+ if (!main_thread_->BelongsToCurrentThread()) {
+ main_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &DatabaseConnectionsWrapper::RemoveOpenConnection,
+ origin_identifier, database_name));
+ return;
+ }
+ base::AutoLock auto_lock(open_connections_lock_);
+ open_connections_.RemoveConnection(origin_identifier, database_name);
+ if (waiting_for_dbs_to_close_ && open_connections_.IsEmpty())
+ MessageLoop::current()->Quit();
+}
+
} // namespace webkit_database
diff --git a/webkit/database/database_connections.h b/webkit/database/database_connections.h
index 433bb3f..6a594b2 100644
--- a/webkit/database/database_connections.h
+++ b/webkit/database/database_connections.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 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.
@@ -8,7 +8,13 @@
#include <map>
#include <vector>
+#include "base/memory/ref_counted.h"
#include "base/string16.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+class MessageLoopProxy;
+}
namespace webkit_database {
@@ -40,6 +46,34 @@ class DatabaseConnections {
int num_connections);
};
+// A wrapper class that provides thread-safety and the
+// ability to wait until all connections have closed.
+// Intended for use in renderer processes.
+class DatabaseConnectionsWrapper
+ : public base::RefCountedThreadSafe<DatabaseConnectionsWrapper> {
+ public:
+ DatabaseConnectionsWrapper();
+
+ // The Wait and Has methods should only be called on the
+ // main thread (the thread on which the wrapper is constructed).
+ void WaitForAllDatabasesToClose();
+ bool HasOpenConnections();
+
+ // Add and Remove may be called on any thread.
+ void AddOpenConnection(const string16& origin_identifier,
+ const string16& database_name);
+ void RemoveOpenConnection(const string16& origin_identifier,
+ const string16& database_name);
+ private:
+ ~DatabaseConnectionsWrapper();
+ friend class base::RefCountedThreadSafe<DatabaseConnectionsWrapper>;
+
+ bool waiting_for_dbs_to_close_;
+ base::Lock open_connections_lock_;
+ DatabaseConnections open_connections_;
+ scoped_refptr<base::MessageLoopProxy> main_thread_;
+};
+
} // namespace webkit_database
#endif // WEBKIT_DATABASE_DATABASE_CONNECTIONS_H_
diff --git a/webkit/database/database_connections_unittest.cc b/webkit/database/database_connections_unittest.cc
new file mode 100644
index 0000000..1b3ef34
--- /dev/null
+++ b/webkit/database/database_connections_unittest.cc
@@ -0,0 +1,79 @@
+// 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.
+
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "base/threading/thread.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/database/database_connections.h"
+
+namespace webkit_database {
+
+namespace {
+
+void RemoveConnectionTask(
+ const string16& origin_id, const string16& database_name,
+ scoped_refptr<DatabaseConnectionsWrapper> obj,
+ bool* did_task_execute) {
+ *did_task_execute = true;
+ obj->RemoveOpenConnection(origin_id, database_name);
+}
+
+void ScheduleRemoveConnectionTask(
+ base::Thread* thread, const string16& origin_id,
+ const string16& database_name,
+ scoped_refptr<DatabaseConnectionsWrapper> obj,
+ bool* did_task_execute) {
+ thread->message_loop()->PostTask(FROM_HERE,
+ NewRunnableFunction(RemoveConnectionTask,
+ origin_id, database_name, obj, did_task_execute));
+}
+
+} // anonymous namespace
+
+TEST(DatabaseConnectionsTest, DatabaseConnectionsWrapperTest) {
+ string16 kOriginId(ASCIIToUTF16("origin_id"));
+ string16 kName(ASCIIToUTF16("database_name"));
+
+ scoped_refptr<DatabaseConnectionsWrapper> obj(
+ new DatabaseConnectionsWrapper);
+ EXPECT_FALSE(obj->HasOpenConnections());
+ obj->AddOpenConnection(kOriginId, kName);
+ EXPECT_TRUE(obj->HasOpenConnections());
+ obj->AddOpenConnection(kOriginId, kName);
+ EXPECT_TRUE(obj->HasOpenConnections());
+ obj->RemoveOpenConnection(kOriginId, kName);
+ EXPECT_TRUE(obj->HasOpenConnections());
+ obj->RemoveOpenConnection(kOriginId, kName);
+ EXPECT_FALSE(obj->HasOpenConnections());
+ obj->WaitForAllDatabasesToClose(); // should return immediately
+
+ // Test WaitForAllDatabasesToClose with the last connection
+ // being removed on the current thread.
+ obj->AddOpenConnection(kOriginId, kName);
+ bool did_task_execute = false;
+ MessageLoop::current()->PostTask(FROM_HERE,
+ NewRunnableFunction(&RemoveConnectionTask,
+ kOriginId, kName, obj, &did_task_execute));
+ obj->WaitForAllDatabasesToClose(); // should return after the task executes
+ EXPECT_TRUE(did_task_execute);
+ EXPECT_FALSE(obj->HasOpenConnections());
+
+ // Test WaitForAllDatabasesToClose with the last connection
+ // being removed on another thread.
+ obj->AddOpenConnection(kOriginId, kName);
+ base::Thread thread("WrapperTestThread");
+ thread.Start();
+ did_task_execute = false;
+ MessageLoop::current()->PostTask(FROM_HERE,
+ NewRunnableFunction(ScheduleRemoveConnectionTask,
+ &thread, kOriginId, kName,
+ obj, &did_task_execute));
+ obj->WaitForAllDatabasesToClose(); // should return after the task executes
+ EXPECT_TRUE(did_task_execute);
+ EXPECT_FALSE(obj->HasOpenConnections());
+}
+
+} // namespace webkit_database
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_
diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi
index 43fc227..ddde626 100644
--- a/webkit/tools/test_shell/test_shell.gypi
+++ b/webkit/tools/test_shell/test_shell.gypi
@@ -370,6 +370,7 @@
'../../blob/blob_storage_controller_unittest.cc',
'../../blob/blob_url_request_job_unittest.cc',
'../../blob/deletable_file_reference_unittest.cc',
+ '../../database/database_connections_unittest.cc',
'../../database/databases_table_unittest.cc',
'../../database/database_tracker_unittest.cc',
'../../database/database_util_unittest.cc',