summaryrefslogtreecommitdiff
path: root/src/3rdparty/webkit/WebCore/storage
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/WebCore/storage')
-rw-r--r--src/3rdparty/webkit/WebCore/storage/Database.cpp354
-rw-r--r--src/3rdparty/webkit/WebCore/storage/Database.h34
-rw-r--r--src/3rdparty/webkit/WebCore/storage/Database.idl3
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.cpp88
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.h5
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseCallback.h53
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseDetails.h13
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseTask.cpp79
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseTask.h78
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseThread.cpp27
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseThread.h11
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseTracker.cpp625
-rw-r--r--src/3rdparty/webkit/WebCore/storage/DatabaseTracker.h101
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.h64
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.idl37
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.h64
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.idl48
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.h50
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.idl37
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBRequest.cpp64
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBRequest.h88
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IDBRequest.idl45
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IndexedDatabase.cpp49
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IndexedDatabase.h56
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.cpp69
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.h56
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.cpp53
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.h65
-rw-r--r--src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.idl38
-rw-r--r--src/3rdparty/webkit/WebCore/storage/LocalStorageTask.h11
-rw-r--r--src/3rdparty/webkit/WebCore/storage/LocalStorageThread.cpp74
-rw-r--r--src/3rdparty/webkit/WebCore/storage/LocalStorageThread.h28
-rw-r--r--src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.cpp14
-rw-r--r--src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.h1
-rw-r--r--src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.cpp6
-rw-r--r--src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.h2
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLError.idl3
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLResultSet.idl3
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLResultSetRowList.idl3
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLTransaction.cpp28
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLTransaction.h1
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLTransaction.idl3
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.cpp15
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.h8
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.cpp20
-rw-r--r--src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.h6
-rw-r--r--src/3rdparty/webkit/WebCore/storage/Storage.idl1
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageArea.h6
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.cpp58
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.h9
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageAreaSync.cpp92
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageAreaSync.h9
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageEvent.cpp2
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageEvent.idl3
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageEventDispatcher.cpp14
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageMap.cpp34
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageNamespace.cpp3
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageNamespace.h31
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageSyncManager.cpp20
-rw-r--r--src/3rdparty/webkit/WebCore/storage/StorageSyncManager.h6
60 files changed, 2224 insertions, 644 deletions
diff --git a/src/3rdparty/webkit/WebCore/storage/Database.cpp b/src/3rdparty/webkit/WebCore/storage/Database.cpp
index 2f82743ec8..b8023dd6b4 100644
--- a/src/3rdparty/webkit/WebCore/storage/Database.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/Database.cpp
@@ -35,6 +35,7 @@
#include "ChangeVersionWrapper.h"
#include "CString.h"
#include "DatabaseAuthorizer.h"
+#include "DatabaseCallback.h"
#include "DatabaseTask.h"
#include "DatabaseThread.h"
#include "DatabaseTracker.h"
@@ -53,8 +54,8 @@
#include "SQLResultSet.h"
#include "SQLTransactionClient.h"
#include "SQLTransactionCoordinator.h"
-#include <wtf/MainThread.h>
-#endif
+
+#endif // ENABLE(DATABASE)
#if USE(JSC)
#include "JSDOMWindow.h"
@@ -73,6 +74,18 @@ const String& Database::databaseInfoTableName()
#if ENABLE(DATABASE)
+static bool isDatabaseAvailable = true;
+
+void Database::setIsAvailable(bool available)
+{
+ isDatabaseAvailable = available;
+}
+
+bool Database::isAvailable()
+{
+ return isDatabaseAvailable;
+}
+
static Mutex& guidMutex()
{
// Note: We don't have to use AtomicallyInitializedStatic here because
@@ -120,36 +133,75 @@ static const String& databaseVersionKey()
static int guidForOriginAndName(const String& origin, const String& name);
-PassRefPtr<Database> Database::openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e)
+class DatabaseCreationCallbackTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtr<Database> database)
+ {
+ return new DatabaseCreationCallbackTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_database->performCreationCallback();
+ }
+
+private:
+ DatabaseCreationCallbackTask(PassRefPtr<Database> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<Database> m_database;
+};
+
+PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, const String& name,
+ const String& expectedVersion, const String& displayName,
+ unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback,
+ ExceptionCode& e)
{
- if (!DatabaseTracker::tracker().canEstablishDatabase(document, name, displayName, estimatedSize)) {
+ if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) {
// FIXME: There should be an exception raised here in addition to returning a null Database object. The question has been raised with the WHATWG.
- LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), document->securityOrigin()->toString().ascii().data());
+ LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
return 0;
}
- RefPtr<Database> database = adoptRef(new Database(document, name, expectedVersion, displayName, estimatedSize));
+ RefPtr<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize, creationCallback));
if (!database->openAndVerifyVersion(e)) {
- LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
- return 0;
+ LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
+ context->removeOpenDatabase(database.get());
+ DatabaseTracker::tracker().removeOpenDatabase(database.get());
+ return 0;
}
- DatabaseTracker::tracker().setDatabaseDetails(document->securityOrigin(), name, displayName, estimatedSize);
-
- document->setHasOpenDatabases();
+ DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
+ context->setHasOpenDatabases();
#if ENABLE(INSPECTOR)
- if (Page* page = document->frame()->page())
- page->inspectorController()->didOpenDatabase(database.get(), document->securityOrigin()->host(), name, expectedVersion);
+ if (context->isDocument()) {
+ Document* document = static_cast<Document*>(context);
+ if (Page* page = document->page())
+ page->inspectorController()->didOpenDatabase(database.get(), context->securityOrigin()->host(), name, expectedVersion);
+ }
#endif
+ // If it's a new database and a creation callback was provided, reset the expected
+ // version to "" and schedule the creation callback. Because of some subtle String
+ // implementation issues, we have to reset m_expectedVersion here instead of doing
+ // it inside performOpenAndVerify() which is run on the DB thread.
+ if (database->isNew() && database->m_creationCallback.get()) {
+ database->m_expectedVersion = "";
+ LOG(StorageAPI, "Scheduling DatabaseCreationCallbackTask for database %p\n", database.get());
+ database->m_scriptExecutionContext->postTask(DatabaseCreationCallbackTask::create(database));
+ }
+
return database;
}
-Database::Database(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
+Database::Database(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback)
: m_transactionInProgress(false)
- , m_document(document)
+ , m_isTransactionQueueEnabled(true)
+ , m_scriptExecutionContext(context)
, m_name(name.crossThreadString())
, m_guid(0)
, m_expectedVersion(expectedVersion.crossThreadString())
@@ -158,17 +210,18 @@ Database::Database(Document* document, const String& name, const String& expecte
, m_deleted(false)
, m_stopped(false)
, m_opened(false)
+ , m_new(false)
+ , m_creationCallback(creationCallback)
{
- ASSERT(document);
- m_mainThreadSecurityOrigin = document->securityOrigin();
+ ASSERT(m_scriptExecutionContext.get());
+ m_mainThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
m_databaseThreadSecurityOrigin = m_mainThreadSecurityOrigin->threadsafeCopy();
-
if (m_name.isNull())
m_name = "";
ScriptController::initializeThreading();
- m_guid = guidForOriginAndName(m_mainThreadSecurityOrigin->toString(), name);
+ m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
{
MutexLocker locker(guidMutex());
@@ -182,38 +235,51 @@ Database::Database(Document* document, const String& name, const String& expecte
hashSet->add(this);
}
- ASSERT(m_document->databaseThread());
-
- m_filename = DatabaseTracker::tracker().fullPathForDatabase(m_mainThreadSecurityOrigin.get(), m_name);
+ ASSERT(m_scriptExecutionContext->databaseThread());
+ m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name);
DatabaseTracker::tracker().addOpenDatabase(this);
- m_document->addOpenDatabase(this);
+ context->addOpenDatabase(this);
}
+class DerefContextTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DerefContextTask> create()
+ {
+ return new DerefContextTask();
+ }
+
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ context->deref();
+ }
+
+ virtual bool isCleanupTask() const { return true; }
+};
+
Database::~Database()
{
- if (m_document->databaseThread())
- m_document->databaseThread()->unscheduleDatabaseTasks(this);
-
- DatabaseTracker::tracker().removeOpenDatabase(this);
- m_document->removeOpenDatabase(this);
+ // The reference to the ScriptExecutionContext needs to be cleared on the JavaScript thread. If we're on that thread already, we can just let the RefPtr's destruction do the dereffing.
+ if (!m_scriptExecutionContext->isContextThread()) {
+ m_scriptExecutionContext->postTask(DerefContextTask::create());
+ m_scriptExecutionContext.release().releaseRef();
+ }
}
bool Database::openAndVerifyVersion(ExceptionCode& e)
{
- if (!m_document->databaseThread())
+ if (!m_scriptExecutionContext->databaseThread())
return false;
m_databaseAuthorizer = DatabaseAuthorizer::create();
- RefPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this);
+ bool success = false;
+ DatabaseTaskSynchronizer synchronizer;
+ OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, &synchronizer, e, success);
- task->lockForSynchronousScheduling();
- m_document->databaseThread()->scheduleImmediateTask(task);
- task->waitForSynchronousCompletion();
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
+ synchronizer.waitForTaskCompletion();
- ASSERT(task->isComplete());
- e = task->exceptionCode();
- return task->openSuccessful();
+ return success;
}
@@ -305,49 +371,85 @@ bool Database::versionMatchesExpected() const
void Database::markAsDeletedAndClose()
{
- if (m_deleted || !m_document->databaseThread())
+ if (m_deleted || !m_scriptExecutionContext->databaseThread())
return;
LOG(StorageAPI, "Marking %s (%p) as deleted", stringIdentifier().ascii().data(), this);
m_deleted = true;
- if (m_document->databaseThread()->terminationRequested()) {
+ if (m_scriptExecutionContext->databaseThread()->terminationRequested()) {
LOG(StorageAPI, "Database handle %p is on a terminated DatabaseThread, cannot be marked for normal closure\n", this);
return;
}
- m_document->databaseThread()->unscheduleDatabaseTasks(this);
+ m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
- RefPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this);
+ DatabaseTaskSynchronizer synchronizer;
+ OwnPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this, &synchronizer);
- task->lockForSynchronousScheduling();
- m_document->databaseThread()->scheduleImmediateTask(task);
- task->waitForSynchronousCompletion();
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
+ synchronizer.waitForTaskCompletion();
+
+ // DatabaseCloseTask tells Database::close not to do these two removals so that we can do them here synchronously.
+ m_scriptExecutionContext->removeOpenDatabase(this);
+ DatabaseTracker::tracker().removeOpenDatabase(this);
}
-void Database::close()
+class ContextRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<ContextRemoveOpenDatabaseTask> create(PassRefPtr<Database> database)
+ {
+ return new ContextRemoveOpenDatabaseTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ context->removeOpenDatabase(m_database.get());
+ DatabaseTracker::tracker().removeOpenDatabase(m_database.get());
+ }
+
+ virtual bool isCleanupTask() const { return true; }
+
+private:
+ ContextRemoveOpenDatabaseTask(PassRefPtr<Database> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<Database> m_database;
+};
+
+void Database::close(ClosePolicy policy)
{
- if (m_opened) {
- ASSERT(m_document->databaseThread());
- ASSERT(currentThread() == document()->databaseThread()->getThreadID());
- m_sqliteDatabase.close();
- m_document->databaseThread()->recordDatabaseClosed(this);
- m_opened = false;
-
- {
- MutexLocker locker(guidMutex());
-
- HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
- ASSERT(hashSet);
- ASSERT(hashSet->contains(this));
- hashSet->remove(this);
- if (hashSet->isEmpty()) {
- guidToDatabaseMap().remove(m_guid);
- delete hashSet;
- guidToVersionMap().remove(m_guid);
- }
+ RefPtr<Database> protect = this;
+
+ if (!m_opened)
+ return;
+
+ ASSERT(m_scriptExecutionContext->databaseThread());
+ ASSERT(currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID());
+ m_sqliteDatabase.close();
+ // Must ref() before calling databaseThread()->recordDatabaseClosed().
+ m_scriptExecutionContext->databaseThread()->recordDatabaseClosed(this);
+ m_opened = false;
+
+ {
+ MutexLocker locker(guidMutex());
+
+ HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
+ ASSERT(hashSet);
+ ASSERT(hashSet->contains(this));
+ hashSet->remove(this);
+ if (hashSet->isEmpty()) {
+ guidToDatabaseMap().remove(m_guid);
+ delete hashSet;
+ guidToVersionMap().remove(m_guid);
}
}
+
+ m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
+ if (policy == RemoveDatabaseFromContext)
+ m_scriptExecutionContext->postTask(ContextRemoveOpenDatabaseTask::create(this));
}
void Database::stop()
@@ -362,7 +464,7 @@ void Database::stop()
{
MutexLocker locker(m_transactionInProgressMutex);
- m_transactionQueue.kill();
+ m_isTransactionQueueEnabled = false;
m_transactionInProgress = false;
}
}
@@ -443,10 +545,6 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
return false;
}
- m_opened = true;
- if (m_document->databaseThread())
- m_document->databaseThread()->recordDatabaseOpen(this);
-
ASSERT(m_databaseAuthorizer);
m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);
m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
@@ -464,9 +562,13 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
LOG(StorageAPI, "No cached version for guid %i", m_guid);
if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
+ m_new = true;
+
if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
e = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
return false;
}
}
@@ -474,15 +576,19 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
if (!getVersionFromDatabase(currentVersion)) {
LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data());
e = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
return false;
}
if (currentVersion.length()) {
LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
- } else {
+ } else if (!m_new || !m_creationCallback) {
LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
if (!setVersionInDatabase(m_expectedVersion)) {
LOG_ERROR("Failed to set version %s in database %s", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
e = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
return false;
}
currentVersion = m_expectedVersion;
@@ -497,17 +603,23 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
currentVersion = "";
}
- // FIXME: For now, the spec says that if the database has no version, it is valid for any "Expected version" string. That seems silly and I think it should be
- // changed, and here's where we would change it
- if (m_expectedVersion.length()) {
- if (currentVersion.length() && m_expectedVersion != currentVersion) {
- LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(),
- databaseDebugName().ascii().data(), currentVersion.ascii().data());
- e = INVALID_STATE_ERR;
- return false;
- }
+ // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
+ // If the expected version is the empty string, then we always return with whatever version of the database we have.
+ if ((!m_new || !m_creationCallback) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
+ LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(),
+ databaseDebugName().ascii().data(), currentVersion.ascii().data());
+ e = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
+ return false;
}
+ // All checks passed and we still have a handle to this database file.
+ // Make sure DatabaseThread closes it when DatabaseThread goes away.
+ m_opened = true;
+ if (m_scriptExecutionContext->databaseThread())
+ m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
+
return true;
}
@@ -534,32 +646,58 @@ void Database::scheduleTransaction()
{
ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
RefPtr<SQLTransaction> transaction;
- if (m_transactionQueue.tryGetMessage(transaction) && m_document->databaseThread()) {
- RefPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
+
+ if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) {
+ transaction = m_transactionQueue.first();
+ m_transactionQueue.removeFirst();
+ }
+
+ if (transaction && m_scriptExecutionContext->databaseThread()) {
+ OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
m_transactionInProgress = true;
- m_document->databaseThread()->scheduleTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
} else
m_transactionInProgress = false;
}
void Database::scheduleTransactionStep(SQLTransaction* transaction, bool immediately)
{
- if (!m_document->databaseThread())
+ if (!m_scriptExecutionContext->databaseThread())
return;
- RefPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
+ OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
if (immediately)
- m_document->databaseThread()->scheduleImmediateTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
else
- m_document->databaseThread()->scheduleTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
}
+class DeliverPendingCallbackTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction)
+ {
+ return new DeliverPendingCallbackTask(transaction);
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_transaction->performPendingCallback();
+ }
+
+private:
+ DeliverPendingCallbackTask(PassRefPtr<SQLTransaction> transaction)
+ : m_transaction(transaction)
+ {
+ }
+
+ RefPtr<SQLTransaction> m_transaction;
+};
+
void Database::scheduleTransactionCallback(SQLTransaction* transaction)
{
- transaction->ref();
- callOnMainThread(deliverPendingCallback, transaction);
+ m_scriptExecutionContext->postTask(DeliverPendingCallbackTask::create(transaction));
}
Vector<String> Database::performGetTableNames()
@@ -591,14 +729,19 @@ Vector<String> Database::performGetTableNames()
return tableNames;
}
+void Database::performCreationCallback()
+{
+ m_creationCallback->handleEvent(m_scriptExecutionContext.get(), this);
+}
+
SQLTransactionClient* Database::transactionClient() const
{
- return m_document->databaseThread()->transactionClient();
+ return m_scriptExecutionContext->databaseThread()->transactionClient();
}
SQLTransactionCoordinator* Database::transactionCoordinator() const
{
- return m_document->databaseThread()->transactionCoordinator();
+ return m_scriptExecutionContext->databaseThread()->transactionCoordinator();
}
String Database::version() const
@@ -609,24 +752,21 @@ String Database::version() const
return guidToVersionMap().get(m_guid).threadsafeCopy();
}
-void Database::deliverPendingCallback(void* context)
-{
- SQLTransaction* transaction = static_cast<SQLTransaction*>(context);
- transaction->performPendingCallback();
- transaction->deref(); // Was ref'd in scheduleTransactionCallback().
-}
-
Vector<String> Database::tableNames()
{
- if (!m_document->databaseThread())
- return Vector<String>();
- RefPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this);
+ // FIXME: Not using threadsafeCopy on these strings looks ok since threads take strict turns
+ // in dealing with them. However, if the code changes, this may not be true anymore.
+ Vector<String> result;
+ if (!m_scriptExecutionContext->databaseThread())
+ return result;
+
+ DatabaseTaskSynchronizer synchronizer;
+ OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
- task->lockForSynchronousScheduling();
- m_document->databaseThread()->scheduleImmediateTask(task);
- task->waitForSynchronousCompletion();
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
+ synchronizer.waitForTaskCompletion();
- return task->tableNames();
+ return result;
}
void Database::setExpectedVersion(const String& version)
@@ -639,9 +779,9 @@ void Database::setExpectedVersion(const String& version)
SecurityOrigin* Database::securityOrigin() const
{
- if (isMainThread())
+ if (scriptExecutionContext()->isContextThread())
return m_mainThreadSecurityOrigin.get();
- if (currentThread() == document()->databaseThread()->getThreadID())
+ if (currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID())
return m_databaseThreadSecurityOrigin.get();
return 0;
}
@@ -669,6 +809,6 @@ String Database::fileName() const
return m_filename.threadsafeCopy();
}
-#endif
+#endif // ENABLE(DATABASE)
-}
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/Database.h b/src/3rdparty/webkit/WebCore/storage/Database.h
index f275027e20..f7b88a27f8 100644
--- a/src/3rdparty/webkit/WebCore/storage/Database.h
+++ b/src/3rdparty/webkit/WebCore/storage/Database.h
@@ -30,7 +30,6 @@
#define Database_h
#if ENABLE(DATABASE)
-#include <wtf/MessageQueue.h>
#include "PlatformString.h"
#include "SecurityOrigin.h"
#include "SQLiteDatabase.h"
@@ -52,8 +51,9 @@
namespace WebCore {
class DatabaseAuthorizer;
+class DatabaseCallback;
class DatabaseThread;
-class Document;
+class ScriptExecutionContext;
class SQLResultSet;
class SQLTransactionCallback;
class SQLTransactionClient;
@@ -68,10 +68,16 @@ class Database : public ThreadSafeShared<Database> {
friend class SQLStatement;
friend class SQLTransaction;
public:
+ static void setIsAvailable(bool);
+ static bool isAvailable();
+
~Database();
// Direct support for the DOM API
- static PassRefPtr<Database> openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
+ static PassRefPtr<Database> openDatabase(ScriptExecutionContext* context, const String& name,
+ const String& expectedVersion, const String& displayName,
+ unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback,
+ ExceptionCode&);
String version() const;
void changeVersion(const String& oldVersion, const String& newVersion,
PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
@@ -88,7 +94,7 @@ public:
Vector<String> tableNames();
- Document* document() const { return m_document.get(); }
+ ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext.get(); }
SecurityOrigin* securityOrigin() const;
String stringIdentifier() const;
String displayName() const;
@@ -103,12 +109,15 @@ public:
void markAsDeletedAndClose();
bool deleted() const { return m_deleted; }
- void close();
+ enum ClosePolicy { DoNotRemoveDatabaseFromContext, RemoveDatabaseFromContext };
+ void close(ClosePolicy);
bool opened() const { return m_opened; }
void stop();
bool stopped() const { return m_stopped; }
+ bool isNew() const { return m_new; }
+
unsigned long long databaseSize() const;
unsigned long long maximumSize() const;
@@ -119,13 +128,15 @@ public:
bool performOpenAndVerify(ExceptionCode&);
Vector<String> performGetTableNames();
+ void performCreationCallback();
SQLTransactionClient* transactionClient() const;
SQLTransactionCoordinator* transactionCoordinator() const;
private:
- Database(Document* document, const String& name, const String& expectedVersion,
- const String& displayName, unsigned long estimatedSize);
+ Database(ScriptExecutionContext* context, const String& name,
+ const String& expectedVersion, const String& displayName,
+ unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback);
bool openAndVerifyVersion(ExceptionCode&);
@@ -133,13 +144,14 @@ private:
void scheduleTransactionCallback(SQLTransaction*);
void scheduleTransactionStep(SQLTransaction* transaction, bool immediately = false);
- MessageQueue<RefPtr<SQLTransaction> > m_transactionQueue;
+ Deque<RefPtr<SQLTransaction> > m_transactionQueue;
Mutex m_transactionInProgressMutex;
bool m_transactionInProgress;
+ bool m_isTransactionQueueEnabled;
static void deliverPendingCallback(void*);
- RefPtr<Document> m_document;
+ RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
RefPtr<SecurityOrigin> m_mainThreadSecurityOrigin;
RefPtr<SecurityOrigin> m_databaseThreadSecurityOrigin;
String m_name;
@@ -155,9 +167,13 @@ private:
bool m_opened;
+ bool m_new;
+
SQLiteDatabase m_sqliteDatabase;
RefPtr<DatabaseAuthorizer> m_databaseAuthorizer;
+ RefPtr<DatabaseCallback> m_creationCallback;
+
#ifndef NDEBUG
String databaseDebugName() const { return m_mainThreadSecurityOrigin->toString() + "::" + m_name; }
#endif
diff --git a/src/3rdparty/webkit/WebCore/storage/Database.idl b/src/3rdparty/webkit/WebCore/storage/Database.idl
index 6ca9c952b9..c8a537c1aa 100644
--- a/src/3rdparty/webkit/WebCore/storage/Database.idl
+++ b/src/3rdparty/webkit/WebCore/storage/Database.idl
@@ -29,7 +29,8 @@
module storage {
interface [
- Conditional=DATABASE
+ Conditional=DATABASE,
+ OmitConstructor
] Database {
readonly attribute DOMString version;
[Custom] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.cpp b/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.cpp
index 93f91067ff..6b6b1470a8 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.cpp
@@ -38,6 +38,7 @@ DatabaseAuthorizer::DatabaseAuthorizer()
: m_securityEnabled(false)
{
reset();
+ addWhitelistedFunctions();
}
void DatabaseAuthorizer::reset()
@@ -47,6 +48,69 @@ void DatabaseAuthorizer::reset()
m_readOnly = false;
}
+void DatabaseAuthorizer::addWhitelistedFunctions()
+{
+ // SQLite functions used to help implement some operations
+ // ALTER TABLE helpers
+ m_whitelistedFunctions.add("sqlite_rename_table");
+ m_whitelistedFunctions.add("sqlite_rename_trigger");
+ // GLOB helpers
+ m_whitelistedFunctions.add("glob");
+
+ // SQLite core functions
+ m_whitelistedFunctions.add("abs");
+ m_whitelistedFunctions.add("changes");
+ m_whitelistedFunctions.add("coalesce");
+ m_whitelistedFunctions.add("glob");
+ m_whitelistedFunctions.add("ifnull");
+ m_whitelistedFunctions.add("hex");
+ m_whitelistedFunctions.add("last_insert_rowid");
+ m_whitelistedFunctions.add("length");
+ m_whitelistedFunctions.add("like");
+ m_whitelistedFunctions.add("lower");
+ m_whitelistedFunctions.add("ltrim");
+ m_whitelistedFunctions.add("max");
+ m_whitelistedFunctions.add("min");
+ m_whitelistedFunctions.add("nullif");
+ m_whitelistedFunctions.add("quote");
+ m_whitelistedFunctions.add("replace");
+ m_whitelistedFunctions.add("round");
+ m_whitelistedFunctions.add("rtrim");
+ m_whitelistedFunctions.add("soundex");
+ m_whitelistedFunctions.add("sqlite_source_id");
+ m_whitelistedFunctions.add("sqlite_version");
+ m_whitelistedFunctions.add("substr");
+ m_whitelistedFunctions.add("total_changes");
+ m_whitelistedFunctions.add("trim");
+ m_whitelistedFunctions.add("typeof");
+ m_whitelistedFunctions.add("upper");
+ m_whitelistedFunctions.add("zeroblob");
+
+ // SQLite date and time functions
+ m_whitelistedFunctions.add("date");
+ m_whitelistedFunctions.add("time");
+ m_whitelistedFunctions.add("datetime");
+ m_whitelistedFunctions.add("julianday");
+ m_whitelistedFunctions.add("strftime");
+
+ // SQLite aggregate functions
+ // max() and min() are already in the list
+ m_whitelistedFunctions.add("avg");
+ m_whitelistedFunctions.add("count");
+ m_whitelistedFunctions.add("group_concat");
+ m_whitelistedFunctions.add("sum");
+ m_whitelistedFunctions.add("total");
+
+ // SQLite FTS functions
+ m_whitelistedFunctions.add("snippet");
+ m_whitelistedFunctions.add("offsets");
+ m_whitelistedFunctions.add("optimize");
+
+ // SQLite ICU functions
+ // like(), lower() and upper() are already in the list
+ m_whitelistedFunctions.add("regexp");
+}
+
int DatabaseAuthorizer::createTable(const String& tableName)
{
if (m_readOnly && m_securityEnabled)
@@ -199,21 +263,29 @@ int DatabaseAuthorizer::dropTempView(const String&)
return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
}
-int DatabaseAuthorizer::createVTable(const String&, const String&)
+int DatabaseAuthorizer::createVTable(const String& tableName, const String& moduleName)
{
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
+ // fts2 is used in Chromium
+ if (moduleName != "fts2")
+ return SQLAuthDeny;
+
m_lastActionChangedDatabase = true;
- return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+ return denyBasedOnTableName(tableName);
}
-int DatabaseAuthorizer::dropVTable(const String&, const String&)
+int DatabaseAuthorizer::dropVTable(const String& tableName, const String& moduleName)
{
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+ // fts2 is used in Chromium
+ if (moduleName != "fts2")
+ return SQLAuthDeny;
+
+ return denyBasedOnTableName(tableName);
}
int DatabaseAuthorizer::allowDelete(const String& tableName)
@@ -278,11 +350,11 @@ int DatabaseAuthorizer::allowDetach(const String&)
return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
}
-int DatabaseAuthorizer::allowFunction(const String&)
+int DatabaseAuthorizer::allowFunction(const String& functionName)
{
- // FIXME: Are there any of these we need to prevent? One might guess current_date, current_time, current_timestamp because
- // they would violate the "sandbox environment" part of 4.11.3, but scripts can generate the local client side information via
- // javascript directly, anyways. Are there any other built-ins we need to be worried about?
+ if (m_securityEnabled && !m_whitelistedFunctions.contains(functionName))
+ return SQLAuthDeny;
+
return SQLAuthAllow;
}
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.h b/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.h
index 248b659d81..037409e2f9 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.h
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseAuthorizer.h
@@ -28,6 +28,8 @@
#ifndef DatabaseAuthorizer_h
#define DatabaseAuthorizer_h
+#include "StringHash.h"
+#include <wtf/HashSet.h>
#include <wtf/PassRefPtr.h>
#include <wtf/Threading.h>
@@ -94,12 +96,15 @@ public:
private:
DatabaseAuthorizer();
+ void addWhitelistedFunctions();
int denyBasedOnTableName(const String&);
bool m_securityEnabled : 1;
bool m_lastActionWasInsert : 1;
bool m_lastActionChangedDatabase : 1;
bool m_readOnly : 1;
+
+ HashSet<String, CaseFoldingHash> m_whitelistedFunctions;
};
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseCallback.h b/src/3rdparty/webkit/WebCore/storage/DatabaseCallback.h
new file mode 100644
index 0000000000..2115a21df6
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseCallback.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DatabaseCallback_h
+#define DatabaseCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class Database;
+class ScriptExecutionContext;
+
+class DatabaseCallback : public ThreadSafeShared<DatabaseCallback> {
+public:
+ virtual ~DatabaseCallback() { }
+ virtual void handleEvent(ScriptExecutionContext*, Database*) = 0;
+};
+
+}
+
+#endif
+
+#endif // DatabaseCallback_h
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseDetails.h b/src/3rdparty/webkit/WebCore/storage/DatabaseDetails.h
index 9b0f506477..ceebd35250 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseDetails.h
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseDetails.h
@@ -41,6 +41,9 @@ public:
: m_expectedUsage(0)
, m_currentUsage(0)
{
+#ifndef NDEBUG
+ m_thread = currentThread();
+#endif
}
DatabaseDetails(const String& databaseName, const String& displayName, unsigned long long expectedUsage, unsigned long long currentUsage)
@@ -49,19 +52,27 @@ public:
, m_expectedUsage(expectedUsage)
, m_currentUsage(currentUsage)
{
+#ifndef NDEBUG
+ m_thread = currentThread();
+#endif
}
const String& name() const { return m_name; }
const String& displayName() const { return m_displayName; }
unsigned long long expectedUsage() const { return m_expectedUsage; }
unsigned long long currentUsage() const { return m_currentUsage; }
+#ifndef NDEBUG
+ ThreadIdentifier thread() const { return m_thread; }
+#endif
private:
String m_name;
String m_displayName;
unsigned long long m_expectedUsage;
unsigned long long m_currentUsage;
-
+#ifndef NDEBUG
+ ThreadIdentifier m_thread;
+#endif
};
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseTask.cpp b/src/3rdparty/webkit/WebCore/storage/DatabaseTask.cpp
index 755da7c487..20908027fd 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseTask.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseTask.cpp
@@ -35,9 +35,33 @@
namespace WebCore {
-DatabaseTask::DatabaseTask(Database* database)
+DatabaseTaskSynchronizer::DatabaseTaskSynchronizer()
+ : m_taskCompleted(false)
+{
+}
+
+void DatabaseTaskSynchronizer::waitForTaskCompletion()
+{
+ m_synchronousMutex.lock();
+ if (!m_taskCompleted)
+ m_synchronousCondition.wait(m_synchronousMutex);
+ m_synchronousMutex.unlock();
+}
+
+void DatabaseTaskSynchronizer::taskCompleted()
+{
+ m_synchronousMutex.lock();
+ m_taskCompleted = true;
+ m_synchronousCondition.signal();
+ m_synchronousMutex.unlock();
+}
+
+DatabaseTask::DatabaseTask(Database* database, DatabaseTaskSynchronizer* synchronizer)
: m_database(database)
+ , m_synchronizer(synchronizer)
+#ifndef NDEBUG
, m_complete(false)
+#endif
{
}
@@ -56,43 +80,19 @@ void DatabaseTask::performTask()
doPerformTask();
m_database->performPolicyChecks();
- if (m_synchronousMutex)
- m_synchronousMutex->lock();
-
- m_complete = true;
-
- if (m_synchronousMutex) {
- m_synchronousCondition->signal();
- m_synchronousMutex->unlock();
- }
-}
-
-void DatabaseTask::lockForSynchronousScheduling()
-{
- // Called from main thread.
- ASSERT(!m_synchronousMutex);
- ASSERT(!m_synchronousCondition);
- m_synchronousMutex.set(new Mutex);
- m_synchronousCondition.set(new ThreadCondition);
-}
-
-void DatabaseTask::waitForSynchronousCompletion()
-{
- // Called from main thread.
- m_synchronousMutex->lock();
- if (!m_complete)
- m_synchronousCondition->wait(*m_synchronousMutex);
- m_synchronousMutex->unlock();
+ if (m_synchronizer)
+ m_synchronizer->taskCompleted();
}
// *** DatabaseOpenTask ***
// Opens the database file and verifies the version matches the expected version.
-DatabaseOpenTask::DatabaseOpenTask(Database* database)
- : DatabaseTask(database)
- , m_code(0)
- , m_success(false)
+DatabaseOpenTask::DatabaseOpenTask(Database* database, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
+ : DatabaseTask(database, synchronizer)
+ , m_code(code)
+ , m_success(success)
{
+ ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous.
}
void DatabaseOpenTask::doPerformTask()
@@ -110,14 +110,15 @@ const char* DatabaseOpenTask::debugTaskName() const
// *** DatabaseCloseTask ***
// Closes the database.
-DatabaseCloseTask::DatabaseCloseTask(Database* database)
- : DatabaseTask(database)
+DatabaseCloseTask::DatabaseCloseTask(Database* database, DatabaseTaskSynchronizer* synchronizer)
+ : DatabaseTask(database, synchronizer)
{
}
void DatabaseCloseTask::doPerformTask()
{
- database()->close();
+ // Tell the database not to call back to the context thread; we'll handle it.
+ database()->close(Database::DoNotRemoveDatabaseFromContext);
}
#ifndef NDEBUG
@@ -131,7 +132,7 @@ const char* DatabaseCloseTask::debugTaskName() const
// Starts a transaction that will report its results via a callback.
DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransaction> transaction)
- : DatabaseTask(transaction->database())
+ : DatabaseTask(transaction->database(), 0)
, m_transaction(transaction)
{
}
@@ -159,9 +160,11 @@ const char* DatabaseTransactionTask::debugTaskName() const
// *** DatabaseTableNamesTask ***
// Retrieves a list of all tables in the database - for WebInspector support.
-DatabaseTableNamesTask::DatabaseTableNamesTask(Database* database)
- : DatabaseTask(database)
+DatabaseTableNamesTask::DatabaseTableNamesTask(Database* database, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names)
+ : DatabaseTask(database, synchronizer)
+ , m_tableNames(names)
{
+ ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous.
}
void DatabaseTableNamesTask::doPerformTask()
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseTask.h b/src/3rdparty/webkit/WebCore/storage/DatabaseTask.h
index 4aef892bd2..998e37346d 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseTask.h
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseTask.h
@@ -32,6 +32,7 @@
#include "ExceptionCode.h"
#include "PlatformString.h"
#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/Threading.h>
#include <wtf/Vector.h>
@@ -39,13 +40,32 @@
namespace WebCore {
class Database;
+class DatabaseTask;
class DatabaseThread;
class SQLValue;
class SQLCallback;
class SQLTransaction;
class VersionChangeCallback;
-class DatabaseTask : public ThreadSafeShared<DatabaseTask> {
+// Can be used to wait until DatabaseTask is completed.
+// Has to be passed into DatabaseTask::create to be associated with the task.
+class DatabaseTaskSynchronizer : public Noncopyable {
+public:
+ DatabaseTaskSynchronizer();
+
+ // Called from main thread to wait until task is completed.
+ void waitForTaskCompletion();
+
+ // Called by the task.
+ void taskCompleted();
+private:
+
+ bool m_taskCompleted;
+ Mutex m_synchronousMutex;
+ ThreadCondition m_synchronousCondition;
+};
+
+class DatabaseTask : public Noncopyable {
friend class Database;
public:
virtual ~DatabaseTask();
@@ -53,53 +73,50 @@ public:
void performTask();
Database* database() const { return m_database; }
- bool isComplete() const { return m_complete; }
protected:
- DatabaseTask(Database*);
+ DatabaseTask(Database*, DatabaseTaskSynchronizer*);
private:
virtual void doPerformTask() = 0;
-#ifndef NDEBUG
- virtual const char* debugTaskName() const = 0;
-#endif
-
- void lockForSynchronousScheduling();
- void waitForSynchronousCompletion();
Database* m_database;
+ DatabaseTaskSynchronizer* m_synchronizer;
- bool m_complete;
-
- OwnPtr<Mutex> m_synchronousMutex;
- OwnPtr<ThreadCondition> m_synchronousCondition;
+#ifndef NDEBUG
+ virtual const char* debugTaskName() const = 0;
+ bool m_complete;
+#endif
};
class DatabaseOpenTask : public DatabaseTask {
public:
- static PassRefPtr<DatabaseOpenTask> create(Database* db) { return adoptRef(new DatabaseOpenTask(db)); }
-
- ExceptionCode exceptionCode() const { return m_code; }
- bool openSuccessful() const { return m_success; }
+ static PassOwnPtr<DatabaseOpenTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
+ {
+ return new DatabaseOpenTask(db, synchronizer, code, success);
+ }
private:
- DatabaseOpenTask(Database*);
+ DatabaseOpenTask(Database*, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success);
virtual void doPerformTask();
#ifndef NDEBUG
virtual const char* debugTaskName() const;
#endif
- ExceptionCode m_code;
- bool m_success;
+ ExceptionCode& m_code;
+ bool& m_success;
};
class DatabaseCloseTask : public DatabaseTask {
public:
- static PassRefPtr<DatabaseCloseTask> create(Database* db) { return adoptRef(new DatabaseCloseTask(db)); }
+ static PassOwnPtr<DatabaseCloseTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer)
+ {
+ return new DatabaseCloseTask(db, synchronizer);
+ }
private:
- DatabaseCloseTask(Database*);
+ DatabaseCloseTask(Database*, DatabaseTaskSynchronizer*);
virtual void doPerformTask();
#ifndef NDEBUG
@@ -109,7 +126,11 @@ private:
class DatabaseTransactionTask : public DatabaseTask {
public:
- static PassRefPtr<DatabaseTransactionTask> create(PassRefPtr<SQLTransaction> transaction) { return adoptRef(new DatabaseTransactionTask(transaction)); }
+ // Transaction task is never synchronous, so no 'synchronizer' parameter.
+ static PassOwnPtr<DatabaseTransactionTask> create(PassRefPtr<SQLTransaction> transaction)
+ {
+ return new DatabaseTransactionTask(transaction);
+ }
SQLTransaction* transaction() const { return m_transaction.get(); }
@@ -127,19 +148,20 @@ private:
class DatabaseTableNamesTask : public DatabaseTask {
public:
- static PassRefPtr<DatabaseTableNamesTask> create(Database* db) { return adoptRef(new DatabaseTableNamesTask(db)); }
-
- Vector<String>& tableNames() { return m_tableNames; }
+ static PassOwnPtr<DatabaseTableNamesTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names)
+ {
+ return new DatabaseTableNamesTask(db, synchronizer, names);
+ }
private:
- DatabaseTableNamesTask(Database*);
+ DatabaseTableNamesTask(Database*, DatabaseTaskSynchronizer*, Vector<String>& names);
virtual void doPerformTask();
#ifndef NDEBUG
virtual const char* debugTaskName() const;
#endif
- Vector<String> m_tableNames;
+ Vector<String>& m_tableNames;
};
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseThread.cpp b/src/3rdparty/webkit/WebCore/storage/DatabaseThread.cpp
index 40c83ee116..ec6241ce1d 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseThread.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseThread.cpp
@@ -44,6 +44,7 @@ DatabaseThread::DatabaseThread()
: m_threadID(0)
, m_transactionClient(new SQLTransactionClient())
, m_transactionCoordinator(new SQLTransactionCoordinator())
+ , m_cleanupSync(0)
{
m_selfRef = this;
}
@@ -51,6 +52,7 @@ DatabaseThread::DatabaseThread()
DatabaseThread::~DatabaseThread()
{
// FIXME: Any cleanup required here? Since the thread deletes itself after running its detached course, I don't think so. Lets be sure.
+ ASSERT(terminationRequested());
}
bool DatabaseThread::start()
@@ -65,8 +67,10 @@ bool DatabaseThread::start()
return m_threadID;
}
-void DatabaseThread::requestTermination()
+void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync)
{
+ ASSERT(!m_cleanupSync);
+ m_cleanupSync = cleanupSync;
LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
m_queue.kill();
}
@@ -91,13 +95,8 @@ void* DatabaseThread::databaseThread()
}
AutodrainedPool pool;
- while (true) {
- RefPtr<DatabaseTask> task;
- if (!m_queue.waitForMessage(task))
- break;
-
+ while (OwnPtr<DatabaseTask> task = m_queue.waitForMessage()) {
task->performTask();
-
pool.cycle();
}
@@ -114,15 +113,20 @@ void* DatabaseThread::databaseThread()
openSetCopy.swap(m_openDatabaseSet);
DatabaseSet::iterator end = openSetCopy.end();
for (DatabaseSet::iterator it = openSetCopy.begin(); it != end; ++it)
- (*it)->close();
+ (*it)->close(Database::RemoveDatabaseFromContext);
}
// Detach the thread so its resources are no longer of any concern to anyone else
detachThread(m_threadID);
+ DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync;
+
// Clear the self refptr, possibly resulting in deletion
m_selfRef = 0;
+ if (cleanupSync) // Someone wanted to know when we were done cleaning up.
+ cleanupSync->taskCompleted();
+
return 0;
}
@@ -142,12 +146,12 @@ void DatabaseThread::recordDatabaseClosed(Database* database)
m_openDatabaseSet.remove(database);
}
-void DatabaseThread::scheduleTask(PassRefPtr<DatabaseTask> task)
+void DatabaseThread::scheduleTask(PassOwnPtr<DatabaseTask> task)
{
m_queue.append(task);
}
-void DatabaseThread::scheduleImmediateTask(PassRefPtr<DatabaseTask> task)
+void DatabaseThread::scheduleImmediateTask(PassOwnPtr<DatabaseTask> task)
{
m_queue.prepend(task);
}
@@ -155,7 +159,7 @@ void DatabaseThread::scheduleImmediateTask(PassRefPtr<DatabaseTask> task)
class SameDatabasePredicate {
public:
SameDatabasePredicate(const Database* database) : m_database(database) { }
- bool operator()(RefPtr<DatabaseTask>& task) const { return task->database() == m_database; }
+ bool operator()(DatabaseTask* task) const { return task->database() == m_database; }
private:
const Database* m_database;
};
@@ -167,6 +171,5 @@ void DatabaseThread::unscheduleDatabaseTasks(Database* database)
SameDatabasePredicate predicate(database);
m_queue.removeIf(predicate);
}
-
} // namespace WebCore
#endif
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseThread.h b/src/3rdparty/webkit/WebCore/storage/DatabaseThread.h
index 83b1baf558..3702619dc4 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseThread.h
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseThread.h
@@ -34,6 +34,7 @@
#include <wtf/HashSet.h>
#include <wtf/MessageQueue.h>
#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Threading.h>
@@ -42,6 +43,7 @@ namespace WebCore {
class Database;
class DatabaseTask;
+class DatabaseTaskSynchronizer;
class Document;
class SQLTransactionClient;
class SQLTransactionCoordinator;
@@ -52,11 +54,11 @@ public:
~DatabaseThread();
bool start();
- void requestTermination();
+ void requestTermination(DatabaseTaskSynchronizer* cleanupSync);
bool terminationRequested() const;
- void scheduleTask(PassRefPtr<DatabaseTask>);
- void scheduleImmediateTask(PassRefPtr<DatabaseTask>); // This just adds the task to the front of the queue - the caller needs to be extremely careful not to create deadlocks when waiting for completion.
+ void scheduleTask(PassOwnPtr<DatabaseTask>);
+ void scheduleImmediateTask(PassOwnPtr<DatabaseTask>); // This just adds the task to the front of the queue - the caller needs to be extremely careful not to create deadlocks when waiting for completion.
void unscheduleDatabaseTasks(Database*);
void recordDatabaseOpen(Database*);
@@ -76,7 +78,7 @@ private:
ThreadIdentifier m_threadID;
RefPtr<DatabaseThread> m_selfRef;
- MessageQueue<RefPtr<DatabaseTask> > m_queue;
+ MessageQueue<DatabaseTask> m_queue;
// This set keeps track of the open databases that have been used on this thread.
typedef HashSet<RefPtr<Database> > DatabaseSet;
@@ -84,6 +86,7 @@ private:
OwnPtr<SQLTransactionClient> m_transactionClient;
OwnPtr<SQLTransactionCoordinator> m_transactionCoordinator;
+ DatabaseTaskSynchronizer* m_cleanupSync;
};
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.cpp b/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.cpp
index c0c424209b..34b4567577 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.cpp
@@ -31,14 +31,15 @@
#if ENABLE(DATABASE)
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Database.h"
#include "DatabaseThread.h"
#include "DatabaseTrackerClient.h"
-#include "Document.h"
#include "Logging.h"
#include "OriginQuotaManager.h"
#include "Page.h"
+#include "ScriptExecutionContext.h"
#include "SecurityOrigin.h"
#include "SecurityOriginHash.h"
#include "SQLiteFileSystem.h"
@@ -50,13 +51,19 @@ using namespace std;
namespace WebCore {
-OriginQuotaManager& DatabaseTracker::originQuotaManager()
+OriginQuotaManager& DatabaseTracker::originQuotaManagerNoLock()
{
- populateOrigins();
ASSERT(m_quotaManager);
return *m_quotaManager;
}
+OriginQuotaManager& DatabaseTracker::originQuotaManager()
+{
+ MutexLocker lockDatabase(m_databaseGuard);
+ populateOrigins();
+ return originQuotaManagerNoLock();
+}
+
DatabaseTracker& DatabaseTracker::tracker()
{
DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ());
@@ -65,36 +72,30 @@ DatabaseTracker& DatabaseTracker::tracker()
DatabaseTracker::DatabaseTracker()
: m_client(0)
- , m_proposedDatabase(0)
-#ifndef NDEBUG
- , m_thread(currentThread())
-#endif
{
SQLiteFileSystem::registerSQLiteVFS();
}
void DatabaseTracker::setDatabaseDirectoryPath(const String& path)
{
- ASSERT(currentThread() == m_thread);
+ MutexLocker lockDatabase(m_databaseGuard);
ASSERT(!m_database.isOpen());
- m_databaseDirectoryPath = path;
+ m_databaseDirectoryPath = path.threadsafeCopy();
}
-const String& DatabaseTracker::databaseDirectoryPath() const
+String DatabaseTracker::databaseDirectoryPath() const
{
- ASSERT(currentThread() == m_thread);
- return m_databaseDirectoryPath;
+ return m_databaseDirectoryPath.threadsafeCopy();
}
String DatabaseTracker::trackerDatabasePath() const
{
- ASSERT(currentThread() == m_thread);
return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath, "Databases.db");
}
void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
if (m_database.isOpen())
return;
@@ -105,70 +106,98 @@ void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist)
if (!m_database.open(databasePath)) {
// FIXME: What do do here?
+ LOG_ERROR("Failed to open databasePath %s.", databasePath.ascii().data());
return;
}
+ m_database.disableThreadingChecks();
if (!m_database.tableExists("Origins")) {
if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) {
// FIXME: and here
+ LOG_ERROR("Failed to create Origins table");
}
}
if (!m_database.tableExists("Databases")) {
if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize INTEGER, path TEXT);")) {
// FIXME: and here
+ LOG_ERROR("Failed to create Databases table");
}
}
}
-bool DatabaseTracker::canEstablishDatabase(Document* document, const String& name, const String& displayName, unsigned long estimatedSize)
+bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* context, const String& name, const String& displayName, unsigned long estimatedSize)
{
- ASSERT(currentThread() == m_thread);
+ SecurityOrigin* origin = context->securityOrigin();
+ ProposedDatabase details;
- // Populate the origins before we establish a database; this guarantees that quotaForOrigin
- // can run on the database thread later.
- populateOrigins();
+ unsigned long long requirement;
+ unsigned long long tempUsage;
+ {
+ Locker<OriginQuotaManager> locker(originQuotaManager());
+ MutexLocker lockDatabase(m_databaseGuard);
- SecurityOrigin* origin = document->securityOrigin();
+ if (!canCreateDatabase(origin, name))
+ return false;
- // Since we're imminently opening a database within this Document's origin, make sure this origin is being tracked by the QuotaTracker
- // by fetching it's current usage now
- unsigned long long usage = usageForOrigin(origin);
+ recordCreatingDatabase(origin, name);
- // If a database already exists, ignore the passed-in estimated size and say it's OK.
- if (hasEntryForDatabase(origin, name))
- return true;
+ populateOrigins();
- // If the database will fit, allow its creation.
- unsigned long long requirement = usage + max(1UL, estimatedSize);
- if (requirement < usage)
- return false; // If the estimated size is so big it causes an overflow, don't allow creation.
+ // Since we're imminently opening a database within this context's origin, make sure this origin is being tracked by the QuotaTracker
+ // by fetching its current usage now.
+ unsigned long long usage = usageForOriginNoLock(origin);
+
+ // If a database already exists, ignore the passed-in estimated size and say it's OK.
+ if (hasEntryForDatabase(origin, name))
+ return true;
+
+ // If the database will fit, allow its creation.
+ requirement = usage + max(1UL, estimatedSize);
+ tempUsage = usage;
+ if (requirement < usage) {
+ doneCreatingDatabase(origin, name);
+ return false; // If the estimated size is so big it causes an overflow, don't allow creation.
+ }
+ if (requirement <= quotaForOriginNoLock(origin))
+ return true;
+
+ // Give the chrome client a chance to increase the quota.
+ // Temporarily make the details of the proposed database available, so the client can get at them.
+ // FIXME: We should really just pass the details into this call, rather than using m_proposedDatabases.
+ details = ProposedDatabase(origin->threadsafeCopy(), DatabaseDetails(name.threadsafeCopy(), displayName.threadsafeCopy(), estimatedSize, 0));
+ m_proposedDatabases.add(&details);
+ }
+ // Drop all locks before calling out; we don't know what they'll do.
+ context->databaseExceededQuota(name);
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ m_proposedDatabases.remove(&details);
+ }
+
+ // If the database will fit now, allow its creation.
if (requirement <= quotaForOrigin(origin))
return true;
- // Give the chrome client a chance to increase the quota.
- // Temporarily make the details of the proposed database available, so the client can get at them.
- Page* page = document->page();
- if (!page)
- return false;
- pair<SecurityOrigin*, DatabaseDetails> details(origin, DatabaseDetails(name, displayName, estimatedSize, 0));
- m_proposedDatabase = &details;
- page->chrome()->client()->exceededDatabaseQuota(document->frame(), name);
- m_proposedDatabase = 0;
+ doneCreatingDatabase(origin, name);
+ return false;
+}
- // If the database will fit now, allow its creation.
- return requirement <= quotaForOrigin(origin);
+bool DatabaseTracker::hasEntryForOriginNoLock(SecurityOrigin* origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(m_quotaMap);
+ return m_quotaMap->contains(origin);
}
bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread);
+ MutexLocker lockDatabase(m_databaseGuard);
populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
- return m_quotaMap->contains(origin);
+ return hasEntryForOriginNoLock(origin);
}
bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String& databaseIdentifier)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
openTrackerDatabase(false);
if (!m_database.isOpen())
return false;
@@ -185,7 +214,7 @@ bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String&
unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database)
{
- ASSERT(currentThread() == database->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID());
// The maximum size for a database is the full quota for its origin, minus the current usage within the origin,
// plus the current usage of the given database
Locker<OriginQuotaManager> locker(originQuotaManager());
@@ -195,16 +224,17 @@ unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* databa
String DatabaseTracker::originPath(SecurityOrigin* origin) const
{
- ASSERT(currentThread() == m_thread);
- return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath, origin->databaseIdentifier());
+ return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.threadsafeCopy(), origin->databaseIdentifier());
}
-String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists)
+String DatabaseTracker::fullPathForDatabaseNoLock(SecurityOrigin* origin, const String& name, bool createIfNotExists)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(!originQuotaManagerNoLock().tryLock());
- if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
- return String();
+ for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.begin(); iter != m_proposedDatabases.end(); ++iter)
+ if ((*iter)->first == origin && (*iter)->second.name() == name)
+ return String();
String originIdentifier = origin->databaseIdentifier();
String originPath = this->originPath(origin);
@@ -214,7 +244,6 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
return String();
// See if we have a path for this database yet
- openTrackerDatabase(false);
if (!m_database.isOpen())
return String();
SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
@@ -233,36 +262,42 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
return String();
if (result != SQLResultDone) {
- LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin->databaseIdentifier().ascii().data(), name.ascii().data());
+ LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", originIdentifier.ascii().data(), name.ascii().data());
return String();
}
statement.finalize();
- String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, origin->databaseIdentifier(), &m_database);
+ String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, originIdentifier, &m_database);
if (!addDatabase(origin, name, fileName))
return String();
// If this origin's quota is being tracked (open handle to a database in this origin), add this new database
// to the quota manager now
String fullFilePath = SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, fileName);
- {
- Locker<OriginQuotaManager> locker(originQuotaManager());
- if (originQuotaManager().tracksOrigin(origin))
- originQuotaManager().addDatabase(origin, name, fullFilePath);
- }
+ if (originQuotaManagerNoLock().tracksOrigin(origin))
+ originQuotaManagerNoLock().addDatabase(origin, name, fullFilePath);
return fullFilePath;
}
+String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists)
+{
+ Locker<OriginQuotaManager> locker(originQuotaManager());
+ MutexLocker lockDatabase(m_databaseGuard);
+ populateOrigins();
+
+ return fullPathForDatabaseNoLock(origin, name, createIfNotExists).threadsafeCopy();
+}
+
void DatabaseTracker::populateOrigins()
{
+ ASSERT(!m_databaseGuard.tryLock());
if (m_quotaMap)
return;
- ASSERT(currentThread() == m_thread);
-
m_quotaMap.set(new QuotaMap);
- m_quotaManager.set(new OriginQuotaManager);
+ if (!m_quotaManager)
+ m_quotaManager.set(new OriginQuotaManager);
openTrackerDatabase(false);
if (!m_database.isOpen())
@@ -270,30 +305,32 @@ void DatabaseTracker::populateOrigins()
SQLiteStatement statement(m_database, "SELECT origin, quota FROM Origins");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLResultOk) {
+ LOG_ERROR("Failed to prepare statement.");
return;
+ }
int result;
while ((result = statement.step()) == SQLResultRow) {
RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdentifier(statement.getColumnText(0));
- m_quotaMap->set(origin.get(), statement.getColumnInt64(1));
+ m_quotaMap->set(origin.get()->threadsafeCopy(), statement.getColumnInt64(1));
}
if (result != SQLResultDone)
- LOG_ERROR("Failed to read in all origins from the database");
+ LOG_ERROR("Failed to read in all origins from the database.");
}
void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin> >& result)
{
- ASSERT(currentThread() == m_thread);
+ MutexLocker lockDatabase(m_databaseGuard);
populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
+ ASSERT(m_quotaMap);
copyKeysToVector(*m_quotaMap, result);
}
-bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector)
+bool DatabaseTracker::databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
openTrackerDatabase(false);
if (!m_database.isOpen())
return false;
@@ -317,44 +354,65 @@ bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<Stri
return true;
}
-DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin)
+bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector)
{
- ASSERT(currentThread() == m_thread);
+ MutexLocker lockDatabase(m_databaseGuard);
+ Vector<String> temp;
+ if (!databaseNamesForOriginNoLock(origin, temp))
+ return false;
- if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
- return m_proposedDatabase->second;
+ for (Vector<String>::iterator iter = temp.begin(); iter != temp.end(); ++iter)
+ resultVector.append(iter->threadsafeCopy());
+ return true;
+}
+DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin)
+{
String originIdentifier = origin->databaseIdentifier();
+ String displayName;
+ int64_t expectedUsage;
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return DatabaseDetails();
- SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
- if (statement.prepare() != SQLResultOk)
- return DatabaseDetails();
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
- statement.bindText(1, originIdentifier);
- statement.bindText(2, name);
+ for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.begin(); iter != m_proposedDatabases.end(); ++iter)
+ if ((*iter)->first == origin && (*iter)->second.name() == name) {
+ ASSERT((*iter)->second.thread() == currentThread());
+ return (*iter)->second;
+ }
- int result = statement.step();
- if (result == SQLResultDone)
- return DatabaseDetails();
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return DatabaseDetails();
+ SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
+ if (statement.prepare() != SQLResultOk)
+ return DatabaseDetails();
+
+ statement.bindText(1, originIdentifier);
+ statement.bindText(2, name);
- if (result != SQLResultRow) {
- LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data());
- return DatabaseDetails();
+ int result = statement.step();
+ if (result == SQLResultDone)
+ return DatabaseDetails();
+
+ if (result != SQLResultRow) {
+ LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data());
+ return DatabaseDetails();
+ }
+ displayName = statement.getColumnText(0);
+ expectedUsage = statement.getColumnInt64(1);
}
- return DatabaseDetails(name, statement.getColumnText(0), statement.getColumnInt64(1), usageForDatabase(name, origin));
+ return DatabaseDetails(name, displayName, expectedUsage, usageForDatabase(name, origin));
}
void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& name, const String& displayName, unsigned long estimatedSize)
{
- ASSERT(currentThread() == m_thread);
-
String originIdentifier = origin->databaseIdentifier();
int64_t guid = 0;
+ MutexLocker lockDatabase(m_databaseGuard);
+
openTrackerDatabase(true);
if (!m_database.isOpen())
return;
@@ -402,7 +460,6 @@ void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n
unsigned long long DatabaseTracker::usageForDatabase(const String& name, SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread);
String path = fullPathForDatabase(origin, name, false);
if (path.isEmpty())
return 0;
@@ -424,18 +481,21 @@ void DatabaseTracker::addOpenDatabase(Database* database)
DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
if (!nameMap) {
nameMap = new DatabaseNameMap;
- m_openDatabaseMap->set(database->securityOrigin(), nameMap);
+ m_openDatabaseMap->set(database->securityOrigin()->threadsafeCopy(), nameMap);
}
DatabaseSet* databaseSet = nameMap->get(name);
if (!databaseSet) {
databaseSet = new DatabaseSet;
- nameMap->set(name, databaseSet);
+ nameMap->set(name.threadsafeCopy(), databaseSet);
}
databaseSet->add(database);
LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
+
+ MutexLocker lockDatabase(m_databaseGuard);
+ doneCreatingDatabase(database->securityOrigin(), database->stringIdentifier());
}
void DatabaseTracker::removeOpenDatabase(Database* database)
@@ -443,6 +503,8 @@ void DatabaseTracker::removeOpenDatabase(Database* database)
if (!database)
return;
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ MutexLocker lockDatabase(m_databaseGuard);
MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
if (!m_openDatabaseMap) {
@@ -478,94 +540,124 @@ void DatabaseTracker::removeOpenDatabase(Database* database)
m_openDatabaseMap->remove(database->securityOrigin());
delete nameMap;
+ originQuotaManagerNoLock().removeOrigin(database->securityOrigin());
}
-unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
+void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases)
{
- ASSERT(currentThread() == m_thread);
- Locker<OriginQuotaManager> locker(originQuotaManager());
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+ if (!m_openDatabaseMap)
+ return;
+
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
+ if (!nameMap)
+ return;
+
+ DatabaseSet* databaseSet = nameMap->get(name);
+ if (!databaseSet)
+ return;
+
+ for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
+ databases->add(*it);
+}
+
+unsigned long long DatabaseTracker::usageForOriginNoLock(SecurityOrigin* origin)
+{
+ ASSERT(!originQuotaManagerNoLock().tryLock());
// Use the OriginQuotaManager mechanism to calculate the usage
- if (originQuotaManager().tracksOrigin(origin))
- return originQuotaManager().diskUsage(origin);
+ if (originQuotaManagerNoLock().tracksOrigin(origin))
+ return originQuotaManagerNoLock().diskUsage(origin);
// If the OriginQuotaManager doesn't track this origin already, prime it to do so
- originQuotaManager().trackOrigin(origin);
+ originQuotaManagerNoLock().trackOrigin(origin);
Vector<String> names;
- databaseNamesForOrigin(origin, names);
+ databaseNamesForOriginNoLock(origin, names);
for (unsigned i = 0; i < names.size(); ++i)
- originQuotaManager().addDatabase(origin, names[i], fullPathForDatabase(origin, names[i], false));
+ originQuotaManagerNoLock().addDatabase(origin, names[i], fullPathForDatabaseNoLock(origin, names[i], false));
- if (!originQuotaManager().tracksOrigin(origin))
+ if (!originQuotaManagerNoLock().tracksOrigin(origin))
return 0;
- return originQuotaManager().diskUsage(origin);
+ return originQuotaManagerNoLock().diskUsage(origin);
+}
+
+unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
+{
+ Locker<OriginQuotaManager> locker(originQuotaManager());
+
+ return usageForOriginNoLock(origin);
+}
+
+unsigned long long DatabaseTracker::quotaForOriginNoLock(SecurityOrigin* origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(m_quotaMap);
+ return m_quotaMap->get(origin);
}
unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread || m_quotaMap);
+ MutexLocker lockDatabase(m_databaseGuard);
populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
- return m_quotaMap->get(origin);
+ return quotaForOriginNoLock(origin);
}
void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota)
{
- ASSERT(currentThread() == m_thread);
- if (quotaForOrigin(origin) == quota)
+ MutexLocker lockDatabase(m_databaseGuard);
+
+ populateOrigins();
+ if (quotaForOriginNoLock(origin) == quota)
return;
openTrackerDatabase(true);
if (!m_database.isOpen())
return;
- {
- MutexLocker lockQuotaMap(m_quotaMapGuard);
-
- if (!m_quotaMap->contains(origin)) {
- SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
- if (statement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
- } else {
- statement.bindText(1, origin->databaseIdentifier());
- statement.bindInt64(2, quota);
-
- if (statement.step() != SQLResultDone)
- LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
- }
+ if (!m_quotaMap->contains(origin)) {
+ SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
+ if (statement.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
} else {
- SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
- bool error = statement.prepare() != SQLResultOk;
- if (!error) {
- statement.bindInt64(1, quota);
- statement.bindText(2, origin->databaseIdentifier());
-
- error = !statement.executeCommand();
- }
+ statement.bindText(1, origin->databaseIdentifier());
+ statement.bindInt64(2, quota);
- if (error)
- LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
+ if (statement.step() != SQLResultDone)
+ LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
+ }
+ } else {
+ SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
+ bool error = statement.prepare() != SQLResultOk;
+ if (!error) {
+ statement.bindInt64(1, quota);
+ statement.bindText(2, origin->databaseIdentifier());
+
+ error = !statement.executeCommand();
}
- // FIXME: Is it really OK to update the quota in memory if we failed to update it on disk?
- m_quotaMap->set(origin, quota);
+ if (error)
+ LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
}
+ // FIXME: Is it really OK to update the quota in memory if we failed to update it on disk?
+ m_quotaMap->set(origin->threadsafeCopy(), quota);
+
if (m_client)
m_client->dispatchDidModifyOrigin(origin);
}
bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, const String& path)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(m_quotaMap);
openTrackerDatabase(true);
if (!m_database.isOpen())
return false;
// New database should never be added until the origin has been established
- ASSERT(hasEntryForOrigin(origin));
+ ASSERT(hasEntryForOriginNoLock(origin));
SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
@@ -589,8 +681,6 @@ bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co
void DatabaseTracker::deleteAllDatabases()
{
- ASSERT(currentThread() == m_thread);
-
Vector<RefPtr<SecurityOrigin> > originsCopy;
origins(originsCopy);
@@ -598,19 +688,30 @@ void DatabaseTracker::deleteAllDatabases()
deleteOrigin(originsCopy[i].get());
}
+// It is the caller's responsibility to make sure that nobody is trying to create, delete, open, or close databases in this origin while the deletion is
+// taking place.
void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return;
-
Vector<String> databaseNames;
- if (!databaseNamesForOrigin(origin, databaseNames)) {
- LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
- return;
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return;
+
+ if (!databaseNamesForOriginNoLock(origin, databaseNames)) {
+ LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
+ return;
+ }
+ if (!canDeleteOrigin(origin)) {
+ LOG_ERROR("Tried to delete an origin (%s) while either creating database in it or already deleting it", origin->databaseIdentifier().ascii().data());
+ ASSERT(false);
+ return;
+ }
+ recordDeletingOrigin(origin);
}
+ // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
for (unsigned i = 0; i < databaseNames.size(); ++i) {
if (!deleteDatabaseFile(origin, databaseNames[i])) {
// Even if the file can't be deleted, we want to try and delete the rest, don't return early here.
@@ -618,41 +719,45 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
}
}
- SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
- if (statement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ {
+ // To satisfy the lock hierarchy, we have to lock the originQuotaManager before m_databaseGuard if there's any chance we'll to lock both.
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ MutexLocker lockDatabase(m_databaseGuard);
+ SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
- statement.bindText(1, origin->databaseIdentifier());
+ doneDeletingOrigin(origin);
- if (!statement.executeCommand()) {
- LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ if (statement.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return;
+ }
- SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
- if (originStatement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ statement.bindText(1, origin->databaseIdentifier());
- originStatement.bindText(1, origin->databaseIdentifier());
+ if (!statement.executeCommand()) {
+ LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return;
+ }
- if (!originStatement.executeCommand()) {
- LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
+ if (originStatement.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return;
+ }
- SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin));
+ originStatement.bindText(1, origin->databaseIdentifier());
- RefPtr<SecurityOrigin> originPossiblyLastReference = origin;
- {
- MutexLocker lockQuotaMap(m_quotaMapGuard);
+ if (!originStatement.executeCommand()) {
+ LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return;
+ }
+
+ SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin));
+
+ RefPtr<SecurityOrigin> originPossiblyLastReference = origin;
m_quotaMap->remove(origin);
- Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
- originQuotaManager().removeOrigin(origin);
+ originQuotaManagerNoLock().removeOrigin(origin);
// If we removed the last origin, do some additional deletion.
if (m_quotaMap->isEmpty()) {
@@ -661,30 +766,159 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath());
SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPath);
}
+
+ if (m_client) {
+ m_client->dispatchDidModifyOrigin(origin);
+ for (unsigned i = 0; i < databaseNames.size(); ++i)
+ m_client->dispatchDidModifyDatabase(origin, databaseNames[i]);
+ }
}
+}
- if (m_client) {
- m_client->dispatchDidModifyOrigin(origin);
- for (unsigned i = 0; i < databaseNames.size(); ++i)
- m_client->dispatchDidModifyDatabase(origin, databaseNames[i]);
+bool DatabaseTracker::canCreateDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ // Can't create a database while someone else is deleting it; there's a risk of leaving untracked database debris on the disk.
+ return !deletingDatabase(origin, name) && !deletingOrigin(origin);
+}
+
+void DatabaseTracker::recordCreatingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameCountMap* nameMap = m_beingCreated.get(origin);
+ if (!nameMap) {
+ nameMap = new NameCountMap();
+ m_beingCreated.set(origin->threadsafeCopy(), nameMap);
+ }
+ long count = nameMap->get(name);
+ nameMap->set(name.threadsafeCopy(), count + 1);
+}
+
+void DatabaseTracker::doneCreatingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameCountMap* nameMap = m_beingCreated.get(origin);
+ if (nameMap) {
+ long count = nameMap->get(name);
+ ASSERT(count > 0);
+ if (count <= 1) {
+ nameMap->remove(name);
+ if (nameMap->isEmpty()) {
+ m_beingCreated.remove(origin);
+ delete nameMap;
+ }
+ } else
+ nameMap->set(name, count - 1);
+ } else
+ ASSERT(false);
+}
+
+bool DatabaseTracker::creatingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameCountMap* nameMap = m_beingCreated.get(origin);
+ return nameMap && nameMap->get(name);
+}
+
+bool DatabaseTracker::canDeleteDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ return !creatingDatabase(origin, name) && !deletingDatabase(origin, name);
+}
+
+void DatabaseTracker::recordDeletingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(canDeleteDatabase(origin, name));
+ NameSet* nameSet = m_beingDeleted.get(origin);
+ if (!nameSet) {
+ nameSet = new NameSet();
+ m_beingDeleted.set(origin->threadsafeCopy(), nameSet);
}
+ ASSERT(!nameSet->contains(name));
+ nameSet->add(name.threadsafeCopy());
+}
+
+void DatabaseTracker::doneDeletingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameSet* nameSet = m_beingDeleted.get(origin);
+ if (nameSet) {
+ ASSERT(nameSet->contains(name));
+ nameSet->remove(name);
+ if (nameSet->isEmpty()) {
+ m_beingDeleted.remove(origin);
+ delete nameSet;
+ }
+ } else {
+ ASSERT(false);
+ }
+}
+
+bool DatabaseTracker::deletingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameSet* nameSet = m_beingDeleted.get(origin);
+ return nameSet && nameSet->contains(name);
+}
+
+bool DatabaseTracker::canDeleteOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ return !(deletingOrigin(origin) || m_beingCreated.get(origin));
+}
+
+bool DatabaseTracker::deletingOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ return m_originsBeingDeleted.contains(origin);
+}
+
+void DatabaseTracker::recordDeletingOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(!deletingOrigin(origin));
+ m_originsBeingDeleted.add(origin->threadsafeCopy());
+}
+
+void DatabaseTracker::doneDeletingOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(deletingOrigin(origin));
+ m_originsBeingDeleted.remove(origin);
}
void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return;
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return;
+
+ if (!canDeleteDatabase(origin, name)) {
+ ASSERT(FALSE);
+ return;
+ }
+ recordDeletingDatabase(origin, name);
+ }
+ // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
if (!deleteDatabaseFile(origin, name)) {
LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data());
+ MutexLocker lockDatabase(m_databaseGuard);
+ doneDeletingDatabase(origin, name);
return;
}
+ // To satisfy the lock hierarchy, we have to lock the originQuotaManager before m_databaseGuard if there's any chance we'll to lock both.
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ MutexLocker lockDatabase(m_databaseGuard);
+
SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
if (statement.prepare() != SQLResultOk) {
LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
+ doneDeletingDatabase(origin, name);
return;
}
@@ -693,40 +927,46 @@ void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
if (!statement.executeCommand()) {
LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
+ doneDeletingDatabase(origin, name);
return;
}
- {
- Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
- originQuotaManager().removeDatabase(origin, name);
- }
+ originQuotaManagerNoLock().removeDatabase(origin, name);
if (m_client) {
m_client->dispatchDidModifyOrigin(origin);
m_client->dispatchDidModifyDatabase(origin, name);
}
+ doneDeletingDatabase(origin, name);
}
+// deleteDatabaseFile has to release locks between looking up the list of databases to close and closing them. While this is in progress, the caller
+// is responsible for making sure no new databases are opened in the file to be deleted.
bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& name)
{
- ASSERT(currentThread() == m_thread);
String fullPath = fullPathForDatabase(origin, name, false);
if (fullPath.isEmpty())
return true;
+#ifndef NDEBUG
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ ASSERT(deletingDatabase(origin, name) || deletingOrigin(origin));
+ }
+#endif
+
Vector<RefPtr<Database> > deletedDatabases;
- // Make sure not to hold the m_openDatabaseMapGuard mutex when calling
+ // Make sure not to hold the any locks when calling
// Database::markAsDeletedAndClose(), since that can cause a deadlock
// during the synchronous DatabaseThread call it triggers.
-
{
MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
if (m_openDatabaseMap) {
// There are some open databases, lets check if they are for this origin.
DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
if (nameMap && nameMap->size()) {
- // There are some open databases for this origin, lets check
+ // There are some open databases for this origin, let's check
// if they are this database by name.
DatabaseSet* databaseSet = nameMap->get(name);
if (databaseSet && databaseSet->size()) {
@@ -747,7 +987,6 @@ bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& n
void DatabaseTracker::setClient(DatabaseTrackerClient* client)
{
- ASSERT(currentThread() == m_thread);
m_client = client;
}
@@ -757,7 +996,7 @@ static Mutex& notificationMutex()
return mutex;
}
-typedef Vector<pair<SecurityOrigin*, String> > NotificationQueue;
+typedef Vector<pair<RefPtr<SecurityOrigin>, String> > NotificationQueue;
static NotificationQueue& notificationQueue()
{
@@ -769,7 +1008,7 @@ void DatabaseTracker::scheduleNotifyDatabaseChanged(SecurityOrigin* origin, cons
{
MutexLocker locker(notificationMutex());
- notificationQueue().append(pair<SecurityOrigin*, String>(origin, name.crossThreadString()));
+ notificationQueue().append(pair<RefPtr<SecurityOrigin>, String>(origin->threadsafeCopy(), name.crossThreadString()));
scheduleForNotification();
}
@@ -804,7 +1043,7 @@ void DatabaseTracker::notifyDatabasesChanged(void*)
return;
for (unsigned i = 0; i < notifications.size(); ++i)
- theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first, notifications[i].second);
+ theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first.get(), notifications[i].second);
}
diff --git a/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.h b/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.h
index 85e4858ad0..79419660ed 100644
--- a/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.h
+++ b/src/3rdparty/webkit/WebCore/storage/DatabaseTracker.h
@@ -31,41 +31,71 @@
#if ENABLE(DATABASE)
-#include "DatabaseDetails.h"
#include "PlatformString.h"
-#include "SQLiteDatabase.h"
#include "StringHash.h"
+#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
+
+#if !PLATFORM(CHROMIUM)
+#include "DatabaseDetails.h"
+#include "SQLiteDatabase.h"
#include <wtf/OwnPtr.h>
+#endif // !PLATFORM(CHROMIUM)
namespace WebCore {
class Database;
-class DatabaseTrackerClient;
-class Document;
-class OriginQuotaManager;
+class ScriptExecutionContext;
class SecurityOrigin;
struct SecurityOriginHash;
+
+#if !PLATFORM(CHROMIUM)
+class DatabaseTrackerClient;
+class OriginQuotaManager;
+
struct SecurityOriginTraits;
+#endif // !PLATFORM(CHROMIUM)
-class DatabaseTracker {
+class DatabaseTracker : public Noncopyable {
public:
- void setDatabaseDirectoryPath(const String&);
- const String& databaseDirectoryPath() const;
+ static DatabaseTracker& tracker();
+ // This singleton will potentially be used from multiple worker threads and the page's context thread simultaneously. To keep this safe, it's
+ // currently using 4 locks. In order to avoid deadlock when taking multiple locks, you must take them in the correct order:
+ // originQuotaManager() before m_databaseGuard or m_openDatabaseMapGuard
+ // m_databaseGuard before m_openDatabaseMapGuard
+ // notificationMutex() is currently independent of the other locks.
- bool canEstablishDatabase(Document*, const String& name, const String& displayName, unsigned long estimatedSize);
+ bool canEstablishDatabase(ScriptExecutionContext*, const String& name, const String& displayName, unsigned long estimatedSize);
void setDatabaseDetails(SecurityOrigin*, const String& name, const String& displayName, unsigned long estimatedSize);
String fullPathForDatabase(SecurityOrigin*, const String& name, bool createIfDoesNotExist = true);
+ void addOpenDatabase(Database*);
+ void removeOpenDatabase(Database*);
+ void getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases);
+
+ unsigned long long getMaxSizeForDatabase(const Database*);
+
+private:
+ DatabaseTracker();
+
+ typedef HashSet<Database*> DatabaseSet;
+ typedef HashMap<String, DatabaseSet*> DatabaseNameMap;
+ typedef HashMap<RefPtr<SecurityOrigin>, DatabaseNameMap*, SecurityOriginHash> DatabaseOriginMap;
+
+ Mutex m_openDatabaseMapGuard;
+ mutable OwnPtr<DatabaseOriginMap> m_openDatabaseMap;
+
+#if !PLATFORM(CHROMIUM)
+public:
+ void setDatabaseDirectoryPath(const String&);
+ String databaseDirectoryPath() const;
+
void origins(Vector<RefPtr<SecurityOrigin> >& result);
bool databaseNamesForOrigin(SecurityOrigin*, Vector<String>& result);
DatabaseDetails detailsForNameAndOrigin(const String&, SecurityOrigin*);
- void addOpenDatabase(Database*);
- void removeOpenDatabase(Database*);
-
unsigned long long usageForDatabase(const String&, SecurityOrigin*);
unsigned long long usageForOrigin(SecurityOrigin*);
unsigned long long quotaForOrigin(SecurityOrigin*);
@@ -82,14 +112,16 @@ public:
OriginQuotaManager& originQuotaManager();
- static DatabaseTracker& tracker();
bool hasEntryForOrigin(SecurityOrigin*);
- unsigned long long getMaxSizeForDatabase(const Database*);
-
private:
- DatabaseTracker();
+ OriginQuotaManager& originQuotaManagerNoLock();
+ bool hasEntryForOriginNoLock(SecurityOrigin* origin);
+ String fullPathForDatabaseNoLock(SecurityOrigin*, const String& name, bool createIfDoesNotExist);
+ bool databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector);
+ unsigned long long usageForOriginNoLock(SecurityOrigin* origin);
+ unsigned long long quotaForOriginNoLock(SecurityOrigin* origin);
String trackerDatabasePath() const;
void openTrackerDatabase(bool createIfDoesNotExist);
@@ -103,33 +135,44 @@ private:
bool deleteDatabaseFile(SecurityOrigin*, const String& name);
+ // This lock protects m_database, m_quotaMap, m_proposedDatabases, m_databaseDirectoryPath, m_originsBeingDeleted, m_beingCreated, and m_beingDeleted.
+ Mutex m_databaseGuard;
SQLiteDatabase m_database;
typedef HashMap<RefPtr<SecurityOrigin>, unsigned long long, SecurityOriginHash> QuotaMap;
- Mutex m_quotaMapGuard;
mutable OwnPtr<QuotaMap> m_quotaMap;
- typedef HashSet<Database*> DatabaseSet;
- typedef HashMap<String, DatabaseSet*> DatabaseNameMap;
- typedef HashMap<RefPtr<SecurityOrigin>, DatabaseNameMap*, SecurityOriginHash> DatabaseOriginMap;
-
- Mutex m_openDatabaseMapGuard;
- mutable OwnPtr<DatabaseOriginMap> m_openDatabaseMap;
-
OwnPtr<OriginQuotaManager> m_quotaManager;
String m_databaseDirectoryPath;
DatabaseTrackerClient* m_client;
- std::pair<SecurityOrigin*, DatabaseDetails>* m_proposedDatabase;
-
-#ifndef NDEBUG
- ThreadIdentifier m_thread;
-#endif
+ typedef std::pair<RefPtr<SecurityOrigin>, DatabaseDetails> ProposedDatabase;
+ HashSet<ProposedDatabase*> m_proposedDatabases;
+
+ typedef HashMap<String, long> NameCountMap;
+ typedef HashMap<RefPtr<SecurityOrigin>, NameCountMap*, SecurityOriginHash> CreateSet;
+ CreateSet m_beingCreated;
+ typedef HashSet<String> NameSet;
+ HashMap<RefPtr<SecurityOrigin>, NameSet*, SecurityOriginHash> m_beingDeleted;
+ HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash> m_originsBeingDeleted;
+ bool canCreateDatabase(SecurityOrigin *origin, const String& name);
+ void recordCreatingDatabase(SecurityOrigin *origin, const String& name);
+ void doneCreatingDatabase(SecurityOrigin *origin, const String& name);
+ bool creatingDatabase(SecurityOrigin *origin, const String& name);
+ bool canDeleteDatabase(SecurityOrigin *origin, const String& name);
+ void recordDeletingDatabase(SecurityOrigin *origin, const String& name);
+ void doneDeletingDatabase(SecurityOrigin *origin, const String& name);
+ bool deletingDatabase(SecurityOrigin *origin, const String& name);
+ bool canDeleteOrigin(SecurityOrigin *origin);
+ bool deletingOrigin(SecurityOrigin *origin);
+ void recordDeletingOrigin(SecurityOrigin *origin);
+ void doneDeletingOrigin(SecurityOrigin *origin);
static void scheduleForNotification();
static void notifyDatabasesChanged(void*);
+#endif // !PLATFORM(CHROMIUM)
};
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.h b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.h
new file mode 100644
index 0000000000..e8fd2dd236
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IDBDatabaseError_h
+#define IDBDatabaseError_h
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBDatabaseError : public RefCounted<IDBDatabaseError> {
+public:
+ static PassRefPtr<IDBDatabaseError> create()
+ {
+ return adoptRef(new IDBDatabaseError());
+ }
+ ~IDBDatabaseError() { }
+
+ unsigned short code() const { return m_code; }
+ void setCode(unsigned short value) { m_code = value; }
+ String message() const { return m_message; }
+ void setMessage(const String& value) { m_message = value; }
+
+private:
+ IDBDatabaseError() { }
+
+ unsigned short m_code;
+ String m_message;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseError_h
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.idl b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.idl
new file mode 100644
index 0000000000..6c6019cfea
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseError.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBDatabaseError {
+ attribute unsigned short code;
+ attribute DOMString message;
+ };
+
+}
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.h b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.h
new file mode 100644
index 0000000000..d94a7f9faf
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IDBDatabaseException_h
+#define IDBDatabaseException_h
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBDatabaseException : public RefCounted<IDBDatabaseException> {
+public:
+ static PassRefPtr<IDBDatabaseException> create()
+ {
+ return adoptRef(new IDBDatabaseException());
+ }
+ ~IDBDatabaseException() { }
+
+ unsigned short code() const { return m_code; }
+ void setCode(unsigned short value) { m_code = value; }
+ String message() const { return m_message; }
+ void setMessage(const String& value) { m_message = value; }
+
+private:
+ IDBDatabaseException() { }
+
+ unsigned short m_code;
+ String m_message;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseException_h
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.idl b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.idl
new file mode 100644
index 0000000000..898e5f9c13
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseException.idl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBDatabaseException {
+ const unsigned short UNKNOWN_ERR = 0;
+ const unsigned short NON_TRANSIENT_ERR = 1;
+ const unsigned short NOT_FOUND_ERR = 2;
+ const unsigned short CONSTRAINT_ERR = 3;
+ const unsigned short DATA_ERR = 4;
+ const unsigned short NOT_ALLOWED_ERR = 5;
+ const unsigned short SERIAL_ERR = 11;
+ const unsigned short RECOVERABLE_ERR = 21;
+ const unsigned short TRANSIENT_ERR = 31;
+ const unsigned short TIMEOUT_ERR = 32;
+ const unsigned short DEADLOCK_ERR = 33;
+ attribute unsigned short code;
+ attribute DOMString message;
+ };
+
+}
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.h b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.h
new file mode 100644
index 0000000000..859aae4f12
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IDBDatabaseRequest_h
+#define IDBDatabaseRequest_h
+
+#include <wtf/RefCounted.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBRequest;
+
+class IDBDatabaseRequest : public RefCounted<IDBDatabaseRequest> {
+public:
+ // FIXME: Write.
+ IDBRequest* request() const { return 0; }
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseRequest_h
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.idl b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.idl
new file mode 100644
index 0000000000..030bb6e5c7
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBDatabaseRequest.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBDatabaseRequest {
+ readonly attribute IDBRequest request;
+ // FIXME: Write.
+ };
+
+}
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBRequest.cpp b/src/3rdparty/webkit/WebCore/storage/IDBRequest.cpp
new file mode 100644
index 0000000000..1a2049949b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBRequest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "IDBRequest.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBDatabaseError.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+IDBRequest::IDBRequest(ScriptExecutionContext* context)
+ : ActiveDOMObject(context, this)
+{
+}
+
+IDBRequest::~IDBRequest()
+{
+}
+
+void IDBRequest::abort()
+{
+}
+
+EventTargetData* IDBRequest::eventTargetData()
+{
+ return 0;
+}
+
+EventTargetData* IDBRequest::ensureEventTargetData()
+{
+ return 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBRequest.h b/src/3rdparty/webkit/WebCore/storage/IDBRequest.h
new file mode 100644
index 0000000000..5f00aa8624
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBRequest.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IDBRequest_h
+#define IDBRequest_h
+
+#include "ActiveDOMObject.h"
+#include "EventTarget.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBDatabaseError;
+class SerializedScriptValue;
+
+class IDBRequest : public RefCounted<IDBRequest>, public ActiveDOMObject, public EventTarget {
+public:
+ static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context)
+ {
+ return adoptRef(new IDBRequest(context));
+ }
+ ~IDBRequest();
+
+ void abort();
+ unsigned short readyState() const { return m_readyState; }
+ IDBDatabaseError* error() const { return m_error.get(); }
+ SerializedScriptValue* result() const { return m_result.get(); }
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(success);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
+
+ using RefCounted<IDBRequest>::ref;
+ using RefCounted<IDBRequest>::deref;
+
+ // EventTarget interface
+ virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); }
+ virtual IDBRequest* toIDBRequest() { return this; }
+
+private:
+ explicit IDBRequest(ScriptExecutionContext* context);
+
+ // EventTarget interface
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+ virtual EventTargetData* eventTargetData();
+ virtual EventTargetData* ensureEventTargetData();
+
+ unsigned short m_readyState;
+ RefPtr<IDBDatabaseError> m_error;
+ RefPtr<SerializedScriptValue> m_result;
+
+ EventTargetData m_eventTargetData;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBRequest_h
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IDBRequest.idl b/src/3rdparty/webkit/WebCore/storage/IDBRequest.idl
new file mode 100644
index 0000000000..b34184c5ce
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IDBRequest.idl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE,
+ EventTarget
+ ] IDBRequest {
+ void abort();
+ const unsigned short INITIAL = 0;
+ const unsigned short LOADING = 1;
+ const unsigned short DONE = 2;
+ readonly attribute unsigned short readyState;
+ readonly attribute IDBDatabaseError error;
+ readonly attribute [CustomGetter] any result;
+ attribute EventListener onsuccess;
+ attribute EventListener onerror;
+ };
+
+}
diff --git a/src/3rdparty/webkit/WebCore/storage/IndexedDatabase.cpp b/src/3rdparty/webkit/WebCore/storage/IndexedDatabase.cpp
new file mode 100644
index 0000000000..167494e049
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IndexedDatabase.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "IndexedDatabase.h"
+
+#include "IndexedDatabaseImpl.h"
+
+#if PLATFORM(CHROMIUM)
+#error "Chromium should not compile this file and instead define its own version of this factory that navigates the multi-process boundry."
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+PassRefPtr<IndexedDatabase> IndexedDatabase::get()
+{
+ return IndexedDatabaseImpl::get();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IndexedDatabase.h b/src/3rdparty/webkit/WebCore/storage/IndexedDatabase.h
new file mode 100644
index 0000000000..e00f0558cc
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IndexedDatabase.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IndexedDatabase_h
+#define IndexedDatabase_h
+
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+// This class is shared by IndexedDatabaseRequest (async) and IndexedDatabaseSync (sync).
+// This is implemented by IndexedDatabaseImpl and optionally others (in order to proxy
+// calls across process barriers). All calls to these classes should be non-blocking and
+// trigger work on a background thread if necessary.
+class IndexedDatabase : public ThreadSafeShared<IndexedDatabase> {
+public:
+ static PassRefPtr<IndexedDatabase> get();
+ virtual ~IndexedDatabase() { }
+
+ virtual void open(const String& name, const String& description, bool modifyDatabase, ExceptionCode&) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IndexedDatabase_h
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.cpp b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.cpp
new file mode 100644
index 0000000000..cfba05dc59
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "IndexedDatabaseImpl.h"
+
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IndexedDatabaseImpl* IndexedDatabaseImpl::indexedDatabaseImpl = 0;
+
+PassRefPtr<IndexedDatabaseImpl> IndexedDatabaseImpl::get()
+{
+ if (!indexedDatabaseImpl)
+ indexedDatabaseImpl = new IndexedDatabaseImpl();
+ ASSERT(indexedDatabaseImpl);
+ return indexedDatabaseImpl;
+}
+
+IndexedDatabaseImpl::IndexedDatabaseImpl()
+{
+ // FIXME: Make this thread safe.
+ ASSERT(!indexedDatabaseImpl);
+ indexedDatabaseImpl = this;
+}
+
+IndexedDatabaseImpl::~IndexedDatabaseImpl()
+{
+ // FIXME: Make this thread safe.
+ ASSERT(indexedDatabaseImpl == this);
+ indexedDatabaseImpl = 0;
+}
+
+void IndexedDatabaseImpl::open(const String& name, const String& description, bool modifyDatabase, ExceptionCode&)
+{
+ // FIXME: Write.
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.h b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.h
new file mode 100644
index 0000000000..37bbc273bf
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseImpl.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IndexedDatabaseImpl_h
+#define IndexedDatabaseImpl_h
+
+#include "IndexedDatabase.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IndexedDatabaseImpl : public IndexedDatabase {
+public:
+ static PassRefPtr<IndexedDatabaseImpl> get();
+ virtual ~IndexedDatabaseImpl();
+
+ virtual void open(const String& name, const String& description, bool modifyDatabase, ExceptionCode&);
+
+private:
+ IndexedDatabaseImpl();
+
+ // We only create one instance of this class at a time.
+ static IndexedDatabaseImpl* indexedDatabaseImpl;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IndexedDatabaseImpl_h
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.cpp b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.cpp
new file mode 100644
index 0000000000..827493bf5c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "IndexedDatabaseRequest.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "ExceptionCode.h"
+#include "IDBRequest.h"
+
+namespace WebCore {
+
+IndexedDatabaseRequest::IndexedDatabaseRequest()
+{
+}
+
+IndexedDatabaseRequest::~IndexedDatabaseRequest()
+{
+}
+
+void IndexedDatabaseRequest::open(const String& name, const String& description, bool modifyDatabase, ExceptionCode& exception)
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.h b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.h
new file mode 100644
index 0000000000..74aada3276
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IndexedDatabaseRequest_h
+#define IndexedDatabaseRequest_h
+
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBRequest;
+
+class IndexedDatabaseRequest : public RefCounted<IndexedDatabaseRequest> {
+public:
+ static PassRefPtr<IndexedDatabaseRequest> create()
+ {
+ return adoptRef(new IndexedDatabaseRequest());
+ }
+ ~IndexedDatabaseRequest();
+
+ IDBRequest* request() const { return m_request.get(); }
+ void open(const String& name, const String& description, bool modifyDatabase, ExceptionCode&);
+
+private:
+ IndexedDatabaseRequest();
+
+ PassRefPtr<IDBRequest> m_request;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IndexedDatabaseRequest_h
+
diff --git a/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.idl b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.idl
new file mode 100644
index 0000000000..5f3b63e988
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/storage/IndexedDatabaseRequest.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IndexedDatabaseRequest {
+ readonly attribute IDBRequest request;
+ [Custom] void open(in DOMString name, in DOMString description, in optional boolean modifyDatabase, IDBDatabaseErrorCallback onerror, IDBDatabaseRequestCallback onsuccess)
+ raises(IDBDatabaseException);
+ };
+
+}
diff --git a/src/3rdparty/webkit/WebCore/storage/LocalStorageTask.h b/src/3rdparty/webkit/WebCore/storage/LocalStorageTask.h
index f03d851c76..dc3e7e2dac 100644
--- a/src/3rdparty/webkit/WebCore/storage/LocalStorageTask.h
+++ b/src/3rdparty/webkit/WebCore/storage/LocalStorageTask.h
@@ -28,8 +28,7 @@
#if ENABLE(DOM_STORAGE)
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
+#include <wtf/PassOwnPtr.h>
#include <wtf/Threading.h>
namespace WebCore {
@@ -38,15 +37,15 @@ namespace WebCore {
class LocalStorageThread;
// FIXME: Rename this class to StorageTask
- class LocalStorageTask : public ThreadSafeShared<LocalStorageTask> {
+ class LocalStorageTask : public Noncopyable {
public:
enum Type { AreaImport, AreaSync, TerminateThread };
~LocalStorageTask();
- static PassRefPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return adoptRef(new LocalStorageTask(AreaImport, area)); }
- static PassRefPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return adoptRef(new LocalStorageTask(AreaSync, area)); }
- static PassRefPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return adoptRef(new LocalStorageTask(TerminateThread, thread)); }
+ static PassOwnPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return new LocalStorageTask(AreaImport, area); }
+ static PassOwnPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return new LocalStorageTask(AreaSync, area); }
+ static PassOwnPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return new LocalStorageTask(TerminateThread, thread); }
void performTask();
diff --git a/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.cpp b/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.cpp
index 78640a92f7..d4a7b4cc63 100644
--- a/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.cpp
@@ -33,96 +33,70 @@
namespace WebCore {
-PassRefPtr<LocalStorageThread> LocalStorageThread::create()
+PassOwnPtr<LocalStorageThread> LocalStorageThread::create()
{
- return adoptRef(new LocalStorageThread);
+ return new LocalStorageThread;
}
LocalStorageThread::LocalStorageThread()
: m_threadID(0)
{
- m_selfRef = this;
}
-bool LocalStorageThread::start()
+LocalStorageThread::~LocalStorageThread()
{
- MutexLocker lock(m_threadCreationMutex);
-
- if (m_threadID)
- return true;
-
- m_threadID = createThread(LocalStorageThread::localStorageThreadStart, this, "WebCore: LocalStorage");
+ ASSERT(isMainThread());
+ ASSERT(!m_threadID);
+}
+bool LocalStorageThread::start()
+{
+ ASSERT(isMainThread());
+ if (!m_threadID)
+ m_threadID = createThread(LocalStorageThread::threadEntryPointCallback, this, "WebCore: LocalStorage");
return m_threadID;
}
-void* LocalStorageThread::localStorageThreadStart(void* thread)
+void* LocalStorageThread::threadEntryPointCallback(void* thread)
{
- return static_cast<LocalStorageThread*>(thread)->localStorageThread();
+ return static_cast<LocalStorageThread*>(thread)->threadEntryPoint();
}
-void* LocalStorageThread::localStorageThread()
+void* LocalStorageThread::threadEntryPoint()
{
- {
- // Wait for LocalStorageThread::start() to complete.
- MutexLocker lock(m_threadCreationMutex);
- }
-
- while (true) {
- RefPtr<LocalStorageTask> task;
- if (!m_queue.waitForMessage(task))
- break;
-
+ ASSERT(!isMainThread());
+ while (OwnPtr<LocalStorageTask> task = m_queue.waitForMessage())
task->performTask();
- }
-
- // Detach the thread so its resources are no longer of any concern to anyone else
- detachThread(m_threadID);
- m_threadID = 0;
-
- // Clear the self refptr, possibly resulting in deletion
- m_selfRef = 0;
return 0;
}
-void LocalStorageThread::scheduleImport(StorageAreaSync* area)
-{
- ASSERT(!m_queue.killed() && m_threadID);
- m_queue.append(LocalStorageTask::createImport(area));
-}
-
-void LocalStorageThread::scheduleSync(StorageAreaSync* area)
+void LocalStorageThread::scheduleTask(PassOwnPtr<LocalStorageTask> task)
{
+ ASSERT(isMainThread());
ASSERT(!m_queue.killed() && m_threadID);
- m_queue.append(LocalStorageTask::createSync(area));
+ m_queue.append(task);
}
void LocalStorageThread::terminate()
{
ASSERT(isMainThread());
-
- // Ideally we'd never be killing a thread that wasn't live, so ASSERT it.
- // But if we do in a release build, make sure to not wait on a condition that will never get signalled
ASSERT(!m_queue.killed() && m_threadID);
+ // Even in weird, exceptional cases, don't wait on a nonexistent thread to terminate.
if (!m_threadID)
return;
- MutexLocker locker(m_terminateLock);
-
+ void* returnValue;
m_queue.append(LocalStorageTask::createTerminate(this));
-
- m_terminateCondition.wait(m_terminateLock);
+ waitForThreadCompletion(m_threadID, &returnValue);
+ ASSERT(m_queue.killed());
+ m_threadID = 0;
}
void LocalStorageThread::performTerminate()
{
ASSERT(!isMainThread());
-
m_queue.kill();
-
- MutexLocker locker(m_terminateLock);
- m_terminateCondition.signal();
}
}
diff --git a/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.h b/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.h
index e9e2b58862..6f05911445 100644
--- a/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.h
+++ b/src/3rdparty/webkit/WebCore/storage/LocalStorageThread.h
@@ -30,6 +30,7 @@
#include <wtf/HashSet.h>
#include <wtf/MessageQueue.h>
+#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/Threading.h>
@@ -39,34 +40,27 @@ namespace WebCore {
class LocalStorageTask;
// FIXME: Rename this class to StorageThread
- class LocalStorageThread : public ThreadSafeShared<LocalStorageThread> {
+ class LocalStorageThread : public Noncopyable {
public:
- static PassRefPtr<LocalStorageThread> create();
+ static PassOwnPtr<LocalStorageThread> create();
+ ~LocalStorageThread();
bool start();
-
- void scheduleImport(StorageAreaSync*);
- void scheduleSync(StorageAreaSync*);
-
- // Called from the main thread to synchronously shut down this thread
void terminate();
- // Background thread part of the terminate procedure
+ void scheduleTask(PassOwnPtr<LocalStorageTask>);
+
+ // Background thread part of the terminate procedure.
void performTerminate();
private:
LocalStorageThread();
- static void* localStorageThreadStart(void*);
- void* localStorageThread();
+ // Called on background thread.
+ static void* threadEntryPointCallback(void*);
+ void* threadEntryPoint();
- Mutex m_threadCreationMutex;
ThreadIdentifier m_threadID;
- RefPtr<LocalStorageThread> m_selfRef;
-
- MessageQueue<RefPtr<LocalStorageTask> > m_queue;
-
- Mutex m_terminateLock;
- ThreadCondition m_terminateCondition;
+ MessageQueue<LocalStorageTask> m_queue;
};
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.cpp b/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.cpp
index 30b32717ac..88f75b8b56 100644
--- a/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.cpp
@@ -42,6 +42,18 @@ OriginQuotaManager::OriginQuotaManager()
{
}
+bool OriginQuotaManager::tryLock()
+{
+ bool locked = m_usageRecordGuard.tryLock();
+#ifndef NDEBUG
+ if (locked)
+ m_usageRecordGuardLocked = true;
+ else
+ ASSERT(m_usageRecordGuardLocked);
+#endif
+ return locked;
+}
+
void OriginQuotaManager::lock()
{
m_usageRecordGuard.lock();
@@ -63,7 +75,7 @@ void OriginQuotaManager::trackOrigin(PassRefPtr<SecurityOrigin> origin)
ASSERT(m_usageRecordGuardLocked);
ASSERT(!m_usageMap.contains(origin.get()));
- m_usageMap.set(origin, new OriginUsageRecord);
+ m_usageMap.set(origin->threadsafeCopy(), new OriginUsageRecord);
}
bool OriginQuotaManager::tracksOrigin(SecurityOrigin* origin) const
diff --git a/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.h b/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.h
index 2e3615d271..33c201af2b 100644
--- a/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.h
+++ b/src/3rdparty/webkit/WebCore/storage/OriginQuotaManager.h
@@ -45,6 +45,7 @@ class OriginQuotaManager : public Noncopyable {
public:
OriginQuotaManager();
+ bool tryLock();
void lock();
void unlock();
diff --git a/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.cpp b/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.cpp
index 684df530f2..8128a1bfa7 100644
--- a/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.cpp
@@ -42,8 +42,8 @@ OriginUsageRecord::OriginUsageRecord()
void OriginUsageRecord::addDatabase(const String& identifier, const String& fullPath)
{
ASSERT(!m_databaseMap.contains(identifier));
- ASSERT_ARG(identifier, identifier.impl()->refCount() == 1);
- ASSERT_ARG(fullPath, fullPath.impl()->refCount() == 1);
+ ASSERT_ARG(identifier, identifier.impl()->hasOneRef());
+ ASSERT_ARG(fullPath, fullPath.impl()->hasOneRef());
m_databaseMap.set(identifier, DatabaseEntry(fullPath));
m_unknownSet.add(identifier);
@@ -63,7 +63,7 @@ void OriginUsageRecord::removeDatabase(const String& identifier)
void OriginUsageRecord::markDatabase(const String& identifier)
{
ASSERT(m_databaseMap.contains(identifier));
- ASSERT_ARG(identifier, identifier.impl()->refCount() == 1);
+ ASSERT_ARG(identifier, identifier.impl()->hasOneRef());
m_unknownSet.add(identifier);
m_cachedDiskUsageIsValid = false;
diff --git a/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.h b/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.h
index 609a793df4..25bddf2db2 100644
--- a/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.h
+++ b/src/3rdparty/webkit/WebCore/storage/OriginUsageRecord.h
@@ -40,7 +40,7 @@ namespace WebCore {
// Objects of this class can be used from multiple threads with external synchronization.
// String arguments are also supposed to be deeply copied by the caller when necessary.
-class OriginUsageRecord {
+class OriginUsageRecord : public Noncopyable {
public:
OriginUsageRecord();
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLError.idl b/src/3rdparty/webkit/WebCore/storage/SQLError.idl
index d889c5b8a2..503fe6f075 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLError.idl
+++ b/src/3rdparty/webkit/WebCore/storage/SQLError.idl
@@ -29,7 +29,8 @@
module storage {
interface [
- Conditional=DATABASE
+ Conditional=DATABASE,
+ OmitConstructor
] SQLError {
readonly attribute unsigned long code;
readonly attribute DOMString message;
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLResultSet.idl b/src/3rdparty/webkit/WebCore/storage/SQLResultSet.idl
index 1db07cdc1a..c98fff6371 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLResultSet.idl
+++ b/src/3rdparty/webkit/WebCore/storage/SQLResultSet.idl
@@ -29,7 +29,8 @@
module storage {
interface [
- Conditional=DATABASE
+ Conditional=DATABASE,
+ OmitConstructor
] SQLResultSet {
readonly attribute SQLResultSetRowList rows;
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLResultSetRowList.idl b/src/3rdparty/webkit/WebCore/storage/SQLResultSetRowList.idl
index 6a477e9071..7ae7a9c369 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLResultSetRowList.idl
+++ b/src/3rdparty/webkit/WebCore/storage/SQLResultSetRowList.idl
@@ -29,7 +29,8 @@
module storage {
interface [
- Conditional=DATABASE
+ Conditional=DATABASE,
+ OmitConstructor
] SQLResultSetRowList {
readonly attribute unsigned long length;
[Custom] DOMObject item(in unsigned long index);
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLTransaction.cpp b/src/3rdparty/webkit/WebCore/storage/SQLTransaction.cpp
index 165685b15e..a7c2558754 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLTransaction.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/SQLTransaction.cpp
@@ -35,11 +35,12 @@
#include "Database.h"
#include "DatabaseAuthorizer.h"
#include "DatabaseDetails.h"
-#include "Document.h"
+#include "DatabaseThread.h"
#include "ExceptionCode.h"
#include "Logging.h"
#include "Page.h"
#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
#include "Settings.h"
#include "SQLError.h"
#include "SQLiteTransaction.h"
@@ -83,6 +84,7 @@ SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback>
SQLTransaction::~SQLTransaction()
{
+ ASSERT(!m_sqliteTransaction);
}
void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e)
@@ -94,8 +96,7 @@ void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValu
bool readOnlyMode = m_readOnly;
if (!readOnlyMode) {
- Page* page = m_database->document()->page();
- if (!page || page->settings()->privateBrowsingEnabled())
+ if (m_database->scriptExecutionContext()->isDatabaseReadOnly())
readOnlyMode = true;
}
@@ -157,6 +158,10 @@ void SQLTransaction::checkAndHandleClosedDatabase()
m_statementQueue.clear();
m_nextStep = 0;
+ // The next steps should be executed only if we're on the DB thread.
+ if (currentThread() != database()->scriptExecutionContext()->databaseThread()->getThreadID())
+ return;
+
// The current SQLite transaction should be stopped, as well
if (m_sqliteTransaction) {
m_sqliteTransaction->stop();
@@ -204,6 +209,16 @@ void SQLTransaction::performPendingCallback()
(this->*m_nextStep)();
}
+void SQLTransaction::notifyDatabaseThreadIsShuttingDown()
+{
+ ASSERT(currentThread() == database()->scriptExecutionContext()->databaseThread()->getThreadID());
+
+ // If the transaction is in progress, we should roll it back here, since this is our last
+ // oportunity to do something related to this transaction on the DB thread.
+ // Clearing m_sqliteTransaction invokes SQLiteTransaction's destructor which does just that.
+ m_sqliteTransaction.clear();
+}
+
void SQLTransaction::acquireLock()
{
m_database->transactionCoordinator()->acquireLock(this);
@@ -302,7 +317,7 @@ void SQLTransaction::runStatements()
// If there is a series of statements queued up that are all successful and have no associated
// SQLStatementCallback objects, then we can burn through the queue
do {
- if (m_shouldRetryCurrentStatement) {
+ if (m_shouldRetryCurrentStatement && !m_sqliteTransaction->wasRolledBackBySqlite()) {
m_shouldRetryCurrentStatement = false;
// FIXME - Another place that needs fixing up after <rdar://problem/5628468> is addressed.
// See ::openTransactionAndPreflight() for discussion
@@ -382,8 +397,8 @@ bool SQLTransaction::runCurrentStatement()
void SQLTransaction::handleCurrentStatementError()
{
// Transaction Steps 6.error - Call the statement's error callback, but if there was no error callback,
- // jump to the transaction error callback
- if (m_currentStatement->hasStatementErrorCallback()) {
+ // or the transaction was rolled back, jump to the transaction error callback
+ if (m_currentStatement->hasStatementErrorCallback() && !m_sqliteTransaction->wasRolledBackBySqlite()) {
m_nextStep = &SQLTransaction::deliverStatementCallback;
LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this);
m_database->scheduleTransactionCallback(this);
@@ -492,6 +507,7 @@ void SQLTransaction::cleanupAfterSuccessCallback()
// There is no next step
LOG(StorageAPI, "Transaction %p is complete\n", this);
ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ m_sqliteTransaction.clear();
m_nextStep = 0;
// Release the lock on this database
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLTransaction.h b/src/3rdparty/webkit/WebCore/storage/SQLTransaction.h
index 6d6a8d7b16..1b02d013be 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLTransaction.h
+++ b/src/3rdparty/webkit/WebCore/storage/SQLTransaction.h
@@ -80,6 +80,7 @@ public:
Database* database() { return m_database.get(); }
bool isReadOnly() { return m_readOnly; }
+ void notifyDatabaseThreadIsShuttingDown();
private:
SQLTransaction(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLTransaction.idl b/src/3rdparty/webkit/WebCore/storage/SQLTransaction.idl
index 5d4885c9c9..7d694e8777 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLTransaction.idl
+++ b/src/3rdparty/webkit/WebCore/storage/SQLTransaction.idl
@@ -29,7 +29,8 @@
module storage {
interface [
- Conditional=DATABASE
+ Conditional=DATABASE,
+ OmitConstructor
] SQLTransaction {
[Custom] void executeSql(in DOMString sqlStatement, in ObjectArray arguments, in SQLStatementCallback callback, in SQLStatementErrorCallback errorCallback);
};
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.cpp b/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.cpp
index 5918bd8ef0..6064c993c8 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.cpp
@@ -31,6 +31,9 @@
#include "config.h"
#include "SQLTransactionClient.h"
+#if ENABLE(DATABASE)
+
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Database.h"
#include "DatabaseThread.h"
@@ -44,7 +47,7 @@ namespace WebCore {
void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
{
- ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
Database* database = transaction->database();
DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(
database->securityOrigin(), database->stringIdentifier());
@@ -52,7 +55,7 @@ void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
{
- ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager());
Locker<OriginQuotaManager> locker(manager);
manager.markDatabase(transaction->database());
@@ -60,15 +63,15 @@ void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
{
- ASSERT(isMainThread());
+ ASSERT(transaction->database()->scriptExecutionContext()->isContextThread());
Database* database = transaction->database();
- Page* page = database->document()->page();
- ASSERT(page);
unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
- page->chrome()->client()->exceededDatabaseQuota(database->document()->frame(), database->stringIdentifier());
+ database->scriptExecutionContext()->databaseExceededQuota(database->stringIdentifier());
unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
return (newQuota > currentQuota);
}
}
+
+#endif // ENABLE(DATABASE)
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.h b/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.h
index 941c1638aa..801647ba28 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.h
+++ b/src/3rdparty/webkit/WebCore/storage/SQLTransactionClient.h
@@ -31,13 +31,17 @@
#ifndef SQLTransactionClient_h
#define SQLTransactionClient_h
+#if ENABLE(DATABASE)
+
+#include <wtf/Noncopyable.h>
+
namespace WebCore {
class SQLTransaction;
// A client to the SQLTransaction class. Allows SQLTransaction to notify interested
// parties that certain things have happened in a transaction.
- class SQLTransactionClient {
+ class SQLTransactionClient : public Noncopyable {
public:
void didCommitTransaction(SQLTransaction*);
void didExecuteStatement(SQLTransaction*);
@@ -45,4 +49,6 @@ namespace WebCore {
};
}
+#endif // ENABLE(DATABASE)
+
#endif // SQLTransactionClient_h
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.cpp b/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.cpp
index 30b0c4a895..0fe5bda9c3 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.cpp
@@ -31,6 +31,8 @@
#include "config.h"
#include "SQLTransactionCoordinator.h"
+#if ENABLE(DATABASE)
+
#include "CString.h"
#include "Database.h"
#include "SQLTransaction.h"
@@ -107,8 +109,24 @@ void SQLTransactionCoordinator::releaseLock(SQLTransaction* transaction)
void SQLTransactionCoordinator::shutdown()
{
+ // Notify all transactions in progress that the database thread is shutting down
+ for (CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.begin();
+ coordinationInfoIterator != m_coordinationInfoMap.end(); ++coordinationInfoIterator) {
+ CoordinationInfo& info = coordinationInfoIterator->second;
+ if (info.activeWriteTransaction)
+ info.activeWriteTransaction->notifyDatabaseThreadIsShuttingDown();
+ for (HashSet<RefPtr<SQLTransaction> >::iterator activeReadTransactionsIterator =
+ info.activeReadTransactions.begin();
+ activeReadTransactionsIterator != info.activeReadTransactions.end();
+ ++activeReadTransactionsIterator) {
+ (*activeReadTransactionsIterator)->notifyDatabaseThreadIsShuttingDown();
+ }
+ }
+
// Clean up all pending transactions for all databases
m_coordinationInfoMap.clear();
}
-}
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.h b/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.h
index 20cc863881..a51084f211 100644
--- a/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.h
+++ b/src/3rdparty/webkit/WebCore/storage/SQLTransactionCoordinator.h
@@ -31,6 +31,8 @@
#ifndef SQLTransactionCoordinator_h
#define SQLTransactionCoordinator_h
+#if ENABLE(DATABASE)
+
#include "CString.h"
#include "StringHash.h"
#include <wtf/Deque.h>
@@ -42,7 +44,7 @@ namespace WebCore {
class SQLTransaction;
- class SQLTransactionCoordinator {
+ class SQLTransactionCoordinator : public Noncopyable {
public:
void acquireLock(SQLTransaction*);
void releaseLock(SQLTransaction*);
@@ -62,4 +64,6 @@ namespace WebCore {
};
}
+#endif // ENABLE(DATABASE)
+
#endif // SQLTransactionCoordinator_h
diff --git a/src/3rdparty/webkit/WebCore/storage/Storage.idl b/src/3rdparty/webkit/WebCore/storage/Storage.idl
index 7127efd205..ffd1af15bb 100644
--- a/src/3rdparty/webkit/WebCore/storage/Storage.idl
+++ b/src/3rdparty/webkit/WebCore/storage/Storage.idl
@@ -26,7 +26,6 @@
module storage {
interface [
- GenerateConstructor,
HasNameGetter,
CustomDeleteProperty,
CustomGetPropertyNames,
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageArea.h b/src/3rdparty/webkit/WebCore/storage/StorageArea.h
index a64d44a035..6081240dd9 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageArea.h
+++ b/src/3rdparty/webkit/WebCore/storage/StorageArea.h
@@ -50,9 +50,9 @@ namespace WebCore {
virtual unsigned length() const = 0;
virtual String key(unsigned index) const = 0;
virtual String getItem(const String& key) const = 0;
- virtual void setItem(const String& key, const String& value, ExceptionCode& ec, Frame* sourceFrame) = 0;
- virtual void removeItem(const String& key, Frame* sourceFrame) = 0;
- virtual void clear(Frame* sourceFrame) = 0;
+ virtual String setItem(const String& key, const String& value, ExceptionCode& ec, Frame* sourceFrame) = 0;
+ virtual String removeItem(const String& key, Frame* sourceFrame) = 0;
+ virtual bool clear(Frame* sourceFrame) = 0;
virtual bool contains(const String& key) const = 0;
};
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.cpp b/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.cpp
index 612cb5fde2..aa04781489 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.cpp
@@ -30,6 +30,7 @@
#include "ExceptionCode.h"
#include "Frame.h"
+#include "Page.h"
#include "Settings.h"
#include "StorageAreaSync.h"
#include "StorageEventDispatcher.h"
@@ -64,7 +65,7 @@ StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOri
// FIXME: If there's no backing storage for LocalStorage, the default WebKit behavior should be that of private browsing,
// not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
if (m_storageSyncManager) {
- m_storageAreaSync = StorageAreaSync::create(m_storageSyncManager, this);
+ m_storageAreaSync = StorageAreaSync::create(m_storageSyncManager, this, m_securityOrigin->databaseIdentifier());
ASSERT(m_storageAreaSync);
}
}
@@ -106,6 +107,8 @@ static bool privateBrowsingEnabled(Frame* frame)
unsigned StorageAreaImpl::length() const
{
ASSERT(!m_isShutdown);
+ blockUntilImportComplete();
+
return m_storageMap->length();
}
@@ -113,6 +116,7 @@ String StorageAreaImpl::key(unsigned index) const
{
ASSERT(!m_isShutdown);
blockUntilImportComplete();
+
return m_storageMap->key(index);
}
@@ -124,7 +128,7 @@ String StorageAreaImpl::getItem(const String& key) const
return m_storageMap->getItem(key);
}
-void StorageAreaImpl::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame)
+String StorageAreaImpl::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame)
{
ASSERT(!m_isShutdown);
ASSERT(!value.isNull());
@@ -132,57 +136,61 @@ void StorageAreaImpl::setItem(const String& key, const String& value, ExceptionC
if (privateBrowsingEnabled(frame)) {
ec = QUOTA_EXCEEDED_ERR;
- return;
+ return String();
}
String oldValue;
bool quotaException;
RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException);
+ if (newMap)
+ m_storageMap = newMap.release();
if (quotaException) {
ec = QUOTA_EXCEEDED_ERR;
- return;
+ return oldValue;
}
- if (newMap)
- m_storageMap = newMap.release();
+ if (oldValue == value)
+ return oldValue;
- // Only notify the client if an item was actually changed
- if (oldValue != value) {
- if (m_storageAreaSync)
- m_storageAreaSync->scheduleItemForSync(key, value);
- StorageEventDispatcher::dispatch(key, oldValue, value, m_storageType, m_securityOrigin.get(), frame);
- }
+ if (m_storageAreaSync)
+ m_storageAreaSync->scheduleItemForSync(key, value);
+ StorageEventDispatcher::dispatch(key, oldValue, value, m_storageType, m_securityOrigin.get(), frame);
+ return oldValue;
}
-void StorageAreaImpl::removeItem(const String& key, Frame* frame)
+String StorageAreaImpl::removeItem(const String& key, Frame* frame)
{
ASSERT(!m_isShutdown);
blockUntilImportComplete();
if (privateBrowsingEnabled(frame))
- return;
+ return String();
String oldValue;
RefPtr<StorageMap> newMap = m_storageMap->removeItem(key, oldValue);
if (newMap)
m_storageMap = newMap.release();
- // Only notify the client if an item was actually removed
- if (!oldValue.isNull()) {
- if (m_storageAreaSync)
- m_storageAreaSync->scheduleItemForSync(key, String());
- StorageEventDispatcher::dispatch(key, oldValue, String(), m_storageType, m_securityOrigin.get(), frame);
- }
+ if (oldValue.isNull())
+ return oldValue;
+
+ if (m_storageAreaSync)
+ m_storageAreaSync->scheduleItemForSync(key, String());
+ StorageEventDispatcher::dispatch(key, oldValue, String(), m_storageType, m_securityOrigin.get(), frame);
+ return oldValue;
}
-void StorageAreaImpl::clear(Frame* frame)
+bool StorageAreaImpl::clear(Frame* frame)
{
ASSERT(!m_isShutdown);
blockUntilImportComplete();
if (privateBrowsingEnabled(frame))
- return;
+ return false;
+
+ if (!m_storageMap->length())
+ return false;
unsigned quota = m_storageMap->quota();
m_storageMap = StorageMap::create(quota);
@@ -190,6 +198,7 @@ void StorageAreaImpl::clear(Frame* frame)
if (m_storageAreaSync)
m_storageAreaSync->scheduleClear();
StorageEventDispatcher::dispatch(String(), String(), String(), m_storageType, m_securityOrigin.get(), frame);
+ return true;
}
bool StorageAreaImpl::contains(const String& key) const
@@ -206,11 +215,6 @@ void StorageAreaImpl::importItem(const String& key, const String& value)
m_storageMap->importItem(key, value);
}
-SecurityOrigin* StorageAreaImpl::securityOrigin()
-{
- return m_securityOrigin.get();
-}
-
void StorageAreaImpl::close()
{
if (m_storageAreaSync)
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.h b/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.h
index fe21a45906..60d72cbd9f 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.h
+++ b/src/3rdparty/webkit/WebCore/storage/StorageAreaImpl.h
@@ -48,17 +48,16 @@ namespace WebCore {
virtual unsigned length() const;
virtual String key(unsigned index) const;
virtual String getItem(const String& key) const;
- virtual void setItem(const String& key, const String& value, ExceptionCode& ec, Frame* sourceFrame);
- virtual void removeItem(const String& key, Frame* sourceFrame);
- virtual void clear(Frame* sourceFrame);
+ virtual String setItem(const String& key, const String& value, ExceptionCode& ec, Frame* sourceFrame);
+ virtual String removeItem(const String& key, Frame* sourceFrame);
+ virtual bool clear(Frame* sourceFrame);
virtual bool contains(const String& key) const;
PassRefPtr<StorageAreaImpl> copy();
void close();
- // Could be called from a background thread.
+ // Only called from a background thread.
void importItem(const String& key, const String& value);
- SecurityOrigin* securityOrigin();
private:
StorageAreaImpl(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota);
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.cpp b/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.cpp
index ad41e2860b..3434c1ff2d 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.cpp
@@ -31,6 +31,7 @@
#include "CString.h"
#include "EventNames.h"
#include "HTMLElement.h"
+#include "SecurityOrigin.h"
#include "SQLiteStatement.h"
#include "StorageAreaImpl.h"
#include "StorageSyncManager.h"
@@ -42,19 +43,25 @@ namespace WebCore {
// Instead, queue up a batch of items to sync and actually do the sync at the following interval.
static const double StorageSyncInterval = 1.0;
-PassRefPtr<StorageAreaSync> StorageAreaSync::create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea)
+// A sane limit on how many items we'll schedule to sync all at once. This makes it
+// much harder to starve the rest of LocalStorage and the OS's IO subsystem in general.
+static const int MaxiumItemsToSync = 100;
+
+PassRefPtr<StorageAreaSync> StorageAreaSync::create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier)
{
- return adoptRef(new StorageAreaSync(storageSyncManager, storageArea));
+ return adoptRef(new StorageAreaSync(storageSyncManager, storageArea, databaseIdentifier));
}
-StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea)
+StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier)
: m_syncTimer(this, &StorageAreaSync::syncTimerFired)
, m_itemsCleared(false)
, m_finalSyncScheduled(false)
, m_storageArea(storageArea)
, m_syncManager(storageSyncManager)
+ , m_databaseIdentifier(databaseIdentifier.crossThreadString())
, m_clearItemsWhileSyncing(false)
, m_syncScheduled(false)
+ , m_syncInProgress(false)
, m_importComplete(false)
{
ASSERT(isMainThread());
@@ -71,6 +78,7 @@ StorageAreaSync::~StorageAreaSync()
{
ASSERT(isMainThread());
ASSERT(!m_syncTimer.isActive());
+ ASSERT(m_finalSyncScheduled);
}
void StorageAreaSync::scheduleFinalSync()
@@ -78,6 +86,7 @@ void StorageAreaSync::scheduleFinalSync()
ASSERT(isMainThread());
// FIXME: We do this to avoid races, but it'd be better to make things safe without blocking.
blockUntilImportComplete();
+ m_storageArea = 0; // This is done in blockUntilImportComplete() but this is here as a form of documentation that we must be absolutely sure the ref count cycle is broken.
if (m_syncTimer.isActive())
m_syncTimer.stop();
@@ -88,8 +97,8 @@ void StorageAreaSync::scheduleFinalSync()
}
// FIXME: This is synchronous. We should do it on the background process, but
// we should do it safely.
- syncTimerFired(&m_syncTimer);
m_finalSyncScheduled = true;
+ syncTimerFired(&m_syncTimer);
}
void StorageAreaSync::scheduleItemForSync(const String& key, const String& value)
@@ -127,20 +136,43 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
{
ASSERT(isMainThread());
- HashMap<String, String>::iterator it = m_changedItems.begin();
- HashMap<String, String>::iterator end = m_changedItems.end();
-
+ bool partialSync = false;
{
MutexLocker locker(m_syncLock);
+ // Do not schedule another sync if we're still trying to complete the
+ // previous one. But, if we're shutting down, schedule it anyway.
+ if (m_syncInProgress && !m_finalSyncScheduled) {
+ ASSERT(!m_syncTimer.isActive());
+ m_syncTimer.startOneShot(StorageSyncInterval);
+ return;
+ }
+
if (m_itemsCleared) {
m_itemsPendingSync.clear();
m_clearItemsWhileSyncing = true;
m_itemsCleared = false;
}
- for (; it != end; ++it)
- m_itemsPendingSync.set(it->first.crossThreadString(), it->second.crossThreadString());
+ HashMap<String, String>::iterator changed_it = m_changedItems.begin();
+ HashMap<String, String>::iterator changed_end = m_changedItems.end();
+ for (int count = 0; changed_it != changed_end; ++count, ++changed_it) {
+ if (count >= MaxiumItemsToSync && !m_finalSyncScheduled) {
+ partialSync = true;
+ break;
+ }
+ m_itemsPendingSync.set(changed_it->first.crossThreadString(), changed_it->second.crossThreadString());
+ }
+
+ if (partialSync) {
+ // We can't do the fast path of simply clearing all items, so we'll need to manually
+ // remove them one by one. Done under lock since m_itemsPendingSync is modified by
+ // the background thread.
+ HashMap<String, String>::iterator pending_it = m_itemsPendingSync.begin();
+ HashMap<String, String>::iterator pending_end = m_itemsPendingSync.end();
+ for (; pending_it != pending_end; ++pending_it)
+ m_changedItems.remove(pending_it->first);
+ }
if (!m_syncScheduled) {
m_syncScheduled = true;
@@ -153,11 +185,17 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
}
}
- // The following is balanced by the calls to disableSuddenTermination in the
- // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions.
- enableSuddenTermination();
+ if (partialSync) {
+ // If we didn't finish syncing, then we need to finish the job later.
+ ASSERT(!m_syncTimer.isActive());
+ m_syncTimer.startOneShot(StorageSyncInterval);
+ } else {
+ // The following is balanced by the calls to disableSuddenTermination in the
+ // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions.
+ enableSuddenTermination();
- m_changedItems.clear();
+ m_changedItems.clear();
+ }
}
void StorageAreaSync::performImport()
@@ -165,7 +203,7 @@ void StorageAreaSync::performImport()
ASSERT(!isMainThread());
ASSERT(!m_database.isOpen());
- String databaseFilename = m_syncManager->fullDatabaseFilename(m_storageArea->securityOrigin());
+ String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier);
if (databaseFilename.isEmpty()) {
LOG_ERROR("Filename for local storage database is empty - cannot open for persistent storage");
@@ -206,27 +244,18 @@ void StorageAreaSync::performImport()
return;
}
- MutexLocker locker(m_importLock);
-
HashMap<String, String>::iterator it = itemMap.begin();
HashMap<String, String>::iterator end = itemMap.end();
for (; it != end; ++it)
m_storageArea->importItem(it->first, it->second);
- // Break the (ref count) cycle.
- m_storageArea = 0;
- m_importComplete = true;
- m_importCondition.signal();
+ markImported();
}
void StorageAreaSync::markImported()
{
- ASSERT(!isMainThread());
-
MutexLocker locker(m_importLock);
- // Break the (ref count) cycle.
- m_storageArea = 0;
m_importComplete = true;
m_importCondition.signal();
}
@@ -238,19 +267,18 @@ void StorageAreaSync::markImported()
// item currently in the map. Get/remove can work whether or not it's in the map, but we'll need a list
// of items the import should not overwrite. Clear can also work, but it'll need to kill the import
// job first.
-void StorageAreaSync::blockUntilImportComplete() const
+void StorageAreaSync::blockUntilImportComplete()
{
ASSERT(isMainThread());
- // Fast path to avoid locking.
- if (m_importComplete)
+ // Fast path. We set m_storageArea to 0 only after m_importComplete being true.
+ if (!m_storageArea)
return;
MutexLocker locker(m_importLock);
while (!m_importComplete)
m_importCondition.wait(m_importLock);
- ASSERT(m_importComplete);
- ASSERT(!m_storageArea);
+ m_storageArea = 0;
}
void StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items)
@@ -325,10 +353,16 @@ void StorageAreaSync::performSync()
m_clearItemsWhileSyncing = false;
m_syncScheduled = false;
+ m_syncInProgress = true;
}
sync(clearItems, items);
+ {
+ MutexLocker locker(m_syncLock);
+ m_syncInProgress = false;
+ }
+
// The following is balanced by the call to disableSuddenTermination in the
// syncTimerFired function.
enableSuddenTermination();
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.h b/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.h
index 9d6436f32b..0e467630eb 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.h
+++ b/src/3rdparty/webkit/WebCore/storage/StorageAreaSync.h
@@ -42,17 +42,17 @@ namespace WebCore {
class StorageAreaSync : public RefCounted<StorageAreaSync> {
public:
- static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea);
+ static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier);
~StorageAreaSync();
void scheduleFinalSync();
- void blockUntilImportComplete() const;
+ void blockUntilImportComplete();
void scheduleItemForSync(const String& key, const String& value);
void scheduleClear();
private:
- StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea);
+ StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier);
void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame);
@@ -78,10 +78,13 @@ namespace WebCore {
void syncTimerFired(Timer<StorageAreaSync>*);
void sync(bool clearItems, const HashMap<String, String>& items);
+ const String m_databaseIdentifier;
+
Mutex m_syncLock;
HashMap<String, String> m_itemsPendingSync;
bool m_clearItemsWhileSyncing;
bool m_syncScheduled;
+ bool m_syncInProgress;
mutable Mutex m_importLock;
mutable ThreadCondition m_importCondition;
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageEvent.cpp b/src/3rdparty/webkit/WebCore/storage/StorageEvent.cpp
index 13ccfe98aa..126aca0bff 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageEvent.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/StorageEvent.cpp
@@ -47,7 +47,7 @@ PassRefPtr<StorageEvent> StorageEvent::create(const AtomicString& type, const St
}
StorageEvent::StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea)
- : Event(type, false, true)
+ : Event(type, false, false)
, m_key(key)
, m_oldValue(oldValue)
, m_newValue(newValue)
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageEvent.idl b/src/3rdparty/webkit/WebCore/storage/StorageEvent.idl
index 7c875618d2..3e77edac21 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageEvent.idl
+++ b/src/3rdparty/webkit/WebCore/storage/StorageEvent.idl
@@ -26,10 +26,9 @@
module storage {
interface [
- GenerateConstructor,
Conditional=DOM_STORAGE
] StorageEvent : Event {
- readonly attribute DOMString key;
+ readonly attribute [ConvertNullStringTo=Null] DOMString key;
readonly attribute [ConvertNullStringTo=Null] DOMString oldValue;
readonly attribute [ConvertNullStringTo=Null] DOMString newValue;
readonly attribute DOMString uri;
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageEventDispatcher.cpp b/src/3rdparty/webkit/WebCore/storage/StorageEventDispatcher.cpp
index 9763e076cd..2118a8323b 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageEventDispatcher.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/StorageEventDispatcher.cpp
@@ -50,25 +50,29 @@ void StorageEventDispatcher::dispatch(const String& key, const String& oldValue,
if (storageType == SessionStorage) {
// Send events only to our page.
for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
- if (frame->document()->securityOrigin()->equal(securityOrigin))
+ if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
frames.append(frame);
}
for (unsigned i = 0; i < frames.size(); ++i)
- frames[i]->document()->dispatchWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), frames[i]->domWindow()->sessionStorage()));
+ frames[i]->document()->enqueueEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), frames[i]->domWindow()->sessionStorage()));
} else {
// Send events to every page.
const HashSet<Page*>& pages = page->group().pages();
HashSet<Page*>::const_iterator end = pages.end();
for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
- if (frame->document()->securityOrigin()->equal(securityOrigin))
+ if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
frames.append(frame);
}
}
- for (unsigned i = 0; i < frames.size(); ++i)
- frames[i]->document()->dispatchWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), frames[i]->domWindow()->localStorage()));
+ for (unsigned i = 0; i < frames.size(); ++i) {
+ ExceptionCode ec = 0;
+ Storage* storage = frames[i]->domWindow()->localStorage(ec);
+ if (!ec)
+ frames[i]->document()->enqueueEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
+ }
}
}
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageMap.cpp b/src/3rdparty/webkit/WebCore/storage/StorageMap.cpp
index 5498d9ee45..790fde25a5 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageMap.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/StorageMap.cpp
@@ -47,6 +47,7 @@ PassRefPtr<StorageMap> StorageMap::copy()
{
RefPtr<StorageMap> newMap = create(m_quotaSize);
newMap->m_map = m_map;
+ newMap->m_currentLength = m_currentLength;
return newMap.release();
}
@@ -111,12 +112,21 @@ PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& valu
return newStorageMap.release();
}
- // Quota tracking. If the quota is enabled and this would go over it, bail.
+ // Quota tracking. This is done in a couple of steps to keep the overflow tracking simple.
+ unsigned newLength = m_currentLength;
+ bool overflow = newLength + value.length() < newLength;
+ newLength += value.length();
+
oldValue = m_map.get(key);
- unsigned newLength = m_currentLength + value.length() - oldValue.length();
+ overflow |= newLength - oldValue.length() > newLength;
+ newLength -= oldValue.length();
+
+ unsigned adjustedKeyLength = oldValue.isNull() ? key.length() : 0;
+ overflow |= newLength + adjustedKeyLength < newLength;
+ newLength += adjustedKeyLength;
+
+ ASSERT(!overflow); // Overflow is bad...even if quotas are off.
bool overQuota = newLength > m_quotaSize / sizeof(UChar);
- bool overflow = (newLength > m_currentLength) != (value.length() > oldValue.length());
- ASSERT(!overflow); // If we're debugging, make a fuss. But it's still worth checking this in the following if statement.
if (m_quotaSize != noQuota && (overflow || overQuota)) {
quotaException = true;
return 0;
@@ -143,10 +153,11 @@ PassRefPtr<StorageMap> StorageMap::removeItem(const String& key, String& oldValu
}
oldValue = m_map.take(key);
- if (!oldValue.isNull())
+ if (!oldValue.isNull()) {
invalidateIterator();
-
- // Update quota.
+ ASSERT(m_currentLength - key.length() <= m_currentLength);
+ m_currentLength -= key.length();
+ }
ASSERT(m_currentLength - oldValue.length() <= m_currentLength);
m_currentLength -= oldValue.length();
@@ -162,12 +173,11 @@ void StorageMap::importItem(const String& key, const String& value)
{
// Be sure to copy the keys/values as items imported on a background thread are destined
// to cross a thread boundary
- pair<HashMap<String, String>::iterator, bool> result = m_map.add(key.threadsafeCopy(), String());
-
- if (result.second)
- result.first->second = value.threadsafeCopy();
+ pair<HashMap<String, String>::iterator, bool> result = m_map.add(key.threadsafeCopy(), value.threadsafeCopy());
+ ASSERT(result.second); // True if the key didn't exist previously.
- // Update quota.
+ ASSERT(m_currentLength + key.length() >= m_currentLength);
+ m_currentLength += key.length();
ASSERT(m_currentLength + value.length() >= m_currentLength);
m_currentLength += value.length();
}
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageNamespace.cpp b/src/3rdparty/webkit/WebCore/storage/StorageNamespace.cpp
index 6b8caebc00..b54ba16324 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageNamespace.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/StorageNamespace.cpp
@@ -41,7 +41,8 @@ PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const Strin
return StorageNamespaceImpl::localStorageNamespace(path, quota);
}
-PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace()
+// The page argument is only used by the Chromium port.
+PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace(Page*)
{
return StorageNamespaceImpl::sessionStorageNamespace();
}
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageNamespace.h b/src/3rdparty/webkit/WebCore/storage/StorageNamespace.h
index 0ac5f8628f..e84e5a6068 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageNamespace.h
+++ b/src/3rdparty/webkit/WebCore/storage/StorageNamespace.h
@@ -35,21 +35,22 @@
namespace WebCore {
- class SecurityOrigin;
- class StorageArea;
-
- // This interface is required for Chromium since these actions need to be proxied between processes.
- class StorageNamespace : public RefCounted<StorageNamespace> {
- public:
- static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
- static PassRefPtr<StorageNamespace> sessionStorageNamespace();
-
- virtual ~StorageNamespace() { }
- virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>) = 0;
- virtual PassRefPtr<StorageNamespace> copy() = 0;
- virtual void close() = 0;
- virtual void unlock() = 0;
- };
+class Page;
+class SecurityOrigin;
+class StorageArea;
+
+// This interface is required for Chromium since these actions need to be proxied between processes.
+class StorageNamespace : public RefCounted<StorageNamespace> {
+public:
+ static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
+ static PassRefPtr<StorageNamespace> sessionStorageNamespace(Page*);
+
+ virtual ~StorageNamespace() { }
+ virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>) = 0;
+ virtual PassRefPtr<StorageNamespace> copy() = 0;
+ virtual void close() = 0;
+ virtual void unlock() = 0;
+};
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.cpp b/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.cpp
index f9276ddae6..d9641b7578 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.cpp
+++ b/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.cpp
@@ -48,28 +48,29 @@ PassRefPtr<StorageSyncManager> StorageSyncManager::create(const String& path)
}
StorageSyncManager::StorageSyncManager(const String& path)
- : m_path(path.crossThreadString())
+ : m_thread(LocalStorageThread::create())
+ , m_path(path.crossThreadString())
{
ASSERT(isMainThread());
ASSERT(!m_path.isEmpty());
- m_thread = LocalStorageThread::create();
m_thread->start();
}
StorageSyncManager::~StorageSyncManager()
{
ASSERT(isMainThread());
+ ASSERT(!m_thread);
}
-String StorageSyncManager::fullDatabaseFilename(SecurityOrigin* origin)
+// Called on a background thread.
+String StorageSyncManager::fullDatabaseFilename(const String& databaseIdentifier)
{
- ASSERT(origin);
if (!makeAllDirectories(m_path)) {
LOG_ERROR("Unabled to create LocalStorage database path %s", m_path.utf8().data());
return String();
}
- return pathByAppendingComponent(m_path, origin->databaseIdentifier() + ".localstorage");
+ return pathByAppendingComponent(m_path, databaseIdentifier + ".localstorage");
}
void StorageSyncManager::close()
@@ -85,19 +86,18 @@ void StorageSyncManager::close()
bool StorageSyncManager::scheduleImport(PassRefPtr<StorageAreaSync> area)
{
ASSERT(isMainThread());
-
+ ASSERT(m_thread);
if (m_thread)
- m_thread->scheduleImport(area.get());
-
+ m_thread->scheduleTask(LocalStorageTask::createImport(area.get()));
return m_thread;
}
void StorageSyncManager::scheduleSync(PassRefPtr<StorageAreaSync> area)
{
ASSERT(isMainThread());
-
+ ASSERT(m_thread);
if (m_thread)
- m_thread->scheduleSync(area.get());
+ m_thread->scheduleTask(LocalStorageTask::createSync(area.get()));
}
} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.h b/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.h
index fe35e3daaa..e2dfa76ad1 100644
--- a/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.h
+++ b/src/3rdparty/webkit/WebCore/storage/StorageSyncManager.h
@@ -32,7 +32,7 @@
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
+#include <wtf/OwnPtr.h>
namespace WebCore {
@@ -53,12 +53,12 @@ namespace WebCore {
private:
StorageSyncManager(const String& path);
- RefPtr<LocalStorageThread> m_thread;
+ OwnPtr<LocalStorageThread> m_thread;
// The following members are subject to thread synchronization issues
public:
// To be called from the background thread:
- String fullDatabaseFilename(SecurityOrigin*);
+ String fullDatabaseFilename(const String& databaseIdentifier);
private:
String m_path;