mozStorageAsyncStatementExecution.h (7784B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozStorageAsyncStatementExecution_h 8 #define mozStorageAsyncStatementExecution_h 9 10 #include "nscore.h" 11 #include "nsTArray.h" 12 #include "mozilla/Mutex.h" 13 #include "mozilla/TimeStamp.h" 14 #include "nsThreadUtils.h" 15 16 #include "SQLiteMutex.h" 17 #include "mozIStoragePendingStatement.h" 18 #include "mozIStorageStatementCallback.h" 19 #include "mozStorageHelper.h" 20 21 struct sqlite3_stmt; 22 23 namespace mozilla { 24 namespace storage { 25 26 class Connection; 27 class ResultSet; 28 class StatementData; 29 } // namespace storage 30 } // namespace mozilla 31 32 namespace mozilla::storage { 33 class AsyncExecuteStatements final : public Runnable, 34 public mozIStoragePendingStatement { 35 public: 36 NS_DECL_ISUPPORTS_INHERITED 37 NS_DECL_NSIRUNNABLE 38 NS_DECL_MOZISTORAGEPENDINGSTATEMENT 39 40 /** 41 * Describes the state of execution. 42 */ 43 enum ExecutionState { 44 PENDING = -1, 45 COMPLETED = mozIStorageStatementCallback::REASON_FINISHED, 46 CANCELED = mozIStorageStatementCallback::REASON_CANCELED, 47 ERROR = mozIStorageStatementCallback::REASON_ERROR 48 }; 49 50 typedef nsTArray<StatementData> StatementDataArray; 51 52 /** 53 * Executes a statement in the background, and passes results back to the 54 * caller. 55 * 56 * @param aStatements 57 * The statements to execute and possibly bind in the background. 58 * Ownership is transfered from the caller. 59 * @param aConnection 60 * The connection that created the statements to execute. 61 * @param aNativeConnection 62 * The native Sqlite connection that created the statements to execute. 63 * @param aCallback 64 * The callback that is notified of results, completion, and errors. 65 * @param _stmt 66 * The handle to control the execution of the statements. 67 */ 68 static nsresult execute(StatementDataArray&& aStatements, 69 Connection* aConnection, sqlite3* aNativeConnection, 70 mozIStorageStatementCallback* aCallback, 71 mozIStoragePendingStatement** _stmt); 72 73 /** 74 * Indicates when events on the calling thread should run or not. Certain 75 * events posted back to the calling thread should call this see if they 76 * should run or not. 77 * 78 * @pre mMutex is not held 79 * 80 * @returns true if the event should notify still, false otherwise. 81 */ 82 bool shouldNotify(); 83 84 /** 85 * Used by notifyComplete(), notifyError() and notifyResults() to notify on 86 * the calling thread. 87 */ 88 nsresult notifyCompleteOnCallingThread(); 89 nsresult notifyErrorOnCallingThread(mozIStorageError* aError); 90 nsresult notifyResultsOnCallingThread(ResultSet* aResultSet); 91 92 private: 93 AsyncExecuteStatements(StatementDataArray&& aStatements, 94 Connection* aConnection, sqlite3* aNativeConnection, 95 mozIStorageStatementCallback* aCallback); 96 ~AsyncExecuteStatements(); 97 98 /** 99 * Binds and then executes a given statement until completion, an error 100 * occurs, or we are canceled. If aLastStatement is true, we should set 101 * mState accordingly. 102 * 103 * @pre mMutex is not held 104 * 105 * @param aData 106 * The StatementData to bind, execute, and then process. 107 * @param aLastStatement 108 * Indicates if this is the last statement or not. If it is, we have 109 * to set the proper state. 110 * @returns true if we should continue to process statements, false otherwise. 111 */ 112 bool bindExecuteAndProcessStatement(StatementData& aData, 113 bool aLastStatement); 114 115 /** 116 * Executes a given statement until completion, an error occurs, or we are 117 * canceled. If aLastStatement is true, we should set mState accordingly. 118 * 119 * @pre mMutex is not held 120 * 121 * @param aData 122 * The StatementData to execute, and then process. 123 * @param aLastStatement 124 * Indicates if this is the last statement or not. If it is, we have 125 * to set the proper state. 126 * @returns true if we should continue to process statements, false otherwise. 127 */ 128 bool executeAndProcessStatement(StatementData& aData, bool aLastStatement); 129 130 /** 131 * Executes a statement to completion, properly handling any error conditions. 132 * 133 * @pre mMutex is not held 134 * 135 * @param aData 136 * The StatementData to execute to completion. 137 * @returns true if results were obtained, false otherwise. 138 */ 139 bool executeStatement(StatementData& aData); 140 141 /** 142 * Builds a result set up with a row from a given statement. If we meet the 143 * right criteria, go ahead and notify about this results too. 144 * 145 * @pre mMutex is not held 146 * 147 * @param aStatement 148 * The statement to get the row data from. 149 */ 150 nsresult buildAndNotifyResults(sqlite3_stmt* aStatement); 151 152 /** 153 * Notifies callback about completion, and does any necessary cleanup. 154 * 155 * @pre mMutex is not held 156 */ 157 nsresult notifyComplete(); 158 159 /** 160 * Notifies callback about an error. 161 * 162 * @pre mMutex is not held 163 * @pre mDBMutex is not held 164 * 165 * @param aErrorCode 166 * The error code defined in mozIStorageError for the error. 167 * @param aMessage 168 * The error string, if any. 169 * @param aError 170 * The error object to notify the caller with. 171 */ 172 nsresult notifyError(int32_t aErrorCode, const char* aMessage); 173 nsresult notifyError(mozIStorageError* aError); 174 175 /** 176 * Notifies the callback about a result set. 177 * 178 * @pre mMutex is not held 179 */ 180 nsresult notifyResults(); 181 182 /** 183 * Tests whether the current statements should be wrapped in an explicit 184 * transaction. 185 * 186 * @return true if an explicit transaction is needed, false otherwise. 187 */ 188 bool statementsNeedTransaction(); 189 190 StatementDataArray mStatements; 191 RefPtr<Connection> mConnection; 192 sqlite3* mNativeConnection; 193 bool mHasTransaction; 194 // Note, this may not be a threadsafe object - never addref/release off 195 // the calling thread. We take a reference when this is created, and 196 // release it in the CompletionNotifier::Run() call back to this thread. 197 nsCOMPtr<mozIStorageStatementCallback> mCallback; 198 nsCOMPtr<nsIThread> mCallingThread; 199 RefPtr<ResultSet> mResultSet; 200 201 /** 202 * The maximum amount of time we want to wait between results. Defined by 203 * MAX_MILLISECONDS_BETWEEN_RESULTS and set at construction. 204 */ 205 const TimeDuration mMaxWait; 206 207 /** 208 * The start time since our last set of results. 209 */ 210 TimeStamp mIntervalStart; 211 212 /** 213 * Indicates our state of execution. 214 */ 215 ExecutionState mState; 216 217 /** 218 * Indicates if we should try to cancel at a cancelation point. 219 */ 220 bool mCancelRequested; 221 222 /** 223 * This is the mutex that protects our state from changing between threads. 224 * This includes the following variables: 225 * - mCancelRequested is only set on the calling thread while the lock is 226 * held. It is always read from within the lock on the background thread, 227 * but not on the calling thread (see shouldNotify for why). 228 */ 229 Mutex& mMutex; 230 231 /** 232 * The wrapped SQLite recursive connection mutex. We use it whenever we call 233 * sqlite3_step and care about having reliable error messages. By taking it 234 * prior to the call and holding it until the point where we no longer care 235 * about the error message, the user gets reliable error messages. 236 */ 237 SQLiteMutex& mDBMutex; 238 }; 239 240 } // namespace mozilla::storage 241 242 #endif // mozStorageAsyncStatementExecution_h