Title: [280157] trunk/Source/WebKit
Revision
280157
Author
[email protected]
Date
2021-07-21 13:29:14 -0700 (Wed, 21 Jul 2021)

Log Message

REGRESSION (r278916): Hitting ASSERT(!m_db.m_transactionInProgress) in SQLiteTransaction::begin()
https://bugs.webkit.org/show_bug.cgi?id=228151
<rdar://80231894>

Reviewed by Geoffrey Garen.

Because it is hard to keep track of whether or not a transaction has already been started in
ResourceLoadStatisticsDatabaseStore code and because passing a transaction as parameter adds
a lot of function overloads, I decided to switch to another approach. I added a
beginTransactionIfNecessary() member function that begins a transaction if there isn't one
already going on. This way, we can safely ask to begin a transaction within the scope of
a function (if we're about to do several write statements), without having to worry about
whether or not our caller already started a transaction.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::ResourceLoadStatisticsDatabaseStore::ResourceLoadStatisticsDatabaseStore):
(WebKit::ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable):
(WebKit::ResourceLoadStatisticsDatabaseStore::addMissingTablesIfNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::ensureAndMakeDomainList):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationships):
(WebKit::ResourceLoadStatisticsDatabaseStore::populateFromMemoryStore):
(WebKit::ResourceLoadStatisticsDatabaseStore::merge):
(WebKit::ResourceLoadStatisticsDatabaseStore::mergeStatistic):
(WebKit::ResourceLoadStatisticsDatabaseStore::mergeStatistics):
(WebKit::ResourceLoadStatisticsDatabaseStore::reclassifyResources):
(WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccess):
(WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener):
(WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccess):
(WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal):
(WebKit::ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains):
(WebKit::ResourceLoadStatisticsDatabaseStore::ensurePrevalentResourcesForDebugMode):
(WebKit::ResourceLoadStatisticsDatabaseStore::logFrameNavigation):
(WebKit::ResourceLoadStatisticsDatabaseStore::logCrossSiteLoadWithLinkDecoration):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement):
(WebKit::ResourceLoadStatisticsDatabaseStore::logUserInteraction):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearUserInteraction):
(WebKit::ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction):
(WebKit::ResourceLoadStatisticsDatabaseStore::setPrevalentResource):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearPrevalentResource):
(WebKit::ResourceLoadStatisticsDatabaseStore::setGrandfathered):
(WebKit::ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval):
(WebKit::ResourceLoadStatisticsDatabaseStore::setSubframeUnderTopFrameDomain):
(WebKit::ResourceLoadStatisticsDatabaseStore::setSubresourceUnderTopFrameDomain):
(WebKit::ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectTo):
(WebKit::ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectFrom):
(WebKit::ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectTo):
(WebKit::ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectFrom):
(WebKit::ResourceLoadStatisticsDatabaseStore::registrableDomainsToDeleteOrRestrictWebsiteDataFor):
(WebKit::ResourceLoadStatisticsDatabaseStore::setLastSeen):
(WebKit::ResourceLoadStatisticsDatabaseStore::setVeryPrevalentResource):
(WebKit::ResourceLoadStatisticsDatabaseStore::includeTodayAsOperatingDateIfNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertExpiredStatisticForTesting):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement):
(WebKit::ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting):
(WebKit::ResourceLoadStatisticsDatabaseStore::beginTransactionIfNecessary):
* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (280156 => 280157)


--- trunk/Source/WebKit/ChangeLog	2021-07-21 20:27:29 UTC (rev 280156)
+++ trunk/Source/WebKit/ChangeLog	2021-07-21 20:29:14 UTC (rev 280157)
@@ -1,3 +1,65 @@
+2021-07-21  Chris Dumez  <[email protected]>
+
+        REGRESSION (r278916): Hitting ASSERT(!m_db.m_transactionInProgress) in SQLiteTransaction::begin()
+        https://bugs.webkit.org/show_bug.cgi?id=228151
+        <rdar://80231894>
+
+        Reviewed by Geoffrey Garen.
+
+        Because it is hard to keep track of whether or not a transaction has already been started in
+        ResourceLoadStatisticsDatabaseStore code and because passing a transaction as parameter adds
+        a lot of function overloads, I decided to switch to another approach. I added a
+        beginTransactionIfNecessary() member function that begins a transaction if there isn't one
+        already going on. This way, we can safely ask to begin a transaction within the scope of
+        a function (if we're about to do several write statements), without having to worry about
+        whether or not our caller already started a transaction.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
+        (WebKit::ResourceLoadStatisticsDatabaseStore::ResourceLoadStatisticsDatabaseStore):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::addMissingTablesIfNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::ensureAndMakeDomainList):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationships):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::populateFromMemoryStore):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::merge):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::mergeStatistic):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::mergeStatistics):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::reclassifyResources):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccess):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccess):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::ensurePrevalentResourcesForDebugMode):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::logFrameNavigation):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::logCrossSiteLoadWithLinkDecoration):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::logUserInteraction):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearUserInteraction):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setPrevalentResource):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearPrevalentResource):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setGrandfathered):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setSubframeUnderTopFrameDomain):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setSubresourceUnderTopFrameDomain):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectTo):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectFrom):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectTo):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectFrom):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::registrableDomainsToDeleteOrRestrictWebsiteDataFor):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setLastSeen):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setVeryPrevalentResource):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::includeTodayAsOperatingDateIfNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertExpiredStatisticForTesting):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::beginTransactionIfNecessary):
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
+
 2021-07-21  Miguel Gomez  <[email protected]>
 
         [GTK][WPE] Allow the user to configure the MemoryPressureHandler inside the web process

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp (280156 => 280157)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp	2021-07-21 20:27:29 UTC (rev 280156)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp	2021-07-21 20:29:14 UTC (rev 280157)
@@ -44,7 +44,6 @@
 #include <WebCore/ResourceLoadStatistics.h>
 #include <WebCore/SQLiteDatabase.h>
 #include <WebCore/SQLiteStatement.h>
-#include <WebCore/SQLiteTransaction.h>
 #include <WebCore/UserGestureIndicator.h>
 #include <wtf/CallbackAggregator.h>
 #include <wtf/CrossThreadCopier.h>
@@ -350,6 +349,7 @@
 ResourceLoadStatisticsDatabaseStore::ResourceLoadStatisticsDatabaseStore(WebResourceLoadStatisticsStore& store, WorkQueue& workQueue, ShouldIncludeLocalhost shouldIncludeLocalhost, const String& storageDirectoryPath, PAL::SessionID sessionID)
     : ResourceLoadStatisticsStore(store, workQueue, shouldIncludeLocalhost)
     , m_storageDirectoryPath(FileSystem::pathByAppendingComponent(storageDirectoryPath, "observations.db"_s))
+    , m_transaction(m_database)
     , m_sessionID(sessionID)
 {
     ASSERT(!RunLoop::isMain());
@@ -575,8 +575,7 @@
     if (!needsUpdatedSchema())
         return;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     for (auto& table : expectedTableAndIndexQueries().keys()) {
         auto alterTable = m_database.prepareStatementSlow(makeString("ALTER TABLE ", table, " RENAME TO _", table));
@@ -609,8 +608,6 @@
         }
     }
 
-    transaction.commit();
-
     if (!createUniqueIndices()) {
         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary failed to create unique indices, error message: %s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
@@ -641,13 +638,11 @@
 {
     ASSERT(existingColumns.size() <= expectedColumns.size());
 
-    SQLiteTransaction transaction(m_database);
+    auto transaction = beginTransactionIfNecessary();
+
     for (auto& column : expectedColumns) {
         if (existingColumns.contains(column))
             continue;
-        
-        if (!transaction.inProgress())
-            transaction.begin();
 
         auto statement = m_database.prepareStatementSlow(makeString("ALTER TABLE ", tableName, " ADD COLUMN ", column));
         if (!statement) {
@@ -662,7 +657,6 @@
         }
         statement->reset();
     }
-    transaction.commit();
 }
 
 void ResourceLoadStatisticsDatabaseStore::addMissingColumnsIfNecessary()
@@ -719,8 +713,8 @@
     if (!missingTables)
         return;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transaction = beginTransactionIfNecessary();
+
     for (auto& table : *missingTables) {
         auto createTableQuery = expectedTableAndIndexQueries().get(table).first;
         if (!m_database.executeCommandSlow(createTableQuery))
@@ -732,7 +726,6 @@
         ASSERT_NOT_REACHED();
         return;
     }
-    transaction.commit();
 }
 
 void ResourceLoadStatisticsDatabaseStore::openAndUpdateSchemaIfNecessary()
@@ -1049,10 +1042,8 @@
     return scopedStatement->columnInt(0);
 }
 
