1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/storage/src/mozStorageConnection.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,391 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_storage_Connection_h 1.11 +#define mozilla_storage_Connection_h 1.12 + 1.13 +#include "nsAutoPtr.h" 1.14 +#include "nsCOMPtr.h" 1.15 +#include "mozilla/Mutex.h" 1.16 +#include "nsProxyRelease.h" 1.17 +#include "nsThreadUtils.h" 1.18 +#include "nsIInterfaceRequestor.h" 1.19 + 1.20 +#include "nsDataHashtable.h" 1.21 +#include "mozIStorageProgressHandler.h" 1.22 +#include "SQLiteMutex.h" 1.23 +#include "mozIStorageConnection.h" 1.24 +#include "mozStorageService.h" 1.25 +#include "mozIStorageAsyncConnection.h" 1.26 +#include "mozIStorageCompletionCallback.h" 1.27 + 1.28 +#include "nsIMutableArray.h" 1.29 +#include "mozilla/Attributes.h" 1.30 + 1.31 +#include "sqlite3.h" 1.32 + 1.33 +struct PRLock; 1.34 +class nsIFile; 1.35 +class nsIFileURL; 1.36 +class nsIEventTarget; 1.37 +class nsIThread; 1.38 + 1.39 +namespace mozilla { 1.40 +namespace storage { 1.41 + 1.42 +class Connection MOZ_FINAL : public mozIStorageConnection 1.43 + , public nsIInterfaceRequestor 1.44 +{ 1.45 +public: 1.46 + NS_DECL_THREADSAFE_ISUPPORTS 1.47 + NS_DECL_MOZISTORAGEASYNCCONNECTION 1.48 + NS_DECL_MOZISTORAGECONNECTION 1.49 + NS_DECL_NSIINTERFACEREQUESTOR 1.50 + 1.51 + /** 1.52 + * Structure used to describe user functions on the database connection. 1.53 + */ 1.54 + struct FunctionInfo { 1.55 + enum FunctionType { 1.56 + SIMPLE, 1.57 + AGGREGATE 1.58 + }; 1.59 + 1.60 + nsCOMPtr<nsISupports> function; 1.61 + FunctionType type; 1.62 + int32_t numArgs; 1.63 + }; 1.64 + 1.65 + /** 1.66 + * @param aService 1.67 + * Pointer to the storage service. Held onto for the lifetime of the 1.68 + * connection. 1.69 + * @param aFlags 1.70 + * The flags to pass to sqlite3_open_v2. 1.71 + * @param aAsyncOnly 1.72 + * If |true|, the Connection only implements asynchronous interface: 1.73 + * - |mozIStorageAsyncConnection|; 1.74 + * If |false|, the result also implements synchronous interface: 1.75 + * - |mozIStorageConnection|. 1.76 + */ 1.77 + Connection(Service *aService, int aFlags, bool aAsyncOnly); 1.78 + 1.79 + /** 1.80 + * Creates the connection to an in-memory database. 1.81 + */ 1.82 + nsresult initialize(); 1.83 + 1.84 + /** 1.85 + * Creates the connection to the database. 1.86 + * 1.87 + * @param aDatabaseFile 1.88 + * The nsIFile of the location of the database to open, or create if it 1.89 + * does not exist. 1.90 + */ 1.91 + nsresult initialize(nsIFile *aDatabaseFile); 1.92 + 1.93 + /** 1.94 + * Creates the connection to the database. 1.95 + * 1.96 + * @param aFileURL 1.97 + * The nsIFileURL of the location of the database to open, or create if it 1.98 + * does not exist. 1.99 + */ 1.100 + nsresult initialize(nsIFileURL *aFileURL); 1.101 + 1.102 + /** 1.103 + * Fetches runtime status information for this connection. 1.104 + * 1.105 + * @param aStatusOption One of the SQLITE_DBSTATUS options defined at 1.106 + * http://www.sqlite.org/c3ref/c_dbstatus_options.html 1.107 + * @param [optional] aMaxValue if provided, will be set to the highest 1.108 + * istantaneous value. 1.109 + * @return the current value for the specified option. 1.110 + */ 1.111 + int32_t getSqliteRuntimeStatus(int32_t aStatusOption, 1.112 + int32_t* aMaxValue=nullptr); 1.113 + /** 1.114 + * Registers/unregisters a commit hook callback. 1.115 + * 1.116 + * @param aCallbackFn a callback function to be invoked on transactions 1.117 + * commit. Pass nullptr to unregister the current callback. 1.118 + * @param [optional] aData if provided, will be passed to the callback. 1.119 + * @see http://sqlite.org/c3ref/commit_hook.html 1.120 + */ 1.121 + void setCommitHook(int (*aCallbackFn)(void *) , void *aData=nullptr) { 1.122 + MOZ_ASSERT(mDBConn, "A connection must exist at this point"); 1.123 + ::sqlite3_commit_hook(mDBConn, aCallbackFn, aData); 1.124 + }; 1.125 + 1.126 + /** 1.127 + * Lazily creates and returns a background execution thread. In the future, 1.128 + * the thread may be re-claimed if left idle, so you should call this 1.129 + * method just before you dispatch and not save the reference. 1.130 + * 1.131 + * @returns an event target suitable for asynchronous statement execution. 1.132 + */ 1.133 + nsIEventTarget *getAsyncExecutionTarget(); 1.134 + 1.135 + /** 1.136 + * Mutex used by asynchronous statements to protect state. The mutex is 1.137 + * declared on the connection object because there is no contention between 1.138 + * asynchronous statements (they are serialized on mAsyncExecutionThread). 1.139 + * Currently protects: 1.140 + * - Connection.mAsyncExecutionThreadShuttingDown 1.141 + * - Connection.mAsyncExecutionThread 1.142 + * - Connection.mConnectionClosed 1.143 + * - AsyncExecuteStatements.mCancelRequested 1.144 + */ 1.145 + Mutex sharedAsyncExecutionMutex; 1.146 + 1.147 + /** 1.148 + * Wraps the mutex that SQLite gives us from sqlite3_db_mutex. This is public 1.149 + * because we already expose the sqlite3* native connection and proper 1.150 + * operation of the deadlock detector requires everyone to use the same single 1.151 + * SQLiteMutex instance for correctness. 1.152 + */ 1.153 + SQLiteMutex sharedDBMutex; 1.154 + 1.155 + /** 1.156 + * References the thread this database was opened on. This MUST be thread it is 1.157 + * closed on. 1.158 + */ 1.159 + const nsCOMPtr<nsIThread> threadOpenedOn; 1.160 + 1.161 + /** 1.162 + * Closes the SQLite database, and warns about any non-finalized statements. 1.163 + */ 1.164 + nsresult internalClose(sqlite3 *aDBConn); 1.165 + 1.166 + /** 1.167 + * Obtains the filename of the connection. Useful for logging. 1.168 + */ 1.169 + nsCString getFilename(); 1.170 + 1.171 + /** 1.172 + * Creates an sqlite3 prepared statement object from an SQL string. 1.173 + * 1.174 + * @param aNativeConnection 1.175 + * The underlying Sqlite connection to prepare the statement with. 1.176 + * @param aSQL 1.177 + * The SQL statement string to compile. 1.178 + * @param _stmt 1.179 + * New sqlite3_stmt object. 1.180 + * @return the result from sqlite3_prepare_v2. 1.181 + */ 1.182 + int prepareStatement(sqlite3* aNativeConnection, 1.183 + const nsCString &aSQL, sqlite3_stmt **_stmt); 1.184 + 1.185 + /** 1.186 + * Performs a sqlite3_step on aStatement, while properly handling SQLITE_LOCKED 1.187 + * when not on the main thread by waiting until we are notified. 1.188 + * 1.189 + * @param aNativeConnection 1.190 + * The underlying Sqlite connection to step the statement with. 1.191 + * @param aStatement 1.192 + * A pointer to a sqlite3_stmt object. 1.193 + * @return the result from sqlite3_step. 1.194 + */ 1.195 + int stepStatement(sqlite3* aNativeConnection, sqlite3_stmt* aStatement); 1.196 + 1.197 + /** 1.198 + * Raw connection transaction management. 1.199 + * 1.200 + * @see BeginTransactionAs, CommitTransaction, RollbackTransaction. 1.201 + */ 1.202 + nsresult beginTransactionInternal(sqlite3 *aNativeConnection, 1.203 + int32_t aTransactionType=TRANSACTION_DEFERRED); 1.204 + nsresult commitTransactionInternal(sqlite3 *aNativeConnection); 1.205 + nsresult rollbackTransactionInternal(sqlite3 *aNativeConnection); 1.206 + 1.207 + bool connectionReady(); 1.208 + 1.209 + /** 1.210 + * True if this connection is shutting down but not yet closed. 1.211 + */ 1.212 + bool isClosing(); 1.213 + 1.214 + /** 1.215 + * True if the underlying connection is closed. 1.216 + * Any sqlite resources may be lost when this returns true, so nothing should 1.217 + * try to use them. 1.218 + */ 1.219 + bool isClosed(); 1.220 + 1.221 + nsresult initializeClone(Connection *aClone, bool aReadOnly); 1.222 + 1.223 +private: 1.224 + ~Connection(); 1.225 + nsresult initializeInternal(nsIFile *aDatabaseFile); 1.226 + 1.227 + /** 1.228 + * Sets the database into a closed state so no further actions can be 1.229 + * performed. 1.230 + * 1.231 + * @note mDBConn is set to nullptr in this method. 1.232 + */ 1.233 + nsresult setClosedState(); 1.234 + 1.235 + /** 1.236 + * Helper for calls to sqlite3_exec. Reports long delays to Telemetry. 1.237 + * 1.238 + * @param aNativeConnection 1.239 + * The underlying Sqlite connection to execute the query with. 1.240 + * @param aSqlString 1.241 + * SQL string to execute 1.242 + * @return the result from sqlite3_exec. 1.243 + */ 1.244 + int executeSql(sqlite3 *aNativeConnection, const char *aSqlString); 1.245 + 1.246 + /** 1.247 + * Describes a certain primitive type in the database. 1.248 + * 1.249 + * Possible Values Are: 1.250 + * INDEX - To check for the existence of an index 1.251 + * TABLE - To check for the existence of a table 1.252 + */ 1.253 + enum DatabaseElementType { 1.254 + INDEX, 1.255 + TABLE 1.256 + }; 1.257 + 1.258 + /** 1.259 + * Determines if the specified primitive exists. 1.260 + * 1.261 + * @param aElementType 1.262 + * The type of element to check the existence of 1.263 + * @param aElementName 1.264 + * The name of the element to check for 1.265 + * @returns true if element exists, false otherwise 1.266 + */ 1.267 + nsresult databaseElementExists(enum DatabaseElementType aElementType, 1.268 + const nsACString& aElementName, 1.269 + bool *_exists); 1.270 + 1.271 + bool findFunctionByInstance(nsISupports *aInstance); 1.272 + 1.273 + static int sProgressHelper(void *aArg); 1.274 + // Generic progress handler 1.275 + // Dispatch call to registered progress handler, 1.276 + // if there is one. Do nothing in other cases. 1.277 + int progressHandler(); 1.278 + 1.279 + sqlite3 *mDBConn; 1.280 + nsCOMPtr<nsIFileURL> mFileURL; 1.281 + nsCOMPtr<nsIFile> mDatabaseFile; 1.282 + 1.283 + /** 1.284 + * Lazily created thread for asynchronous statement execution. Consumers 1.285 + * should use getAsyncExecutionTarget rather than directly accessing this 1.286 + * field. 1.287 + */ 1.288 + nsCOMPtr<nsIThread> mAsyncExecutionThread; 1.289 + 1.290 + /** 1.291 + * Set to true by Close() or AsyncClose() prior to shutdown. 1.292 + * 1.293 + * If false, we guarantee both that the underlying sqlite3 database 1.294 + * connection is still open and that getAsyncExecutionTarget() can 1.295 + * return a thread. Once true, either the sqlite3 database 1.296 + * connection is being shutdown or it has been 1.297 + * shutdown. Additionally, once true, getAsyncExecutionTarget() 1.298 + * returns null. 1.299 + * 1.300 + * This variable should be accessed while holding the 1.301 + * sharedAsyncExecutionMutex. 1.302 + */ 1.303 + bool mAsyncExecutionThreadShuttingDown; 1.304 + 1.305 + /** 1.306 + * Set to true just prior to calling sqlite3_close on the 1.307 + * connection. 1.308 + * 1.309 + * This variable should be accessed while holding the 1.310 + * sharedAsyncExecutionMutex. 1.311 + */ 1.312 + bool mConnectionClosed; 1.313 + 1.314 + /** 1.315 + * Tracks if we have a transaction in progress or not. Access protected by 1.316 + * sharedDBMutex. 1.317 + */ 1.318 + bool mTransactionInProgress; 1.319 + 1.320 + /** 1.321 + * Stores the mapping of a given function by name to its instance. Access is 1.322 + * protected by sharedDBMutex. 1.323 + */ 1.324 + nsDataHashtable<nsCStringHashKey, FunctionInfo> mFunctions; 1.325 + 1.326 + /** 1.327 + * Stores the registered progress handler for the database connection. Access 1.328 + * is protected by sharedDBMutex. 1.329 + */ 1.330 + nsCOMPtr<mozIStorageProgressHandler> mProgressHandler; 1.331 + 1.332 + /** 1.333 + * Stores the flags we passed to sqlite3_open_v2. 1.334 + */ 1.335 + const int mFlags; 1.336 + 1.337 + // This is here for two reasons: 1) It's used to make sure that the 1.338 + // connections do not outlive the service. 2) Our custom collating functions 1.339 + // call its localeCompareStrings() method. 1.340 + nsRefPtr<Service> mStorageService; 1.341 + 1.342 + /** 1.343 + * If |false|, this instance supports synchronous operations 1.344 + * and it can be cast to |mozIStorageConnection|. 1.345 + */ 1.346 + const bool mAsyncOnly; 1.347 +}; 1.348 + 1.349 + 1.350 +/** 1.351 + * A Runnable designed to call a mozIStorageCompletionCallback on 1.352 + * the appropriate thread. 1.353 + */ 1.354 +class CallbackComplete MOZ_FINAL : public nsRunnable 1.355 +{ 1.356 +public: 1.357 + /** 1.358 + * @param aValue The result to pass to the callback. It must 1.359 + * already be owned by the main thread. 1.360 + * @param aCallback The callback. It must already be owned by the 1.361 + * main thread. 1.362 + */ 1.363 + CallbackComplete(nsresult aStatus, 1.364 + nsISupports* aValue, 1.365 + already_AddRefed<mozIStorageCompletionCallback> aCallback) 1.366 + : mStatus(aStatus) 1.367 + , mValue(aValue) 1.368 + , mCallback(aCallback) 1.369 + { 1.370 + } 1.371 + 1.372 + NS_IMETHOD Run() { 1.373 + MOZ_ASSERT(NS_IsMainThread()); 1.374 + nsresult rv = mCallback->Complete(mStatus, mValue); 1.375 + 1.376 + // Ensure that we release on the main thread 1.377 + mValue = nullptr; 1.378 + mCallback = nullptr; 1.379 + return rv; 1.380 + } 1.381 + 1.382 +private: 1.383 + nsresult mStatus; 1.384 + nsCOMPtr<nsISupports> mValue; 1.385 + // This is a nsRefPtr<T> and not a nsCOMPtr<T> because 1.386 + // nsCOMP<T> would cause an off-main thread QI, which 1.387 + // is not a good idea (and crashes XPConnect). 1.388 + nsRefPtr<mozIStorageCompletionCallback> mCallback; 1.389 +}; 1.390 + 1.391 +} // namespace storage 1.392 +} // namespace mozilla 1.393 + 1.394 +#endif // mozilla_storage_Connection_h