summaryrefslogtreecommitdiffstats
path: root/dom/quota/CachingDatabaseConnection.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/CachingDatabaseConnection.h')
-rw-r--r--dom/quota/CachingDatabaseConnection.h238
1 files changed, 238 insertions, 0 deletions
diff --git a/dom/quota/CachingDatabaseConnection.h b/dom/quota/CachingDatabaseConnection.h
new file mode 100644
index 0000000000..ea94035a34
--- /dev/null
+++ b/dom/quota/CachingDatabaseConnection.h
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DOM_QUOTA_CACHINGDATABASECONNECTION_H_
+#define DOM_QUOTA_CACHINGDATABASECONNECTION_H_
+
+#include "mozilla/dom/quota/Config.h"
+
+#include "mozStorageHelper.h"
+#include "nsCOMPtr.h"
+#include "nscore.h"
+#include "nsHashKeys.h"
+#include "nsInterfaceHashtable.h"
+#include "nsString.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/InitializedOnce.h"
+#include "mozilla/NotNull.h"
+#include "mozilla/dom/quota/QuotaCommon.h"
+#include "mozilla/dom/quota/ResultExtensions.h"
+#include "mozilla/dom/quota/ScopedLogExtraInfo.h"
+
+namespace mozilla::dom::quota {
+
+class CachingDatabaseConnection {
+ public:
+ class CachedStatement;
+
+ // A stack-only RAII wrapper that resets its borrowed statement when the
+ // wrapper goes out of scope. Note it's intentionally not declared MOZ_RAII,
+ // because it actually is used as a temporary in simple cases like
+ // `stmt.Borrow()->Execute()`. It also automatically exposes the current query
+ // to ScopedLogExtraInfo as "query" in builds where this mechanism is active.
+ class MOZ_STACK_CLASS BorrowedStatement : mozStorageStatementScoper {
+ public:
+ mozIStorageStatement& operator*() const;
+
+ MOZ_NONNULL_RETURN mozIStorageStatement* operator->() const
+ MOZ_NO_ADDREF_RELEASE_ON_RETURN;
+
+ BorrowedStatement(BorrowedStatement&& aOther) = default;
+
+ // No funny business allowed.
+ BorrowedStatement& operator=(BorrowedStatement&&) = delete;
+ BorrowedStatement(const BorrowedStatement&) = delete;
+ BorrowedStatement& operator=(const BorrowedStatement&) = delete;
+
+ private:
+ friend class CachedStatement;
+
+#ifdef QM_SCOPED_LOG_EXTRA_INFO_ENABLED
+ BorrowedStatement(NotNull<mozIStorageStatement*> aStatement,
+ const nsACString& aQuery)
+ : mozStorageStatementScoper(aStatement),
+ mExtraInfo{ScopedLogExtraInfo::kTagQuery, aQuery} {}
+
+ ScopedLogExtraInfo mExtraInfo;
+#else
+ MOZ_IMPLICIT BorrowedStatement(NotNull<mozIStorageStatement*> aStatement)
+ : mozStorageStatementScoper(aStatement) {}
+#endif
+ };
+
+ class LazyStatement;
+
+ void AssertIsOnConnectionThread() const {
+#ifdef CACHING_DB_CONNECTION_CHECK_THREAD_OWNERSHIP
+ mOwningThread->AssertOwnership("CachingDatabaseConnection not thread-safe");
+#endif
+ }
+
+ bool HasStorageConnection() const {
+ return static_cast<bool>(mStorageConnection);
+ }
+
+ mozIStorageConnection& MutableStorageConnection() const {
+ AssertIsOnConnectionThread();
+ MOZ_ASSERT(mStorageConnection);
+
+ return **mStorageConnection;
+ }
+
+ Result<CachedStatement, nsresult> GetCachedStatement(
+ const nsACString& aQuery);
+
+ Result<BorrowedStatement, nsresult> BorrowCachedStatement(
+ const nsACString& aQuery);
+
+ template <typename BindFunctor>
+ nsresult ExecuteCachedStatement(const nsACString& aQuery,
+ BindFunctor&& aBindFunctor) {
+ QM_TRY_INSPECT(const auto& stmt, BorrowCachedStatement(aQuery));
+ QM_TRY(std::forward<BindFunctor>(aBindFunctor)(*stmt));
+ QM_TRY(MOZ_TO_RESULT(stmt->Execute()));
+
+ return NS_OK;
+ }
+
+ nsresult ExecuteCachedStatement(const nsACString& aQuery);
+
+ template <typename BindFunctor>
+ Result<Maybe<BorrowedStatement>, nsresult>
+ BorrowAndExecuteSingleStepStatement(const nsACString& aQuery,
+ BindFunctor&& aBindFunctor);
+
+#ifdef DEBUG
+ ~CachingDatabaseConnection() {
+ MOZ_ASSERT(!mStorageConnection);
+ MOZ_ASSERT(!mCachedStatements.Count());
+ }
+#endif
+
+ protected:
+ explicit CachingDatabaseConnection(
+ MovingNotNull<nsCOMPtr<mozIStorageConnection>> aStorageConnection);
+
+ CachingDatabaseConnection() = default;
+
+ void LazyInit(
+ MovingNotNull<nsCOMPtr<mozIStorageConnection>> aStorageConnection);
+
+ void Close();
+
+ private:
+#ifdef CACHING_DB_CONNECTION_CHECK_THREAD_OWNERSHIP
+ LazyInitializedOnce<const nsAutoOwningThread> mOwningThread;
+#endif
+
+ LazyInitializedOnceEarlyDestructible<
+ const NotNull<nsCOMPtr<mozIStorageConnection>>>
+ mStorageConnection;
+ nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
+ mCachedStatements;
+};
+
+class CachingDatabaseConnection::CachedStatement final {
+ friend class CachingDatabaseConnection;
+
+ nsCOMPtr<mozIStorageStatement> mStatement;
+
+#ifdef QM_SCOPED_LOG_EXTRA_INFO_ENABLED
+ nsCString mQuery;
+#endif
+
+#ifdef DEBUG
+ CachingDatabaseConnection* mDEBUGConnection;
+#endif
+
+ public:
+#if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
+ CachedStatement();
+ ~CachedStatement();
+#else
+ CachedStatement() = default;
+#endif
+
+ void AssertIsOnConnectionThread() const;
+
+ explicit operator bool() const;
+
+ BorrowedStatement Borrow() const;
+
+ private:
+ // Only called by CachingDatabaseConnection.
+ CachedStatement(CachingDatabaseConnection* aConnection,
+ nsCOMPtr<mozIStorageStatement> aStatement,
+ const nsACString& aQuery);
+
+ public:
+#if defined(NS_BUILD_REFCNT_LOGGING)
+ CachedStatement(CachedStatement&& aOther)
+ : mStatement(std::move(aOther.mStatement))
+# ifdef QM_SCOPED_LOG_EXTRA_INFO_ENABLED
+ ,
+ mQuery(std::move(aOther.mQuery))
+# endif
+# ifdef DEBUG
+ ,
+ mDEBUGConnection(aOther.mDEBUGConnection)
+# endif
+ {
+ MOZ_COUNT_CTOR(CachingDatabaseConnection::CachedStatement);
+ }
+#else
+ CachedStatement(CachedStatement&&) = default;
+#endif
+
+ CachedStatement& operator=(CachedStatement&&) = default;
+
+ // No funny business allowed.
+ CachedStatement(const CachedStatement&) = delete;
+ CachedStatement& operator=(const CachedStatement&) = delete;
+};
+
+class CachingDatabaseConnection::LazyStatement final {
+ public:
+ LazyStatement(CachingDatabaseConnection& aConnection,
+ const nsACString& aQueryString)
+ : mConnection{aConnection}, mQueryString{aQueryString} {}
+
+ Result<CachingDatabaseConnection::BorrowedStatement, nsresult> Borrow();
+
+ template <typename BindFunctor>
+ Result<Maybe<CachingDatabaseConnection::BorrowedStatement>, nsresult>
+ BorrowAndExecuteSingleStep(BindFunctor&& aBindFunctor) {
+ QM_TRY_UNWRAP(auto borrowedStatement, Borrow());
+
+ QM_TRY(std::forward<BindFunctor>(aBindFunctor)(*borrowedStatement));
+
+ QM_TRY_INSPECT(
+ const bool& hasResult,
+ MOZ_TO_RESULT_INVOKE_MEMBER(&*borrowedStatement, ExecuteStep));
+
+ return hasResult ? Some(std::move(borrowedStatement)) : Nothing{};
+ }
+
+ private:
+ Result<Ok, nsresult> Initialize();
+
+ CachingDatabaseConnection& mConnection;
+ const nsCString mQueryString;
+ CachingDatabaseConnection::CachedStatement mCachedStatement;
+};
+
+template <typename BindFunctor>
+Result<Maybe<CachingDatabaseConnection::BorrowedStatement>, nsresult>
+CachingDatabaseConnection::BorrowAndExecuteSingleStepStatement(
+ const nsACString& aQuery, BindFunctor&& aBindFunctor) {
+ return LazyStatement{*this, aQuery}.BorrowAndExecuteSingleStep(
+ std::forward<BindFunctor>(aBindFunctor));
+}
+
+} // namespace mozilla::dom::quota
+
+#endif // DOM_QUOTA_CACHINGDATABASECONNECTION_H_