diff options
author | Steve Block <steveblock@google.com> | 2011-05-25 19:08:45 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-06-08 13:51:31 +0100 |
commit | 2bde8e466a4451c7319e3a072d118917957d6554 (patch) | |
tree | 28f4a1b869a513e565c7760d0e6a06e7cf1fe95a /Source/WebCore/storage | |
parent | 6939c99b71d9372d14a0c74a772108052e8c48c8 (diff) | |
download | external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.zip external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.gz external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.bz2 |
Merge WebKit at r82507: Initial merge by git
Change-Id: I60ce9d780725b58b45e54165733a8ffee23b683e
Diffstat (limited to 'Source/WebCore/storage')
48 files changed, 1339 insertions, 173 deletions
diff --git a/Source/WebCore/storage/AbstractDatabase.h b/Source/WebCore/storage/AbstractDatabase.h index bd5d0db..9279adc 100644 --- a/Source/WebCore/storage/AbstractDatabase.h +++ b/Source/WebCore/storage/AbstractDatabase.h @@ -35,7 +35,7 @@ #include "PlatformString.h" #include "SQLiteDatabase.h" #include <wtf/Forward.h> -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> #ifndef NDEBUG #include "SecurityOrigin.h" #endif @@ -46,7 +46,7 @@ class DatabaseAuthorizer; class ScriptExecutionContext; class SecurityOrigin; -class AbstractDatabase : public ThreadSafeShared<AbstractDatabase> { +class AbstractDatabase : public ThreadSafeRefCounted<AbstractDatabase> { public: static bool isAvailable(); static void setIsAvailable(bool available); diff --git a/Source/WebCore/storage/DatabaseAuthorizer.h b/Source/WebCore/storage/DatabaseAuthorizer.h index da7761d..939b409 100644 --- a/Source/WebCore/storage/DatabaseAuthorizer.h +++ b/Source/WebCore/storage/DatabaseAuthorizer.h @@ -31,7 +31,7 @@ #include "PlatformString.h" #include <wtf/Forward.h> #include <wtf/HashSet.h> -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> #include <wtf/text/StringHash.h> namespace WebCore { @@ -40,7 +40,7 @@ extern const int SQLAuthAllow; extern const int SQLAuthIgnore; extern const int SQLAuthDeny; -class DatabaseAuthorizer : public ThreadSafeShared<DatabaseAuthorizer> { +class DatabaseAuthorizer : public ThreadSafeRefCounted<DatabaseAuthorizer> { public: enum Permissions { diff --git a/Source/WebCore/storage/DatabaseCallback.h b/Source/WebCore/storage/DatabaseCallback.h index 8ad56ed..586416a 100644 --- a/Source/WebCore/storage/DatabaseCallback.h +++ b/Source/WebCore/storage/DatabaseCallback.h @@ -33,14 +33,14 @@ #if ENABLE(DATABASE) -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { class Database; class DatabaseSync; -class DatabaseCallback : public ThreadSafeShared<DatabaseCallback> { +class DatabaseCallback : public ThreadSafeRefCounted<DatabaseCallback> { public: virtual ~DatabaseCallback() { } virtual bool handleEvent(Database*) = 0; diff --git a/Source/WebCore/storage/DatabaseThread.h b/Source/WebCore/storage/DatabaseThread.h index c81e376..ee1702c 100644 --- a/Source/WebCore/storage/DatabaseThread.h +++ b/Source/WebCore/storage/DatabaseThread.h @@ -48,7 +48,7 @@ class Document; class SQLTransactionClient; class SQLTransactionCoordinator; -class DatabaseThread : public ThreadSafeShared<DatabaseThread> { +class DatabaseThread : public ThreadSafeRefCounted<DatabaseThread> { public: static PassRefPtr<DatabaseThread> create() { return adoptRef(new DatabaseThread); } ~DatabaseThread(); diff --git a/Source/WebCore/storage/IDBBackingStore.h b/Source/WebCore/storage/IDBBackingStore.h index e75fee1..29523a2 100644 --- a/Source/WebCore/storage/IDBBackingStore.h +++ b/Source/WebCore/storage/IDBBackingStore.h @@ -44,37 +44,36 @@ class SecurityOrigin; class IDBBackingStore : public RefCounted<IDBBackingStore> { public: - static PassRefPtr<IDBBackingStore> open(SecurityOrigin*, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl*); - ~IDBBackingStore(); - - bool extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId); - bool setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId); - - void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags); - bool createObjectStore(const String& name, const String& keyPath, bool autoIncrement, int64_t databaseId, int64_t& assignedObjectStoreId); - void deleteObjectStore(int64_t objectStoreId); - String getObjectStoreRecord(int64_t objectStoreId, const IDBKey&); - bool putObjectStoreRecord(int64_t objectStoreId, const IDBKey&, const String& value, int64_t& rowId, bool invalidRowId); - void clearObjectStore(int64_t objectStoreId); - void deleteObjectStoreRecord(int64_t objectStoreId, int64_t objectStoreDataId); - double nextAutoIncrementNumber(int64_t objectStoreId); - bool keyExistsInObjectStore(int64_t objectStoreId, const IDBKey&, int64_t& foundObjectStoreDataId); + virtual ~IDBBackingStore() {}; + + virtual bool extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) = 0; + virtual bool setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId) = 0; + + virtual void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags) = 0; + virtual bool createObjectStore(const String& name, const String& keyPath, bool autoIncrement, int64_t databaseId, int64_t& assignedObjectStoreId) = 0; + virtual void deleteObjectStore(int64_t objectStoreId) = 0; + virtual String getObjectStoreRecord(int64_t objectStoreId, const IDBKey&) = 0; + virtual bool putObjectStoreRecord(int64_t objectStoreId, const IDBKey&, const String& value, int64_t& rowId, bool invalidRowId) = 0; + virtual void clearObjectStore(int64_t objectStoreId) = 0; + virtual void deleteObjectStoreRecord(int64_t objectStoreId, int64_t objectStoreDataId) = 0; + virtual double nextAutoIncrementNumber(int64_t objectStoreId) = 0; + virtual bool keyExistsInObjectStore(int64_t objectStoreId, const IDBKey&, int64_t& foundObjectStoreDataId) = 0; class ObjectStoreRecordCallback { public: virtual bool callback(int64_t objectStoreDataId, const String& value) = 0; virtual ~ObjectStoreRecordCallback() {}; }; - bool forEachObjectStoreRecord(int64_t objectStoreId, ObjectStoreRecordCallback&); + virtual bool forEachObjectStoreRecord(int64_t objectStoreId, ObjectStoreRecordCallback&) = 0; - void getIndexes(int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundUniqueFlags); - bool createIndex(int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId); - void deleteIndex(int64_t indexId); - bool putIndexDataForRecord(int64_t indexId, const IDBKey&, int64_t objectStoreDataId); - bool deleteIndexDataForRecord(int64_t objectStoreDataId); - String getObjectViaIndex(int64_t indexId, const IDBKey&); - PassRefPtr<IDBKey> getPrimaryKeyViaIndex(int64_t indexId, const IDBKey&); - bool keyExistsInIndex(int64_t indexId, const IDBKey&); + virtual void getIndexes(int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundUniqueFlags) = 0; + virtual bool createIndex(int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId) = 0; + virtual void deleteIndex(int64_t indexId) = 0; + virtual bool putIndexDataForRecord(int64_t indexId, const IDBKey&, int64_t objectStoreDataId) = 0; + virtual bool deleteIndexDataForRecord(int64_t objectStoreDataId) = 0; + virtual String getObjectViaIndex(int64_t indexId, const IDBKey&) = 0; + virtual PassRefPtr<IDBKey> getPrimaryKeyViaIndex(int64_t indexId, const IDBKey&) = 0; + virtual bool keyExistsInIndex(int64_t indexId, const IDBKey&) = 0; class Cursor : public RefCounted<Cursor> { public: @@ -87,9 +86,9 @@ public: virtual ~Cursor() {}; }; - PassRefPtr<Cursor> openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction); - PassRefPtr<Cursor> openIndexKeyCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); - PassRefPtr<Cursor> openIndexCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); + virtual PassRefPtr<Cursor> openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction) = 0; + virtual PassRefPtr<Cursor> openIndexKeyCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction) = 0; + virtual PassRefPtr<Cursor> openIndexCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction) = 0; class Transaction : public RefCounted<Transaction> { public: @@ -97,14 +96,7 @@ public: virtual void commit() = 0; virtual void rollback() = 0; }; - PassRefPtr<Transaction> createTransaction(); - -private: - IDBBackingStore(String identifier, IDBFactoryBackendImpl* factory); - - SQLiteDatabase m_db; - String m_identifier; - RefPtr<IDBFactoryBackendImpl> m_factory; + virtual PassRefPtr<Transaction> createTransaction() = 0; }; } // namespace WebCore diff --git a/Source/WebCore/storage/IDBCallbacks.h b/Source/WebCore/storage/IDBCallbacks.h index f4e1b98..ddc6e60 100644 --- a/Source/WebCore/storage/IDBCallbacks.h +++ b/Source/WebCore/storage/IDBCallbacks.h @@ -32,7 +32,6 @@ #include "IDBCursorBackendInterface.h" #include "IDBDatabaseBackendInterface.h" #include "IDBDatabaseError.h" -#include "IDBIndexBackendInterface.h" #include "IDBKey.h" #include "IDBObjectStoreBackendInterface.h" #include "IDBTransactionBackendInterface.h" @@ -44,14 +43,13 @@ namespace WebCore { // FIXME: All child classes need to be made threadsafe. -class IDBCallbacks : public ThreadSafeShared<IDBCallbacks> { +class IDBCallbacks : public ThreadSafeRefCounted<IDBCallbacks> { public: virtual ~IDBCallbacks() { } virtual void onError(PassRefPtr<IDBDatabaseError>) = 0; virtual void onSuccess(PassRefPtr<IDBCursorBackendInterface>) = 0; virtual void onSuccess(PassRefPtr<IDBDatabaseBackendInterface>) = 0; - virtual void onSuccess(PassRefPtr<IDBIndexBackendInterface>) = 0; virtual void onSuccess(PassRefPtr<IDBKey>) = 0; virtual void onSuccess(PassRefPtr<IDBTransactionBackendInterface>) = 0; virtual void onSuccess(PassRefPtr<SerializedScriptValue>) = 0; diff --git a/Source/WebCore/storage/IDBCursorBackendInterface.h b/Source/WebCore/storage/IDBCursorBackendInterface.h index 6cdab42..21425c9 100644 --- a/Source/WebCore/storage/IDBCursorBackendInterface.h +++ b/Source/WebCore/storage/IDBCursorBackendInterface.h @@ -41,7 +41,7 @@ class IDBKey; class IDBRequest; class SerializedScriptValue; -class IDBCursorBackendInterface : public ThreadSafeShared<IDBCursorBackendInterface> { +class IDBCursorBackendInterface : public ThreadSafeRefCounted<IDBCursorBackendInterface> { public: virtual ~IDBCursorBackendInterface() {} diff --git a/Source/WebCore/storage/IDBDatabase.cpp b/Source/WebCore/storage/IDBDatabase.cpp index fe8d350..d54b969 100644 --- a/Source/WebCore/storage/IDBDatabase.cpp +++ b/Source/WebCore/storage/IDBDatabase.cpp @@ -29,6 +29,7 @@ #include "Document.h" #include "EventQueue.h" #include "IDBAny.h" +#include "IDBDatabaseCallbacksImpl.h" #include "IDBDatabaseError.h" #include "IDBDatabaseException.h" #include "IDBEventDispatcher.h" @@ -58,10 +59,12 @@ IDBDatabase::IDBDatabase(ScriptExecutionContext* context, PassRefPtr<IDBDatabase { // We pass a reference of this object before it can be adopted. relaxAdoptionRequirement(); + m_databaseCallbacks = IDBDatabaseCallbacksImpl::create(this); } IDBDatabase::~IDBDatabase() { + m_databaseCallbacks->unregisterDatabase(this); } void IDBDatabase::setSetVersionTransaction(IDBTransaction* transaction) @@ -103,7 +106,7 @@ void IDBDatabase::deleteObjectStore(const String& name, ExceptionCode& ec) PassRefPtr<IDBVersionChangeRequest> IDBDatabase::setVersion(ScriptExecutionContext* context, const String& version, ExceptionCode& ec) { RefPtr<IDBVersionChangeRequest> request = IDBVersionChangeRequest::create(context, IDBAny::create(this), version); - m_backend->setVersion(version, request, this, ec); + m_backend->setVersion(version, request, m_databaseCallbacks, ec); return request; } @@ -154,7 +157,7 @@ void IDBDatabase::close() } m_noNewTransactions = true; - m_backend->close(this); + m_backend->close(m_databaseCallbacks); } void IDBDatabase::onVersionChange(const String& version) @@ -174,7 +177,7 @@ bool IDBDatabase::hasPendingActivity() const void IDBDatabase::open() { - m_backend->open(this); + m_backend->open(m_databaseCallbacks); } void IDBDatabase::enqueueEvent(PassRefPtr<Event> event) diff --git a/Source/WebCore/storage/IDBDatabase.h b/Source/WebCore/storage/IDBDatabase.h index 51f1d23..9d4883e 100644 --- a/Source/WebCore/storage/IDBDatabase.h +++ b/Source/WebCore/storage/IDBDatabase.h @@ -32,7 +32,7 @@ #include "EventTarget.h" #include "ExceptionCode.h" #include "IDBDatabaseBackendInterface.h" -#include "IDBDatabaseCallbacks.h" +#include "IDBDatabaseCallbacksImpl.h" #include "IDBObjectStore.h" #include "IDBTransaction.h" #include "OptionsObject.h" @@ -47,7 +47,7 @@ namespace WebCore { class IDBVersionChangeRequest; class ScriptExecutionContext; -class IDBDatabase : public IDBDatabaseCallbacks, public EventTarget, public ActiveDOMObject { +class IDBDatabase : public RefCounted<IDBDatabase>, public EventTarget, public ActiveDOMObject { public: static PassRefPtr<IDBDatabase> create(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendInterface>); ~IDBDatabase(); @@ -91,8 +91,8 @@ public: bool dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec) { return EventTarget::dispatchEvent(event, ec); } virtual bool dispatchEvent(PassRefPtr<Event>); - using RefCounted<IDBDatabaseCallbacks>::ref; - using RefCounted<IDBDatabaseCallbacks>::deref; + using RefCounted<IDBDatabase>::ref; + using RefCounted<IDBDatabase>::deref; private: IDBDatabase(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendInterface>); @@ -114,6 +114,8 @@ private: // Keep track of the versionchange events waiting to be fired on this // database so that we can cancel them if the database closes. Vector<RefPtr<Event> > m_enqueuedEvents; + + RefPtr<IDBDatabaseCallbacksImpl> m_databaseCallbacks; }; } // namespace WebCore diff --git a/Source/WebCore/storage/IDBDatabaseBackendInterface.h b/Source/WebCore/storage/IDBDatabaseBackendInterface.h index ad6fdc7..2245bd7 100644 --- a/Source/WebCore/storage/IDBDatabaseBackendInterface.h +++ b/Source/WebCore/storage/IDBDatabaseBackendInterface.h @@ -46,7 +46,7 @@ class IDBTransactionBackendInterface; // This is implemented by IDBDatabaseBackendImpl 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 IDBDatabaseBackendInterface : public ThreadSafeShared<IDBDatabaseBackendInterface> { +class IDBDatabaseBackendInterface : public ThreadSafeRefCounted<IDBDatabaseBackendInterface> { public: virtual ~IDBDatabaseBackendInterface() { } diff --git a/Source/WebCore/storage/IDBDatabaseCallbacksImpl.cpp b/Source/WebCore/storage/IDBDatabaseCallbacksImpl.cpp new file mode 100644 index 0000000..39c4409 --- /dev/null +++ b/Source/WebCore/storage/IDBDatabaseCallbacksImpl.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 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. + * + * 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 "IDBDatabaseCallbacksImpl.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBDatabase.h" + +namespace WebCore { + +PassRefPtr<IDBDatabaseCallbacksImpl> IDBDatabaseCallbacksImpl::create(IDBDatabase* database) +{ + return adoptRef(new IDBDatabaseCallbacksImpl(database)); +} + +IDBDatabaseCallbacksImpl::IDBDatabaseCallbacksImpl(IDBDatabase* database) + : m_database(database) +{ +} + +IDBDatabaseCallbacksImpl::~IDBDatabaseCallbacksImpl() +{ +} + +void IDBDatabaseCallbacksImpl::onVersionChange(const String& version) +{ + if (m_database) + m_database->onVersionChange(version); +} + +void IDBDatabaseCallbacksImpl::unregisterDatabase(IDBDatabase* database) +{ + ASSERT(database == m_database); + m_database = 0; +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/storage/IDBDatabaseCallbacksImpl.h b/Source/WebCore/storage/IDBDatabaseCallbacksImpl.h new file mode 100644 index 0000000..e8b1f99 --- /dev/null +++ b/Source/WebCore/storage/IDBDatabaseCallbacksImpl.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 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. + * + * 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 IDBDatabaseCallbacksImpl_h +#define IDBDatabaseCallbacksImpl_h + +#include "IDBDatabaseCallbacks.h" +#include "PlatformString.h" +#include <wtf/RefCounted.h> + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +class IDBDatabase; + +class IDBDatabaseCallbacksImpl : public IDBDatabaseCallbacks { +public: + static PassRefPtr<IDBDatabaseCallbacksImpl> create(IDBDatabase*); + virtual ~IDBDatabaseCallbacksImpl(); + + virtual void onVersionChange(const String& version); + void unregisterDatabase(IDBDatabase*); + +private: + IDBDatabaseCallbacksImpl(IDBDatabase*); + + // m_database has a RefPtr to this, so use a weak pointer to avoid a cycle. + IDBDatabase* m_database; +}; + +} // namespace WebCore + +#endif + +#endif // IDBDatabaseCallbacksImpl_h diff --git a/Source/WebCore/storage/IDBFactory.cpp b/Source/WebCore/storage/IDBFactory.cpp index 85e976c..295398b 100644 --- a/Source/WebCore/storage/IDBFactory.cpp +++ b/Source/WebCore/storage/IDBFactory.cpp @@ -74,7 +74,7 @@ PassRefPtr<IDBRequest> IDBFactory::open(ScriptExecutionContext* context, const S RefPtr<IDBRequest> request = IDBRequest::create(document, IDBAny::create(this), 0); GroupSettings* groupSettings = document->page()->group().groupSettings(); - m_factoryBackend->open(name, request, document->securityOrigin(), document->frame(), groupSettings->indexedDBDatabasePath(), groupSettings->indexedDBQuotaBytes()); + m_factoryBackend->open(name, request, document->securityOrigin(), document->frame(), groupSettings->indexedDBDatabasePath(), groupSettings->indexedDBQuotaBytes(), IDBFactoryBackendInterface::DefaultBackingStore); return request; } diff --git a/Source/WebCore/storage/IDBFactoryBackendImpl.cpp b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp index 9127455..461e930 100644 --- a/Source/WebCore/storage/IDBFactoryBackendImpl.cpp +++ b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp @@ -30,9 +30,9 @@ #include "IDBFactoryBackendImpl.h" #include "DOMStringList.h" -#include "IDBBackingStore.h" #include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseException.h" +#include "IDBSQLiteBackingStore.h" #include "IDBTransactionCoordinator.h" #include "SecurityOrigin.h" #include <wtf/Threading.h> @@ -69,7 +69,7 @@ void IDBFactoryBackendImpl::removeIDBBackingStore(const String& uniqueIdentifier m_backingStoreMap.remove(uniqueIdentifier); } -void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir, int64_t maximumSize) +void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir, int64_t maximumSize, BackingStoreType) { String fileIdentifier = securityOrigin->databaseIdentifier(); String uniqueIdentifier = fileIdentifier + "@" + name; @@ -86,7 +86,7 @@ void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> ca if (it2 != m_backingStoreMap.end()) backingStore = it2->second; else { - backingStore = IDBBackingStore::open(securityOrigin.get(), dataDir, maximumSize, fileIdentifier, this); + backingStore = IDBSQLiteBackingStore::open(securityOrigin.get(), dataDir, maximumSize, fileIdentifier, this); if (!backingStore) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error.")); return; diff --git a/Source/WebCore/storage/IDBFactoryBackendImpl.h b/Source/WebCore/storage/IDBFactoryBackendImpl.h index 071bcf8..ab6e153 100644 --- a/Source/WebCore/storage/IDBFactoryBackendImpl.h +++ b/Source/WebCore/storage/IDBFactoryBackendImpl.h @@ -55,7 +55,7 @@ public: void addIDBBackingStore(const String& uniqueIdentifier, IDBBackingStore*); void removeIDBBackingStore(const String& uniqueIdentifier); - virtual void open(const String& name, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize); + virtual void open(const String& name, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize, BackingStoreType); private: IDBFactoryBackendImpl(); diff --git a/Source/WebCore/storage/IDBFactoryBackendInterface.h b/Source/WebCore/storage/IDBFactoryBackendInterface.h index e05f316..87362d4 100644 --- a/Source/WebCore/storage/IDBFactoryBackendInterface.h +++ b/Source/WebCore/storage/IDBFactoryBackendInterface.h @@ -46,12 +46,17 @@ class SecurityOrigin; // This is implemented by IDBFactoryBackendImpl 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 IDBFactoryBackendInterface : public ThreadSafeShared<IDBFactoryBackendInterface> { +class IDBFactoryBackendInterface : public ThreadSafeRefCounted<IDBFactoryBackendInterface> { public: static PassRefPtr<IDBFactoryBackendInterface> create(); virtual ~IDBFactoryBackendInterface() { } - virtual void open(const String& name, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize) = 0; + enum BackingStoreType { + DefaultBackingStore, + LevelDBBackingStore + }; + + virtual void open(const String& name, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize, BackingStoreType) = 0; }; } // namespace WebCore diff --git a/Source/WebCore/storage/IDBIndexBackendInterface.h b/Source/WebCore/storage/IDBIndexBackendInterface.h index e0e578d..81ef1d5 100644 --- a/Source/WebCore/storage/IDBIndexBackendInterface.h +++ b/Source/WebCore/storage/IDBIndexBackendInterface.h @@ -39,7 +39,7 @@ class IDBKey; class IDBKeyRange; class IDBTransactionBackendInterface; -class IDBIndexBackendInterface : public ThreadSafeShared<IDBIndexBackendInterface> { +class IDBIndexBackendInterface : public ThreadSafeRefCounted<IDBIndexBackendInterface> { public: virtual ~IDBIndexBackendInterface() { } diff --git a/Source/WebCore/storage/IDBKey.h b/Source/WebCore/storage/IDBKey.h index 5816ce3..8ee9b8e 100644 --- a/Source/WebCore/storage/IDBKey.h +++ b/Source/WebCore/storage/IDBKey.h @@ -34,7 +34,7 @@ namespace WebCore { -class IDBKey : public ThreadSafeShared<IDBKey> { +class IDBKey : public ThreadSafeRefCounted<IDBKey> { public: static PassRefPtr<IDBKey> createNull() { @@ -100,8 +100,8 @@ public: bool isLessThan(const IDBKey* other) const; bool isEqual(const IDBKey* other) const; - using ThreadSafeShared<IDBKey>::ref; - using ThreadSafeShared<IDBKey>::deref; + using ThreadSafeRefCounted<IDBKey>::ref; + using ThreadSafeRefCounted<IDBKey>::deref; private: IDBKey(); diff --git a/Source/WebCore/storage/IDBKeyRange.h b/Source/WebCore/storage/IDBKeyRange.h index 636a5c1..7a87088 100644 --- a/Source/WebCore/storage/IDBKeyRange.h +++ b/Source/WebCore/storage/IDBKeyRange.h @@ -35,7 +35,7 @@ namespace WebCore { -class IDBKeyRange : public ThreadSafeShared<IDBKeyRange> { +class IDBKeyRange : public ThreadSafeRefCounted<IDBKeyRange> { public: static PassRefPtr<IDBKeyRange> create(PassRefPtr<IDBKey> lower, PassRefPtr<IDBKey> upper, bool lowerOpen, bool upperOpen) { diff --git a/Source/WebCore/storage/IDBObjectStoreBackendInterface.h b/Source/WebCore/storage/IDBObjectStoreBackendInterface.h index 177701c..2975ed7 100644 --- a/Source/WebCore/storage/IDBObjectStoreBackendInterface.h +++ b/Source/WebCore/storage/IDBObjectStoreBackendInterface.h @@ -42,7 +42,7 @@ class IDBKeyRange; class IDBTransactionBackendInterface; class SerializedScriptValue; -class IDBObjectStoreBackendInterface : public ThreadSafeShared<IDBObjectStoreBackendInterface> { +class IDBObjectStoreBackendInterface : public ThreadSafeRefCounted<IDBObjectStoreBackendInterface> { public: virtual ~IDBObjectStoreBackendInterface() { } diff --git a/Source/WebCore/storage/IDBRequest.cpp b/Source/WebCore/storage/IDBRequest.cpp index e1837fc..f8d818a 100644 --- a/Source/WebCore/storage/IDBRequest.cpp +++ b/Source/WebCore/storage/IDBRequest.cpp @@ -39,7 +39,6 @@ #include "IDBCursorWithValue.h" #include "IDBDatabase.h" #include "IDBEventDispatcher.h" -#include "IDBIndex.h" #include "IDBPendingTransactionMonitor.h" #include "IDBTransaction.h" @@ -205,11 +204,6 @@ void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend) enqueueEvent(createSuccessEvent()); } -void IDBRequest::onSuccess(PassRefPtr<IDBIndexBackendInterface> backend) -{ - ASSERT_NOT_REACHED(); // FIXME: This method should go away. -} - void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey) { ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); diff --git a/Source/WebCore/storage/IDBRequest.h b/Source/WebCore/storage/IDBRequest.h index b6b4e5b..900df01 100644 --- a/Source/WebCore/storage/IDBRequest.h +++ b/Source/WebCore/storage/IDBRequest.h @@ -76,7 +76,6 @@ public: virtual void onError(PassRefPtr<IDBDatabaseError>); virtual void onSuccess(PassRefPtr<IDBDatabaseBackendInterface>); virtual void onSuccess(PassRefPtr<IDBCursorBackendInterface>); - virtual void onSuccess(PassRefPtr<IDBIndexBackendInterface>); virtual void onSuccess(PassRefPtr<IDBKey>); virtual void onSuccess(PassRefPtr<IDBTransactionBackendInterface>); virtual void onSuccess(PassRefPtr<SerializedScriptValue>); @@ -92,8 +91,8 @@ public: bool dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec) { return EventTarget::dispatchEvent(event, ec); } virtual void uncaughtExceptionInEventHandler(); - using ThreadSafeShared<IDBCallbacks>::ref; - using ThreadSafeShared<IDBCallbacks>::deref; + using ThreadSafeRefCounted<IDBCallbacks>::ref; + using ThreadSafeRefCounted<IDBCallbacks>::deref; protected: IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransaction*); diff --git a/Source/WebCore/storage/IDBBackingStore.cpp b/Source/WebCore/storage/IDBSQLiteBackingStore.cpp index 3859c4c..e43b7a3 100644 --- a/Source/WebCore/storage/IDBBackingStore.cpp +++ b/Source/WebCore/storage/IDBSQLiteBackingStore.cpp @@ -24,7 +24,7 @@ */ #include "config.h" -#include "IDBBackingStore.h" +#include "IDBSQLiteBackingStore.h" #if ENABLE(INDEXED_DATABASE) @@ -39,14 +39,14 @@ namespace WebCore { -IDBBackingStore::IDBBackingStore(String identifier, IDBFactoryBackendImpl* factory) +IDBSQLiteBackingStore::IDBSQLiteBackingStore(String identifier, IDBFactoryBackendImpl* factory) : m_identifier(identifier) , m_factory(factory) { m_factory->addIDBBackingStore(identifier, this); } -IDBBackingStore::~IDBBackingStore() +IDBSQLiteBackingStore::~IDBSQLiteBackingStore() { m_factory->removeIDBBackingStore(m_identifier); } @@ -165,9 +165,9 @@ static bool migrateDatabase(SQLiteDatabase& sqliteDatabase) return true; } -PassRefPtr<IDBBackingStore> IDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl* factory) +PassRefPtr<IDBBackingStore> IDBSQLiteBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl* factory) { - RefPtr<IDBBackingStore> backingStore(adoptRef(new IDBBackingStore(fileIdentifier, factory))); + RefPtr<IDBSQLiteBackingStore> backingStore(adoptRef(new IDBSQLiteBackingStore(fileIdentifier, factory))); String path = ":memory:"; if (!pathBase.isEmpty()) { @@ -197,7 +197,7 @@ PassRefPtr<IDBBackingStore> IDBBackingStore::open(SecurityOrigin* securityOrigin return backingStore.release(); } -bool IDBBackingStore::extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) +bool IDBSQLiteBackingStore::extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) { SQLiteStatement databaseQuery(m_db, "SELECT id, version FROM Databases WHERE name = ?"); if (databaseQuery.prepare() != SQLResultOk) { @@ -216,7 +216,7 @@ bool IDBBackingStore::extractIDBDatabaseMetaData(const String& name, String& fou return true; } -bool IDBBackingStore::setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId) +bool IDBSQLiteBackingStore::setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId) { ASSERT(!name.isNull()); ASSERT(!version.isNull()); @@ -242,7 +242,7 @@ bool IDBBackingStore::setIDBDatabaseMetaData(const String& name, const String& v return true; } -void IDBBackingStore::getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags) +void IDBSQLiteBackingStore::getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags) { SQLiteStatement query(m_db, "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores WHERE databaseId = ?"); bool ok = query.prepare() == SQLResultOk; @@ -263,7 +263,7 @@ void IDBBackingStore::getObjectStores(int64_t databaseId, Vector<int64_t>& found } } -bool IDBBackingStore::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, int64_t databaseId, int64_t& assignedObjectStoreId) +bool IDBSQLiteBackingStore::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, int64_t databaseId, int64_t& assignedObjectStoreId) { SQLiteStatement query(m_db, "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement, databaseId) VALUES (?, ?, ?, ?)"); if (query.prepare() != SQLResultOk) @@ -291,7 +291,7 @@ static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id) ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. } -void IDBBackingStore::deleteObjectStore(int64_t objectStoreId) +void IDBSQLiteBackingStore::deleteObjectStore(int64_t objectStoreId) { doDelete(m_db, "DELETE FROM ObjectStores WHERE id = ?", objectStoreId); doDelete(m_db, "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStoreId); @@ -373,7 +373,7 @@ static String upperCursorWhereFragment(const IDBKey& key, String comparisonOpera return ""; } -String IDBBackingStore::getObjectStoreRecord(int64_t objectStoreId, const IDBKey& key) +String IDBSQLiteBackingStore::getObjectStoreRecord(int64_t objectStoreId, const IDBKey& key) { SQLiteStatement query(m_db, "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE objectStoreId = ? AND " + whereSyntaxForKey(key)); bool ok = query.prepare() == SQLResultOk; @@ -422,7 +422,7 @@ static void bindKeyToQueryWithNulls(SQLiteStatement& query, int baseColumn, cons } } -bool IDBBackingStore::putObjectStoreRecord(int64_t objectStoreId, const IDBKey& key, const String& value, int64_t& rowId, bool invalidRowId) +bool IDBSQLiteBackingStore::putObjectStoreRecord(int64_t objectStoreId, const IDBKey& key, const String& value, int64_t& rowId, bool invalidRowId) { String sql = !invalidRowId ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?" : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)"; @@ -446,13 +446,13 @@ bool IDBBackingStore::putObjectStoreRecord(int64_t objectStoreId, const IDBKey& return true; } -void IDBBackingStore::clearObjectStore(int64_t objectStoreId) +void IDBSQLiteBackingStore::clearObjectStore(int64_t objectStoreId) { doDelete(m_db, "DELETE FROM IndexData WHERE objectStoreDataId IN (SELECT id FROM ObjectStoreData WHERE objectStoreId = ?)", objectStoreId); doDelete(m_db, "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStoreId); } -void IDBBackingStore::deleteObjectStoreRecord(int64_t, int64_t objectStoreDataId) +void IDBSQLiteBackingStore::deleteObjectStoreRecord(int64_t, int64_t objectStoreDataId) { SQLiteStatement osQuery(m_db, "DELETE FROM ObjectStoreData WHERE id = ?"); bool ok = osQuery.prepare() == SQLResultOk; @@ -473,7 +473,7 @@ void IDBBackingStore::deleteObjectStoreRecord(int64_t, int64_t objectStoreDataId ASSERT_UNUSED(ok, ok); } -double IDBBackingStore::nextAutoIncrementNumber(int64_t objectStoreId) +double IDBSQLiteBackingStore::nextAutoIncrementNumber(int64_t objectStoreId) { SQLiteStatement query(m_db, "SELECT max(keyNumber) + 1 FROM ObjectStoreData WHERE objectStoreId = ? AND keyString IS NULL AND keyDate IS NULL"); bool ok = query.prepare() == SQLResultOk; @@ -487,7 +487,7 @@ double IDBBackingStore::nextAutoIncrementNumber(int64_t objectStoreId) return query.getColumnDouble(0); } -bool IDBBackingStore::keyExistsInObjectStore(int64_t objectStoreId, const IDBKey& key, int64_t& foundObjectStoreDataId) +bool IDBSQLiteBackingStore::keyExistsInObjectStore(int64_t objectStoreId, const IDBKey& key, int64_t& foundObjectStoreDataId) { String sql = String("SELECT id FROM ObjectStoreData WHERE objectStoreId = ? AND ") + whereSyntaxForKey(key); SQLiteStatement query(m_db, sql); @@ -504,7 +504,7 @@ bool IDBBackingStore::keyExistsInObjectStore(int64_t objectStoreId, const IDBKey return true; } -bool IDBBackingStore::forEachObjectStoreRecord(int64_t objectStoreId, ObjectStoreRecordCallback& callback) +bool IDBSQLiteBackingStore::forEachObjectStoreRecord(int64_t objectStoreId, ObjectStoreRecordCallback& callback) { SQLiteStatement query(m_db, "SELECT id, value FROM ObjectStoreData WHERE objectStoreId = ?"); if (query.prepare() != SQLResultOk) @@ -522,7 +522,7 @@ bool IDBBackingStore::forEachObjectStoreRecord(int64_t objectStoreId, ObjectStor return true; } -void IDBBackingStore::getIndexes(int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundUniqueFlags) +void IDBSQLiteBackingStore::getIndexes(int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundUniqueFlags) { SQLiteStatement query(m_db, "SELECT id, name, keyPath, isUnique FROM Indexes WHERE objectStoreId = ?"); bool ok = query.prepare() == SQLResultOk; @@ -543,7 +543,7 @@ void IDBBackingStore::getIndexes(int64_t objectStoreId, Vector<int64_t>& foundId } } -bool IDBBackingStore::createIndex(int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId) +bool IDBSQLiteBackingStore::createIndex(int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId) { SQLiteStatement query(m_db, "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)"); if (query.prepare() != SQLResultOk) @@ -561,13 +561,13 @@ bool IDBBackingStore::createIndex(int64_t objectStoreId, const String& name, con return true; } -void IDBBackingStore::deleteIndex(int64_t indexId) +void IDBSQLiteBackingStore::deleteIndex(int64_t indexId) { doDelete(m_db, "DELETE FROM Indexes WHERE id = ?", indexId); doDelete(m_db, "DELETE FROM IndexData WHERE indexId = ?", indexId); } -bool IDBBackingStore::putIndexDataForRecord(int64_t indexId, const IDBKey& key, int64_t objectStoreDataId) +bool IDBSQLiteBackingStore::putIndexDataForRecord(int64_t indexId, const IDBKey& key, int64_t objectStoreDataId) { SQLiteStatement query(m_db, "INSERT INTO IndexData (keyString, keyDate, keyNumber, indexId, objectStoreDataId) VALUES (?, ?, ?, ?, ?)"); if (query.prepare() != SQLResultOk) @@ -580,7 +580,7 @@ bool IDBBackingStore::putIndexDataForRecord(int64_t indexId, const IDBKey& key, return query.step() == SQLResultDone; } -bool IDBBackingStore::deleteIndexDataForRecord(int64_t objectStoreDataId) +bool IDBSQLiteBackingStore::deleteIndexDataForRecord(int64_t objectStoreDataId) { SQLiteStatement query(m_db, "DELETE FROM IndexData WHERE objectStoreDataId = ?"); if (query.prepare() != SQLResultOk) @@ -590,7 +590,7 @@ bool IDBBackingStore::deleteIndexDataForRecord(int64_t objectStoreDataId) return query.step() == SQLResultDone; } -String IDBBackingStore::getObjectViaIndex(int64_t indexId, const IDBKey& key) +String IDBSQLiteBackingStore::getObjectViaIndex(int64_t indexId, const IDBKey& key) { String sql = String("SELECT ") + "ObjectStoreData.value " @@ -629,7 +629,7 @@ static PassRefPtr<IDBKey> keyFromQuery(SQLiteStatement& query, int baseColumn) return IDBKey::createNull(); } -PassRefPtr<IDBKey> IDBBackingStore::getPrimaryKeyViaIndex(int64_t indexId, const IDBKey& key) +PassRefPtr<IDBKey> IDBSQLiteBackingStore::getPrimaryKeyViaIndex(int64_t indexId, const IDBKey& key) { String sql = String("SELECT ") + "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber " @@ -651,7 +651,7 @@ PassRefPtr<IDBKey> IDBBackingStore::getPrimaryKeyViaIndex(int64_t indexId, const return foundKey.release(); } -bool IDBBackingStore::keyExistsInIndex(int64_t indexId, const IDBKey& key) +bool IDBSQLiteBackingStore::keyExistsInIndex(int64_t indexId, const IDBKey& key) { String sql = String("SELECT id FROM IndexData WHERE indexId = ? AND ") + whereSyntaxForKey(key); SQLiteStatement query(m_db, sql); @@ -666,7 +666,7 @@ bool IDBBackingStore::keyExistsInIndex(int64_t indexId, const IDBKey& key) namespace { -class CursorImplCommon : public IDBBackingStore::Cursor { +class CursorImplCommon : public IDBSQLiteBackingStore::Cursor { public: CursorImplCommon(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint, bool iterateForward) : m_query(sqliteDatabase, query) @@ -849,7 +849,7 @@ bool IndexCursorImpl::currentRowExists() } // namespace -PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction) +PassRefPtr<IDBBackingStore::Cursor> IDBSQLiteBackingStore::openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction) { bool lowerBound = range && range->lower(); bool upperBound = range && range->upper(); @@ -886,7 +886,7 @@ PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openObjectStoreCursor(int64 return cursor.release(); } -PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openIndexKeyCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) +PassRefPtr<IDBBackingStore::Cursor> IDBSQLiteBackingStore::openIndexKeyCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) { String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") + ("ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") @@ -926,7 +926,7 @@ PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openIndexKeyCursor(int64_t return cursor.release(); } -PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openIndexCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) +PassRefPtr<IDBBackingStore::Cursor> IDBSQLiteBackingStore::openIndexCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) { String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") @@ -986,7 +986,7 @@ private: } // namespace -PassRefPtr<IDBBackingStore::Transaction> IDBBackingStore::createTransaction() +PassRefPtr<IDBBackingStore::Transaction> IDBSQLiteBackingStore::createTransaction() { return adoptRef(new TransactionImpl(m_db)); } diff --git a/Source/WebCore/storage/IDBSQLiteBackingStore.h b/Source/WebCore/storage/IDBSQLiteBackingStore.h new file mode 100644 index 0000000..fe0c6c1 --- /dev/null +++ b/Source/WebCore/storage/IDBSQLiteBackingStore.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 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. + * + * 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 IDBSQLiteBackingStore_h +#define IDBSQLiteBackingStore_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBBackingStore.h" + +namespace WebCore { + +class IDBSQLiteBackingStore : public IDBBackingStore { +public: + static PassRefPtr<IDBBackingStore> open(SecurityOrigin*, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl*); + virtual ~IDBSQLiteBackingStore(); + + virtual bool extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId); + virtual bool setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId); + + virtual void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags); + virtual bool createObjectStore(const String& name, const String& keyPath, bool autoIncrement, int64_t databaseId, int64_t& assignedObjectStoreId); + virtual void deleteObjectStore(int64_t objectStoreId); + virtual String getObjectStoreRecord(int64_t objectStoreId, const IDBKey&); + virtual bool putObjectStoreRecord(int64_t objectStoreId, const IDBKey&, const String& value, int64_t& rowId, bool invalidRowId); + virtual void clearObjectStore(int64_t objectStoreId); + virtual void deleteObjectStoreRecord(int64_t objectStoreId, int64_t objectStoreDataId); + virtual double nextAutoIncrementNumber(int64_t objectStoreId); + virtual bool keyExistsInObjectStore(int64_t objectStoreId, const IDBKey&, int64_t& foundObjectStoreDataId); + + virtual bool forEachObjectStoreRecord(int64_t objectStoreId, ObjectStoreRecordCallback&); + + virtual void getIndexes(int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundUniqueFlags); + virtual bool createIndex(int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId); + virtual void deleteIndex(int64_t indexId); + virtual bool putIndexDataForRecord(int64_t indexId, const IDBKey&, int64_t objectStoreDataId); + virtual bool deleteIndexDataForRecord(int64_t objectStoreDataId); + virtual String getObjectViaIndex(int64_t indexId, const IDBKey&); + virtual PassRefPtr<IDBKey> getPrimaryKeyViaIndex(int64_t indexId, const IDBKey&); + virtual bool keyExistsInIndex(int64_t indexId, const IDBKey&); + + virtual PassRefPtr<Cursor> openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction); + virtual PassRefPtr<Cursor> openIndexKeyCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); + virtual PassRefPtr<Cursor> openIndexCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); + + virtual PassRefPtr<Transaction> createTransaction(); + +private: + IDBSQLiteBackingStore(String identifier, IDBFactoryBackendImpl*); + + SQLiteDatabase m_db; + String m_identifier; + RefPtr<IDBFactoryBackendImpl> m_factory; +}; + +} // namespace WebCore + +#endif + +#endif // IDBSQLiteBackingStore_h diff --git a/Source/WebCore/storage/IDBTransactionBackendInterface.h b/Source/WebCore/storage/IDBTransactionBackendInterface.h index 1b370af..3432e9a 100644 --- a/Source/WebCore/storage/IDBTransactionBackendInterface.h +++ b/Source/WebCore/storage/IDBTransactionBackendInterface.h @@ -43,7 +43,7 @@ class IDBTransactionCallbacks; // This is implemented by IDBTransactionBackendImpl 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 IDBTransactionBackendInterface : public ThreadSafeShared<IDBTransactionBackendInterface> { +class IDBTransactionBackendInterface : public ThreadSafeRefCounted<IDBTransactionBackendInterface> { public: virtual ~IDBTransactionBackendInterface() { } diff --git a/Source/WebCore/storage/LocalStorageTask.cpp b/Source/WebCore/storage/LocalStorageTask.cpp index d31c991..5d2c807 100644 --- a/Source/WebCore/storage/LocalStorageTask.cpp +++ b/Source/WebCore/storage/LocalStorageTask.cpp @@ -30,6 +30,7 @@ #include "LocalStorageThread.h" #include "StorageAreaSync.h" +#include "StorageTracker.h" namespace WebCore { @@ -50,6 +51,27 @@ LocalStorageTask::LocalStorageTask(Type type, LocalStorageThread* thread) ASSERT(m_thread); ASSERT(m_type == TerminateThread); } + +LocalStorageTask::LocalStorageTask(Type type) + : m_type(type) +{ + ASSERT(m_type == ImportOrigins || m_type == DeleteAllOrigins); +} + +LocalStorageTask::LocalStorageTask(Type type, const String& originIdentifier) + : m_type(type) + , m_originIdentifier(originIdentifier) +{ + ASSERT(m_type == DeleteOrigin); +} + +LocalStorageTask::LocalStorageTask(Type type, const String& originIdentifier, const String& databaseFilename) + : m_type(type) + , m_originIdentifier(originIdentifier) + , m_databaseFilename(databaseFilename) +{ + ASSERT(m_type == SetOriginDetails); +} LocalStorageTask::~LocalStorageTask() { @@ -64,6 +86,18 @@ void LocalStorageTask::performTask() case AreaSync: m_area->performSync(); break; + case SetOriginDetails: + StorageTracker::tracker().syncSetOriginDetails(m_originIdentifier, m_databaseFilename); + break; + case ImportOrigins: + StorageTracker::tracker().syncImportOriginIdentifiers(); + break; + case DeleteAllOrigins: + StorageTracker::tracker().syncDeleteAllOrigins(); + break; + case DeleteOrigin: + StorageTracker::tracker().syncDeleteOrigin(m_originIdentifier); + break; case DeleteEmptyDatabase: m_area->deleteEmptyDatabase(); break; diff --git a/Source/WebCore/storage/LocalStorageTask.h b/Source/WebCore/storage/LocalStorageTask.h index 27a8eb5..99e72f5 100644 --- a/Source/WebCore/storage/LocalStorageTask.h +++ b/Source/WebCore/storage/LocalStorageTask.h @@ -28,6 +28,7 @@ #if ENABLE(DOM_STORAGE) +#include "PlatformString.h" #include <wtf/PassOwnPtr.h> #include <wtf/Threading.h> @@ -40,13 +41,17 @@ namespace WebCore { class LocalStorageTask { WTF_MAKE_NONCOPYABLE(LocalStorageTask); WTF_MAKE_FAST_ALLOCATED; public: - enum Type { AreaImport, AreaSync, DeleteEmptyDatabase, TerminateThread }; + enum Type { AreaImport, AreaSync, DeleteEmptyDatabase, SetOriginDetails, ImportOrigins, DeleteAllOrigins, DeleteOrigin, TerminateThread }; ~LocalStorageTask(); static PassOwnPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return adoptPtr(new LocalStorageTask(AreaImport, area)); } static PassOwnPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return adoptPtr(new LocalStorageTask(AreaSync, area)); } static PassOwnPtr<LocalStorageTask> createDeleteEmptyDatabase(StorageAreaSync* area) { return adoptPtr(new LocalStorageTask(DeleteEmptyDatabase, area)); } + static PassOwnPtr<LocalStorageTask> createOriginIdentifiersImport() { return adoptPtr(new LocalStorageTask(ImportOrigins)); } + static PassOwnPtr<LocalStorageTask> createSetOriginDetails(const String& originIdentifier, const String& databaseFilename) { return adoptPtr(new LocalStorageTask(SetOriginDetails, originIdentifier, databaseFilename)); } + static PassOwnPtr<LocalStorageTask> createDeleteOrigin(const String& originIdentifier) { return adoptPtr(new LocalStorageTask(DeleteOrigin, originIdentifier)); } + static PassOwnPtr<LocalStorageTask> createDeleteAllOrigins() { return adoptPtr(new LocalStorageTask(DeleteAllOrigins)); } static PassOwnPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return adoptPtr(new LocalStorageTask(TerminateThread, thread)); } void performTask(); @@ -54,10 +59,15 @@ namespace WebCore { private: LocalStorageTask(Type, StorageAreaSync*); LocalStorageTask(Type, LocalStorageThread*); + LocalStorageTask(Type, const String& originIdentifier); + LocalStorageTask(Type, const String& originIdentifier, const String& databaseFilename); + LocalStorageTask(Type); Type m_type; StorageAreaSync* m_area; LocalStorageThread* m_thread; + String m_originIdentifier; + String m_databaseFilename; }; } // namespace WebCore diff --git a/Source/WebCore/storage/SQLCallbackWrapper.h b/Source/WebCore/storage/SQLCallbackWrapper.h new file mode 100644 index 0000000..38059fa --- /dev/null +++ b/Source/WebCore/storage/SQLCallbackWrapper.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 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 SQLCallbackWrapper_h +#define SQLCallbackWrapper_h + +#if ENABLE(DATABASE) + +#include "CrossThreadTask.h" +#include "ScriptExecutionContext.h" +#include <wtf/ThreadingPrimitives.h> + +namespace WebCore { + +// A helper class to safely dereference the callback objects held by +// SQLStatement and SQLTransaction on the proper thread. The 'wrapped' +// callback is dereferenced: +// - by destructing the enclosing wrapper - on any thread +// - by calling clear() - on any thread +// - by unwrapping and then dereferencing normally - on context thread only +template<typename T> class SQLCallbackWrapper { +public: + SQLCallbackWrapper(PassRefPtr<T> callback, ScriptExecutionContext* scriptExecutionContext) + : m_callback(callback) + , m_scriptExecutionContext(m_callback ? scriptExecutionContext : 0) + { + ASSERT(!m_callback || (m_scriptExecutionContext.get() && m_scriptExecutionContext->isContextThread())); + } + + ~SQLCallbackWrapper() + { + clear(); + } + + void clear() + { + ScriptExecutionContext* context; + T* callback; + { + MutexLocker locker(m_mutex); + if (!m_callback) { + ASSERT(!m_scriptExecutionContext); + return; + } + if (m_scriptExecutionContext->isContextThread()) { + m_callback = 0; + m_scriptExecutionContext = 0; + return; + } + context = m_scriptExecutionContext.release().leakRef(); + callback = m_callback.release().leakRef(); + } + context->postTask(createCallbackTask(&safeRelease, callback)); + } + + PassRefPtr<T> unwrap() + { + MutexLocker locker(m_mutex); + ASSERT(!m_callback || m_scriptExecutionContext->isContextThread()); + m_scriptExecutionContext = 0; + return m_callback.release(); + } + + // Useful for optimizations only, please test the return value of unwrap to be sure. + bool hasCallback() const { return m_callback; } + +private: + static void safeRelease(ScriptExecutionContext* context, T* callback) + { + ASSERT(callback && context && context->isContextThread()); + callback->deref(); + context->deref(); + } + + Mutex m_mutex; + RefPtr<T> m_callback; + RefPtr<ScriptExecutionContext> m_scriptExecutionContext; +}; + +} // namespace WebCore + +#endif // ENABLE(DATABASE) + +#endif // SQLCallbackWrapper_h diff --git a/Source/WebCore/storage/SQLError.h b/Source/WebCore/storage/SQLError.h index 496145a..eb9005b 100644 --- a/Source/WebCore/storage/SQLError.h +++ b/Source/WebCore/storage/SQLError.h @@ -32,11 +32,11 @@ #if ENABLE(DATABASE) #include "PlatformString.h" -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { -class SQLError : public ThreadSafeShared<SQLError> { +class SQLError : public ThreadSafeRefCounted<SQLError> { public: static PassRefPtr<SQLError> create(unsigned code, const String& message) { return adoptRef(new SQLError(code, message)); } diff --git a/Source/WebCore/storage/SQLResultSet.h b/Source/WebCore/storage/SQLResultSet.h index 268472f..964504c 100644 --- a/Source/WebCore/storage/SQLResultSet.h +++ b/Source/WebCore/storage/SQLResultSet.h @@ -33,11 +33,11 @@ #include "ExceptionCode.h" #include "SQLResultSetRowList.h" -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { -class SQLResultSet : public ThreadSafeShared<SQLResultSet> { +class SQLResultSet : public ThreadSafeRefCounted<SQLResultSet> { public: static PassRefPtr<SQLResultSet> create() { return adoptRef(new SQLResultSet); } diff --git a/Source/WebCore/storage/SQLStatement.cpp b/Source/WebCore/storage/SQLStatement.cpp index 306f561..58b7f71 100644 --- a/Source/WebCore/storage/SQLStatement.cpp +++ b/Source/WebCore/storage/SQLStatement.cpp @@ -43,16 +43,16 @@ namespace WebCore { -PassRefPtr<SQLStatement> SQLStatement::create(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, int permissions) +PassRefPtr<SQLStatement> SQLStatement::create(Database* database, const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, int permissions) { - return adoptRef(new SQLStatement(statement, arguments, callback, errorCallback, permissions)); + return adoptRef(new SQLStatement(database, statement, arguments, callback, errorCallback, permissions)); } -SQLStatement::SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, int permissions) +SQLStatement::SQLStatement(Database* database, const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, int permissions) : m_statement(statement.crossThreadString()) , m_arguments(arguments) - , m_statementCallback(callback) - , m_statementErrorCallback(errorCallback) + , m_statementCallbackWrapper(callback, database->scriptExecutionContext()) + , m_statementErrorCallbackWrapper(errorCallback, database->scriptExecutionContext()) , m_permissions(permissions) { } @@ -166,17 +166,16 @@ bool SQLStatement::performCallback(SQLTransaction* transaction) bool callbackError = false; + RefPtr<SQLStatementCallback> callback = m_statementCallbackWrapper.unwrap(); + RefPtr<SQLStatementErrorCallback> errorCallback = m_statementErrorCallbackWrapper.unwrap(); + // Call the appropriate statement callback and track if it resulted in an error, // because then we need to jump to the transaction error callback. if (m_error) { - ASSERT(m_statementErrorCallback); - callbackError = m_statementErrorCallback->handleEvent(transaction, m_error.get()); - } else if (m_statementCallback) - callbackError = !m_statementCallback->handleEvent(transaction, m_resultSet.get()); - - // Now release our callbacks, to break reference cycles. - m_statementCallback = 0; - m_statementErrorCallback = 0; + ASSERT(errorCallback); + callbackError = errorCallback->handleEvent(transaction, m_error.get()); + } else if (callback) + callbackError = !callback->handleEvent(transaction, m_resultSet.get()); return callbackError; } diff --git a/Source/WebCore/storage/SQLStatement.h b/Source/WebCore/storage/SQLStatement.h index afd605a..1d81eb2 100644 --- a/Source/WebCore/storage/SQLStatement.h +++ b/Source/WebCore/storage/SQLStatement.h @@ -31,6 +31,7 @@ #if ENABLE(DATABASE) #include "PlatformString.h" +#include "SQLCallbackWrapper.h" #include "SQLResultSet.h" #include "SQLValue.h" #include <wtf/Forward.h> @@ -44,15 +45,15 @@ class SQLStatementCallback; class SQLStatementErrorCallback; class SQLTransaction; -class SQLStatement : public ThreadSafeShared<SQLStatement> { +class SQLStatement : public ThreadSafeRefCounted<SQLStatement> { public: - static PassRefPtr<SQLStatement> create(const String&, const Vector<SQLValue>&, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, int permissions); + static PassRefPtr<SQLStatement> create(Database*, const String&, const Vector<SQLValue>&, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, int permissions); bool execute(Database*); bool lastExecutionFailedDueToQuota() const; - bool hasStatementCallback() const { return m_statementCallback; } - bool hasStatementErrorCallback() const { return m_statementErrorCallback; } + bool hasStatementCallback() const { return m_statementCallbackWrapper.hasCallback(); } + bool hasStatementErrorCallback() const { return m_statementErrorCallbackWrapper.hasCallback(); } void setDatabaseDeletedError(); void setVersionMismatchedError(); @@ -61,15 +62,15 @@ public: SQLError* sqlError() const { return m_error.get(); } private: - SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, int permissions); + SQLStatement(Database*, const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, int permissions); void setFailureDueToQuota(); void clearFailureDueToQuota(); String m_statement; Vector<SQLValue> m_arguments; - RefPtr<SQLStatementCallback> m_statementCallback; - RefPtr<SQLStatementErrorCallback> m_statementErrorCallback; + SQLCallbackWrapper<SQLStatementCallback> m_statementCallbackWrapper; + SQLCallbackWrapper<SQLStatementErrorCallback> m_statementErrorCallbackWrapper; RefPtr<SQLError> m_error; RefPtr<SQLResultSet> m_resultSet; diff --git a/Source/WebCore/storage/SQLStatementCallback.h b/Source/WebCore/storage/SQLStatementCallback.h index f86e29f..cae5827 100644 --- a/Source/WebCore/storage/SQLStatementCallback.h +++ b/Source/WebCore/storage/SQLStatementCallback.h @@ -30,14 +30,14 @@ #if ENABLE(DATABASE) -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { class SQLTransaction; class SQLResultSet; -class SQLStatementCallback : public ThreadSafeShared<SQLStatementCallback> { +class SQLStatementCallback : public ThreadSafeRefCounted<SQLStatementCallback> { public: virtual ~SQLStatementCallback() { } virtual bool handleEvent(SQLTransaction*, SQLResultSet*) = 0; diff --git a/Source/WebCore/storage/SQLStatementErrorCallback.h b/Source/WebCore/storage/SQLStatementErrorCallback.h index acb8f64..5fecec4 100644 --- a/Source/WebCore/storage/SQLStatementErrorCallback.h +++ b/Source/WebCore/storage/SQLStatementErrorCallback.h @@ -31,14 +31,14 @@ #if ENABLE(DATABASE) -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { class SQLTransaction; class SQLError; -class SQLStatementErrorCallback : public ThreadSafeShared<SQLStatementErrorCallback> { +class SQLStatementErrorCallback : public ThreadSafeRefCounted<SQLStatementErrorCallback> { public: virtual ~SQLStatementErrorCallback() { } virtual bool handleEvent(SQLTransaction*, SQLError*) = 0; diff --git a/Source/WebCore/storage/SQLTransaction.cpp b/Source/WebCore/storage/SQLTransaction.cpp index dea9d97..dfcd568 100644 --- a/Source/WebCore/storage/SQLTransaction.cpp +++ b/Source/WebCore/storage/SQLTransaction.cpp @@ -71,9 +71,9 @@ SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> , m_executeSqlAllowed(false) , m_database(db) , m_wrapper(wrapper) - , m_callback(callback) - , m_successCallback(successCallback) - , m_errorCallback(errorCallback) + , m_callbackWrapper(callback, db->scriptExecutionContext()) + , m_successCallbackWrapper(successCallback, db->scriptExecutionContext()) + , m_errorCallbackWrapper(errorCallback, db->scriptExecutionContext()) , m_shouldRetryCurrentStatement(false) , m_modifiedDatabase(false) , m_lockAcquired(false) @@ -100,7 +100,7 @@ void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValu else if (m_readOnly) permissions |= DatabaseAuthorizer::ReadOnlyMask; - RefPtr<SQLStatement> statement = SQLStatement::create(sqlStatement, arguments, callback, callbackError, permissions); + RefPtr<SQLStatement> statement = SQLStatement::create(m_database.get(), sqlStatement, arguments, callback, callbackError, permissions); if (m_database->deleted()) statement->setDatabaseDeletedError(); @@ -159,9 +159,9 @@ void SQLTransaction::checkAndHandleClosedOrInterruptedDatabase() m_nextStep = 0; // Release the unneeded callbacks, to break reference cycles. - m_callback = 0; - m_successCallback = 0; - m_errorCallback = 0; + m_callbackWrapper.clear(); + m_successCallbackWrapper.clear(); + m_errorCallbackWrapper.clear(); // The next steps should be executed only if we're on the DB thread. if (currentThread() != database()->scriptExecutionContext()->databaseThread()->getThreadID()) @@ -293,11 +293,11 @@ void SQLTransaction::deliverTransactionCallback() { bool shouldDeliverErrorCallback = false; - if (m_callback) { + RefPtr<SQLTransactionCallback> callback = m_callbackWrapper.unwrap(); + if (callback) { m_executeSqlAllowed = true; - shouldDeliverErrorCallback = !m_callback->handleEvent(this); + shouldDeliverErrorCallback = !callback->handleEvent(this); m_executeSqlAllowed = false; - m_callback = 0; } // Transaction Step 5 - If the transaction callback was null or raised an exception, jump to the error callback @@ -425,7 +425,7 @@ void SQLTransaction::deliverStatementCallback() m_executeSqlAllowed = false; if (result) { - m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false"); + m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false"); handleTransactionError(true); } else scheduleToRunStatements(); @@ -465,7 +465,7 @@ void SQLTransaction::postflightAndCommit() // If the commit failed, the transaction will still be marked as "in progress" if (m_sqliteTransaction->inProgress()) { - m_successCallback = 0; + m_successCallbackWrapper.clear(); m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "failed to commit the transaction"); handleTransactionError(false); return; @@ -480,10 +480,10 @@ void SQLTransaction::postflightAndCommit() m_database->transactionClient()->didCommitWriteTransaction(database()); // Now release our unneeded callbacks, to break reference cycles. - m_errorCallback = 0; + m_errorCallbackWrapper.clear(); // Transaction Step 10 - Deliver success callback, if there is one - if (m_successCallback) { + if (m_successCallbackWrapper.hasCallback()) { m_nextStep = &SQLTransaction::deliverSuccessCallback; LOG(StorageAPI, "Scheduling deliverSuccessCallback for transaction %p\n", this); m_database->scheduleTransactionCallback(this); @@ -494,11 +494,9 @@ void SQLTransaction::postflightAndCommit() void SQLTransaction::deliverSuccessCallback() { // Transaction Step 10 - Deliver success callback - ASSERT(m_successCallback); - m_successCallback->handleEvent(); - - // Release the last callback to break reference cycle - m_successCallback = 0; + RefPtr<VoidCallback> successCallback = m_successCallbackWrapper.unwrap(); + if (successCallback) + successCallback->handleEvent(); // Schedule a "post-success callback" step to return control to the database thread in case there // are further transactions queued up for this Database @@ -524,7 +522,7 @@ void SQLTransaction::cleanupAfterSuccessCallback() void SQLTransaction::handleTransactionError(bool inCallback) { - if (m_errorCallback) { + if (m_errorCallbackWrapper.hasCallback()) { if (inCallback) deliverTransactionErrorCallback(); else { @@ -552,10 +550,9 @@ void SQLTransaction::deliverTransactionErrorCallback() // Transaction Step 12 - If exists, invoke error callback with the last // error to have occurred in this transaction. - if (m_errorCallback) { - m_errorCallback->handleEvent(m_transactionError.get()); - m_errorCallback = 0; - } + RefPtr<SQLTransactionErrorCallback> errorCallback = m_errorCallbackWrapper.unwrap(); + if (errorCallback) + errorCallback->handleEvent(m_transactionError.get()); m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback; LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this); diff --git a/Source/WebCore/storage/SQLTransaction.h b/Source/WebCore/storage/SQLTransaction.h index 3eb1fd5..4c84f91 100644 --- a/Source/WebCore/storage/SQLTransaction.h +++ b/Source/WebCore/storage/SQLTransaction.h @@ -34,7 +34,7 @@ #include "SQLStatement.h" #include <wtf/Deque.h> #include <wtf/Forward.h> -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> #include <wtf/Vector.h> namespace WebCore { @@ -50,7 +50,7 @@ class SQLTransactionErrorCallback; class SQLValue; class VoidCallback; -class SQLTransactionWrapper : public ThreadSafeShared<SQLTransactionWrapper> { +class SQLTransactionWrapper : public ThreadSafeRefCounted<SQLTransactionWrapper> { public: virtual ~SQLTransactionWrapper() { } virtual bool performPreflight(SQLTransaction*) = 0; @@ -59,7 +59,7 @@ public: virtual SQLError* sqlError() const = 0; }; -class SQLTransaction : public ThreadSafeShared<SQLTransaction> { +class SQLTransaction : public ThreadSafeRefCounted<SQLTransaction> { public: static PassRefPtr<SQLTransaction> create(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>, PassRefPtr<VoidCallback>, PassRefPtr<SQLTransactionWrapper>, bool readOnly = false); @@ -115,9 +115,9 @@ private: RefPtr<Database> m_database; RefPtr<SQLTransactionWrapper> m_wrapper; - RefPtr<SQLTransactionCallback> m_callback; - RefPtr<VoidCallback> m_successCallback; - RefPtr<SQLTransactionErrorCallback> m_errorCallback; + SQLCallbackWrapper<SQLTransactionCallback> m_callbackWrapper; + SQLCallbackWrapper<VoidCallback> m_successCallbackWrapper; + SQLCallbackWrapper<SQLTransactionErrorCallback> m_errorCallbackWrapper; RefPtr<SQLError> m_transactionError; bool m_shouldRetryCurrentStatement; bool m_modifiedDatabase; diff --git a/Source/WebCore/storage/SQLTransactionCallback.h b/Source/WebCore/storage/SQLTransactionCallback.h index aff6233..6904880 100644 --- a/Source/WebCore/storage/SQLTransactionCallback.h +++ b/Source/WebCore/storage/SQLTransactionCallback.h @@ -31,13 +31,13 @@ #if ENABLE(DATABASE) -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { class SQLTransaction; -class SQLTransactionCallback : public ThreadSafeShared<SQLTransactionCallback> { +class SQLTransactionCallback : public ThreadSafeRefCounted<SQLTransactionCallback> { public: virtual ~SQLTransactionCallback() { } virtual bool handleEvent(SQLTransaction*) = 0; diff --git a/Source/WebCore/storage/SQLTransactionErrorCallback.h b/Source/WebCore/storage/SQLTransactionErrorCallback.h index 4095d6a..f067571 100644 --- a/Source/WebCore/storage/SQLTransactionErrorCallback.h +++ b/Source/WebCore/storage/SQLTransactionErrorCallback.h @@ -31,13 +31,13 @@ #if ENABLE(DATABASE) -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { class SQLError; -class SQLTransactionErrorCallback : public ThreadSafeShared<SQLTransactionErrorCallback> { +class SQLTransactionErrorCallback : public ThreadSafeRefCounted<SQLTransactionErrorCallback> { public: virtual ~SQLTransactionErrorCallback() { } virtual bool handleEvent(SQLError*) = 0; diff --git a/Source/WebCore/storage/StorageAreaImpl.cpp b/Source/WebCore/storage/StorageAreaImpl.cpp index 54df135..bb2d702 100644 --- a/Source/WebCore/storage/StorageAreaImpl.cpp +++ b/Source/WebCore/storage/StorageAreaImpl.cpp @@ -231,6 +231,31 @@ void StorageAreaImpl::close() #endif } +void StorageAreaImpl::clearForOriginDeletion() +{ + ASSERT(!m_isShutdown); + blockUntilImportComplete(); + + if (m_storageMap->length()) { + unsigned quota = m_storageMap->quota(); + m_storageMap = StorageMap::create(quota); + } + + if (m_storageAreaSync) { + m_storageAreaSync->scheduleClear(); + m_storageAreaSync->scheduleCloseDatabase(); + } +} + +void StorageAreaImpl::sync() +{ + ASSERT(!m_isShutdown); + blockUntilImportComplete(); + + if (m_storageAreaSync) + m_storageAreaSync->scheduleSync(); +} + void StorageAreaImpl::blockUntilImportComplete() const { if (m_storageAreaSync) diff --git a/Source/WebCore/storage/StorageAreaImpl.h b/Source/WebCore/storage/StorageAreaImpl.h index 60d72cb..9f87e69 100644 --- a/Source/WebCore/storage/StorageAreaImpl.h +++ b/Source/WebCore/storage/StorageAreaImpl.h @@ -59,6 +59,11 @@ namespace WebCore { // Only called from a background thread. void importItem(const String& key, const String& value); + // Used to clear a StorageArea and close db before backing db file is deleted. + void clearForOriginDeletion(); + + void sync(); + private: StorageAreaImpl(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota); StorageAreaImpl(StorageAreaImpl*); diff --git a/Source/WebCore/storage/StorageAreaSync.cpp b/Source/WebCore/storage/StorageAreaSync.cpp index f2008ab..94a002a 100644 --- a/Source/WebCore/storage/StorageAreaSync.cpp +++ b/Source/WebCore/storage/StorageAreaSync.cpp @@ -36,6 +36,7 @@ #include "SecurityOrigin.h" #include "StorageAreaImpl.h" #include "StorageSyncManager.h" +#include "StorageTracker.h" #include "SuddenTermination.h" #include <wtf/text/CString.h> @@ -60,6 +61,7 @@ inline StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSy , m_syncScheduled(false) , m_syncInProgress(false) , m_databaseOpenFailed(false) + , m_syncCloseDatabase(false) , m_importComplete(false) { ASSERT(isMainThread()); @@ -138,6 +140,25 @@ void StorageAreaSync::scheduleClear() } } +void StorageAreaSync::scheduleCloseDatabase() +{ + ASSERT(isMainThread()); + ASSERT(!m_finalSyncScheduled); + + if (!m_database.isOpen()) + return; + + m_syncCloseDatabase = true; + + if (!m_syncTimer.isActive()) { + m_syncTimer.startOneShot(StorageSyncInterval); + + // The following is balanced by the call to enableSuddenTermination in the + // syncTimerFired function. + disableSuddenTermination(); + } +} + void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*) { ASSERT(isMainThread()); @@ -222,6 +243,10 @@ void StorageAreaSync::openDatabase(OpenDatabaseParamType openingStrategy) return; } + // A StorageTracker thread may have been scheduled to delete the db we're + // reopening, so cancel possible deletion. + StorageTracker::tracker().cancelDeletingOrigin(m_databaseIdentifier); + if (!m_database.open(databaseFilename)) { LOG_ERROR("Failed to open database file %s for local storage", databaseFilename.utf8().data()); markImported(); @@ -235,6 +260,8 @@ void StorageAreaSync::openDatabase(OpenDatabaseParamType openingStrategy) m_databaseOpenFailed = true; return; } + + StorageTracker::tracker().setOriginDetails(m_databaseIdentifier, databaseFilename); } void StorageAreaSync::performImport() @@ -319,6 +346,15 @@ void StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items if (!m_database.isOpen()) return; + // Closing this db because it is about to be deleted by StorageTracker. + // The delete will be cancelled if StorageAreaSync needs to reopen the db + // to write new items created after the request to delete the db. + if (m_syncCloseDatabase) { + m_syncCloseDatabase = false; + m_database.close(); + return; + } + // If the clear flag is set, then we clear all items out before we write any new ones in. if (clearItems) { SQLiteStatement clear(m_database, "DELETE FROM ItemTable"); @@ -421,12 +457,21 @@ void StorageAreaSync::deleteEmptyDatabase() if (!count) { query.finalize(); m_database.close(); - String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier); - if (!SQLiteFileSystem::deleteDatabaseFile(databaseFilename)) - LOG_ERROR("Failed to delete database file %s\n", databaseFilename.utf8().data()); + if (StorageTracker::tracker().isActive()) + StorageTracker::tracker().deleteOrigin(m_databaseIdentifier); + else { + String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier); + if (!SQLiteFileSystem::deleteDatabaseFile(databaseFilename)) + LOG_ERROR("Failed to delete database file %s\n", databaseFilename.utf8().data()); + } } } +void StorageAreaSync::scheduleSync() +{ + syncTimerFired(&m_syncTimer); +} + } // namespace WebCore #endif // ENABLE(DOM_STORAGE) diff --git a/Source/WebCore/storage/StorageAreaSync.h b/Source/WebCore/storage/StorageAreaSync.h index 90aa6a7..ebfb053 100644 --- a/Source/WebCore/storage/StorageAreaSync.h +++ b/Source/WebCore/storage/StorageAreaSync.h @@ -49,6 +49,9 @@ namespace WebCore { void scheduleItemForSync(const String& key, const String& value); void scheduleClear(); + void scheduleCloseDatabase(); + + void scheduleSync(); private: StorageAreaSync(PassRefPtr<StorageSyncManager>, PassRefPtr<StorageAreaImpl>, const String& databaseIdentifier); @@ -92,6 +95,8 @@ namespace WebCore { bool m_syncScheduled; bool m_syncInProgress; bool m_databaseOpenFailed; + + bool m_syncCloseDatabase; mutable Mutex m_importLock; mutable ThreadCondition m_importCondition; diff --git a/Source/WebCore/storage/StorageNamespace.h b/Source/WebCore/storage/StorageNamespace.h index f7dad1e..f5604b0 100644 --- a/Source/WebCore/storage/StorageNamespace.h +++ b/Source/WebCore/storage/StorageNamespace.h @@ -50,10 +50,16 @@ public: virtual PassRefPtr<StorageNamespace> copy() = 0; virtual void close() = 0; virtual void unlock() = 0; +<<<<<<< HEAD #ifdef ANDROID virtual void clear(Page*) = 0; #endif +======= + virtual void clearOriginForDeletion(SecurityOrigin*) = 0; + virtual void clearAllOriginsForDeletion() = 0; + virtual void sync() = 0; +>>>>>>> webkit.org at r82507 }; } // namespace WebCore diff --git a/Source/WebCore/storage/StorageNamespaceImpl.cpp b/Source/WebCore/storage/StorageNamespaceImpl.cpp index 68508a7..c6279ed 100644 --- a/Source/WebCore/storage/StorageNamespaceImpl.cpp +++ b/Source/WebCore/storage/StorageNamespaceImpl.cpp @@ -32,6 +32,7 @@ #include "StorageAreaImpl.h" #include "StorageMap.h" #include "StorageSyncManager.h" +#include "StorageTracker.h" #include <wtf/StdLibExtras.h> #include <wtf/text/StringHash.h> @@ -167,6 +168,32 @@ void StorageNamespaceImpl::unlock() // Because there's a single event loop per-process, this is a no-op. } +void StorageNamespaceImpl::clearOriginForDeletion(SecurityOrigin* origin) +{ + ASSERT(isMainThread()); + + RefPtr<StorageAreaImpl> storageArea = m_storageAreaMap.get(origin); + if (storageArea) + storageArea->clearForOriginDeletion(); +} + +void StorageNamespaceImpl::clearAllOriginsForDeletion() +{ + ASSERT(isMainThread()); + + StorageAreaMap::iterator end = m_storageAreaMap.end(); + for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) + it->second->clearForOriginDeletion(); +} + +void StorageNamespaceImpl::sync() +{ + ASSERT(isMainThread()); + StorageAreaMap::iterator end = m_storageAreaMap.end(); + for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) + it->second->sync(); +} + } // namespace WebCore #endif // ENABLE(DOM_STORAGE) diff --git a/Source/WebCore/storage/StorageNamespaceImpl.h b/Source/WebCore/storage/StorageNamespaceImpl.h index c2361fa..871f540 100644 --- a/Source/WebCore/storage/StorageNamespaceImpl.h +++ b/Source/WebCore/storage/StorageNamespaceImpl.h @@ -53,10 +53,21 @@ namespace WebCore { virtual void close(); virtual void unlock(); +<<<<<<< HEAD #ifdef ANDROID virtual void clear(Page*); #endif +======= + // Not removing the origin's StorageArea from m_storageAreaMap because + // we're just deleting the underlying db file. If an item is added immediately + // after file deletion, we want the same StorageArea to eventually trigger + // a sync and for StorageAreaSync to recreate the backing db file. + virtual void clearOriginForDeletion(SecurityOrigin*); + virtual void clearAllOriginsForDeletion(); + virtual void sync(); + +>>>>>>> webkit.org at r82507 private: StorageNamespaceImpl(StorageType, const String& path, unsigned quota); diff --git a/Source/WebCore/storage/StorageTracker.cpp b/Source/WebCore/storage/StorageTracker.cpp new file mode 100644 index 0000000..e18b4b8 --- /dev/null +++ b/Source/WebCore/storage/StorageTracker.cpp @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2011 Apple 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "StorageTracker.h" + +#if ENABLE(DOM_STORAGE) + +#include "DatabaseThread.h" +#include "FileSystem.h" +#include "LocalStorageTask.h" +#include "LocalStorageThread.h" +#include "Logging.h" +#include "PageGroup.h" +#include "SQLiteFileSystem.h" +#include "SQLiteStatement.h" +#include "SecurityOrigin.h" +#include "StorageTrackerClient.h" +#include "TextEncoding.h" +#include <wtf/MainThread.h> +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> +#include <wtf/text/CString.h> + +namespace WebCore { + +static StorageTracker* storageTracker = 0; + +void StorageTracker::initializeTracker(const String& storagePath) +{ + ASSERT(isMainThread()); + ASSERT(!storageTracker); + + if (!storageTracker) + storageTracker = new StorageTracker(storagePath); + + // Make sure text encoding maps have been built on the main thread, as the StorageTracker thread might try to do it there instead. + // FIXME (<rdar://problem/9127819>): Is there a more explicit way of doing this besides accessing the UTF8Encoding? + UTF8Encoding(); + + SQLiteFileSystem::registerSQLiteVFS(); + storageTracker->setIsActive(true); + storageTracker->m_thread->start(); + storageTracker->importOriginIdentifiers(); +} + +StorageTracker& StorageTracker::tracker() +{ + if (!storageTracker) + storageTracker = new StorageTracker(""); + + return *storageTracker; +} + +StorageTracker::StorageTracker(const String& storagePath) + : m_client(0) + , m_thread(LocalStorageThread::create()) + , m_isActive(false) +{ + setStorageDirectoryPath(storagePath); +} + +void StorageTracker::setStorageDirectoryPath(const String& path) +{ + MutexLocker lockDatabase(m_databaseGuard); + ASSERT(!m_database.isOpen()); + + m_storageDirectoryPath = path.threadsafeCopy(); +} + +String StorageTracker::trackerDatabasePath() +{ + ASSERT(!m_databaseGuard.tryLock()); + return SQLiteFileSystem::appendDatabaseFileNameToPath(m_storageDirectoryPath, "StorageTracker.db"); +} + +void StorageTracker::openTrackerDatabase(bool createIfDoesNotExist) +{ + ASSERT(m_isActive); + ASSERT(!isMainThread()); + ASSERT(!m_databaseGuard.tryLock()); + + if (m_database.isOpen()) + return; + + String databasePath = trackerDatabasePath(); + + if (!SQLiteFileSystem::ensureDatabaseFileExists(databasePath, createIfDoesNotExist)) { + if (createIfDoesNotExist) + LOG_ERROR("Failed to create database file '%s'", databasePath.ascii().data()); + return; + } + + if (!m_database.open(databasePath)) { + 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, path TEXT);")) + LOG_ERROR("Failed to create Origins table."); + } +} + +void StorageTracker::importOriginIdentifiers() +{ + if (!m_isActive) + return; + + ASSERT(isMainThread()); + ASSERT(m_thread); + + m_thread->scheduleTask(LocalStorageTask::createOriginIdentifiersImport()); +} + +void StorageTracker::syncImportOriginIdentifiers() +{ + ASSERT(m_isActive); + + ASSERT(!isMainThread()); + + { + MutexLocker lockDatabase(m_databaseGuard); + + // Don't force creation of StorageTracker's db just because a tracker + // was initialized. It will be created if local storage dbs are found + // by syncFileSystemAndTrackerDatabse() or the next time a local storage + // db is created by StorageAreaSync. + openTrackerDatabase(false); + + if (m_database.isOpen()) { + SQLiteStatement statement(m_database, "SELECT origin FROM Origins"); + if (statement.prepare() != SQLResultOk) { + LOG_ERROR("Failed to prepare statement."); + return; + } + + int result; + + { + MutexLocker lockOrigins(m_originSetGuard); + while ((result = statement.step()) == SQLResultRow) + m_originSet.add(statement.getColumnText(0).threadsafeCopy()); + } + + if (result != SQLResultDone) { + LOG_ERROR("Failed to read in all origins from the database."); + return; + } + } + } + + syncFileSystemAndTrackerDatabase(); + + { + MutexLocker lockClient(m_clientGuard); + if (m_client) { + MutexLocker lockOrigins(m_originSetGuard); + OriginSet::const_iterator end = m_originSet.end(); + for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it) + m_client->dispatchDidModifyOrigin(*it); + } + } +} + +void StorageTracker::syncFileSystemAndTrackerDatabase() +{ + ASSERT(!isMainThread()); + ASSERT(m_isActive); + + m_databaseGuard.lock(); + DEFINE_STATIC_LOCAL(const String, fileMatchPattern, ("*.localstorage")); + DEFINE_STATIC_LOCAL(const String, fileExt, (".localstorage")); + DEFINE_STATIC_LOCAL(const unsigned, fileExtLength, (fileExt.length())); + m_databaseGuard.unlock(); + + Vector<String> paths; + { + MutexLocker lock(m_databaseGuard); + paths = listDirectory(m_storageDirectoryPath, fileMatchPattern); + } + + // Use a copy of m_originSet to find expired entries and to schedule their + // deletions from disk and from m_originSet. + OriginSet originSetCopy; + { + MutexLocker lock(m_originSetGuard); + OriginSet::const_iterator end = m_originSet.end(); + for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it) + originSetCopy.add((*it).threadsafeCopy()); + } + + // Add missing StorageTracker records. + OriginSet foundOrigins; + Vector<String>::const_iterator end = paths.end(); + for (Vector<String>::const_iterator it = paths.begin(); it != end; ++it) { + String path = *it; + if (path.endsWith(fileExt, true) && path.length() > fileExtLength) { + String file = pathGetFileName(path); + String originIdentifier = file.substring(0, file.length() - fileExtLength); + if (!originSetCopy.contains(originIdentifier)) + syncSetOriginDetails(originIdentifier, path); + + foundOrigins.add(originIdentifier); + } + } + + // Delete stale StorageTracker records. + OriginSet::const_iterator setEnd = originSetCopy.end(); + for (OriginSet::const_iterator it = originSetCopy.begin(); it != setEnd; ++it) { + if (!foundOrigins.contains(*it)) + syncDeleteOrigin(*it); + } +} + +void StorageTracker::setOriginDetails(const String& originIdentifier, const String& databaseFile) +{ + if (!m_isActive) + return; + + { + MutexLocker lockOrigins(m_originSetGuard); + + if (m_originSet.contains(originIdentifier)) + return; + + m_originSet.add(originIdentifier); + } + + OwnPtr<LocalStorageTask> task = LocalStorageTask::createSetOriginDetails(originIdentifier.threadsafeCopy(), databaseFile); + + if (isMainThread()) { + ASSERT(m_thread); + m_thread->scheduleTask(task.release()); + } else + callOnMainThread(scheduleTask, reinterpret_cast<void*>(task.leakPtr())); +} + +void StorageTracker::scheduleTask(void* taskIn) +{ + ASSERT(isMainThread()); + ASSERT(StorageTracker::tracker().m_thread); + + OwnPtr<LocalStorageTask> task = adoptPtr(reinterpret_cast<LocalStorageTask*>(taskIn)); + + StorageTracker::tracker().m_thread->scheduleTask(task.release()); +} + +void StorageTracker::syncSetOriginDetails(const String& originIdentifier, const String& databaseFile) +{ + ASSERT(!isMainThread()); + + MutexLocker lockDatabase(m_databaseGuard); + + openTrackerDatabase(true); + + if (!m_database.isOpen()) + return; + + SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)"); + if (statement.prepare() != SQLResultOk) { + LOG_ERROR("Unable to establish origin '%s' in the tracker", originIdentifier.ascii().data()); + return; + } + + statement.bindText(1, originIdentifier); + statement.bindText(2, databaseFile); + + if (statement.step() != SQLResultDone) + LOG_ERROR("Unable to establish origin '%s' in the tracker", originIdentifier.ascii().data()); + + { + MutexLocker lockOrigins(m_originSetGuard); + if (!m_originSet.contains(originIdentifier)) + m_originSet.add(originIdentifier); + } + + { + MutexLocker lockClient(m_clientGuard); + if (m_client) + m_client->dispatchDidModifyOrigin(originIdentifier); + } +} + +void StorageTracker::origins(Vector<RefPtr<SecurityOrigin> >& result) +{ + ASSERT(m_isActive); + + if (!m_isActive) + return; + + MutexLocker lockOrigins(m_originSetGuard); + + OriginSet::const_iterator end = m_originSet.end(); + for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it) + result.append(SecurityOrigin::createFromDatabaseIdentifier(*it)); +} + +void StorageTracker::deleteAllOrigins() +{ + ASSERT(m_isActive); + ASSERT(isMainThread()); + ASSERT(m_thread); + + if (!m_isActive) + return; + + { + MutexLocker lockOrigins(m_originSetGuard); + willDeleteAllOrigins(); + m_originSet.clear(); + } + + PageGroup::clearLocalStorageForAllOrigins(); + + m_thread->scheduleTask(LocalStorageTask::createDeleteAllOrigins()); +} + +void StorageTracker::syncDeleteAllOrigins() +{ + ASSERT(!isMainThread()); + + MutexLocker lockDatabase(m_databaseGuard); + + openTrackerDatabase(false); + if (!m_database.isOpen()) + return; + + SQLiteStatement statement(m_database, "SELECT origin, path FROM Origins"); + if (statement.prepare() != SQLResultOk) { + LOG_ERROR("Failed to prepare statement."); + return; + } + + int result; + while ((result = statement.step()) == SQLResultRow) { + if (!canDeleteOrigin(statement.getColumnText(0))) + continue; + + SQLiteFileSystem::deleteDatabaseFile(statement.getColumnText(1)); + + { + MutexLocker lockClient(m_clientGuard); + if (m_client) + m_client->dispatchDidModifyOrigin(statement.getColumnText(0)); + } + } + + if (result != SQLResultDone) + LOG_ERROR("Failed to read in all origins from the database."); + + if (m_database.isOpen()) + m_database.close(); + + SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); + SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_storageDirectoryPath); +} + +void StorageTracker::deleteOrigin(const String& originIdentifier) +{ + deleteOrigin(SecurityOrigin::createFromDatabaseIdentifier(originIdentifier).get()); +} + +void StorageTracker::deleteOrigin(SecurityOrigin* origin) +{ + ASSERT(m_isActive); + ASSERT(isMainThread()); + ASSERT(m_thread); + + if (!m_isActive) + return; + + // Before deleting database, we need to clear in-memory local storage data + // in StorageArea, and to close the StorageArea db. It's possible for an + // item to be added immediately after closing the db and cause StorageAreaSync + // to reopen the db before the db is deleted by a StorageTracker thread. + // In this case, reopening the db in StorageAreaSync will cancel a pending + // StorageTracker db deletion. + PageGroup::clearLocalStorageForOrigin(origin); + + String originId = origin->databaseIdentifier(); + + { + MutexLocker lockOrigins(m_originSetGuard); + willDeleteOrigin(originId); + m_originSet.remove(originId); + } + + m_thread->scheduleTask(LocalStorageTask::createDeleteOrigin(originId)); +} + +void StorageTracker::syncDeleteOrigin(const String& originIdentifier) +{ + ASSERT(!isMainThread()); + + MutexLocker lockDatabase(m_databaseGuard); + + if (!canDeleteOrigin(originIdentifier)) { + LOG_ERROR("Attempted to delete origin '%s' while it was being created\n", originIdentifier.ascii().data()); + return; + } + + openTrackerDatabase(false); + if (!m_database.isOpen()) + return; + + // Get origin's db file path, delete entry in tracker's db, then delete db file. + SQLiteStatement pathStatement(m_database, "SELECT path FROM Origins WHERE origin=?"); + if (pathStatement.prepare() != SQLResultOk) { + LOG_ERROR("Unable to prepare selection of path for origin '%s'", originIdentifier.ascii().data()); + return; + } + pathStatement.bindText(1, originIdentifier); + int result = pathStatement.step(); + if (result != SQLResultRow) { + LOG_ERROR("Unable to find origin '%s' in Origins table", originIdentifier.ascii().data()); + return; + } + + String path = pathStatement.getColumnText(0); + + ASSERT(!path.isEmpty()); + + SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins where origin=?"); + if (deleteStatement.prepare() != SQLResultOk) { + LOG_ERROR("Unable to prepare deletion of origin '%s'", originIdentifier.ascii().data()); + return; + } + deleteStatement.bindText(1, originIdentifier); + if (!deleteStatement.executeCommand()) { + LOG_ERROR("Unable to execute deletion of origin '%s'", originIdentifier.ascii().data()); + return; + } + + SQLiteFileSystem::deleteDatabaseFile(path); + + bool shouldDeleteTrackerFiles = false; + { + MutexLocker originLock(m_originSetGuard); + m_originSet.remove(originIdentifier); + shouldDeleteTrackerFiles = m_originSet.isEmpty(); + } + + if (shouldDeleteTrackerFiles) { + m_database.close(); + SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); + SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_storageDirectoryPath); + } + + { + MutexLocker lockClient(m_clientGuard); + if (m_client) + m_client->dispatchDidModifyOrigin(originIdentifier); + } +} + +void StorageTracker::willDeleteAllOrigins() +{ + ASSERT(!m_originSetGuard.tryLock()); + + OriginSet::const_iterator end = m_originSet.end(); + for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it) + m_originsBeingDeleted.add((*it).threadsafeCopy()); +} + +void StorageTracker::willDeleteOrigin(const String& originIdentifier) +{ + ASSERT(isMainThread()); + ASSERT(!m_originSetGuard.tryLock()); + + m_originsBeingDeleted.add(originIdentifier); +} + +bool StorageTracker::canDeleteOrigin(const String& originIdentifier) +{ + ASSERT(!m_databaseGuard.tryLock()); + MutexLocker lockOrigins(m_originSetGuard); + return m_originsBeingDeleted.contains(originIdentifier); +} + +void StorageTracker::cancelDeletingOrigin(const String& originIdentifier) +{ + if (!m_isActive) + return; + + MutexLocker lockDatabase(m_databaseGuard); + MutexLocker lockOrigins(m_originSetGuard); + if (!m_originsBeingDeleted.isEmpty()) + m_originsBeingDeleted.remove(originIdentifier); +} + +void StorageTracker::setClient(StorageTrackerClient* client) +{ + MutexLocker lockClient(m_clientGuard); + m_client = client; +} + +void StorageTracker::syncLocalStorage() +{ + PageGroup::syncLocalStorage(); +} + +bool StorageTracker::isActive() +{ + return m_isActive; +} + +void StorageTracker::setIsActive(bool flag) +{ + m_isActive = flag; +} + +} // namespace WebCore + +#endif // ENABLE(DOM_STORAGE) diff --git a/Source/WebCore/storage/StorageTracker.h b/Source/WebCore/storage/StorageTracker.h new file mode 100644 index 0000000..04a821b --- /dev/null +++ b/Source/WebCore/storage/StorageTracker.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 Apple 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 StorageTracker_h +#define StorageTracker_h + +#if ENABLE(DOM_STORAGE) + +#include "PlatformString.h" +#include "SQLiteDatabase.h" +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +class LocalStorageTask; +class LocalStorageThread; +class SecurityOrigin; +class StorageTrackerClient; + +class StorageTracker { + WTF_MAKE_NONCOPYABLE(StorageTracker); + WTF_MAKE_FAST_ALLOCATED; +public: + static void initializeTracker(const String& storagePath); + static StorageTracker& tracker(); + static void scheduleTask(void*); + + void importOriginIdentifiers(); + void setOriginDetails(const String& originIdentifier, const String& databaseFile); + + void deleteAllOrigins(); + void deleteOrigin(SecurityOrigin*); + void deleteOrigin(const String& originIdentifier); + void origins(Vector<RefPtr<SecurityOrigin> >& result); + + void cancelDeletingOrigin(const String& originIdentifier); + + void setClient(StorageTrackerClient*); + + bool isActive(); + + // Sync to disk on background thread. + void syncDeleteAllOrigins(); + void syncDeleteOrigin(const String& originIdentifier); + void syncSetOriginDetails(const String& originIdentifier, const String& databaseFile); + void syncImportOriginIdentifiers(); + void syncFileSystemAndTrackerDatabase(); + + void syncLocalStorage(); + +private: + StorageTracker(const String& storagePath); + + String trackerDatabasePath(); + void openTrackerDatabase(bool createIfDoesNotExist); + + void setStorageDirectoryPath(const String&); + + void deleteTrackerFiles(); + + bool canDeleteOrigin(const String& originIdentifier); + void willDeleteOrigin(const String& originIdentifier); + void willDeleteAllOrigins(); + + void originFilePaths(Vector<String>& paths); + + void setIsActive(bool); + + // Guard for m_database, m_storageDirectoryPath and static Strings in syncFileSystemAndTrackerDatabase(). + Mutex m_databaseGuard; + SQLiteDatabase m_database; + String m_storageDirectoryPath; + + Mutex m_clientGuard; + StorageTrackerClient* m_client; + + // Guard for m_originSet and m_originsBeingDeleted. + Mutex m_originSetGuard; + typedef HashSet<String> OriginSet; + OriginSet m_originSet; + OriginSet m_originsBeingDeleted; + + OwnPtr<LocalStorageThread> m_thread; + + bool m_isActive; +}; + +} // namespace WebCore + +#endif // ENABLE(DOM_STORAGE) + +#endif // StorageTracker_h diff --git a/Source/WebCore/storage/StorageTrackerClient.h b/Source/WebCore/storage/StorageTrackerClient.h new file mode 100644 index 0000000..9c2d53e --- /dev/null +++ b/Source/WebCore/storage/StorageTrackerClient.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011 Apple 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 StorageTrackerClient_h +#define StorageTrackerClient_h + +#include <wtf/Forward.h> + +namespace WebCore { + +class StorageTrackerClient { +public: + virtual ~StorageTrackerClient() { } + virtual void dispatchDidModifyOrigin(const String& originIdentifier) = 0; +}; + +} // namespace WebCore + +#endif // StorageTrackerClient_h |