dom/src/storage/DOMStorageDBThread.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial