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"
18 #include "nsIThreadInternal.h"
20 class mozIStorageConnection
;
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
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
95 class PendingOperations
;
97 // Representation of a singe database task, like adding and removing keys,
98 // (pre)loading the whole origin data, cleaning.
103 // Only operation that reads data from the database
105 // The same as opPreload, just executed with highest priority
108 // Load usage of a scope
111 // Operations invoked by the DOM content API
117 // Operations invoked by chrome
119 opClearMatchingScope
,
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
);
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();
148 // The operation implementation body
149 nsresult
Perform(DOMStorageDBThread
* aThread
);
151 friend class PendingOperations
;
153 nsRefPtr
<DOMStorageCacheBridge
> mCache
;
154 nsRefPtr
<DOMStorageUsageBridge
> mUsage
;
160 // Encapsulation of collective and coalescing logic for all pending operations
161 // except preloads that are handled separately as priority operations
162 class 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
173 // Moves collected operations to a local flat list to allow execution of the operation
174 // list out of the thread lock
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
);
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
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
; }
234 virtual ~ThreadObserver() {}
235 bool mHasPendingEvents
;
236 // The monitor we drive the thread with
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
);
279 nsCOMPtr
<nsIFile
> mDatabaseFile
;
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().
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
296 // State of the database initiation
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
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
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();
369 static void ThreadFunc(void* aArg
);
376 #endif /* DOMStorageDBThread_h___ */