|
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 |