LCOV - code coverage report
Current view: top level - dom/storage - StorageDBThread.h (source / functions) Hit Total Coverage
Test: output.info Lines: 18 45 40.0 %
Date: 2017-07-14 16:53:18 Functions: 6 22 27.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_dom_StorageDBThread_h
       8             : #define mozilla_dom_StorageDBThread_h
       9             : 
      10             : #include "prthread.h"
      11             : #include "prinrval.h"
      12             : #include "nsTArray.h"
      13             : #include "mozilla/Atomics.h"
      14             : #include "mozilla/Monitor.h"
      15             : #include "mozilla/BasePrincipal.h"
      16             : #include "mozilla/storage/StatementCache.h"
      17             : #include "nsAutoPtr.h"
      18             : #include "nsString.h"
      19             : #include "nsCOMPtr.h"
      20             : #include "nsClassHashtable.h"
      21             : #include "nsIFile.h"
      22             : #include "nsIThreadInternal.h"
      23             : 
      24             : class mozIStorageConnection;
      25             : 
      26             : namespace mozilla {
      27             : namespace dom {
      28             : 
      29             : class LocalStorageCacheBridge;
      30             : class StorageUsageBridge;
      31             : class StorageUsage;
      32             : 
      33             : typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
      34             : 
      35             : // Interface used by the cache to post operations to the asynchronous
      36             : // database thread or process.
      37             : class StorageDBBridge
      38             : {
      39             : public:
      40             :   StorageDBBridge();
      41           0 :   virtual ~StorageDBBridge() {}
      42             : 
      43             :   // Ensures the database engine is started
      44             :   virtual nsresult Init() = 0;
      45             : 
      46             :   // Releases the database and disallows its usage
      47             :   virtual nsresult Shutdown() = 0;
      48             : 
      49             :   // Asynchronously fills the cache with data from the database for first use.
      50             :   // When |aPriority| is true, the preload operation is scheduled as the first
      51             :   // one.  This method is responsible to keep hard reference to the cache for
      52             :   // the time of the preload or, when preload cannot be performed, call
      53             :   // LoadDone() immediately.
      54             :   virtual void AsyncPreload(LocalStorageCacheBridge* aCache,
      55             :                             bool aPriority = false) = 0;
      56             : 
      57             :   // Asynchronously fill the |usage| object with actual usage of data by its
      58             :   // scope.  The scope is eTLD+1 tops, never deeper subdomains.
      59             :   virtual void AsyncGetUsage(StorageUsageBridge* aUsage) = 0;
      60             : 
      61             :   // Synchronously fills the cache, when |aForceSync| is false and cache already
      62             :   // got some data before, the method waits for the running preload to finish
      63             :   virtual void SyncPreload(LocalStorageCacheBridge* aCache,
      64             :                            bool aForceSync = false) = 0;
      65             : 
      66             :   // Called when an existing key is modified in the storage, schedules update to
      67             :   // the database
      68             :   virtual nsresult AsyncAddItem(LocalStorageCacheBridge* aCache,
      69             :                                 const nsAString& aKey,
      70             :                                 const nsAString& aValue) = 0;
      71             : 
      72             :   // Called when an existing key is modified in the storage, schedules update to
      73             :   // the database
      74             :   virtual nsresult AsyncUpdateItem(LocalStorageCacheBridge* aCache,
      75             :                                    const nsAString& aKey,
      76             :                                    const nsAString& aValue) = 0;
      77             : 
      78             :   // Called when an item is removed from the storage, schedules delete of the
      79             :   // key
      80             :   virtual nsresult AsyncRemoveItem(LocalStorageCacheBridge* aCache,
      81             :                                    const nsAString& aKey) = 0;
      82             : 
      83             :   // Called when the whole storage is cleared by the DOM API, schedules delete
      84             :   // of the scope
      85             :   virtual nsresult AsyncClear(LocalStorageCacheBridge* aCache) = 0;
      86             : 
      87             :   // Called when chrome deletes e.g. cookies, schedules delete of the whole
      88             :   // database
      89             :   virtual void AsyncClearAll() = 0;
      90             : 
      91             :   // Called when only a domain and its subdomains is about to clear
      92             :   virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix) = 0;
      93             : 
      94             :   // Called when data matching an origin pattern have to be cleared
      95             :   virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern) = 0;
      96             : 
      97             :   // Forces scheduled DB operations to be early flushed to the disk
      98             :   virtual void AsyncFlush() = 0;
      99             : 
     100             :   // Check whether the scope has any data stored on disk and is thus allowed to
     101             :   // preload
     102             :   virtual bool ShouldPreloadOrigin(const nsACString& aOriginNoSuffix) = 0;
     103             : 
     104             :   // Get the complete list of scopes having data
     105             :   virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins) = 0;
     106             : };
     107             : 
     108             : // The implementation of the the database engine, this directly works
     109             : // with the sqlite or any other db API we are based on
     110             : // This class is resposible for collecting and processing asynchronous
     111             : // DB operations over caches (LocalStorageCache) communicating though
     112             : // LocalStorageCacheBridge interface class
     113             : class StorageDBThread final : public StorageDBBridge
     114             : {
     115             : public:
     116             :   class PendingOperations;
     117             : 
     118             :   // Representation of a singe database task, like adding and removing keys,
     119             :   // (pre)loading the whole origin data, cleaning.
     120             :   class DBOperation
     121             :   {
     122             :   public:
     123             :     typedef enum {
     124             :       // Only operation that reads data from the database
     125             :       opPreload,
     126             :       // The same as opPreload, just executed with highest priority
     127             :       opPreloadUrgent,
     128             : 
     129             :       // Load usage of a scope
     130             :       opGetUsage,
     131             : 
     132             :       // Operations invoked by the DOM content API
     133             :       opAddItem,
     134             :       opUpdateItem,
     135             :       opRemoveItem,
     136             :       // Clears a specific single origin data
     137             :       opClear,
     138             : 
     139             :       // Operations invoked by chrome
     140             : 
     141             :       // Clear all the data stored in the database, for all scopes, no
     142             :       // exceptions
     143             :       opClearAll,
     144             :       // Clear data under a domain and all its subdomains regardless
     145             :       // OriginAttributes value
     146             :       opClearMatchingOrigin,
     147             :       // Clear all data matching an OriginAttributesPattern regardless a domain
     148             :       opClearMatchingOriginAttributes,
     149             :     } OperationType;
     150             : 
     151             :     explicit DBOperation(const OperationType aType,
     152             :                          LocalStorageCacheBridge* aCache = nullptr,
     153           2 :                          const nsAString& aKey = EmptyString(),
     154           2 :                          const nsAString& aValue = EmptyString());
     155             :     DBOperation(const OperationType aType,
     156             :                 StorageUsageBridge* aUsage);
     157             :     DBOperation(const OperationType aType,
     158             :                 const nsACString& aOriginNoSuffix);
     159             :     DBOperation(const OperationType aType,
     160             :                 const OriginAttributesPattern& aOriginNoSuffix);
     161             :     ~DBOperation();
     162             : 
     163             :     // Executes the operation, doesn't necessarity have to be called on the I/O
     164             :     // thread
     165             :     void PerformAndFinalize(StorageDBThread* aThread);
     166             : 
     167             :     // Finalize the operation, i.e. do any internal cleanup and finish calls
     168             :     void Finalize(nsresult aRv);
     169             : 
     170             :     // The operation type
     171           9 :     OperationType Type() const { return mType; }
     172             : 
     173             :     // The origin in the database usage format (reversed)
     174             :     const nsCString OriginNoSuffix() const;
     175             : 
     176             :     // The origin attributes suffix
     177             :     const nsCString OriginSuffix() const;
     178             : 
     179             :     // |origin suffix + origin key| the operation is working with or a scope
     180             :     // pattern to delete with simple SQL's "LIKE %" from the database.
     181             :     const nsCString Origin() const;
     182             : 
     183             :     // |origin suffix + origin key + key| the operation is working with
     184             :     const nsCString Target() const;
     185             : 
     186             :     // Pattern to delete matching data with this op
     187           0 :     const OriginAttributesPattern& OriginPattern() const
     188             :     {
     189           0 :       return mOriginPattern;
     190             :     }
     191             : 
     192             :   private:
     193             :     // The operation implementation body
     194             :     nsresult Perform(StorageDBThread* aThread);
     195             : 
     196             :     friend class PendingOperations;
     197             :     OperationType mType;
     198             :     RefPtr<LocalStorageCacheBridge> mCache;
     199             :     RefPtr<StorageUsageBridge> mUsage;
     200             :     nsString const mKey;
     201             :     nsString const mValue;
     202             :     nsCString const mOrigin;
     203             :     OriginAttributesPattern const mOriginPattern;
     204             :   };
     205             : 
     206             :   // Encapsulation of collective and coalescing logic for all pending operations
     207             :   // except preloads that are handled separately as priority operations
     208           0 :   class PendingOperations {
     209             :   public:
     210             :     PendingOperations();
     211             : 
     212             :     // Method responsible for coalescing redundant update operations with the
     213             :     // same |Target()| or clear operations with the same or matching |Origin()|
     214             :     void Add(DBOperation* aOperation);
     215             : 
     216             :     // True when there are some scheduled operations to flush on disk
     217             :     bool HasTasks() const;
     218             : 
     219             :     // Moves collected operations to a local flat list to allow execution of the
     220             :     // operation list out of the thread lock
     221             :     bool Prepare();
     222             : 
     223             :     // Executes the previously |Prepared()'ed| list of operations, returns
     224             :     // result, but doesn't handle it in any way in case of a failure
     225             :     nsresult Execute(StorageDBThread* aThread);
     226             : 
     227             :     // Finalizes the pending operation list, returns false when too many
     228             :     // operations failed to flush what indicates a long standing issue with the
     229             :     // database access.
     230             :     bool Finalize(nsresult aRv);
     231             : 
     232             :     // true when a clear that deletes the given origin attr pattern and/or
     233             :     // origin key is among the pending operations; when a preload for that scope
     234             :     // is being scheduled, it must be finished right away
     235             :     bool IsOriginClearPending(const nsACString& aOriginSuffix,
     236             :                               const nsACString& aOriginNoSuffix) const;
     237             : 
     238             :     // Checks whether there is a pending update operation for this scope.
     239             :     bool IsOriginUpdatePending(const nsACString& aOriginSuffix,
     240             :                                const nsACString& aOriginNoSuffix) const;
     241             : 
     242             :   private:
     243             :     // Returns true iff new operation is of type newType and there is a pending
     244             :     // operation of type pendingType for the same key (target).
     245             :     bool CheckForCoalesceOpportunity(DBOperation* aNewOp,
     246             :                                      DBOperation::OperationType aPendingType,
     247             :                                      DBOperation::OperationType aNewType);
     248             : 
     249             :     // List of all clearing operations, executed first
     250             :     nsClassHashtable<nsCStringHashKey, DBOperation> mClears;
     251             : 
     252             :     // List of all update/insert operations, executed as second
     253             :     nsClassHashtable<nsCStringHashKey, DBOperation> mUpdates;
     254             : 
     255             :     // Collection of all tasks, valid only between Prepare() and Execute()
     256             :     nsTArray<nsAutoPtr<DBOperation> > mExecList;
     257             : 
     258             :     // Number of failing flush attempts
     259             :     uint32_t mFlushFailureCount;
     260             :   };
     261             : 
     262             :   class ThreadObserver final : public nsIThreadObserver
     263             :   {
     264             :     NS_DECL_THREADSAFE_ISUPPORTS
     265             :     NS_DECL_NSITHREADOBSERVER
     266             : 
     267           1 :     ThreadObserver()
     268           1 :       : mHasPendingEvents(false)
     269           1 :       , mMonitor("StorageThreadMonitor")
     270             :     {
     271           1 :     }
     272             : 
     273           4 :     bool HasPendingEvents() {
     274           4 :       mMonitor.AssertCurrentThreadOwns();
     275           4 :       return mHasPendingEvents;
     276             :     }
     277           0 :     void ClearPendingEvents() {
     278           0 :       mMonitor.AssertCurrentThreadOwns();
     279           0 :       mHasPendingEvents = false;
     280           0 :     }
     281           8 :     Monitor& GetMonitor() { return mMonitor; }
     282             : 
     283             :   private:
     284           0 :     virtual ~ThreadObserver() {}
     285             :     bool mHasPendingEvents;
     286             :     // The monitor we drive the thread with
     287             :     Monitor mMonitor;
     288             :   };
     289             : 
     290             : public:
     291             :   StorageDBThread();
     292           0 :   virtual ~StorageDBThread() {}
     293             : 
     294             :   virtual nsresult Init();
     295             :   virtual nsresult Shutdown();
     296             : 
     297           2 :   virtual void AsyncPreload(LocalStorageCacheBridge* aCache,
     298             :                             bool aPriority = false)
     299             :   {
     300           4 :     InsertDBOp(new DBOperation(aPriority
     301             :                                  ? DBOperation::opPreloadUrgent
     302             :                                  : DBOperation::opPreload,
     303           2 :                                aCache));
     304           2 :   }
     305             : 
     306             :   virtual void SyncPreload(LocalStorageCacheBridge* aCache,
     307             :                            bool aForce = false);
     308             : 
     309           1 :   virtual void AsyncGetUsage(StorageUsageBridge* aUsage)
     310             :   {
     311           1 :     InsertDBOp(new DBOperation(DBOperation::opGetUsage, aUsage));
     312           1 :   }
     313             : 
     314           0 :   virtual nsresult AsyncAddItem(LocalStorageCacheBridge* aCache,
     315             :                                 const nsAString& aKey,
     316             :                                 const nsAString& aValue)
     317             :   {
     318             :     return InsertDBOp(new DBOperation(DBOperation::opAddItem, aCache, aKey,
     319           0 :                                       aValue));
     320             :   }
     321             : 
     322           0 :   virtual nsresult AsyncUpdateItem(LocalStorageCacheBridge* aCache,
     323             :                                    const nsAString& aKey,
     324             :                                    const nsAString& aValue)
     325             :   {
     326             :     return InsertDBOp(new DBOperation(DBOperation::opUpdateItem, aCache, aKey,
     327           0 :                                       aValue));
     328             :   }
     329             : 
     330           0 :   virtual nsresult AsyncRemoveItem(LocalStorageCacheBridge* aCache,
     331             :                                    const nsAString& aKey)
     332             :   {
     333           0 :     return InsertDBOp(new DBOperation(DBOperation::opRemoveItem, aCache, aKey));
     334             :   }
     335             : 
     336           0 :   virtual nsresult AsyncClear(LocalStorageCacheBridge* aCache)
     337             :   {
     338           0 :     return InsertDBOp(new DBOperation(DBOperation::opClear, aCache));
     339             :   }
     340             : 
     341           0 :   virtual void AsyncClearAll()
     342             :   {
     343           0 :     InsertDBOp(new DBOperation(DBOperation::opClearAll));
     344           0 :   }
     345             : 
     346           0 :   virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix)
     347             :   {
     348             :     InsertDBOp(new DBOperation(DBOperation::opClearMatchingOrigin,
     349           0 :                                aOriginNoSuffix));
     350           0 :   }
     351             : 
     352           0 :   virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern)
     353             :   {
     354             :     InsertDBOp(new DBOperation(DBOperation::opClearMatchingOriginAttributes,
     355           0 :                                aPattern));
     356           0 :   }
     357             : 
     358             :   virtual void AsyncFlush();
     359             : 
     360             :   virtual bool ShouldPreloadOrigin(const nsACString& aOrigin);
     361             :   virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins);
     362             : 
     363             : private:
     364             :   nsCOMPtr<nsIFile> mDatabaseFile;
     365             :   PRThread* mThread;
     366             : 
     367             :   // Used to observe runnables dispatched to our thread and to monitor it.
     368             :   RefPtr<ThreadObserver> mThreadObserver;
     369             : 
     370             :   // Flag to stop, protected by the monitor returned by
     371             :   // mThreadObserver->GetMonitor().
     372             :   bool mStopIOThread;
     373             : 
     374             :   // Whether WAL is enabled
     375             :   bool mWALModeEnabled;
     376             : 
     377             :   // Whether DB has already been open, avoid races between main thread reads
     378             :   // and pending DB init in the background I/O thread
     379             :   Atomic<bool, ReleaseAcquire> mDBReady;
     380             : 
     381             :   // State of the database initiation
     382             :   nsresult mStatus;
     383             : 
     384             :   // List of origins (including origin attributes suffix) having data, for
     385             :   // optimization purposes only
     386             :   nsTHashtable<nsCStringHashKey> mOriginsHavingData;
     387             : 
     388             :   // Connection used by the worker thread for all read and write ops
     389             :   nsCOMPtr<mozIStorageConnection> mWorkerConnection;
     390             : 
     391             :   // Connection used only on the main thread for sync read operations
     392             :   nsCOMPtr<mozIStorageConnection> mReaderConnection;
     393             : 
     394             :   StatementCache mWorkerStatements;
     395             :   StatementCache mReaderStatements;
     396             : 
     397             :   // Time the first pending operation has been added to the pending operations
     398             :   // list
     399             :   PRIntervalTime mDirtyEpoch;
     400             : 
     401             :   // Flag to force immediate flush of all pending operations
     402             :   bool mFlushImmediately;
     403             : 
     404             :   // List of preloading operations, in chronological or priority order.
     405             :   // Executed prioritly over pending update operations.
     406             :   nsTArray<DBOperation*> mPreloads;
     407             : 
     408             :   // Collector of pending update operations
     409             :   PendingOperations mPendingTasks;
     410             : 
     411             :   // Counter of calls for thread priority rising.
     412             :   int32_t mPriorityCounter;
     413             : 
     414             :   // Helper to direct an operation to one of the arrays above;
     415             :   // also checks IsOriginClearPending for preloads
     416             :   nsresult InsertDBOp(DBOperation* aOperation);
     417             : 
     418             :   // Opens the database, first thing we do after start of the thread.
     419             :   nsresult OpenDatabaseConnection();
     420             :   nsresult OpenAndUpdateDatabase();
     421             :   nsresult InitDatabase();
     422             :   nsresult ShutdownDatabase();
     423             : 
     424             :   // Tries to establish WAL mode
     425             :   nsresult SetJournalMode(bool aIsWal);
     426             :   nsresult TryJournalMode();
     427             : 
     428             :   // Sets the threshold for auto-checkpointing the WAL.
     429             :   nsresult ConfigureWALBehavior();
     430             : 
     431             :   void SetHigherPriority();
     432             :   void SetDefaultPriority();
     433             : 
     434             :   // Ensures we flush pending tasks in some reasonble time
     435             :   void ScheduleFlush();
     436             : 
     437             :   // Called when flush of pending tasks is being executed
     438             :   void UnscheduleFlush();
     439             : 
     440             :   // This method is used for two purposes:
     441             :   // 1. as a value passed to monitor.Wait() method
     442             :   // 2. as in indicator that flush has to be performed
     443             :   //
     444             :   // Return:
     445             :   // - PR_INTERVAL_NO_TIMEOUT when no pending tasks are scheduled
     446             :   // - larger then zero when tasks have been scheduled, but it is
     447             :   //   still not time to perform the flush ; it is actual interval
     448             :   //   time to wait until the flush has to happen
     449             :   // - 0 when it is time to do the flush
     450             :   PRIntervalTime TimeUntilFlush();
     451             : 
     452             :   // Notifies to the main thread that flush has completed
     453             :   void NotifyFlushCompletion();
     454             : 
     455             :   // Thread loop
     456             :   static void ThreadFunc(void* aArg);
     457             :   void ThreadFunc();
     458             : };
     459             : 
     460             : } // namespace dom
     461             : } // namespace mozilla
     462             : 
     463             : #endif // mozilla_dom_StorageDBThread_h

Generated by: LCOV version 1.13