Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp (278915 => 278916)
--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp 2021-06-16 00:46:26 UTC (rev 278915)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp 2021-06-16 00:56:03 UTC (rev 278916)
@@ -51,6 +51,7 @@
#include <wtf/DateMath.h>
#include <wtf/MathExtras.h>
#include <wtf/RobinHoodHashMap.h>
+#include <wtf/Scope.h>
#include <wtf/StdSet.h>
#include <wtf/text/StringBuilder.h>
@@ -627,10 +628,14 @@
{
ASSERT(existingColumns.size() <= expectedColumns.size());
+ SQLiteTransaction transaction(m_database);
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) {
RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable Unable to prepare statement to add missing columns to table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
@@ -644,6 +649,7 @@
}
statement->reset();
}
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::addMissingColumnsIfNecessary()
@@ -700,6 +706,8 @@
if (!missingTables)
return;
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
for (auto& table : *missingTables) {
auto createTableQuery = expectedTableAndIndexQueries().get(table).first;
if (!m_database.executeCommandSlow(createTableQuery))
@@ -711,6 +719,7 @@
ASSERT_NOT_REACHED();
return;
}
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::openAndUpdateSchemaIfNecessary()
@@ -1027,8 +1036,10 @@
return scopedStatement->columnInt(0);
}
-String ResourceLoadStatisticsDatabaseStore::ensureAndMakeDomainList(const HashSet<RegistrableDomain>& domainList)
+String ResourceLoadStatisticsDatabaseStore::ensureAndMakeDomainList(const SQLiteTransaction&, 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
@@ -1038,9 +1049,9 @@
return builder.toString();
}
-void ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList(const String& statement, const HashSet<RegistrableDomain>& domainList, unsigned domainID)
+void ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList(const SQLiteTransaction& transaction, const String& statement, const HashSet<RegistrableDomain>& domainList, unsigned domainID)
{
- auto insertRelationshipStatement = m_database.prepareStatementSlow(makeString(statement, ensureAndMakeDomainList(domainList), " );"));
+ auto insertRelationshipStatement = m_database.prepareStatementSlow(makeString(statement, ensureAndMakeDomainList(transaction, domainList), " );"));
if (!insertRelationshipStatement
|| insertRelationshipStatement->bindInt(1, domainID) != SQLITE_OK) {
@@ -1063,24 +1074,26 @@
}
}
-void ResourceLoadStatisticsDatabaseStore::insertDomainRelationships(const ResourceLoadStatistics& loadStatistics)
+void ResourceLoadStatisticsDatabaseStore::insertDomainRelationships(const SQLiteTransaction& transaction, const ResourceLoadStatistics& loadStatistics)
{
ASSERT(!RunLoop::isMain());
+ ASSERT(m_database.transactionInProgress());
+
auto registrableDomainID = domainID(loadStatistics.registrableDomain);
if (!registrableDomainID)
return;
- 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());
+ 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());
}
void ResourceLoadStatisticsDatabaseStore::populateFromMemoryStore(const ResourceLoadStatisticsMemoryStore& memoryStore)
@@ -1090,6 +1103,9 @@
if (!isEmpty())
return;
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto& statisticsMap = memoryStore.data();
for (const auto& statistic : statisticsMap.values()) {
auto result = insertObservedDomain(statistic);
@@ -1103,12 +1119,15 @@
// Make a separate pass for inter-domain relationships so we
// can refer to the ObservedDomain table entries
for (auto& statistic : statisticsMap.values())
- insertDomainRelationships(statistic);
+ insertDomainRelationships(transaction, statistic);
+
+ transaction.commit();
}
-void ResourceLoadStatisticsDatabaseStore::merge(WebCore::SQLiteStatement* current, const ResourceLoadStatistics& other)
+void ResourceLoadStatisticsDatabaseStore::merge(const SQLiteTransaction& transaction, WebCore::SQLiteStatement* current, const ResourceLoadStatistics& other)
{
ASSERT(!RunLoop::isMain());
+ ASSERT(m_database.transactionInProgress());
auto currentRegistrableDomain = current->columnText(RegistrableDomainIndex);
auto currentLastSeen = current->columnDouble(LastSeenIndex);
@@ -1132,18 +1151,18 @@
setUserInteraction(other.registrableDomain, true, std::max(WallTime::fromRawSeconds(currentMostRecentUserInteraction), other.mostRecentUserInteractionTime));
if (other.grandfathered && !currentGrandfathered)
- setGrandfathered(other.registrableDomain, true);
+ setGrandfathered(transaction, other.registrableDomain, true);
if (other.isPrevalentResource && !currentIsPrevalent)
- setPrevalentResource(other.registrableDomain);
+ setPrevalentResource(transaction, other.registrableDomain);
if (other.isVeryPrevalentResource && !currentIsVeryPrevalent)
- setVeryPrevalentResource(other.registrableDomain);
+ setVeryPrevalentResource(transaction, other.registrableDomain);
if (other.dataRecordsRemoved > currentDataRecordsRemoved)
updateDataRecordsRemoved(other.registrableDomain, other.dataRecordsRemoved);
if (other.gotLinkDecorationFromPrevalentResource && !currentIsScheduledForAllButCookieDataRemoval)
- setIsScheduledForAllButCookieDataRemoval(other.registrableDomain, true);
+ setIsScheduledForAllButCookieDataRemoval(transaction, other.registrableDomain, true);
}
-void ResourceLoadStatisticsDatabaseStore::mergeStatistic(const ResourceLoadStatistics& statistic)
+void ResourceLoadStatisticsDatabaseStore::mergeStatistic(const SQLiteTransaction& transaction, const ResourceLoadStatistics& statistic)
{
ASSERT(!RunLoop::isMain());
@@ -1156,13 +1175,18 @@
return;
}
- merge(scopedStatement.get(), statistic);
+ merge(transaction, scopedStatement.get(), statistic);
}
void ResourceLoadStatisticsDatabaseStore::mergeStatistics(Vector<ResourceLoadStatistics>&& statistics)
{
ASSERT(!RunLoop::isMain());
+ if (statistics.isEmpty())
+ return;
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
for (auto& statistic : statistics) {
if (!domainID(statistic.registrableDomain)) {
auto result = insertObservedDomain(statistic);
@@ -1172,13 +1196,15 @@
return;
}
} else
- mergeStatistic(statistic);
+ mergeStatistic(transaction, statistic);
}
// Make a separate pass for inter-domain relationships so we
// can refer to the ObservedDomain table entries.
for (auto& statistic : statistics)
- insertDomainRelationships(statistic);
+ insertDomainRelationships(transaction, statistic);
+
+ transaction.commit();
}
static ASCIILiteral joinSubStatisticsForSorting()
@@ -1419,15 +1445,22 @@
ASSERT(!RunLoop::isMain());
auto notVeryPrevalentResources = findNotVeryPrevalentResources();
+ if (notVeryPrevalentResources.isEmpty())
+ return;
+ SQLiteTransaction transaction(m_database);
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)
- setPrevalentResource(resourceStatistic.registrableDomain, newPrevalence);
+ if (newPrevalence != resourceStatistic.prevalence) {
+ if (!transaction.inProgress())
+ transaction.begin();
+ setPrevalentResource(transaction, resourceStatistic.registrableDomain, newPrevalence);
+ }
}
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::classifyPrevalentResources()
@@ -1534,6 +1567,9 @@
}
}
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto incrementStorageAccess = m_database.prepareStatement("UPDATE ObservedDomains SET timesAccessedAsFirstPartyDueToStorageAccessAPI = timesAccessedAsFirstPartyDueToStorageAccessAPI + 1 WHERE domainID = ?"_s);
if (!incrementStorageAccess
|| incrementStorageAccess->bindInt(1, *subFrameStatus.second) != SQLITE_OK
@@ -1543,9 +1579,11 @@
return;
}
- grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, userWasPromptedEarlier, scope, [completionHandler = WTFMove(completionHandler)] (StorageAccessWasGranted wasGranted) mutable {
+ grantStorageAccessInternal(transaction, 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)
@@ -1561,7 +1599,10 @@
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));
}
- grantStorageAccessInternal(WTFMove(domainInNeedOfStorageAccess), WTFMove(openerDomain), std::nullopt, openerPageID, StorageAccessPromptWasShown::No, StorageAccessScope::PerPage, [](StorageAccessWasGranted) { });
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+ grantStorageAccessInternal(transaction, WTFMove(domainInNeedOfStorageAccess), WTFMove(openerDomain), std::nullopt, openerPageID, StorageAccessPromptWasShown::No, StorageAccessScope::PerPage, [](StorageAccessWasGranted) { });
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::grantStorageAccess(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, FrameIdentifier frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShown, StorageAccessScope scope, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
@@ -1568,6 +1609,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
if (promptWasShown == StorageAccessPromptWasShown::Yes) {
auto subFrameStatus = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
if (!subFrameStatus.second) {
@@ -1579,15 +1623,18 @@
if (!NetworkStorageSession::canRequestStorageAccessForLoginOrCompatibilityPurposesWithoutPriorUserInteraction(subFrameDomain, topFrameDomain))
ASSERT(hasHadUserInteraction(subFrameDomain, OperatingDatesWindow::Long));
#endif
- insertDomainRelationshipList(storageAccessUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *subFrameStatus.second);
+ insertDomainRelationshipList(transaction, storageAccessUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *subFrameStatus.second);
}
- grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, promptWasShown, scope, WTFMove(completionHandler));
+ grantStorageAccessInternal(transaction, WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, promptWasShown, scope, WTFMove(completionHandler));
+
+ transaction.commit();
}
-void ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, std::optional<FrameIdentifier> frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShownNowOrEarlier, StorageAccessScope scope, CompletionHandler<void(StorageAccessWasGranted)>&& 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)
{
ASSERT(!RunLoop::isMain());
+ ASSERT(m_database.transactionInProgress());
if (subFrameDomain == topFrameDomain) {
completionHandler(StorageAccessWasGranted::Yes);
@@ -1624,7 +1671,11 @@
void ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains(const HashSet<RegistrableDomain>& domains)
{
ASSERT(!RunLoop::isMain());
+ if (domains.isEmpty())
+ return;
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
for (auto& registrableDomain : domains) {
auto result = ensureResourceStatisticsForRegistrableDomain(registrableDomain);
if (!result.second)
@@ -1636,6 +1687,7 @@
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
ASSERT_NOT_REACHED();
}
+ transaction.commit();
}
Vector<RegistrableDomain> ResourceLoadStatisticsDatabaseStore::ensurePrevalentResourcesForDebugMode()
@@ -1648,6 +1700,9 @@
Vector<RegistrableDomain> primaryDomainsToBlock;
primaryDomainsToBlock.reserveInitialCapacity(2);
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(debugStaticPrevalentResource());
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::ensurePrevalentResourcesForDebugMode was not completed due to failed insert attempt for debugStaticPrevalentResource", this);
@@ -1654,7 +1709,7 @@
return { };
}
- setPrevalentResource(debugStaticPrevalentResource(), ResourceLoadPrevalence::High);
+ setPrevalentResource(transaction, debugStaticPrevalentResource(), ResourceLoadPrevalence::High);
primaryDomainsToBlock.uncheckedAppend(debugStaticPrevalentResource());
if (!debugManualPrevalentResource().isEmpty()) {
@@ -1663,7 +1718,7 @@
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::ensurePrevalentResourcesForDebugMode was not completed due to failed insert attempt for debugManualPrevalentResource", this);
return { };
}
- setPrevalentResource(debugManualPrevalentResource(), ResourceLoadPrevalence::High);
+ setPrevalentResource(transaction, debugManualPrevalentResource(), ResourceLoadPrevalence::High);
primaryDomainsToBlock.uncheckedAppend(debugManualPrevalentResource());
if (debugLoggingEnabled()) {
@@ -1672,6 +1727,8 @@
}
}
+ transaction.commit();
+
return primaryDomainsToBlock;
}
@@ -1682,8 +1739,13 @@
bool areTargetAndTopFrameDomainsSameSite = targetDomain == topFrameDomain;
bool areTargetAndSourceDomainsSameSite = targetDomain == sourceDomain;
+ SQLiteTransaction transaction(m_database);
+
bool statisticsWereUpdated = false;
if (!isMainFrame && !(areTargetAndTopFrameDomainsSameSite || areTargetAndSourceDomainsSameSite)) {
+ if (!transaction.inProgress())
+ transaction.begin();
+
auto targetResult = ensureResourceStatisticsForRegistrableDomain(targetDomain);
if (!targetResult.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logFrameNavigation was not completed due to failed insert attempt of target domain", this);
@@ -1690,7 +1752,7 @@
return;
}
updateLastSeen(targetDomain, ResourceLoadStatistics::reduceTimeResolution(WallTime::now()));
- insertDomainRelationshipList(subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *targetResult.second);
+ insertDomainRelationshipList(transaction, subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *targetResult.second);
statisticsWereUpdated = true;
}
@@ -1698,6 +1760,9 @@
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) {
@@ -1704,9 +1769,9 @@
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logFrameNavigation was not completed due to failed insert attempt of target or redirecting domain (isMainFrame)", this);
return;
}
- insertDomainRelationshipList(topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
+ insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
if (isRedirect) {
- insertDomainRelationshipList(topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
+ insertDomainRelationshipList(transaction, 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());
@@ -1713,10 +1778,13 @@
debugBroadcastConsoleMessage(MessageSource::ITPDebug, MessageLevel::Info, makeString("Did set '", sourceDomain.string(), "' as making a top frame redirect to '", targetDomain.string(), "'."));
}
}
- insertDomainRelationshipList(topFrameUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ sourceDomain }), *targetResult.second);
+ insertDomainRelationshipList(transaction, 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) {
@@ -1723,11 +1791,12 @@
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logFrameNavigation was not completed due to failed insert attempt of target or redirecting domain (isRedirect)", this);
return;
}
- insertDomainRelationshipList(subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
- insertDomainRelationshipList(subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ sourceDomain }), *targetResult.second);
+ insertDomainRelationshipList(transaction, subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ targetDomain }), *redirectingDomainResult.second);
+ insertDomainRelationshipList(transaction, subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ sourceDomain }), *targetResult.second);
statisticsWereUpdated = true;
}
}
+ transaction.commit();
if (statisticsWereUpdated)
scheduleStatisticsProcessingRequestIfNecessary();
@@ -1738,15 +1807,20 @@
ASSERT(!RunLoop::isMain());
ASSERT(fromDomain != toDomain);
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto toDomainResult = ensureResourceStatisticsForRegistrableDomain(toDomain);
if (!toDomainResult.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logCrossSiteLoadWithLinkDecoration was not completed due to failed insert attempt", this);
return;
}
- insertDomainRelationshipList(topFrameLinkDecorationsFromQuery, HashSet<RegistrableDomain>({ fromDomain }), *toDomainResult.second);
+ insertDomainRelationshipList(transaction, topFrameLinkDecorationsFromQuery, HashSet<RegistrableDomain>({ fromDomain }), *toDomainResult.second);
if (isPrevalentResource(fromDomain))
- setIsScheduledForAllButCookieDataRemoval(toDomain, true);
+ setIsScheduledForAllButCookieDataRemoval(transaction, toDomain, true);
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement(const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
@@ -1753,6 +1827,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto targetResult = ensureResourceStatisticsForRegistrableDomain(domain);
if (!targetResult.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement was not completed due to failed insert attempt", this);
@@ -1767,6 +1844,8 @@
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement failed to bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
ASSERT_NOT_REACHED();
}
+
+ transaction.commit();
completionHandler();
}
@@ -1791,6 +1870,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(domain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::logUserInteraction was not completed due to failed insert attempt", this);
@@ -1798,6 +1880,9 @@
}
bool didHavePreviousUserInteraction = hasHadUserInteraction(domain, OperatingDatesWindow::Long);
setUserInteraction(domain, true, WallTime::now());
+
+ transaction.commit();
+
if (didHavePreviousUserInteraction) {
completionHandler();
return;
@@ -1809,6 +1894,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto targetResult = ensureResourceStatisticsForRegistrableDomain(domain);
if (!targetResult.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearUserInteraction was not completed due to failed insert attempt", this);
@@ -1824,6 +1912,8 @@
ASSERT_NOT_REACHED();
}
+ transaction.commit();
+
// Update cookie blocking unconditionally since a call to hasHadUserInteraction()
// to check the previous user interaction status could call clearUserInteraction(),
// blowing the call stack.
@@ -1858,9 +1948,11 @@
return hadUserInteraction;
}
-void ResourceLoadStatisticsDatabaseStore::setPrevalentResource(const RegistrableDomain& domain, ResourceLoadPrevalence newPrevalence)
+void ResourceLoadStatisticsDatabaseStore::setPrevalentResource(const SQLiteTransaction&, const RegistrableDomain& domain, ResourceLoadPrevalence newPrevalence)
{
ASSERT(!RunLoop::isMain());
+ ASSERT(m_database.transactionInProgress());
+
if (shouldSkip(domain))
return;
@@ -2006,6 +2098,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(domain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearPrevalentResource was not completed due to failed insert attempt", this);
@@ -2021,11 +2116,24 @@
ASSERT_NOT_REACHED();
return;
}
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::setGrandfathered(const RegistrableDomain& domain, bool value)
{
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
+ setGrandfathered(transaction, domain, value);
+
+ 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) {
@@ -2043,9 +2151,10 @@
}
}
-void ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval(const RegistrableDomain& domain, bool value)
+void ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval(const SQLiteTransaction&, const RegistrableDomain& domain, bool value)
{
ASSERT(!RunLoop::isMain());
+ ASSERT(m_database.transactionInProgress());
auto result = ensureResourceStatisticsForRegistrableDomain(domain);
if (!result.second) {
@@ -2105,6 +2214,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setSubframeUnderTopFrameDomain was not completed due to failed insert attempt", this);
@@ -2111,7 +2223,9 @@
return;
}
// For consistency, make sure we also have a statistics entry for the top frame domain.
- insertDomainRelationshipList(subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
+ insertDomainRelationshipList(transaction, subframeUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::setSubresourceUnderTopFrameDomain(const SubResourceDomain& subresourceDomain, const TopFrameDomain& topFrameDomain)
@@ -2118,6 +2232,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(subresourceDomain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setSubresourceUnderTopFrameDomain was not completed due to failed insert attempt", this);
@@ -2124,7 +2241,9 @@
return;
}
// For consistency, make sure we also have a statistics entry for the top frame domain.
- insertDomainRelationshipList(subresourceUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
+ insertDomainRelationshipList(transaction, subresourceUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *result.second);
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectTo(const SubResourceDomain& subresourceDomain, const RedirectDomain& redirectDomain)
@@ -2131,6 +2250,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(subresourceDomain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectTo was not completed due to failed insert attempt", this);
@@ -2137,7 +2259,9 @@
return;
}
// For consistency, make sure we also have a statistics entry for the redirect domain.
- insertDomainRelationshipList(subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+ insertDomainRelationshipList(transaction, subresourceUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectFrom(const SubResourceDomain& subresourceDomain, const RedirectDomain& redirectDomain)
@@ -2144,6 +2268,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(subresourceDomain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setSubresourceUniqueRedirectFrom was not completed due to failed insert attempt", this);
@@ -2150,7 +2277,9 @@
return;
}
// For consistency, make sure we also have a statistics entry for the redirect domain.
- insertDomainRelationshipList(subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+ insertDomainRelationshipList(transaction, subresourceUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectTo(const TopFrameDomain& topFrameDomain, const RedirectDomain& redirectDomain)
@@ -2157,6 +2286,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(topFrameDomain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectTo was not completed due to failed insert attempt", this);
@@ -2163,8 +2295,10 @@
return;
}
- insertDomainRelationshipList(topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
- insertDomainRelationshipList(topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+ insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+ insertDomainRelationshipList(transaction, topFrameUniqueRedirectsToSinceSameSiteStrictEnforcementQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectFrom(const TopFrameDomain& topFrameDomain, const RedirectDomain& redirectDomain)
@@ -2171,6 +2305,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(topFrameDomain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setTopFrameUniqueRedirectFrom was not completed due to failed insert attempt", this);
@@ -2177,7 +2314,9 @@
return;
}
// For consistency, make sure we also have a statistics entry for the redirect domain.
- insertDomainRelationshipList(topFrameUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+ insertDomainRelationshipList(transaction, topFrameUniqueRedirectsFromQuery, HashSet<RegistrableDomain>({ redirectDomain }), *result.second);
+
+ transaction.commit();
}
std::pair<ResourceLoadStatisticsDatabaseStore::AddedRecord, std::optional<unsigned>> ResourceLoadStatisticsDatabaseStore::ensureResourceStatisticsForRegistrableDomain(const RegistrableDomain& domain)
@@ -2538,6 +2677,8 @@
auto oldestUserInteraction = now;
RegistrableDomainsToDeleteOrRestrictWebsiteDataFor toDeleteOrRestrictFor;
+ SQLiteTransaction transaction(m_database);
+
Vector<DomainData> domains = this->domains();
Vector<unsigned> domainIDsToClearGrandfathering;
for (auto& statistic : domains) {
@@ -2551,7 +2692,9 @@
} else {
if (shouldRemoveAllButCookiesFor(statistic, shouldCheckForGrandfathering)) {
toDeleteOrRestrictFor.domainsToDeleteAllNonCookieWebsiteDataFor.append(statistic.registrableDomain);
- setIsScheduledForAllButCookieDataRemoval(statistic.registrableDomain, false);
+ if (!transaction.inProgress())
+ transaction.begin();
+ setIsScheduledForAllButCookieDataRemoval(transaction, statistic.registrableDomain, false);
}
if (shouldEnforceSameSiteStrictFor(statistic, shouldCheckForGrandfathering)) {
toDeleteOrRestrictFor.domainsToEnforceSameSiteStrictFor.append(statistic.registrableDomain);
@@ -2571,6 +2714,8 @@
toDeleteOrRestrictFor.domainsToDeleteAllNonCookieWebsiteDataFor.clear();
clearGrandfathering(WTFMove(domainIDsToClearGrandfathering));
+
+ transaction.commit();
return toDeleteOrRestrictFor;
}
@@ -2635,6 +2780,9 @@
{
ASSERT(!RunLoop::isMain());
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto result = ensureResourceStatisticsForRegistrableDomain(domain);
if (!result.second) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setLastSeen was not completed due to failed insert attempt", this);
@@ -2642,6 +2790,8 @@
}
updateLastSeen(domain, WallTime::fromRawSeconds(seconds.seconds()));
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::setPrevalentResource(const RegistrableDomain& domain)
@@ -2650,7 +2800,21 @@
if (shouldSkip(domain))
return;
-
+
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+ setPrevalentResource(transaction, domain);
+ transaction.commit();
+}
+
+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) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setPrevalentResource was not completed due to failed insert attempt", this);
@@ -2657,7 +2821,7 @@
return;
}
- setPrevalentResource(domain, ResourceLoadPrevalence::High);
+ setPrevalentResource(transaction, domain, ResourceLoadPrevalence::High);
}
void ResourceLoadStatisticsDatabaseStore::setVeryPrevalentResource(const RegistrableDomain& domain)
@@ -2666,7 +2830,23 @@
if (shouldSkip(domain))
return;
-
+
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
+ 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) {
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setVeryPrevalentResource was not completed due to failed insert attempt", this);
@@ -2673,7 +2853,7 @@
return;
}
- setPrevalentResource(domain, ResourceLoadPrevalence::VeryHigh);
+ setPrevalentResource(transaction, domain, ResourceLoadPrevalence::VeryHigh);
}
void ResourceLoadStatisticsDatabaseStore::updateDataRecordsRemoved(const RegistrableDomain& domain, int value)
@@ -2971,6 +3151,9 @@
return;
}
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
int rowsToPrune = m_operatingDatesSize - operatingDatesWindowLong + 1;
if (rowsToPrune > 0) {
auto deleteLeastRecentOperatingDateStatement = m_database.prepareStatement("DELETE FROM OperatingDates ORDER BY year, month, monthDay LIMIT ?;"_s);
@@ -2993,6 +3176,8 @@
}
updateOperatingDatesParameters();
+
+ transaction.commit();
}
bool ResourceLoadStatisticsDatabaseStore::hasStatisticsExpired(WallTime mostRecentUserInteractionTime, OperatingDatesWindow operatingDatesWindow) const
@@ -3026,6 +3211,10 @@
{
// Populate the Operating Dates table with enough days to require pruning.
double daysAgoInSeconds = 0;
+
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
for (unsigned i = 1; i <= numberOfOperatingDaysPassed; i++) {
double daysToSubtract = Seconds::fromHours(24 * i).value();
daysAgoInSeconds = WallTime::now().secondsSinceEpoch().value() - daysToSubtract;
@@ -3045,6 +3234,8 @@
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);
@@ -3147,6 +3338,10 @@
void ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement(PrivateClickMeasurement&& attribution, PrivateClickMeasurementAttributionType attributionType)
{
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+ auto commitTransaction = makeScopeExit([&transaction] { transaction.commit(); });
+
auto sourceData = ensureResourceStatisticsForRegistrableDomain(attribution.sourceSite().registrableDomain);
auto attributionDestinationData = ensureResourceStatisticsForRegistrableDomain(attribution.destinationSite().registrableDomain);
@@ -3330,6 +3525,9 @@
bindParameter = String::number(*domainIDToMatch);
}
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto clearUnattributedScopedStatement = this->scopedStatement(m_clearUnattributedPrivateClickMeasurementStatement, clearUnattributedPrivateClickMeasurementQuery, "clearPrivateClickMeasurement"_s);
if (!clearUnattributedScopedStatement
@@ -3349,6 +3547,8 @@
RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement clearAttributedScopedStatement, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
ASSERT_NOT_REACHED();
}
+
+ transaction.commit();
}
void ResourceLoadStatisticsDatabaseStore::clearExpiredPrivateClickMeasurement()
@@ -3544,6 +3744,9 @@
{
auto expiredTimeToSend = WallTime::now() - 1_h;
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
auto earliestTimeToSendToSourceStatement = m_database.prepareStatement("UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToSource = ?"_s);
auto earliestTimeToSendToDestinationStatement = m_database.prepareStatement("UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToDestination = null"_s);
@@ -3559,6 +3762,8 @@
ASSERT_NOT_REACHED();
}
+ transaction.commit();
+
return;
}