dom/src/storage/DOMStorageDBThread.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:c1c546e54b6a
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/. */
5
6 #ifndef DOMStorageDBThread_h___
7 #define DOMStorageDBThread_h___
8
9 #include "prthread.h"
10 #include "prinrval.h"
11 #include "nsTArray.h"
12 #include "mozilla/Monitor.h"
13 #include "mozilla/storage/StatementCache.h"
14 #include "nsString.h"
15 #include "nsCOMPtr.h"
16 #include "nsClassHashtable.h"
17 #include "nsIFile.h"
18
19 class mozIStorageConnection;
20
21 namespace mozilla {
22 namespace dom {
23
24 class DOMStorageCacheBridge;
25 class DOMStorageUsageBridge;
26 class DOMStorageUsage;
27
28 typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
29
30 // Interface used by the cache to post operations to the asynchronous
31 // database thread or process.
32 class DOMStorageDBBridge
33 {
34 public:
35 DOMStorageDBBridge();
36 virtual ~DOMStorageDBBridge() {}
37
38 // Ensures the database engine is started
39 virtual nsresult Init() = 0;
40
41 // Releases the database and disallows its usage
42 virtual nsresult Shutdown() = 0;
43
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;
49
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;
53
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;
57
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;
60
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;
63
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;
66
67 // Called when the whole storage is cleared by the DOM API, schedules delete of the scope
68 virtual nsresult AsyncClear(DOMStorageCacheBridge* aCache) = 0;
69
70 // Called when chrome deletes e.g. cookies, schedules delete of the whole database
71 virtual void AsyncClearAll() = 0;
72
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;
75
76 // Forces scheduled DB operations to be early flushed to the disk
77 virtual void AsyncFlush() = 0;
78
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;
81
82 // Get the complete list of scopes having data
83 virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes) = 0;
84 };
85
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
92 {
93 public:
94 class PendingOperations;
95
96 // Representation of a singe database task, like adding and removing keys,
97 // (pre)loading the whole origin data, cleaning.
98 class DBOperation
99 {
100 public:
101 typedef enum {
102 // Only operation that reads data from the database
103 opPreload,
104 // The same as opPreload, just executed with highest priority
105 opPreloadUrgent,
106
107 // Load usage of a scope
108 opGetUsage,
109
110 // Operations invoked by the DOM content API
111 opAddItem,
112 opUpdateItem,
113 opRemoveItem,
114 opClear,
115
116 // Operations invoked by chrome
117 opClearAll,
118 opClearMatchingScope,
119 } OperationType;
120
121 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);
129 ~DBOperation();
130
131 // Executes the operation, doesn't necessarity have to be called on the I/O thread
132 void PerformAndFinalize(DOMStorageDBThread* aThread);
133
134 // Finalize the operation, i.e. do any internal cleanup and finish calls
135 void Finalize(nsresult aRv);
136
137 // The operation type
138 OperationType Type() { return mType; }
139
140 // The operation scope (=origin)
141 const nsCString Scope();
142
143 // |Scope + key| the operation is working with
144 const nsCString Target();
145
146 private:
147 // The operation implementation body
148 nsresult Perform(DOMStorageDBThread* aThread);
149
150 friend class PendingOperations;
151 OperationType mType;
152 nsRefPtr<DOMStorageCacheBridge> mCache;
153 nsRefPtr<DOMStorageUsageBridge> mUsage;
154 nsString mKey;
155 nsString mValue;
156 nsCString mScope;
157 };
158
159 // Encapsulation of collective and coalescing logic for all pending operations
160 // except preloads that are handled separately as priority operations
161 class PendingOperations {
162 public:
163 PendingOperations();
164
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);
168
169 // True when there are some scheduled operations to flush on disk
170 bool HasTasks();
171
172 // Moves collected operations to a local flat list to allow execution of the operation
173 // list out of the thread lock
174 bool Prepare();
175
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);
179
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);
183
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);
187
188 // Checks whether there is a pending update (or clear, actually) operation for this scope.
189 bool IsScopeUpdatePending(const nsACString& aScope);
190
191 private:
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);
197
198 // List of all clearing operations, executed first
199 nsClassHashtable<nsCStringHashKey, DBOperation> mClears;
200
201 // List of all update/insert operations, executed as second
202 nsClassHashtable<nsCStringHashKey, DBOperation> mUpdates;
203
204 // Collection of all tasks, valid only between Prepare() and Execute()
205 nsTArray<nsAutoPtr<DBOperation> > mExecList;
206
207 // Number of failing flush attempts
208 uint32_t mFlushFailureCount;
209 };
210
211 public:
212 DOMStorageDBThread();
213 virtual ~DOMStorageDBThread() {}
214
215 virtual nsresult Init();
216 virtual nsresult Shutdown();
217
218 virtual void AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority = false)
219 { InsertDBOp(new DBOperation(aPriority ? DBOperation::opPreloadUrgent : DBOperation::opPreload, aCache)); }
220
221 virtual void SyncPreload(DOMStorageCacheBridge* aCache, bool aForce = false);
222
223 virtual void AsyncGetUsage(DOMStorageUsageBridge * aUsage)
224 { InsertDBOp(new DBOperation(DBOperation::opGetUsage, aUsage)); }
225
226 virtual nsresult AsyncAddItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue)
227 { return InsertDBOp(new DBOperation(DBOperation::opAddItem, aCache, aKey, aValue)); }
228
229 virtual nsresult AsyncUpdateItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue)
230 { return InsertDBOp(new DBOperation(DBOperation::opUpdateItem, aCache, aKey, aValue)); }
231
232 virtual nsresult AsyncRemoveItem(DOMStorageCacheBridge* aCache, const nsAString& aKey)
233 { return InsertDBOp(new DBOperation(DBOperation::opRemoveItem, aCache, aKey)); }
234
235 virtual nsresult AsyncClear(DOMStorageCacheBridge* aCache)
236 { return InsertDBOp(new DBOperation(DBOperation::opClear, aCache)); }
237
238 virtual void AsyncClearAll()
239 { InsertDBOp(new DBOperation(DBOperation::opClearAll)); }
240
241 virtual void AsyncClearMatchingScope(const nsACString& aScope)
242 { InsertDBOp(new DBOperation(DBOperation::opClearMatchingScope, aScope)); }
243
244 virtual void AsyncFlush();
245
246 virtual bool ShouldPreloadScope(const nsACString& aScope);
247 virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes);
248
249 private:
250 nsCOMPtr<nsIFile> mDatabaseFile;
251 PRThread* mThread;
252
253 // The monitor we drive the thread with
254 Monitor mMonitor;
255
256 // Flag to stop, protected by the monitor
257 bool mStopIOThread;
258
259 // Whether WAL is enabled
260 bool mWALModeEnabled;
261
262 // Whether DB has already been open, avoid races between main thread reads
263 // and pending DB init in the background I/O thread
264 bool mDBReady;
265
266 // State of the database initiation
267 nsresult mStatus;
268
269 // List of scopes having data, for optimization purposes only
270 nsTHashtable<nsCStringHashKey> mScopesHavingData;
271
272 StatementCache mWorkerStatements;
273 StatementCache mReaderStatements;
274
275 // Connection used by the worker thread for all read and write ops
276 nsCOMPtr<mozIStorageConnection> mWorkerConnection;
277
278 // Connection used only on the main thread for sync read operations
279 nsCOMPtr<mozIStorageConnection> mReaderConnection;
280
281 // Time the first pending operation has been added to the pending operations
282 // list
283 PRIntervalTime mDirtyEpoch;
284
285 // Flag to force immediate flush of all pending operations
286 bool mFlushImmediately;
287
288 // List of preloading operations, in chronological or priority order.
289 // Executed prioritly over pending update operations.
290 nsTArray<DBOperation*> mPreloads;
291
292 // Collector of pending update operations
293 PendingOperations mPendingTasks;
294
295 // Counter of calls for thread priority rising.
296 int32_t mPriorityCounter;
297
298 // Helper to direct an operation to one of the arrays above;
299 // also checks IsScopeClearPending for preloads
300 nsresult InsertDBOp(DBOperation* aOperation);
301
302 // Opens the database, first thing we do after start of the thread.
303 nsresult OpenDatabaseConnection();
304 nsresult InitDatabase();
305 nsresult ShutdownDatabase();
306
307 // Tries to establish WAL mode
308 nsresult SetJournalMode(bool aIsWal);
309 nsresult TryJournalMode();
310
311 // Sets the threshold for auto-checkpointing the WAL.
312 nsresult ConfigureWALBehavior();
313
314 void SetHigherPriority();
315 void SetDefaultPriority();
316
317 // Ensures we flush pending tasks in some reasonble time
318 void ScheduleFlush();
319
320 // Called when flush of pending tasks is being executed
321 void UnscheduleFlush();
322
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
326 //
327 // Return:
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();
334
335 // Notifies to the main thread that flush has completed
336 void NotifyFlushCompletion();
337
338 // Thread loop
339 static void ThreadFunc(void* aArg);
340 void ThreadFunc();
341 };
342
343 } // ::dom
344 } // ::mozilla
345
346 #endif /* DOMStorageDBThread_h___ */

mercurial