diff options
Diffstat (limited to '')
-rw-r--r-- | storage/mozStorageAsyncStatementExecution.h | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/storage/mozStorageAsyncStatementExecution.h b/storage/mozStorageAsyncStatementExecution.h new file mode 100644 index 0000000000..a7f35dcfbe --- /dev/null +++ b/storage/mozStorageAsyncStatementExecution.h @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozStorageAsyncStatementExecution_h +#define mozStorageAsyncStatementExecution_h + +#include "nscore.h" +#include "nsTArray.h" +#include "mozilla/Mutex.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/Attributes.h" +#include "nsThreadUtils.h" + +#include "SQLiteMutex.h" +#include "mozIStoragePendingStatement.h" +#include "mozIStorageStatementCallback.h" +#include "mozStorageHelper.h" + +struct sqlite3_stmt; + +namespace mozilla { +namespace storage { + +class Connection; +class ResultSet; +class StatementData; +} // namespace storage +} // namespace mozilla + +namespace mozilla::storage { +class AsyncExecuteStatements final : public Runnable, + public mozIStoragePendingStatement { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIRUNNABLE + NS_DECL_MOZISTORAGEPENDINGSTATEMENT + + /** + * Describes the state of execution. + */ + enum ExecutionState { + PENDING = -1, + COMPLETED = mozIStorageStatementCallback::REASON_FINISHED, + CANCELED = mozIStorageStatementCallback::REASON_CANCELED, + ERROR = mozIStorageStatementCallback::REASON_ERROR + }; + + typedef nsTArray<StatementData> StatementDataArray; + + /** + * Executes a statement in the background, and passes results back to the + * caller. + * + * @param aStatements + * The statements to execute and possibly bind in the background. + * Ownership is transfered from the caller. + * @param aConnection + * The connection that created the statements to execute. + * @param aNativeConnection + * The native Sqlite connection that created the statements to execute. + * @param aCallback + * The callback that is notified of results, completion, and errors. + * @param _stmt + * The handle to control the execution of the statements. + */ + static nsresult execute(StatementDataArray&& aStatements, + Connection* aConnection, sqlite3* aNativeConnection, + mozIStorageStatementCallback* aCallback, + mozIStoragePendingStatement** _stmt); + + /** + * Indicates when events on the calling thread should run or not. Certain + * events posted back to the calling thread should call this see if they + * should run or not. + * + * @pre mMutex is not held + * + * @returns true if the event should notify still, false otherwise. + */ + bool shouldNotify(); + + /** + * Used by notifyComplete(), notifyError() and notifyResults() to notify on + * the calling thread. + */ + nsresult notifyCompleteOnCallingThread(); + nsresult notifyErrorOnCallingThread(mozIStorageError* aError); + nsresult notifyResultsOnCallingThread(ResultSet* aResultSet); + + private: + AsyncExecuteStatements(StatementDataArray&& aStatements, + Connection* aConnection, sqlite3* aNativeConnection, + mozIStorageStatementCallback* aCallback); + ~AsyncExecuteStatements(); + + /** + * Binds and then executes a given statement until completion, an error + * occurs, or we are canceled. If aLastStatement is true, we should set + * mState accordingly. + * + * @pre mMutex is not held + * + * @param aData + * The StatementData to bind, execute, and then process. + * @param aLastStatement + * Indicates if this is the last statement or not. If it is, we have + * to set the proper state. + * @returns true if we should continue to process statements, false otherwise. + */ + bool bindExecuteAndProcessStatement(StatementData& aData, + bool aLastStatement); + + /** + * Executes a given statement until completion, an error occurs, or we are + * canceled. If aLastStatement is true, we should set mState accordingly. + * + * @pre mMutex is not held + * + * @param aData + * The StatementData to execute, and then process. + * @param aLastStatement + * Indicates if this is the last statement or not. If it is, we have + * to set the proper state. + * @returns true if we should continue to process statements, false otherwise. + */ + bool executeAndProcessStatement(StatementData& aData, bool aLastStatement); + + /** + * Executes a statement to completion, properly handling any error conditions. + * + * @pre mMutex is not held + * + * @param aData + * The StatementData to execute to completion. + * @returns true if results were obtained, false otherwise. + */ + bool executeStatement(StatementData& aData); + + /** + * Builds a result set up with a row from a given statement. If we meet the + * right criteria, go ahead and notify about this results too. + * + * @pre mMutex is not held + * + * @param aStatement + * The statement to get the row data from. + */ + nsresult buildAndNotifyResults(sqlite3_stmt* aStatement); + + /** + * Notifies callback about completion, and does any necessary cleanup. + * + * @pre mMutex is not held + */ + nsresult notifyComplete(); + + /** + * Notifies callback about an error. + * + * @pre mMutex is not held + * @pre mDBMutex is not held + * + * @param aErrorCode + * The error code defined in mozIStorageError for the error. + * @param aMessage + * The error string, if any. + * @param aError + * The error object to notify the caller with. + */ + nsresult notifyError(int32_t aErrorCode, const char* aMessage); + nsresult notifyError(mozIStorageError* aError); + + /** + * Notifies the callback about a result set. + * + * @pre mMutex is not held + */ + nsresult notifyResults(); + + /** + * Tests whether the current statements should be wrapped in an explicit + * transaction. + * + * @return true if an explicit transaction is needed, false otherwise. + */ + bool statementsNeedTransaction(); + + StatementDataArray mStatements; + RefPtr<Connection> mConnection; + sqlite3* mNativeConnection; + bool mHasTransaction; + // Note, this may not be a threadsafe object - never addref/release off + // the calling thread. We take a reference when this is created, and + // release it in the CompletionNotifier::Run() call back to this thread. + nsCOMPtr<mozIStorageStatementCallback> mCallback; + nsCOMPtr<nsIThread> mCallingThread; + RefPtr<ResultSet> mResultSet; + + /** + * The maximum amount of time we want to wait between results. Defined by + * MAX_MILLISECONDS_BETWEEN_RESULTS and set at construction. + */ + const TimeDuration mMaxWait; + + /** + * The start time since our last set of results. + */ + TimeStamp mIntervalStart; + + /** + * Indicates our state of execution. + */ + ExecutionState mState; + + /** + * Indicates if we should try to cancel at a cancelation point. + */ + bool mCancelRequested; + + /** + * This is the mutex that protects our state from changing between threads. + * This includes the following variables: + * - mCancelRequested is only set on the calling thread while the lock is + * held. It is always read from within the lock on the background thread, + * but not on the calling thread (see shouldNotify for why). + */ + Mutex& mMutex; + + /** + * The wrapped SQLite recursive connection mutex. We use it whenever we call + * sqlite3_step and care about having reliable error messages. By taking it + * prior to the call and holding it until the point where we no longer care + * about the error message, the user gets reliable error messages. + */ + SQLiteMutex& mDBMutex; +}; + +} // namespace mozilla::storage + +#endif // mozStorageAsyncStatementExecution_h |