зеркало из https://github.com/mozilla/pjs.git
Bug 692911: Refactor some VERSION_CHANGE transaction locking stuff and disallow transaction creation before databases are completely open. r=bent
This commit is contained in:
Родитель
308444aebe
Коммит
5e7a740f36
|
@ -560,8 +560,8 @@ TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable,
|
|||
NS_ASSERTION(aRunnable, "Null pointer!");
|
||||
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!");
|
||||
|
||||
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
|
||||
NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE);
|
||||
TransactionThreadPool* pool = TransactionThreadPool::Get();
|
||||
NS_ASSERTION(pool, "This should never be null!");
|
||||
|
||||
return pool->Dispatch(mTransaction, aRunnable, false, nsnull);
|
||||
}
|
||||
|
|
|
@ -125,6 +125,11 @@ public:
|
|||
|
||||
static IDBTransaction* GetCurrentTransaction();
|
||||
|
||||
bool HasTransaction()
|
||||
{
|
||||
return mTransaction;
|
||||
}
|
||||
|
||||
nsISupports* GetSource()
|
||||
{
|
||||
return mRequest ? mRequest->Source() : nsnull;
|
||||
|
|
|
@ -85,7 +85,8 @@ EnumerateObjectStoreNames(const nsAString& aKey,
|
|||
DatabaseInfo::DatabaseInfo()
|
||||
: id(0),
|
||||
nextObjectStoreId(1),
|
||||
nextIndexId(1)
|
||||
nextIndexId(1),
|
||||
runningVersionChange(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(DatabaseInfo);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ struct DatabaseInfo
|
|||
~DatabaseInfo();
|
||||
#else
|
||||
DatabaseInfo()
|
||||
: id(0), nextObjectStoreId(1), nextIndexId(1) { }
|
||||
: id(0), nextObjectStoreId(1), nextIndexId(1), runningVersionChange(false)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
static bool Get(PRUint32 aId,
|
||||
|
@ -73,6 +74,7 @@ struct DatabaseInfo
|
|||
nsString filePath;
|
||||
PRInt64 nextObjectStoreId;
|
||||
PRInt64 nextIndexId;
|
||||
bool runningVersionChange;
|
||||
|
||||
nsAutoRefCnt referenceCount;
|
||||
};
|
||||
|
|
|
@ -428,6 +428,34 @@ IDBDatabase::IsClosed()
|
|||
return mClosed;
|
||||
}
|
||||
|
||||
void
|
||||
IDBDatabase::EnterSetVersionTransaction()
|
||||
{
|
||||
DatabaseInfo* dbInfo;
|
||||
if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
|
||||
NS_ERROR("This should never fail!");
|
||||
}
|
||||
|
||||
NS_ASSERTION(!dbInfo->runningVersionChange, "How did that happen?");
|
||||
dbInfo->runningVersionChange = true;
|
||||
}
|
||||
|
||||
void
|
||||
IDBDatabase::ExitSetVersionTransaction()
|
||||
{
|
||||
DatabaseInfo* dbInfo;
|
||||
if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
|
||||
NS_ERROR("This should never fail!");
|
||||
}
|
||||
|
||||
NS_ASSERTION(dbInfo->runningVersionChange, "How did that happen?");
|
||||
dbInfo->runningVersionChange = false;
|
||||
|
||||
IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(manager, "We should always have a manager here");
|
||||
manager->UnblockSetVersionRunnable(this);
|
||||
}
|
||||
|
||||
void
|
||||
IDBDatabase::OnUnlink()
|
||||
{
|
||||
|
@ -710,6 +738,10 @@ IDBDatabase::Transaction(nsIVariant* aStoreNames,
|
|||
NS_ERROR("This should never fail!");
|
||||
}
|
||||
|
||||
if (info->runningVersionChange) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
nsTArray<nsString> storesToOpen;
|
||||
|
||||
switch (type) {
|
||||
|
|
|
@ -135,6 +135,9 @@ public:
|
|||
// Whether or not the database has had Close called on it.
|
||||
bool IsClosed();
|
||||
|
||||
void EnterSetVersionTransaction();
|
||||
void ExitSetVersionTransaction();
|
||||
|
||||
private:
|
||||
IDBDatabase();
|
||||
~IDBDatabase();
|
||||
|
|
|
@ -693,19 +693,15 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
|
|||
|
||||
// Now run the helper if there are no more live databases.
|
||||
if (runnable->mHelper && runnable->mDatabases.IsEmpty()) {
|
||||
// Don't hold the callback alive longer than necessary.
|
||||
nsRefPtr<AsyncConnectionHelper> helper;
|
||||
helper.swap(runnable->mHelper);
|
||||
// At this point, all databases are closed, so no new transactions can
|
||||
// be started. There may, however, still be outstanding transactions
|
||||
// that have not completed. We need to wait for those before we
|
||||
// dispatch the helper.
|
||||
|
||||
if (NS_FAILED(helper->DispatchToTransactionPool())) {
|
||||
NS_WARNING("Failed to dispatch to thread pool!");
|
||||
}
|
||||
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
|
||||
|
||||
// Now wait for the transaction to complete. Completing the transaction
|
||||
// will be our cue to remove the SetVersionRunnable from our list and
|
||||
// therefore allow other SetVersion requests to begin.
|
||||
TransactionThreadPool* pool = TransactionThreadPool::Get();
|
||||
NS_ASSERTION(pool, "This should never be null!");
|
||||
nsRefPtr<WaitForTransactionsToFinishRunnable> waitRunnable =
|
||||
new WaitForTransactionsToFinishRunnable(runnable);
|
||||
|
||||
// All other databases should be closed, so we only need to wait on this
|
||||
// one.
|
||||
|
@ -714,8 +710,8 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
|
|||
NS_ERROR("This should never fail!");
|
||||
}
|
||||
|
||||
// Use the SetVersionRunnable as the callback.
|
||||
if (!pool->WaitForAllDatabasesToComplete(array, runnable)) {
|
||||
// Use the WaitForTransactionsToFinishRunnable as the callback.
|
||||
if (!pool->WaitForAllDatabasesToComplete(array, waitRunnable)) {
|
||||
NS_WARNING("Failed to wait for transaction to complete!");
|
||||
}
|
||||
}
|
||||
|
@ -724,6 +720,27 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
IndexedDatabaseManager::UnblockSetVersionRunnable(IDBDatabase* aDatabase)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aDatabase, "Null pointer!");
|
||||
|
||||
// Check through the list of SetVersionRunnables to find the one we're seeking.
|
||||
for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
|
||||
nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];
|
||||
|
||||
if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) {
|
||||
NS_ASSERTION(!runnable->mHelper,
|
||||
"Why are we unblocking a runnable if the helper didn't run?");
|
||||
NS_DispatchToCurrentThread(runnable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NS_NOTREACHED("How did we get here!");
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IndexedDatabaseManager::SetCurrentDatabase(IDBDatabase* aDatabase)
|
||||
|
@ -1283,3 +1300,39 @@ IndexedDatabaseManager::SetVersionRunnable::Run()
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::WaitForTransactionsToFinishRunnable,
|
||||
nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
IndexedDatabaseManager::WaitForTransactionsToFinishRunnable::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
// Don't hold the callback alive longer than necessary.
|
||||
nsRefPtr<AsyncConnectionHelper> helper;
|
||||
helper.swap(mRunnable->mHelper);
|
||||
|
||||
nsRefPtr<SetVersionRunnable> runnable;
|
||||
runnable.swap(mRunnable);
|
||||
|
||||
// If the helper has a transaction, dispatch it to the transaction
|
||||
// threadpool.
|
||||
if (helper->HasTransaction()) {
|
||||
if (NS_FAILED(helper->DispatchToTransactionPool())) {
|
||||
NS_WARNING("Failed to dispatch to thread pool!");
|
||||
}
|
||||
}
|
||||
// Otherwise, dispatch it to the IO thread.
|
||||
else {
|
||||
IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(manager, "We should definitely have a manager here");
|
||||
|
||||
helper->Dispatch(manager->IOThread());
|
||||
}
|
||||
|
||||
// The helper is responsible for calling
|
||||
// IndexedDatabaseManager::UnblockSetVersionRunnable.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -204,6 +204,8 @@ private:
|
|||
// Called when AsyncUsageRunnable has finished its Run() method.
|
||||
inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable);
|
||||
|
||||
void UnblockSetVersionRunnable(IDBDatabase* aDatabase);
|
||||
|
||||
// Responsible for waiting until all databases have been closed before running
|
||||
// the version change transaction. Created when
|
||||
// IndexedDatabaseManager::SetDatabaseVersion is called. Runs only once on the
|
||||
|
@ -227,6 +229,26 @@ private:
|
|||
// Called when SetVersionRunnable has finished its Run() method.
|
||||
inline void OnSetVersionRunnableComplete(SetVersionRunnable* aRunnable);
|
||||
|
||||
|
||||
// A callback runnable used by the TransactionPool when it's safe to proceed
|
||||
// with a SetVersion/DeleteDatabase/etc.
|
||||
class WaitForTransactionsToFinishRunnable : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
WaitForTransactionsToFinishRunnable(SetVersionRunnable* aRunnable)
|
||||
: mRunnable(aRunnable)
|
||||
{
|
||||
NS_ASSERTION(mRunnable, "Why don't we have a runnable?");
|
||||
NS_ASSERTION(mRunnable->mDatabases.IsEmpty(), "We're here too early!");
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
nsRefPtr<SetVersionRunnable> mRunnable;
|
||||
};
|
||||
|
||||
// Maintains a list of live databases per origin.
|
||||
nsClassHashtable<nsCStringHashKey, nsTArray<IDBDatabase*> > mLiveDatabases;
|
||||
|
||||
|
|
|
@ -495,10 +495,13 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
|
||||
protected:
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult Init();
|
||||
|
||||
// SetVersionHelper never fires an error event at the request. It hands that
|
||||
// responsibility back to the OpenDatabaseHelper
|
||||
void OnError() { }
|
||||
|
@ -684,6 +687,7 @@ OpenDatabaseHelper::StartSetVersion()
|
|||
// The SetVersionHelper is responsible for dispatching us back to the
|
||||
// main thread again and changing the state to eSetVersionCompleted.
|
||||
mState = eSetVersionPending;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -711,6 +715,12 @@ OpenDatabaseHelper::Run()
|
|||
mState == eSetVersionCompleted, "Why are we here?");
|
||||
|
||||
if (mState == eSetVersionCompleted) {
|
||||
// Allow transaction creation/other version change transactions to proceed
|
||||
// before we fire events. Other version changes will be postd to the end
|
||||
// of the event loop, and will be behind whatever the page does in
|
||||
// its error/success event handlers.
|
||||
mDatabase->ExitSetVersionTransaction();
|
||||
|
||||
mState = eFiringEvents;
|
||||
} else {
|
||||
// Notify the request that we're done, but only if we didn't just finish
|
||||
|
@ -865,6 +875,15 @@ OpenDatabaseHelper::NotifySetVersionFinished()
|
|||
return NS_DispatchToCurrentThread(this);
|
||||
}
|
||||
|
||||
void
|
||||
OpenDatabaseHelper::BlockDatabase()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(mDatabase, "This is going bad fast.");
|
||||
|
||||
mDatabase->EnterSetVersionTransaction();
|
||||
}
|
||||
|
||||
void
|
||||
OpenDatabaseHelper::DispatchSuccessEvent()
|
||||
{
|
||||
|
@ -916,6 +935,15 @@ OpenDatabaseHelper::ReleaseMainThreadObjects()
|
|||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper);
|
||||
|
||||
nsresult
|
||||
SetVersionHelper::Init()
|
||||
{
|
||||
// Block transaction creation until we are done.
|
||||
mOpenHelper->BlockDatabase();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
{
|
||||
|
|
|
@ -82,6 +82,7 @@ public:
|
|||
}
|
||||
|
||||
nsresult NotifySetVersionFinished();
|
||||
void BlockDatabase();
|
||||
|
||||
protected:
|
||||
// Methods only called on the main thread
|
||||
|
|
|
@ -238,7 +238,6 @@ TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
|
|||
|
||||
#ifdef DEBUG
|
||||
if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
|
||||
NS_ASSERTION(dbTransactionInfo->locked, "Should be locked!");
|
||||
NS_ASSERTION(transactionCount == 1,
|
||||
"More transactions running than should be!");
|
||||
}
|
||||
|
@ -344,10 +343,6 @@ TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction,
|
|||
PRUint32 transactionCount = transactionsInProgress.Length();
|
||||
NS_ASSERTION(transactionCount, "Should never be 0!");
|
||||
|
||||
if (mode == IDBTransaction::VERSION_CHANGE) {
|
||||
dbTransactionInfo->lockPending = true;
|
||||
}
|
||||
|
||||
for (PRUint32 index = 0; index < transactionCount; index++) {
|
||||
// See if this transaction is in out list of current transactions.
|
||||
const TransactionInfo& info = transactionsInProgress[index];
|
||||
|
@ -358,11 +353,7 @@ TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction,
|
|||
}
|
||||
}
|
||||
|
||||
if (dbTransactionInfo->locked || dbTransactionInfo->lockPending) {
|
||||
*aCanRun = false;
|
||||
*aExistingQueue = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(mode != IDBTransaction::VERSION_CHANGE, "How did we get here?");
|
||||
|
||||
bool writeOverlap;
|
||||
nsresult rv =
|
||||
|
@ -448,11 +439,6 @@ TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
|
|||
dbTransactionInfo = autoDBTransactionInfo;
|
||||
}
|
||||
|
||||
if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
|
||||
NS_ASSERTION(!dbTransactionInfo->locked, "Already locked?!");
|
||||
dbTransactionInfo->locked = true;
|
||||
}
|
||||
|
||||
const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
|
||||
|
||||
nsTArray<nsString>& storesInUse =
|
||||
|
|
|
@ -123,12 +123,6 @@ protected:
|
|||
|
||||
struct DatabaseTransactionInfo
|
||||
{
|
||||
DatabaseTransactionInfo()
|
||||
: locked(false), lockPending(false)
|
||||
{ }
|
||||
|
||||
bool locked;
|
||||
bool lockPending;
|
||||
nsTArray<TransactionInfo> transactions;
|
||||
nsTArray<nsString> storesReading;
|
||||
nsTArray<nsString> storesWriting;
|
||||
|
|
|
@ -98,6 +98,7 @@ TEST_FILES = \
|
|||
test_setVersion.html \
|
||||
test_setVersion_abort.html \
|
||||
test_setVersion_events.html \
|
||||
test_setVersion_exclusion.html \
|
||||
test_writer_starvation.html \
|
||||
third_party_iframe1.html \
|
||||
third_party_iframe2.html \
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
db.onerror = errorEventCounter;
|
||||
db.addEventListener("error", errorEventCounter, true);
|
||||
|
||||
event.target.transaction.oncomplete = grabEventAndContinueHandler;
|
||||
event.target.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
db.createObjectStore("foo", { autoIncrement: true });
|
||||
yield;
|
||||
|
|
|
@ -12,7 +12,7 @@ function startDBWork() {
|
|||
}
|
||||
var store = db.createObjectStore("mystore");
|
||||
store.add({ hello: "world" }, 42);
|
||||
trans.oncomplete = madeMod;
|
||||
e.target.onsuccess = madeMod;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
|
||||
let key = event.target.result;
|
||||
ok(key, "Added entry");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
event = yield;
|
||||
|
||||
let objectStore = db.transaction("foo").objectStore("foo");
|
||||
let first = objectStore.index("first");
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
let db = request.result;
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
|
||||
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
|
||||
// Make object store, add data.
|
||||
let objectStore = db.createObjectStore("foo", { keyPath: "id" });
|
||||
|
@ -39,7 +39,7 @@
|
|||
let db2 = event.target.result;
|
||||
db2.onerror = errorHandler;
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
|
||||
// Create index.
|
||||
event.target.transaction.objectStore("foo").createIndex("foo", "num");
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
|
||||
let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
|
||||
objectStore.createIndex("name", "name", { unique: true });
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
|
||||
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
request = objectStore.getAll();
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
@ -46,6 +47,7 @@
|
|||
}
|
||||
}
|
||||
yield;
|
||||
yield;
|
||||
|
||||
request = db.transaction("foo").objectStore("foo").getAll();
|
||||
request.onerror = errorHandler;
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -78,7 +79,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
event = yield;
|
||||
yield;
|
||||
ok(true, "1");
|
||||
|
||||
// Now create the indexes.
|
||||
|
@ -88,7 +89,6 @@
|
|||
}
|
||||
|
||||
is(objectStore.indexNames.length, indexData.length, "Good index count");
|
||||
continueToNextStep();
|
||||
yield;
|
||||
|
||||
ok(true, "2");
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -87,7 +88,6 @@
|
|||
}
|
||||
|
||||
is(objectStore.indexNames.length, indexData.length, "Good index count");
|
||||
continueToNextStep();
|
||||
yield;
|
||||
|
||||
objectStore = db.transaction(objectStoreName)
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
|
||||
for (let objectStoreIndex in objectStoreData) {
|
||||
const objectStoreInfo = objectStoreData[objectStoreIndex];
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -97,7 +98,6 @@
|
|||
indexData[i].options);
|
||||
}
|
||||
is(objectStore.indexNames.length, indexData.length, "Good index count");
|
||||
continueToNextStep();
|
||||
yield;
|
||||
|
||||
objectStore = db.transaction(objectStoreName)
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -87,6 +88,7 @@
|
|||
}
|
||||
}
|
||||
yield;
|
||||
yield;
|
||||
|
||||
objectStore = db.transaction(objectStoreName)
|
||||
.objectStore(objectStoreName);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
let index2 = objectStore2.index("bar");
|
||||
ok(index1 === index2, "Got same indexes");
|
||||
|
||||
transaction.oncomplete = continueToNextStep;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield;
|
||||
|
||||
transaction = db.transaction("foo");
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
autoIncrement: true });
|
||||
let index = objectStore.createIndex("foo", "index");
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
yield;
|
||||
|
||||
objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -31,7 +32,6 @@
|
|||
is(db.objectStoreNames.length, 1, "Bad objectStores list");
|
||||
is(db.objectStoreNames.item(0), objectStoreName, "Bad name");
|
||||
|
||||
continueToNextStep();
|
||||
yield;
|
||||
|
||||
objectStore = db.transaction(objectStoreName).objectStore(objectStoreName);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
let db = event.target.result;
|
||||
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
|
||||
|
||||
event.target.transaction.oncomplete = grabEventAndContinueHandler;
|
||||
event.target.onsuccess = grabEventAndContinueHandler;
|
||||
for (let i in objectStores) {
|
||||
db.createObjectStore(objectStores[i], { autoIncrement: true });
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -29,6 +30,8 @@
|
|||
|
||||
db.createObjectStore(osName, { autoIncrement: "true" });
|
||||
|
||||
yield;
|
||||
|
||||
let key1, key2;
|
||||
|
||||
request = db.transaction([osName], READ_WRITE)
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const name = window.location.pathname;
|
||||
|
||||
let request = mozIndexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
|
||||
let request2 = mozIndexedDB.open(name, 2);
|
||||
request2.onerror = errorHandler;
|
||||
request2.onupgradeneeded = unexpectedSuccessHandler;
|
||||
|
||||
let event = yield;
|
||||
is(event.type, "upgradeneeded", "Expect an upgradeneeded event");
|
||||
is(event.target, request, "Event should be fired on the request");
|
||||
ok(event.target.result instanceof IDBDatabase, "Expect a database here");
|
||||
|
||||
let db = event.target.result;
|
||||
is(db.version, 1, "Database has correct version");
|
||||
|
||||
db.onupgradeneeded = function() {
|
||||
ok(false, "our ongoing VERSION_CHANGE transaction should exclude any others!");
|
||||
}
|
||||
|
||||
db.createObjectStore("foo");
|
||||
|
||||
try {
|
||||
db.transaction("foo");
|
||||
ok(false, "Transactions should be disallowed now!");
|
||||
} catch (e) {
|
||||
ok(e instanceof IDBDatabaseException, "Expect an IDBException");
|
||||
is(e.code, IDBDatabaseException.NOT_ALLOWED_ERR, "Expect a NOT_ALLOWED_ERR");
|
||||
}
|
||||
|
||||
request.transaction.oncomplete = grabEventAndContinueHandler;
|
||||
|
||||
yield;
|
||||
|
||||
// The database is still not fully open here.
|
||||
try {
|
||||
db.transaction("foo");
|
||||
ok(false, "Transactions should be disallowed now!");
|
||||
} catch (e) {
|
||||
ok(e instanceof IDBDatabaseException, "Expect an IDBException");
|
||||
is(e.code, IDBDatabaseException.NOT_ALLOWED_ERR, "Expect a NOT_ALLOWED_ERR");
|
||||
}
|
||||
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
yield;
|
||||
|
||||
db.onversionchange = function() {
|
||||
ok(true, "next setVersion was unblocked appropriately");
|
||||
db.close();
|
||||
}
|
||||
|
||||
try {
|
||||
db.transaction("foo");
|
||||
ok(true, "Transactions should be allowed now!");
|
||||
} catch (e) {
|
||||
ok(false, "Transactions should be allowed now!");
|
||||
}
|
||||
|
||||
request2.onupgradeneeded = null;
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
let db = event.target.result;
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
|
||||
let objectStore = db.createObjectStore("foo");
|
||||
objectStore.add({}, 1).onerror = errorHandler;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -157,6 +158,8 @@
|
|||
ok(true, "RemoveIndex threw");
|
||||
}
|
||||
|
||||
yield;
|
||||
|
||||
request = db.transaction("foo", READ_WRITE).objectStore("foo").add({});
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
|
||||
db.createObjectStore("foo", { autoIncrement: true });
|
||||
yield;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
event.target.onsuccess = continueToNextStep;
|
||||
db.createObjectStore("foo");
|
||||
yield;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
|
@ -39,7 +40,6 @@
|
|||
let key = event.target.result;
|
||||
ok(key, "Got a key");
|
||||
|
||||
SimpleTest.executeSoon(function() { testGenerator.next(); });
|
||||
yield;
|
||||
|
||||
let continueReading = true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче