1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
/* 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_places_ConcurrentConnection_h_
#define mozilla_places_ConcurrentConnection_h_
#include "mozilla/storage/StatementCache.h"
#include "mozIStorageCompletionCallback.h"
#include "mozIStorageStatementCallback.h"
#include "Helpers.h"
#include "nsCOMPtr.h"
#include "nsDeque.h"
#include "nsIAsyncShutdown.h"
#include "nsIObserver.h"
#include "nsISupportsImpl.h"
#include "nsWeakReference.h"
namespace mozilla::places {
/**
* Tracks all the necessary information to asynchronously run a query, and
* call back once done.
*/
struct PendingQuery final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PendingQuery);
PendingQuery(const nsCString& aSQL, PendingStatementCallback* aCallback)
: mSQL(aSQL), mCallback(aCallback) {}
nsCString mSQL;
RefPtr<PendingStatementCallback> mCallback;
private:
~PendingQuery() = default;
};
/**
* Wraps a concurrent SQLite connection, that has zero dependencies on Places.
* This is useful to read from the database without fully initializing the
* whole Places subsystem, e.g. link coloring, favicons...
*
* Since this is lacking any capability of setting up the database file, if it
* doesn't exist, or has an outdated schema version, it will queue up requests
* and await for Places to start up fully.
*/
class ConcurrentConnection final : public nsIObserver,
public nsSupportsWeakReference,
public nsIAsyncShutdownBlocker,
public mozIStorageCompletionCallback,
public mozIStorageStatementCallback {
using StatementCache = mozilla::storage::StatementCache<mozIStorageStatement>;
using AsyncStatementCache =
mozilla::storage::StatementCache<mozIStorageAsyncStatement>;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIASYNCSHUTDOWNBLOCKER
NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
NS_DECL_MOZISTORAGESTATEMENTCALLBACK
/**
* It is normally not necessary to have more than one instance of this, so
* it's suggested to use the GetInstance static helper below to instance
* this class.
*/
ConcurrentConnection();
/**
* Get a pointer to the singleton instance.
*/
static Maybe<ConcurrentConnection*> GetInstance();
/**
* Enqueue a query or a Runnable.
* Each consumers should only use one of these for proper serialization.
* TODO: Unify the queues, maybe using a Union.
*/
void Queue(const nsCString& aSQL, PendingStatementCallback* aCallback);
void Queue(Runnable* aRunnable);
/**
* Gets a cached synchronous statement on the helper thread.
*
* @param aQuery
* nsCString of SQL query.
* @returns The cached statement.
* @note Always null check the result.
* @note Always use a scoper to reset the statement.
*/
already_AddRefed<mozIStorageStatement> GetStatementOnHelperThread(
const nsCString& aQuery);
private:
/**
* Gets a cached asynchronous statement on the main thread.
* This is private, as you normally should use Queue.
*
* @param aQuery
* nsCString of SQL query.
* @returns The cached statement.
* @note Always null check the result.
* @note As this returns an async statement, it's not necessary to use a
* scoper, as it will be reset automatically after execution.
*/
already_AddRefed<mozIStorageAsyncStatement> GetStatement(
const nsCString& aQuery);
/**
* Try to consume the queue.
*/
void TryToConsumeQueues();
/**
* Try to open a database connection.
* This may arguably fail, for example if the database was not created yet,
* or has an outdated schema version. In that case this component will try
* again later, once it is notified the Places subsystem is up and running.
*/
void TryToOpenConnection();
/**
* Setups the connection, initializing functions and attaching other
* databases.
*/
void SetupConnection();
/**
* Close the currently tracked connection.
*/
void CloseConnection();
void CloseConnectionComplete(nsresult rv);
/**
* Shutdown and cleanup.
* @note After invoking this the component cannot be resurrected.
*/
void Shutdown();
/**
* Helper to attach a database file.
*/
nsresult AttachDatabase(const nsString& aFileName,
const nsCString& aSchemaName);
static ConcurrentConnection* gConcurrentConnection;
~ConcurrentConnection() = default;
// The current state, used to track progress in AsyncShutdown.
enum States {
NOT_STARTED = 0,
AWAITING_DATABASE_READY = 1,
READY = 2,
SHUTTING_DOWN = 3,
AWAITING_DATABASE_CLOSED = 4,
CLOSED = 5,
};
States mState = NOT_STARTED;
bool mIsOpening = false;
bool mPlacesIsInitialized = false;
bool mRetryOpening = true;
bool mIsShuttingDown = false;
bool mIsConnectionReady = false;
int32_t mSchemaVersion = -1;
// Ideally this should be a mozIStorageAsyncConnection, as that would give us
// additional checks we're not abusing the main-thread, though that would
// limit us excessively, since `StatementCache` and `CreateStatement` only
// work on a full-fledged Connection object. We'll have to take particular
// care of not touching the main-thread.
nsCOMPtr<mozIStorageConnection> mConn;
/**
* The parent object who registered this as a blocker.
*/
nsCOMPtr<nsIAsyncShutdownClient> mShutdownBarrierClient;
/**
* Collections of queries and runnables to be executed.
*/
nsRefPtrDeque<PendingQuery> mPendingQueries;
nsRefPtrDeque<Runnable> mPendingRunnables;
/**
* Statements caches.
*/
UniquePtr<AsyncStatementCache> mAsyncStatements;
UniquePtr<StatementCache> mHelperThreadStatements;
};
} // namespace mozilla::places
#endif // mozilla_places_ConcurrentConnection_h_
|