LCOV - code coverage report
Current view: top level - storage - mozStorageConnection.h (source / functions) Hit Total Coverage
Test: output.info Lines: 14 16 87.5 %
Date: 2017-07-14 16:53:18 Functions: 9 11 81.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : class nsIFile;
      31             : class nsIFileURL;
      32             : class nsIEventTarget;
      33             : class nsIThread;
      34             : 
      35             : namespace mozilla {
      36             : namespace storage {
      37             : 
      38             : class Connection final : public mozIStorageConnection
      39             :                        , public nsIInterfaceRequestor
      40             : {
      41             : public:
      42             :   NS_DECL_THREADSAFE_ISUPPORTS
      43             :   NS_DECL_MOZISTORAGEASYNCCONNECTION
      44             :   NS_DECL_MOZISTORAGECONNECTION
      45             :   NS_DECL_NSIINTERFACEREQUESTOR
      46             : 
      47             :   /**
      48             :    * Structure used to describe user functions on the database connection.
      49             :    */
      50          64 :   struct FunctionInfo {
      51             :     enum FunctionType {
      52             :       SIMPLE,
      53             :       AGGREGATE
      54             :     };
      55             : 
      56             :     nsCOMPtr<nsISupports> function;
      57             :     FunctionType type;
      58             :     int32_t numArgs;
      59             :   };
      60             : 
      61             :   /**
      62             :    * @param aService
      63             :    *        Pointer to the storage service.  Held onto for the lifetime of the
      64             :    *        connection.
      65             :    * @param aFlags
      66             :    *        The flags to pass to sqlite3_open_v2.
      67             :    * @param aAsyncOnly
      68             :    *        If |true|, the Connection only implements asynchronous interface:
      69             :    *        - |mozIStorageAsyncConnection|;
      70             :    *        If |false|, the result also implements synchronous interface:
      71             :    *        - |mozIStorageConnection|.
      72             :    * @param aIgnoreLockingMode
      73             :    *        If |true|, ignore locks in force on the file. Only usable with
      74             :    *        read-only connections. Defaults to false.
      75             :    *        Use with extreme caution. If sqlite ignores locks, reads may fail
      76             :    *        indicating database corruption (the database won't actually be
      77             :    *        corrupt) or produce wrong results without any indication that has
      78             :    *        happened.
      79             :    */
      80             :   Connection(Service *aService, int aFlags, bool aAsyncOnly,
      81             :              bool aIgnoreLockingMode = false);
      82             : 
      83             :   /**
      84             :    * Creates the connection to an in-memory database.
      85             :    */
      86             :   nsresult initialize();
      87             : 
      88             :   /**
      89             :    * Creates the connection to the database.
      90             :    *
      91             :    * @param aDatabaseFile
      92             :    *        The nsIFile of the location of the database to open, or create if it
      93             :    *        does not exist.
      94             :    */
      95             :   nsresult initialize(nsIFile *aDatabaseFile);
      96             : 
      97             :   /**
      98             :    * Creates the connection to the database.
      99             :    *
     100             :    * @param aFileURL
     101             :    *        The nsIFileURL of the location of the database to open, or create if it
     102             :    *        does not exist.
     103             :    */
     104             :   nsresult initialize(nsIFileURL *aFileURL);
     105             : 
     106             :   /**
     107             :    * Same as initialize, but to be used on the async thread.
     108             :    */
     109             :   nsresult initializeOnAsyncThread(nsIFile* aStorageFile);
     110             : 
     111             :   /**
     112             :    * Fetches runtime status information for this connection.
     113             :    *
     114             :    * @param aStatusOption One of the SQLITE_DBSTATUS options defined at
     115             :    *        http://www.sqlite.org/c3ref/c_dbstatus_options.html
     116             :    * @param [optional] aMaxValue if provided, will be set to the highest
     117             :    *        istantaneous value.
     118             :    * @return the current value for the specified option.
     119             :    */
     120             :   int32_t getSqliteRuntimeStatus(int32_t aStatusOption,
     121             :                                  int32_t* aMaxValue=nullptr);
     122             :   /**
     123             :    * Registers/unregisters a commit hook callback.
     124             :    *
     125             :    * @param aCallbackFn a callback function to be invoked on transactions
     126             :    *        commit.  Pass nullptr to unregister the current callback.
     127             :    * @param [optional] aData if provided, will be passed to the callback.
     128             :    * @see http://sqlite.org/c3ref/commit_hook.html
     129             :    */
     130             :   void setCommitHook(int (*aCallbackFn)(void *) , void *aData=nullptr) {
     131             :     MOZ_ASSERT(mDBConn, "A connection must exist at this point");
     132             :     ::sqlite3_commit_hook(mDBConn, aCallbackFn, aData);
     133             :   };
     134             : 
     135             :   /**
     136             :    * Gets autocommit status.
     137             :    */
     138           0 :   bool getAutocommit() {
     139           0 :     return mDBConn && static_cast<bool>(::sqlite3_get_autocommit(mDBConn));
     140             :   };
     141             : 
     142             :   /**
     143             :    * Lazily creates and returns a background execution thread.  In the future,
     144             :    * the thread may be re-claimed if left idle, so you should call this
     145             :    * method just before you dispatch and not save the reference.
     146             :    *
     147             :    * This must be called from the opener thread.
     148             :    *
     149             :    * @return an event target suitable for asynchronous statement execution.
     150             :    * @note This method will return null once AsyncClose() has been called.
     151             :    */
     152             :   nsIEventTarget *getAsyncExecutionTarget();
     153             : 
     154             :   /**
     155             :    * Mutex used by asynchronous statements to protect state.  The mutex is
     156             :    * declared on the connection object because there is no contention between
     157             :    * asynchronous statements (they are serialized on mAsyncExecutionThread).
     158             :    * Currently protects:
     159             :    *  - Connection.mAsyncExecutionThreadShuttingDown
     160             :    *  - Connection.mConnectionClosed
     161             :    *  - AsyncExecuteStatements.mCancelRequested
     162             :    */
     163             :   Mutex sharedAsyncExecutionMutex;
     164             : 
     165             :   /**
     166             :    * Wraps the mutex that SQLite gives us from sqlite3_db_mutex.  This is public
     167             :    * because we already expose the sqlite3* native connection and proper
     168             :    * operation of the deadlock detector requires everyone to use the same single
     169             :    * SQLiteMutex instance for correctness.
     170             :    */
     171             :   SQLiteMutex sharedDBMutex;
     172             : 
     173             :   /**
     174             :    * References the thread this database was opened on.  This MUST be thread it is
     175             :    * closed on.
     176             :    */
     177             :   const nsCOMPtr<nsIThread> threadOpenedOn;
     178             : 
     179             :   /**
     180             :    * Closes the SQLite database, and warns about any non-finalized statements.
     181             :    */
     182             :   nsresult internalClose(sqlite3 *aDBConn);
     183             : 
     184             :   /**
     185             :    * Shuts down the passed-in async thread.
     186             :    */
     187             :   void shutdownAsyncThread();
     188             : 
     189             :   /**
     190             :    * Obtains the filename of the connection.  Useful for logging.
     191             :    */
     192             :   nsCString getFilename();
     193             : 
     194             :   /**
     195             :    * Creates an sqlite3 prepared statement object from an SQL string.
     196             :    *
     197             :    * @param aNativeConnection
     198             :    *        The underlying Sqlite connection to prepare the statement with.
     199             :    * @param aSQL
     200             :    *        The SQL statement string to compile.
     201             :    * @param _stmt
     202             :    *        New sqlite3_stmt object.
     203             :    * @return the result from sqlite3_prepare_v2.
     204             :    */
     205             :   int prepareStatement(sqlite3* aNativeConnection,
     206             :                        const nsCString &aSQL, sqlite3_stmt **_stmt);
     207             : 
     208             :   /**
     209             :    * Performs a sqlite3_step on aStatement, while properly handling SQLITE_LOCKED
     210             :    * when not on the main thread by waiting until we are notified.
     211             :    *
     212             :    * @param aNativeConnection
     213             :    *        The underlying Sqlite connection to step the statement with.
     214             :    * @param aStatement
     215             :    *        A pointer to a sqlite3_stmt object.
     216             :    * @return the result from sqlite3_step.
     217             :    */
     218             :   int stepStatement(sqlite3* aNativeConnection, sqlite3_stmt* aStatement);
     219             : 
     220             :   /**
     221             :    * Raw connection transaction management.
     222             :    *
     223             :    * @see BeginTransactionAs, CommitTransaction, RollbackTransaction.
     224             :    */
     225             :   nsresult beginTransactionInternal(sqlite3 *aNativeConnection,
     226             :                                     int32_t aTransactionType=TRANSACTION_DEFERRED);
     227             :   nsresult commitTransactionInternal(sqlite3 *aNativeConnection);
     228             :   nsresult rollbackTransactionInternal(sqlite3 *aNativeConnection);
     229             : 
     230             :   bool connectionReady();
     231             : 
     232             :   /**
     233             :    * Thread-aware version of connectionReady, results per caller's thread are:
     234             :    *  - owner thread: Same as connectionReady().  True means we have a valid,
     235             :    *    un-closed database connection and it's not going away until you invoke
     236             :    *    Close() or AsyncClose().
     237             :    *  - async thread: Returns true at all times because you can't schedule
     238             :    *    runnables against the async thread after AsyncClose() has been called.
     239             :    *    Therefore, the connection is still around if your code is running.
     240             :    *  - any other thread: Race-prone Lies!  If you are main-thread code in
     241             :    *    mozStorageService iterating over the list of connections, you need to
     242             :    *    acquire the sharedAsyncExecutionMutex for the connection, invoke
     243             :    *    connectionReady() while holding it, and then continue to hold it while
     244             :    *    you do whatever you need to do.  This is because of off-main-thread
     245             :    *    consumers like dom/cache and IndexedDB and other QuotaManager clients.
     246             :    */
     247             :   bool isConnectionReadyOnThisThread();
     248             : 
     249             :   /**
     250             :    * True if this connection has inited shutdown.
     251             :    */
     252             :   bool isClosing();
     253             : 
     254             :   /**
     255             :    * True if the underlying connection is closed.
     256             :    * Any sqlite resources may be lost when this returns true, so nothing should
     257             :    * try to use them.
     258             :    * This locks on sharedAsyncExecutionMutex.
     259             :    */
     260             :   bool isClosed();
     261             : 
     262             :   /**
     263             :    * Same as isClosed(), but takes a proof-of-lock instead of locking internally.
     264             :    */
     265             :   bool isClosed(MutexAutoLock& lock);
     266             : 
     267             :   /**
     268             :    * True if the async execution thread is alive and able to be used (i.e., it
     269             :    * is not in the process of shutting down.)
     270             :    *
     271             :    * This must be called from the opener thread.
     272             :    */
     273             :   bool isAsyncExecutionThreadAvailable();
     274             : 
     275             :   nsresult initializeClone(Connection *aClone, bool aReadOnly);
     276             : 
     277             : private:
     278             :   ~Connection();
     279             :   nsresult initializeInternal();
     280             : 
     281             :   /**
     282             :    * Sets the database into a closed state so no further actions can be
     283             :    * performed.
     284             :    *
     285             :    * @note mDBConn is set to nullptr in this method.
     286             :    */
     287             :   nsresult setClosedState();
     288             : 
     289             :   /**
     290             :    * Helper for calls to sqlite3_exec. Reports long delays to Telemetry.
     291             :    *
     292             :    * @param aNativeConnection
     293             :    *        The underlying Sqlite connection to execute the query with.
     294             :    * @param aSqlString
     295             :    *        SQL string to execute
     296             :    * @return the result from sqlite3_exec.
     297             :    */
     298             :   int executeSql(sqlite3 *aNativeConnection, const char *aSqlString);
     299             : 
     300             :   /**
     301             :    * Describes a certain primitive type in the database.
     302             :    *
     303             :    * Possible Values Are:
     304             :    *  INDEX - To check for the existence of an index
     305             :    *  TABLE - To check for the existence of a table
     306             :    */
     307             :   enum DatabaseElementType {
     308             :     INDEX,
     309             :     TABLE
     310             :   };
     311             : 
     312             :   /**
     313             :    * Determines if the specified primitive exists.
     314             :    *
     315             :    * @param aElementType
     316             :    *        The type of element to check the existence of
     317             :    * @param aElementName
     318             :    *        The name of the element to check for
     319             :    * @returns true if element exists, false otherwise
     320             :    */
     321             :   nsresult databaseElementExists(enum DatabaseElementType aElementType,
     322             :                                  const nsACString& aElementName,
     323             :                                  bool *_exists);
     324             : 
     325             :   bool findFunctionByInstance(nsISupports *aInstance);
     326             : 
     327             :   static int sProgressHelper(void *aArg);
     328             :   // Generic progress handler
     329             :   // Dispatch call to registered progress handler,
     330             :   // if there is one. Do nothing in other cases.
     331             :   int progressHandler();
     332             : 
     333             :   sqlite3 *mDBConn;
     334             :   nsCOMPtr<nsIFileURL> mFileURL;
     335             :   nsCOMPtr<nsIFile> mDatabaseFile;
     336             : 
     337             :   /**
     338             :    * The filename that will be reported to telemetry for this connection. By
     339             :    * default this will be the leaf of the path to the database file.
     340             :   */
     341             :   nsCString mTelemetryFilename;
     342             : 
     343             :   /**
     344             :    * Lazily created thread for asynchronous statement execution.  Consumers
     345             :    * should use getAsyncExecutionTarget rather than directly accessing this
     346             :    * field.
     347             :    *
     348             :    * This must be modified only on the opener thread.
     349             :    */
     350             :   nsCOMPtr<nsIThread> mAsyncExecutionThread;
     351             : 
     352             :   /**
     353             :    * Set to true by Close() or AsyncClose() prior to shutdown.
     354             :    *
     355             :    * If false, we guarantee both that the underlying sqlite3 database
     356             :    * connection is still open and that getAsyncExecutionTarget() can
     357             :    * return a thread. Once true, either the sqlite3 database
     358             :    * connection is being shutdown or it has been
     359             :    * shutdown. Additionally, once true, getAsyncExecutionTarget()
     360             :    * returns null.
     361             :    *
     362             :    * This variable should be accessed while holding the
     363             :    * sharedAsyncExecutionMutex.
     364             :    */
     365             :   bool mAsyncExecutionThreadShuttingDown;
     366             : 
     367             :   /**
     368             :    * Set to true just prior to calling sqlite3_close on the
     369             :    * connection.
     370             :    *
     371             :    * This variable should be accessed while holding the
     372             :    * sharedAsyncExecutionMutex.
     373             :    */
     374             :   bool mConnectionClosed;
     375             : 
     376             :   /**
     377             :    * Tracks if we have a transaction in progress or not.  Access protected by
     378             :    * sharedDBMutex.
     379             :    */
     380             :   bool mTransactionInProgress;
     381             : 
     382             :   /**
     383             :    * Stores the mapping of a given function by name to its instance.  Access is
     384             :    * protected by sharedDBMutex.
     385             :    */
     386             :   nsDataHashtable<nsCStringHashKey, FunctionInfo> mFunctions;
     387             : 
     388             :   /**
     389             :    * Stores the registered progress handler for the database connection.  Access
     390             :    * is protected by sharedDBMutex.
     391             :    */
     392             :   nsCOMPtr<mozIStorageProgressHandler> mProgressHandler;
     393             : 
     394             :   /**
     395             :    * Stores the flags we passed to sqlite3_open_v2.
     396             :    */
     397             :   const int mFlags;
     398             : 
     399             :   /**
     400             :    * Stores whether we should ask sqlite3_open_v2 to ignore locking.
     401             :    */
     402             :   const bool mIgnoreLockingMode;
     403             : 
     404             :   // This is here for two reasons: 1) It's used to make sure that the
     405             :   // connections do not outlive the service.  2) Our custom collating functions
     406             :   // call its localeCompareStrings() method.
     407             :   RefPtr<Service> mStorageService;
     408             : 
     409             :   /**
     410             :    * If |false|, this instance supports synchronous operations
     411             :    * and it can be cast to |mozIStorageConnection|.
     412             :    */
     413             :   const bool mAsyncOnly;
     414             : };
     415             : 
     416             : 
     417             : /**
     418             :  * A Runnable designed to call a mozIStorageCompletionCallback on
     419             :  * the appropriate thread.
     420             :  */
     421           3 : class CallbackComplete final : public Runnable
     422             : {
     423             : public:
     424             :   /**
     425             :    * @param aValue The result to pass to the callback. It must
     426             :    *               already be owned by the main thread.
     427             :    * @param aCallback The callback. It must already be owned by the
     428             :    *                  main thread.
     429             :    */
     430           1 :   CallbackComplete(nsresult aStatus,
     431             :                    nsISupports* aValue,
     432             :                    already_AddRefed<mozIStorageCompletionCallback> aCallback)
     433           1 :     : Runnable("storage::CallbackComplete")
     434             :     , mStatus(aStatus)
     435             :     , mValue(aValue)
     436           1 :     , mCallback(aCallback)
     437             :   {
     438           1 :   }
     439             : 
     440           1 :   NS_IMETHOD Run() override {
     441           1 :     MOZ_ASSERT(NS_IsMainThread());
     442           1 :     nsresult rv = mCallback->Complete(mStatus, mValue);
     443             : 
     444             :     // Ensure that we release on the main thread
     445           1 :     mValue = nullptr;
     446           1 :     mCallback = nullptr;
     447           1 :     return rv;
     448             :   }
     449             : 
     450             : private:
     451             :   nsresult mStatus;
     452             :   nsCOMPtr<nsISupports> mValue;
     453             :   // This is a RefPtr<T> and not a nsCOMPtr<T> because
     454             :   // nsCOMP<T> would cause an off-main thread QI, which
     455             :   // is not a good idea (and crashes XPConnect).
     456             :   RefPtr<mozIStorageCompletionCallback> mCallback;
     457             : };
     458             : 
     459             : } // namespace storage
     460             : } // namespace mozilla
     461             : 
     462             : /**
     463             :  * Casting Connection to nsISupports is ambiguous.
     464             :  * This method handles that.
     465             :  */
     466             : inline nsISupports*
     467           8 : ToSupports(mozilla::storage::Connection* p)
     468             : {
     469           8 :   return NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*, p);
     470             : }
     471             : 
     472             : #endif // mozilla_storage_Connection_h

Generated by: LCOV version 1.13