summaryrefslogtreecommitdiffstats
path: root/storage/mozStorageConnection.h
diff options
context:
space:
mode:
Diffstat (limited to 'storage/mozStorageConnection.h')
-rw-r--r--storage/mozStorageConnection.h439
1 files changed, 439 insertions, 0 deletions
diff --git a/storage/mozStorageConnection.h b/storage/mozStorageConnection.h
new file mode 100644
index 000000000..979ac6436
--- /dev/null
+++ b/storage/mozStorageConnection.h
@@ -0,0 +1,439 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_storage_Connection_h
+#define mozilla_storage_Connection_h
+
+#include "nsAutoPtr.h"
+#include "nsCOMPtr.h"
+#include "mozilla/Mutex.h"
+#include "nsProxyRelease.h"
+#include "nsThreadUtils.h"
+#include "nsIInterfaceRequestor.h"
+
+#include "nsDataHashtable.h"
+#include "mozIStorageProgressHandler.h"
+#include "SQLiteMutex.h"
+#include "mozIStorageConnection.h"
+#include "mozStorageService.h"
+#include "mozIStorageAsyncConnection.h"
+#include "mozIStorageCompletionCallback.h"
+
+#include "nsIMutableArray.h"
+#include "mozilla/Attributes.h"
+
+#include "sqlite3.h"
+
+class nsIFile;
+class nsIFileURL;
+class nsIEventTarget;
+class nsIThread;
+
+namespace mozilla {
+namespace storage {
+
+class Connection final : public mozIStorageConnection
+ , public nsIInterfaceRequestor
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_MOZISTORAGEASYNCCONNECTION
+ NS_DECL_MOZISTORAGECONNECTION
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+ /**
+ * Structure used to describe user functions on the database connection.
+ */
+ struct FunctionInfo {
+ enum FunctionType {
+ SIMPLE,
+ AGGREGATE
+ };
+
+ nsCOMPtr<nsISupports> function;
+ FunctionType type;
+ int32_t numArgs;
+ };
+
+ /**
+ * @param aService
+ * Pointer to the storage service. Held onto for the lifetime of the
+ * connection.
+ * @param aFlags
+ * The flags to pass to sqlite3_open_v2.
+ * @param aAsyncOnly
+ * If |true|, the Connection only implements asynchronous interface:
+ * - |mozIStorageAsyncConnection|;
+ * If |false|, the result also implements synchronous interface:
+ * - |mozIStorageConnection|.
+ * @param aIgnoreLockingMode
+ * If |true|, ignore locks in force on the file. Only usable with
+ * read-only connections. Defaults to false.
+ * Use with extreme caution. If sqlite ignores locks, reads may fail
+ * indicating database corruption (the database won't actually be
+ * corrupt) or produce wrong results without any indication that has
+ * happened.
+ */
+ Connection(Service *aService, int aFlags, bool aAsyncOnly,
+ bool aIgnoreLockingMode = false);
+
+ /**
+ * Creates the connection to an in-memory database.
+ */
+ nsresult initialize();
+
+ /**
+ * Creates the connection to the database.
+ *
+ * @param aDatabaseFile
+ * The nsIFile of the location of the database to open, or create if it
+ * does not exist.
+ */
+ nsresult initialize(nsIFile *aDatabaseFile);
+
+ /**
+ * Creates the connection to the database.
+ *
+ * @param aFileURL
+ * The nsIFileURL of the location of the database to open, or create if it
+ * does not exist.
+ */
+ nsresult initialize(nsIFileURL *aFileURL);
+
+ /**
+ * Fetches runtime status information for this connection.
+ *
+ * @param aStatusOption One of the SQLITE_DBSTATUS options defined at
+ * http://www.sqlite.org/c3ref/c_dbstatus_options.html
+ * @param [optional] aMaxValue if provided, will be set to the highest
+ * istantaneous value.
+ * @return the current value for the specified option.
+ */
+ int32_t getSqliteRuntimeStatus(int32_t aStatusOption,
+ int32_t* aMaxValue=nullptr);
+ /**
+ * Registers/unregisters a commit hook callback.
+ *
+ * @param aCallbackFn a callback function to be invoked on transactions
+ * commit. Pass nullptr to unregister the current callback.
+ * @param [optional] aData if provided, will be passed to the callback.
+ * @see http://sqlite.org/c3ref/commit_hook.html
+ */
+ void setCommitHook(int (*aCallbackFn)(void *) , void *aData=nullptr) {
+ MOZ_ASSERT(mDBConn, "A connection must exist at this point");
+ ::sqlite3_commit_hook(mDBConn, aCallbackFn, aData);
+ };
+
+ /**
+ * Gets autocommit status.
+ */
+ bool getAutocommit() {
+ return mDBConn && static_cast<bool>(::sqlite3_get_autocommit(mDBConn));
+ };
+
+ /**
+ * Lazily creates and returns a background execution thread. In the future,
+ * the thread may be re-claimed if left idle, so you should call this
+ * method just before you dispatch and not save the reference.
+ *
+ * @returns an event target suitable for asynchronous statement execution.
+ */
+ nsIEventTarget *getAsyncExecutionTarget();
+
+ /**
+ * Mutex used by asynchronous statements to protect state. The mutex is
+ * declared on the connection object because there is no contention between
+ * asynchronous statements (they are serialized on mAsyncExecutionThread).
+ * Currently protects:
+ * - Connection.mAsyncExecutionThreadShuttingDown
+ * - Connection.mAsyncExecutionThread
+ * - Connection.mConnectionClosed
+ * - AsyncExecuteStatements.mCancelRequested
+ */
+ Mutex sharedAsyncExecutionMutex;
+
+ /**
+ * Wraps the mutex that SQLite gives us from sqlite3_db_mutex. This is public
+ * because we already expose the sqlite3* native connection and proper
+ * operation of the deadlock detector requires everyone to use the same single
+ * SQLiteMutex instance for correctness.
+ */
+ SQLiteMutex sharedDBMutex;
+
+ /**
+ * References the thread this database was opened on. This MUST be thread it is
+ * closed on.
+ */
+ const nsCOMPtr<nsIThread> threadOpenedOn;
+
+ /**
+ * Closes the SQLite database, and warns about any non-finalized statements.
+ */
+ nsresult internalClose(sqlite3 *aDBConn);
+
+ /**
+ * Shuts down the passed-in async thread.
+ */
+ void shutdownAsyncThread(nsIThread *aAsyncThread);
+
+ /**
+ * Obtains the filename of the connection. Useful for logging.
+ */
+ nsCString getFilename();
+
+ /**
+ * Creates an sqlite3 prepared statement object from an SQL string.
+ *
+ * @param aNativeConnection
+ * The underlying Sqlite connection to prepare the statement with.
+ * @param aSQL
+ * The SQL statement string to compile.
+ * @param _stmt
+ * New sqlite3_stmt object.
+ * @return the result from sqlite3_prepare_v2.
+ */
+ int prepareStatement(sqlite3* aNativeConnection,
+ const nsCString &aSQL, sqlite3_stmt **_stmt);
+
+ /**
+ * Performs a sqlite3_step on aStatement, while properly handling SQLITE_LOCKED
+ * when not on the main thread by waiting until we are notified.
+ *
+ * @param aNativeConnection
+ * The underlying Sqlite connection to step the statement with.
+ * @param aStatement
+ * A pointer to a sqlite3_stmt object.
+ * @return the result from sqlite3_step.
+ */
+ int stepStatement(sqlite3* aNativeConnection, sqlite3_stmt* aStatement);
+
+ /**
+ * Raw connection transaction management.
+ *
+ * @see BeginTransactionAs, CommitTransaction, RollbackTransaction.
+ */
+ nsresult beginTransactionInternal(sqlite3 *aNativeConnection,
+ int32_t aTransactionType=TRANSACTION_DEFERRED);
+ nsresult commitTransactionInternal(sqlite3 *aNativeConnection);
+ nsresult rollbackTransactionInternal(sqlite3 *aNativeConnection);
+
+ bool connectionReady();
+
+ /**
+ * True if this connection is shutting down but not yet closed.
+ */
+ bool isClosing();
+
+ /**
+ * True if the underlying connection is closed.
+ * Any sqlite resources may be lost when this returns true, so nothing should
+ * try to use them.
+ */
+ bool isClosed();
+
+ nsresult initializeClone(Connection *aClone, bool aReadOnly);
+
+private:
+ ~Connection();
+ nsresult initializeInternal();
+
+ /**
+ * Sets the database into a closed state so no further actions can be
+ * performed.
+ *
+ * @note mDBConn is set to nullptr in this method.
+ */
+ nsresult setClosedState();
+
+ /**
+ * Helper for calls to sqlite3_exec. Reports long delays to Telemetry.
+ *
+ * @param aNativeConnection
+ * The underlying Sqlite connection to execute the query with.
+ * @param aSqlString
+ * SQL string to execute
+ * @return the result from sqlite3_exec.
+ */
+ int executeSql(sqlite3 *aNativeConnection, const char *aSqlString);
+
+ /**
+ * Describes a certain primitive type in the database.
+ *
+ * Possible Values Are:
+ * INDEX - To check for the existence of an index
+ * TABLE - To check for the existence of a table
+ */
+ enum DatabaseElementType {
+ INDEX,
+ TABLE
+ };
+
+ /**
+ * Determines if the specified primitive exists.
+ *
+ * @param aElementType
+ * The type of element to check the existence of
+ * @param aElementName
+ * The name of the element to check for
+ * @returns true if element exists, false otherwise
+ */
+ nsresult databaseElementExists(enum DatabaseElementType aElementType,
+ const nsACString& aElementName,
+ bool *_exists);
+
+ bool findFunctionByInstance(nsISupports *aInstance);
+
+ static int sProgressHelper(void *aArg);
+ // Generic progress handler
+ // Dispatch call to registered progress handler,
+ // if there is one. Do nothing in other cases.
+ int progressHandler();
+
+ sqlite3 *mDBConn;
+ nsCOMPtr<nsIFileURL> mFileURL;
+ nsCOMPtr<nsIFile> mDatabaseFile;
+
+ /**
+ * The filename that will be reported to telemetry for this connection. By
+ * default this will be the leaf of the path to the database file.
+ */
+ nsCString mTelemetryFilename;
+
+ /**
+ * Lazily created thread for asynchronous statement execution. Consumers
+ * should use getAsyncExecutionTarget rather than directly accessing this
+ * field.
+ */
+ nsCOMPtr<nsIThread> mAsyncExecutionThread;
+
+ /**
+ * Set to true by Close() or AsyncClose() prior to shutdown.
+ *
+ * If false, we guarantee both that the underlying sqlite3 database
+ * connection is still open and that getAsyncExecutionTarget() can
+ * return a thread. Once true, either the sqlite3 database
+ * connection is being shutdown or it has been
+ * shutdown. Additionally, once true, getAsyncExecutionTarget()
+ * returns null.
+ *
+ * This variable should be accessed while holding the
+ * sharedAsyncExecutionMutex.
+ */
+ bool mAsyncExecutionThreadShuttingDown;
+
+ /**
+ * Tracks whether the async thread has been initialized and Shutdown() has
+ * not yet been invoked on it.
+ */
+#ifdef DEBUG
+ bool mAsyncExecutionThreadIsAlive;
+#endif
+
+ /**
+ * Set to true just prior to calling sqlite3_close on the
+ * connection.
+ *
+ * This variable should be accessed while holding the
+ * sharedAsyncExecutionMutex.
+ */
+ bool mConnectionClosed;
+
+ /**
+ * Tracks if we have a transaction in progress or not. Access protected by
+ * sharedDBMutex.
+ */
+ bool mTransactionInProgress;
+
+ /**
+ * Stores the mapping of a given function by name to its instance. Access is
+ * protected by sharedDBMutex.
+ */
+ nsDataHashtable<nsCStringHashKey, FunctionInfo> mFunctions;
+
+ /**
+ * Stores the registered progress handler for the database connection. Access
+ * is protected by sharedDBMutex.
+ */
+ nsCOMPtr<mozIStorageProgressHandler> mProgressHandler;
+
+ /**
+ * Stores the flags we passed to sqlite3_open_v2.
+ */
+ const int mFlags;
+
+ /**
+ * Stores whether we should ask sqlite3_open_v2 to ignore locking.
+ */
+ const bool mIgnoreLockingMode;
+
+ // This is here for two reasons: 1) It's used to make sure that the
+ // connections do not outlive the service. 2) Our custom collating functions
+ // call its localeCompareStrings() method.
+ RefPtr<Service> mStorageService;
+
+ /**
+ * If |false|, this instance supports synchronous operations
+ * and it can be cast to |mozIStorageConnection|.
+ */
+ const bool mAsyncOnly;
+};
+
+
+/**
+ * A Runnable designed to call a mozIStorageCompletionCallback on
+ * the appropriate thread.
+ */
+class CallbackComplete final : public Runnable
+{
+public:
+ /**
+ * @param aValue The result to pass to the callback. It must
+ * already be owned by the main thread.
+ * @param aCallback The callback. It must already be owned by the
+ * main thread.
+ */
+ CallbackComplete(nsresult aStatus,
+ nsISupports* aValue,
+ already_AddRefed<mozIStorageCompletionCallback> aCallback)
+ : mStatus(aStatus)
+ , mValue(aValue)
+ , mCallback(aCallback)
+ {
+ }
+
+ NS_IMETHOD Run() override {
+ MOZ_ASSERT(NS_IsMainThread());
+ nsresult rv = mCallback->Complete(mStatus, mValue);
+
+ // Ensure that we release on the main thread
+ mValue = nullptr;
+ mCallback = nullptr;
+ return rv;
+ }
+
+private:
+ nsresult mStatus;
+ nsCOMPtr<nsISupports> mValue;
+ // This is a RefPtr<T> and not a nsCOMPtr<T> because
+ // nsCOMP<T> would cause an off-main thread QI, which
+ // is not a good idea (and crashes XPConnect).
+ RefPtr<mozIStorageCompletionCallback> mCallback;
+};
+
+} // namespace storage
+} // namespace mozilla
+
+/**
+ * Casting Connection to nsISupports is ambiguous.
+ * This method handles that.
+ */
+inline nsISupports*
+ToSupports(mozilla::storage::Connection* p)
+{
+ return NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*, p);
+}
+
+#endif // mozilla_storage_Connection_h