diff --git a/dom/indexedDB/IDBObjectStoreRequest.cpp b/dom/indexedDB/IDBObjectStoreRequest.cpp index e1b57af4885..7197b9f008f 100644 --- a/dom/indexedDB/IDBObjectStoreRequest.cpp +++ b/dom/indexedDB/IDBObjectStoreRequest.cpp @@ -384,6 +384,8 @@ IDBObjectStoreRequest::GetName(nsAString& aName) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + aName.Assign(mName); return NS_OK; } @@ -393,6 +395,8 @@ IDBObjectStoreRequest::GetKeyPath(nsAString& aKeyPath) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + aKeyPath.Assign(mKeyPath); return NS_OK; } @@ -402,6 +406,8 @@ IDBObjectStoreRequest::GetIndexNames(nsIDOMDOMStringList** aIndexNames) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + nsRefPtr list(new nsDOMStringList()); #if 0 PRUint32 count = mIndexes.Length(); @@ -419,6 +425,8 @@ IDBObjectStoreRequest::Get(nsIVariant* aKey, { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + Key key; nsresult rv = GetKeyFromVariant(aKey, key); NS_ENSURE_SUCCESS(rv, rv); @@ -446,6 +454,9 @@ IDBObjectStoreRequest::GetAll(nsIIDBKeyRange* aKeyRange, nsIIDBRequest** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + NS_NOTYETIMPLEMENTED("Implement me!"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -457,6 +468,8 @@ IDBObjectStoreRequest::Add(nsIVariant* /* aValue */, { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + if (mMode != nsIIDBTransaction::READ_WRITE) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } @@ -493,6 +506,8 @@ IDBObjectStoreRequest::Modify(nsIVariant* /* aValue */, { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + if (mMode != nsIIDBTransaction::READ_WRITE) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } @@ -529,6 +544,8 @@ IDBObjectStoreRequest::AddOrModify(nsIVariant* /* aValue */, { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + if (mMode != nsIIDBTransaction::READ_WRITE) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } @@ -564,6 +581,8 @@ IDBObjectStoreRequest::Remove(nsIVariant* aKey, { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + if (mMode != nsIIDBTransaction::READ_WRITE) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } @@ -598,6 +617,10 @@ IDBObjectStoreRequest::OpenCursor(nsIIDBKeyRange* aRange, nsIIDBRequest** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + + NS_NOTYETIMPLEMENTED("Implement me!"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -608,6 +631,9 @@ IDBObjectStoreRequest::CreateIndex(const nsAString& aName, nsIIDBRequest** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + NS_NOTYETIMPLEMENTED("Implement me!"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -617,6 +643,9 @@ IDBObjectStoreRequest::Index(const nsAString& aName, nsIIDBIndexRequest** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + NS_NOTYETIMPLEMENTED("Implement me!"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -626,6 +655,9 @@ IDBObjectStoreRequest::RemoveIndex(const nsAString& aName, nsIIDBRequest** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(mTransaction->TransactionIsOpen()); + NS_NOTYETIMPLEMENTED("Implement me!"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -638,14 +670,19 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) nsresult rv; bool mayOverwrite = mOverwrite; + bool unsetKey = mKey.IsUnset(); - if (mKey.IsUnset()) { + if (unsetKey) { NS_ASSERTION(mAutoIncrement, "Must have a key for non-autoIncrement!"); // Will need to add first and then set the key later. mayOverwrite = false; } + if (mAutoIncrement && !unsetKey) { + mayOverwrite = true; + } + nsCOMPtr stmt = mTransaction->AddStatement(mCreate, mayOverwrite, mAutoIncrement); NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR); @@ -678,8 +715,6 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) } if (mAutoIncrement && mCreate && !mOverwrite) { - bool unsetKey = mKey.IsUnset(); - #ifdef DEBUG PRInt64 oldKey = unsetKey ? 0 : mKey.IntValue(); #endif diff --git a/dom/indexedDB/IDBTransactionRequest.cpp b/dom/indexedDB/IDBTransactionRequest.cpp index 8ae492a3382..54863ac4871 100644 --- a/dom/indexedDB/IDBTransactionRequest.cpp +++ b/dom/indexedDB/IDBTransactionRequest.cpp @@ -441,6 +441,9 @@ NS_IMETHODIMP IDBTransactionRequest::GetDb(nsIIDBDatabase** aDB) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + NS_ADDREF(*aDB = mDatabase); return NS_OK; } @@ -449,6 +452,9 @@ NS_IMETHODIMP IDBTransactionRequest::GetReadyState(PRUint16* aReadyState) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + *aReadyState = mReadyState; return NS_OK; } @@ -457,6 +463,9 @@ NS_IMETHODIMP IDBTransactionRequest::GetMode(PRUint16* aMode) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + *aMode = mMode; return NS_OK; } @@ -466,6 +475,8 @@ IDBTransactionRequest::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(TransactionIsOpen()); + nsRefPtr list(new nsDOMStringList()); PRUint32 count = mObjectStoreNames.Length(); for (PRUint32 index = 0; index < count; index++) { @@ -481,6 +492,8 @@ IDBTransactionRequest::ObjectStore(const nsAString& aName, { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ENSURE_STATE(TransactionIsOpen()); + ObjectStoreInfo* info = nsnull; PRUint32 count = mObjectStoreNames.Length(); @@ -512,6 +525,8 @@ IDBTransactionRequest::Abort() NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_WARNING("Abort doesn't actually do anything yet! Fix me now!"); + NS_ENSURE_STATE(TransactionIsOpen()); + nsCOMPtr runnable = IDBEvent::CreateGenericEventRunnable(NS_LITERAL_STRING(ABORT_EVT_STR), this); @@ -527,6 +542,9 @@ NS_IMETHODIMP IDBTransactionRequest::GetOncomplete(nsIDOMEventListener** aOncomplete) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + return GetInnerEventListener(mOnCompleteListener, aOncomplete); } @@ -534,6 +552,9 @@ NS_IMETHODIMP IDBTransactionRequest::SetOncomplete(nsIDOMEventListener* aOncomplete) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + return RemoveAddEventListener(NS_LITERAL_STRING(COMPLETE_EVT_STR), mOnCompleteListener, aOncomplete); } @@ -542,6 +563,9 @@ NS_IMETHODIMP IDBTransactionRequest::GetOnabort(nsIDOMEventListener** aOnabort) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + return GetInnerEventListener(mOnAbortListener, aOnabort); } @@ -549,6 +573,9 @@ NS_IMETHODIMP IDBTransactionRequest::SetOnabort(nsIDOMEventListener* aOnabort) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + return RemoveAddEventListener(NS_LITERAL_STRING(ABORT_EVT_STR), mOnAbortListener, aOnabort); } @@ -557,6 +584,9 @@ NS_IMETHODIMP IDBTransactionRequest::GetOntimeout(nsIDOMEventListener** aOntimeout) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + return GetInnerEventListener(mOnTimeoutListener, aOntimeout); } @@ -564,6 +594,9 @@ NS_IMETHODIMP IDBTransactionRequest::SetOntimeout(nsIDOMEventListener* aOntimeout) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + NS_ENSURE_STATE(TransactionIsOpen()); + return RemoveAddEventListener(NS_LITERAL_STRING(TIMEOUT_EVT_STR), mOnTimeoutListener, aOntimeout); } diff --git a/dom/indexedDB/IDBTransactionRequest.h b/dom/indexedDB/IDBTransactionRequest.h index 5d98a057e43..ac26397270c 100644 --- a/dom/indexedDB/IDBTransactionRequest.h +++ b/dom/indexedDB/IDBTransactionRequest.h @@ -103,6 +103,11 @@ public: void CloseConnection(); + bool TransactionIsOpen() { + return mReadyState == nsIIDBTransaction::INITIAL || + mReadyState == nsIIDBTransaction::LOADING; + } + private: IDBTransactionRequest(); ~IDBTransactionRequest(); diff --git a/dom/indexedDB/IndexedDatabaseRequest.cpp b/dom/indexedDB/IndexedDatabaseRequest.cpp index f2858152c37..9f205f78f02 100644 --- a/dom/indexedDB/IndexedDatabaseRequest.cpp +++ b/dom/indexedDB/IndexedDatabaseRequest.cpp @@ -151,9 +151,10 @@ CreateTables(mozIStorageConnection* aDBConn) // Table `ai_object_data` rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TABLE ai_object_data (" - "id INTEGER PRIMARY KEY, " + "id INTEGER, " "object_store_id INTEGER NOT NULL, " "data TEXT NOT NULL, " + "PRIMARY KEY (id), " "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " "CASCADE" ");" diff --git a/dom/indexedDB/TransactionThreadPool.cpp b/dom/indexedDB/TransactionThreadPool.cpp index ed333440713..1b8d58c99b3 100644 --- a/dom/indexedDB/TransactionThreadPool.cpp +++ b/dom/indexedDB/TransactionThreadPool.cpp @@ -67,10 +67,11 @@ bool gShutdown = false; struct TransactionObjectStoreInfo { - TransactionObjectStoreInfo() : writing(false) { } + TransactionObjectStoreInfo() : writing(false), writerWaiting(false) { } nsString objectStoreName; bool writing; + bool writerWaiting; }; } // anonymous namespace @@ -311,7 +312,7 @@ TransactionThreadPool::TransactionCanRun(IDBTransactionRequest* aTransaction, for (PRUint32 transactionIndex = 0; transactionIndex < transactionCount; transactionIndex++) { - const TransactionInfo& transactionInfo = + TransactionInfo& transactionInfo = transactionsInProgress->ElementAt(transactionIndex); if (transactionInfo.transaction == aTransaction) { @@ -321,14 +322,14 @@ TransactionThreadPool::TransactionCanRun(IDBTransactionRequest* aTransaction, } // Not our transaction, see if the objectStores overlap. - const nsTArray& objectStoreInfoArray = + nsTArray& objectStoreInfoArray = transactionInfo.objectStoreInfo; PRUint32 objectStoreCount = objectStoreInfoArray.Length(); for (PRUint32 objectStoreIndex = 0; objectStoreIndex < objectStoreCount; objectStoreIndex++) { - const TransactionObjectStoreInfo& objectStoreInfo = + TransactionObjectStoreInfo& objectStoreInfo = objectStoreInfoArray[objectStoreIndex]; if (objectStoreNames.Contains(objectStoreInfo.objectStoreName)) { @@ -336,12 +337,13 @@ TransactionThreadPool::TransactionCanRun(IDBTransactionRequest* aTransaction, switch (mode) { case nsIIDBTransaction::READ_WRITE: { // Someone else is reading or writing to this table, we can't - // run now. + // run now. Mark that we're waiting for it though. + objectStoreInfo.writerWaiting = true; return false; } case nsIIDBTransaction::READ_ONLY: { - if (objectStoreInfo.writing) { + if (objectStoreInfo.writing || objectStoreInfo.writerWaiting) { // Someone else is writing to this table, we can't run now. return false; } diff --git a/dom/indexedDB/test/Makefile.in b/dom/indexedDB/test/Makefile.in index 02aa0e6c142..cbce718deb1 100644 --- a/dom/indexedDB/test/Makefile.in +++ b/dom/indexedDB/test/Makefile.in @@ -62,6 +62,7 @@ _TEST_FILES = \ test_readonly_transactions.html \ test_remove_objectStore.html \ test_setVersion.html \ + test_writer_starvation.html \ $(NULL) libs:: $(_TEST_FILES) diff --git a/dom/indexedDB/test/test_key_requirements.html b/dom/indexedDB/test/test_key_requirements.html index 3819a830d1f..0d36bde9be9 100644 --- a/dom/indexedDB/test/test_key_requirements.html +++ b/dom/indexedDB/test/test_key_requirements.html @@ -53,6 +53,15 @@ is(event.result, key2, "modify gave the same key back"); + key2 = 100; + + request = objectStore.add({}, key2); + request.onerror = errorHandler; + request.onsuccess = grabEventAndContinueHandler; + event = yield; + + is(event.result, key2, "modify gave the same key back"); + try { objectStore.addOrModify({}); ok(false, "addOrModify with no key should throw!"); diff --git a/dom/indexedDB/test/test_writer_starvation.html b/dom/indexedDB/test/test_writer_starvation.html new file mode 100644 index 00000000000..12f7c04ee6a --- /dev/null +++ b/dom/indexedDB/test/test_writer_starvation.html @@ -0,0 +1,106 @@ + + + + Indexed Database Property Test + + + + + + + + + + + + +