Bug 1884032 [wpt PR 44942] - [css-color] add missing colorscheme-aware tests, a=testonly
[gecko.git] / dom / storage / StorageDBThread.h
blob7708de5a97bd5ece48103b58cd28eaa51fb0010b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #ifndef mozilla_dom_StorageDBThread_h
8 #define mozilla_dom_StorageDBThread_h
10 #include "prthread.h"
11 #include "prinrval.h"
12 #include "nsTArray.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/Monitor.h"
15 #include "mozilla/BasePrincipal.h"
16 #include "mozilla/OriginAttributes.h"
17 #include "mozilla/storage/StatementCache.h"
18 #include "mozilla/TimeStamp.h"
19 #include "mozilla/UniquePtr.h"
20 #include "nsString.h"
21 #include "nsCOMPtr.h"
22 #include "nsClassHashtable.h"
23 #include "nsIFile.h"
24 #include "nsIThreadInternal.h"
25 #include "nsThreadUtils.h"
26 #include "nsTHashSet.h"
28 class mozIStorageConnection;
30 namespace mozilla::dom {
32 class LocalStorageCacheBridge;
33 class StorageUsageBridge;
34 class StorageUsage;
36 using StatementCache = mozilla::storage::StatementCache<mozIStorageStatement>;
38 // XXX Fix me!
39 // 1. Move comments to StorageDBThread/StorageDBChild.
40 // 2. Devirtualize relevant methods in StorageDBThread/StorageDBChild.
41 // 3. Remove relevant methods in StorageDBThread/StorageDBChild that are
42 // unused.
43 // 4. Remove this class completely.
45 // See bug 1387636 for more details.
46 #if 0
47 // Interface used by the cache to post operations to the asynchronous
48 // database thread or process.
49 class StorageDBBridge
51 public:
52 StorageDBBridge();
53 virtual ~StorageDBBridge() {}
55 // Ensures the database engine is started
56 virtual nsresult Init() = 0;
58 // Releases the database and disallows its usage
59 virtual nsresult Shutdown() = 0;
61 // Asynchronously fills the cache with data from the database for first use.
62 // When |aPriority| is true, the preload operation is scheduled as the first
63 // one. This method is responsible to keep hard reference to the cache for
64 // the time of the preload or, when preload cannot be performed, call
65 // LoadDone() immediately.
66 virtual void AsyncPreload(LocalStorageCacheBridge* aCache,
67 bool aPriority = false) = 0;
69 // Asynchronously fill the |usage| object with actual usage of data by its
70 // scope. The scope is eTLD+1 tops, never deeper subdomains.
71 virtual void AsyncGetUsage(StorageUsageBridge* aUsage) = 0;
73 // Synchronously fills the cache, when |aForceSync| is false and cache already
74 // got some data before, the method waits for the running preload to finish
75 virtual void SyncPreload(LocalStorageCacheBridge* aCache,
76 bool aForceSync = false) = 0;
78 // Called when an existing key is modified in the storage, schedules update to
79 // the database
80 virtual nsresult AsyncAddItem(LocalStorageCacheBridge* aCache,
81 const nsAString& aKey,
82 const nsAString& aValue) = 0;
84 // Called when an existing key is modified in the storage, schedules update to
85 // the database
86 virtual nsresult AsyncUpdateItem(LocalStorageCacheBridge* aCache,
87 const nsAString& aKey,
88 const nsAString& aValue) = 0;
90 // Called when an item is removed from the storage, schedules delete of the
91 // key
92 virtual nsresult AsyncRemoveItem(LocalStorageCacheBridge* aCache,
93 const nsAString& aKey) = 0;
95 // Called when the whole storage is cleared by the DOM API, schedules delete
96 // of the scope
97 virtual nsresult AsyncClear(LocalStorageCacheBridge* aCache) = 0;
99 // Called when chrome deletes e.g. cookies, schedules delete of the whole
100 // database
101 virtual void AsyncClearAll() = 0;
103 // Called when only a domain and its subdomains is about to clear
104 virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix) = 0;
106 // Called when data matching an origin pattern have to be cleared
107 virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern) = 0;
109 // Forces scheduled DB operations to be early flushed to the disk
110 virtual void AsyncFlush() = 0;
112 // Check whether the scope has any data stored on disk and is thus allowed to
113 // preload
114 virtual bool ShouldPreloadOrigin(const nsACString& aOriginNoSuffix) = 0;
116 #endif
118 // The implementation of the the database engine, this directly works
119 // with the sqlite or any other db API we are based on
120 // This class is resposible for collecting and processing asynchronous
121 // DB operations over caches (LocalStorageCache) communicating though
122 // LocalStorageCacheBridge interface class
123 class StorageDBThread final {
124 public:
125 class PendingOperations;
127 // Representation of a singe database task, like adding and removing keys,
128 // (pre)loading the whole origin data, cleaning.
129 class DBOperation {
130 public:
131 enum OperationType {
132 // Only operation that reads data from the database
133 opPreload,
134 // The same as opPreload, just executed with highest priority
135 opPreloadUrgent,
137 // Load usage of a scope
138 opGetUsage,
140 // Operations invoked by the DOM content API
141 opAddItem,
142 opUpdateItem,
143 opRemoveItem,
144 // Clears a specific single origin data
145 opClear,
147 // Operations invoked by chrome
149 // Clear all the data stored in the database, for all scopes, no
150 // exceptions
151 opClearAll,
152 // Clear data under a domain and all its subdomains regardless
153 // OriginAttributes value
154 opClearMatchingOrigin,
155 // Clear all data matching an OriginAttributesPattern regardless a domain
156 opClearMatchingOriginAttributes,
159 explicit DBOperation(const OperationType aType,
160 LocalStorageCacheBridge* aCache = nullptr,
161 const nsAString& aKey = u""_ns,
162 const nsAString& aValue = u""_ns);
163 DBOperation(const OperationType aType, StorageUsageBridge* aUsage);
164 DBOperation(const OperationType aType, const nsACString& aOriginNoSuffix);
165 DBOperation(const OperationType aType,
166 const OriginAttributesPattern& aOriginNoSuffix);
167 ~DBOperation();
169 // Executes the operation, doesn't necessarity have to be called on the I/O
170 // thread
171 void PerformAndFinalize(StorageDBThread* aThread);
173 // Finalize the operation, i.e. do any internal cleanup and finish calls
174 void Finalize(nsresult aRv);
176 // The operation type
177 OperationType Type() const { return mType; }
179 // The origin in the database usage format (reversed)
180 const nsCString OriginNoSuffix() const;
182 // The origin attributes suffix
183 const nsCString OriginSuffix() const;
185 // |origin suffix + origin key| the operation is working with or a scope
186 // pattern to delete with simple SQL's "LIKE %" from the database.
187 const nsCString Origin() const;
189 // |origin suffix + origin key + key| the operation is working with
190 const nsCString Target() const;
192 // Pattern to delete matching data with this op
193 const OriginAttributesPattern& OriginPattern() const {
194 return mOriginPattern;
197 private:
198 // The operation implementation body
199 nsresult Perform(StorageDBThread* aThread);
201 friend class PendingOperations;
202 OperationType mType;
203 RefPtr<LocalStorageCacheBridge> mCache;
204 RefPtr<StorageUsageBridge> mUsage;
205 nsString const mKey;
206 nsString const mValue;
207 nsCString const mOrigin;
208 OriginAttributesPattern const mOriginPattern;
211 // Encapsulation of collective and coalescing logic for all pending operations
212 // except preloads that are handled separately as priority operations
213 class PendingOperations {
214 public:
215 PendingOperations();
217 // Method responsible for coalescing redundant update operations with the
218 // same |Target()| or clear operations with the same or matching |Origin()|
219 void Add(UniquePtr<DBOperation> aOperation);
221 // True when there are some scheduled operations to flush on disk
222 bool HasTasks() const;
224 // Moves collected operations to a local flat list to allow execution of the
225 // operation list out of the thread lock
226 bool Prepare();
228 // Executes the previously |Prepared()'ed| list of operations, returns
229 // result, but doesn't handle it in any way in case of a failure
230 nsresult Execute(StorageDBThread* aThread);
232 // Finalizes the pending operation list, returns false when too many
233 // operations failed to flush what indicates a long standing issue with the
234 // database access.
235 bool Finalize(nsresult aRv);
237 // true when a clear that deletes the given origin attr pattern and/or
238 // origin key is among the pending operations; when a preload for that scope
239 // is being scheduled, it must be finished right away
240 bool IsOriginClearPending(const nsACString& aOriginSuffix,
241 const nsACString& aOriginNoSuffix) const;
243 // Checks whether there is a pending update operation for this scope.
244 bool IsOriginUpdatePending(const nsACString& aOriginSuffix,
245 const nsACString& aOriginNoSuffix) const;
247 private:
248 // Returns true iff new operation is of type newType and there is a pending
249 // operation of type pendingType for the same key (target).
250 bool CheckForCoalesceOpportunity(DBOperation* aNewOp,
251 DBOperation::OperationType aPendingType,
252 DBOperation::OperationType aNewType);
254 // List of all clearing operations, executed first
255 nsClassHashtable<nsCStringHashKey, DBOperation> mClears;
257 // List of all update/insert operations, executed as second
258 nsClassHashtable<nsCStringHashKey, DBOperation> mUpdates;
260 // Collection of all tasks, valid only between Prepare() and Execute()
261 nsTArray<UniquePtr<DBOperation> > mExecList;
263 // Number of failing flush attempts
264 uint32_t mFlushFailureCount;
267 class ThreadObserver final : public nsIThreadObserver {
268 NS_DECL_THREADSAFE_ISUPPORTS
269 NS_DECL_NSITHREADOBSERVER
271 ThreadObserver()
272 : mHasPendingEvents(false), mMonitor("StorageThreadMonitor") {}
274 bool HasPendingEvents() {
275 mMonitor.AssertCurrentThreadOwns();
276 return mHasPendingEvents;
278 void ClearPendingEvents() {
279 mMonitor.AssertCurrentThreadOwns();
280 mHasPendingEvents = false;
282 Monitor& GetMonitor() { return mMonitor; }
284 private:
285 virtual ~ThreadObserver() = default;
286 bool mHasPendingEvents;
287 // The monitor we drive the thread with
288 Monitor mMonitor MOZ_UNANNOTATED;
291 class InitHelper;
293 class NoteBackgroundThreadRunnable;
295 class ShutdownRunnable : public Runnable {
296 // Expected to be only 0 or 1.
297 const uint32_t mPrivateBrowsingId;
298 // Only touched on the main thread.
299 bool& mDone;
301 public:
302 explicit ShutdownRunnable(const uint32_t aPrivateBrowsingId, bool& aDone)
303 : Runnable("dom::StorageDBThread::ShutdownRunnable"),
304 mPrivateBrowsingId(aPrivateBrowsingId),
305 mDone(aDone) {
306 MOZ_ASSERT(NS_IsMainThread());
309 private:
310 ~ShutdownRunnable() = default;
312 NS_DECL_NSIRUNNABLE
315 public:
316 explicit StorageDBThread(uint32_t aPrivateBrowsingId);
317 virtual ~StorageDBThread() = default;
319 static StorageDBThread* Get(uint32_t aPrivateBrowsingId);
321 static StorageDBThread* GetOrCreate(const nsString& aProfilePath,
322 uint32_t aPrivateBrowsingId);
324 static nsresult GetProfilePath(nsString& aProfilePath);
326 virtual nsresult Init(const nsString& aProfilePath);
328 // Flushes all uncommited data and stops the I/O thread.
329 virtual nsresult Shutdown();
331 virtual void AsyncPreload(LocalStorageCacheBridge* aCache,
332 bool aPriority = false) {
333 InsertDBOp(MakeUnique<DBOperation>(
334 aPriority ? DBOperation::opPreloadUrgent : DBOperation::opPreload,
335 aCache));
338 virtual void SyncPreload(LocalStorageCacheBridge* aCache,
339 bool aForce = false);
341 virtual void AsyncGetUsage(StorageUsageBridge* aUsage) {
342 InsertDBOp(MakeUnique<DBOperation>(DBOperation::opGetUsage, aUsage));
345 virtual nsresult AsyncAddItem(LocalStorageCacheBridge* aCache,
346 const nsAString& aKey,
347 const nsAString& aValue) {
348 return InsertDBOp(
349 MakeUnique<DBOperation>(DBOperation::opAddItem, aCache, aKey, aValue));
352 virtual nsresult AsyncUpdateItem(LocalStorageCacheBridge* aCache,
353 const nsAString& aKey,
354 const nsAString& aValue) {
355 return InsertDBOp(MakeUnique<DBOperation>(DBOperation::opUpdateItem, aCache,
356 aKey, aValue));
359 virtual nsresult AsyncRemoveItem(LocalStorageCacheBridge* aCache,
360 const nsAString& aKey) {
361 return InsertDBOp(
362 MakeUnique<DBOperation>(DBOperation::opRemoveItem, aCache, aKey));
365 virtual nsresult AsyncClear(LocalStorageCacheBridge* aCache) {
366 return InsertDBOp(MakeUnique<DBOperation>(DBOperation::opClear, aCache));
369 virtual void AsyncClearAll() {
370 InsertDBOp(MakeUnique<DBOperation>(DBOperation::opClearAll));
373 virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix) {
374 InsertDBOp(MakeUnique<DBOperation>(DBOperation::opClearMatchingOrigin,
375 aOriginNoSuffix));
378 virtual void AsyncClearMatchingOriginAttributes(
379 const OriginAttributesPattern& aPattern) {
380 InsertDBOp(MakeUnique<DBOperation>(
381 DBOperation::opClearMatchingOriginAttributes, aPattern));
384 virtual void AsyncFlush();
386 virtual bool ShouldPreloadOrigin(const nsACString& aOrigin);
388 // Get the complete list of scopes having data.
389 void GetOriginsHavingData(nsTArray<nsCString>* aOrigins);
391 private:
392 nsCOMPtr<nsIFile> mDatabaseFile;
393 PRThread* mThread;
395 // Used to observe runnables dispatched to our thread and to monitor it.
396 RefPtr<ThreadObserver> mThreadObserver;
398 // Flag to stop, protected by the monitor returned by
399 // mThreadObserver->GetMonitor().
400 bool mStopIOThread;
402 // Whether WAL is enabled
403 bool mWALModeEnabled;
405 // Whether DB has already been open, avoid races between main thread reads
406 // and pending DB init in the background I/O thread
407 Atomic<bool, ReleaseAcquire> mDBReady;
409 // State of the database initiation
410 nsresult mStatus;
412 // List of origins (including origin attributes suffix) having data, for
413 // optimization purposes only
414 nsTHashSet<nsCString> mOriginsHavingData;
416 // Connection used by the worker thread for all read and write ops
417 nsCOMPtr<mozIStorageConnection> mWorkerConnection;
419 // Connection used only on the main thread for sync read operations
420 nsCOMPtr<mozIStorageConnection> mReaderConnection;
422 StatementCache mWorkerStatements;
423 StatementCache mReaderStatements;
425 // Time the first pending operation has been added to the pending operations
426 // list
427 TimeStamp mDirtyEpoch;
429 // Flag to force immediate flush of all pending operations
430 bool mFlushImmediately;
432 // List of preloading operations, in chronological or priority order.
433 // Executed prioritly over pending update operations.
434 nsTArray<DBOperation*> mPreloads;
436 // Collector of pending update operations
437 PendingOperations mPendingTasks;
439 // Expected to be only 0 or 1.
440 const uint32_t mPrivateBrowsingId;
442 // Counter of calls for thread priority rising.
443 int32_t mPriorityCounter;
445 // Helper to direct an operation to one of the arrays above;
446 // also checks IsOriginClearPending for preloads
447 nsresult InsertDBOp(UniquePtr<DBOperation> aOperation);
449 // Opens the database, first thing we do after start of the thread.
450 nsresult OpenDatabaseConnection();
451 nsresult OpenAndUpdateDatabase();
452 nsresult InitDatabase();
453 nsresult ShutdownDatabase();
455 // Tries to establish WAL mode
456 nsresult SetJournalMode(bool aIsWal);
457 nsresult TryJournalMode();
459 // Sets the threshold for auto-checkpointing the WAL.
460 nsresult ConfigureWALBehavior();
462 void SetHigherPriority();
463 void SetDefaultPriority();
465 // Ensures we flush pending tasks in some reasonble time
466 void ScheduleFlush();
468 // Called when flush of pending tasks is being executed
469 void UnscheduleFlush();
471 // This method is used for two purposes:
472 // 1. as a value passed to monitor.Wait() method
473 // 2. as in indicator that flush has to be performed
475 // Return:
476 // - TimeDuration::Forever() when no pending tasks are scheduled
477 // - Non-zero TimeDuration when tasks have been scheduled, but it
478 // is still not time to perform the flush ; it is actual time to
479 // wait until the flush has to happen.
480 // - 0 TimeDuration when it is time to do the flush
481 TimeDuration TimeUntilFlush();
483 // Notifies to the main thread that flush has completed
484 void NotifyFlushCompletion();
486 // Thread loop
487 static void ThreadFunc(void* aArg);
488 void ThreadFunc();
491 } // namespace mozilla::dom
493 #endif // mozilla_dom_StorageDBThread_h