Ejemplo n.º 1
0
nsresult
IDBTransaction::CommitOrRollback()
{
    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");

    if (!IndexedDatabaseManager::IsMainProcess()) {
        NS_ASSERTION(mActorChild, "Must have an actor!");

        mActorChild->SendAllRequestsFinished();

        return NS_OK;
    }

    nsRefPtr<CommitHelper> helper =
        new CommitHelper(this, mListener, mCreatedObjectStores);

    TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
    NS_ENSURE_STATE(pool);

    mCachedStatements.Enumerate(DoomCachedStatements, helper);
    NS_ASSERTION(!mCachedStatements.Count(), "Statements left!");

    nsresult rv = pool->Dispatch(this, helper, true, helper);
    NS_ENSURE_SUCCESS(rv, rv);

    return NS_OK;
}
NS_IMETHODIMP
TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable,
                                     PRUint32 aFlags)
{
  NS_ASSERTION(aRunnable, "Null pointer!");
  NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!");

  TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
  return pool->Dispatch(mTransaction, aRunnable, false, nsnull);
}
Ejemplo n.º 3
0
void
IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(aDatabase, "Null pointer!");

  // Check through the list of SetVersionRunnables we have amassed to see if
  // this database is part of a SetVersion callback.
  for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
    nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];

    if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) {
      // This is the SetVersionRunnable for the given database file. Remove the
      // database from the list of databases that need to be closed. Since we
      // use this hook for SetVersion requests that don't actually need to wait
      // for other databases the mDatabases array may be empty.
      if (!runnable->mDatabases.IsEmpty() &&
          !runnable->mDatabases.RemoveElement(aDatabase)) {
        NS_ERROR("Didn't have this database in our list!");
      }

      // 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);

        if (NS_FAILED(helper->DispatchToTransactionPool())) {
          NS_WARNING("Failed to dispatch to thread pool!");
        }

        // 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!");

        // All other databases should be closed, so we only need to wait on this
        // one.
        nsAutoTArray<nsRefPtr<IDBDatabase>, 1> array;
        if (!array.AppendElement(aDatabase)) {
          NS_ERROR("This should never fail!");
        }

        // Use the SetVersionRunnable as the callback.
        if (!pool->WaitForAllDatabasesToComplete(array, runnable)) {
          NS_WARNING("Failed to wait for transaction to complete!");
        }
      }
      break;
    }
  }
}
Ejemplo n.º 4
0
bool
Client::HasTransactionsForStorage(nsIOfflineStorage* aStorage)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");

  TransactionThreadPool* pool = TransactionThreadPool::Get();
  NS_ASSERTION(pool, "Should have checked if transaction service is active!");

  IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
  NS_ASSERTION(database, "This shouldn't be null!");

  return pool->HasTransactionsForDatabase(database);
}
NS_IMETHODIMP
TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable,
                                     uint32_t aFlags)
{
  NS_ASSERTION(aRunnable, "Null pointer!");
  NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!");

  TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
  NS_ENSURE_TRUE(pool, NS_ERROR_UNEXPECTED);

  nsresult rv = pool->Dispatch(mTransaction, aRunnable, false, nullptr);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
void
IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(aDatabase, "Null pointer!");

  // Check through the list of SynchronizedOps to see if any are waiting for
  // this database to close before proceeding.
  PRUint32 count = mSynchronizedOps.Length();
  for (PRUint32 index = 0; index < count; index++) {
    nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];

    if (op->mOrigin == aDatabase->Origin() &&
        (op->mId == aDatabase->Id() || !op->mId)) {
      // This database is in the scope of this SynchronizedOp.  Remove it
      // from the list if necessary.
      if (op->mDatabases.RemoveElement(aDatabase)) {
        // Now set up the helper if there are no more live databases.
        NS_ASSERTION(op->mHelper, "How did we get rid of the helper before "
                     "removing the last database?");
        if (op->mDatabases.IsEmpty()) {
          // 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.

          TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
          if (!pool) {
            NS_ERROR("IndexedDB is totally broken.");
            return;
          }

          nsRefPtr<WaitForTransactionsToFinishRunnable> waitRunnable =
            new WaitForTransactionsToFinishRunnable(op);

          nsAutoTArray<nsRefPtr<IDBDatabase>, 1> array;
          array.AppendElement(aDatabase);

          // Use the WaitForTransactionsToFinishRunnable as the callback.
          if (!pool->WaitForAllDatabasesToComplete(array, waitRunnable)) {
            NS_WARNING("Failed to wait for transaction to complete!");
          }
        }
        break;
      }
    }
  }
}
Ejemplo n.º 7
0
// static
already_AddRefed<IDBTransaction>
IDBTransaction::Create(IDBDatabase* aDatabase,
                       nsTArray<nsString>& aObjectStoreNames,
                       Mode aMode,
                       bool aDispatchDelayed)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");

  nsRefPtr<IDBTransaction> transaction = new IDBTransaction();

  transaction->BindToOwner(aDatabase);
  if (!transaction->SetScriptOwner(aDatabase->GetScriptOwner())) {
    return nsnull;
  }

  transaction->mDatabase = aDatabase;
  transaction->mMode = aMode;
  
  transaction->mDatabaseInfo = aDatabase->Info();

  if (!transaction->mObjectStoreNames.AppendElements(aObjectStoreNames)) {
    NS_ERROR("Out of memory!");
    return nsnull;
  }

  if (!transaction->mCachedStatements.Init()) {
    NS_ERROR("Failed to initialize hash!");
    return nsnull;
  }

  if (!aDispatchDelayed) {
    nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
    NS_ENSURE_TRUE(appShell, nsnull);

    nsresult rv = appShell->RunBeforeNextEvent(transaction);
    NS_ENSURE_SUCCESS(rv, nsnull);

    transaction->mCreating = true;
  }

  if (aMode != IDBTransaction::VERSION_CHANGE) {
    TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
    pool->Dispatch(transaction, &gStartTransactionRunnable, false, nsnull);
  }

  return transaction.forget();
}
Ejemplo n.º 8
0
NS_IMETHODIMP
IDBCursor::Continue(const jsval &aKey,
                    JSContext* aCx,
                    PRUint8 aOptionalArgCount,
                    PRBool* _retval)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");

  if (!mObjectStore->TransactionIsOpen()) {
    return NS_ERROR_UNEXPECTED;
  }

  if (mContinueCalled) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  Key key;
  nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, key);
  NS_ENSURE_SUCCESS(rv, rv);

  if (key.IsNull()) {
    if (aOptionalArgCount) {
      return NS_ERROR_INVALID_ARG;
    }
    else {
      key = Key::UNSETKEY;
    }
  }

  TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
  NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE);

  nsRefPtr<ContinueRunnable> runnable(new ContinueRunnable(this, key));

  rv = pool->Dispatch(mTransaction, runnable, false, nsnull);
  NS_ENSURE_SUCCESS(rv, rv);

  mTransaction->OnNewRequest();

  mContinueCalled = true;

  *_retval = PR_TRUE;
  return NS_OK;
}
Ejemplo n.º 9
0
nsresult
IDBTransaction::CommitOrRollback()
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");

  TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
  NS_ENSURE_STATE(pool);

  nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener,
                                                 mCreatedObjectStores));

  mCachedStatements.Enumerate(DoomCachedStatements, helper);
  NS_ASSERTION(!mCachedStatements.Count(), "Statements left!");

  nsresult rv = pool->Dispatch(this, helper, true, helper);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
