示例#1
0
NS_IMETHODIMP
OpenDatabaseHelper::Run()
{
  NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?");

  if (NS_IsMainThread()) {
    // If we need to queue up a SetVersionHelper, do that here.
    if (mState == eSetVersionPending) {
      nsresult rv = StartSetVersion();

      if (NS_SUCCEEDED(rv)) {
        return rv;
      }

      SetError(rv);
      // fall through and run the default error processing
    }

    // We've done whatever work we need to do on the DB thread, and any
    // SetVersion stuff is done by now.
    NS_ASSERTION(mState == eFiringEvents ||
                 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
      // a SetVersionHelper.  In the SetVersionHelper case, that helper tells
      // the request that it is done, and we avoid calling NotifyHandlerCompleted
      // twice.

      nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
      if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
        mResultCode = rv;
      }
    }

    NS_ASSERTION(mState == eFiringEvents, "Why are we here?");

    if (NS_FAILED(mResultCode)) {
      DispatchErrorEvent();
    } else {
      DispatchSuccessEvent();
    }

    IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
    NS_ASSERTION(manager, "This should never be null!");

    manager->AllowNextSynchronizedOp(mASCIIOrigin, mDatabaseId);

    ReleaseMainThreadObjects();

    return NS_OK;
  }

  // If we're on the DB thread, do that
  NS_ASSERTION(mState == eDBWork, "Why are we here?");
  mResultCode = DoDatabaseWork();
  NS_ASSERTION(mState != eDBWork, "We should be doing something else now.");

  return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
}
NS_IMETHODIMP
AsyncConnectionHelper::Run()
{
  if (NS_IsMainThread()) {
    if (mTransaction &&
        mTransaction->IsAborted()) {
      // Always fire a "error" event with ABORT_ERR if the transaction was
      // aborted, even if the request succeeded or failed with another error.
      mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
    }

    IDBTransaction* oldTransaction = gCurrentTransaction;
    gCurrentTransaction = mTransaction;

    if (mRequest) {
      nsresult rv = mRequest->NotifyHelperCompleted(this);
      if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
        mResultCode = rv;
      }
    }

    // Call OnError if the database had an error or if the OnSuccess handler
    // has an error.
    if (NS_FAILED(mResultCode) ||
        NS_FAILED((mResultCode = OnSuccess()))) {
      OnError();
    }

    NS_ASSERTION(gCurrentTransaction == mTransaction, "Should be unchanged!");
    gCurrentTransaction = oldTransaction;

    if (mDispatched && mTransaction) {
      mTransaction->OnRequestFinished();
    }

    ReleaseMainThreadObjects();

    NS_ASSERTION(!(mDatabase || mTransaction || mRequest), "Subclass didn't "
                 "call AsyncConnectionHelper::ReleaseMainThreadObjects!");

    return NS_OK;
  }

  nsresult rv = NS_OK;
  nsCOMPtr<mozIStorageConnection> connection;

  if (mTransaction) {
    rv = mTransaction->GetOrCreateConnection(getter_AddRefs(connection));
    if (NS_SUCCEEDED(rv)) {
      NS_ASSERTION(connection, "This should never be null!");
    }
  }

  bool setProgressHandler = false;
  if (connection) {
    rv = connection->SetProgressHandler(kProgressHandlerGranularity, this,
                                        getter_AddRefs(mOldProgressHandler));
    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "SetProgressHandler failed!");
    if (NS_SUCCEEDED(rv)) {
      setProgressHandler = true;
    }
  }

  if (NS_SUCCEEDED(rv)) {
    bool hasSavepoint = false;
    if (mDatabase) {
      IndexedDatabaseManager::SetCurrentDatabase(mDatabase);

      // Make the first savepoint.
      if (mTransaction) {
        if (!(hasSavepoint = mTransaction->StartSavepoint())) {
          NS_WARNING("Failed to make savepoint!");
        }
      }
    }

    mResultCode = DoDatabaseWork(connection);

    if (mDatabase) {
      IndexedDatabaseManager::SetCurrentDatabase(nsnull);

      // Release or roll back the savepoint depending on the error code.
      if (hasSavepoint) {
        NS_ASSERTION(mTransaction, "Huh?!");
        if (NS_SUCCEEDED(mResultCode)) {
          mTransaction->ReleaseSavepoint();
        }
        else {
          mTransaction->RollbackSavepoint();
        }
      }
    }
  }
  else {
    // NS_ERROR_NOT_AVAILABLE is our special code for "database is invalidated"
    // and we should fail with RECOVERABLE_ERR.
    if (rv == NS_ERROR_NOT_AVAILABLE) {
      mResultCode = NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR;
    }
    else {
      mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    }
  }

  if (setProgressHandler) {
    nsCOMPtr<mozIStorageProgressHandler> handler;
    rv = connection->RemoveProgressHandler(getter_AddRefs(handler));
    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "RemoveProgressHandler failed!");
#ifdef DEBUG
    if (NS_SUCCEEDED(rv)) {
      NS_ASSERTION(SameCOMIdentity(handler, static_cast<nsIRunnable*>(this)),
                   "Mismatch!");
    }
#endif
  }

  return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
}