WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-91125-20120813210304.patch (text/plain), 78.07 KB, created by
Alec Flett
on 2012-08-13 21:03:36 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Alec Flett
Created:
2012-08-13 21:03:36 PDT
Size:
78.07 KB
patch
obsolete
>Subversion Revision: 125411 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index fec0e32350fb7a73a11e72d2a39837749fed9f8a..09bcfade5602b55533e626698da353849a2092b5 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,91 @@ >+2012-08-10 Alec Flett <alecflett@chromium.org> >+ >+ IndexedDB: generate index keys for existing data in createIndex in front end >+ https://bugs.webkit.org/show_bug.cgi?id=91125 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Make createIndex() do index key generation in the frontend, rather >+ than the backend. When an index is created, the frontend uses the >+ cursor API to iterate through the values in the backend to >+ generate keys, sending them back to the backend using >+ IDBObjectStore::setIndexKeys() >+ >+ This confines all key injection/extraction to the frontend. >+ >+ The new test verifies the implemented behavior with respect to >+ error handling in degenerate uses of put(), though that behavior >+ is still in discussion as the spec is vague on the proper error >+ behavior. >+ >+ Test: storage/indexeddb/lazy-index-population.html >+ >+ * Modules/indexeddb/IDBCursorBackendImpl.cpp: Make sure that the >+ TaskType propagates throught the cursor and all subsequent >+ continue() calls. >+ (WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl): >+ (WebCore::IDBCursorBackendImpl::continueFunction): >+ (WebCore::IDBCursorBackendImpl::prefetchContinue): >+ * Modules/indexeddb/IDBCursorBackendImpl.h: >+ (WebCore::IDBCursorBackendImpl::create): >+ (IDBCursorBackendImpl): >+ * Modules/indexeddb/IDBObjectStore.cpp: Add an IndexPopulator >+ class to run a cursor from the frontend. >+ (WebCore): >+ (WebCore::IDBObjectStore::createIndex): >+ (WebCore::IDBObjectStore::openCursor): >+ * Modules/indexeddb/IDBObjectStore.h: >+ (WebCore::IDBObjectStore::openCursor): >+ (IDBObjectStore): >+ (WebCore::IDBObjectStore::createIndex): >+ * Modules/indexeddb/IDBObjectStore.idl: Pass along ScriptContext >+ so that openCursor can be called from createIndex. >+ * Modules/indexeddb/IDBObjectStoreBackendImpl.cpp: >+ (WebCore): >+ (WebCore::makeIndexWriters): >+ (WebCore::IDBObjectStoreBackendImpl::setIndexKeys): >+ (WebCore::IDBObjectStoreBackendImpl::setIndexesReady): >+ (WebCore::IDBObjectStoreBackendImpl::setIndexesReadyInternal): >+ (WebCore::IDBObjectStoreBackendImpl::putInternal): >+ (WebCore::IDBObjectStoreBackendImpl::deleteInternal): >+ (WebCore::IDBObjectStoreBackendImpl::createIndexInternal): >+ (WebCore::IDBObjectStoreBackendImpl::openCursor): >+ (WebCore::IDBObjectStoreBackendImpl::openCursorInternal): >+ * Modules/indexeddb/IDBObjectStoreBackendImpl.h: >+ (IDBObjectStoreBackendImpl): >+ (WebCore::IDBObjectStoreBackendImpl::iterIndexesBegin): >+ (WebCore::IDBObjectStoreBackendImpl::iterIndexesEnd): >+ (WebCore::IDBObjectStoreBackendImpl::backingStore): >+ (WebCore::IDBObjectStoreBackendImpl::databaseId): >+ * Modules/indexeddb/IDBObjectStoreBackendInterface.h: >+ * Modules/indexeddb/IDBRequest.cpp: >+ Allow requests to keep their own TaskType, to give certain >+ requests priority over others. >+ (WebCore::IDBRequest::create): >+ (WebCore): >+ (WebCore::IDBRequest::IDBRequest): >+ (WebCore::IDBRequest::abort): >+ * Modules/indexeddb/IDBRequest.h: >+ (IDBRequest): >+ (WebCore::IDBRequest::taskType): >+ * Modules/indexeddb/IDBTransactionBackendImpl.cpp: >+ Introduce a second, higher priority event queue, m_preemptiveTaskQueue, >+ which takes priority over the regular task queue. >+ (WebCore::IDBTransactionBackendImpl::IDBTransactionBackendImpl): >+ (WebCore::IDBTransactionBackendImpl::scheduleTask): >+ (WebCore::IDBTransactionBackendImpl::isTaskQueueEmpty): >+ (WebCore): >+ (WebCore::IDBTransactionBackendImpl::commit): >+ (WebCore::IDBTransactionBackendImpl::taskTimerFired): >+ (WebCore::IDBTransactionBackendImpl::taskEventTimerFired): >+ * Modules/indexeddb/IDBTransactionBackendImpl.h: >+ (WebCore::IDBTransactionBackendImpl::scheduleTask): >+ (IDBTransactionBackendImpl): >+ (WebCore::IDBTransactionBackendImpl::addEarlyEvent): >+ (WebCore::IDBTransactionBackendImpl::didCompleteEarlyEvent): >+ * Modules/indexeddb/IDBVersionChangeRequest.cpp: >+ (WebCore::IDBVersionChangeRequest::IDBVersionChangeRequest): >+ > 2012-08-13 Kwang Yul Seo <skyul@company100.net> > > [Qt] Add gprof.prf to build WebKit with gprof enabled >diff --git a/Source/WebKit/chromium/ChangeLog b/Source/WebKit/chromium/ChangeLog >index 05a0a37b3d7d6d6040e9f6a7d84a9d62ec3f1323..12c6032319a31f7d35fbee9befb38ca8530e52e8 100644 >--- a/Source/WebKit/chromium/ChangeLog >+++ b/Source/WebKit/chromium/ChangeLog >@@ -1,3 +1,30 @@ >+2012-08-10 Alec Flett <alecflett@chromium.org> >+ >+ IndexedDB: generate index keys for existing data in createIndex in front end >+ https://bugs.webkit.org/show_bug.cgi?id=91125 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add Chromium API methods to let the renderer process tell the >+ browser process about indexing progress. >+ >+ * public/WebIDBObjectStore.h: >+ (WebKit::WebIDBObjectStore::openCursor): >+ * src/IDBObjectStoreBackendProxy.cpp: >+ (WebKit::IDBObjectStoreBackendProxy::setIndexKeys): >+ (WebKit): >+ (WebKit::IDBObjectStoreBackendProxy::setIndexesReady): >+ (WebKit::IDBObjectStoreBackendProxy::openCursor): >+ * src/IDBObjectStoreBackendProxy.h: >+ (IDBObjectStoreBackendProxy): >+ * src/WebIDBObjectStoreImpl.cpp: >+ (WebKit::WebIDBObjectStoreImpl::setIndexKeys): >+ (WebKit): >+ (WebKit::WebIDBObjectStoreImpl::setIndexesReady): >+ (WebKit::WebIDBObjectStoreImpl::openCursor): >+ * src/WebIDBObjectStoreImpl.h: >+ (WebIDBObjectStoreImpl): >+ > 2012-08-13 Peter Beverloo <peter@chromium.org> > > Unreviewed. Rolled DEPS. >diff --git a/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.cpp b/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.cpp >index 9569990cd3d695c59378e3cbbd0b019bea55c7fc..66ab0b2fe6973425a12f70d8b4cb70fbcae9a11e 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.cpp >@@ -42,8 +42,9 @@ > > namespace WebCore { > >-IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor> cursor, CursorType cursorType, IDBTransactionBackendImpl* transaction, IDBObjectStoreBackendImpl* objectStore) >+IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor> cursor, CursorType cursorType, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendImpl* transaction, IDBObjectStoreBackendImpl* objectStore) > : m_cursor(cursor) >+ , m_taskType(taskType) > , m_cursorType(cursorType) > , m_transaction(transaction) > , m_objectStore(objectStore) >@@ -85,9 +86,8 @@ PassRefPtr<SerializedScriptValue> IDBCursorBackendImpl::value() const > void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec) > { > IDB_TRACE("IDBCursorBackendImpl::continue"); >- RefPtr<IDBKey> key = prpKey; > >- if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::continueFunctionInternal, this, key, prpCallbacks))) >+ if (!m_transaction->scheduleTask(m_taskType, createCallbackTask(&IDBCursorBackendImpl::continueFunctionInternal, this, prpKey, prpCallbacks))) > ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR; > } > >@@ -146,7 +146,7 @@ void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, > void IDBCursorBackendImpl::prefetchContinue(int numberToFetch, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec) > { > IDB_TRACE("IDBCursorBackendImpl::prefetchContinue"); >- if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::prefetchContinueInternal, this, numberToFetch, prpCallbacks))) >+ if (!m_transaction->scheduleTask(m_taskType, createCallbackTask(&IDBCursorBackendImpl::prefetchContinueInternal, this, numberToFetch, prpCallbacks))) > ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR; > } > >diff --git a/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.h b/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.h >index 8c9b2e6eddaff35a9d371b143947126b8a60e2a3..ca9e63cc98b9f40e4eae6236199abe218ec3efab 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.h >+++ b/Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.h >@@ -49,7 +49,11 @@ class IDBCursorBackendImpl : public IDBCursorBackendInterface { > public: > static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBBackingStore::Cursor> cursor, CursorType cursorType, IDBTransactionBackendImpl* transaction, IDBObjectStoreBackendImpl* objectStore) > { >- return adoptRef(new IDBCursorBackendImpl(cursor, cursorType, transaction, objectStore)); >+ return adoptRef(new IDBCursorBackendImpl(cursor, cursorType, IDBTransactionBackendInterface::NormalTask, transaction, objectStore)); >+ } >+ static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBBackingStore::Cursor> cursor, CursorType cursorType, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendImpl* transaction, IDBObjectStoreBackendImpl* objectStore) >+ { >+ return adoptRef(new IDBCursorBackendImpl(cursor, cursorType, taskType, transaction, objectStore)); > } > virtual ~IDBCursorBackendImpl(); > >@@ -67,7 +71,7 @@ public: > void close(); > > private: >- IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor>, CursorType, IDBTransactionBackendImpl*, IDBObjectStoreBackendImpl*); >+ IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor>, CursorType, IDBTransactionBackendInterface::TaskType, IDBTransactionBackendImpl*, IDBObjectStoreBackendImpl*); > > static void advanceInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, unsigned long, PassRefPtr<IDBCallbacks>); > static void continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>); >@@ -75,6 +79,7 @@ private: > > RefPtr<IDBBackingStore::Cursor> m_cursor; > RefPtr<IDBBackingStore::Cursor> m_savedCursor; >+ IDBTransactionBackendInterface::TaskType m_taskType; > CursorType m_cursorType; > RefPtr<IDBTransactionBackendImpl> m_transaction; > RefPtr<IDBObjectStoreBackendImpl> m_objectStore; >diff --git a/Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp b/Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp >index 7f7cd74bb0edcb63f84540beb0c959dece626f19..725d2e959ef41e3a0167b858cad80b38b1369d57 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp >@@ -32,6 +32,7 @@ > #include "IDBAny.h" > #include "IDBBindingUtilities.h" > #include "IDBCursorBackendInterface.h" >+#include "IDBCursorWithValue.h" > #include "IDBDatabase.h" > #include "IDBDatabaseException.h" > #include "IDBIndex.h" >@@ -282,18 +283,95 @@ PassRefPtr<IDBRequest> IDBObjectStore::clear(ScriptExecutionContext* context, Ex > return request.release(); > } > >-PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const String& keyPath, const Dictionary& options, ExceptionCode& ec) >+namespace { >+// This class creates the index keys for a given index by extracting >+// them from the SerializedScriptValue, for all the existing values in >+// the objectStore. It only needs to be kept alive by virtue of being >+// a listener on an IDBRequest object, in the same way that JavaScript >+// cursor success handlers are kept alive. >+class IndexPopulator : public EventListener { >+public: >+ static PassRefPtr<IndexPopulator> create(PassRefPtr<IDBObjectStoreBackendInterface> backend, PassRefPtr<IDBTransactionBackendInterface> transaction, PassRefPtr<IDBRequest> request, const IDBIndexMetadata& indexMetadata) >+ { >+ return adoptRef(new IndexPopulator(backend, transaction, indexMetadata)); >+ } >+ >+ virtual bool operator==(const EventListener& other) >+ { >+ return this == &other; >+ } >+ >+private: >+ IndexPopulator(PassRefPtr<IDBObjectStoreBackendInterface> backend, >+ PassRefPtr<IDBTransactionBackendInterface> transaction, >+ const IDBIndexMetadata& indexMetadata) >+ : EventListener(CPPEventListenerType) >+ , m_objectStoreBackend(backend) >+ , m_transaction(transaction) >+ , m_indexMetadata(indexMetadata) { } >+ >+ virtual void handleEvent(ScriptExecutionContext*, Event* event) >+ { >+ ASSERT(event->type() == eventNames().successEvent); >+ EventTarget* target = event->target(); >+ IDBRequest* request = static_cast<IDBRequest*>(target); >+ >+ ExceptionCode ec = 0; >+ RefPtr<IDBAny> cursorAny = request->result(ec); >+ ASSERT(!ec); >+ RefPtr<IDBCursorWithValue> cursor; >+ if (cursorAny->type() == IDBAny::IDBCursorWithValueType) >+ cursor = cursorAny->idbCursorWithValue(); >+ >+ Vector<String, 1> indexNames; >+ indexNames.append(m_indexMetadata.name); >+ if (cursor) { >+ cursor->continueFunction(ec); >+ ASSERT(!ec); >+ >+ RefPtr<IDBKey> primaryKey = cursor->primaryKey(); >+ RefPtr<IDBAny> valueAny = cursor->value(); >+ >+ ASSERT(valueAny->type() == IDBAny::SerializedScriptValueType); >+ RefPtr<SerializedScriptValue> value = valueAny->serializedScriptValue(); >+ >+ IDBObjectStore::IndexKeys indexKeys; >+ generateIndexKeysForValue(m_indexMetadata, value, &indexKeys); >+ >+ Vector<IDBObjectStore::IndexKeys, 1> indexKeysList; >+ indexKeysList.append(indexKeys); >+ >+ m_objectStoreBackend->setIndexKeys(primaryKey, indexNames, indexKeysList, m_transaction.get()); >+ >+ } else { >+ // Now that we are done indexing, tell the backend to go >+ // back to processing tasks of type NormalTask. >+ m_objectStoreBackend->setIndexesReady(indexNames, m_transaction.get()); >+ m_objectStoreBackend.clear(); >+ m_transaction.clear(); >+ } >+ >+ } >+ >+ RefPtr<IDBObjectStoreBackendInterface> m_objectStoreBackend; >+ RefPtr<IDBTransactionBackendInterface> m_transaction; >+ IDBIndexMetadata m_indexMetadata; >+ >+}; >+} >+ >+PassRefPtr<IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const String& keyPath, const Dictionary& options, ExceptionCode& ec) > { >- return createIndex(name, IDBKeyPath(keyPath), options, ec); >+ return createIndex(context, name, IDBKeyPath(keyPath), options, ec); > } > >-PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, PassRefPtr<DOMStringList> keyPath, const Dictionary& options, ExceptionCode& ec) >+PassRefPtr<IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, PassRefPtr<DOMStringList> keyPath, const Dictionary& options, ExceptionCode& ec) > { >- return createIndex(name, IDBKeyPath(*keyPath), options, ec); >+ return createIndex(context, name, IDBKeyPath(*keyPath), options, ec); > } > > >-PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const IDBKeyPath& keyPath, const Dictionary& options, ExceptionCode& ec) >+PassRefPtr<IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const IDBKeyPath& keyPath, const Dictionary& options, ExceptionCode& ec) > { > IDB_TRACE("IDBObjectStore::createIndex"); > if (!m_transaction->isVersionChange() || m_deleted) { >@@ -338,6 +416,19 @@ PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const IDBKe > m_indexMap.set(name, index); > m_metadata.indexes.set(name, metadata); > >+ ASSERT(!ec); >+ if (ec) >+ return 0; >+ >+ RefPtr<IDBRequest> indexRequest = openCursor(context, static_cast<IDBKeyRange*>(0), IDBCursor::directionNext(), IDBTransactionBackendInterface::PreemptiveTask, ec); >+ ASSERT(!ec); >+ if (ec) >+ return 0; >+ >+ // This is kept alive by being the success handler of the request, which is in turn kept alive by the owning transaction. >+ RefPtr<IndexPopulator> indexPopulator = IndexPopulator::create(m_backend, m_transaction->backend(), indexRequest, metadata); >+ indexRequest->setOnsuccess(indexPopulator); >+ > return index.release(); > } > >@@ -398,7 +489,7 @@ void IDBObjectStore::deleteIndex(const String& name, ExceptionCode& ec) > } > } > >-PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, const String& directionString, ExceptionCode& ec) >+PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, const String& directionString, IDBTransactionBackendInterface::TaskType taskType, ExceptionCode& ec) > { > IDB_TRACE("IDBObjectStore::openCursor"); > if (m_deleted) { >@@ -415,7 +506,7 @@ PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* contex > > RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); > request->setCursorDetails(IDBCursorBackendInterface::ObjectStoreCursor, direction); >- m_backend->openCursor(range, direction, request, m_transaction->backend(), ec); >+ m_backend->openCursor(range, direction, request, taskType, m_transaction->backend(), ec); > if (ec) { > request->markEarlyDeath(); > return 0; >diff --git a/Source/WebCore/Modules/indexeddb/IDBObjectStore.h b/Source/WebCore/Modules/indexeddb/IDBObjectStore.h >index 6fefc4e2bad095ae6d1334c3ebb96fe9089b880f..dab290c1f19d66ee77902d58ac0bbae10cac22a6 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBObjectStore.h >+++ b/Source/WebCore/Modules/indexeddb/IDBObjectStore.h >@@ -68,6 +68,11 @@ public: > PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openCursor(context, static_cast<IDBKeyRange*>(0), ec); } > PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec) { return openCursor(context, keyRange, IDBCursor::directionNext(), ec); } > PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec) { return openCursor(context, key, IDBCursor::directionNext(), ec); } >+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, const String& direction, ExceptionCode& ec) { return openCursor(context, range, direction, IDBTransactionBackendInterface::NormalTask, ec); } >+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, const String& direction, IDBTransactionBackendInterface::TaskType, ExceptionCode&); >+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKey>, const String& direction, ExceptionCode&); >+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, unsigned short direction, ExceptionCode&); >+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKey>, unsigned short direction, ExceptionCode&); > > PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&); > PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, ExceptionCode&); >@@ -78,19 +83,15 @@ public: > PassRefPtr<IDBRequest> clear(ScriptExecutionContext*, ExceptionCode&); > > // FIXME: Try to modify the code generator so this duplication is unneeded. >- PassRefPtr<IDBIndex> createIndex(const String& name, const String& keyPath, const Dictionary&, ExceptionCode&); >- PassRefPtr<IDBIndex> createIndex(const String& name, const String& keyPath, ExceptionCode& ec) { return createIndex(name, keyPath, Dictionary(), ec); } >- PassRefPtr<IDBIndex> createIndex(const String& name, PassRefPtr<DOMStringList> keyPath, const Dictionary&, ExceptionCode&); >- PassRefPtr<IDBIndex> createIndex(const String& name, PassRefPtr<DOMStringList> keyPath, ExceptionCode& ec) { return createIndex(name, keyPath, Dictionary(), ec); } >- PassRefPtr<IDBIndex> createIndex(const String&, const IDBKeyPath&, const Dictionary&, ExceptionCode&); >+ PassRefPtr<IDBIndex> createIndex(ScriptExecutionContext*, const String& name, const String& keyPath, const Dictionary&, ExceptionCode&); >+ PassRefPtr<IDBIndex> createIndex(ScriptExecutionContext* context, const String& name, const String& keyPath, ExceptionCode& ec) { return createIndex(context, name, keyPath, Dictionary(), ec); } >+ PassRefPtr<IDBIndex> createIndex(ScriptExecutionContext*, const String& name, PassRefPtr<DOMStringList> keyPath, const Dictionary&, ExceptionCode&); >+ PassRefPtr<IDBIndex> createIndex(ScriptExecutionContext* context, const String& name, PassRefPtr<DOMStringList> keyPath, ExceptionCode& ec) { return createIndex(context, name, keyPath, Dictionary(), ec); } >+ PassRefPtr<IDBIndex> createIndex(ScriptExecutionContext*, const String&, const IDBKeyPath&, const Dictionary&, ExceptionCode&); > > PassRefPtr<IDBIndex> index(const String& name, ExceptionCode&); > void deleteIndex(const String& name, ExceptionCode&); > >- PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, const String& direction, ExceptionCode&); >- PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKey>, const String& direction, ExceptionCode&); >- PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, unsigned short direction, ExceptionCode&); >- PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKey>, unsigned short direction, ExceptionCode&); > PassRefPtr<IDBRequest> count(ScriptExecutionContext* context, ExceptionCode& ec) { return count(context, static_cast<IDBKeyRange*>(0), ec); } > PassRefPtr<IDBRequest> count(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, ExceptionCode&); > PassRefPtr<IDBRequest> count(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&); >diff --git a/Source/WebCore/Modules/indexeddb/IDBObjectStore.idl b/Source/WebCore/Modules/indexeddb/IDBObjectStore.idl >index 9ed1422b72d2065cf1c268459881f1a330c27b6c..ca652b0310c5e30fafb20aaf03c304a351519d1a 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBObjectStore.idl >+++ b/Source/WebCore/Modules/indexeddb/IDBObjectStore.idl >@@ -59,9 +59,9 @@ module storage { > [CallWith=ScriptExecutionContext] IDBRequest openCursor(in IDBKey key, in [Optional] unsigned short direction) > raises (IDBDatabaseException); > >- IDBIndex createIndex(in DOMString name, in DOMString[] keyPath, in [Optional] Dictionary options) >+ [CallWith=ScriptExecutionContext] IDBIndex createIndex(in DOMString name, in DOMString[] keyPath, in [Optional] Dictionary options) > raises (IDBDatabaseException); >- IDBIndex createIndex(in DOMString name, in DOMString keyPath, in [Optional] Dictionary options) >+ [CallWith=ScriptExecutionContext] IDBIndex createIndex(in DOMString name, in DOMString keyPath, in [Optional] Dictionary options) > raises (IDBDatabaseException); > IDBIndex index(in DOMString name) > raises (IDBDatabaseException); >diff --git a/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp b/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp >index ce0915a306f1a73f4bc9f5e29cd70ca6f3a9f275..dbf1a58ff0f952a574c086eec31aeae7f8db2f83 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp >@@ -154,31 +154,6 @@ public: > , m_indexKeys(indexKeys) > { } > >- // FIXME: remove this once createIndex() generates these in the renderer. >- void generateIndexKeysForValue(SerializedScriptValue* objectValue) >- { >- m_indexKeys.clear(); >- >- RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue); >- >- if (!indexKey) >- return; >- >- if (!m_indexMetadata.multiEntry || indexKey->type() != IDBKey::ArrayType) { >- if (!indexKey->isValid()) >- return; >- >- m_indexKeys.append(indexKey); >- } else { >- ASSERT(m_indexMetadata.multiEntry); >- ASSERT(indexKey->type() == IDBKey::ArrayType); >- indexKey = IDBKey::createMultiEntryArray(indexKey->array()); >- >- for (size_t i = 0; i < indexKey->array().size(); ++i) >- m_indexKeys.append(indexKey->array()[i]); >- } >- } >- > bool verifyIndexKeys(IDBBackingStore& backingStore, > int64_t databaseId, int64_t objectStoreId, int64_t indexId, > const IDBKey* primaryKey = 0, String* errorMessage = 0) >@@ -245,6 +220,97 @@ private: > }; > } > >+static bool makeIndexWriters(IDBObjectStoreBackendImpl* objectStore, PassRefPtr<IDBKey> primaryKey, bool keyWasGenerated, const Vector<String> indexNames, const Vector<IDBObjectStoreBackendInterface::IndexKeys>& indexKeys, Vector<OwnPtr<IndexWriter> > *indexWriters, String *errorMessage) >+{ >+ ASSERT(indexNames.size() == indexKeys.size()); >+ >+ HashMap<String, IDBObjectStoreBackendInterface::IndexKeys> indexKeyMap; >+ for (size_t i = 0; i < indexNames.size(); i++) >+ indexKeyMap.add(indexNames[i], indexKeys[i]); >+ >+ for (IDBObjectStoreBackendImpl::IndexMap::iterator it = objectStore->iterIndexesBegin(); it != objectStore->iterIndexesEnd(); ++it) { >+ >+ const RefPtr<IDBIndexBackendImpl>& index = it->second; >+ if (!index->hasValidId()) >+ continue; // The index object has been created, but does not exist in the database yet. >+ >+ OwnPtr<IndexWriter> indexWriter; >+ IDBObjectStoreBackendInterface::IndexKeys keys = indexKeyMap.get(it->first); >+ // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key. >+ if (keyWasGenerated) { >+ const IDBKeyPath& indexKeyPath = index->keyPath(); >+ if (indexKeyPath == objectStore->keyPath()) >+ keys.append(primaryKey); >+ } >+ indexWriter = adoptPtr(new IndexWriter(index->metadata(), keys)); >+ >+ if (!indexWriter->verifyIndexKeys(*objectStore->backingStore(), >+ objectStore->databaseId(), >+ objectStore->id(), >+ index->id(), primaryKey.get(), errorMessage)) { >+ return false; >+ } >+ >+ indexWriters->append(indexWriter.release()); >+ } >+ >+ return true; >+} >+ >+void IDBObjectStoreBackendImpl::setIndexKeys(PassRefPtr<IDBKey> prpPrimaryKey, const Vector<String>& indexNames, const Vector<IndexKeys>& indexKeys, IDBTransactionBackendInterface* transaction) >+{ >+ IDB_TRACE("IDBObjectStoreImpl::setIndexKeys"); >+ RefPtr<IDBKey> primaryKey = prpPrimaryKey; >+ >+ // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity. >+ RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = backingStore()->createInvalidRecordIdentifier(); >+ if (!backingStore()->keyExistsInObjectStore(databaseId(), id(), *primaryKey, recordIdentifier.get())) { >+ transaction->abort(); >+ return; >+ } >+ >+ Vector<OwnPtr<IndexWriter> > indexWriters; >+ String errorMessage; >+ if (!makeIndexWriters(this, primaryKey, false, indexNames, indexKeys, &indexWriters, &errorMessage)) { >+ // FIXME: Need to deal with errorMessage here. makeIndexWriters only fails on uniqueness constraint errors. >+ transaction->abort(); >+ return; >+ } >+ >+ for (size_t i = 0; i < indexWriters.size(); ++i) { >+ IndexWriter* indexWriter = indexWriters[i].get(); >+ if (!indexWriter->writeIndexKeys(recordIdentifier.get(), >+ *backingStore(), >+ databaseId(), >+ m_id, >+ m_indexes.get(indexWriter->indexName())->id())) { >+ transaction->abort(); >+ return; >+ } >+ } >+} >+ >+void IDBObjectStoreBackendImpl::setIndexesReady(const Vector<String>& indexNames, IDBTransactionBackendInterface* transactionInterface) >+{ >+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this; >+ >+ OwnPtr<Vector<String> > names = adoptPtr(new Vector<String>(indexNames)); >+ RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionInterface); >+ >+ if (!transaction->scheduleTask( >+ IDBTransactionBackendInterface::PreemptiveTask, >+ createCallbackTask(&IDBObjectStoreBackendImpl::setIndexesReadyInternal, objectStore, names.release(), transaction))) >+ ASSERT_NOT_REACHED(); >+} >+ >+void IDBObjectStoreBackendImpl::setIndexesReadyInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassOwnPtr<Vector<String> > popIndexNames, PassRefPtr<IDBTransactionBackendImpl> transaction) >+{ >+ OwnPtr<Vector<String> > indexNames = popIndexNames; >+ for (size_t i = 0; i < indexNames->size(); ++i) >+ transaction->didCompletePreemptiveEvent(); >+ transaction->didCompleteTaskEvents(); >+} >+ > void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction, PassOwnPtr<Vector<String> > popIndexNames, PassOwnPtr<Vector<IndexKeys> > popIndexKeys) > { > IDB_TRACE("IDBObjectStoreBackendImpl::putInternal"); >@@ -276,39 +342,10 @@ void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr< > } > > Vector<OwnPtr<IndexWriter> > indexWriters; >- HashMap<String, IndexKeys> indexKeyMap; >- for (size_t i = 0; i < indexNames->size(); ++i) { >- IndexKeys keys = indexKeys->at(i); >- >- // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key. >- if (keyWasGenerated) { >- const IDBKeyPath& indexKeyPath = objectStore->m_indexes.get(indexNames->at(i))->keyPath(); >- if (indexKeyPath == objectStore->keyPath()) >- keys.append(key); >- } >- >- indexKeyMap.add(indexNames->at(i), keys); >- } >- >- for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) { >- >- const RefPtr<IDBIndexBackendImpl>& index = it->second; >- if (!index->hasValidId()) >- continue; // The index object has been created, but does not exist in the database yet. >- >- OwnPtr<IndexWriter> indexWriter; >- indexWriter = adoptPtr(new IndexWriter(index->metadata(), indexKeyMap.get(it->first))); >- >- String errorMessage; >- if (!indexWriter->verifyIndexKeys(*objectStore->backingStore(), >- objectStore->databaseId(), >- objectStore->id(), >- index->id(), key.get(), &errorMessage)) { >- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, errorMessage)); >- return; >- } >- >- indexWriters.append(indexWriter.release()); >+ String errorMessage; >+ if (!makeIndexWriters(objectStore.get(), key, keyWasGenerated, *indexNames, *indexKeys, &indexWriters, &errorMessage)) { >+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, errorMessage)); >+ return; > } > > // Before this point, don't do any mutation. After this point, rollback the transaction in case of error. >@@ -365,7 +402,7 @@ void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefP > do { > recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier(); > >- for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) { >+ for (IDBObjectStoreBackendImpl::IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) { > if (!it->second->hasValidId()) > continue; // The index object has been created, but does not exist in the database yet. > >@@ -403,44 +440,6 @@ void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPt > callbacks->onSuccess(SerializedScriptValue::undefinedValue()); > } > >-namespace { >-class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback { >-public: >- PopulateIndexCallback(IDBBackingStore& backingStore, const IDBIndexMetadata& indexMetadata, int64_t databaseId, int64_t objectStoreId, int64_t indexId) >- : m_backingStore(backingStore) >- , m_databaseId(databaseId) >- , m_objectStoreId(objectStoreId) >- , m_indexId(indexId) >- , m_writer(indexMetadata) >- { >- } >- >- virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value) >- { >- RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value); >- m_writer.generateIndexKeysForValue(objectValue.get()); >- if (!m_writer.verifyIndexKeys(m_backingStore, m_databaseId, m_objectStoreId, m_indexId)) >- return false; >- return m_writer.writeIndexKeys(recordIdentifier, m_backingStore, m_databaseId, m_objectStoreId, m_indexId); >- } >- >-private: >- IDBBackingStore& m_backingStore; >- int64_t m_databaseId; >- int64_t m_objectStoreId; >- int64_t m_indexId; >- IndexWriter m_writer; >-}; >-} >- >-bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index) >-{ >- PopulateIndexCallback callback(backingStore, index->metadata(), databaseId, objectStoreId, index->id()); >- if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback)) >- return false; >- return true; >-} >- > PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) > { > ASSERT(!m_indexes.contains(name)); >@@ -473,11 +472,6 @@ void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, Pas > > index->setId(id); > >- if (!populateIndex(*objectStore->backingStore(), objectStore->databaseId(), objectStore->m_id, index)) { >- transaction->abort(); >- return; >- } >- > transaction->didCompleteTaskEvents(); > } > >@@ -515,7 +509,13 @@ void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, Pas > transaction->didCompleteTaskEvents(); > } > >-void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) >+void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) >+{ >+ IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection); >+ openCursor(prpRange, direction, prpCallbacks, IDBTransactionBackendInterface::NormalTask, transactionPtr, ec); >+} >+ >+void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) > { > IDB_TRACE("IDBObjectStoreBackendImpl::openCursor"); > RefPtr<IDBObjectStoreBackendImpl> objectStore = this; >@@ -523,23 +523,28 @@ void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, uns > RefPtr<IDBCallbacks> callbacks = prpCallbacks; > RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr); > if (!transaction->scheduleTask( >- createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, transaction))) { >+ createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, taskType, transaction))) { > ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR; > } > } > >-void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction) >+void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface::TaskType taskType, PassRefPtr<IDBTransactionBackendImpl> transaction) > { > IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal"); >- IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection); > > RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), direction); >+ // The frontend has begun indexing, so this pauses the transaction >+ // until the indexing is complete. This can't happen any earlier >+ // because we don't want to switch to early mode in case multiple >+ // indexes are being created in a row, with put()'s in between. >+ if (taskType == IDBTransactionBackendInterface::PreemptiveTask) >+ transaction->addPreemptiveEvent(); > if (!backingStoreCursor) { > callbacks->onSuccess(SerializedScriptValue::nullValue()); > return; > } > >- RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get()); >+ RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), IDBCursorBackendInterface::ObjectStoreCursor, taskType, transaction.get(), objectStore.get()); > callbacks->onSuccess(cursor.release()); > } > >diff --git a/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.h b/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.h >index 5b1b54fc2db85fd493aecd7d67bc5dbf95a57042..0a82473acffe43441afeb73516ce90d47fe5e8d8 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.h >+++ b/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.h >@@ -26,6 +26,7 @@ > #ifndef IDBObjectStoreBackendImpl_h > #define IDBObjectStoreBackendImpl_h > >+#include "IDBBackingStore.h" > #include "IDBDatabaseBackendImpl.h" > #include "IDBKeyPath.h" > #include "IDBMetadata.h" >@@ -56,6 +57,8 @@ public: > } > virtual ~IDBObjectStoreBackendImpl(); > >+ typedef HashMap<String, RefPtr<IDBIndexBackendImpl> > IndexMap; >+ > static const int64_t InvalidId = 0; > int64_t id() const > { >@@ -71,19 +74,29 @@ public: > virtual void clear(PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&); > > virtual PassRefPtr<IDBIndexBackendInterface> createIndex(const String& name, const IDBKeyPath&, bool unique, bool multiEntry, IDBTransactionBackendInterface*, ExceptionCode&); >+ virtual void setIndexKeys(PassRefPtr<IDBKey> prpPrimaryKey, const Vector<String>&, const Vector<IndexKeys>& , IDBTransactionBackendInterface*); >+ virtual void setIndexesReady(const Vector<String>&, IDBTransactionBackendInterface*); > virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name, ExceptionCode&); > virtual void deleteIndex(const String& name, IDBTransactionBackendInterface*, ExceptionCode&); > >+ // FIXME: Remove this version of openCursor when TaskType is plumbed through chromium. > virtual void openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&); >+ virtual void openCursor(PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface::TaskType, IDBTransactionBackendInterface*, ExceptionCode&); > virtual void count(PassRefPtr<IDBKeyRange>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&); > > static bool populateIndex(IDBBackingStore&, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl>); > >+ const IndexMap::iterator iterIndexesBegin() { return m_indexes.begin(); }; >+ const IndexMap::iterator iterIndexesEnd() { return m_indexes.end(); }; >+ > IDBObjectStoreMetadata metadata() const; > const String& name() { return m_name; } > const IDBKeyPath& keyPath() const { return m_keyPath; } > const bool& autoIncrement() const { return m_autoIncrement; } >- >+ >+ PassRefPtr<IDBBackingStore> backingStore() const { return m_database->backingStore(); } >+ int64_t databaseId() const { return m_database->id(); } >+ > private: > IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl*, int64_t databaseId, const String& name, const IDBKeyPath&, bool autoIncrement); > IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl*, const String& name, const IDBKeyPath&, bool autoIncrement); >@@ -95,26 +108,23 @@ private: > static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, PassRefPtr<IDBCallbacks>); > static void putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, PutMode, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendImpl>, PassOwnPtr<Vector<String> > popIndexNames, PassOwnPtr<Vector<IndexKeys> >); > static void deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, PassRefPtr<IDBCallbacks>); >+ static void setIndexesReadyInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassOwnPtr<Vector<String> > popIndexNames, PassRefPtr<IDBTransactionBackendImpl>); > static void clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBCallbacks>); > static void createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBTransactionBackendImpl>); > static void deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBTransactionBackendImpl>); >- static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendImpl>); >+ static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface::TaskType, PassRefPtr<IDBTransactionBackendImpl>); > static void countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, PassRefPtr<IDBCallbacks>); > > // These are used as setVersion transaction abort tasks. > static void removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>); > static void addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>); > >- PassRefPtr<IDBBackingStore> backingStore() const { return m_database->backingStore(); } >- int64_t databaseId() const { return m_database->id(); } >- > const IDBDatabaseBackendImpl* m_database; > int64_t m_id; > String m_name; > IDBKeyPath m_keyPath; > bool m_autoIncrement; > >- typedef HashMap<String, RefPtr<IDBIndexBackendImpl> > IndexMap; > IndexMap m_indexes; > }; > >diff --git a/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendInterface.h b/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendInterface.h >index f2fd088c1c4314d8bd4a3f36352b939b3495dfe5..3801e48117f30311a4e853fa95fd42017c4a8888 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendInterface.h >+++ b/Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendInterface.h >@@ -26,6 +26,7 @@ > #ifndef IDBObjectStoreBackendInterface_h > #define IDBObjectStoreBackendInterface_h > >+#include "IDBCursor.h" > #include "PlatformString.h" > #include <wtf/Threading.h> > >@@ -63,10 +64,14 @@ public: > virtual void clear(PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0; > > virtual PassRefPtr<IDBIndexBackendInterface> createIndex(const String& name, const IDBKeyPath&, bool unique, bool multiEntry, IDBTransactionBackendInterface*, ExceptionCode&) = 0; >+ virtual void setIndexKeys(PassRefPtr<IDBKey> prpPrimaryKey, const Vector<String>&, const Vector<IndexKeys>&, IDBTransactionBackendInterface*) = 0; >+ virtual void setIndexesReady(const Vector<String>&, IDBTransactionBackendInterface*) = 0; > virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name, ExceptionCode&) = 0; > virtual void deleteIndex(const String& name, IDBTransactionBackendInterface*, ExceptionCode&) = 0; > >+ // FIXME: Remove this version of openCursor when TaskType is plumbed through chromium. > virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0; >+ virtual void openCursor(PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface::TaskType, IDBTransactionBackendInterface*, ExceptionCode&) = 0; > virtual void count(PassRefPtr<IDBKeyRange>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0; > }; > >diff --git a/Source/WebCore/Modules/indexeddb/IDBRequest.cpp b/Source/WebCore/Modules/indexeddb/IDBRequest.cpp >index 1270efccdd4227c5b2e7be23de65305b5061873c..697cbc84ba5140bb710a4f427b243d1a72af5586 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBRequest.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBRequest.cpp >@@ -46,15 +46,23 @@ namespace WebCore { > > PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction) > { >- RefPtr<IDBRequest> request(adoptRef(new IDBRequest(context, source, transaction))); >+ RefPtr<IDBRequest> request(adoptRef(new IDBRequest(context, source, IDBTransactionBackendInterface::NormalTask, transaction))); > request->suspendIfNeeded(); > return request.release(); > } > >-IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction) >+PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface::TaskType taskType, IDBTransaction* transaction) >+{ >+ RefPtr<IDBRequest> request(adoptRef(new IDBRequest(context, source, taskType, transaction))); >+ request->suspendIfNeeded(); >+ return request.release(); >+} >+ >+IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface::TaskType taskType, IDBTransaction* transaction) > : ActiveDOMObject(context, this) > , m_errorCode(0) > , m_source(source) >+ , m_taskType(taskType) > , m_transaction(transaction) > , m_readyState(PENDING) > , m_requestAborted(false) >diff --git a/Source/WebCore/Modules/indexeddb/IDBRequest.h b/Source/WebCore/Modules/indexeddb/IDBRequest.h >index f5cb5b7427fb8aab1985b8425f054675130e7b72..9a5f44957f1cf96d6ef0aad9435317ff5cd5381c 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBRequest.h >+++ b/Source/WebCore/Modules/indexeddb/IDBRequest.h >@@ -52,6 +52,7 @@ typedef int ExceptionCode; > class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject { > public: > static PassRefPtr<IDBRequest> create(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransaction*); >+ static PassRefPtr<IDBRequest> create(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface::TaskType, IDBTransaction*); > virtual ~IDBRequest(); > > PassRefPtr<IDBAny> result(ExceptionCode&) const; >@@ -105,8 +106,10 @@ public: > using ThreadSafeRefCounted<IDBCallbacks>::ref; > using ThreadSafeRefCounted<IDBCallbacks>::deref; > >+ IDBTransactionBackendInterface::TaskType taskType() { return m_taskType; } >+ > protected: >- IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransaction*); >+ IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface::TaskType, IDBTransaction*); > void enqueueEvent(PassRefPtr<Event>); > bool shouldEnqueueEvent() const; > >@@ -126,6 +129,7 @@ private: > void setResultCursor(PassRefPtr<IDBCursor>); > > RefPtr<IDBAny> m_source; >+ const IDBTransactionBackendInterface::TaskType m_taskType; > RefPtr<IDBTransaction> m_transaction; > > ReadyState m_readyState; >diff --git a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp >index 1bbd23b56bba0f9e6ef34499deb806b3c08470ef..2a6b82268f34f1647fb0c37fbc5a6e533d7d30ff 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp >@@ -51,6 +51,7 @@ IDBTransactionBackendImpl::IDBTransactionBackendImpl(DOMStringList* objectStores > , m_transaction(database->backingStore()->createTransaction()) > , m_taskTimer(this, &IDBTransactionBackendImpl::taskTimerFired) > , m_taskEventTimer(this, &IDBTransactionBackendImpl::taskEventTimerFired) >+ , m_pendingPreemptiveEvents(0) > , m_pendingEvents(0) > { > ASSERT(m_objectStoreNames); >@@ -89,12 +90,16 @@ PassRefPtr<IDBObjectStoreBackendInterface> IDBTransactionBackendImpl::objectStor > return objectStore.release(); > } > >-bool IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask) >+bool IDBTransactionBackendImpl::scheduleTask(TaskType type, PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask) > { > if (m_state == Finished) > return false; > >- m_taskQueue.append(task); >+ if (type == NormalTask) >+ m_taskQueue.append(task); >+ else >+ m_preemptiveTaskQueue.append(task); >+ > if (abortTask) > m_abortTaskQueue.prepend(abortTask); > >@@ -149,6 +154,11 @@ void IDBTransactionBackendImpl::abort() > m_database = 0; > } > >+bool IDBTransactionBackendImpl::isTaskQueueEmpty() const >+{ >+ return m_preemptiveTaskQueue.isEmpty() && m_taskQueue.isEmpty(); >+} >+ > void IDBTransactionBackendImpl::registerOpenCursor(IDBCursorBackendImpl* cursor) > { > m_openCursors.add(cursor); >@@ -203,7 +213,7 @@ void IDBTransactionBackendImpl::commit() > // alive while executing this method. > RefPtr<IDBTransactionBackendImpl> self(this); > ASSERT(m_state == Unused || m_state == Running); >- ASSERT(m_taskQueue.isEmpty()); >+ ASSERT(isTaskQueueEmpty()); > > bool unused = m_state == Unused; > m_state = Finished; >@@ -235,19 +245,20 @@ void IDBTransactionBackendImpl::commit() > void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*) > { > IDB_TRACE("IDBTransactionBackendImpl::taskTimerFired"); >- ASSERT(!m_taskQueue.isEmpty()); >+ ASSERT(!isTaskQueueEmpty()); > > if (m_state == StartPending) { > m_transaction->begin(); > m_state = Running; > } > >- TaskQueue queue; >- queue.swap(m_taskQueue); >- while (!queue.isEmpty() && m_state != Finished) { >+ // Just process a single event here, in case the event itself >+ // changes which queue should be processed next. >+ TaskQueue& taskQueue = m_pendingPreemptiveEvents ? m_preemptiveTaskQueue : m_taskQueue; >+ if (!taskQueue.isEmpty() && m_state != Finished) { > ASSERT(m_state == Running); >- OwnPtr<ScriptExecutionContext::Task> task(queue.first().release()); >- queue.removeFirst(); >+ OwnPtr<ScriptExecutionContext::Task> task(taskQueue.first().release()); >+ taskQueue.removeFirst(); > m_pendingEvents++; > task->performTask(0); > } >@@ -258,7 +269,7 @@ void IDBTransactionBackendImpl::taskEventTimerFired(Timer<IDBTransactionBackendI > IDB_TRACE("IDBTransactionBackendImpl::taskEventTimerFired"); > ASSERT(m_state == Running); > >- if (!m_pendingEvents && m_taskQueue.isEmpty()) { >+ if (!m_pendingEvents && isTaskQueueEmpty()) { > // The last task event has completed and the task > // queue is empty. Commit the transaction. > commit(); >@@ -268,7 +279,7 @@ void IDBTransactionBackendImpl::taskEventTimerFired(Timer<IDBTransactionBackendI > // We are still waiting for other events to complete. However, > // the task queue is non-empty and the timer is inactive. > // We can therfore schedule the timer again. >- if (!m_taskQueue.isEmpty() && !m_taskTimer.isActive()) >+ if (!isTaskQueueEmpty() && !m_taskTimer.isActive()) > m_taskTimer.startOneShot(0); > } > >diff --git a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h >index daa39e1c392c52cf25985ae753d5b6cea9aeba2c..24c4fee0415bd5bb512a2322ca8bf575eb517376 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h >+++ b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h >@@ -58,10 +58,13 @@ public: > > void run(); > unsigned short mode() const { return m_mode; } >- bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>, PassOwnPtr<ScriptExecutionContext::Task> abortTask = nullptr); >+ bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask = nullptr) { return scheduleTask(NormalTask, task, abortTask); } >+ bool scheduleTask(TaskType, PassOwnPtr<ScriptExecutionContext::Task>, PassOwnPtr<ScriptExecutionContext::Task> abortTask = nullptr); > void registerOpenCursor(IDBCursorBackendImpl*); > void unregisterOpenCursor(IDBCursorBackendImpl*); > void addPendingEvents(int); >+ void addPreemptiveEvent() { m_pendingPreemptiveEvents++; } >+ void didCompletePreemptiveEvent() { m_pendingPreemptiveEvents--; ASSERT(m_pendingPreemptiveEvents >= 0); } > > private: > IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, IDBDatabaseBackendImpl*); >@@ -76,6 +79,8 @@ private: > void start(); > void commit(); > >+ bool isTaskQueueEmpty() const; >+ > void taskTimerFired(Timer<IDBTransactionBackendImpl>*); > void taskEventTimerFired(Timer<IDBTransactionBackendImpl>*); > void closeOpenCursors(); >@@ -89,6 +94,7 @@ private: > > typedef Deque<OwnPtr<ScriptExecutionContext::Task> > TaskQueue; > TaskQueue m_taskQueue; >+ TaskQueue m_preemptiveTaskQueue; > TaskQueue m_abortTaskQueue; > > RefPtr<IDBBackingStore::Transaction> m_transaction; >@@ -96,6 +102,7 @@ private: > // FIXME: delete the timer once we have threads instead. > Timer<IDBTransactionBackendImpl> m_taskTimer; > Timer<IDBTransactionBackendImpl> m_taskEventTimer; >+ int m_pendingPreemptiveEvents; > int m_pendingEvents; > > HashSet<IDBCursorBackendImpl*> m_openCursors; >diff --git a/Source/WebCore/Modules/indexeddb/IDBVersionChangeRequest.cpp b/Source/WebCore/Modules/indexeddb/IDBVersionChangeRequest.cpp >index c741a7be4d0b385d165abdf6acb17bb79188c38e..92f4ef123aa4027f4d6b2bae98e6019a6f61aae2 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBVersionChangeRequest.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBVersionChangeRequest.cpp >@@ -42,7 +42,7 @@ PassRefPtr<IDBVersionChangeRequest> IDBVersionChangeRequest::create(ScriptExecut > } > > IDBVersionChangeRequest::IDBVersionChangeRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, const String& version) >- : IDBRequest(context, source, 0) >+ : IDBRequest(context, source, IDBTransactionBackendInterface::NormalTask, 0) > , m_version(version) > { > } >diff --git a/Source/WebKit/chromium/public/WebIDBObjectStore.h b/Source/WebKit/chromium/public/WebIDBObjectStore.h >index ba59c15eeaf4f3d6a8f8d27c63c180e558ea414c..826965c0dea2e17bb2b9d61a1b6b613bb1dbb216 100644 >--- a/Source/WebKit/chromium/public/WebIDBObjectStore.h >+++ b/Source/WebKit/chromium/public/WebIDBObjectStore.h >@@ -73,7 +73,10 @@ public: > } > virtual void deleteIndex(const WebString& name, const WebIDBTransaction&, WebExceptionCode&) { WEBKIT_ASSERT_NOT_REACHED(); } > // FIXME: Remove this version of openCursor when TaskType is plumbed through chromium. >- virtual void openCursor(const WebIDBKeyRange&, unsigned short direction, WebIDBCallbacks*, const WebIDBTransaction&, WebExceptionCode&) { WEBKIT_ASSERT_NOT_REACHED(); } >+ virtual void openCursor(const WebIDBKeyRange& range, unsigned short direction, WebIDBCallbacks* callbacks, const WebIDBTransaction& transaction, WebExceptionCode& ec) >+ { >+ openCursor(range, static_cast<WebIDBCursor::Direction>(direction), callbacks, WebIDBTransaction::NormalTask, transaction, ec); >+ } > virtual void openCursor(const WebIDBKeyRange&, WebIDBCursor::Direction direction, WebIDBCallbacks*, WebIDBTransaction::TaskType, const WebIDBTransaction&, WebExceptionCode&) { WEBKIT_ASSERT_NOT_REACHED(); } > virtual void count(const WebIDBKeyRange&, WebIDBCallbacks*, const WebIDBTransaction&, WebExceptionCode&) { WEBKIT_ASSERT_NOT_REACHED(); } > >diff --git a/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.cpp b/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.cpp >index 4d1c91d075ff607a737b220107fdb7b0bf24b759..b8fb074eaa678dbf0167d20b49524d8d4290a699 100755 >--- a/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.cpp >+++ b/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.cpp >@@ -77,6 +77,16 @@ void IDBObjectStoreBackendProxy::putWithIndexKeys(PassRefPtr<SerializedScriptVal > m_webIDBObjectStore->putWithIndexKeys(value, key, static_cast<WebIDBObjectStore::PutMode>(putMode), new WebIDBCallbacksImpl(callbacks), *transactionProxy->getWebIDBTransaction(), webIndexNames, webIndexKeys, ec); > } > >+void IDBObjectStoreBackendProxy::setIndexKeys(PassRefPtr<IDBKey> prpPrimaryKey, const Vector<String>& indexNames, const Vector<IndexKeys>& indexKeys, IDBTransactionBackendInterface* transaction) >+{ >+ // The transaction pointer is guaranteed to be a pointer to a proxy object as, in the renderer, >+ // all implementations of IDB interfaces are proxy objects. >+ IDBTransactionBackendProxy* transactionProxy = static_cast<IDBTransactionBackendProxy*>(transaction); >+ WebVector<WebString> webIndexNames(indexNames); >+ WebVector<IndexKeys> webIndexKeys(indexKeys); >+ m_webIDBObjectStore->setIndexKeys(prpPrimaryKey, webIndexNames, webIndexKeys, *transactionProxy->getWebIDBTransaction()); >+} >+ > void IDBObjectStoreBackendProxy::deleteFunction(PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) > { > // The transaction pointer is guaranteed to be a pointer to a proxy object as, in the renderer, >@@ -104,6 +114,14 @@ PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendProxy::createIndex(con > return IDBIndexBackendProxy::create(index.release()); > } > >+void IDBObjectStoreBackendProxy::setIndexesReady(const Vector<String>& indexNames, IDBTransactionBackendInterface* transaction) >+{ >+ // The transaction pointer is guaranteed to be a pointer to a proxy object as, in the renderer, >+ // all implementations of IDB interfaces are proxy objects. >+ IDBTransactionBackendProxy* transactionProxy = static_cast<IDBTransactionBackendProxy*>(transaction); >+ m_webIDBObjectStore->setIndexesReady(indexNames, *transactionProxy->getWebIDBTransaction()); >+} >+ > PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendProxy::index(const String& name, ExceptionCode& ec) > { > OwnPtr<WebIDBIndex> index = adoptPtr(m_webIDBObjectStore->index(name, ec)); >@@ -125,7 +143,15 @@ void IDBObjectStoreBackendProxy::openCursor(PassRefPtr<IDBKeyRange> range, unsig > // The transaction pointer is guaranteed to be a pointer to a proxy object as, in the renderer, > // all implementations of IDB interfaces are proxy objects. > IDBTransactionBackendProxy* transactionProxy = static_cast<IDBTransactionBackendProxy*>(transaction); >- m_webIDBObjectStore->openCursor(range, direction, new WebIDBCallbacksImpl(callbacks), *transactionProxy->getWebIDBTransaction(), ec); >+ m_webIDBObjectStore->openCursor(range, static_cast<WebIDBCursor::Direction>(direction), new WebIDBCallbacksImpl(callbacks), *transactionProxy->getWebIDBTransaction(), ec); >+} >+ >+void IDBObjectStoreBackendProxy::openCursor(PassRefPtr<IDBKeyRange> range, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) >+{ >+ // The transaction pointer is guaranteed to be a pointer to a proxy object as, in the renderer, >+ // all implementations of IDB interfaces are proxy objects. >+ IDBTransactionBackendProxy* transactionProxy = static_cast<IDBTransactionBackendProxy*>(transaction); >+ m_webIDBObjectStore->openCursor(range, static_cast<WebIDBCursor::Direction>(direction), new WebIDBCallbacksImpl(callbacks), static_cast<WebIDBTransaction::TaskType>(taskType), *transactionProxy->getWebIDBTransaction(), ec); > } > > void IDBObjectStoreBackendProxy::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) >diff --git a/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.h b/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.h >index 0235077fa973fe8f16192e4136fa200997e2a63a..fb0f2af377e57a1ad078f565831a592db5c2a305 100644 >--- a/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.h >+++ b/Source/WebKit/chromium/src/IDBObjectStoreBackendProxy.h >@@ -49,10 +49,15 @@ public: > virtual void clear(PassRefPtr<WebCore::IDBCallbacks>, WebCore::IDBTransactionBackendInterface*, WebCore::ExceptionCode&); > > PassRefPtr<WebCore::IDBIndexBackendInterface> createIndex(const String& name, const WebCore::IDBKeyPath&, bool unique, bool multiEntry, WebCore::IDBTransactionBackendInterface*, WebCore::ExceptionCode&); >+ virtual void setIndexKeys(PassRefPtr<WebCore::IDBKey> prpPrimaryKey, const WTF::Vector<WTF::String>&, const WTF::Vector<IndexKeys>&, WebCore::IDBTransactionBackendInterface*); >+ virtual void setIndexesReady(const Vector<String>&, WebCore::IDBTransactionBackendInterface*); >+ > PassRefPtr<WebCore::IDBIndexBackendInterface> index(const String& name, WebCore::ExceptionCode&); > void deleteIndex(const String& name, WebCore::IDBTransactionBackendInterface*, WebCore::ExceptionCode&); > >+ // FIXME: Remove this version of openCursor when TaskType is plumbed through chromium. > virtual void openCursor(PassRefPtr<WebCore::IDBKeyRange>, unsigned short direction, PassRefPtr<WebCore::IDBCallbacks>, WebCore::IDBTransactionBackendInterface*, WebCore::ExceptionCode&); >+ virtual void openCursor(PassRefPtr<WebCore::IDBKeyRange>, WebCore::IDBCursor::Direction, PassRefPtr<WebCore::IDBCallbacks>, WebCore::IDBTransactionBackendInterface::TaskType, WebCore::IDBTransactionBackendInterface*, WebCore::ExceptionCode&); > virtual void count(PassRefPtr<WebCore::IDBKeyRange>, PassRefPtr<WebCore::IDBCallbacks>, WebCore::IDBTransactionBackendInterface*, WebCore::ExceptionCode&); > > private: >diff --git a/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.cpp b/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.cpp >index c327eba84c6ca7d2e8cb848c47347df9ef06bb61..f8bc4adc280afe7ba76896057fcff86c50f1057a 100755 >--- a/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.cpp >+++ b/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.cpp >@@ -75,6 +75,30 @@ void WebIDBObjectStoreImpl::putWithIndexKeys(const WebSerializedScriptValue& val > m_objectStore->putWithIndexKeys(value, key, static_cast<IDBObjectStoreBackendInterface::PutMode>(putMode), IDBCallbacksProxy::create(adoptPtr(callbacks)), transaction.getIDBTransactionBackendInterface(), indexNames, indexKeys, ec); > } > >+void WebIDBObjectStoreImpl::setIndexKeys(const WebIDBKey& primaryKey, const WebVector<WebString>& webIndexNames, const WebVector<WebIndexKeys>& webIndexKeys, const WebIDBTransaction& transaction) >+{ >+ ASSERT(webIndexNames.size() == webIndexKeys.size()); >+ Vector<String> indexNames(webIndexNames.size()); >+ Vector<IDBObjectStoreBackendInterface::IndexKeys> indexKeys(webIndexKeys.size()); >+ >+ for (size_t i = 0; i < webIndexNames.size(); ++i) { >+ indexNames[i] = webIndexNames[i]; >+ Vector<RefPtr<IDBKey> > indexKeyList(webIndexKeys[i].size()); >+ for (size_t j = 0; j < webIndexKeys[i].size(); ++j) >+ indexKeyList[j] = webIndexKeys[i][j]; >+ indexKeys[i] = indexKeyList; >+ } >+ m_objectStore->setIndexKeys(primaryKey, indexNames, indexKeys, transaction.getIDBTransactionBackendInterface()); >+} >+ >+void WebIDBObjectStoreImpl::setIndexesReady(const WebVector<WebString>& webIndexNames, const WebIDBTransaction& transaction) >+{ >+ Vector<String> indexNames(webIndexNames.size()); >+ for (size_t i = 0; i < webIndexNames.size(); i++) >+ indexNames[i] = webIndexNames[i]; >+ m_objectStore->setIndexesReady(indexNames, transaction.getIDBTransactionBackendInterface()); >+} >+ > void WebIDBObjectStoreImpl::deleteFunction(const WebIDBKeyRange& keyRange, WebIDBCallbacks* callbacks, const WebIDBTransaction& transaction, WebExceptionCode& ec) > { > m_objectStore->deleteFunction(keyRange, IDBCallbacksProxy::create(adoptPtr(callbacks)), transaction.getIDBTransactionBackendInterface(), ec); >@@ -106,10 +130,9 @@ void WebIDBObjectStoreImpl::deleteIndex(const WebString& name, const WebIDBTrans > m_objectStore->deleteIndex(name, transaction.getIDBTransactionBackendInterface(), ec); > } > >-void WebIDBObjectStoreImpl::openCursor(const WebIDBKeyRange& keyRange, WebIDBCursor::Direction direction, WebIDBCallbacks* callbacks, WebIDBTransaction::TaskType, const WebIDBTransaction& transaction, WebExceptionCode& ec) >+void WebIDBObjectStoreImpl::openCursor(const WebIDBKeyRange& keyRange, WebIDBCursor::Direction direction, WebIDBCallbacks* callbacks, WebIDBTransaction::TaskType taskType, const WebIDBTransaction& transaction, WebExceptionCode& ec) > { >- // FIXME: Pass along TaskType when the API becomes available. >- m_objectStore->openCursor(keyRange, direction, IDBCallbacksProxy::create(adoptPtr(callbacks)), transaction.getIDBTransactionBackendInterface(), ec); >+ m_objectStore->openCursor(keyRange, static_cast<IDBCursor::Direction>(direction), IDBCallbacksProxy::create(adoptPtr(callbacks)), static_cast<IDBTransactionBackendInterface::TaskType>(taskType), transaction.getIDBTransactionBackendInterface(), ec); > } > > void WebIDBObjectStoreImpl::count(const WebIDBKeyRange& keyRange, WebIDBCallbacks* callbacks, const WebIDBTransaction& transaction, WebExceptionCode& ec) >diff --git a/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.h b/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.h >index 482b22380e5896f7fedfa18ca4de8609d3dfe5fb..95879b5d0ed1c4478637020227be6f43bdf16365 100644 >--- a/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.h >+++ b/Source/WebKit/chromium/src/WebIDBObjectStoreImpl.h >@@ -46,7 +46,9 @@ public: > ~WebIDBObjectStoreImpl(); > > void get(const WebIDBKeyRange&, WebIDBCallbacks*, const WebIDBTransaction&, WebExceptionCode&); >- void putWithIndexKeys(const WebSerializedScriptValue&, const WebIDBKey&, PutMode, WebIDBCallbacks*, const WebIDBTransaction&, const WebVector<WebString>& indexNames, const WebVector<WebIndexKeys>&, WebExceptionCode&); >+ void putWithIndexKeys(const WebSerializedScriptValue&, const WebIDBKey&, PutMode, WebIDBCallbacks*, const WebIDBTransaction&, const WebVector<WebString>&, const WebVector<WebIndexKeys>&, WebExceptionCode&); >+ void setIndexKeys(const WebIDBKey&, const WebVector<WebString>& indexNames, const WebVector<WebIndexKeys>&, const WebIDBTransaction&); >+ void setIndexesReady(const WebVector<WebString>&, const WebIDBTransaction&); > void deleteFunction(const WebIDBKeyRange&, WebIDBCallbacks*, const WebIDBTransaction&, WebExceptionCode&); > void clear(WebIDBCallbacks*, const WebIDBTransaction&, WebExceptionCode&); > >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 836b3f8784bd615c38bf4571337cc831fcc9c4ef..e9dc27dd250c8afa2810f00caafb5f563532f8cf 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,16 @@ >+2012-08-10 Alec Flett <alecflett@chromium.org> >+ >+ IndexedDB: generate index keys for existing data in createIndex in front end >+ https://bugs.webkit.org/show_bug.cgi?id=91125 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The transaction should be aborted when existing data in an >+ objectStore causes uniqueness errors during index creation. >+ >+ * storage/indexeddb/lazy-index-population-expected.txt: Added. >+ * storage/indexeddb/lazy-index-population.html: Added. >+ > 2012-08-13 Christophe Dumez <christophe.dumez@intel.com> > > [EFL][WK2] Skip inspector tests that hit assertion in WebCore::SuspendableTimer::resume() >diff --git a/LayoutTests/storage/indexeddb/lazy-index-population-expected.txt b/LayoutTests/storage/indexeddb/lazy-index-population-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..c299504bbbe048050c4c4dcc3ab7b8c735b8a666 >--- /dev/null >+++ b/LayoutTests/storage/indexeddb/lazy-index-population-expected.txt >@@ -0,0 +1,78 @@ >+Verify edge cases that lazy index population in an IndexedDB implementation might reveal. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+ >+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB; >+ >+indexedDB.open('lazy-index-population') >+connection = request.result >+ >+Verify that uniqueness constraints are enforced with a pre-existing index: >+connection.setVersion('1') >+Deleted all object stores. >+store = connection.createObjectStore('store') >+store.createIndex('index1', 'name', {unique: true}) >+trans = connection.transaction('store', 'readwrite') >+store = trans.objectStore('store') >+request1 = store.put({name: 'bob'}, 1) >+request2 = store.put({name: 'bob'}, 2) >+state = 0 >+request1 received success event >+PASS ++state is 1 >+request2 received error event >+PASS ++state is 2 >+transaction aborted >+PASS ++state is 3 >+ >+Verify that uniqueness constraints are enforced when index is created before puts: >+connection.setVersion('2') >+deleteAllObjectStores(connection) >+Deleted all object stores. >+store = connection.createObjectStore('store') >+store.createIndex('index2', 'name', {unique: true}) >+request1 = store.put({name: 'carol'}, 1) >+request2 = store.put({name: 'carol'}, 2) >+state = 0 >+request1 (index2) received success event >+PASS ++state is 1 >+request2 (index2) received error event >+PASS ++state is 2 >+transaction aborted >+PASS ++state is 3 >+ >+Verify that uniqueness constraints are enforced when index is created after puts: >+connection.setVersion('3') >+deleteAllObjectStores(connection) >+Deleted all object stores. >+store = connection.createObjectStore('store') >+request1 = store.put({name: 'ted'}, 1) >+request2 = store.put({name: 'ted'}, 2) >+store.createIndex('index3', 'name', {unique: true}) >+state = 0 >+request1 received success event >+PASS ++state is 1 >+request2 received success event >+PASS ++state is 2 >+transaction aborted >+PASS ++state is 3 >+ >+Verify that uniqueness constraints are enforced when index is created between puts: >+connection.setVersion('4') >+deleteAllObjectStores(connection) >+Deleted all object stores. >+store = connection.createObjectStore('store') >+request1 = store.put({name: 'alice'}, 1) >+store.createIndex('index4', 'name', {unique: true}) >+request2 = store.put({name: 'alice'}, 2) >+state = 0 >+request1 received success event >+PASS ++state is 1 >+request2 received error event >+PASS ++state is 2 >+transaction aborted >+PASS ++state is 3 >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/storage/indexeddb/lazy-index-population.html b/LayoutTests/storage/indexeddb/lazy-index-population.html >new file mode 100644 >index 0000000000000000000000000000000000000000..d860cd887d2674dc938327c16dfd9b674f84c955 >--- /dev/null >+++ b/LayoutTests/storage/indexeddb/lazy-index-population.html >@@ -0,0 +1,187 @@ >+<!DOCTYPE html> >+<script src="../../fast/js/resources/js-test-pre.js"></script> >+<script src="resources/shared.js"></script> >+<script> >+setTimeout(finishJSTest, 4000); >+description("Verify edge cases that lazy index population in an IndexedDB implementation might reveal."); >+ >+function test() >+{ >+ removeVendorPrefixes(); >+ prepareDatabase(); >+} >+ >+function prepareDatabase() >+{ >+ request = evalAndLog("indexedDB.open('lazy-index-population')"); >+ request.onerror = unexpectedErrorCallback; >+ request.onsuccess = function(e) { >+ evalAndLog("connection = request.result"); >+ verifyPreExistingIndex(); >+ }; >+} >+ >+function verifyPreExistingIndex() >+{ >+ debug(""); >+ debug("Verify that uniqueness constraints are enforced with a pre-existing index:"); >+ >+ request = evalAndLog("connection.setVersion('1')"); >+ request.onerror = unexpectedErrorCallback; >+ request.onsuccess = function() { >+ trans = request.result; >+ trans.onabort = unexpectedAbortCallback; >+ deleteAllObjectStores(connection); >+ evalAndLog("store = connection.createObjectStore('store')"); >+ evalAndLog("store.createIndex('index1', 'name', {unique: true})"); >+ >+ trans.oncomplete = function() { >+ evalAndLog("trans = connection.transaction('store', 'readwrite')"); >+ evalAndLog("store = trans.objectStore('store')"); >+ evalAndLog("request1 = store.put({name: 'bob'}, 1)"); >+ evalAndLog("request2 = store.put({name: 'bob'}, 2)"); >+ evalAndLog("state = 0"); >+ >+ request1.onerror = unexpectedErrorCallback; >+ request1.onsuccess = function () { >+ debug("request1 received success event"); >+ shouldBe("++state", "1"); >+ }; >+ >+ request2.onsuccess = unexpectedSuccessCallback; >+ request2.onerror = function () { >+ debug("request2 received error event"); >+ shouldBe("++state", "2"); >+ }; >+ >+ trans.oncomplete = unexpectedCompleteCallback; >+ trans.onabort = function () { >+ debug("transaction aborted"); >+ shouldBe("++state", "3"); >+ verifyCreateThenPut(); >+ }; >+ }; >+ }; >+} >+ >+function verifyCreateThenPut() >+{ >+ debug(""); >+ debug("Verify that uniqueness constraints are enforced when index is created before puts:"); >+ >+ request = evalAndLog("connection.setVersion('2')"); >+ request.onerror = unexpectedErrorCallback; >+ request.onsuccess = function() { >+ trans = request.result; >+ >+ evalAndLog("deleteAllObjectStores(connection)"); >+ >+ evalAndLog("store = connection.createObjectStore('store')"); >+ evalAndLog("store.createIndex('index2', 'name', {unique: true})"); >+ evalAndLog("request1 = store.put({name: 'carol'}, 1)"); >+ evalAndLog("request2 = store.put({name: 'carol'}, 2)"); >+ evalAndLog("state = 0"); >+ >+ request1.onerror = unexpectedErrorCallback; >+ request1.onsuccess = function () { >+ debug("request1 (index2) received success event"); >+ shouldBe("++state", "1"); >+ }; >+ >+ request2.onsuccess = unexpectedSuccessCallback; >+ request2.onerror = function () { >+ debug("request2 (index2) received error event"); >+ shouldBe("++state", "2"); >+ }; >+ >+ trans.oncomplete = unexpectedCompleteCallback; >+ trans.onabort = function () { >+ debug("transaction aborted"); >+ shouldBe("++state", "3"); >+ verifyPutThenCreate(); >+ }; >+ }; >+} >+ >+function verifyPutThenCreate() >+{ >+ debug(""); >+ debug("Verify that uniqueness constraints are enforced when index is created after puts:"); >+ >+ request = evalAndLog("connection.setVersion('3')"); >+ request.onerror = unexpectedErrorCallback; >+ request.onsuccess = function() { >+ trans = request.result; >+ >+ evalAndLog("deleteAllObjectStores(connection)"); >+ >+ evalAndLog("store = connection.createObjectStore('store')"); >+ evalAndLog("request1 = store.put({name: 'ted'}, 1)"); >+ evalAndLog("request2 = store.put({name: 'ted'}, 2)"); >+ evalAndLog("store.createIndex('index3', 'name', {unique: true})"); >+ evalAndLog("state = 0"); >+ >+ request1.onerror = unexpectedErrorCallback; >+ request1.onsuccess = function () { >+ debug("request1 received success event"); >+ shouldBe("++state", "1"); >+ }; >+ >+ request2.onerror = unexpectedErrorCallback; >+ request2.onsuccess = function () { >+ debug("request2 received success event"); >+ shouldBe("++state", "2"); >+ }; >+ >+ trans.oncomplete = unexpectedCompleteCallback; >+ trans.onabort = function () { >+ debug("transaction aborted"); >+ shouldBe("++state", "3"); >+ verifyPutThenCreateThenPut(); >+ }; >+ }; >+} >+ >+function verifyPutThenCreateThenPut() >+{ >+ debug(""); >+ debug("Verify that uniqueness constraints are enforced when index is created between puts:"); >+ >+ request = evalAndLog("connection.setVersion('4')"); >+ request.onerror = unexpectedErrorCallback; >+ request.onsuccess = function() { >+ trans = request.result; >+ >+ evalAndLog("deleteAllObjectStores(connection)"); >+ >+ evalAndLog("store = connection.createObjectStore('store')"); >+ evalAndLog("request1 = store.put({name: 'alice'}, 1)"); >+ evalAndLog("store.createIndex('index4', 'name', {unique: true})"); >+ evalAndLog("request2 = store.put({name: 'alice'}, 2)"); >+ evalAndLog("state = 0"); >+ >+ request1.onerror = unexpectedErrorCallback; >+ request1.onsuccess = function () { >+ debug("request1 received success event"); >+ shouldBe("++state", "1"); >+ }; >+ >+ request2.onsuccess = unexpectedSuccessCallback; >+ request2.onerror = function () { >+ debug("request2 received error event"); >+ shouldBe("++state", "2"); >+ }; >+ >+ trans.oncomplete = unexpectedCompleteCallback; >+ trans.onabort = function () { >+ debug("transaction aborted"); >+ shouldBe("++state", "3"); >+ finishJSTest(); >+ }; >+ }; >+} >+ >+test(); >+ >+</script> >+<script src="../../fast/js/resources/js-test-post.js"></script>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 91125
:
157800
|
158200
|
158209
|
158377
|
158588
|
158596
|
158618
|
158646
|
158648
|
158658