-String ResourceLoadStatisticsDatabaseStore::ensureAndMakeDomainList(const SQLiteTransaction&, const HashSet<RegistrableDomain>& domainList)
+String ResourceLoadStatisticsDatabaseStore::ensureAndMakeDomainList(const HashSet<RegistrableDomain>& domainList)
 {
-    ASSERT(m_database.transactionInProgress());
-
     StringBuilder builder;
     for (auto& topFrameResource : domainList) {
         // Insert query will fail if top frame domain is not already in the database
@@ -1062,9 +1053,9 @@
     return builder.toString();
 }
 
-void ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList(const SQLiteTransaction& transaction, const String& statement, const HashSet<RegistrableDomain>& domainList, unsigned domainID)
+void ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList(const String& statement, const HashSet<RegistrableDomain>& domainList, unsigned domainID)
 {
-    auto insertRelationshipStatement = m_database.prepareStatementSlow(makeString(statement, ensureAndMakeDomainList(transaction, domainList), " );"));
+    auto insertRelationshipStatement = m_database.prepareStatementSlow(makeString(statement, ensureAndMakeDomainList(domainList), " );"));
     
     if (!insertRelationshipStatement
         || insertRelationshipStatement->bindInt(1, domainID) != SQLITE_OK) {
@@ -1088,26 +1079,27 @@
     }
 }
 
-void ResourceLoadStatisticsDatabaseStore::insertDomainRelationships(const SQLiteTransaction& transaction, const ResourceLoadStatistics& loadStatistics)
+void ResourceLoadStatisticsDatabaseStore::insertDomainRelationships(const ResourceLoadStatistics& loadStatistics)
 {
     ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
 
+    auto transactionScope = beginTransactionIfNecessary();
+
     auto registrableDomainID = domainID(loadStatistics.registrableDomain);
     
     if (!registrableDomainID)
         return;
 
-    insertDomainRelationshipList(transaction, storageAccessUnderTopFrameDomainsQuery, loadStatistics.storageAccessUnderTopFrameDomains, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToQuery, loadStatistics.topFrameUniqueRedirectsTo, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, loadStatistics.topFrameUniqueRedirectsToSinceSameSiteStrictEnforcement, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, topFrameUniqueRedirectsFromQuery, loadStatistics.topFrameUniqueRedirectsFrom, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, subframeUnderTopFrameDomainsQuery, loadStatistics.subframeUnderTopFrameDomains, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, subresourceUnderTopFrameDomainsQuery, loadStatistics.subresourceUnderTopFrameDomains, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, subresourceUniqueRedirectsToQuery, loadStatistics.subresourceUniqueRedirectsTo, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, subresourceUniqueRedirectsFromQuery, loadStatistics.subresourceUniqueRedirectsFrom, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, topFrameLinkDecorationsFromQuery, loadStatistics.topFrameLinkDecorationsFrom, registrableDomainID.value());
-    insertDomainRelationshipList(transaction, topFrameLoadedThirdPartyScriptsQuery, loadStatistics.topFrameLoadedThirdPartyScripts, registrableDomainID.value());
+    insertDomainRelationshipList(storageAccessUnderTopFrameDomainsQuery, loadStatistics.storageAccessUnderTopFrameDomains, registrableDomainID.value());
+    insertDomainRelationshipList(topFrameUniqueRedirectsToQuery, loadStatistics.topFrameUniqueRedirectsTo, registrableDomainID.value());
+    insertDomainRelationshipList(topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, loadStatistics.topFrameUniqueRedirectsToSinceSameSiteStrictEnforcement, registrableDomainID.value());
+    insertDomainRelationshipList(topFrameUniqueRedirectsFromQuery, loadStatistics.topFrameUniqueRedirectsFrom, registrableDomainID.value());
+    insertDomainRelationshipList(subframeUnderTopFrameDomainsQuery, loadStatistics.subframeUnderTopFrameDomains, registrableDomainID.value());
+    insertDomainRelationshipList(subresourceUnderTopFrameDomainsQuery, loadStatistics.subresourceUnderTopFrameDomains, registrableDomainID.value());
+    insertDomainRelationshipList(subresourceUniqueRedirectsToQuery, loadStatistics.subresourceUniqueRedirectsTo, registrableDomainID.value());
+    insertDomainRelationshipList(subresourceUniqueRedirectsFromQuery, loadStatistics.subresourceUniqueRedirectsFrom, registrableDomainID.value());
+    insertDomainRelationshipList(topFrameLinkDecorationsFromQuery, loadStatistics.topFrameLinkDecorationsFrom, registrableDomainID.value());
+    insertDomainRelationshipList(topFrameLoadedThirdPartyScriptsQuery, loadStatistics.topFrameLoadedThirdPartyScripts, registrableDomainID.value());
 }
 
 void ResourceLoadStatisticsDatabaseStore::populateFromMemoryStore(const ResourceLoadStatisticsMemoryStore& memoryStore)
@@ -1117,8 +1109,7 @@
     if (!isEmpty())
         return;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto& statisticsMap = memoryStore.data();
     for (const auto& statistic : statisticsMap.values()) {
@@ -1133,16 +1124,15 @@
     // Make a separate pass for inter-domain relationships so we
     // can refer to the ObservedDomain table entries
     for (auto& statistic : statisticsMap.values())
-        insertDomainRelationships(transaction, statistic);
-
-    transaction.commit();
+        insertDomainRelationships(statistic);
 }
 
-void ResourceLoadStatisticsDatabaseStore::merge(const SQLiteTransaction& transaction, WebCore::SQLiteStatement* current, const ResourceLoadStatistics& other)
+void ResourceLoadStatisticsDatabaseStore::merge(WebCore::SQLiteStatement* current, const ResourceLoadStatistics& other)
 {
     ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
 
+    auto transactionScope = beginTransactionIfNecessary();
+
     auto currentRegistrableDomain = current->columnText(RegistrableDomainIndex);
     auto currentLastSeen = current->columnDouble(LastSeenIndex);
     auto currentMostRecentUserInteraction = current->columnDouble(MostRecentUserInteractionTimeIndex);
@@ -1165,21 +1155,22 @@
         setUserInteraction(other.registrableDomain, true, std::max(WallTime::fromRawSeconds(currentMostRecentUserInteraction), other.mostRecentUserInteractionTime));
 
     if (other.grandfathered && !currentGrandfathered)
-        setGrandfathered(transaction, other.registrableDomain, true);
+        setGrandfathered(other.registrableDomain, true);
     if (other.isPrevalentResource && !currentIsPrevalent)
-        setPrevalentResource(transaction, other.registrableDomain);
+        setPrevalentResource(other.registrableDomain);
     if (other.isVeryPrevalentResource && !currentIsVeryPrevalent)
-        setVeryPrevalentResource(transaction, other.registrableDomain);
+        setVeryPrevalentResource(other.registrableDomain);
     if (other.dataRecordsRemoved > currentDataRecordsRemoved)
         updateDataRecordsRemoved(other.registrableDomain, other.dataRecordsRemoved);
     if (other.gotLinkDecorationFromPrevalentResource && !currentIsScheduledForAllButCookieDataRemoval)
-        setIsScheduledForAllButCookieDataRemoval(transaction, other.registrableDomain, true);
+        setIsScheduledForAllButCookieDataRemoval(other.registrableDomain, true);
 }
 
-void ResourceLoadStatisticsDatabaseStore::mergeStatistic(const SQLiteTransaction& transaction, const ResourceLoadStatistics& statistic)
+void ResourceLoadStatisticsDatabaseStore::mergeStatistic(const ResourceLoadStatistics& statistic)
 {
     ASSERT(!RunLoop::isMain());
 
+    auto transactionScope = beginTransactionIfNecessary();
     auto scopedStatement = this->scopedStatement(m_getResourceDataByDomainNameStatement, getResourceDataByDomainNameQuery, "mergeStatistic"_s);
     if (!scopedStatement
         || scopedStatement->bindText(1, statistic.registrableDomain.string()) != SQLITE_OK
@@ -1189,7 +1180,7 @@
         return;
     }
 
-    merge(transaction, scopedStatement.get(), statistic);
+    merge(scopedStatement.get(), statistic);
 }
 
 void ResourceLoadStatisticsDatabaseStore::mergeStatistics(Vector<ResourceLoadStatistics>&& statistics)
@@ -1198,8 +1189,7 @@
     if (statistics.isEmpty())
         return;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     for (auto& statistic : statistics) {
         if (!domainID(statistic.registrableDomain)) {
@@ -1210,15 +1200,13 @@
                 return;
             }
         } else
-            mergeStatistic(transaction, statistic);
+            mergeStatistic(statistic);
     }
 
     // Make a separate pass for inter-domain relationships so we
     // can refer to the ObservedDomain table entries.
     for (auto& statistic : statistics)
-        insertDomainRelationships(transaction, statistic);
-
-    transaction.commit();
+        insertDomainRelationships(statistic);
 }
 
 static ASCIILiteral joinSubStatisticsForSorting()
@@ -1456,19 +1444,16 @@
     if (notVeryPrevalentResources.isEmpty())
         return;
 
-    SQLiteTransaction transaction(m_database);
+    auto transaction = beginTransactionIfNecessary();
+
     for (auto& resourceStatistic : notVeryPrevalentResources.values()) {
         if (shouldSkip(resourceStatistic.registrableDomain))
             continue;
 
         auto newPrevalence = classifier().calculateResourcePrevalence(resourceStatistic.subresourceUnderTopFrameDomainsCount, resourceStatistic.subresourceUniqueRedirectsToCount, resourceStatistic.subframeUnderTopFrameDomainsCount, resourceStatistic.topFrameUniqueRedirectsToCount, resourceStatistic.prevalence);
-        if (newPrevalence != resourceStatistic.prevalence) {
-            if (!transaction.inProgress())
-                transaction.begin();
-            setPrevalentResource(transaction, resourceStatistic.registrableDomain, newPrevalence);
-        }
+        if (newPrevalence != resourceStatistic.prevalence)
+            setPrevalentResource(resourceStatistic.registrableDomain, newPrevalence);
     }
-    transaction.commit();
 }
 
 void ResourceLoadStatisticsDatabaseStore::classifyPrevalentResources()
@@ -1575,8 +1560,7 @@
         }
     }
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto incrementStorageAccess = m_database.prepareStatement("UPDATE ObservedDomains SET timesAccessedAsFirstPartyDueToStorageAccessAPI = timesAccessedAsFirstPartyDueToStorageAccessAPI + 1 WHERE domainID = ?"_s);
     if (!incrementStorageAccess
@@ -1587,11 +1571,9 @@
         return;
     }
     