Ejemplo n.º 10
0
void
Client::WaitForStoragesToComplete(nsTArray<nsIOfflineStorage*>& aStorages,
                                  nsIRunnable* aCallback)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(!aStorages.IsEmpty(), "No storages to wait on!");
  NS_ASSERTION(aCallback, "Passed null callback!");

  TransactionThreadPool* pool = TransactionThreadPool::Get();
  NS_ASSERTION(pool, "Should have checked if transaction service is active!");

  nsTArray<nsRefPtr<IDBDatabase> > databases(aStorages.Length());
  for (uint32_t index = 0; index < aStorages.Length(); index++) {
    IDBDatabase* database = IDBDatabase::FromStorage(aStorages[index]);
    if (!database) {
      MOZ_CRASH();
    }

    databases.AppendElement(database);
  }

  pool->WaitForDatabasesToComplete(databases, aCallback);
}
bool
IndexedDatabaseManager::HasOpenTransactions(nsPIDOMWindow* aWindow)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(aWindow, "Null pointer!");

  nsAutoTArray<IDBDatabase*, 50> liveDatabases;
  mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);

  TransactionThreadPool* pool = TransactionThreadPool::Get();
  if (!pool) {
    return false;
  }

  for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
    IDBDatabase*& database = liveDatabases[index];
    if (database->Owner() == aWindow &&
        pool->HasTransactionsForDatabase(database)) {
      return true;
    }
  }
  
  return false;
}
void
IndexedDatabaseManager::AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(aWindow, "Null pointer!");

  nsAutoTArray<IDBDatabase*, 50> liveDatabases;
  mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);

  TransactionThreadPool* pool = TransactionThreadPool::Get();

  for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
    IDBDatabase*& database = liveDatabases[index];
    if (database->Owner() == aWindow) {
      if (NS_FAILED(database->Close())) {
        NS_WARNING("Failed to close database for dying window!");
      }

      if (pool) {
        pool->AbortTransactionsForDatabase(database);
      }
    }
  }
}
Ejemplo n.º 13
0
// static
already_AddRefed<IDBTransaction>
IDBTransaction::CreateInternal(IDBDatabase* aDatabase,
                               nsTArray<nsString>& aObjectStoreNames,
                               Mode aMode,
                               bool aDispatchDelayed,
                               bool aIsVersionChangeTransactionChild)
{
    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    NS_ASSERTION(IndexedDatabaseManager::IsMainProcess() || !aDispatchDelayed,
                 "No support for delayed-dispatch transactions in child "
                 "process!");
    NS_ASSERTION(!aIsVersionChangeTransactionChild ||
                 (!IndexedDatabaseManager::IsMainProcess() &&
                  aMode == IDBTransaction::VERSION_CHANGE),
                 "Busted logic!");

    nsRefPtr<IDBTransaction> transaction = new IDBTransaction();

    transaction->BindToOwner(aDatabase);
    if (!transaction->SetScriptOwner(aDatabase->GetScriptOwner())) {
        return nsnull;
    }

    transaction->mDatabase = aDatabase;
    transaction->mMode = aMode;
    transaction->mDatabaseInfo = aDatabase->Info();
    transaction->mObjectStoreNames.AppendElements(aObjectStoreNames);
    transaction->mObjectStoreNames.Sort();

    IndexedDBTransactionChild* actor = nsnull;

    transaction->mCreatedFileInfos.Init();

    if (IndexedDatabaseManager::IsMainProcess()) {
        transaction->mCachedStatements.Init();

        if (aMode != IDBTransaction::VERSION_CHANGE) {
            TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
            NS_ENSURE_TRUE(pool, nsnull);

            pool->Dispatch(transaction, &gStartTransactionRunnable, false, nsnull);
        }
    }
    else if (!aIsVersionChangeTransactionChild) {
        IndexedDBDatabaseChild* dbActor = aDatabase->GetActorChild();
        NS_ASSERTION(dbActor, "Must have an actor here!");

        ipc::NormalTransactionParams params;
        params.names().AppendElements(aObjectStoreNames);
        params.mode() = aMode;

        actor = new IndexedDBTransactionChild();

        dbActor->SendPIndexedDBTransactionConstructor(actor, params);
    }

    if (!aDispatchDelayed) {
        nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
        NS_ENSURE_TRUE(appShell, nsnull);

        nsresult rv = appShell->RunBeforeNextEvent(transaction);
        NS_ENSURE_SUCCESS(rv, nsnull);

        transaction->mCreating = true;
    }

    if (actor) {
        NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
        actor->SetTransaction(transaction);
    }

    return transaction.forget();
}
Ejemplo n.º 14
0
NS_IMETHODIMP
IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");

  NS_ENSURE_ARG_POINTER(aURI);

  // Figure out which origin we're dealing with.
  nsCString origin;
  nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
  NS_ENSURE_SUCCESS(rv, rv);

  // Non-standard URIs can't create databases anyway, so return immediately.
  if (origin.EqualsLiteral("null")) {
    return NS_OK;
  }

  // If we're already clearing out files for this origin then return
  // immediately.
  PRUint32 clearDataCount = mOriginClearRunnables.Length();
  for (PRUint32 index = 0; index < clearDataCount; index++) {
    if (mOriginClearRunnables[index]->mOrigin == origin) {
      return NS_OK;
    }
  }

  // We need to grab references to any live databases here to prevent them from
  // dying while we invalidate them.
  nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;

  // Grab all live databases for this origin.
  nsTArray<IDBDatabase*>* array;
  if (mLiveDatabases.Get(origin, &array)) {
    if (!liveDatabases.AppendElements(*array)) {
      NS_WARNING("Out of memory?");
      return NS_ERROR_OUT_OF_MEMORY;
    }
  }

  nsRefPtr<OriginClearRunnable> runnable =
    new OriginClearRunnable(origin, mIOThread);

  // Make a new entry for this origin in mOriginClearRunnables.
  nsRefPtr<OriginClearRunnable>* newRunnable =
    mOriginClearRunnables.AppendElement(runnable);
  NS_ENSURE_TRUE(newRunnable, NS_ERROR_OUT_OF_MEMORY);

  if (liveDatabases.IsEmpty()) {
    rv = runnable->Run();
    NS_ENSURE_SUCCESS(rv, rv);

    return NS_OK;
  }

  // Invalidate all the live databases first.
  for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
    liveDatabases[index]->Invalidate();
  }

  // Now set up our callback so that we know when they have finished.
  TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
  NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE);

  if (!pool->WaitForAllDatabasesToComplete(liveDatabases, runnable)) {
    NS_WARNING("Can't wait on databases!");
    return NS_ERROR_FAILURE;
  }

  NS_ASSERTION(liveDatabases.IsEmpty(), "Should have swapped!");

  return NS_OK;
}