dom/src/storage/DOMStorageDBThread.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/src/storage/DOMStorageDBThread.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,346 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef DOMStorageDBThread_h___
    1.10 +#define DOMStorageDBThread_h___
    1.11 +
    1.12 +#include "prthread.h"
    1.13 +#include "prinrval.h"
    1.14 +#include "nsTArray.h"
    1.15 +#include "mozilla/Monitor.h"
    1.16 +#include "mozilla/storage/StatementCache.h"
    1.17 +#include "nsString.h"
    1.18 +#include "nsCOMPtr.h"
    1.19 +#include "nsClassHashtable.h"
    1.20 +#include "nsIFile.h"
    1.21 +
    1.22 +class mozIStorageConnection;
    1.23 +
    1.24 +namespace mozilla {
    1.25 +namespace dom {
    1.26 +
    1.27 +class DOMStorageCacheBridge;
    1.28 +class DOMStorageUsageBridge;
    1.29 +class DOMStorageUsage;
    1.30 +
    1.31 +typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
    1.32 +
    1.33 +// Interface used by the cache to post operations to the asynchronous
    1.34 +// database thread or process.
    1.35 +class DOMStorageDBBridge
    1.36 +{
    1.37 +public:
    1.38 +  DOMStorageDBBridge();
    1.39 +  virtual ~DOMStorageDBBridge() {}
    1.40 +
    1.41 +  // Ensures the database engine is started
    1.42 +  virtual nsresult Init() = 0;
    1.43 +
    1.44 +  // Releases the database and disallows its usage
    1.45 +  virtual nsresult Shutdown() = 0;
    1.46 +
    1.47 +  // Asynchronously fills the cache with data from the database for first use.
    1.48 +  // When |aPriority| is true, the preload operation is scheduled as the first one.
    1.49 +  // This method is responsible to keep hard reference to the cache for the time of
    1.50 +  // the preload or, when preload cannot be performed, call LoadDone() immediately.
    1.51 +  virtual void AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority = false) = 0;
    1.52 +
    1.53 +  // Asynchronously fill the |usage| object with actual usage of data by its scope.
    1.54 +  // The scope is eTLD+1 tops, never deeper subdomains.
    1.55 +  virtual void AsyncGetUsage(DOMStorageUsageBridge* aUsage) = 0;
    1.56 +
    1.57 +  // Synchronously fills the cache, when |aForceSync| is false and cache already got some
    1.58 +  // data before, the method waits for the running preload to finish
    1.59 +  virtual void SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync = false) = 0;
    1.60 +
    1.61 +  // Called when an existing key is modified in the storage, schedules update to the database
    1.62 +  virtual nsresult AsyncAddItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue) = 0;
    1.63 +
    1.64 +  // Called when an existing key is modified in the storage, schedules update to the database
    1.65 +  virtual nsresult AsyncUpdateItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue) = 0;
    1.66 +
    1.67 +  // Called when an item is removed from the storage, schedules delete of the key
    1.68 +  virtual nsresult AsyncRemoveItem(DOMStorageCacheBridge* aCache, const nsAString& aKey) = 0;
    1.69 +
    1.70 +  // Called when the whole storage is cleared by the DOM API, schedules delete of the scope
    1.71 +  virtual nsresult AsyncClear(DOMStorageCacheBridge* aCache) = 0;
    1.72 +
    1.73 +  // Called when chrome deletes e.g. cookies, schedules delete of the whole database
    1.74 +  virtual void AsyncClearAll() = 0;
    1.75 +
    1.76 +  // Called when only a domain and its subdomains or an app data is about to clear
    1.77 +  virtual void AsyncClearMatchingScope(const nsACString& aScope) = 0;
    1.78 +
    1.79 +  // Forces scheduled DB operations to be early flushed to the disk
    1.80 +  virtual void AsyncFlush() = 0;
    1.81 +
    1.82 +  // Check whether the scope has any data stored on disk and is thus allowed to preload
    1.83 +  virtual bool ShouldPreloadScope(const nsACString& aScope) = 0;
    1.84 +
    1.85 +  // Get the complete list of scopes having data
    1.86 +  virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes) = 0;
    1.87 +};
    1.88 +
    1.89 +// The implementation of the the database engine, this directly works
    1.90 +// with the sqlite or any other db API we are based on
    1.91 +// This class is resposible for collecting and processing asynchronous 
    1.92 +// DB operations over caches (DOMStorageCache) communicating though 
    1.93 +// DOMStorageCacheBridge interface class
    1.94 +class DOMStorageDBThread MOZ_FINAL : public DOMStorageDBBridge
    1.95 +{
    1.96 +public:
    1.97 +  class PendingOperations;
    1.98 +
    1.99 +  // Representation of a singe database task, like adding and removing keys,
   1.100 +  // (pre)loading the whole origin data, cleaning.
   1.101 +  class DBOperation
   1.102 +  {
   1.103 +  public:
   1.104 +    typedef enum {
   1.105 +      // Only operation that reads data from the database
   1.106 +      opPreload,
   1.107 +      // The same as opPreload, just executed with highest priority
   1.108 +      opPreloadUrgent,
   1.109 +
   1.110 +      // Load usage of a scope
   1.111 +      opGetUsage,
   1.112 +
   1.113 +      // Operations invoked by the DOM content API
   1.114 +      opAddItem,
   1.115 +      opUpdateItem,
   1.116 +      opRemoveItem,
   1.117 +      opClear,
   1.118 +
   1.119 +      // Operations invoked by chrome
   1.120 +      opClearAll,
   1.121 +      opClearMatchingScope,
   1.122 +    } OperationType;
   1.123 +
   1.124 +    DBOperation(const OperationType aType,
   1.125 +                DOMStorageCacheBridge* aCache = nullptr,
   1.126 +                const nsAString& aKey = EmptyString(),
   1.127 +                const nsAString& aValue = EmptyString());
   1.128 +    DBOperation(const OperationType aType,
   1.129 +                DOMStorageUsageBridge* aUsage);
   1.130 +    DBOperation(const OperationType aType,
   1.131 +                const nsACString& aScope);
   1.132 +    ~DBOperation();
   1.133 +
   1.134 +    // Executes the operation, doesn't necessarity have to be called on the I/O thread
   1.135 +    void PerformAndFinalize(DOMStorageDBThread* aThread);
   1.136 +
   1.137 +    // Finalize the operation, i.e. do any internal cleanup and finish calls
   1.138 +    void Finalize(nsresult aRv);
   1.139 +
   1.140 +    // The operation type
   1.141 +    OperationType Type() { return mType; }
   1.142 +
   1.143 +    // The operation scope (=origin)
   1.144 +    const nsCString Scope();
   1.145 +
   1.146 +    // |Scope + key| the operation is working with
   1.147 +    const nsCString Target();
   1.148 +
   1.149 +  private:
   1.150 +    // The operation implementation body
   1.151 +    nsresult Perform(DOMStorageDBThread* aThread);
   1.152 +
   1.153 +    friend class PendingOperations;
   1.154 +    OperationType mType;
   1.155 +    nsRefPtr<DOMStorageCacheBridge> mCache;
   1.156 +    nsRefPtr<DOMStorageUsageBridge> mUsage;
   1.157 +    nsString mKey;
   1.158 +    nsString mValue;
   1.159 +    nsCString mScope;
   1.160 +  };
   1.161 +
   1.162 +  // Encapsulation of collective and coalescing logic for all pending operations
   1.163 +  // except preloads that are handled separately as priority operations
   1.164 +  class PendingOperations {
   1.165 +  public:
   1.166 +    PendingOperations();
   1.167 +
   1.168 +    // Method responsible for coalescing redundant update operations with the same
   1.169 +    // |Target()| or clear operations with the same or matching |Scope()|
   1.170 +    void Add(DBOperation* aOperation);
   1.171 +
   1.172 +    // True when there are some scheduled operations to flush on disk
   1.173 +    bool HasTasks();
   1.174 +
   1.175 +    // Moves collected operations to a local flat list to allow execution of the operation
   1.176 +    // list out of the thread lock
   1.177 +    bool Prepare();
   1.178 +
   1.179 +    // Executes the previously |Prepared()'ed| list of operations, retuns result, but doesn't
   1.180 +    // handle it in any way in case of a failure
   1.181 +    nsresult Execute(DOMStorageDBThread* aThread);
   1.182 +
   1.183 +    // Finalizes the pending operation list, returns false when too many operations failed
   1.184 +    // to flush what indicates a long standing issue with the database access.
   1.185 +    bool Finalize(nsresult aRv);
   1.186 +
   1.187 +    // true when a clear that deletes the given |scope| is among the pending operations;
   1.188 +    // when a preload for that scope is being scheduled, it must be finished right away
   1.189 +    bool IsScopeClearPending(const nsACString& aScope);
   1.190 +
   1.191 +    // Checks whether there is a pending update (or clear, actually) operation for this scope.
   1.192 +    bool IsScopeUpdatePending(const nsACString& aScope);
   1.193 +
   1.194 +  private:
   1.195 +    // Returns true iff new operation is of type newType and there is a pending 
   1.196 +    // operation of type pendingType for the same key (target).
   1.197 +    bool CheckForCoalesceOpportunity(DBOperation* aNewOp,
   1.198 +                                     DBOperation::OperationType aPendingType,
   1.199 +                                     DBOperation::OperationType aNewType);
   1.200 +
   1.201 +    // List of all clearing operations, executed first
   1.202 +    nsClassHashtable<nsCStringHashKey, DBOperation> mClears;
   1.203 +
   1.204 +    // List of all update/insert operations, executed as second
   1.205 +    nsClassHashtable<nsCStringHashKey, DBOperation> mUpdates;
   1.206 +
   1.207 +    // Collection of all tasks, valid only between Prepare() and Execute()
   1.208 +    nsTArray<nsAutoPtr<DBOperation> > mExecList;
   1.209 +
   1.210 +    // Number of failing flush attempts
   1.211 +    uint32_t mFlushFailureCount;
   1.212 +  };
   1.213 +
   1.214 +public:
   1.215 +  DOMStorageDBThread();
   1.216 +  virtual ~DOMStorageDBThread() {}
   1.217 +
   1.218 +  virtual nsresult Init();
   1.219 +  virtual nsresult Shutdown();
   1.220 +
   1.221 +  virtual void AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority = false)
   1.222 +    { InsertDBOp(new DBOperation(aPriority ? DBOperation::opPreloadUrgent : DBOperation::opPreload, aCache)); }
   1.223 +
   1.224 +  virtual void SyncPreload(DOMStorageCacheBridge* aCache, bool aForce = false);
   1.225 +
   1.226 +  virtual void AsyncGetUsage(DOMStorageUsageBridge * aUsage)
   1.227 +    { InsertDBOp(new DBOperation(DBOperation::opGetUsage, aUsage)); }
   1.228 +
   1.229 +  virtual nsresult AsyncAddItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue)
   1.230 +    { return InsertDBOp(new DBOperation(DBOperation::opAddItem, aCache, aKey, aValue)); }
   1.231 +
   1.232 +  virtual nsresult AsyncUpdateItem(DOMStorageCacheBridge* aCache, const nsAString& aKey, const nsAString& aValue)
   1.233 +    { return InsertDBOp(new DBOperation(DBOperation::opUpdateItem, aCache, aKey, aValue)); }
   1.234 +
   1.235 +  virtual nsresult AsyncRemoveItem(DOMStorageCacheBridge* aCache, const nsAString& aKey)
   1.236 +    { return InsertDBOp(new DBOperation(DBOperation::opRemoveItem, aCache, aKey)); }
   1.237 +
   1.238 +  virtual nsresult AsyncClear(DOMStorageCacheBridge* aCache)
   1.239 +    { return InsertDBOp(new DBOperation(DBOperation::opClear, aCache)); }
   1.240 +
   1.241 +  virtual void AsyncClearAll()
   1.242 +    { InsertDBOp(new DBOperation(DBOperation::opClearAll)); }
   1.243 +
   1.244 +  virtual void AsyncClearMatchingScope(const nsACString& aScope)
   1.245 +    { InsertDBOp(new DBOperation(DBOperation::opClearMatchingScope, aScope)); }
   1.246 +
   1.247 +  virtual void AsyncFlush();
   1.248 +
   1.249 +  virtual bool ShouldPreloadScope(const nsACString& aScope);
   1.250 +  virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes);
   1.251 +
   1.252 +private:
   1.253 +  nsCOMPtr<nsIFile> mDatabaseFile;
   1.254 +  PRThread* mThread;
   1.255 +
   1.256 +  // The monitor we drive the thread with
   1.257 +  Monitor mMonitor;
   1.258 +
   1.259 +  // Flag to stop, protected by the monitor
   1.260 +  bool mStopIOThread;
   1.261 +
   1.262 +  // Whether WAL is enabled
   1.263 +  bool mWALModeEnabled;
   1.264 +
   1.265 +  // Whether DB has already been open, avoid races between main thread reads
   1.266 +  // and pending DB init in the background I/O thread
   1.267 +  bool mDBReady;
   1.268 +
   1.269 +  // State of the database initiation
   1.270 +  nsresult mStatus;
   1.271 +
   1.272 +  // List of scopes having data, for optimization purposes only
   1.273 +  nsTHashtable<nsCStringHashKey> mScopesHavingData;
   1.274 +
   1.275 +  StatementCache mWorkerStatements;
   1.276 +  StatementCache mReaderStatements;
   1.277 +
   1.278 +  // Connection used by the worker thread for all read and write ops
   1.279 +  nsCOMPtr<mozIStorageConnection> mWorkerConnection;
   1.280 +
   1.281 +  // Connection used only on the main thread for sync read operations
   1.282 +  nsCOMPtr<mozIStorageConnection> mReaderConnection;
   1.283 +
   1.284 +  // Time the first pending operation has been added to the pending operations
   1.285 +  // list
   1.286 +  PRIntervalTime mDirtyEpoch;
   1.287 +
   1.288 +  // Flag to force immediate flush of all pending operations
   1.289 +  bool mFlushImmediately;
   1.290 +
   1.291 +  // List of preloading operations, in chronological or priority order.
   1.292 +  // Executed prioritly over pending update operations.
   1.293 +  nsTArray<DBOperation*> mPreloads;
   1.294 +
   1.295 +  // Collector of pending update operations
   1.296 +  PendingOperations mPendingTasks;
   1.297 +
   1.298 +  // Counter of calls for thread priority rising.
   1.299 +  int32_t mPriorityCounter;
   1.300 +
   1.301 +  // Helper to direct an operation to one of the arrays above;
   1.302 +  // also checks IsScopeClearPending for preloads
   1.303 +  nsresult InsertDBOp(DBOperation* aOperation);
   1.304 +
   1.305 +  // Opens the database, first thing we do after start of the thread.
   1.306 +  nsresult OpenDatabaseConnection();
   1.307 +  nsresult InitDatabase();
   1.308 +  nsresult ShutdownDatabase();
   1.309 +
   1.310 +  // Tries to establish WAL mode
   1.311 +  nsresult SetJournalMode(bool aIsWal);
   1.312 +  nsresult TryJournalMode();
   1.313 +
   1.314 +  // Sets the threshold for auto-checkpointing the WAL.
   1.315 +  nsresult ConfigureWALBehavior();
   1.316 +
   1.317 +  void SetHigherPriority();
   1.318 +  void SetDefaultPriority();
   1.319 +
   1.320 +  // Ensures we flush pending tasks in some reasonble time
   1.321 +  void ScheduleFlush();
   1.322 +
   1.323 +  // Called when flush of pending tasks is being executed
   1.324 +  void UnscheduleFlush();
   1.325 +
   1.326 +  // This method is used for two purposes:
   1.327 +  // 1. as a value passed to monitor.Wait() method
   1.328 +  // 2. as in indicator that flush has to be performed
   1.329 +  //
   1.330 +  // Return:
   1.331 +  // - PR_INTERVAL_NO_TIMEOUT when no pending tasks are scheduled
   1.332 +  // - larger then zero when tasks have been scheduled, but it is
   1.333 +  //   still not time to perform the flush ; it is actual interval
   1.334 +  //   time to wait until the flush has to happen
   1.335 +  // - 0 when it is time to do the flush
   1.336 +  PRIntervalTime TimeUntilFlush();
   1.337 +
   1.338 +  // Notifies to the main thread that flush has completed
   1.339 +  void NotifyFlushCompletion();
   1.340 +
   1.341 +  // Thread loop
   1.342 +  static void ThreadFunc(void* aArg);
   1.343 +  void ThreadFunc();
   1.344 +};
   1.345 +
   1.346 +} // ::dom
   1.347 +} // ::mozilla
   1.348 +
   1.349 +#endif /* DOMStorageDBThread_h___ */

mercurial