-    grantStorageAccessInternal(transaction, WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, userWasPromptedEarlier, scope, [completionHandler = WTFMove(completionHandler)] (StorageAccessWasGranted wasGranted) mutable {
+    grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, userWasPromptedEarlier, scope, [completionHandler = WTFMove(completionHandler)] (StorageAccessWasGranted wasGranted) mutable {
         completionHandler(wasGranted == StorageAccessWasGranted::Yes ? StorageAccessStatus::HasAccess : StorageAccessStatus::CannotRequestAccess);
     });
-
-    transaction.commit();
 }
 
 void ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener(DomainInNeedOfStorageAccess&& domainInNeedOfStorageAccess, PageIdentifier openerPageID, OpenerDomain&& openerDomain)
@@ -1607,10 +1589,7 @@
         debugBroadcastConsoleMessage(MessageSource::ITPDebug, MessageLevel::Info, makeString("[ITP] Storage access was granted for '"_s, domainInNeedOfStorageAccess.string(), "' under opener page from '"_s, openerDomain.string(), "', with user interaction in the opened window."_s));
     }
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
-    grantStorageAccessInternal(transaction, WTFMove(domainInNeedOfStorageAccess), WTFMove(openerDomain), std::nullopt, openerPageID, StorageAccessPromptWasShown::No, StorageAccessScope::PerPage, [](StorageAccessWasGranted) { });
-    transaction.commit();
+    grantStorageAccessInternal(WTFMove(domainInNeedOfStorageAccess), WTFMove(openerDomain), std::nullopt, openerPageID, StorageAccessPromptWasShown::No, StorageAccessScope::PerPage, [](StorageAccessWasGranted) { });
 }
 
 void ResourceLoadStatisticsDatabaseStore::grantStorageAccess(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, FrameIdentifier frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShown, StorageAccessScope scope, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
@@ -1617,8 +1596,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     if (promptWasShown == StorageAccessPromptWasShown::Yes) {
         auto subFrameStatus = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
@@ -1629,20 +1607,17 @@
         ASSERT(subFrameStatus.first == AddedRecord::No);
 #if ASSERT_ENABLED
         if (!NetworkStorageSession::canRequestStorageAccessForLoginOrCompatibilityPurposesWithoutPriorUserInteraction(subFrameDomain, topFrameDomain))
-            ASSERT(hasHadUserInteraction(transaction, subFrameDomain, OperatingDatesWindow::Long));
+            ASSERT(hasHadUserInteraction(subFrameDomain, OperatingDatesWindow::Long));
 #endif
-        insertDomainRelationshipList(transaction, storageAccessUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *subFrameStatus.second);
+        insertDomainRelationshipList(storageAccessUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *subFrameStatus.second);
     }
 
-    grantStorageAccessInternal(transaction, WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, promptWasShown, scope, WTFMove(completionHandler));
-
-    transaction.commit();
+    grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, promptWasShown, scope, WTFMove(completionHandler));
 }
 
