summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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',