1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef DOMStorageDBThread_h___
7 #define DOMStorageDBThread_h___
12 #include "mozilla/Monitor.h"
13 #include "mozilla/storage/StatementCache.h"
16 #include "nsClassHashtable.h"
19 class mozIStorageConnection
;
24 class DOMStorageCacheBridge
;
25 class DOMStorageUsageBridge
;
26 class DOMStorageUsage
;
28 typedef mozilla::storage::StatementCache
<mozIStorageStatement
> StatementCache
;
30 // Interface used by the cache to post operations to the asynchronous
31 // database thread or process.
32 class DOMStorageDBBridge
36 virtual ~DOMStorageDBBridge() {}
38 // Ensures the database engine is started
39 virtual nsresult
Init() = 0;
41 // Releases the database and disallows its usage
42 virtual nsresult
Shutdown() = 0;
44 // Asynchronously fills the cache with data from the database for first use.
45 // When |aPriority| is true, the preload operation is scheduled as the first one.
46 // This method is responsible to keep hard reference to the cache for the time of
47 // the preload or, when preload cannot be performed, call LoadDone() immediately.
48 virtual void AsyncPreload(DOMStorageCacheBridge
* aCache
, bool aPriority
= false) = 0;
50 // Asynchronously fill the |usage| object with actual usage of data by its scope.
51 // The scope is eTLD+1 tops, never deeper subdomains.
52 virtual void AsyncGetUsage(DOMStorageUsageBridge
* aUsage
) = 0;
54 // Synchronously fills the cache, when |aForceSync| is false and cache already got some
55 // data before, the method waits for the running preload to finish
56 virtual void SyncPreload(DOMStorageCacheBridge
* aCache
, bool aForceSync
= false) = 0;
58 // Called when an existing key is modified in the storage, schedules update to the database
59 virtual nsresult
AsyncAddItem(DOMStorageCacheBridge
* aCache
, const nsAString
& aKey
, const nsAString
& aValue
) = 0;
61 // Called when an existing key is modified in the storage, schedules update to the database
62 virtual nsresult
AsyncUpdateItem(DOMStorageCacheBridge
* aCache
, const nsAString
& aKey
, const nsAString
& aValue
) = 0;
64 // Called when an item is removed from the storage, schedules delete of the key
65 virtual nsresult
AsyncRemoveItem(DOMStorageCacheBridge
* aCache
, const nsAString
& aKey
) = 0;
67 // Called when the whole storage is cleared by the DOM API, schedules delete of the scope
68 virtual nsresult
AsyncClear(DOMStorageCacheBridge
* aCache
) = 0;
70 // Called when chrome deletes e.g. cookies, schedules delete of the whole database
71 virtual void AsyncClearAll() = 0;
73 // Called when only a domain and its subdomains or an app data is about to clear
74 virtual void AsyncClearMatchingScope(const nsACString
& aScope
) = 0;
76 // Forces scheduled DB operations to be early flushed to the disk
77 virtual void AsyncFlush() = 0;
79 // Check whether the scope has any data stored on disk and is thus allowed to preload
80 virtual bool ShouldPreloadScope(const nsACString
& aScope
) = 0;
82 // Get the complete list of scopes having data
83 virtual void GetScopesHavingData(InfallibleTArray
<nsCString
>* aScopes
) = 0;
86 // The implementation of the the database engine, this directly works
87 // with the sqlite or any other db API we are based on
88 // This class is resposible for collecting and processing asynchronous
89 // DB operations over caches (DOMStorageCache) communicating though
90 // DOMStorageCacheBridge interface class
91 class DOMStorageDBThread MOZ_FINAL
: public DOMStorageDBBridge
94 class PendingOperations
;
96 // Representation of a singe database task, like adding and removing keys,
97 // (pre)loading the whole origin data, cleaning.
102 // Only operation that reads data from the database
104 // The same as opPreload, just executed with highest priority
107 // Load usage of a scope
110 // Operations invoked by the DOM content API
116 // Operations invoked by chrome
118 opClearMatchingScope
,
121 explicit DBOperation(const OperationType aType
,
122 DOMStorageCacheBridge
* aCache
= nullptr,
123 const nsAString
& aKey
= EmptyString(),
124 const nsAString
& aValue
= EmptyString());
125 DBOperation(const OperationType aType
,
126 DOMStorageUsageBridge
* aUsage
);
127 DBOperation(const OperationType aType
,
128 const nsACString
& aScope
);
131 // Executes the operation, doesn't necessarity have to be called on the I/O thread
132 void PerformAndFinalize(DOMStorageDBThread
* aThread
);
134 // Finalize the operation, i.e. do any internal cleanup and finish calls
135 void Finalize(nsresult aRv
);
137 // The operation type
138 OperationType
Type() { return mType
; }
140 // The operation scope (=origin)
141 const nsCString
Scope();
143 // |Scope + key| the operation is working with
144 const nsCString
Target();
147 // The operation implementation body
148 nsresult
Perform(DOMStorageDBThread
* aThread
);
150 friend class PendingOperations
;
152 nsRefPtr
<DOMStorageCacheBridge
> mCache
;
153 nsRefPtr
<DOMStorageUsageBridge
> mUsage
;
159 // Encapsulation of collective and coalescing logic for all pending operations
160 // except preloads that are handled separately as priority operations
161 class PendingOperations
{
165 // Method responsible for coalescing redundant update operations with the same
166 // |Target()| or clear operations with the same or matching |Scope()|
167 void Add(DBOperation
* aOperation
);
169 // True when there are some scheduled operations to flush on disk
172 // Moves collected operations to a local flat list to allow execution of the operation
173 // list out of the thread lock
176 // Executes the previously |Prepared()'ed| list of operations, retuns result, but doesn't
177 // handle it in any way in case of a failure
178 nsresult
Execute(DOMStorageDBThread
* aThread
);
180 // Finalizes the pending operation list, returns false when too many operations failed
181 // to flush what indicates a long standing issue with the database access.
182 bool Finalize(nsresult aRv
);
184 // true when a clear that deletes the given |scope| is among the pending operations;
185 // when a preload for that scope is being scheduled, it must be finished right away
186 bool IsScopeClearPending(const nsACString
& aScope
);
188 // Checks whether there is a pending update (or clear, actually) operation for this scope.
189 bool IsScopeUpdatePending(const nsACString
& aScope
);
192 // Returns true iff new operation is of type newType and there is a pending
193 // operation of type pendingType for the same key (target).
194 bool CheckForCoalesceOpportunity(DBOperation
* aNewOp
,
195 DBOperation::OperationType aPendingType
,
196 DBOperation::OperationType aNewType
);
198 // List of all clearing operations, executed first
199 nsClassHashtable
<nsCStringHashKey
, DBOperation
> mClears
;
201 // List of all update/insert operations, executed as second
202 nsClassHashtable
<nsCStringHashKey
, DBOperation
> mUpdates
;
204 // Collection of all tasks, valid only between Prepare() and Execute()
205 nsTArray
<nsAutoPtr
<DBOperation
> > mExecList
;
207 // Number of failing flush attempts
208 uint32_t mFlushFailureCount
;
212 DOMStorageDBThread();
213 virtual ~DOMStorageDBThread() {}
215 virtual nsresult
Init();
216 virtual nsresult
Shutdown();
218 virtual void AsyncPreload(DOMStorageCacheBridge
* aCache
, bool aPriority
= false)
219 { InsertDBOp(new DBOperation(aPriority
? DBOperation::opPreloadUrgent
: DBOperation::opPreload
, aCache
)); }
221 virtual void SyncPreload(DOMStorageCacheBridge
* aCache
, bool aForce
= false);
223 virtual void AsyncGetUsage(DOMStorageUsageBridge
* aUsage
)
224 { InsertDBOp(new DBOperation(DBOperation::opGetUsage
, aUsage
)); }
226 virtual nsresult
AsyncAddItem(DOMStorageCacheBridge
* aCache
, const nsAString
& aKey
, const nsAString
& aValue
)
227 { return InsertDBOp(new DBOperation(DBOperation::opAddItem
, aCache
, aKey
, aValue
)); }
229 virtual nsresult
AsyncUpdateItem(DOMStorageCacheBridge
* aCache
, const nsAString
& aKey
, const nsAString
& aValue
)
230 { return InsertDBOp(new DBOperation(DBOperation::opUpdateItem
, aCache
, aKey
, aValue
)); }
232 virtual nsresult
AsyncRemoveItem(DOMStorageCacheBridge
* aCache
, const nsAString
& aKey
)
233 { return InsertDBOp(new DBOperation(DBOperation::opRemoveItem
, aCache
, aKey
)); }
235 virtual nsresult
AsyncClear(DOMStorageCacheBridge
* aCache
)
236 { return InsertDBOp(new DBOperation(DBOperation::opClear
, aCache
)); }
238 virtual void AsyncClearAll()
239 { InsertDBOp(new DBOperation(DBOperation::opClearAll
)); }
241 virtual void AsyncClearMatchingScope(const nsACString
& aScope
)
242 { InsertDBOp(new DBOperation(DBOperation::opClearMatchingScope
, aScope
)); }
244 virtual void AsyncFlush();
246 virtual bool ShouldPreloadScope(const nsACString
& aScope
);
247 virtual void GetScopesHavingData(InfallibleTArray
<nsCString
>* aScopes
);
250 nsCOMPtr
<nsIFile
> mDatabaseFile
;
253 // The monitor we drive the thread with
256 // Flag to stop, protected by the monitor
259 // Whether WAL is enabled
260 bool mWALModeEnabled
;
262 // Whether DB has already been open, avoid races between main thread reads
263 // and pending DB init in the background I/O thread
266 // State of the database initiation
269 // List of scopes having data, for optimization purposes only
270 nsTHashtable
<nsCStringHashKey
> mScopesHavingData
;
272 StatementCache mWorkerStatements
;
273 StatementCache mReaderStatements
;
275 // Connection used by the worker thread for all read and write ops
276 nsCOMPtr
<mozIStorageConnection
> mWorkerConnection
;
278 // Connection used only on the main thread for sync read operations
279 nsCOMPtr
<mozIStorageConnection
> mReaderConnection
;
281 // Time the first pending operation has been added to the pending operations
283 PRIntervalTime mDirtyEpoch
;
285 // Flag to force immediate flush of all pending operations
286 bool mFlushImmediately
;
288 // List of preloading operations, in chronological or priority order.
289 // Executed prioritly over pending update operations.
290 nsTArray
<DBOperation
*> mPreloads
;
292 // Collector of pending update operations
293 PendingOperations mPendingTasks
;
295 // Counter of calls for thread priority rising.
296 int32_t mPriorityCounter
;
298 // Helper to direct an operation to one of the arrays above;
299 // also checks IsScopeClearPending for preloads
300 nsresult
InsertDBOp(DBOperation
* aOperation
);
302 // Opens the database, first thing we do after start of the thread.
303 nsresult
OpenDatabaseConnection();
304 nsresult
InitDatabase();
305 nsresult
ShutdownDatabase();
307 // Tries to establish WAL mode
308 nsresult
SetJournalMode(bool aIsWal
);
309 nsresult
TryJournalMode();
311 // Sets the threshold for auto-checkpointing the WAL.
312 nsresult
ConfigureWALBehavior();
314 void SetHigherPriority();
315 void SetDefaultPriority();
317 // Ensures we flush pending tasks in some reasonble time
318 void ScheduleFlush();
320 // Called when flush of pending tasks is being executed
321 void UnscheduleFlush();
323 // This method is used for two purposes:
324 // 1. as a value passed to monitor.Wait() method
325 // 2. as in indicator that flush has to be performed
328 // - PR_INTERVAL_NO_TIMEOUT when no pending tasks are scheduled
329 // - larger then zero when tasks have been scheduled, but it is
330 // still not time to perform the flush ; it is actual interval
331 // time to wait until the flush has to happen
332 // - 0 when it is time to do the flush
333 PRIntervalTime
TimeUntilFlush();
335 // Notifies to the main thread that flush has completed
336 void NotifyFlushCompletion();
339 static void ThreadFunc(void* aArg
);
346 #endif /* DOMStorageDBThread_h___ */