tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CachingDatabaseConnection.h (7456B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef DOM_QUOTA_CACHINGDATABASECONNECTION_H_
      8 #define DOM_QUOTA_CACHINGDATABASECONNECTION_H_
      9 
     10 #include "mozStorageHelper.h"
     11 #include "mozilla/Assertions.h"
     12 #include "mozilla/Atomics.h"
     13 #include "mozilla/Attributes.h"
     14 #include "mozilla/InitializedOnce.h"
     15 #include "mozilla/NotNull.h"
     16 #include "mozilla/dom/quota/Config.h"
     17 #include "mozilla/dom/quota/QuotaCommon.h"
     18 #include "mozilla/dom/quota/ResultExtensions.h"
     19 #include "mozilla/dom/quota/ScopedLogExtraInfo.h"
     20 #include "nsCOMPtr.h"
     21 #include "nsHashKeys.h"
     22 #include "nsISupportsImpl.h"
     23 #include "nsInterfaceHashtable.h"
     24 #include "nsString.h"
     25 #include "nscore.h"
     26 
     27 namespace mozilla::dom::quota {
     28 
     29 class CachingDatabaseConnection {
     30 public:
     31  class CachedStatement;
     32 
     33  // A stack-only RAII wrapper that resets its borrowed statement when the
     34  // wrapper goes out of scope. Note it's intentionally not declared MOZ_RAII,
     35  // because it actually is used as a temporary in simple cases like
     36  // `stmt.Borrow()->Execute()`. It also automatically exposes the current query
     37  // to ScopedLogExtraInfo as "query" in builds where this mechanism is active.
     38  class MOZ_STACK_CLASS BorrowedStatement : mozStorageStatementScoper {
     39   public:
     40    mozIStorageStatement& operator*() const;
     41 
     42    MOZ_NONNULL_RETURN mozIStorageStatement* operator->() const
     43        MOZ_NO_ADDREF_RELEASE_ON_RETURN;
     44 
     45    BorrowedStatement(BorrowedStatement&& aOther) = default;
     46 
     47    // No funny business allowed.
     48    BorrowedStatement& operator=(BorrowedStatement&&) = delete;
     49    BorrowedStatement(const BorrowedStatement&) = delete;
     50    BorrowedStatement& operator=(const BorrowedStatement&) = delete;
     51 
     52   private:
     53    friend class CachedStatement;
     54 
     55 #ifdef QM_SCOPED_LOG_EXTRA_INFO_ENABLED
     56    BorrowedStatement(NotNull<mozIStorageStatement*> aStatement,
     57                      const nsACString& aQuery)
     58        : mozStorageStatementScoper(aStatement),
     59          mExtraInfo{ScopedLogExtraInfo::kTagQueryTainted, aQuery} {}
     60 
     61    ScopedLogExtraInfo mExtraInfo;
     62 #else
     63    MOZ_IMPLICIT BorrowedStatement(NotNull<mozIStorageStatement*> aStatement)
     64        : mozStorageStatementScoper(aStatement) {}
     65 #endif
     66  };
     67 
     68  class LazyStatement;
     69 
     70  void AssertIsOnConnectionThread() const {
     71 #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
     72    mOwningEventTarget->AssertOwnership(
     73        "CachingDatabaseConnection not thread-safe");
     74 #endif
     75  }
     76 
     77  bool HasStorageConnection() const {
     78    return static_cast<bool>(mStorageConnection);
     79  }
     80 
     81  mozIStorageConnection& MutableStorageConnection() const {
     82    AssertIsOnConnectionThread();
     83    MOZ_ASSERT(mStorageConnection);
     84 
     85    return **mStorageConnection;
     86  }
     87 
     88  bool Closed() const { return mClosed; }
     89 
     90  Result<CachedStatement, nsresult> GetCachedStatement(
     91      const nsACString& aQuery);
     92 
     93  Result<BorrowedStatement, nsresult> BorrowCachedStatement(
     94      const nsACString& aQuery);
     95 
     96  template <typename BindFunctor>
     97  nsresult ExecuteCachedStatement(const nsACString& aQuery,
     98                                  BindFunctor&& aBindFunctor) {
     99    QM_TRY_INSPECT(const auto& stmt, BorrowCachedStatement(aQuery));
    100    QM_TRY(std::forward<BindFunctor>(aBindFunctor)(*stmt));
    101    QM_TRY(MOZ_TO_RESULT(stmt->Execute()));
    102 
    103    return NS_OK;
    104  }
    105 
    106  nsresult ExecuteCachedStatement(const nsACString& aQuery);
    107 
    108  template <typename BindFunctor>
    109  Result<Maybe<BorrowedStatement>, nsresult>
    110  BorrowAndExecuteSingleStepStatement(const nsACString& aQuery,
    111                                      BindFunctor&& aBindFunctor);
    112 
    113 #ifdef DEBUG
    114  ~CachingDatabaseConnection() {
    115    MOZ_ASSERT(!mStorageConnection);
    116    MOZ_ASSERT(!mCachedStatements.Count());
    117  }
    118 #endif
    119 
    120 protected:
    121  explicit CachingDatabaseConnection(
    122      MovingNotNull<nsCOMPtr<mozIStorageConnection>> aStorageConnection);
    123 
    124  CachingDatabaseConnection() = default;
    125 
    126  void LazyInit(
    127      MovingNotNull<nsCOMPtr<mozIStorageConnection>> aStorageConnection);
    128 
    129  void Close();
    130 
    131 private:
    132 #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
    133  LazyInitializedOnce<const nsAutoOwningEventTarget> mOwningEventTarget;
    134 #endif
    135 
    136  LazyInitializedOnceEarlyDestructible<
    137      const NotNull<nsCOMPtr<mozIStorageConnection>>>
    138      mStorageConnection;
    139  nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
    140      mCachedStatements;
    141  Atomic<bool> mClosed;
    142 };
    143 
    144 class CachingDatabaseConnection::CachedStatement final {
    145  friend class CachingDatabaseConnection;
    146 
    147  nsCOMPtr<mozIStorageStatement> mStatement;
    148 
    149 #ifdef QM_SCOPED_LOG_EXTRA_INFO_ENABLED
    150  nsCString mQuery;
    151 #endif
    152 
    153 #ifdef DEBUG
    154  CachingDatabaseConnection* mDEBUGConnection;
    155 #endif
    156 
    157 public:
    158 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
    159  CachedStatement();
    160  ~CachedStatement();
    161 #else
    162  CachedStatement() = default;
    163 #endif
    164 
    165  void AssertIsOnConnectionThread() const;
    166 
    167  explicit operator bool() const;
    168 
    169  BorrowedStatement Borrow() const;
    170 
    171 private:
    172  // Only called by CachingDatabaseConnection.
    173  CachedStatement(CachingDatabaseConnection* aConnection,
    174                  nsCOMPtr<mozIStorageStatement> aStatement,
    175                  const nsACString& aQuery);
    176 
    177 public:
    178 #if defined(NS_BUILD_REFCNT_LOGGING)
    179  CachedStatement(CachedStatement&& aOther)
    180      : mStatement(std::move(aOther.mStatement))
    181 #  ifdef QM_SCOPED_LOG_EXTRA_INFO_ENABLED
    182        ,
    183        mQuery(std::move(aOther.mQuery))
    184 #  endif
    185 #  ifdef DEBUG
    186        ,
    187        mDEBUGConnection(aOther.mDEBUGConnection)
    188 #  endif
    189  {
    190    MOZ_COUNT_CTOR(CachingDatabaseConnection::CachedStatement);
    191  }
    192 #else
    193  CachedStatement(CachedStatement&&) = default;
    194 #endif
    195 
    196  CachedStatement& operator=(CachedStatement&&) = default;
    197 
    198  // No funny business allowed.
    199  CachedStatement(const CachedStatement&) = delete;
    200  CachedStatement& operator=(const CachedStatement&) = delete;
    201 };
    202 
    203 class CachingDatabaseConnection::LazyStatement final {
    204 public:
    205  LazyStatement(CachingDatabaseConnection& aConnection,
    206                const nsACString& aQueryString)
    207      : mConnection{aConnection}, mQueryString{aQueryString} {}
    208 
    209  Result<CachingDatabaseConnection::BorrowedStatement, nsresult> Borrow();
    210 
    211  template <typename BindFunctor>
    212  Result<Maybe<CachingDatabaseConnection::BorrowedStatement>, nsresult>
    213  BorrowAndExecuteSingleStep(BindFunctor&& aBindFunctor) {
    214    QM_TRY_UNWRAP(auto borrowedStatement, Borrow());
    215 
    216    QM_TRY(std::forward<BindFunctor>(aBindFunctor)(*borrowedStatement));
    217 
    218    QM_TRY_INSPECT(
    219        const bool& hasResult,
    220        MOZ_TO_RESULT_INVOKE_MEMBER(&*borrowedStatement, ExecuteStep));
    221 
    222    return hasResult ? Some(std::move(borrowedStatement)) : Nothing{};
    223  }
    224 
    225 private:
    226  Result<Ok, nsresult> Initialize();
    227 
    228  CachingDatabaseConnection& mConnection;
    229  const nsCString mQueryString;
    230  CachingDatabaseConnection::CachedStatement mCachedStatement;
    231 };
    232 
    233 template <typename BindFunctor>
    234 Result<Maybe<CachingDatabaseConnection::BorrowedStatement>, nsresult>
    235 CachingDatabaseConnection::BorrowAndExecuteSingleStepStatement(
    236    const nsACString& aQuery, BindFunctor&& aBindFunctor) {
    237  return LazyStatement{*this, aQuery}.BorrowAndExecuteSingleStep(
    238      std::forward<BindFunctor>(aBindFunctor));
    239 }
    240 
    241 }  // namespace mozilla::dom::quota
    242 
    243 #endif  // DOM_QUOTA_CACHINGDATABASECONNECTION_H_