storage/src/mozStorageConnection.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:6b842f90339e
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 mozilla_storage_Connection_h
8 #define mozilla_storage_Connection_h
9
10 #include "nsAutoPtr.h"
11 #include "nsCOMPtr.h"
12 #include "mozilla/Mutex.h"
13 #include "nsProxyRelease.h"
14 #include "nsThreadUtils.h"
15 #include "nsIInterfaceRequestor.h"
16
17 #include "nsDataHashtable.h"
18 #include "mozIStorageProgressHandler.h"
19 #include "SQLiteMutex.h"
20 #include "mozIStorageConnection.h"
21 #include "mozStorageService.h"
22 #include "mozIStorageAsyncConnection.h"
23 #include "mozIStorageCompletionCallback.h"
24
25 #include "nsIMutableArray.h"
26 #include "mozilla/Attributes.h"
27
28 #include "sqlite3.h"
29
30 struct PRLock;
31 class nsIFile;
32 class nsIFileURL;
33 class nsIEventTarget;
34 class nsIThread;
35
36 namespace mozilla {
37 namespace storage {
38
39 class Connection MOZ_FINAL : public mozIStorageConnection
40 , public nsIInterfaceRequestor
41 {
42 public:
43 NS_DECL_THREADSAFE_ISUPPORTS
44 NS_DECL_MOZISTORAGEASYNCCONNECTION
45 NS_DECL_MOZISTORAGECONNECTION
46 NS_DECL_NSIINTERFACEREQUESTOR
47
48 /**
49 * Structure used to describe user functions on the database connection.
50 */
51 struct FunctionInfo {
52 enum FunctionType {
53 SIMPLE,
54 AGGREGATE
55 };
56
57 nsCOMPtr<nsISupports> function;
58 FunctionType type;
59 int32_t numArgs;
60 };
61
62 /**
63 * @param aService
64 * Pointer to the storage service. Held onto for the lifetime of the
65 * connection.
66 * @param aFlags
67 * The flags to pass to sqlite3_open_v2.
68 * @param aAsyncOnly
69 * If |true|, the Connection only implements asynchronous interface:
70 * - |mozIStorageAsyncConnection|;
71 * If |false|, the result also implements synchronous interface:
72 * - |mozIStorageConnection|.
73 */
74 Connection(Service *aService, int aFlags, bool aAsyncOnly);
75
76 /**
77 * Creates the connection to an in-memory database.
78 */
79 nsresult initialize();
80
81 /**
82 * Creates the connection to the database.
83 *
84 * @param aDatabaseFile
85 * The nsIFile of the location of the database to open, or create if it
86 * does not exist.
87 */
88 nsresult initialize(nsIFile *aDatabaseFile);
89
90 /**
91 * Creates the connection to the database.
92 *
93 * @param aFileURL
94 * The nsIFileURL of the location of the database to open, or create if it
95 * does not exist.
96 */
97 nsresult initialize(nsIFileURL *aFileURL);
98
99 /**
100 * Fetches runtime status information for this connection.
101 *
102 * @param aStatusOption One of the SQLITE_DBSTATUS options defined at
103 * http://www.sqlite.org/c3ref/c_dbstatus_options.html
104 * @param [optional] aMaxValue if provided, will be set to the highest
105 * istantaneous value.
106 * @return the current value for the specified option.
107 */
108 int32_t getSqliteRuntimeStatus(int32_t aStatusOption,
109 int32_t* aMaxValue=nullptr);
110 /**
111 * Registers/unregisters a commit hook callback.
112 *
113 * @param aCallbackFn a callback function to be invoked on transactions
114 * commit. Pass nullptr to unregister the current callback.
115 * @param [optional] aData if provided, will be passed to the callback.
116 * @see http://sqlite.org/c3ref/commit_hook.html
117 */
118 void setCommitHook(int (*aCallbackFn)(void *) , void *aData=nullptr) {
119 MOZ_ASSERT(mDBConn, "A connection must exist at this point");
120 ::sqlite3_commit_hook(mDBConn, aCallbackFn, aData);
121 };
122
123 /**
124 * Lazily creates and returns a background execution thread. In the future,
125 * the thread may be re-claimed if left idle, so you should call this
126 * method just before you dispatch and not save the reference.
127 *
128 * @returns an event target suitable for asynchronous statement execution.
129 */
130 nsIEventTarget *getAsyncExecutionTarget();
131
132 /**
133 * Mutex used by asynchronous statements to protect state. The mutex is
134 * declared on the connection object because there is no contention between
135 * asynchronous statements (they are serialized on mAsyncExecutionThread).
136 * Currently protects:
137 * - Connection.mAsyncExecutionThreadShuttingDown
138 * - Connection.mAsyncExecutionThread
139 * - Connection.mConnectionClosed
140 * - AsyncExecuteStatements.mCancelRequested
141 */
142 Mutex sharedAsyncExecutionMutex;
143
144 /**
145 * Wraps the mutex that SQLite gives us from sqlite3_db_mutex. This is public
146 * because we already expose the sqlite3* native connection and proper
147 * operation of the deadlock detector requires everyone to use the same single
148 * SQLiteMutex instance for correctness.
149 */
150 SQLiteMutex sharedDBMutex;
151
152 /**
153 * References the thread this database was opened on. This MUST be thread it is
154 * closed on.
155 */
156 const nsCOMPtr<nsIThread> threadOpenedOn;
157
158 /**
159 * Closes the SQLite database, and warns about any non-finalized statements.
160 */
161 nsresult internalClose(sqlite3 *aDBConn);
162
163 /**
164 * Obtains the filename of the connection. Useful for logging.
165 */
166 nsCString getFilename();
167
168 /**
169 * Creates an sqlite3 prepared statement object from an SQL string.
170 *
171 * @param aNativeConnection
172 * The underlying Sqlite connection to prepare the statement with.
173 * @param aSQL
174 * The SQL statement string to compile.
175 * @param _stmt
176 * New sqlite3_stmt object.
177 * @return the result from sqlite3_prepare_v2.
178 */
179 int prepareStatement(sqlite3* aNativeConnection,
180 const nsCString &aSQL, sqlite3_stmt **_stmt);
181
182 /**
183 * Performs a sqlite3_step on aStatement, while properly handling SQLITE_LOCKED
184 * when not on the main thread by waiting until we are notified.
185 *
186 * @param aNativeConnection
187 * The underlying Sqlite connection to step the statement with.
188 * @param aStatement
189 * A pointer to a sqlite3_stmt object.
190 * @return the result from sqlite3_step.
191 */
192 int stepStatement(sqlite3* aNativeConnection, sqlite3_stmt* aStatement);
193
194 /**
195 * Raw connection transaction management.
196 *
197 * @see BeginTransactionAs, CommitTransaction, RollbackTransaction.
198 */
199 nsresult beginTransactionInternal(sqlite3 *aNativeConnection,
200 int32_t aTransactionType=TRANSACTION_DEFERRED);
201 nsresult commitTransactionInternal(sqlite3 *aNativeConnection);
202 nsresult rollbackTransactionInternal(sqlite3 *aNativeConnection);
203
204 bool connectionReady();
205
206 /**
207 * True if this connection is shutting down but not yet closed.
208 */
209 bool isClosing();
210
211 /**
212 * True if the underlying connection is closed.
213 * Any sqlite resources may be lost when this returns true, so nothing should
214 * try to use them.
215 */
216 bool isClosed();
217
218 nsresult initializeClone(Connection *aClone, bool aReadOnly);
219
220 private:
221 ~Connection();
222 nsresult initializeInternal(nsIFile *aDatabaseFile);
223
224 /**
225 * Sets the database into a closed state so no further actions can be
226 * performed.
227 *
228 * @note mDBConn is set to nullptr in this method.
229 */
230 nsresult setClosedState();
231
232 /**
233 * Helper for calls to sqlite3_exec. Reports long delays to Telemetry.
234 *
235 * @param aNativeConnection
236 * The underlying Sqlite connection to execute the query with.
237 * @param aSqlString
238 * SQL string to execute
239 * @return the result from sqlite3_exec.
240 */
241 int executeSql(sqlite3 *aNativeConnection, const char *aSqlString);
242
243 /**
244 * Describes a certain primitive type in the database.
245 *
246 * Possible Values Are:
247 * INDEX - To check for the existence of an index
248 * TABLE - To check for the existence of a table
249 */
250 enum DatabaseElementType {
251 INDEX,
252 TABLE
253 };
254
255 /**
256 * Determines if the specified primitive exists.
257 *
258 * @param aElementType
259 * The type of element to check the existence of
260 * @param aElementName
261 * The name of the element to check for
262 * @returns true if element exists, false otherwise
263 */
264 nsresult databaseElementExists(enum DatabaseElementType aElementType,
265 const nsACString& aElementName,
266 bool *_exists);
267
268 bool findFunctionByInstance(nsISupports *aInstance);
269
270 static int sProgressHelper(void *aArg);
271 // Generic progress handler
272 // Dispatch call to registered progress handler,
273 // if there is one. Do nothing in other cases.
274 int progressHandler();
275
276 sqlite3 *mDBConn;
277 nsCOMPtr<nsIFileURL> mFileURL;
278 nsCOMPtr<nsIFile> mDatabaseFile;
279
280 /**
281 * Lazily created thread for asynchronous statement execution. Consumers
282 * should use getAsyncExecutionTarget rather than directly accessing this
283 * field.
284 */
285 nsCOMPtr<nsIThread> mAsyncExecutionThread;
286
287 /**
288 * Set to true by Close() or AsyncClose() prior to shutdown.
289 *
290 * If false, we guarantee both that the underlying sqlite3 database
291 * connection is still open and that getAsyncExecutionTarget() can
292 * return a thread. Once true, either the sqlite3 database
293 * connection is being shutdown or it has been
294 * shutdown. Additionally, once true, getAsyncExecutionTarget()
295 * returns null.
296 *
297 * This variable should be accessed while holding the
298 * sharedAsyncExecutionMutex.
299 */
300 bool mAsyncExecutionThreadShuttingDown;
301
302 /**
303 * Set to true just prior to calling sqlite3_close on the
304 * connection.
305 *
306 * This variable should be accessed while holding the
307 * sharedAsyncExecutionMutex.
308 */
309 bool mConnectionClosed;
310
311 /**
312 * Tracks if we have a transaction in progress or not. Access protected by
313 * sharedDBMutex.
314 */
315 bool mTransactionInProgress;
316
317 /**
318 * Stores the mapping of a given function by name to its instance. Access is
319 * protected by sharedDBMutex.
320 */
321 nsDataHashtable<nsCStringHashKey, FunctionInfo> mFunctions;
322
323 /**
324 * Stores the registered progress handler for the database connection. Access
325 * is protected by sharedDBMutex.
326 */
327 nsCOMPtr<mozIStorageProgressHandler> mProgressHandler;
328
329 /**
330 * Stores the flags we passed to sqlite3_open_v2.
331 */
332 const int mFlags;
333
334 // This is here for two reasons: 1) It's used to make sure that the
335 // connections do not outlive the service. 2) Our custom collating functions
336 // call its localeCompareStrings() method.
337 nsRefPtr<Service> mStorageService;
338
339 /**
340 * If |false|, this instance supports synchronous operations
341 * and it can be cast to |mozIStorageConnection|.
342 */
343 const bool mAsyncOnly;
344 };
345
346
347 /**
348 * A Runnable designed to call a mozIStorageCompletionCallback on
349 * the appropriate thread.
350 */
351 class CallbackComplete MOZ_FINAL : public nsRunnable
352 {
353 public:
354 /**
355 * @param aValue The result to pass to the callback. It must
356 * already be owned by the main thread.
357 * @param aCallback The callback. It must already be owned by the
358 * main thread.
359 */
360 CallbackComplete(nsresult aStatus,
361 nsISupports* aValue,
362 already_AddRefed<mozIStorageCompletionCallback> aCallback)
363 : mStatus(aStatus)
364 , mValue(aValue)
365 , mCallback(aCallback)
366 {
367 }
368
369 NS_IMETHOD Run() {
370 MOZ_ASSERT(NS_IsMainThread());
371 nsresult rv = mCallback->Complete(mStatus, mValue);
372
373 // Ensure that we release on the main thread
374 mValue = nullptr;
375 mCallback = nullptr;
376 return rv;
377 }
378
379 private:
380 nsresult mStatus;
381 nsCOMPtr<nsISupports> mValue;
382 // This is a nsRefPtr<T> and not a nsCOMPtr<T> because
383 // nsCOMP<T> would cause an off-main thread QI, which
384 // is not a good idea (and crashes XPConnect).
385 nsRefPtr<mozIStorageCompletionCallback> mCallback;
386 };
387
388 } // namespace storage
389 } // namespace mozilla
390
391 #endif // mozilla_storage_Connection_h

mercurial