DOMStorageDBThread.h 15 KB

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