diff options
Diffstat (limited to 'WebCore/storage')
45 files changed, 1732 insertions, 83 deletions
diff --git a/WebCore/storage/DOMFilePath.cpp b/WebCore/storage/DOMFilePath.cpp new file mode 100644 index 0000000..2da057c --- /dev/null +++ b/WebCore/storage/DOMFilePath.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DOMFilePath.h" + +#if ENABLE(FILE_SYSTEM) + +#include "RegularExpression.h" +#include <wtf/Vector.h> +#include <wtf/text/CString.h> + +namespace WebCore { + +const char DOMFilePath::separator = '/'; +const char DOMFilePath::root[] = "/"; + +String DOMFilePath::append(const String& base, const String& components) +{ + return ensureDirectoryPath(base) + components; +} + +String DOMFilePath::ensureDirectoryPath(const String& path) +{ + if (!DOMFilePath::endsWithSeparator(path)) { + String newPath = path; + newPath.append(DOMFilePath::separator); + return newPath; + } + return path; +} + +String DOMFilePath::getName(const String& path) +{ + int index = path.reverseFind(DOMFilePath::separator); + if (index != -1) + return path.substring(index); + return path; +} + +String DOMFilePath::getDirectory(const String& path) +{ + int index = path.reverseFind(DOMFilePath::separator); + if (index == 0) + return DOMFilePath::root; + if (index != -1) + return path.substring(0, index); + return "."; +} + +bool DOMFilePath::isParentOf(const String& parent, const String& mayBeChild) +{ + ASSERT(DOMFilePath::isAbsolute(parent)); + ASSERT(DOMFilePath::isAbsolute(mayBeChild)); + if (parent == DOMFilePath::root && mayBeChild != DOMFilePath::root) + return true; + if (parent.length() >= mayBeChild.length() || !mayBeChild.startsWith(parent, false)) + return false; + if (mayBeChild[parent.length()] != DOMFilePath::separator) + return false; + return true; +} + +String DOMFilePath::removeExtraParentReferences(const String& path) +{ + ASSERT(DOMFilePath::isAbsolute(path)); + Vector<String> components; + Vector<String> canonicalized; + path.split(DOMFilePath::separator, components); + for (size_t i = 0; i < components.size(); ++i) { + if (components[i] == ".") + continue; + if (components[i] == "..") { + if (canonicalized.size() > 0) + canonicalized.removeLast(); + continue; + } + canonicalized.append(components[i]); + } + if (canonicalized.isEmpty()) + return DOMFilePath::root; + String result; + for (size_t i = 0; i < canonicalized.size(); ++i) { + result.append(DOMFilePath::separator); + result.append(canonicalized[i]); + } + return result; +} + +// Check the naming restrictions defined in FileSystem API 8.3. +// http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions +bool DOMFilePath::isValidPath(const String& path) +{ + if (path.isEmpty() || path == DOMFilePath::root) + return true; + + // Chars 0-31 in UTF-8 prepresentation are not allowed. + for (size_t i = 0; i < path.length(); ++i) + if (path[i] < 32) + return false; + + // Unallowed names. + DEFINE_STATIC_LOCAL(RegularExpression, unallowedNamesRegExp1, ("(/|^)(CON|PRN|AUX|NUL)([\\./]|$)", TextCaseInsensitive)); + DEFINE_STATIC_LOCAL(RegularExpression, unallowedNamesRegExp2, ("(/|^)(COM|LPT)[1-9]([\\./]|$)", TextCaseInsensitive)); + + if (unallowedNamesRegExp1.match(path) >= 0) + return false; + if (unallowedNamesRegExp2.match(path) >= 0) + return false; + + // Names must not end with period or whitespace. + DEFINE_STATIC_LOCAL(RegularExpression, endingRegExp, ("[\\.\\s](/|$)", TextCaseInsensitive)); + + if (endingRegExp.match(path) >= 0) + return false; + + // Unallowed chars: '\', '<', '>', ':', '?', '*', '"', '|' + // (We don't check '/' here as this method takes paths as its argument.) + DEFINE_STATIC_LOCAL(RegularExpression, unallowedCharsRegExp, ("[\\\\<>:\\?\\*\"|]", TextCaseInsensitive)); + + if (unallowedCharsRegExp.match(path) >= 0) + return false; + + return true; +} + +bool DOMFilePath::isValidName(const String& name) +{ + if (name.isEmpty()) + return true; + // '/' is not allowed in name. + if (name.contains('/')) + return false; + return isValidPath(name); +} + +} // namespace WebCore + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/DOMFilePath.h b/WebCore/storage/DOMFilePath.h new file mode 100644 index 0000000..2f2bb23 --- /dev/null +++ b/WebCore/storage/DOMFilePath.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DOMFilePath_h +#define DOMFilePath_h + +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +// DOMFileSystem path utilities. All methods in this class are static. +class DOMFilePath { +public: + static const char separator; + static const char root[]; + + // Returns the name part from the given path. + static String getName(const String& path); + + // Returns the parent directory path of the given path. + static String getDirectory(const String& path); + + // Checks if a given path is a parent of mayBeChild. This method assumes given paths are absolute and do not have extra references to a parent (i.e. "../"). + static bool isParentOf(const String& path, const String& mayBeChild); + + // Appends the separator at the end of the path if it's not there already. + static String ensureDirectoryPath(const String& path); + + // Returns a new path by appending a separator and the supplied path component to the path. + static String append(const String& path, const String& component); + + static bool isAbsolute(const String& path) + { + return path.startsWith(DOMFilePath::root); + } + + static bool endsWithSeparator(const String& path) + { + return path[path.length() - 1] == DOMFilePath::separator; + } + + // Evaluates all "../" and "./" segments. Note that "/../" expands to "/", so you can't ever refer to anything above the root directory. + static String removeExtraParentReferences(const String& path); + + // Checks if the given path follows the FileSystem API naming restrictions. + static bool isValidPath(const String& path); + + // Checks if the given name follows the FileSystem API naming restrictions. + static bool isValidName(const String& name); + +private: + DOMFilePath() { } +}; + +} // namespace WebCore + +#endif // DOMFilePath_h diff --git a/WebCore/storage/Database.cpp b/WebCore/storage/Database.cpp index 961310d..089f9ee 100644 --- a/WebCore/storage/Database.cpp +++ b/WebCore/storage/Database.cpp @@ -65,7 +65,7 @@ class DatabaseCreationCallbackTask : public ScriptExecutionContext::Task { public: static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> creationCallback) { - return new DatabaseCreationCallbackTask(database, creationCallback); + return adoptPtr(new DatabaseCreationCallbackTask(database, creationCallback)); } virtual void performTask(ScriptExecutionContext*) @@ -142,7 +142,7 @@ class DerefContextTask : public ScriptExecutionContext::Task { public: static PassOwnPtr<DerefContextTask> create(PassRefPtr<ScriptExecutionContext> context) { - return new DerefContextTask(context); + return adoptPtr(new DerefContextTask(context)); } virtual void performTask(ScriptExecutionContext* context) @@ -329,7 +329,7 @@ class DeliverPendingCallbackTask : public ScriptExecutionContext::Task { public: static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction) { - return new DeliverPendingCallbackTask(transaction); + return adoptPtr(new DeliverPendingCallbackTask(transaction)); } virtual void performTask(ScriptExecutionContext*) diff --git a/WebCore/storage/DatabaseSync.cpp b/WebCore/storage/DatabaseSync.cpp index 817fdcc..9c654a1 100644 --- a/WebCore/storage/DatabaseSync.cpp +++ b/WebCore/storage/DatabaseSync.cpp @@ -161,7 +161,7 @@ class CloseSyncDatabaseOnContextThreadTask : public ScriptExecutionContext::Task public: static PassOwnPtr<CloseSyncDatabaseOnContextThreadTask> create(PassRefPtr<DatabaseSync> database) { - return new CloseSyncDatabaseOnContextThreadTask(database); + return adoptPtr(new CloseSyncDatabaseOnContextThreadTask(database)); } virtual void performTask(ScriptExecutionContext*) diff --git a/WebCore/storage/DatabaseTask.h b/WebCore/storage/DatabaseTask.h index 847846d..b61e465 100644 --- a/WebCore/storage/DatabaseTask.h +++ b/WebCore/storage/DatabaseTask.h @@ -98,7 +98,7 @@ class Database::DatabaseOpenTask : public DatabaseTask { public: static PassOwnPtr<DatabaseOpenTask> create(Database* db, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success) { - return new DatabaseOpenTask(db, setVersionInNewDatabase, synchronizer, code, success); + return adoptPtr(new DatabaseOpenTask(db, setVersionInNewDatabase, synchronizer, code, success)); } private: @@ -118,7 +118,7 @@ class Database::DatabaseCloseTask : public DatabaseTask { public: static PassOwnPtr<DatabaseCloseTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer) { - return new DatabaseCloseTask(db, synchronizer); + return adoptPtr(new DatabaseCloseTask(db, synchronizer)); } private: @@ -135,7 +135,7 @@ public: // Transaction task is never synchronous, so no 'synchronizer' parameter. static PassOwnPtr<DatabaseTransactionTask> create(PassRefPtr<SQLTransaction> transaction) { - return new DatabaseTransactionTask(transaction); + return adoptPtr(new DatabaseTransactionTask(transaction)); } SQLTransaction* transaction() const { return m_transaction.get(); } @@ -155,7 +155,7 @@ class Database::DatabaseTableNamesTask : public DatabaseTask { public: static PassOwnPtr<DatabaseTableNamesTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names) { - return new DatabaseTableNamesTask(db, synchronizer, names); + return adoptPtr(new DatabaseTableNamesTask(db, synchronizer, names)); } private: diff --git a/WebCore/storage/DatabaseThread.cpp b/WebCore/storage/DatabaseThread.cpp index 99cf3b9..3b790ee 100644 --- a/WebCore/storage/DatabaseThread.cpp +++ b/WebCore/storage/DatabaseThread.cpp @@ -43,8 +43,8 @@ namespace WebCore { DatabaseThread::DatabaseThread() : m_threadID(0) - , m_transactionClient(new SQLTransactionClient()) - , m_transactionCoordinator(new SQLTransactionCoordinator()) + , m_transactionClient(adoptPtr(new SQLTransactionClient())) + , m_transactionCoordinator(adoptPtr(new SQLTransactionCoordinator())) , m_cleanupSync(0) { m_selfRef = this; diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp index e0ba422..1a13612 100644 --- a/WebCore/storage/DatabaseTracker.cpp +++ b/WebCore/storage/DatabaseTracker.cpp @@ -336,7 +336,7 @@ void DatabaseTracker::populateOrigins() if (m_quotaMap) return; - m_quotaMap.set(new QuotaMap); + m_quotaMap = adoptPtr(new QuotaMap); openTrackerDatabase(false); if (!m_database.isOpen()) @@ -516,7 +516,7 @@ void DatabaseTracker::addOpenDatabase(AbstractDatabase* database) MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) - m_openDatabaseMap.set(new DatabaseOriginMap); + m_openDatabaseMap = adoptPtr(new DatabaseOriginMap); String name(database->stringIdentifier()); DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); diff --git a/WebCore/storage/EntryCallback.h b/WebCore/storage/EntryCallback.h index 121bf07..9580eda 100644 --- a/WebCore/storage/EntryCallback.h +++ b/WebCore/storage/EntryCallback.h @@ -38,7 +38,6 @@ namespace WebCore { class Entry; -class ScriptExecutionContext; class EntryCallback : public RefCounted<EntryCallback> { public: diff --git a/WebCore/storage/FileSystemCallback.h b/WebCore/storage/FileSystemCallback.h index 19f44df..63f8416 100644 --- a/WebCore/storage/FileSystemCallback.h +++ b/WebCore/storage/FileSystemCallback.h @@ -38,7 +38,6 @@ namespace WebCore { class DOMFileSystem; -class ScriptExecutionContext; class FileSystemCallback : public RefCounted<FileSystemCallback> { public: diff --git a/WebCore/storage/FileSystemCallbacks.cpp b/WebCore/storage/FileSystemCallbacks.cpp new file mode 100644 index 0000000..ec352dd --- /dev/null +++ b/WebCore/storage/FileSystemCallbacks.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FileSystemCallbacks.h" + +#if ENABLE(FILE_SYSTEM) + +#include "DOMFileSystem.h" +#include "DirectoryEntry.h" +#include "EntriesCallback.h" +#include "EntryArray.h" +#include "EntryCallback.h" +#include "ErrorCallback.h" +#include "ExceptionCode.h" +#include "FileEntry.h" +#include "FileError.h" +#include "FileSystemCallback.h" +#include "Metadata.h" +#include "MetadataCallback.h" +#include "ScriptExecutionContext.h" +#include "VoidCallback.h" + +namespace WebCore { + +FileSystemCallbacksBase::FileSystemCallbacksBase(PassRefPtr<ErrorCallback> errorCallback) + : m_errorCallback(errorCallback) +{ +} + +FileSystemCallbacksBase::~FileSystemCallbacksBase() +{ +} + +void FileSystemCallbacksBase::didSucceed() +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didOpenFileSystem(const String&, const String&) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didReadMetadata(double) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didReadDirectoryChunkDone(bool) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didReadDirectoryEntry(const String&, bool) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didFail(ExceptionCode code) +{ + if (m_errorCallback) { + m_errorCallback->handleEvent(FileError::create(code).get()); + m_errorCallback.clear(); + } +} + +// EntryCallbacks ------------------------------------------------------------- + +EntryCallbacks::EntryCallbacks(PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, DOMFileSystem* fileSystem, const String& expectedPath, bool isDirectory) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) + , m_fileSystem(fileSystem) + , m_expectedPath(expectedPath) + , m_isDirectory(isDirectory) +{ +} + +void EntryCallbacks::didSucceed() +{ + if (m_successCallback) { + if (m_isDirectory) + m_successCallback->handleEvent(DirectoryEntry::create(m_fileSystem, m_expectedPath).get()); + else + m_successCallback->handleEvent(FileEntry::create(m_fileSystem, m_expectedPath).get()); + } + m_successCallback.clear(); +} + +// EntriesCallbacks ----------------------------------------------------------- + +EntriesCallbacks::EntriesCallbacks(PassRefPtr<EntriesCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, DOMFileSystem* fileSystem, const String& basePath) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) + , m_fileSystem(fileSystem) + , m_basePath(basePath) +{ +} + +void EntriesCallbacks::didReadDirectoryEntry(const String& name, bool isDirectory) +{ + if (isDirectory) + m_entries->append(DirectoryEntry::create(m_fileSystem, m_basePath + "/" + name)); + else + m_entries->append(FileEntry::create(m_fileSystem, m_basePath + "/" + name)); +} + +void EntriesCallbacks::didReadDirectoryChunkDone(bool hasMore) +{ + if (m_successCallback) { + m_successCallback->handleEvent(m_entries.get()); + m_entries->clear(); + if (!hasMore) { + // If there're no more entries, call back once more with an empty array. + m_successCallback->handleEvent(m_entries.get()); + m_successCallback.clear(); + } + } +} + +// FileSystemCallbacks -------------------------------------------------------- + +FileSystemCallbacks::FileSystemCallbacks(PassRefPtr<FileSystemCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) +{ +} + +void FileSystemCallbacks::didOpenFileSystem(const String& name, const String& rootPath) +{ + if (m_successCallback) + m_successCallback->handleEvent(DOMFileSystem::create(name, rootPath).get()); + m_successCallback.clear(); +} + +// MetadataCallbacks ---------------------------------------------------------- + +MetadataCallbacks::MetadataCallbacks(PassRefPtr<MetadataCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) +{ +} + +void MetadataCallbacks::didReadMetadata(double modificationTime) +{ + if (m_successCallback) + m_successCallback->handleEvent(Metadata::create(modificationTime).get()); + m_successCallback.clear(); +} + +// VoidCallbacks -------------------------------------------------------------- + +VoidCallbacks::VoidCallbacks(PassRefPtr<VoidCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) +{ +} + +void VoidCallbacks::didSucceed() +{ + if (m_successCallback) + m_successCallback->handleEvent(); + m_successCallback.clear(); +} + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/FileSystemCallbacks.h b/WebCore/storage/FileSystemCallbacks.h new file mode 100644 index 0000000..e0e78d3 --- /dev/null +++ b/WebCore/storage/FileSystemCallbacks.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FileSystemCallbacks_h +#define FileSystemCallbacks_h + +#if ENABLE(FILE_SYSTEM) + +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class DOMFileSystem; +class ErrorCallback; +class EntriesCallback; +class EntryArray; +class EntryCallback; +class FileSystemCallback; +class MetadataCallback; +class ScriptExecutionContext; +class VoidCallback; + +typedef int ExceptionCode; + +// A base class for FileSystem callbacks that bundles successCallback, errorCallback and some closure data for the callbacks. +class FileSystemCallbacksBase : public Noncopyable { +public: + virtual ~FileSystemCallbacksBase(); + + // For EntryCallbacks and VoidCallbacks. + virtual void didSucceed(); + + // For FileSystemCallbacks. + virtual void didOpenFileSystem(const String& name, const String& rootPath); + + // For MetadataCallbacks. + virtual void didReadMetadata(double modificationTime); + + // For EntriesCallbacks. didReadDirectoryEntry is called each time the API reads an entry, and didReadDirectoryDone is called when a chunk of entries have been read (i.e. good time to call back to the application). If hasMore is true there can be more chunks. + virtual void didReadDirectoryEntry(const String& name, bool isDirectory); + virtual void didReadDirectoryChunkDone(bool hasMore); + + // For ErrorCallback. + virtual void didFail(ExceptionCode code); + +protected: + FileSystemCallbacksBase(PassRefPtr<ErrorCallback> errorCallback); + RefPtr<ErrorCallback> m_errorCallback; +}; + +// Subclasses ---------------------------------------------------------------- + +class EntryCallbacks : public FileSystemCallbacksBase { +public: + EntryCallbacks(PassRefPtr<EntryCallback>, PassRefPtr<ErrorCallback>, DOMFileSystem*, const String& expectedPath, bool isDirectory); + virtual void didSucceed(); + +private: + RefPtr<EntryCallback> m_successCallback; + DOMFileSystem* m_fileSystem; + String m_expectedPath; + bool m_isDirectory; +}; + +class EntriesCallbacks : public FileSystemCallbacksBase { +public: + EntriesCallbacks(PassRefPtr<EntriesCallback>, PassRefPtr<ErrorCallback>, DOMFileSystem*, const String& basePath); + virtual void didReadDirectoryEntry(const String& name, bool isDirectory); + virtual void didReadDirectoryChunkDone(bool hasMore); + +private: + RefPtr<EntriesCallback> m_successCallback; + DOMFileSystem* m_fileSystem; + String m_basePath; + RefPtr<EntryArray> m_entries; +}; + +class FileSystemCallbacks : public FileSystemCallbacksBase { +public: + FileSystemCallbacks(PassRefPtr<FileSystemCallback>, PassRefPtr<ErrorCallback>); + virtual void didOpenFileSystem(const String& name, const String& rootPath); + +private: + RefPtr<FileSystemCallback> m_successCallback; +}; + +class MetadataCallbacks : public FileSystemCallbacksBase { +public: + MetadataCallbacks(PassRefPtr<MetadataCallback>, PassRefPtr<ErrorCallback>); + virtual void didReadMetadata(double modificationTime); + +private: + RefPtr<MetadataCallback> m_successCallback; +}; + +class VoidCallbacks : public FileSystemCallbacksBase { +public: + VoidCallbacks(PassRefPtr<VoidCallback>, PassRefPtr<ErrorCallback>); + virtual void didSucceed(); + +private: + RefPtr<VoidCallback> m_successCallback; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // FileSystemCallbacks_h diff --git a/WebCore/storage/IDBAbortEvent.cpp b/WebCore/storage/IDBAbortEvent.cpp new file mode 100644 index 0000000..21760f8 --- /dev/null +++ b/WebCore/storage/IDBAbortEvent.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBAbortEvent.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "EventNames.h" +#include "IDBAny.h" + +namespace WebCore { + +PassRefPtr<IDBAbortEvent> IDBAbortEvent::create() +{ + return adoptRef(new IDBAbortEvent()); +} + +IDBAbortEvent::IDBAbortEvent() + : IDBEvent(eventNames().abortEvent, 0) // FIXME: set the source to the transaction +{ +} + +IDBAbortEvent::~IDBAbortEvent() +{ +} + +} // namespace WebCore + +#endif diff --git a/WebCore/storage/IDBAbortEvent.h b/WebCore/storage/IDBAbortEvent.h new file mode 100644 index 0000000..bdc2202 --- /dev/null +++ b/WebCore/storage/IDBAbortEvent.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBAbortEvent_h +#define IDBAbortEvent_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBEvent.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBAbortEvent : public IDBEvent { +public: + static PassRefPtr<IDBAbortEvent> create(); + // FIXME: Need to allow creation of these events from JS. + virtual ~IDBAbortEvent(); + + virtual bool isIDBAbortEvent() const { return true; } + +private: + IDBAbortEvent(); +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBAbortEvent_h diff --git a/WebCore/storage/IDBCursorBackendImpl.cpp b/WebCore/storage/IDBCursorBackendImpl.cpp index 4e08b8f..d3298b3 100644 --- a/WebCore/storage/IDBCursorBackendImpl.cpp +++ b/WebCore/storage/IDBCursorBackendImpl.cpp @@ -33,6 +33,7 @@ #include "IDBKeyRange.h" #include "IDBObjectStoreBackendImpl.h" #include "IDBRequest.h" +#include "SQLiteDatabase.h" #include "SerializedScriptValue.h" namespace WebCore { diff --git a/WebCore/storage/IDBDatabase.cpp b/WebCore/storage/IDBDatabase.cpp index b00695b..78a6646 100644 --- a/WebCore/storage/IDBDatabase.cpp +++ b/WebCore/storage/IDBDatabase.cpp @@ -39,7 +39,6 @@ namespace WebCore { IDBDatabase::IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface> backend) : m_backend(backend) - , m_description(m_backend->description()) { // We pass a reference to this object before it can be adopted. relaxAdoptionRequirement(); @@ -75,8 +74,10 @@ PassRefPtr<IDBTransaction> IDBDatabase::transaction(ScriptExecutionContext* cont // We need to create a new transaction synchronously. Locks are acquired asynchronously. Operations // can be queued against the transaction at any point. They will start executing as soon as the // appropriate locks have been acquired. + // Also note that each backend object corresponds to exactly one IDBTransaction object. RefPtr<IDBTransactionBackendInterface> transactionBackend = m_backend->transaction(storeNames, mode, timeout); - RefPtr<IDBTransaction> transaction = IDBTransaction::create(context, transactionBackend.release(), this); + RefPtr<IDBTransaction> transaction = IDBTransaction::create(context, transactionBackend, this); + transactionBackend->setCallbacks(transaction.get()); return transaction.release(); } diff --git a/WebCore/storage/IDBDatabase.h b/WebCore/storage/IDBDatabase.h index 1ad3c65..0e83288 100644 --- a/WebCore/storage/IDBDatabase.h +++ b/WebCore/storage/IDBDatabase.h @@ -52,7 +52,6 @@ public: // Implement the IDL String name() const { return m_backend->name(); } - String description() const { return m_description; } String version() const { return m_backend->version(); } PassRefPtr<DOMStringList> objectStores() const { return m_backend->objectStores(); } @@ -65,8 +64,6 @@ private: IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface>); RefPtr<IDBDatabaseBackendInterface> m_backend; - - String m_description; }; } // namespace WebCore diff --git a/WebCore/storage/IDBDatabase.idl b/WebCore/storage/IDBDatabase.idl index 4e3f620..51bbafb 100644 --- a/WebCore/storage/IDBDatabase.idl +++ b/WebCore/storage/IDBDatabase.idl @@ -29,7 +29,6 @@ module storage { Conditional=INDEXED_DATABASE ] IDBDatabase { readonly attribute DOMString name; - readonly attribute DOMString description; readonly attribute DOMString version; readonly attribute DOMStringList objectStores; diff --git a/WebCore/storage/IDBDatabaseBackendImpl.cpp b/WebCore/storage/IDBDatabaseBackendImpl.cpp index e550e18..23bc44e 100644 --- a/WebCore/storage/IDBDatabaseBackendImpl.cpp +++ b/WebCore/storage/IDBDatabaseBackendImpl.cpp @@ -29,8 +29,10 @@ #include "DOMStringList.h" #include "IDBDatabaseException.h" #include "IDBObjectStoreBackendImpl.h" +#include "IDBTransactionCoordinator.h" #include "SQLiteDatabase.h" #include "SQLiteStatement.h" +#include "SQLiteTransaction.h" #if ENABLE(INDEXED_DATABASE) @@ -83,10 +85,11 @@ static bool setMetaData(SQLiteDatabase* sqliteDatabase, const String& name, cons return true; } -IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> sqliteDatabase) +IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> sqliteDatabase, IDBTransactionCoordinator* coordinator) : m_sqliteDatabase(sqliteDatabase) , m_name(name) , m_version("") + , m_transactionCoordinator(coordinator) { ASSERT(!m_name.isNull()); @@ -97,6 +100,8 @@ IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String& if (!result || m_description != foundDescription) setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version); + + loadObjectStores(); } IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl() @@ -127,9 +132,20 @@ void IDBDatabaseBackendImpl::createObjectStore(const String& name, const String& return; } - RefPtr<IDBObjectStoreBackendInterface> objectStore = IDBObjectStoreBackendImpl::create(name, keyPath, autoIncrement); + SQLiteStatement insert(sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement) VALUES (?, ?, ?)"); + bool ok = insert.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + insert.bindText(1, name); + insert.bindText(2, keyPath); + insert.bindInt(3, static_cast<int>(autoIncrement)); + ok = insert.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + int64_t id = sqliteDatabase().lastInsertRowID(); + + RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(this, id, name, keyPath, autoIncrement); + ASSERT(objectStore->name() == name); m_objectStores.set(name, objectStore); - callbacks->onSuccess(objectStore.release()); + callbacks->onSuccess(objectStore.get()); } PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(const String& name, unsigned short mode) @@ -139,22 +155,55 @@ PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(c return m_objectStores.get(name); } +static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id) +{ + SQLiteStatement deleteQuery(db, sql); + bool ok = deleteQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + deleteQuery.bindInt64(1, id); + ok = deleteQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. +} + void IDBDatabaseBackendImpl::removeObjectStore(const String& name, PassRefPtr<IDBCallbacks> callbacks) { - if (!m_objectStores.contains(name)) { + RefPtr<IDBObjectStoreBackendImpl> objectStore = m_objectStores.get(name); + if (!objectStore) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "No objectStore with that name exists.")); return; } + SQLiteTransaction transaction(sqliteDatabase()); + transaction.begin(); + doDelete(sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id()); + doDelete(sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id()); + doDelete(sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id()); + // FIXME: Delete index data as well. + transaction.commit(); + m_objectStores.remove(name); callbacks->onSuccess(); } -PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::transaction(DOMStringList*, unsigned short, unsigned long) +PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::transaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout) { - // FIXME: Ask the transaction manager for a new IDBTransactionBackendImpl. - ASSERT_NOT_REACHED(); - return 0; + return m_transactionCoordinator->createTransaction(objectStores, mode, timeout, this); +} + +void IDBDatabaseBackendImpl::loadObjectStores() +{ + SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores"); + bool ok = objectStoresQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + while (objectStoresQuery.step() == SQLResultRow) { + int64_t id = objectStoresQuery.getColumnInt64(0); + String name = objectStoresQuery.getColumnText(1); + String keyPath = objectStoresQuery.getColumnText(2); + bool autoIncrement = !!objectStoresQuery.getColumnInt(3); + + m_objectStores.set(name, IDBObjectStoreBackendImpl::create(this, id, name, keyPath, autoIncrement)); + } } } // namespace WebCore diff --git a/WebCore/storage/IDBDatabaseBackendImpl.h b/WebCore/storage/IDBDatabaseBackendImpl.h index 60bec1f..3540b21 100644 --- a/WebCore/storage/IDBDatabaseBackendImpl.h +++ b/WebCore/storage/IDBDatabaseBackendImpl.h @@ -35,17 +35,20 @@ namespace WebCore { +class IDBObjectStoreBackendImpl; +class IDBTransactionCoordinator; class SQLiteDatabase; class IDBDatabaseBackendImpl : public IDBDatabaseBackendInterface { public: - static PassRefPtr<IDBDatabaseBackendImpl> create(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database) + static PassRefPtr<IDBDatabaseBackendImpl> create(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database, IDBTransactionCoordinator* coordinator) { - return adoptRef(new IDBDatabaseBackendImpl(name, description, database)); + return adoptRef(new IDBDatabaseBackendImpl(name, description, database, coordinator)); } virtual ~IDBDatabaseBackendImpl(); void setDescription(const String& description); + SQLiteDatabase& sqliteDatabase() const { return *m_sqliteDatabase.get(); } // Implements IDBDatabase virtual String name() const { return m_name; } @@ -58,16 +61,19 @@ public: virtual void removeObjectStore(const String& name, PassRefPtr<IDBCallbacks>); virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout); private: - IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database); + IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database, IDBTransactionCoordinator*); - OwnPtr<SQLiteDatabase> m_sqliteDatabase; + void loadObjectStores(); + OwnPtr<SQLiteDatabase> m_sqliteDatabase; String m_name; String m_description; String m_version; - typedef HashMap<String, RefPtr<IDBObjectStoreBackendInterface> > ObjectStoreMap; + typedef HashMap<String, RefPtr<IDBObjectStoreBackendImpl> > ObjectStoreMap; ObjectStoreMap m_objectStores; + + RefPtr<IDBTransactionCoordinator> m_transactionCoordinator; }; } // namespace WebCore diff --git a/WebCore/storage/IDBDatabaseBackendInterface.h b/WebCore/storage/IDBDatabaseBackendInterface.h index ac12bf1..9e35369 100644 --- a/WebCore/storage/IDBDatabaseBackendInterface.h +++ b/WebCore/storage/IDBDatabaseBackendInterface.h @@ -39,6 +39,7 @@ class Frame; class IDBCallbacks; class IDBObjectStoreBackendInterface; class IDBTransactionBackendInterface; +class IDBTransactionCallbacks; // This class is shared by IDBDatabase (async) and IDBDatabaseSync (sync). // This is implemented by IDBDatabaseBackendImpl and optionally others (in order to proxy diff --git a/WebCore/storage/IDBFactoryBackendImpl.cpp b/WebCore/storage/IDBFactoryBackendImpl.cpp index 905726f..d656128 100644 --- a/WebCore/storage/IDBFactoryBackendImpl.cpp +++ b/WebCore/storage/IDBFactoryBackendImpl.cpp @@ -33,6 +33,7 @@ #include "FileSystem.h" #include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseException.h" +#include "IDBTransactionCoordinator.h" #include "SQLiteDatabase.h" #include "SecurityOrigin.h" #include <wtf/Threading.h> @@ -42,7 +43,8 @@ namespace WebCore { -IDBFactoryBackendImpl::IDBFactoryBackendImpl() +IDBFactoryBackendImpl::IDBFactoryBackendImpl() + : m_transactionCoordinator(IDBTransactionCoordinator::create()) { } @@ -75,8 +77,25 @@ static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOri static bool createTables(SQLiteDatabase* sqliteDatabase) { + // FIXME: Remove all the drop table commands once the on disk structure stabilizes. static const char* commands[] = { - "CREATE TABLE IF NOT EXISTS MetaData (name TEXT, description TEXT, version TEXT)" + "DROP TABLE IF EXISTS MetaData", + "CREATE TABLE IF NOT EXISTS MetaData (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)", + + "DROP TABLE IF EXISTS ObjectStores", + "CREATE TABLE IF NOT EXISTS ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL)", + "DROP INDEX IF EXISTS ObjectStores_name", + "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStores_name ON ObjectStores(name)", + + "DROP TABLE IF EXISTS Indexes", + "CREATE TABLE IF NOT EXISTS Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)", + "DROP INDEX IF EXISTS Indexes_composit", + "CREATE UNIQUE INDEX IF NOT EXISTS Indexes_composit ON Indexes(objectStoreId, name)", + + "DROP TABLE IF EXISTS ObjectStoreData", + "CREATE TABLE IF NOT EXISTS ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)", + "DROP INDEX IF EXISTS ObjectStoreData_composit", + "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)" }; for (size_t i = 0; i < arraysize(commands); ++i) { @@ -107,11 +126,17 @@ void IDBFactoryBackendImpl::open(const String& name, const String& description, return; } - RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, description, sqliteDatabase.release()); + RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, description, sqliteDatabase.release(), m_transactionCoordinator.get()); callbacks->onSuccess(databaseBackend.get()); m_databaseBackendMap.set(name, databaseBackend.release()); } +void IDBFactoryBackendImpl::abortPendingTransactions(const Vector<int>& pendingIDs) +{ + for (size_t i = 0; i < pendingIDs.size(); ++i) + m_transactionCoordinator->abort(pendingIDs.at(i)); +} + } // namespace WebCore #endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBFactoryBackendImpl.h b/WebCore/storage/IDBFactoryBackendImpl.h index e87ea39..c9a33da 100644 --- a/WebCore/storage/IDBFactoryBackendImpl.h +++ b/WebCore/storage/IDBFactoryBackendImpl.h @@ -37,7 +37,9 @@ namespace WebCore { class DOMStringList; + class IDBDatabaseBackendImpl; +class IDBTransactionCoordinator; class IDBFactoryBackendImpl : public IDBFactoryBackendInterface { public: @@ -48,12 +50,14 @@ public: virtual ~IDBFactoryBackendImpl(); virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*); + virtual void abortPendingTransactions(const Vector<int>& pendingIDs); private: IDBFactoryBackendImpl(); typedef HashMap<String, RefPtr<IDBDatabaseBackendImpl> > IDBDatabaseBackendMap; IDBDatabaseBackendMap m_databaseBackendMap; + RefPtr<IDBTransactionCoordinator> m_transactionCoordinator; // We only create one instance of this class at a time. static IDBFactoryBackendImpl* idbFactoryBackendImpl; diff --git a/WebCore/storage/IDBFactoryBackendInterface.h b/WebCore/storage/IDBFactoryBackendInterface.h index ba18098..c052bc2 100644 --- a/WebCore/storage/IDBFactoryBackendInterface.h +++ b/WebCore/storage/IDBFactoryBackendInterface.h @@ -32,6 +32,7 @@ #include "IDBCallbacks.h" #include "PlatformString.h" #include <wtf/Threading.h> +#include <wtf/Vector.h> #if ENABLE(INDEXED_DATABASE) @@ -51,6 +52,7 @@ public: virtual ~IDBFactoryBackendInterface() { } virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*) = 0; + virtual void abortPendingTransactions(const Vector<int>& ids) = 0; }; } // namespace WebCore diff --git a/WebCore/storage/IDBIndexBackendImpl.cpp b/WebCore/storage/IDBIndexBackendImpl.cpp index 406e37f..180ff1d 100644 --- a/WebCore/storage/IDBIndexBackendImpl.cpp +++ b/WebCore/storage/IDBIndexBackendImpl.cpp @@ -28,10 +28,16 @@ #if ENABLE(INDEXED_DATABASE) +#include "IDBDatabaseBackendImpl.h" +#include "IDBObjectStoreBackendImpl.h" +#include "SQLiteDatabase.h" + namespace WebCore { -IDBIndexBackendImpl::IDBIndexBackendImpl(const String& name, const String& keyPath, bool unique) - : m_name(name) +IDBIndexBackendImpl::IDBIndexBackendImpl(IDBObjectStoreBackendImpl* objectStore, int64_t id, const String& name, const String& keyPath, bool unique) + : m_objectStore(objectStore) + , m_id(id) + , m_name(name) , m_keyPath(keyPath) , m_unique(unique) { @@ -41,6 +47,11 @@ IDBIndexBackendImpl::~IDBIndexBackendImpl() { } +SQLiteDatabase& IDBIndexBackendImpl::sqliteDatabase() const +{ + return m_objectStore->database()->sqliteDatabase(); +} + } // namespace WebCore #endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBIndexBackendImpl.h b/WebCore/storage/IDBIndexBackendImpl.h index ca3f01e..acf6b1f 100644 --- a/WebCore/storage/IDBIndexBackendImpl.h +++ b/WebCore/storage/IDBIndexBackendImpl.h @@ -32,11 +32,14 @@ namespace WebCore { +class IDBObjectStoreBackendImpl; +class SQLiteDatabase; + class IDBIndexBackendImpl : public IDBIndexBackendInterface { public: - static PassRefPtr<IDBIndexBackendImpl> create(const String& name, const String& keyPath, bool unique) + static PassRefPtr<IDBIndexBackendImpl> create(IDBObjectStoreBackendImpl* objectStore, int64_t id, const String& name, const String& keyPath, bool unique) { - return adoptRef(new IDBIndexBackendImpl(name, keyPath, unique)); + return adoptRef(new IDBIndexBackendImpl(objectStore, id, name, keyPath, unique)); } virtual ~IDBIndexBackendImpl(); @@ -46,8 +49,13 @@ public: virtual bool unique() { return m_unique; } private: - IDBIndexBackendImpl(const String& name, const String& keyPath, bool unique); + IDBIndexBackendImpl(IDBObjectStoreBackendImpl*, int64_t id, const String& name, const String& keyPath, bool unique); + + SQLiteDatabase& sqliteDatabase() const; + + RefPtr<IDBObjectStoreBackendImpl> m_objectStore; + int64_t m_id; String m_name; String m_keyPath; bool m_unique; diff --git a/WebCore/storage/IDBKeyPathBackendImpl.cpp b/WebCore/storage/IDBKeyPathBackendImpl.cpp new file mode 100644 index 0000000..6cc9be5 --- /dev/null +++ b/WebCore/storage/IDBKeyPathBackendImpl.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 "IDBKeyPathBackendImpl.h" + +#if PLATFORM(CHROMIUM) +#error "Chromium should not compile this file and instead define its own version of this factory that navigates the multi-process boundry." +#endif + +void IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(const Vector<RefPtr<SerializedScriptValue>&, 0> values, const String& keyPath, Vector<RefPtr<IDBKey>, 0>& keys) +{ + // FIXME: Implement this method once JSC supports WireFormat for SerializedScriptValue. +} diff --git a/WebCore/storage/IDBKeyPathBackendImpl.h b/WebCore/storage/IDBKeyPathBackendImpl.h new file mode 100644 index 0000000..32af5e3 --- /dev/null +++ b/WebCore/storage/IDBKeyPathBackendImpl.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 IDBKeyPathBackendImpl_h +#define IDBKeyPathBackendImpl_h + +#if ENABLE(INDEXED_DATABASE) + +#include <wtf/Forward.h> + +namespace WebCore { + +class IDBKey; +class SerializedScriptValue; + +class IDBKeyPathBackendImpl { +public: + static void createIDBKeysFromSerializedValuesAndKeyPath(const Vector<RefPtr<SerializedScriptValue>, 0>& values, const String& keyPath, Vector<RefPtr<IDBKey>, 0>& keys); +}; + +} + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBKeyPathBackendImpl_h diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/WebCore/storage/IDBObjectStoreBackendImpl.cpp index 9732bc1..1b9b76b 100755 --- a/WebCore/storage/IDBObjectStoreBackendImpl.cpp +++ b/WebCore/storage/IDBObjectStoreBackendImpl.cpp @@ -30,10 +30,14 @@ #include "IDBBindingUtilities.h" #include "IDBCallbacks.h" #include "IDBCursorBackendImpl.h" +#include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseException.h" #include "IDBIndexBackendImpl.h" +#include "IDBKeyPath.h" +#include "IDBKeyPathBackendImpl.h" #include "IDBKeyRange.h" -#include "IDBKeyTree.h" +#include "SQLiteDatabase.h" +#include "SQLiteStatement.h" #if ENABLE(INDEXED_DATABASE) @@ -43,12 +47,14 @@ IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl() { } -IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const String& name, const String& keyPath, bool autoIncrement) - : m_name(name) +IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement) + : m_database(database) + , m_id(id) + , m_name(name) , m_keyPath(keyPath) , m_autoIncrement(autoIncrement) - , m_tree(Tree::create()) { + loadIndexes(); } PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const @@ -59,28 +65,86 @@ PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const return indexNames.release(); } +static String whereClause(IDBKey::Type type) +{ + switch (type) { + case IDBKey::StringType: + return "WHERE objectStoreId = ? AND keyString = ?"; + case IDBKey::NumberType: + return "WHERE objectStoreId = ? AND keyNumber = ?"; + // FIXME: Implement date. + case IDBKey::NullType: + return "WHERE objectStoreId = ? AND keyString IS NULL AND keyDate IS NULL AND keyNumber IS NULL"; + } + + ASSERT_NOT_REACHED(); + return ""; +} + +// Returns number of items bound. +static int bindKey(SQLiteStatement& query, int column, IDBKey* key) +{ + switch (key->type()) { + case IDBKey::StringType: + query.bindText(column, key->string()); + return 1; + case IDBKey::NumberType: + query.bindInt(column, key->number()); + return 1; + // FIXME: Implement date. + case IDBKey::NullType: + return 0; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key) +{ + query.bindInt64(1, id); + bindKey(query, 2, key); +} + void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) { - RefPtr<SerializedScriptValue> value = m_tree->get(key.get()); - if (!value) { + SQLiteStatement query(sqliteDatabase(), "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData " + whereClause(key->type())); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(query, m_id, key.get()); + if (query.step() != SQLResultRow) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store.")); return; } - callbacks->onSuccess(value.get()); + + ASSERT((key->type() == IDBKey::StringType) != query.isColumnNull(0)); + // FIXME: Implement date. + ASSERT((key->type() == IDBKey::NumberType) != query.isColumnNull(2)); + + callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(3))); + ASSERT(query.step() != SQLResultRow); } -void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks) +void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks) { + RefPtr<SerializedScriptValue> value = prpValue; RefPtr<IDBKey> key = prpKey; if (!m_keyPath.isNull()) { if (key) { - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath.")); + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath.")); return; } - ASSERT_NOT_REACHED(); - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "FIXME: keyPath not yet supported.")); - return; + Vector<RefPtr<SerializedScriptValue> > values; + values.append(value); + Vector<RefPtr<IDBKey> > idbKeys; + IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, m_keyPath, idbKeys); + if (idbKeys.isEmpty()) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "An invalid keyPath was supplied for an objectStore.")); + return; + } + key = idbKeys[0]; } if (!key) { @@ -88,18 +152,66 @@ void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> value, Pas return; } - if (addOnly && m_tree->get(key.get())) { + SQLiteStatement getQuery(sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key->type())); + bool ok = getQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(getQuery, m_id, key.get()); + bool existingValue = getQuery.step() == SQLResultRow; + if (addOnly && existingValue) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store.")); return; } - m_tree->put(key.get(), value.get()); + String sql = existingValue ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?" + : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)"; + SQLiteStatement putQuery(sqliteDatabase(), sql); + ok = putQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + switch (key->type()) { + case IDBKey::StringType: + putQuery.bindText(1, key->string()); + putQuery.bindNull(2); + putQuery.bindNull(3); + break; + // FIXME: Implement date. + case IDBKey::NumberType: + putQuery.bindNull(1); + putQuery.bindNull(2); + putQuery.bindInt(3, key->number()); + break; + case IDBKey::NullType: + putQuery.bindNull(1); + putQuery.bindNull(2); + putQuery.bindNull(3); + break; + default: + ASSERT_NOT_REACHED(); + } + putQuery.bindText(4, value->toWireString()); + if (existingValue) + putQuery.bindInt(5, getQuery.getColumnInt(0)); + else + putQuery.bindInt64(5, m_id); + + ok = putQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + callbacks->onSuccess(key.get()); } void IDBObjectStoreBackendImpl::remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) { - m_tree->remove(key.get()); + SQLiteStatement query(sqliteDatabase(), "DELETE FROM ObjectStoreData " + whereClause(key->type())); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(query, m_id, key.get()); + if (query.step() != SQLResultDone) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store.")); + return; + } + callbacks->onSuccess(); } @@ -110,7 +222,18 @@ void IDBObjectStoreBackendImpl::createIndex(const String& name, const String& ke return; } - RefPtr<IDBIndexBackendInterface> index = IDBIndexBackendImpl::create(name, keyPath, unique); + SQLiteStatement insert(sqliteDatabase(), "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)"); + bool ok = insert.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + insert.bindInt64(1, m_id); + insert.bindText(2, name); + insert.bindText(3, keyPath); + insert.bindInt(4, static_cast<int>(unique)); + ok = insert.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + int64_t id = sqliteDatabase().lastInsertRowID(); + + RefPtr<IDBIndexBackendInterface> index = IDBIndexBackendImpl::create(this, id, name, keyPath, unique); ASSERT(index->name() == name); m_indexes.set(name, index); callbacks->onSuccess(index.release()); @@ -128,19 +251,61 @@ void IDBObjectStoreBackendImpl::removeIndex(const String& name, PassRefPtr<IDBCa return; } + SQLiteStatement deleteQuery(sqliteDatabase(), "DELETE FROM Indexes WHERE name = ? AND objectStoreId = ?"); + bool ok = deleteQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + deleteQuery.bindText(1, name); + deleteQuery.bindInt64(2, m_id); + ok = deleteQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + + // FIXME: Delete index data as well. + m_indexes.remove(name); callbacks->onSuccess(); } void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks) { + // FIXME: Fully implement. + RefPtr<IDBKey> key = range->left(); - RefPtr<SerializedScriptValue> value = m_tree->get(key.get()); - if (value) { - RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(this, range, static_cast<IDBCursor::Direction>(direction), key, value); - callbacks->onSuccess(cursor.release()); - } else - callbacks->onSuccess(); + SQLiteStatement query(sqliteDatabase(), "SELECT id, value FROM ObjectStoreData " + whereClause(key->type())); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(query, m_id, key.get()); + if (query.step() != SQLResultRow) { + callbacks->onSuccess(); + return; + } + + RefPtr<SerializedScriptValue> value = SerializedScriptValue::createFromWire(query.getColumnText(1)); + RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(this, range, static_cast<IDBCursor::Direction>(direction), key.release(), value.release()); + callbacks->onSuccess(cursor.release()); +} + +void IDBObjectStoreBackendImpl::loadIndexes() +{ + SQLiteStatement indexQuery(sqliteDatabase(), "SELECT id, name, keyPath, isUnique FROM Indexes WHERE objectStoreId = ?"); + bool ok = indexQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + indexQuery.bindInt64(1, m_id); + + while (indexQuery.step() == SQLResultRow) { + int64_t id = indexQuery.getColumnInt64(0); + String name = indexQuery.getColumnText(1); + String keyPath = indexQuery.getColumnText(2); + bool unique = !!indexQuery.getColumnInt(3); + + m_indexes.set(name, IDBIndexBackendImpl::create(this, id, name, keyPath, unique)); + } +} + +SQLiteDatabase& IDBObjectStoreBackendImpl::sqliteDatabase() const +{ + return m_database->sqliteDatabase(); } } // namespace WebCore diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.h b/WebCore/storage/IDBObjectStoreBackendImpl.h index 4b909af..e1058c8 100644 --- a/WebCore/storage/IDBObjectStoreBackendImpl.h +++ b/WebCore/storage/IDBObjectStoreBackendImpl.h @@ -34,16 +34,18 @@ namespace WebCore { -template <typename ValueType> class IDBKeyTree; +class IDBDatabaseBackendImpl; +class SQLiteDatabase; class IDBObjectStoreBackendImpl : public IDBObjectStoreBackendInterface { public: - static PassRefPtr<IDBObjectStoreBackendInterface> create(const String& name, const String& keyPath, bool autoIncrement) + static PassRefPtr<IDBObjectStoreBackendImpl> create(IDBDatabaseBackendImpl* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement) { - return adoptRef(new IDBObjectStoreBackendImpl(name, keyPath, autoIncrement)); + return adoptRef(new IDBObjectStoreBackendImpl(database, id, name, keyPath, autoIncrement)); } ~IDBObjectStoreBackendImpl(); + int64_t id() const { return m_id; } String name() const { return m_name; } String keyPath() const { return m_keyPath; } PassRefPtr<DOMStringList> indexNames() const; @@ -58,18 +60,23 @@ public: void openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>); + IDBDatabaseBackendImpl* database() const { return m_database.get(); } + private: - IDBObjectStoreBackendImpl(const String& name, const String& keyPath, bool autoIncrement); + IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl*, int64_t id, const String& name, const String& keyPath, bool autoIncrement); + + void loadIndexes(); + SQLiteDatabase& sqliteDatabase() const; + RefPtr<IDBDatabaseBackendImpl> m_database; + + int64_t m_id; String m_name; String m_keyPath; bool m_autoIncrement; typedef HashMap<String, RefPtr<IDBIndexBackendInterface> > IndexMap; IndexMap m_indexes; - - typedef IDBKeyTree<SerializedScriptValue> Tree; - RefPtr<Tree> m_tree; }; } // namespace WebCore diff --git a/WebCore/storage/IDBPendingTransactionMonitor.cpp b/WebCore/storage/IDBPendingTransactionMonitor.cpp new file mode 100644 index 0000000..d026099 --- /dev/null +++ b/WebCore/storage/IDBPendingTransactionMonitor.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 "IDBPendingTransactionMonitor.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +Vector<int>* IDBPendingTransactionMonitor::m_ids = 0; + +bool IDBPendingTransactionMonitor::hasPendingTransactions() +{ + return m_ids && m_ids->size(); +} + +void IDBPendingTransactionMonitor::addPendingTransaction(int id) +{ + if (!m_ids) + m_ids = new Vector<int>(); + m_ids->append(id); +} + +void IDBPendingTransactionMonitor::removePendingTransaction(int id) +{ + m_ids->remove(id); + if (!m_ids->size()) { + delete m_ids; + m_ids = 0; + } +} + +void IDBPendingTransactionMonitor::clearPendingTransactions() +{ + if (!m_ids) + return; + + m_ids->clear(); + delete m_ids; + m_ids = 0; +} + +const Vector<int>& IDBPendingTransactionMonitor::pendingTransactions() +{ + return *m_ids; +} + +}; +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBPendingTransactionMonitor.h b/WebCore/storage/IDBPendingTransactionMonitor.h new file mode 100644 index 0000000..00e833a --- /dev/null +++ b/WebCore/storage/IDBPendingTransactionMonitor.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 IDBPendingTransactionMonitor_h +#define IDBPendingTransactionMonitor_h + +#if ENABLE(INDEXED_DATABASE) + +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +namespace WebCore { + +// This class keeps track of the transactions created during the current +// Javascript execution context. A transaction is 'pending' if no asynchronous +// operation is currently queued for it (e.g. an IDBObjectStore::put() or similar). +// All pending transactions are aborted as soon as execution returns from +// the script engine. +// +// FIXME: move the vector of transaction IDs to TLS. Keeping it static +// will not work once we add support for workers. Another possible +// solution is to keep the vector in the ScriptExecutionContext. +class IDBPendingTransactionMonitor : public Noncopyable { +public: + static bool hasPendingTransactions(); + static void addPendingTransaction(int id); + static void removePendingTransaction(int id); + static void clearPendingTransactions(); + static const Vector<int>& pendingTransactions(); + +private: + IDBPendingTransactionMonitor(); + + static Vector<int>* m_ids; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBPendingTransactionMonitor_h diff --git a/WebCore/storage/IDBTransaction.cpp b/WebCore/storage/IDBTransaction.cpp index 1bc059a..4e93378 100644 --- a/WebCore/storage/IDBTransaction.cpp +++ b/WebCore/storage/IDBTransaction.cpp @@ -1,3 +1,28 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 "IDBTransaction.h" @@ -5,9 +30,11 @@ #include "Event.h" #include "EventException.h" +#include "IDBAbortEvent.h" #include "IDBDatabase.h" #include "IDBObjectStore.h" #include "IDBObjectStoreBackendInterface.h" +#include "IDBPendingTransactionMonitor.h" #include "ScriptExecutionContext.h" namespace WebCore { @@ -16,7 +43,10 @@ IDBTransaction::IDBTransaction(ScriptExecutionContext* context, PassRefPtr<IDBTr : ActiveDOMObject(context, this) , m_backend(backend) , m_database(db) + , m_stopped(false) + , m_timer(this, &IDBTransaction::timerFired) { + IDBPendingTransactionMonitor::addPendingTransaction(m_backend->id()); } IDBTransaction::~IDBTransaction() @@ -50,6 +80,22 @@ ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const return ActiveDOMObject::scriptExecutionContext(); } +void IDBTransaction::onAbort() +{ + if (!m_stopped) { + m_selfRef = this; + m_stopped = true; + m_timer.startOneShot(0); + } + // Release the backend as it holds a (circular) reference back to us. + m_backend.clear(); +} + +int IDBTransaction::id() const +{ + return m_backend->id(); +} + bool IDBTransaction::canSuspend() const { // We may be in the middle of a transaction so we cannot suspend our object. @@ -57,6 +103,15 @@ bool IDBTransaction::canSuspend() const return false; } +void IDBTransaction::stop() +{ + if (!m_stopped) { + // The document is getting detached. Abort! + m_stopped = true; + m_backend->abort(); + } +} + EventTargetData* IDBTransaction::eventTargetData() { return &m_eventTargetData; @@ -67,6 +122,14 @@ EventTargetData* IDBTransaction::ensureEventTargetData() return &m_eventTargetData; } +void IDBTransaction::timerFired(Timer<IDBTransaction>* transaction) +{ + ASSERT(m_selfRef); + + RefPtr<IDBTransaction> selfRef = m_selfRef.release(); + dispatchEvent(IDBAbortEvent::create()); +} + } #endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBTransaction.h b/WebCore/storage/IDBTransaction.h index 2e3167c..3c7f9dd 100644 --- a/WebCore/storage/IDBTransaction.h +++ b/WebCore/storage/IDBTransaction.h @@ -34,13 +34,16 @@ #include "EventNames.h" #include "EventTarget.h" #include "IDBTransactionBackendInterface.h" +#include "IDBTransactionCallbacks.h" +#include "Timer.h" +#include <wtf/RefCounted.h> namespace WebCore { class IDBDatabase; class IDBObjectStore; -class IDBTransaction : public EventTarget, public ActiveDOMObject { +class IDBTransaction : public IDBTransactionCallbacks, public EventTarget, public ActiveDOMObject { public: static PassRefPtr<IDBTransaction> create(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db) { @@ -63,12 +66,20 @@ public: DEFINE_ATTRIBUTE_EVENT_LISTENER(complete); DEFINE_ATTRIBUTE_EVENT_LISTENER(timeout); + // IDBTransactionCallbacks + virtual void onAbort(); + virtual int id() const; + // EventTarget virtual IDBTransaction* toIDBTransaction() { return this; } // ActiveDOMObject virtual ScriptExecutionContext* scriptExecutionContext() const; virtual bool canSuspend() const; + virtual void stop(); + + using RefCounted<IDBTransactionCallbacks>::ref; + using RefCounted<IDBTransactionCallbacks>::deref; private: IDBTransaction(ScriptExecutionContext*, PassRefPtr<IDBTransactionBackendInterface>, IDBDatabase*); @@ -79,9 +90,15 @@ private: virtual EventTargetData* eventTargetData(); virtual EventTargetData* ensureEventTargetData(); + void timerFired(Timer<IDBTransaction>*); + EventTargetData m_eventTargetData; RefPtr<IDBTransactionBackendInterface> m_backend; RefPtr<IDBDatabase> m_database; + + bool m_stopped; + Timer<IDBTransaction> m_timer; + RefPtr<IDBTransaction> m_selfRef; // This is set to us iff there's an event pending. }; } // namespace WebCore diff --git a/WebCore/storage/IDBTransactionBackendImpl.cpp b/WebCore/storage/IDBTransactionBackendImpl.cpp new file mode 100755 index 0000000..51b33b2 --- /dev/null +++ b/WebCore/storage/IDBTransactionBackendImpl.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 "IDBTransactionBackendImpl.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBDatabaseBackendImpl.h" +#include "SQLiteDatabase.h" + +namespace WebCore { + +PassRefPtr<IDBTransactionBackendInterface> IDBTransactionBackendImpl::create(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl* database) +{ + return adoptRef(new IDBTransactionBackendImpl(objectStores, mode, timeout, id, database)); +} + +IDBTransactionBackendImpl::IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl* database) + : m_objectStoreNames(objectStores) + , m_mode(mode) + , m_timeout(timeout) + , m_id(id) + , m_aborted(false) + , m_database(database) +{ +} + +PassRefPtr<IDBObjectStoreBackendInterface> IDBTransactionBackendImpl::objectStore(const String& name) +{ + return m_database->objectStore(name, 0); // FIXME: remove mode param. +} + +void IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>) +{ + // FIXME: implement. + ASSERT_NOT_REACHED(); +} + +void IDBTransactionBackendImpl::abort() +{ + m_aborted = true; + m_callbacks->onAbort(); +} + +}; + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBTransactionBackendImpl.h b/WebCore/storage/IDBTransactionBackendImpl.h new file mode 100755 index 0000000..fb57401 --- /dev/null +++ b/WebCore/storage/IDBTransactionBackendImpl.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 IDBTransactionBackendImpl_h +#define IDBTransactionBackendImpl_h + +#if ENABLE(INDEXED_DATABASE) + +#include "DOMStringList.h" +#include "IDBTransactionBackendInterface.h" +#include "IDBTransactionCallbacks.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBDatabaseBackendImpl; + +class IDBTransactionBackendImpl : public IDBTransactionBackendInterface { +public: + static PassRefPtr<IDBTransactionBackendInterface> create(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl*); + virtual ~IDBTransactionBackendImpl() { } + + virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name); + virtual unsigned short mode() const { return m_mode; } + virtual void scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>); + virtual void abort(); + virtual int id() const { return m_id; } + virtual void setCallbacks(IDBTransactionCallbacks* callbacks) { m_callbacks = callbacks; } + +private: + IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl*); + + RefPtr<DOMStringList> m_objectStoreNames; + unsigned short m_mode; + unsigned long m_timeout; + int m_id; + bool m_aborted; + RefPtr<IDBTransactionCallbacks> m_callbacks; + RefPtr<IDBDatabaseBackendImpl> m_database; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBTransactionBackendImpl_h diff --git a/WebCore/storage/IDBTransactionBackendInterface.h b/WebCore/storage/IDBTransactionBackendInterface.h index dff2bd7..39651f1 100644 --- a/WebCore/storage/IDBTransactionBackendInterface.h +++ b/WebCore/storage/IDBTransactionBackendInterface.h @@ -37,6 +37,7 @@ namespace WebCore { class IDBObjectStoreBackendInterface; +class IDBTransactionCallbacks; class SQLiteDatabase; // This class is shared by IDBTransaction (async) and IDBTransactionSync (sync). @@ -51,7 +52,8 @@ public: virtual unsigned short mode() const = 0; virtual void scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>) = 0; virtual void abort() = 0; - virtual SQLiteDatabase* sqliteDatabase() = 0; + virtual int id() const = 0; + virtual void setCallbacks(IDBTransactionCallbacks*) = 0; }; } // namespace WebCore diff --git a/WebCore/storage/IDBTransactionCallbacks.h b/WebCore/storage/IDBTransactionCallbacks.h new file mode 100644 index 0000000..38181fc --- /dev/null +++ b/WebCore/storage/IDBTransactionCallbacks.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBTransactionCallbacks_h +#define IDBTransactionCallbacks_h + +#if ENABLE(INDEXED_DATABASE) + +#include "SerializedScriptValue.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class IDBTransactionCallbacks : public RefCounted<IDBTransactionCallbacks> { +public: + virtual ~IDBTransactionCallbacks() { } + + virtual void onAbort() = 0; + virtual int id() const = 0; + // FIXME: add the rest +}; + +} // namespace WebCore + +#endif + +#endif // IDBTransactionCallbacks_h diff --git a/WebCore/storage/IDBTransactionCoordinator.cpp b/WebCore/storage/IDBTransactionCoordinator.cpp new file mode 100644 index 0000000..9790c1f --- /dev/null +++ b/WebCore/storage/IDBTransactionCoordinator.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 "IDBTransactionCoordinator.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBDatabaseBackendImpl.h" +#include "IDBObjectStoreBackendInterface.h" +#include "IDBTransactionBackendImpl.h" +#include "SQLiteDatabase.h" +#include "ScriptExecutionContext.h" + +namespace WebCore { + +IDBTransactionCoordinator::IDBTransactionCoordinator() + : m_nextID(0) +{ +} + +IDBTransactionCoordinator::~IDBTransactionCoordinator() +{ +} + +PassRefPtr<IDBTransactionBackendInterface> IDBTransactionCoordinator::createTransaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl* database) +{ + RefPtr<IDBTransactionBackendInterface> transaction = IDBTransactionBackendImpl::create(objectStores, mode, timeout, ++m_nextID, database); + m_transactionQueue.add(transaction.get()); + m_idMap.add(m_nextID, transaction); + return transaction.release(); +} + +void IDBTransactionCoordinator::abort(int id) +{ + ASSERT(m_idMap.contains(id)); + RefPtr<IDBTransactionBackendInterface> transaction = m_idMap.get(id); + ASSERT(transaction); + m_transactionQueue.remove(transaction.get()); + m_idMap.remove(id); + transaction->abort(); + // FIXME: this will change once we have transactions actually running. +} + +}; + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBTransactionCoordinator.h b/WebCore/storage/IDBTransactionCoordinator.h new file mode 100644 index 0000000..104a956 --- /dev/null +++ b/WebCore/storage/IDBTransactionCoordinator.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 IDBTransactionCoordinator_h +#define IDBTransactionCoordinator_h + +#if ENABLE(INDEXED_DATABASE) + +#include "DOMStringList.h" +#include "IDBTransactionBackendInterface.h" +#include <wtf/ListHashSet.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBTransactionCallbacks; +class IDBDatabaseBackendImpl; + +// This class manages transactions as follows. Requests for new transactions are +// always satisfied and the new transaction is placed in a queue. +// Transactions are not actually started until the first operation is issued. +// Each transaction executes in a separate thread and is committed automatically +// when there are no more operations issued in its context. +// When starting, a transaction will attempt to lock all the object stores in its +// scope. If this does not happen within a given timeout, an exception is raised. +// The Coordinator maintains a pool of threads. If there are no threads available +// the next transaction in the queue will have to wait until a thread becomes +// available. +// Transactions are executed in the order the were created. +class IDBTransactionCoordinator : public RefCounted<IDBTransactionCoordinator> { +public: + static PassRefPtr<IDBTransactionCoordinator> create() { return adoptRef(new IDBTransactionCoordinator()); } + virtual ~IDBTransactionCoordinator(); + + PassRefPtr<IDBTransactionBackendInterface> createTransaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl*); + void abort(int transactionId); + +private: + IDBTransactionCoordinator(); + + ListHashSet<IDBTransactionBackendInterface*> m_transactionQueue; + typedef HashMap<int, RefPtr<IDBTransactionBackendInterface> > IdToTransactionMap; + IdToTransactionMap m_idMap; + int m_nextID; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBTransactionCoordinator_h diff --git a/WebCore/storage/LocalStorageTask.h b/WebCore/storage/LocalStorageTask.h index 8d53ce4..a2e35ea 100644 --- a/WebCore/storage/LocalStorageTask.h +++ b/WebCore/storage/LocalStorageTask.h @@ -43,10 +43,10 @@ namespace WebCore { ~LocalStorageTask(); - static PassOwnPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return new LocalStorageTask(AreaImport, area); } - static PassOwnPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return new LocalStorageTask(AreaSync, area); } - static PassOwnPtr<LocalStorageTask> createDeleteEmptyDatabase(StorageAreaSync* area) { return new LocalStorageTask(DeleteEmptyDatabase, area); } - static PassOwnPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return new LocalStorageTask(TerminateThread, thread); } + 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> createTerminate(LocalStorageThread* thread) { return adoptPtr(new LocalStorageTask(TerminateThread, thread)); } void performTask(); diff --git a/WebCore/storage/LocalStorageThread.cpp b/WebCore/storage/LocalStorageThread.cpp index d4a7b4c..cbb81c5 100644 --- a/WebCore/storage/LocalStorageThread.cpp +++ b/WebCore/storage/LocalStorageThread.cpp @@ -35,7 +35,7 @@ namespace WebCore { PassOwnPtr<LocalStorageThread> LocalStorageThread::create() { - return new LocalStorageThread; + return adoptPtr(new LocalStorageThread); } LocalStorageThread::LocalStorageThread() diff --git a/WebCore/storage/SQLTransaction.cpp b/WebCore/storage/SQLTransaction.cpp index c9f6609..feaa46e 100644 --- a/WebCore/storage/SQLTransaction.cpp +++ b/WebCore/storage/SQLTransaction.cpp @@ -255,7 +255,7 @@ void SQLTransaction::openTransactionAndPreflight() m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); ASSERT(!m_sqliteTransaction); - m_sqliteTransaction.set(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); + m_sqliteTransaction = adoptPtr(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); m_database->resetDeletes(); m_database->disableAuthorizer(); @@ -273,7 +273,6 @@ void SQLTransaction::openTransactionAndPreflight() // Transaction Steps 3 - Peform preflight steps, jumping to the error callback if they fail if (m_wrapper && !m_wrapper->performPreflight(this)) { - ASSERT(!m_database->sqliteDatabase().transactionInProgress()); m_sqliteTransaction.clear(); m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) diff --git a/WebCore/storage/SQLTransactionSync.cpp b/WebCore/storage/SQLTransactionSync.cpp index e56d7b4..87f1eff 100644 --- a/WebCore/storage/SQLTransactionSync.cpp +++ b/WebCore/storage/SQLTransactionSync.cpp @@ -58,7 +58,7 @@ SQLTransactionSync::SQLTransactionSync(DatabaseSync* db, PassRefPtr<SQLTransacti , m_callback(callback) , m_readOnly(readOnly) , m_modifiedDatabase(false) - , m_transactionClient(new SQLTransactionClient()) + , m_transactionClient(adoptPtr(new SQLTransactionClient())) { ASSERT(m_database->scriptExecutionContext()->isContextThread()); } @@ -130,7 +130,7 @@ ExceptionCode SQLTransactionSync::begin() m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); ASSERT(!m_sqliteTransaction); - m_sqliteTransaction.set(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); + m_sqliteTransaction = adoptPtr(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); m_database->resetDeletes(); m_database->disableAuthorizer(); diff --git a/WebCore/storage/StorageNamespaceImpl.cpp b/WebCore/storage/StorageNamespaceImpl.cpp index 0f07e07..3a21489 100644 --- a/WebCore/storage/StorageNamespaceImpl.cpp +++ b/WebCore/storage/StorageNamespaceImpl.cpp @@ -93,12 +93,12 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy() ASSERT(!m_isShutdown); ASSERT(m_storageType == SessionStorage); - StorageNamespaceImpl* newNamespace = new StorageNamespaceImpl(m_storageType, m_path, m_quota); + RefPtr<StorageNamespaceImpl> newNamespace = adoptRef(new StorageNamespaceImpl(m_storageType, m_path, m_quota)); StorageAreaMap::iterator end = m_storageAreaMap.end(); for (StorageAreaMap::iterator i = m_storageAreaMap.begin(); i != end; ++i) newNamespace->m_storageAreaMap.set(i->first, i->second->copy()); - return adoptRef(newNamespace); + return newNamespace.release(); } PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOrigin> prpOrigin) diff --git a/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp b/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp new file mode 100644 index 0000000..0f10875 --- /dev/null +++ b/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 "IDBKeyPathBackendImpl.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "ChromiumBridge.h" + +namespace WebCore { + +void IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(const Vector<RefPtr<SerializedScriptValue>, 0>& values, const String& keyPath, Vector<RefPtr<IDBKey>, 0>& keys) +{ + ChromiumBridge::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys); +} + +} // namespace WebCore + +#endif |