-void ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal(const SQLiteTransaction& transaction, SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, std::optional<FrameIdentifier> frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShownNowOrEarlier, StorageAccessScope scope, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
+void ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, std::optional<FrameIdentifier> frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShownNowOrEarlier, StorageAccessScope scope, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
 {
     ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
 
     if (subFrameDomain == topFrameDomain) {
         completionHandler(StorageAccessWasGranted::Yes);
@@ -1650,6 +1625,7 @@
     }
 
     if (promptWasShownNowOrEarlier == StorageAccessPromptWasShown::Yes) {
+        auto transactionScope = beginTransactionIfNecessary();
 #ifndef NDEBUG
         auto subFrameStatus = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
         if (!subFrameStatus.second) {
@@ -1659,7 +1635,7 @@
         ASSERT(subFrameStatus.first == AddedRecord::No);
 #if ASSERT_ENABLED
         if (!NetworkStorageSession::canRequestStorageAccessForLoginOrCompatibilityPurposesWithoutPriorUserInteraction(subFrameDomain, topFrameDomain))
-            ASSERT(hasHadUserInteraction(transaction, subFrameDomain, OperatingDatesWindow::Long));
+            ASSERT(hasHadUserInteraction(subFrameDomain, OperatingDatesWindow::Long));
 #endif
         ASSERT(hasUserGrantedStorageAccessThroughPrompt(*subFrameStatus.second, topFrameDomain) == StorageAccessPromptWasShown::Yes);
 #endif
@@ -1682,8 +1658,8 @@
     if (domains.isEmpty())
         return;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
+
     for (auto& registrableDomain : domains) {
         auto result = ensureResourceStatisticsForRegistrableDomain(registrableDomain);
         if (!result.second)
@@ -1695,7 +1671,6 @@
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
     }
-    transaction.commit();
 }
 
 Vector<RegistrableDomain> ResourceLoadStatisticsDatabaseStore::ensurePrevalentResourcesForDebugMode()
@@ -1708,8 +1683,7 @@
     Vector<RegistrableDomain> primaryDomainsToBlock;
     primaryDomainsToBlock.reserveInitialCapacity(2);
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(debugStaticPrevalentResource());
     if (!result.second) {
@@ -1717,7 +1691,7 @@
         return { };
     }
 
-    setPrevalentResource(transaction, debugStaticPrevalentResource(), ResourceLoadPrevalence::High);
+    setPrevalentResource(debugStaticPrevalentResource(), ResourceLoadPrevalence::High);
     primaryDomainsToBlock.uncheckedAppend(debugStaticPrevalentResource());
 
     if (!debugManualPrevalentResource().isEmpty()) {
@@ -1726,7 +1700,7 @@
             ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::ensurePrevalentResourcesForDebugMode was not completed due to failed insert attempt for debugManualPrevalentResource", this);
             return { };
         }
-        setPrevalentResource(transaction, debugManualPrevalentResource(), ResourceLoadPrevalence::High);
+        setPrevalentResource(debugManualPrevalentResource(), ResourceLoadPrevalence::High);
         primaryDomainsToBlock.uncheckedAppend(debugManualPrevalentResource());
 
         if (debugLoggingEnabled()) {
@@ -1735,8 +1709,6 @@
         }
     }
 
-    transaction.commit();
-
     return primaryDomainsToBlock;
 }
 
@@ -1747,13 +1719,10 @@
     bool areTargetAndTopFrameDomainsSameSite = targetDomain == topFrameDomain;
     bool areTargetAndSourceDomainsSameSite = targetDomain == sourceDomain;
 
-    SQLiteTransaction transaction(m_database);
+    auto transactionScope = beginTransactionIfNecessary();
 
     bool statisticsWereUpdated = false;
     if (!isMainFrame && !(areTargetAndTopFrameDomainsSameSite || areTargetAndSourceDomainsSameSite)) {
-        if (!transaction.inProgress())
-            transaction.begin();
-
         auto targetResult = ensureResourceStatisticsForRegistrableDomain(targetDomain);
         if (!targetResult.second) {
             ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logFrameNavigation was not completed due to failed insert attempt of target domain", this);
@@ -1760,7 +1729,7 @@
             return;
         }
         updateLastSeen(targetDomain, ResourceLoadStatistics::reduceTimeResolution(WallTime::now()));
-        insertDomainRelationshipList(transaction, subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *targetResult.second);
+        insertDomainRelationshipList(subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *targetResult.second);
         statisticsWereUpdated = true;
     }
 
@@ -1768,9 +1737,6 @@
         if (isMainFrame) {
             bool wasNavigatedAfterShortDelayWithoutUserInteraction = !wasPotentiallyInitiatedByUser && delayAfterMainFrameDocumentLoad < parameters().minDelayAfterMainFrameDocumentLoadToNotBeARedirect;
             if (isRedirect || wasNavigatedAfterShortDelayWithoutUserInteraction) {
-                if (!transaction.inProgress())
-                    transaction.begin();
-
                 auto redirectingDomainResult = ensureResourceStatisticsForRegistrableDomain(sourceDomain);
                 auto targetResult = ensureResourceStatisticsForRegistrableDomain(targetDomain);
                 if (!targetResult.second || !redirectingDomainResult.second) {
@@ -1777,9 +1743,9 @@
                     ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logFrameNavigation was not completed due to failed insert attempt of target or redirecting domain (isMainFrame)", this);
                     return;
                 }
-                insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
+                insertDomainRelationshipList(topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
                 if (isRedirect) {
-                    insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
+                    insertDomainRelationshipList(topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
 
                     if (UNLIKELY(debugLoggingEnabled())) {
                         RELEASE_LOG_INFO(ITPDebug, "Did set %" PUBLIC_LOG_STRING " as making a top frame redirect to %" PUBLIC_LOG_STRING ".", sourceDomain.string().utf8().data(), targetDomain.string().utf8().data());
@@ -1786,13 +1752,10 @@
                         debugBroadcastConsoleMessage(MessageSource::ITPDebug, MessageLevel::Info, makeString("Did set '", sourceDomain.string(), "' as making a top frame redirect to '", targetDomain.string(), "'."));
                     }
                 }
-                insertDomainRelationshipList(transaction, topFrameUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ sourceDomain }), *targetResult.second);
+                insertDomainRelationshipList(topFrameUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ sourceDomain }), *targetResult.second);
                 statisticsWereUpdated = true;
             }
         } else if (isRedirect) {
-            if (!transaction.inProgress())
-                transaction.begin();
-
             auto redirectingDomainResult = ensureResourceStatisticsForRegistrableDomain(sourceDomain);
             auto targetResult = ensureResourceStatisticsForRegistrableDomain(targetDomain);
             if (!targetResult.second || !redirectingDomainResult.second) {
@@ -1799,12 +1762,11 @@
                 ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logFrameNavigation was not completed due to failed insert attempt of target or redirecting domain (isRedirect)", this);
                 return;
             }
-            insertDomainRelationshipList(transaction, subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
-            insertDomainRelationshipList(transaction, subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ sourceDomain }), *targetResult.second);
+            insertDomainRelationshipList(subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
+            insertDomainRelationshipList(subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ sourceDomain }), *targetResult.second);
             statisticsWereUpdated = true;
         }
     }
-    transaction.commit();
 
     if (statisticsWereUpdated)
         scheduleStatisticsProcessingRequestIfNecessary();
@@ -1815,8 +1777,7 @@
     ASSERT(!RunLoop::isMain());
     ASSERT(fromDomain != toDomain);
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto toDomainResult = ensureResourceStatisticsForRegistrableDomain(toDomain);
     if (!toDomainResult.second) {
@@ -1823,12 +1784,10 @@
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logCrossSiteLoadWithLinkDecoration was not completed due to failed insert attempt", this);
         return;
     }
-    insertDomainRelationshipList(transaction, topFrameLinkDecorationsFromQuery, HashSet<RegistrableDomain>({ fromDomain }), *toDomainResult.second);
+    insertDomainRelationshipList(topFrameLinkDecorationsFromQuery, HashSet<RegistrableDomain>({ fromDomain }), *toDomainResult.second);
     
     if (isPrevalentResource(fromDomain))
-        setIsScheduledForAllButCookieDataRemoval(transaction, toDomain, true);
-
-    transaction.commit();
+        setIsScheduledForAllButCookieDataRemoval(toDomain, true);
 }
 
 void ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement(const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
@@ -1835,8 +1794,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto targetResult = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!targetResult.second) {
@@ -1852,8 +1810,6 @@
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement failed to bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
     }
-
-    transaction.commit();
     
     completionHandler();
 }
@@ -1878,8 +1834,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!result.second) {
@@ -1886,11 +1841,9 @@
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logUserInteraction was not completed due to failed insert attempt", this);
         return;
     }
-    bool didHavePreviousUserInteraction = hasHadUserInteraction(transaction, domain, OperatingDatesWindow::Long);
+    bool didHavePreviousUserInteraction = hasHadUserInteraction(domain, OperatingDatesWindow::Long);
     setUserInteraction(domain, true, WallTime::now());
 
-    transaction.commit();
-
     if (didHavePreviousUserInteraction) {
         completionHandler();
         return;
@@ -1902,17 +1855,8 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
-    clearUserInteraction(transaction, domain, WTFMove(completionHandler));
-    transaction.commit();
-}
+    auto transactionScope = beginTransactionIfNecessary();
 
