Bumping manifests a=b2g-bump
[gecko.git] / dom / storage / DOMStorageDBThread.h
blobcba7c12e5847af460c22ee641fbbd1d98699c085
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"
18 #include "nsIThreadInternal.h"
20 class mozIStorageConnection;
22 namespace mozilla {
23 namespace dom {
25 class DOMStorageCacheBridge;
26 class DOMStorageUsageBridge;
27 class DOMStorageUsage;
29 typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
31 // Interface used by the cache to post operations to the asynchronous
32 // database thread or process.
33 class DOMStorageDBBridge
35 public:
36 DOMStorageDBBridge();
37 virtual ~DOMStorageDBBridge() {}
39 // Ensures the database engine is started
40 virtual nsresult Init() = 0;
42 // Releases the database and disallows its usage
43 virtual nsresult Shutdown() = 0;
45 // Asynchronously fills the cache with data from the database for first use.
46 // When |aPriority| is true, the preload operation is scheduled as the first one.
47 // This method is responsible to keep hard reference to the cache for the time of
48 // the preload or, when preload cannot be performed, call LoadDone() immediately.
49 virtual void AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority = false) = 0;
51 // Asynchronously fill the |usage| object with actual usage of data by its scope.
52 // The scope is eTLD+1 tops, never deeper subdomains.
53 virtual void AsyncGetUsage(DOMStorageUsageBridge* aUsage) = 0;
55 // Synchronously fills the cache, when |aForceSync| is false and cache already got some
56 // data before, the method waits for the running preload to finish
57 virtual void SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync = false) = 0;
59 // Called when an existing key is modified in the storage, schedules update to the database
60 virtual nsresult AsyncAddItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue) = 0;
62 // Called when an existing key is modified in the storage, schedules update to the database
63 virtual nsresult AsyncUpdateItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue) = 0;
65 // Called when an item is removed from the storage, schedules delete of the key
66 virtual nsresult AsyncRemoveItem(DOMStorageCacheBridge* aCache, const nsAString& aKey) = 0;
68 // Called when the whole storage is cleared by the DOM API, schedules delete of the scope
69 virtual nsresult AsyncClear(DOMStorageCacheBridge* aCache) = 0;
71 // Called when chrome deletes e.g. cookies, schedules delete of the whole database
72 virtual void AsyncClearAll() = 0;
74 // Called when only a domain and its subdomains or an app data is about to clear
75 virtual void AsyncClearMatchingScope(const nsACString& aScope) = 0;
77 // Forces scheduled DB operations to be early flushed to the disk
78 virtual void AsyncFlush() = 0;
80 // Check whether the scope has any data stored on disk and is thus allowed to preload
81 virtual bool ShouldPreloadScope(const nsACString& aScope) = 0;
83 // Get the complete list of scopes having data
84 virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes) = 0;
87 // The implementation of the the database engine, this directly works
88 // with the sqlite or any other db API we are based on
89 // This class is resposible for collecting and processing asynchronous
90 // DB operations over caches (DOMStorageCache) communicating though
91 // DOMStorageCacheBridge interface class
92 class DOMStorageDBThread MOZ_FINAL : public DOMStorageDBBridge
94 public:
95 class PendingOperations;
97 // Representation of a singe database task, like adding and removing keys,
98 // (pre)loading the whole origin data, cleaning.
99 class DBOperation
101 public:
102 typedef enum {
103 // Only operation that reads data from the database
104 opPreload,
105 // The same as opPreload, just executed with highest priority
106 opPreloadUrgent,
108 // Load usage of a scope
109 opGetUsage,
111 // Operations invoked by the DOM content API
112 opAddItem,
113 opUpdateItem,
114 opRemoveItem,
115 opClear,
117 // Operations invoked by chrome
118 opClearAll,
119 opClearMatchingScope,
120 } OperationType;
122 explicit DBOperation(const OperationType aType,
123 DOMStorageCacheBridge* aCache = nullptr,
124 const nsAString& aKey = EmptyString(),
125 const nsAString& aValue = EmptyString());
126 DBOperation(const OperationType aType,
127 DOMStorageUsageBridge* aUsage);
128 DBOperation(const OperationType aType,
129 const nsACString& aScope);
130 ~DBOperation();
132 // Executes the operation, doesn't necessarity have to be called on the I/O thread
133 void PerformAndFinalize(DOMStorageDBThread* aThread);
135 // Finalize the operation, i.e. do any internal cleanup and finish calls
136 void Finalize(nsresult aRv);
138 // The operation type
139 OperationType Type() { return mType; }
141 // The operation scope (=origin)
142 const nsCString Scope();
144 // |Scope + key| the operation is working with
145 const nsCString Target();
147 private:
148 // The operation implementation body
149 nsresult Perform(DOMStorageDBThread* aThread);
151 friend class PendingOperations;
152 OperationType mType;
153 nsRefPtr<DOMStorageCacheBridge> mCache;
154 nsRefPtr<DOMStorageUsageBridge> mUsage;
155 nsString mKey;
156 nsString mValue;
157 nsCString mScope;
160 // Encapsulation of collective and coalescing logic for all pending operations
161 // except preloads that are handled separately as priority operations
162 class PendingOperations {
163 public:
164 PendingOperations();
166 // Method responsible for coalescing redundant update operations with the same
167 // |Target()| or clear operations with the same or matching |Scope()|
168 void Add(DBOperation* aOperation);
170 // True when there are some scheduled operations to flush on disk
171 bool HasTasks();
173 // Moves collected operations to a local flat list to allow execution of the operation
174 // list out of the thread lock
175 bool Prepare();
177 // Executes the previously |Prepared()'ed| list of operations, retuns result, but doesn't
178 // handle it in any way in case of a failure
179 nsresult Execute(DOMStorageDBThread* aThread);
181 // Finalizes the pending operation list, returns false when too many operations failed
182 // to flush what indicates a long standing issue with the database access.
183 bool Finalize(nsresult aRv);
185 // true when a clear that deletes the given |scope| is among the pending operations;
186 // when a preload for that scope is being scheduled, it must be finished right away
187 bool IsScopeClearPending(const nsACString& aScope);
189 // Checks whether there is a pending update (or clear, actually) operation for this scope.
190 bool IsScopeUpdatePending(const nsACString& aScope);
192 private:
193 // Returns true iff new operation is of type newType and there is a pending
194 // operation of type pendingType for the same key (target).
195 bool CheckForCoalesceOpportunity(DBOperation* aNewOp,
196 DBOperation::OperationType aPendingType,
197 DBOperation::OperationType aNewType);
199 // List of all clearing operations, executed first
200 nsClassHashtable<nsCStringHashKey, DBOperation> mClears;
202 // List of all update/insert operations, executed as second
203 nsClassHashtable<nsCStringHashKey, DBOperation> mUpdates;
205 // Collection of all tasks, valid only between Prepare() and Execute()
206 nsTArray<nsAutoPtr<DBOperation> > mExecList;
208 // Number of failing flush attempts
209 uint32_t mFlushFailureCount;
212 class ThreadObserver MOZ_FINAL : public nsIThreadObserver
214 NS_DECL_THREADSAFE_ISUPPORTS
215 NS_DECL_NSITHREADOBSERVER
217 ThreadObserver()
218 : mHasPendingEvents(false)
219 , mMonitor("DOMStorageThreadMonitor")
223 bool HasPendingEvents() {
224 mMonitor.AssertCurrentThreadOwns();
225 return mHasPendingEvents;
227 void ClearPendingEvents() {
228 mMonitor.AssertCurrentThreadOwns();
229 mHasPendingEvents = false;
231 Monitor& GetMonitor() { return mMonitor; }
233 private:
234 virtual ~ThreadObserver() {}
235 bool mHasPendingEvents;
236 // The monitor we drive the thread with
237 Monitor mMonitor;
240 public:
241 DOMStorageDBThread();
242 virtual ~DOMStorageDBThread() {}
244 virtual nsresult Init();
245 virtual nsresult Shutdown();
247 virtual void AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority = false)
248 { InsertDBOp(new DBOperation(aPriority ? DBOperation::opPreloadUrgent : DBOperation::opPreload, aCache)); }
250 virtual void SyncPreload(DOMStorageCacheBridge* aCache, bool aForce = false);
252 virtual void AsyncGetUsage(DOMStorageUsageBridge * aUsage)
253 { InsertDBOp(new DBOperation(DBOperation::opGetUsage, aUsage)); }
255 virtual nsresult AsyncAddItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue)
256 { return InsertDBOp(new DBOperation(DBOperation::opAddItem, aCache, aKey, aValue)); }
258 virtual nsresult AsyncUpdateItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue)
259 { return InsertDBOp(new DBOperation(DBOperation::opUpdateItem, aCache, aKey, aValue)); }
261 virtual nsresult AsyncRemoveItem(DOMStorageCacheBridge* aCache, const nsAString& aKey)
262 { return InsertDBOp(new DBOperation(DBOperation::opRemoveItem, aCache, aKey)); }
264 virtual nsresult AsyncClear(DOMStorageCacheBridge* aCache)
265 { return InsertDBOp(new DBOperation(DBOperation::opClear, aCache)); }
267 virtual void AsyncClearAll()
268 { InsertDBOp(new DBOperation(DBOperation::opClearAll)); }
270 virtual void AsyncClearMatchingScope(const nsACString& aScope)
271 { InsertDBOp(new DBOperation(DBOperation::opClearMatchingScope, aScope)); }
273 virtual void AsyncFlush();
275 virtual bool ShouldPreloadScope(const nsACString& aScope);
276 virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes);
278 private:
279 nsCOMPtr<nsIFile> mDatabaseFile;
280 PRThread* mThread;
282 // Used to observe runnables dispatched to our thread and to monitor it.
283 nsRefPtr<ThreadObserver> mThreadObserver;
285 // Flag to stop, protected by the monitor returned by
286 // mThreadObserver->GetMonitor().
287 bool mStopIOThread;
289 // Whether WAL is enabled
290 bool mWALModeEnabled;
292 // Whether DB has already been open, avoid races between main thread reads
293 // and pending DB init in the background I/O thread
294 bool mDBReady;
296 // State of the database initiation
297 nsresult mStatus;
299 // List of scopes having data, for optimization purposes only
300 nsTHashtable<nsCStringHashKey> mScopesHavingData;
302 StatementCache mWorkerStatements;
303 StatementCache mReaderStatements;
305 // Connection used by the worker thread for all read and write ops
306 nsCOMPtr<mozIStorageConnection> mWorkerConnection;
308 // Connection used only on the main thread for sync read operations
309 nsCOMPtr<mozIStorageConnection> mReaderConnection;
311 // Time the first pending operation has been added to the pending operations
312 // list
313 PRIntervalTime mDirtyEpoch;
315 // Flag to force immediate flush of all pending operations
316 bool mFlushImmediately;
318 // List of preloading operations, in chronological or priority order.
319 // Executed prioritly over pending update operations.
320 nsTArray<DBOperation*> mPreloads;
322 // Collector of pending update operations
323 PendingOperations mPendingTasks;
325 // Counter of calls for thread priority rising.
326 int32_t mPriorityCounter;
328 // Helper to direct an operation to one of the arrays above;
329 // also checks IsScopeClearPending for preloads
330 nsresult InsertDBOp(DBOperation* aOperation);
332 // Opens the database, first thing we do after start of the thread.
333 nsresult OpenDatabaseConnection();
334 nsresult InitDatabase();
335 nsresult ShutdownDatabase();
337 // Tries to establish WAL mode
338 nsresult SetJournalMode(bool aIsWal);
339 nsresult TryJournalMode();
341 // Sets the threshold for auto-checkpointing the WAL.
342 nsresult ConfigureWALBehavior();
344 void SetHigherPriority();
345 void SetDefaultPriority();
347 // Ensures we flush pending tasks in some reasonble time
348 void ScheduleFlush();
350 // Called when flush of pending tasks is being executed
351 void UnscheduleFlush();
353 // This method is used for two purposes:
354 // 1. as a value passed to monitor.Wait() method
355 // 2. as in indicator that flush has to be performed
357 // Return:
358 // - PR_INTERVAL_NO_TIMEOUT when no pending tasks are scheduled
359 // - larger then zero when tasks have been scheduled, but it is
360 // still not time to perform the flush ; it is actual interval
361 // time to wait until the flush has to happen
362 // - 0 when it is time to do the flush
363 PRIntervalTime TimeUntilFlush();
365 // Notifies to the main thread that flush has completed
366 void NotifyFlushCompletion();
368 // Thread loop
369 static void ThreadFunc(void* aArg);
370 void ThreadFunc();
373 } // ::dom
374 } // ::mozilla
376 #endif /* DOMStorageDBThread_h___ */