Bumping manifests a=b2g-bump
[gecko.git] / dom / storage / DOMStorageDBThread.h
blob213d71cbc232df9fec78e8766b9dbea3fb343354
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___
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"
19 class mozIStorageConnection;
21 namespace mozilla {
22 namespace dom {
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
34 public:
35 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
93 public:
94 class PendingOperations;
96 // Representation of a singe database task, like adding and removing keys,
97 // (pre)loading the whole origin data, cleaning.
98 class DBOperation
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,
107 // Load usage of a scope
108 opGetUsage,
110 // Operations invoked by the DOM content API
111 opAddItem,
112 opUpdateItem,
113 opRemoveItem,
114 opClear,
116 // Operations invoked by chrome
117 opClearAll,
118 opClearMatchingScope,
119 } OperationType;
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);
129 ~DBOperation();
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();
146 private:
147 // The operation implementation body
148 nsresult Perform(DOMStorageDBThread* aThread);
150 friend class PendingOperations;
151 OperationType mType;
152 nsRefPtr<DOMStorageCacheBridge> mCache;
153 nsRefPtr<DOMStorageUsageBridge> mUsage;
154 nsString mKey;
155 nsString mValue;
156 nsCString mScope;
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();
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
170 bool HasTasks();
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();
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);
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);
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;
211 public:
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);
249 private:
250 nsCOMPtr<nsIFile> mDatabaseFile;
251 PRThread* mThread;
253 // The monitor we drive the thread with
254 Monitor mMonitor;
256 // Flag to stop, protected by the monitor
257 bool mStopIOThread;
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
264 bool mDBReady;
266 // State of the database initiation
267 nsresult mStatus;
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
282 // list
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
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();
335 // Notifies to the main thread that flush has completed
336 void NotifyFlushCompletion();
338 // Thread loop
339 static void ThreadFunc(void* aArg);
340 void ThreadFunc();
343 } // ::dom
344 } // ::mozilla
346 #endif /* DOMStorageDBThread_h___ */