-void ResourceLoadStatisticsDatabaseStore::clearUserInteraction(const WebCore::SQLiteTransaction&, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
-
     auto targetResult = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!targetResult.second) {
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearUserInteraction was not completed due to failed insert attempt", this);
@@ -1937,19 +1881,8 @@
 bool ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction(const RegistrableDomain& domain, OperatingDatesWindow operatingDatesWindow)
 {
     ASSERT(!RunLoop::isMain());
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
-    bool result = hasHadUserInteraction(transaction, domain, operatingDatesWindow);
-    transaction.commit();
-    return result;
-}
 
-
-bool ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction(const WebCore::SQLiteTransaction& transaction, const RegistrableDomain& domain, OperatingDatesWindow operatingDatesWindow)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
-
+    auto transactionScope = beginTransactionIfNecessary();
     auto scopedStatement = this->scopedStatement(m_hadUserInteractionStatement, hadUserInteractionQuery, "hasHadUserInteraction"_s);
     if (!scopedStatement
         || scopedStatement->bindText(1, domain.string()) != SQLITE_OK
@@ -1968,20 +1901,21 @@
         // Drop privacy sensitive data because we no longer need it.
         // Set timestamp to 0 so that statistics merge will know
         // it has been reset as opposed to its default -1.
-        clearUserInteraction(transaction, domain, [] { });
+        clearUserInteraction(domain, [] { });
         hadUserInteraction = false;
     }
     return hadUserInteraction;
 }
 
-void ResourceLoadStatisticsDatabaseStore::setPrevalentResource(const SQLiteTransaction&, const RegistrableDomain& domain, ResourceLoadPrevalence newPrevalence)
+void ResourceLoadStatisticsDatabaseStore::setPrevalentResource(const RegistrableDomain& domain, ResourceLoadPrevalence newPrevalence)
 {
     ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
 
     if (shouldSkip(domain))
         return;
 
+    auto transactionScope = beginTransactionIfNecessary();
+
     auto registrableDomainID = domainID(domain);
     if (!registrableDomainID) {
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setPrevalentResource domainID should exist but was not found.", this);
@@ -2124,8 +2058,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!result.second) {
@@ -2142,25 +2075,14 @@
         ASSERT_NOT_REACHED();
         return;
     }
-
-    transaction.commit();
 }
 
 void ResourceLoadStatisticsDatabaseStore::setGrandfathered(const RegistrableDomain& domain, bool value)
 {
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    ASSERT(!RunLoop::isMain());
 
-    setGrandfathered(transaction, domain, value);
+    auto transactionScope = beginTransactionIfNecessary();
 
-    transaction.commit();
-}
-
-void ResourceLoadStatisticsDatabaseStore::setGrandfathered(const WebCore::SQLiteTransaction&, const RegistrableDomain& domain, bool value)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
-
     auto result = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!result.second) {
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setGrandfathered was not completed due to failed insert attempt", this);
@@ -2177,11 +2099,12 @@
     }
 }
 
