File: ConcurrentConnection.h

package info (click to toggle)
firefox 142.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,591,884 kB
  • sloc: cpp: 7,451,570; javascript: 6,392,463; ansic: 3,712,584; python: 1,388,569; xml: 629,223; asm: 426,919; java: 184,857; sh: 63,439; makefile: 19,150; objc: 13,059; perl: 12,983; yacc: 4,583; cs: 3,846; pascal: 3,352; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (195 lines) | stat: -rw-r--r-- 6,049 bytes parent folder | download | duplicates (3)
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_