diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/storage')
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; |