-void ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval(const SQLiteTransaction&, const RegistrableDomain& domain, bool value)
+void ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval(const RegistrableDomain& domain, bool value)
 {
     ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
 
+    auto transactionScope = beginTransactionIfNecessary();
+
     auto result = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!result.second) {
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval was not completed due to failed insert attempt", this);
@@ -2240,8 +2163,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
     if (!result.second) {
@@ -2249,9 +2171,7 @@
         return;
     }
     // For consistency, make sure we also have a statistics entry for the top frame domain.
-    insertDomainRelationshipList(transaction, subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
-
-    transaction.commit();
+    insertDomainRelationshipList(subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setSubresourceUnderTopFrameDomain(const SubResourceDomain& subresourceDomain, const TopFrameDomain& topFrameDomain)
@@ -2258,8 +2178,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(subresourceDomain);
     if (!result.second) {
@@ -2267,9 +2186,7 @@
         return;
     }
     // For consistency, make sure we also have a statistics entry for the top frame domain.
-    insertDomainRelationshipList(transaction, subresourceUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
-
-    transaction.commit();
+    insertDomainRelationshipList(subresourceUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectTo(const SubResourceDomain& subresourceDomain, const RedirectDomain& redirectDomain)
@@ -2276,8 +2193,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(subresourceDomain);
     if (!result.second) {
@@ -2285,9 +2201,7 @@
         return;
     }
     // For consistency, make sure we also have a statistics entry for the redirect domain.
-    insertDomainRelationshipList(transaction, subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
-
-    transaction.commit();
+    insertDomainRelationshipList(subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectFrom(const SubResourceDomain& subresourceDomain, const RedirectDomain& redirectDomain)
@@ -2294,8 +2208,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(subresourceDomain);
     if (!result.second) {
@@ -2303,9 +2216,7 @@
         return;
     }
     // For consistency, make sure we also have a statistics entry for the redirect domain.
-    insertDomainRelationshipList(transaction, subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
-
-    transaction.commit();
+    insertDomainRelationshipList(subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectTo(const TopFrameDomain& topFrameDomain, const RedirectDomain& redirectDomain)
@@ -2312,8 +2223,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(topFrameDomain);
     if (!result.second) {
@@ -2321,10 +2231,8 @@
         return;
     }
 
-    insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
-    insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
-
-    transaction.commit();
+    insertDomainRelationshipList(topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+    insertDomainRelationshipList(topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectFrom(const TopFrameDomain& topFrameDomain, const RedirectDomain& redirectDomain)
@@ -2331,8 +2239,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(topFrameDomain);
     if (!result.second) {
@@ -2340,9 +2247,7 @@
         return;
     }
     // For consistency, make sure we also have a statistics entry for the redirect domain.
-    insertDomainRelationshipList(transaction, topFrameUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
-
-    transaction.commit();
+    insertDomainRelationshipList(topFrameUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
 }
 
 std::pair<ResourceLoadStatisticsDatabaseStore::AddedRecord, std::optional<unsigned>> ResourceLoadStatisticsDatabaseStore::ensureResourceStatisticsForRegistrableDomain(const RegistrableDomain& domain)
@@ -2703,7 +2608,7 @@
     auto oldestUserInteraction = now;
     RegistrableDomainsToDeleteOrRestrictWebsiteDataFor toDeleteOrRestrictFor;
 
-    SQLiteTransaction transaction(m_database);
+    auto transactionScope = beginTransactionIfNecessary();
 
     Vector<DomainData> domains = this->domains();
     Vector<unsigned> domainIDsToClearGrandfathering;
@@ -2718,9 +2623,7 @@
         } else {
             if (shouldRemoveAllButCookiesFor(statistic, shouldCheckForGrandfathering)) {
                 toDeleteOrRestrictFor.domainsToDeleteAllNonCookieWebsiteDataFor.append(statistic.registrableDomain);
-                if (!transaction.inProgress())
-                    transaction.begin();
-                setIsScheduledForAllButCookieDataRemoval(transaction, statistic.registrableDomain, false);
+                setIsScheduledForAllButCookieDataRemoval(statistic.registrableDomain, false);
             }
             if (shouldEnforceSameSiteStrictFor(statistic, shouldCheckForGrandfathering)) {
                 toDeleteOrRestrictFor.domainsToEnforceSameSiteStrictFor.append(statistic.registrableDomain);
@@ -2740,8 +2643,6 @@
         toDeleteOrRestrictFor.domainsToDeleteAllNonCookieWebsiteDataFor.clear();
 
     clearGrandfathering(WTFMove(domainIDsToClearGrandfathering));
-
-    transaction.commit();
     
     return toDeleteOrRestrictFor;
 }
@@ -2806,8 +2707,7 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto result = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!result.second) {
@@ -2816,8 +2716,6 @@
     }
     
     updateLastSeen(domain, WallTime::fromRawSeconds(seconds.seconds()));
-
-    transaction.commit();
 }
 
 void ResourceLoadStatisticsDatabaseStore::setPrevalentResource(const RegistrableDomain& domain)
@@ -2827,20 +2725,8 @@
     if (shouldSkip(domain))
         return;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
-    setPrevalentResource(transaction, domain);
-    transaction.commit();
-}
+    auto transactionScope = beginTransactionIfNecessary();
 
-void ResourceLoadStatisticsDatabaseStore::setPrevalentResource(const SQLiteTransaction& transaction, const RegistrableDomain& domain)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
-
-    if (shouldSkip(domain))
-        return;
-
     auto result = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!result.second) {
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setPrevalentResource was not completed due to failed insert attempt", this);
@@ -2847,7 +2733,7 @@
         return;
     }
 
-    setPrevalentResource(transaction, domain, ResourceLoadPrevalence::High);
+    setPrevalentResource(domain, ResourceLoadPrevalence::High);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setVeryPrevalentResource(const RegistrableDomain& domain)
@@ -2857,22 +2743,8 @@
     if (shouldSkip(domain))
         return;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
-    setVeryPrevalentResource(transaction, domain);
-
-    transaction.commit();
-}
-
-void ResourceLoadStatisticsDatabaseStore::setVeryPrevalentResource(const SQLiteTransaction& transaction, const RegistrableDomain& domain)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(m_database.transactionInProgress());
-
-    if (shouldSkip(domain))
-        return;
-
     auto result = ensureResourceStatisticsForRegistrableDomain(domain);
     if (!result.second) {
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setVeryPrevalentResource was not completed due to failed insert attempt", this);
@@ -2879,7 +2751,7 @@
         return;
     }
 
-    setPrevalentResource(transaction, domain, ResourceLoadPrevalence::VeryHigh);
+    setPrevalentResource(domain, ResourceLoadPrevalence::VeryHigh);
 }
 
 void ResourceLoadStatisticsDatabaseStore::updateDataRecordsRemoved(const RegistrableDomain& domain, int value)
@@ -3177,8 +3049,7 @@
             return;
     }
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     int rowsToPrune = m_operatingDatesSize - operatingDatesWindowLong + 1;
     if (rowsToPrune > 0) {
@@ -3202,8 +3073,6 @@
     }
 
     updateOperatingDatesParameters();
-
-    transaction.commit();
 }
 
 bool ResourceLoadStatisticsDatabaseStore::hasStatisticsExpired(WallTime mostRecentUserInteractionTime, OperatingDatesWindow operatingDatesWindow) const
@@ -3238,8 +3107,7 @@
     // Populate the Operating Dates table with enough days to require pruning.
     double daysAgoInSeconds = 0;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     for (unsigned i = 1; i <= numberOfOperatingDaysPassed; i++) {
         double daysToSubtract = Seconds::fromHours(24 * i).value();
@@ -3260,8 +3128,6 @@
 
     updateOperatingDatesParameters();
 
-    transaction.commit();
-
     // Make sure mostRecentUserInteractionTime is the least recent of all entries.
     daysAgoInSeconds -= Seconds::fromHours(24).value();
     auto scopedInsertObservedDomainStatement = this->scopedStatement(m_insertObservedDomainStatement, insertObservedDomainQuery, "insertExpiredStatisticForTesting"_s);
@@ -3364,9 +3230,7 @@
 
 void ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement(PrivateClickMeasurement&& attribution, PrivateClickMeasurementAttributionType attributionType)
 {
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
-    auto commitTransaction = makeScopeExit([&transaction] { transaction.commit(); });
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto sourceData = ensureResourceStatisticsForRegistrableDomain(attribution.sourceSite().registrableDomain);
     auto attributionDestinationData = ensureResourceStatisticsForRegistrableDomain(attribution.destinationSite().registrableDomain);
@@ -3552,8 +3416,7 @@
         bindParameter = String::number(*domainIDToMatch);
     }
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto clearUnattributedScopedStatement = this->scopedStatement(m_clearUnattributedPrivateClickMeasurementStatement, clearUnattributedPrivateClickMeasurementQuery, "clearPrivateClickMeasurement"_s);
 
@@ -3574,8 +3437,6 @@
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement clearAttributedScopedStatement, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
     }
-
-    transaction.commit();
 }
 
 void ResourceLoadStatisticsDatabaseStore::clearExpiredPrivateClickMeasurement()
@@ -3771,8 +3632,7 @@
 {
     auto expiredTimeToSend = WallTime::now() - 1_h;
 
-    SQLiteTransaction transaction(m_database);
-    transaction.begin();
+    auto transactionScope = beginTransactionIfNecessary();
 
     auto earliestTimeToSendToSourceStatement = m_database.prepareStatement("UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToSource = ?"_s);
     auto earliestTimeToSendToDestinationStatement = m_database.prepareStatement("UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToDestination = null"_s);
@@ -3788,10 +3648,17 @@
         ITP_RELEASE_LOG_ERROR(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
     }
+}
 
-    transaction.commit();
+ScopeExit<Function<void()>> ResourceLoadStatisticsDatabaseStore::beginTransactionIfNecessary()
+{
+    if (m_transaction.inProgress())
+        return makeScopeExit(Function<void()> { [] { } });
 
-    return;
+    m_transaction.begin();
+    return makeScopeExit(Function<void()> { [this] {
+        m_transaction.commit();
+    } });
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h (280156 => 280157)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h	2021-07-21 20:27:29 UTC (rev 280156)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h	2021-07-21 20:29:14 UTC (rev 280157)
@@ -32,8 +32,10 @@
 #include <WebCore/SQLiteDatabase.h>
 #include <WebCore/SQLiteStatement.h>
 #include <WebCore/SQLiteStatementAutoResetScope.h>
+#include <WebCore/SQLiteTransaction.h>
 #include <pal/SessionID.h>
 #include <wtf/CompletionHandler.h>
+#include <wtf/Scope.h>
 #include <wtf/StdSet.h>
 #include <wtf/Vector.h>
 #include <wtf/WorkQueue.h>
@@ -108,7 +110,7 @@
     void setGrandfathered(const RegistrableDomain&, bool value) override;
     bool isGrandfathered(const RegistrableDomain&) const override;
 
-    void setIsScheduledForAllButCookieDataRemoval(const WebCore::SQLiteTransaction&, const RegistrableDomain&, bool value);
+    void setIsScheduledForAllButCookieDataRemoval(const RegistrableDomain&, bool value);
     void setSubframeUnderTopFrameDomain(const SubFrameDomain&, const TopFrameDomain&) override;
     void setSubresourceUnderTopFrameDomain(const SubResourceDomain&, const TopFrameDomain&) override;
     void setSubresourceUniqueRedirectTo(const SubResourceDomain&, const RedirectDomain&) override;
@@ -177,11 +179,6 @@
     void destroyStatements();
     WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, ASCIILiteral, const String&) const;
 
-    bool hasHadUserInteraction(const WebCore::SQLiteTransaction&, const RegistrableDomain&, OperatingDatesWindow);
-    void clearUserInteraction(const WebCore::SQLiteTransaction&, const RegistrableDomain&, CompletionHandler<void()>&&);
-    void setPrevalentResource(const WebCore::SQLiteTransaction&, const RegistrableDomain&);
-    void setVeryPrevalentResource(const WebCore::SQLiteTransaction&, const RegistrableDomain&);
-    void setGrandfathered(const WebCore::SQLiteTransaction&, const RegistrableDomain&, bool value);
     bool hasStorageAccess(const TopFrameDomain&, const SubFrameDomain&) const;
     Vector<WebResourceLoadStatisticsStore::ThirdPartyDataForSpecificFirstParty> getThirdPartyDataForSpecificFirstPartyDomains(unsigned, const RegistrableDomain&) const;
     void openAndUpdateSchemaIfNecessary();
@@ -188,12 +185,12 @@
     String getDomainStringFromDomainID(unsigned) const;
     ASCIILiteral getSubStatisticStatement(const String&) const;
     void appendSubStatisticList(StringBuilder&, const String& tableName, const String& domain) const;
-    void mergeStatistic(const WebCore::SQLiteTransaction&, const ResourceLoadStatistics&);
-    void merge(const WebCore::SQLiteTransaction&, WebCore::SQLiteStatement*, const ResourceLoadStatistics&);
+    void mergeStatistic(const ResourceLoadStatistics&);
+    void merge(WebCore::SQLiteStatement*, const ResourceLoadStatistics&);
     void clearDatabaseContents();
     bool insertObservedDomain(const ResourceLoadStatistics&) WARN_UNUSED_RETURN;
-    void insertDomainRelationships(const WebCore::SQLiteTransaction&, const ResourceLoadStatistics&);
-    void insertDomainRelationshipList(const WebCore::SQLiteTransaction&, const String&, const HashSet<RegistrableDomain>&, unsigned);
+    void insertDomainRelationships(const ResourceLoadStatistics&);
+    void insertDomainRelationshipList(const String&, const HashSet<RegistrableDomain>&, unsigned);
     bool relationshipExists(WebCore::SQLiteStatementAutoResetScope&, std::optional<unsigned> firstDomainID, const RegistrableDomain& secondDomain) const;
     std::optional<unsigned> domainID(const RegistrableDomain&) const;
     bool domainExists(const RegistrableDomain&) const;
@@ -240,10 +237,10 @@
     bool areAllThirdPartyCookiesBlockedUnder(const TopFrameDomain&) override;
     CookieAccess cookieAccess(const SubResourceDomain&, const TopFrameDomain&);
 
-    void setPrevalentResource(const WebCore::SQLiteTransaction&, const RegistrableDomain&, ResourceLoadPrevalence);
+    void setPrevalentResource(const RegistrableDomain&, ResourceLoadPrevalence);
     unsigned recursivelyFindNonPrevalentDomainsThatRedirectedToThisDomain(unsigned primaryDomainID, StdSet<unsigned>& nonPrevalentRedirectionSources, unsigned numberOfRecursiveCalls);
     void setDomainsAsPrevalent(StdSet<unsigned>&&);
-    void grantStorageAccessInternal(const WebCore::SQLiteTransaction&, SubFrameDomain&&, TopFrameDomain&&, std::optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, WebCore::StorageAccessScope, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&);
+    void grantStorageAccessInternal(SubFrameDomain&&, TopFrameDomain&&, std::optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, WebCore::StorageAccessScope, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&);
     void markAsPrevalentIfHasRedirectedToPrevalent();
     Vector<RegistrableDomain> ensurePrevalentResourcesForDebugMode() override;
     void removeDataRecords(CompletionHandler<void()>&&);
@@ -258,7 +255,7 @@
 
     bool createUniqueIndices();
     bool createSchema();
-    String ensureAndMakeDomainList(const WebCore::SQLiteTransaction&, const HashSet<RegistrableDomain>&);
+    String ensureAndMakeDomainList(const HashSet<RegistrableDomain>&);
     std::optional<WallTime> mostRecentUserInteractionTime(const DomainData&);
     
     void removeUnattributed(WebCore::PrivateClickMeasurement&);
@@ -266,8 +263,11 @@
     String attributionToString(WebCore::SQLiteStatement*, PrivateClickMeasurementAttributionType);
     std::pair<std::optional<UnattributedPrivateClickMeasurement>, std::optional<AttributedPrivateClickMeasurement>> findPrivateClickMeasurement(const WebCore::PrivateClickMeasurement::SourceSite&, const WebCore::PrivateClickMeasurement::AttributionDestinationSite&);
 
+    ScopeExit<Function<void()>> WARN_UNUSED_RETURN beginTransactionIfNecessary();
+
     const String m_storageDirectoryPath;
     mutable WebCore::SQLiteDatabase m_database;
+    mutable WebCore::SQLiteTransaction m_transaction;
     mutable std::unique_ptr<WebCore::SQLiteStatement> m_observedDomainCountStatement;
     std::unique_ptr<WebCore::SQLiteStatement> m_insertObservedDomainStatement;
     std::unique_ptr<WebCore::SQLiteStatement> m_insertTopLevelDomainStatement;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to