Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #ifndef mozilla_places_Database_h_
6 : #define mozilla_places_Database_h_
7 :
8 : #include "MainThreadUtils.h"
9 : #include "nsWeakReference.h"
10 : #include "nsIInterfaceRequestorUtils.h"
11 : #include "nsIObserver.h"
12 : #include "nsIAsyncShutdown.h"
13 : #include "mozilla/storage.h"
14 : #include "mozilla/storage/StatementCache.h"
15 : #include "mozilla/Attributes.h"
16 : #include "nsIEventTarget.h"
17 : #include "Shutdown.h"
18 : #include "nsCategoryCache.h"
19 :
20 : // This is the schema version. Update it at any schema change and add a
21 : // corresponding migrateVxx method below.
22 : #define DATABASE_SCHEMA_VERSION 38
23 :
24 : // Fired after Places inited.
25 : #define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
26 : // This topic is received when the profile is about to be lost. Places does
27 : // initial shutdown work and notifies TOPIC_PLACES_SHUTDOWN to all listeners.
28 : // Any shutdown work that requires the Places APIs should happen here.
29 : #define TOPIC_PROFILE_CHANGE_TEARDOWN "profile-change-teardown"
30 : // Fired when Places is shutting down. Any code should stop accessing Places
31 : // APIs after this notification. If you need to listen for Places shutdown
32 : // you should only use this notification, next ones are intended only for
33 : // internal Places use.
34 : #define TOPIC_PLACES_SHUTDOWN "places-shutdown"
35 : // For Internal use only. Fired when connection is about to be closed, only
36 : // cleanup tasks should run at this stage, nothing should be added to the
37 : // database, nor APIs should be called.
38 : #define TOPIC_PLACES_WILL_CLOSE_CONNECTION "places-will-close-connection"
39 : // Fired when the connection has gone, nothing will work from now on.
40 : #define TOPIC_PLACES_CONNECTION_CLOSED "places-connection-closed"
41 :
42 : // Simulate profile-before-change. This topic may only be used by
43 : // calling `observe` directly on the database. Used for testing only.
44 : #define TOPIC_SIMULATE_PLACES_SHUTDOWN "test-simulate-places-shutdown"
45 :
46 : class nsIRunnable;
47 :
48 : namespace mozilla {
49 : namespace places {
50 :
51 : enum JournalMode {
52 : // Default SQLite journal mode.
53 : JOURNAL_DELETE = 0
54 : // Can reduce fsyncs on Linux when journal is deleted (See bug 460315).
55 : // We fallback to this mode when WAL is unavailable.
56 : , JOURNAL_TRUNCATE
57 : // Unsafe in case of crashes on database swap or low memory.
58 : , JOURNAL_MEMORY
59 : // Can reduce number of fsyncs. We try to use this mode by default.
60 : , JOURNAL_WAL
61 : };
62 :
63 : class ClientsShutdownBlocker;
64 : class ConnectionShutdownBlocker;
65 :
66 : class Database final : public nsIObserver
67 : , public nsSupportsWeakReference
68 : {
69 : typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
70 : typedef mozilla::storage::StatementCache<mozIStorageAsyncStatement> AsyncStatementCache;
71 :
72 : public:
73 : NS_DECL_THREADSAFE_ISUPPORTS
74 : NS_DECL_NSIOBSERVER
75 :
76 : Database();
77 :
78 : /**
79 : * Initializes the database connection and the schema.
80 : * In case of corruption the database is copied to a backup file and replaced.
81 : */
82 : nsresult Init();
83 :
84 : /**
85 : * The AsyncShutdown client used by clients of this API to be informed of shutdown.
86 : */
87 : already_AddRefed<nsIAsyncShutdownClient> GetClientsShutdown();
88 :
89 : /**
90 : * Getter to use when instantiating the class.
91 : *
92 : * @return Singleton instance of this class.
93 : */
94 : static already_AddRefed<Database> GetDatabase();
95 :
96 : /**
97 : * Actually initialized the connection on first need.
98 : */
99 : nsresult EnsureConnection();
100 :
101 : /**
102 : * Notifies that the connection has been initialized.
103 : */
104 : nsresult NotifyConnectionInitalized();
105 :
106 : /**
107 : * Returns last known database status.
108 : *
109 : * @return one of the nsINavHistoryService::DATABASE_STATUS_* constants.
110 : */
111 1 : uint16_t GetDatabaseStatus()
112 : {
113 1 : mozilla::Unused << EnsureConnection();
114 1 : return mDatabaseStatus;
115 : }
116 :
117 : /**
118 : * Returns a pointer to the storage connection.
119 : *
120 : * @return The connection handle.
121 : */
122 10 : mozIStorageConnection* MainConn()
123 : {
124 10 : mozilla::Unused << EnsureConnection();
125 10 : return mMainConn;
126 : }
127 :
128 : /**
129 : * Dispatches a runnable to the connection async thread, to be serialized
130 : * with async statements.
131 : *
132 : * @param aEvent
133 : * The runnable to be dispatched.
134 : */
135 1 : void DispatchToAsyncThread(nsIRunnable* aEvent)
136 : {
137 1 : if (mClosed || NS_FAILED(EnsureConnection())) {
138 0 : return;
139 : }
140 2 : nsCOMPtr<nsIEventTarget> target = do_GetInterface(mMainConn);
141 1 : if (target) {
142 1 : (void)target->Dispatch(aEvent, NS_DISPATCH_NORMAL);
143 : }
144 : }
145 :
146 : //////////////////////////////////////////////////////////////////////////////
147 : //// Statements Getters.
148 :
149 : /**
150 : * Gets a cached synchronous statement.
151 : *
152 : * @param aQuery
153 : * SQL query literal.
154 : * @return The cached statement.
155 : * @note Always null check the result.
156 : * @note Always use a scoper to reset the statement.
157 : */
158 : template<int N>
159 : already_AddRefed<mozIStorageStatement>
160 7 : GetStatement(const char (&aQuery)[N])
161 : {
162 14 : nsDependentCString query(aQuery, N - 1);
163 14 : return GetStatement(query);
164 : }
165 :
166 : /**
167 : * Gets a cached synchronous statement.
168 : *
169 : * @param aQuery
170 : * nsCString of SQL query.
171 : * @return The cached statement.
172 : * @note Always null check the result.
173 : * @note Always use a scoper to reset the statement.
174 : */
175 : already_AddRefed<mozIStorageStatement> GetStatement(const nsACString& aQuery);
176 :
177 : /**
178 : * Gets a cached asynchronous statement.
179 : *
180 : * @param aQuery
181 : * SQL query literal.
182 : * @return The cached statement.
183 : * @note Always null check the result.
184 : * @note AsyncStatements are automatically reset on execution.
185 : */
186 : template<int N>
187 : already_AddRefed<mozIStorageAsyncStatement>
188 1 : GetAsyncStatement(const char (&aQuery)[N])
189 : {
190 2 : nsDependentCString query(aQuery, N - 1);
191 2 : return GetAsyncStatement(query);
192 : }
193 :
194 : /**
195 : * Gets a cached asynchronous statement.
196 : *
197 : * @param aQuery
198 : * nsCString of SQL query.
199 : * @return The cached statement.
200 : * @note Always null check the result.
201 : * @note AsyncStatements are automatically reset on execution.
202 : */
203 : already_AddRefed<mozIStorageAsyncStatement> GetAsyncStatement(const nsACString& aQuery);
204 :
205 : uint32_t MaxUrlLength();
206 :
207 : protected:
208 : /**
209 : * Finalizes the cached statements and closes the database connection.
210 : * A TOPIC_PLACES_CONNECTION_CLOSED notification is fired when done.
211 : */
212 : void Shutdown();
213 :
214 : bool IsShutdownStarted() const;
215 :
216 : /**
217 : * Initializes the database file. If the database does not exist or is
218 : * corrupt, a new one is created. In case of corruption it also creates a
219 : * backup copy of the database.
220 : *
221 : * @param aStorage
222 : * mozStorage service instance.
223 : * @param aNewDatabaseCreated
224 : * whether a new database file has been created.
225 : */
226 : nsresult InitDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage,
227 : bool* aNewDatabaseCreated);
228 :
229 : /**
230 : * Ensure the favicons database file exists.
231 : *
232 : * @param aStorage
233 : * mozStorage service instance.
234 : */
235 : nsresult EnsureFaviconsDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage);
236 :
237 : /**
238 : * Creates a database backup and replaces the original file with a new
239 : * one.
240 : *
241 : * @param aStorage
242 : * mozStorage service instance.
243 : */
244 : nsresult BackupAndReplaceDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage);
245 :
246 : /**
247 : * Set up the connection environment through PRAGMAs.
248 : * Will return NS_ERROR_FILE_CORRUPTED if any critical setting fails.
249 : *
250 : * @param aStorage
251 : * mozStorage service instance.
252 : */
253 : nsresult SetupDatabaseConnection(nsCOMPtr<mozIStorageService>& aStorage);
254 :
255 : /**
256 : * Initializes the schema. This performs any necessary migrations for the
257 : * database. All migration is done inside a transaction that is rolled back
258 : * if any error occurs.
259 : * @param aDatabaseMigrated
260 : * Whether a schema upgrade happened.
261 : */
262 : nsresult InitSchema(bool* aDatabaseMigrated);
263 :
264 : /**
265 : * Creates bookmark roots in a new DB.
266 : */
267 : nsresult CreateBookmarkRoots();
268 :
269 : /**
270 : * Initializes additionale SQLite functions, defined in SQLFunctions.h
271 : */
272 : nsresult InitFunctions();
273 :
274 : /**
275 : * Initializes temp entities, like triggers, tables, views...
276 : */
277 : nsresult InitTempEntities();
278 :
279 : /**
280 : * Helpers used by schema upgrades.
281 : */
282 : nsresult MigrateV13Up();
283 : nsresult MigrateV15Up();
284 : nsresult MigrateV17Up();
285 : nsresult MigrateV18Up();
286 : nsresult MigrateV19Up();
287 : nsresult MigrateV20Up();
288 : nsresult MigrateV21Up();
289 : nsresult MigrateV22Up();
290 : nsresult MigrateV23Up();
291 : nsresult MigrateV24Up();
292 : nsresult MigrateV25Up();
293 : nsresult MigrateV26Up();
294 : nsresult MigrateV27Up();
295 : nsresult MigrateV28Up();
296 : nsresult MigrateV30Up();
297 : nsresult MigrateV31Up();
298 : nsresult MigrateV32Up();
299 : nsresult MigrateV33Up();
300 : nsresult MigrateV34Up();
301 : nsresult MigrateV35Up();
302 : nsresult MigrateV36Up();
303 : nsresult MigrateV37Up();
304 : nsresult MigrateV38Up();
305 :
306 : nsresult UpdateBookmarkRootTitles();
307 :
308 : friend class ConnectionShutdownBlocker;
309 :
310 : int64_t CreateMobileRoot();
311 : nsresult GetItemsWithAnno(const nsACString& aAnnoName, int32_t aItemType,
312 : nsTArray<int64_t>& aItemIds);
313 : nsresult DeleteBookmarkItem(int32_t aItemId);
314 :
315 : private:
316 : ~Database();
317 :
318 : /**
319 : * Singleton getter, invoked by class instantiation.
320 : */
321 : static already_AddRefed<Database> GetSingleton();
322 :
323 : static Database* gDatabase;
324 :
325 : nsCOMPtr<mozIStorageConnection> mMainConn;
326 :
327 : mutable StatementCache mMainThreadStatements;
328 : mutable AsyncStatementCache mMainThreadAsyncStatements;
329 : mutable StatementCache mAsyncThreadStatements;
330 :
331 : int32_t mDBPageSize;
332 : uint16_t mDatabaseStatus;
333 : bool mClosed;
334 :
335 : /**
336 : * Phases for shutting down the Database.
337 : * See Shutdown.h for further details about the shutdown procedure.
338 : */
339 : already_AddRefed<nsIAsyncShutdownClient> GetProfileChangeTeardownPhase();
340 : already_AddRefed<nsIAsyncShutdownClient> GetProfileBeforeChangePhase();
341 :
342 : /**
343 : * Blockers in charge of waiting for the Places clients and then shutting
344 : * down the mozStorage connection.
345 : * See Shutdown.h for further details about the shutdown procedure.
346 : *
347 : * Cycles with these are broken in `Shutdown()`.
348 : */
349 : RefPtr<ClientsShutdownBlocker> mClientsShutdown;
350 : RefPtr<ConnectionShutdownBlocker> mConnectionShutdown;
351 :
352 : // Maximum length of a stored url.
353 : // For performance reasons we don't store very long urls in history, since
354 : // they are slower to search through and cause abnormal database growth,
355 : // affecting the awesomebar fetch time.
356 : uint32_t mMaxUrlLength;
357 :
358 : // Used to initialize components on places startup.
359 : nsCategoryCache<nsIObserver> mCacheObservers;
360 : };
361 :
362 : } // namespace places
363 : } // namespace mozilla
364 :
365 : #endif // mozilla_places_Database_h_
|