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_