bool AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement) { mMutex.AssertNotCurrentThreadOwns(); Telemetry::AutoTimer<Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_MS> finallySendExecutionDuration(mRequestStartDate); while (true) { // lock the sqlite mutex so sqlite3_errmsg cannot change SQLiteMutexAutoLock lockedScope(mDBMutex); int rc = mConnection->stepStatement(mNativeConnection, aStatement); // Stop if we have no more results. if (rc == SQLITE_DONE) { Telemetry::Accumulate(Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, true); return false; } // If we got results, we can return now. if (rc == SQLITE_ROW) { Telemetry::Accumulate(Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, true); return true; } // Some errors are not fatal, and we can handle them and continue. if (rc == SQLITE_BUSY) { // Don't hold the lock while we call outside our module. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); // Yield, and try again (void)::PR_Sleep(PR_INTERVAL_NO_WAIT); continue; } // Set an error state. mState = ERROR; Telemetry::Accumulate(Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, false); // Construct the error message before giving up the mutex (which we cannot // hold during the call to notifyError). nsCOMPtr<mozIStorageError> errorObj( new Error(rc, ::sqlite3_errmsg(mNativeConnection)) ); // We cannot hold the DB mutex while calling notifyError. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); (void)notifyError(errorObj); // Finally, indicate that we should stop processing. return false; } }
nsresult AsyncExecuteStatements::notifyError(PRInt32 aErrorCode, const char *aMessage) { mMutex.AssertNotCurrentThreadOwns(); if (!mCallback) return NS_OK; nsCOMPtr<mozIStorageError> errorObj(new Error(aErrorCode, aMessage)); NS_ENSURE_TRUE(errorObj, NS_ERROR_OUT_OF_MEMORY); return notifyError(errorObj); }
bool AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement) { mMutex.AssertNotCurrentThreadOwns(); while (true) { // lock the sqlite mutex so sqlite3_errmsg cannot change SQLiteMutexAutoLock lockedScope(mDBMutex); int rc = stepStmt(aStatement); // Stop if we have no more results. if (rc == SQLITE_DONE) return false; // If we got results, we can return now. if (rc == SQLITE_ROW) return true; // Some errors are not fatal, and we can handle them and continue. if (rc == SQLITE_BUSY) { // Don't hold the lock while we call outside our module. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); // Yield, and try again (void)::PR_Sleep(PR_INTERVAL_NO_WAIT); continue; } // Set an error state. mState = ERROR; // Construct the error message before giving up the mutex (which we cannot // hold during the call to notifyError). sqlite3 *db = mConnection->GetNativeConnection(); nsCOMPtr<mozIStorageError> errorObj(new Error(rc, ::sqlite3_errmsg(db))); // We cannot hold the DB mutex while calling notifyError. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); (void)notifyError(errorObj); // Finally, indicate that we should stop processing. return false; } }
NS_IMETHODIMP AsyncExecuteStatements::Run() { MOZ_ASSERT(!mConnection->isClosed()); // Do not run if we have been canceled. { MutexAutoLock lockedScope(mMutex); if (mCancelRequested) mState = CANCELED; } if (mState == CANCELED) return notifyComplete(); if (statementsNeedTransaction() && mConnection->getAutocommit()) { if (NS_SUCCEEDED(mConnection->beginTransactionInternal(mNativeConnection, mozIStorageConnection::TRANSACTION_IMMEDIATE))) { mHasTransaction = true; } #ifdef DEBUG else { NS_WARNING("Unable to create a transaction for async execution."); } #endif } // Execute each statement, giving the callback results if it returns any. for (uint32_t i = 0; i < mStatements.Length(); i++) { bool finished = (i == (mStatements.Length() - 1)); sqlite3_stmt *stmt; { // lock the sqlite mutex so sqlite3_errmsg cannot change SQLiteMutexAutoLock lockedScope(mDBMutex); int rc = mStatements[i].getSqliteStatement(&stmt); if (rc != SQLITE_OK) { // Set our error state. mState = ERROR; // Build the error object; can't call notifyError with the lock held nsCOMPtr<mozIStorageError> errorObj( new Error(rc, ::sqlite3_errmsg(mNativeConnection)) ); { // We cannot hold the DB mutex and call notifyError. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); (void)notifyError(errorObj); } break; } } // If we have parameters to bind, bind them, execute, and process. if (mStatements[i].hasParametersToBeBound()) { if (!bindExecuteAndProcessStatement(mStatements[i], finished)) break; } // Otherwise, just execute and process the statement. else if (!executeAndProcessStatement(stmt, finished)) { break; } } // If we still have results that we haven't notified about, take care of // them now. if (mResultSet) (void)notifyResults(); // Notify about completion return notifyComplete(); }
NS_IMETHODIMP AsyncExecuteStatements::Run() { // Do not run if we have been canceled. { MutexAutoLock lockedScope(mMutex); if (mCancelRequested) mState = CANCELED; } if (mState == CANCELED) return notifyComplete(); if (statementsNeedTransaction()) { mTransactionManager = new mozStorageTransaction(mConnection, false, mozIStorageConnection::TRANSACTION_IMMEDIATE); } // Execute each statement, giving the callback results if it returns any. for (PRUint32 i = 0; i < mStatements.Length(); i++) { bool finished = (i == (mStatements.Length() - 1)); sqlite3_stmt *stmt; { // lock the sqlite mutex so sqlite3_errmsg cannot change SQLiteMutexAutoLock lockedScope(mDBMutex); int rc = mStatements[i].getSqliteStatement(&stmt); if (rc != SQLITE_OK) { // Set our error state. mState = ERROR; // Build the error object; can't call notifyError with the lock held sqlite3 *db = mConnection->GetNativeConnection(); nsCOMPtr<mozIStorageError> errorObj( new Error(rc, ::sqlite3_errmsg(db)) ); { // We cannot hold the DB mutex and call notifyError. SQLiteMutexAutoUnlock unlockedScope(mDBMutex); (void)notifyError(errorObj); } break; } } // If we have parameters to bind, bind them, execute, and process. if (mStatements[i].hasParametersToBeBound()) { if (!bindExecuteAndProcessStatement(mStatements[i], finished)) break; } // Otherwise, just execute and process the statement. else if (!executeAndProcessStatement(stmt, finished)) { break; } } // If we still have results that we haven't notified about, take care of // them now. if (mResultSet) (void)notifyResults(); // Notify about completion return notifyComplete(); }