Unreviewed, rolling out r252805.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 24 Nov 2019 03:03:26 +0000 (03:03 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 24 Nov 2019 03:03:26 +0000 (03:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204553

Caused test failures and ASan crashes (Requested by ap on
#webkit).

Reverted changeset:

"Cross-thread version StorageQuotaManager"
https://bugs.webkit.org/show_bug.cgi?id=203971
https://trac.webkit.org/changeset/252805

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252839 268f45cc-cd09-0410-ab3c-d52691b4dbfc

38 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/Modules/indexeddb/server/IDBServer.cpp
Source/WebCore/Modules/indexeddb/server/IDBServer.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp
Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp
Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/storage/StorageQuotaManager.cpp
Source/WebCore/storage/StorageQuotaManager.h
Source/WebCore/storage/StorageQuotaUser.h [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkProcess.cpp
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/NetworkProcess/NetworkProcess.messages.in
Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp
Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h
Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp
Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp
Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h
Source/WebKit/Shared/WebsiteDataStoreParameters.cpp
Source/WebKit/Shared/WebsiteDataStoreParameters.h
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebCore/StorageQuotaManager.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h

index 5704271..79691c1 100644 (file)
@@ -1,3 +1,17 @@
+2019-11-23  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r252805.
+        https://bugs.webkit.org/show_bug.cgi?id=204553
+
+        Caused test failures and ASan crashes (Requested by ap on
+        #webkit).
+
+        Reverted changeset:
+
+        "Cross-thread version StorageQuotaManager"
+        https://bugs.webkit.org/show_bug.cgi?id=203971
+        https://trac.webkit.org/changeset/252805
+
 2019-11-23  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][IFC] Replace redundant Line::isVisuallyEmpty() with LineBox::isConsideredEmpty()
index 0ec8051..efc275f 100644 (file)
@@ -1381,6 +1381,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     storage/StorageNamespace.h
     storage/StorageNamespaceProvider.h
     storage/StorageQuotaManager.h
+    storage/StorageQuotaUser.h
     storage/StorageType.h
 
     style/StyleChange.h
index bba6623..631c4ce 100644 (file)
 namespace WebCore {
 namespace IDBServer {
 
-Ref<IDBServer> IDBServer::create(PAL::SessionID sessionID, StorageQuotaManagerSpaceRequester&& quotaManagerGetter)
+Ref<IDBServer> IDBServer::create(PAL::SessionID sessionID, QuotaManagerGetter&& quotaManagerGetter)
 {
     return adoptRef(*new IDBServer(sessionID, WTFMove(quotaManagerGetter)));
 }
 
-Ref<IDBServer> IDBServer::create(PAL::SessionID sessionID, const String& databaseDirectoryPath, StorageQuotaManagerSpaceRequester&& quotaManagerGetter)
+Ref<IDBServer> IDBServer::create(PAL::SessionID sessionID, const String& databaseDirectoryPath, QuotaManagerGetter&& quotaManagerGetter)
 {
     return adoptRef(*new IDBServer(sessionID, databaseDirectoryPath, WTFMove(quotaManagerGetter)));
 }
 
-IDBServer::IDBServer(PAL::SessionID sessionID, StorageQuotaManagerSpaceRequester&& spaceRequester)
+IDBServer::IDBServer(PAL::SessionID sessionID, QuotaManagerGetter&& quotaManagerGetter)
     : CrossThreadTaskHandler("IndexedDatabase Server", AutodrainedPoolForRunLoop::Use)
     , m_sessionID(sessionID)
-    , m_spaceRequester(WTFMove(spaceRequester))
+    , m_quotaManagerGetter(WTFMove(quotaManagerGetter))
 {
 }
 
-IDBServer::IDBServer(PAL::SessionID sessionID, const String& databaseDirectoryPath, StorageQuotaManagerSpaceRequester&& spaceRequester)
+IDBServer::IDBServer(PAL::SessionID sessionID, const String& databaseDirectoryPath, QuotaManagerGetter&& quotaManagerGetter)
     : CrossThreadTaskHandler("IndexedDatabase Server", AutodrainedPoolForRunLoop::Use)
     , m_sessionID(sessionID)
     , m_databaseDirectoryPath(databaseDirectoryPath)
-    , m_spaceRequester(WTFMove(spaceRequester))
+    , m_quotaManagerGetter(WTFMove(quotaManagerGetter))
 {
     LOG(IndexedDB, "IDBServer created at path %s", databaseDirectoryPath.utf8().data());
     postDatabaseTask(createCrossThreadTask(*this, &IDBServer::upgradeFilesIfNecessary));
@@ -683,24 +683,157 @@ void IDBServer::performCloseAndDeleteDatabasesForOrigins(const Vector<SecurityOr
 
 void IDBServer::didPerformCloseAndDeleteDatabases(uint64_t callbackID)
 {
+    for (auto& user : m_quotaUsers.values())
+        user->resetSpaceUsed();
+
     auto callback = m_deleteDatabaseCompletionHandlers.take(callbackID);
     ASSERT(callback);
     callback();
 }
 
-StorageQuotaManager::Decision IDBServer::requestSpace(const ClientOrigin& origin, uint64_t taskSize)
+IDBServer::QuotaUser::QuotaUser(IDBServer& server, StorageQuotaManager* manager, ClientOrigin&& origin)
+    : m_server(server)
+    , m_manager(makeWeakPtr(manager))
+    , m_origin(WTFMove(origin))
+    , m_isInitialized(m_server.m_sessionID.isEphemeral())
 {
-    ASSERT(!isMainThread());
-    return m_spaceRequester(origin, taskSize);
+    if (manager)
+        manager->addUser(*this);
+}
+
+IDBServer::QuotaUser::~QuotaUser()
+{
+    if (m_manager)
+        m_manager->removeUser(*this);
+}
+
+void IDBServer::QuotaUser::resetSpaceUsed()
+{
+    m_spaceUsed = 0;
+
+    if (!m_manager)
+        return;
+
+    if (m_server.m_sessionID.isEphemeral())
+        return;
+
+    if (!m_isInitialized)
+        return;
+
+    ASSERT(!m_initializationCallback);
+
+    m_isInitialized = false;
+
+    // Do add/remove to trigger call to whenInitialized.
+    m_manager->removeUser(*this);
+    m_manager->addUser(*this);
+}
+
+void IDBServer::QuotaUser::computeSpaceUsed()
+{
+    resetSpaceUsed();
+}
+
+void IDBServer::QuotaUser::increaseSpaceUsed(uint64_t size)
+{
+    if (!m_isInitialized)
+        return;
+    ASSERT(m_spaceUsed + size > m_spaceUsed);
+    m_spaceUsed += size;
+}
+void IDBServer::QuotaUser::decreaseSpaceUsed(uint64_t size)
+{
+    if (!m_isInitialized)
+        return;
+    ASSERT(m_spaceUsed >= size);
+    m_spaceUsed -= size;
+}
+
+void IDBServer::QuotaUser::whenInitialized(CompletionHandler<void()>&& callback)
+{
+    if (m_isInitialized) {
+        callback();
+        return;
+    }
+    m_initializationCallback = WTFMove(callback);
+    m_server.startComputingSpaceUsedForOrigin(m_origin);
+}
+
+void IDBServer::QuotaUser::initializeSpaceUsed(uint64_t spaceUsed)
+{
+    ASSERT(m_isInitialized || !m_estimatedSpaceIncrease);
+    m_spaceUsed = spaceUsed;
+    m_isInitialized = true;
+
+    if (auto callback = WTFMove(m_initializationCallback))
+        callback();
+}
+
+IDBServer::QuotaUser& IDBServer::ensureQuotaUser(const ClientOrigin& origin)
+{
+    return *m_quotaUsers.ensure(origin, [this, &origin] {
+        return makeUnique<QuotaUser>(*this, m_quotaManagerGetter(m_sessionID, origin), ClientOrigin { origin });
+    }).iterator->value;
 }
 
-uint64_t IDBServer::diskUsage(const String& rootDirectory, const ClientOrigin& origin)
+void IDBServer::startComputingSpaceUsedForOrigin(const ClientOrigin& origin)
+{
+    ASSERT(!m_sessionID.isEphemeral());
+    postDatabaseTask(createCrossThreadTask(*this, &IDBServer::computeSpaceUsedForOrigin, origin));
+}
+
+void IDBServer::computeSpaceUsedForOrigin(const ClientOrigin& origin)
 {
     ASSERT(!isMainThread());
 
-    auto oldVersionOriginDirectory = IDBDatabaseIdentifier::databaseDirectoryRelativeToRoot(origin.topOrigin, origin.clientOrigin, rootDirectory, "v0"_str);
-    auto newVersionOriginDirectory = IDBDatabaseIdentifier::databaseDirectoryRelativeToRoot(origin.topOrigin, origin.clientOrigin, rootDirectory, "v1"_str);
-    return SQLiteIDBBackingStore::databasesSizeForDirectory(oldVersionOriginDirectory) + SQLiteIDBBackingStore::databasesSizeForDirectory(newVersionOriginDirectory);
+    auto databaseDirectoryPath = this->databaseDirectoryPathIsolatedCopy();
+    auto oldVersionOriginDirectory = IDBDatabaseIdentifier::databaseDirectoryRelativeToRoot(origin.topOrigin, origin.clientOrigin, databaseDirectoryPath, "v0");
+    auto newVersionOriginDirectory = IDBDatabaseIdentifier::databaseDirectoryRelativeToRoot(origin.topOrigin, origin.clientOrigin, databaseDirectoryPath, "v1");
+    auto size = SQLiteIDBBackingStore::databasesSizeForDirectory(oldVersionOriginDirectory) + SQLiteIDBBackingStore::databasesSizeForDirectory(newVersionOriginDirectory);
+
+    postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::finishComputingSpaceUsedForOrigin, origin, size));
+}
+
+void IDBServer::finishComputingSpaceUsedForOrigin(const ClientOrigin& origin, uint64_t spaceUsed)
+{
+    ensureQuotaUser(origin).initializeSpaceUsed(spaceUsed);
+}
+
+void IDBServer::requestSpace(const ClientOrigin& origin, uint64_t taskSize, CompletionHandler<void(StorageQuotaManager::Decision)>&& callback)
+{
+    auto* quotaManager = ensureQuotaUser(origin).manager();
+    if (!quotaManager) {
+        callback(StorageQuotaManager::Decision::Deny);
+        return;
+    }
+
+    quotaManager->requestSpace(taskSize, WTFMove(callback));
+}
+
+void IDBServer::resetSpaceUsed(const ClientOrigin& origin)
+{
+    if (auto* user = m_quotaUsers.get(origin))
+        user->resetSpaceUsed();
+}
+
+void IDBServer::increaseSpaceUsed(const ClientOrigin& origin, uint64_t size)
+{
+    ensureQuotaUser(origin).increaseSpaceUsed(size);
+}
+
+void IDBServer::decreaseSpaceUsed(const ClientOrigin& origin, uint64_t size)
+{
+    ensureQuotaUser(origin).decreaseSpaceUsed(size);
+}
+
+void IDBServer::increasePotentialSpaceUsed(const ClientOrigin& origin, uint64_t taskSize)
+{
+    ensureQuotaUser(origin).increasePotentialSpaceUsed(taskSize);
+}
+
+void IDBServer::decreasePotentialSpaceUsed(const ClientOrigin& origin, uint64_t spaceUsed)
+{
+    ensureQuotaUser(origin).decreasePotentialSpaceUsed(spaceUsed);
 }
 
 void IDBServer::upgradeFilesIfNecessary()
index fc1604f..3877a05 100644 (file)
@@ -30,6 +30,7 @@
 #include "IDBConnectionToClient.h"
 #include "IDBDatabaseIdentifier.h"
 #include "StorageQuotaManager.h"
+#include "StorageQuotaUser.h"
 #include "UniqueIDBDatabase.h"
 #include "UniqueIDBDatabaseConnection.h"
 #include <pal/HysteresisActivity.h>
@@ -57,9 +58,9 @@ enum class ShouldForceStop : bool { No, Yes };
 
 class IDBServer : public RefCounted<IDBServer>, public CrossThreadTaskHandler, public CanMakeWeakPtr<IDBServer> {
 public:
-    using StorageQuotaManagerSpaceRequester = Function<StorageQuotaManager::Decision(const ClientOrigin&, uint64_t spaceRequested)>;
-    static Ref<IDBServer> create(PAL::SessionID, StorageQuotaManagerSpaceRequester&&);
-    WEBCORE_EXPORT static Ref<IDBServer> create(PAL::SessionID, const String& databaseDirectoryPath, StorageQuotaManagerSpaceRequester&&);
+    using QuotaManagerGetter = WTF::Function<StorageQuotaManager*(PAL::SessionID, const ClientOrigin&)>;
+    static Ref<IDBServer> create(PAL::SessionID, QuotaManagerGetter&&);
+    WEBCORE_EXPORT static Ref<IDBServer> create(PAL::SessionID, const String& databaseDirectoryPath, QuotaManagerGetter&&);
 
     WEBCORE_EXPORT void registerConnection(IDBConnectionToClient&);
     WEBCORE_EXPORT void unregisterConnection(IDBConnectionToClient&);
@@ -110,8 +111,14 @@ public:
     WEBCORE_EXPORT void closeAndDeleteDatabasesModifiedSince(WallTime, Function<void ()>&& completionHandler);
     WEBCORE_EXPORT void closeAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>&, Function<void ()>&& completionHandler);
 
-    StorageQuotaManager::Decision requestSpace(const ClientOrigin&, uint64_t taskSize);
-    WEBCORE_EXPORT static uint64_t diskUsage(const String& rootDirectory, const ClientOrigin&);
+    void requestSpace(const ClientOrigin&, uint64_t taskSize, CompletionHandler<void(StorageQuotaManager::Decision)>&&);
+    void increasePotentialSpaceUsed(const ClientOrigin&, uint64_t taskSize);
+    void decreasePotentialSpaceUsed(const ClientOrigin&, uint64_t taskSize);
+    void increaseSpaceUsed(const ClientOrigin&, uint64_t size);
+    void decreaseSpaceUsed(const ClientOrigin&, uint64_t size);
+    void resetSpaceUsed(const ClientOrigin&);
+
+    void initializeQuotaUser(const ClientOrigin& origin) { ensureQuotaUser(origin); }
 
     WEBCORE_EXPORT void tryStop(ShouldForceStop);
     WEBCORE_EXPORT void resume();
@@ -120,8 +127,8 @@ public:
     void removeDatabase(UniqueIDBDatabase& database) { m_allUniqueIDBDatabases.remove(database); }
 
 private:
-    IDBServer(PAL::SessionID, StorageQuotaManagerSpaceRequester&&);
-    IDBServer(PAL::SessionID, const String& databaseDirectoryPath, StorageQuotaManagerSpaceRequester&&);
+    IDBServer(PAL::SessionID, QuotaManagerGetter&&);
+    IDBServer(PAL::SessionID, const String& databaseDirectoryPath, QuotaManagerGetter&&);
 
     UniqueIDBDatabase& getOrCreateUniqueIDBDatabase(const IDBDatabaseIdentifier&);
     
@@ -138,6 +145,51 @@ private:
     void removeDatabasesModifiedSinceForVersion(WallTime, const String&);
     void removeDatabasesWithOriginsForVersion(const Vector<SecurityOriginData>&, const String&);
 
+    class QuotaUser final : public StorageQuotaUser {
+        WTF_MAKE_FAST_ALLOCATED;
+    public:
+        QuotaUser(IDBServer&, StorageQuotaManager*, ClientOrigin&&);
+        ~QuotaUser();
+
+        StorageQuotaManager* manager() { return m_manager.get(); }
+
+        void setSpaceUsed(uint64_t spaceUsed) { m_spaceUsed = spaceUsed; }
+        void resetSpaceUsed();
+
+        void increasePotentialSpaceUsed(uint64_t increase) { m_estimatedSpaceIncrease += increase; }
+        void decreasePotentialSpaceUsed(uint64_t decrease)
+        {
+            ASSERT(m_estimatedSpaceIncrease >= decrease);
+            m_estimatedSpaceIncrease -= decrease;
+        }
+        void increaseSpaceUsed(uint64_t size);
+        void decreaseSpaceUsed(uint64_t size);
+
+        void initializeSpaceUsed(uint64_t spaceUsed);
+
+    private:
+        uint64_t spaceUsed() const final
+        {
+            ASSERT(m_isInitialized);
+            return m_spaceUsed + m_estimatedSpaceIncrease;
+        }
+        void computeSpaceUsed() final;
+        void whenInitialized(CompletionHandler<void()>&&) final;
+
+        IDBServer& m_server;
+        WeakPtr<StorageQuotaManager> m_manager;
+        ClientOrigin m_origin;
+        bool m_isInitialized { false };
+        uint64_t m_spaceUsed { 0 };
+        uint64_t m_estimatedSpaceIncrease { 0 };
+        CompletionHandler<void()> m_initializationCallback;
+    };
+
+    WEBCORE_EXPORT QuotaUser& ensureQuotaUser(const ClientOrigin&);
+    void startComputingSpaceUsedForOrigin(const ClientOrigin&);
+    void computeSpaceUsedForOrigin(const ClientOrigin&);
+    void finishComputingSpaceUsedForOrigin(const ClientOrigin&, uint64_t spaceUsed);
+
     PAL::SessionID m_sessionID;
     HashMap<IDBConnectionIdentifier, RefPtr<IDBConnectionToClient>> m_connectionMap;
     HashMap<IDBDatabaseIdentifier, std::unique_ptr<UniqueIDBDatabase>> m_uniqueIDBDatabaseMap;
@@ -150,7 +202,8 @@ private:
 
     String m_databaseDirectoryPath;
 
-    StorageQuotaManagerSpaceRequester m_spaceRequester;
+    HashMap<ClientOrigin, std::unique_ptr<QuotaUser>> m_quotaUsers;
+    QuotaManagerGetter m_quotaManagerGetter;
 };
 
 } // namespace IDBServer
index ff8ad8a..8243422 100644 (file)
@@ -189,6 +189,56 @@ static inline String quotaErrorMessageName(const char* taskName)
     return makeString("Failed to ", taskName, " in database because not enough space for domain");
 }
 
+void UniqueIDBDatabase::requestSpace(UniqueIDBDatabaseTransaction& transaction, uint64_t taskSize, const char* taskName, CompletionHandler<void(IDBError&&)>&& callback)
+{
+    m_server->requestSpace(m_identifier.origin(), taskSize, [weakThis = makeWeakPtr(this), this, weakTransaction = makeWeakPtr(transaction), taskName, callback = WTFMove(callback)](auto decision) mutable {
+        if (!weakThis) {
+            callback(IDBError { UnknownError });
+            return;
+        }
+
+        if (!weakTransaction) {
+            callback(IDBError { UnknownError });
+            return;
+        }
+        if (m_owningPointerForClose) {
+            // We are closing the database, there is no point in trying to modify the database at that point.
+            callback(IDBError { UnknownError });
+            return;
+        }
+
+        switch (decision) {
+        case StorageQuotaManager::Decision::Deny:
+            callback(IDBError { QuotaExceededError, quotaErrorMessageName(taskName) });
+            return;
+        case StorageQuotaManager::Decision::Grant:
+            callback(IDBError { });
+        };
+    });
+}
+
+void UniqueIDBDatabase::waitForRequestSpaceCompletion(UniqueIDBDatabaseTransaction& transaction, CompletionHandler<void(IDBError&&)>&& callback)
+{
+    requestSpace(transaction, 0, "", WTFMove(callback));
+}
+
+void UniqueIDBDatabase::startSpaceIncreaseTask(uint64_t identifier, uint64_t taskSize)
+{
+    m_server->increasePotentialSpaceUsed(m_identifier.origin(), taskSize);
+    ASSERT(!m_pendingSpaceIncreaseTasks.contains(identifier));
+    m_pendingSpaceIncreaseTasks.add(identifier, taskSize);
+}
+
+void UniqueIDBDatabase::finishSpaceIncreaseTask(uint64_t identifier, bool isTaskSuccessful)
+{
+    auto iterator = m_pendingSpaceIncreaseTasks.find(identifier);
+    ASSERT(iterator != m_pendingSpaceIncreaseTasks.end());
+    m_server->decreasePotentialSpaceUsed(m_identifier.origin(), iterator->value);
+    if (isTaskSuccessful)
+        m_server->increaseSpaceUsed(m_identifier.origin(), iterator->value);
+    m_pendingSpaceIncreaseTasks.remove(iterator);
+}
+
 void UniqueIDBDatabase::performCurrentOpenOperation()
 {
     LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentOpenOperation (%p)", this);
@@ -199,7 +249,29 @@ void UniqueIDBDatabase::performCurrentOpenOperation()
     if (!m_databaseInfo) {
         if (!m_isOpeningBackingStore) {
             m_isOpeningBackingStore = true;
-            postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::openBackingStore, m_identifier));
+            // We do not know whether this is an existing or a new database.
+            // We set a small cost so that it is not possible to open an infinite number of database.
+            m_server->requestSpace(m_identifier.origin(), defaultWriteOperationCost, [this, weakThis = makeWeakPtr(this)](auto decision) mutable {
+                if (!weakThis)
+                    return;
+
+                if (m_owningPointerForClose)
+                    return;
+
+                switch (decision) {
+                case StorageQuotaManager::Decision::Deny: {
+                    auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), IDBError { QuotaExceededError, quotaErrorMessageName("openDatabase") });
+                    m_currentOpenDBRequest->connection().didOpenDatabase(result);
+                    m_currentOpenDBRequest = nullptr;
+                    m_isOpeningBackingStore = false;
+                    break;
+                }
+                case StorageQuotaManager::Decision::Grant:
+                    auto callbackID = this->generateUniqueCallbackIdentifier();
+                    startSpaceIncreaseTask(callbackID, defaultWriteOperationCost);
+                    this->postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::openBackingStore, m_identifier, callbackID));
+                };
+            });
         }
         return;
     }
@@ -763,21 +835,14 @@ void UniqueIDBDatabase::addOpenDatabaseConnection(Ref<UniqueIDBDatabaseConnectio
     m_openDatabaseConnections.add(adoptRef(connection.leakRef()));
 }
 
-void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier)
+void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier, uint64_t taskIdentifier)
 {
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::openBackingStore (%p)", this);
 
-    IDBDatabaseInfo databaseInfo;
-    m_origin = identifier.origin();
-    // Quota check.
-    auto decision = m_server->requestSpace(m_origin, defaultWriteOperationCost);
-    if (decision == StorageQuotaManager::Decision::Deny) {
-        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo, IDBError(QuotaExceededError, quotaErrorMessageName("OpenBackingStore"))));
-        return;
-    }
-
     ASSERT(!m_backingStore);
+
+    IDBDatabaseInfo databaseInfo;
     IDBError error;
     {
         LockHolder locker(m_backingStoreLock);
@@ -787,10 +852,10 @@ void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier
         error = m_backingStore->getOrEstablishDatabaseInfo(databaseInfo, locker);
     }
 
-    postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo, error));
+    postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo, error,  taskIdentifier));
 }
 
-void UniqueIDBDatabase::didOpenBackingStore(const IDBDatabaseInfo& info, const IDBError& error)
+void UniqueIDBDatabase::didOpenBackingStore(const IDBDatabaseInfo& info, const IDBError& error, uint64_t taskIdentifier)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didOpenBackingStore");
@@ -801,6 +866,8 @@ void UniqueIDBDatabase::didOpenBackingStore(const IDBDatabaseInfo& info, const I
     ASSERT(m_isOpeningBackingStore);
     m_isOpeningBackingStore = false;
 
+    finishSpaceIncreaseTask(taskIdentifier, error.isNull());
+
     if (m_hardClosedForUserDelete)
         return;
 
@@ -812,22 +879,33 @@ void UniqueIDBDatabase::createObjectStore(UniqueIDBDatabaseTransaction& transact
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::createObjectStore");
 
+    auto taskSize = defaultWriteOperationCost + estimateSize(info);
+    requestSpace(transaction, taskSize, "createObjectStore", [this, taskSize, &transaction, info, callback = WTFMove(callback)](auto error) mutable {
+        if (!error.isNull() && *error.code() != QuotaExceededError) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->createObjectStoreAfterQuotaCheck(taskSize, transaction, info, WTFMove(callback), error);
+    });
+}
+
+void UniqueIDBDatabase::createObjectStoreAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, const IDBObjectStoreInfo& info, ErrorCallback callback, const IDBError& quotaError)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
 
-    postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info));
+    startSpaceIncreaseTask(callbackID, taskSize);
+    postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info,  quotaError));
 }
 
-void UniqueIDBDatabase::performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
+void UniqueIDBDatabase::performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info, const IDBError& quotaError)
 {
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateObjectStore");
 
-    // Quota check.
-    auto taskSize = defaultWriteOperationCost + estimateSize(info);
-    if (m_server->requestSpace(m_origin, taskSize) == StorageQuotaManager::Decision::Deny) {
-        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateObjectStore, callbackIdentifier, IDBError(QuotaExceededError, quotaErrorMessageName("CreateObjectStore")), info));
+    if (!quotaError.isNull()) {
+        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateObjectStore, callbackIdentifier, quotaError, info));
         return;
     }
 
@@ -846,6 +924,7 @@ void UniqueIDBDatabase::didPerformCreateObjectStore(uint64_t callbackIdentifier,
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateObjectStore");
 
+    finishSpaceIncreaseTask(callbackIdentifier, error.isNull());
     if (error.isNull())
         m_databaseInfo->addExistingObjectStore(info);
 
@@ -857,6 +936,17 @@ void UniqueIDBDatabase::deleteObjectStore(UniqueIDBDatabaseTransaction& transact
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteObjectStore");
 
+    waitForRequestSpaceCompletion(transaction, [this, &transaction, objectStoreName, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->deleteObjectStoreAfterQuotaCheck(transaction, objectStoreName, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::deleteObjectStoreAfterQuotaCheck(UniqueIDBDatabaseTransaction& transaction, const String& objectStoreName, ErrorCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -901,15 +991,28 @@ void UniqueIDBDatabase::renameObjectStore(UniqueIDBDatabaseTransaction& transact
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::renameObjectStore");
 
+    auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
+    requestSpace(transaction, taskSize, "renameObjectStore", [this, taskSize, &transaction, objectStoreIdentifier, newName, callback = WTFMove(callback)](auto error) mutable {
+        if (!error.isNull() && *error.code() != QuotaExceededError) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->renameObjectStoreAfterQuotaCheck(taskSize, transaction, objectStoreIdentifier, newName, WTFMove(callback), error);
+    });
+}
+
+void UniqueIDBDatabase::renameObjectStoreAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& newName, ErrorCallback callback, const IDBError& quotaError)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
 
-    IDBError error;
+    IDBError error = quotaError;
     auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
     if (!info)
         error = IDBError { UnknownError, "Attempt to rename non-existant object store"_s };
 
+    startSpaceIncreaseTask(callbackID, taskSize);
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier, newName, error));
 }
 
@@ -918,10 +1021,8 @@ void UniqueIDBDatabase::performRenameObjectStore(uint64_t callbackIdentifier, co
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameObjectStore");
 
-    // Quota check.
-    auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
-    if (m_server->requestSpace(m_origin, taskSize) == StorageQuotaManager::Decision::Deny) {
-        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameObjectStore, callbackIdentifier, IDBError(QuotaExceededError, quotaErrorMessageName("RenameObjectStore")), objectStoreIdentifier, newName));
+    if (!error.isNull()) {
+        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameObjectStore, callbackIdentifier, error, objectStoreIdentifier, newName));
         return;
     }
 
@@ -939,6 +1040,7 @@ void UniqueIDBDatabase::didPerformRenameObjectStore(uint64_t callbackIdentifier,
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameObjectStore");
 
+    finishSpaceIncreaseTask(callbackIdentifier, error.isNull());
     if (error.isNull())
         m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);
 
@@ -950,6 +1052,17 @@ void UniqueIDBDatabase::clearObjectStore(UniqueIDBDatabaseTransaction& transacti
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::clearObjectStore");
 
+    waitForRequestSpaceCompletion(transaction, [this, &transaction, objectStoreIdentifier, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->clearObjectStoreAfetQuotaCheck(transaction, objectStoreIdentifier, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::clearObjectStoreAfetQuotaCheck(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, ErrorCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -984,21 +1097,33 @@ void UniqueIDBDatabase::createIndex(UniqueIDBDatabaseTransaction& transaction, c
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::createIndex");
 
+    auto taskSize = defaultWriteOperationCost + estimateSize(info);
+    requestSpace(transaction, taskSize, "createIndex", [this, taskSize, &transaction, info, callback = WTFMove(callback)](auto error) mutable {
+        if (!error.isNull() && *error.code() != QuotaExceededError) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->createIndexAfterQuotaCheck(taskSize, transaction, info, WTFMove(callback), error);
+    });
+}
+
+void UniqueIDBDatabase::createIndexAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, const IDBIndexInfo& info, ErrorCallback callback, const IDBError& quotaError)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
 
-    postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info));
+    startSpaceIncreaseTask(callbackID, taskSize);
+    postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info, quotaError));
 }
 
-void UniqueIDBDatabase::performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
+void UniqueIDBDatabase::performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info, const IDBError& quotaError)
 {
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateIndex");
 
-    auto taskSize = defaultWriteOperationCost + estimateSize(info);
-    if (m_server->requestSpace(m_origin, taskSize) == StorageQuotaManager::Decision::Deny) {
-        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, IDBError(QuotaExceededError, quotaErrorMessageName("CreateIndex")), info));
+    if (!quotaError.isNull()) {
+        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, quotaError, info));
         return;
     }
 
@@ -1023,6 +1148,8 @@ void UniqueIDBDatabase::didPerformCreateIndex(uint64_t callbackIdentifier, const
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateIndex");
 
+    finishSpaceIncreaseTask(callbackIdentifier, error.isNull());
+
     if (error.isNull()) {
         ASSERT(m_databaseInfo);
         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
@@ -1038,6 +1165,17 @@ void UniqueIDBDatabase::deleteIndex(UniqueIDBDatabaseTransaction& transaction, u
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteIndex");
 
+    waitForRequestSpaceCompletion(transaction, [this, &transaction, objectStoreIdentifier, indexName, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->deleteIndexAfterQuotaCheck(transaction, objectStoreIdentifier, indexName, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::deleteIndexAfterQuotaCheck(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1091,11 +1229,23 @@ void UniqueIDBDatabase::renameIndex(UniqueIDBDatabaseTransaction& transaction, u
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::renameIndex");
 
+    auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
+    requestSpace(transaction, taskSize, "renameIndex", [this, taskSize, &transaction, objectStoreIdentifier, indexIdentifier, newName, callback = WTFMove(callback)](auto error) mutable {
+        if (!error.isNull() && *error.code() != QuotaExceededError) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->renameIndexAfterQuotaCheck(taskSize, transaction, objectStoreIdentifier, indexIdentifier, newName, WTFMove(callback), error);
+    });
+}
+
+void UniqueIDBDatabase::renameIndexAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback callback, const IDBError& quotaError)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
 
-    IDBError error;
+    IDBError error = quotaError;
     auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
     if (!objectStoreInfo)
         error = IDBError { UnknownError, "Attempt to rename index in non-existant object store"_s };
@@ -1104,6 +1254,7 @@ void UniqueIDBDatabase::renameIndex(UniqueIDBDatabaseTransaction& transaction, u
     if (!indexInfo)
         error = IDBError { UnknownError, "Attempt to rename non-existant index"_s };
 
+    startSpaceIncreaseTask(callbackID, taskSize);
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexIdentifier, newName, error));
 }
 
@@ -1112,10 +1263,8 @@ void UniqueIDBDatabase::performRenameIndex(uint64_t callbackIdentifier, const ID
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameIndex");
 
-    // Quota check.
-    auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
-    if (m_server->requestSpace(m_origin, taskSize) == StorageQuotaManager::Decision::Deny) {
-        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameIndex, callbackIdentifier, IDBError(QuotaExceededError, quotaErrorMessageName("RenameIndex")), objectStoreIdentifier, indexIdentifier, newName));
+    if (!error.isNull()) {
+        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier, newName));
         return;
     }
 
@@ -1133,6 +1282,7 @@ void UniqueIDBDatabase::didPerformRenameIndex(uint64_t callbackIdentifier, const
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameIndex");
 
+    finishSpaceIncreaseTask(callbackIdentifier, error.isNull());
     if (error.isNull()) {
         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
         ASSERT(objectStoreInfo);
@@ -1146,39 +1296,52 @@ void UniqueIDBDatabase::didPerformRenameIndex(uint64_t callbackIdentifier, const
     performErrorCallback(callbackIdentifier, error);
 }
 
-void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
+void UniqueIDBDatabase::putOrAdd(UniqueIDBDatabaseTransaction& transaction, const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
 
+    auto taskSize = defaultWriteOperationCost + estimateSize(keyData) + estimateSize(value);
+    ASSERT(m_databaseInfo);
+    auto* objectStore = m_databaseInfo->infoForExistingObjectStore(requestData.objectStoreIdentifier());
+    if (objectStore)
+        taskSize += objectStore->indexNames().size() * taskSize;
+
+    requestSpace(transaction, taskSize, "putOrAdd", [this, taskSize, requestData, keyData, value, callback = WTFMove(callback), overwriteMode](auto error) mutable {
+        if (!error.isNull() && *error.code() != QuotaExceededError) {
+            callback(WTFMove(error), { });
+            return;
+        }
+        this->putOrAddAfterQuotaCheck(taskSize, requestData, keyData, value, overwriteMode, WTFMove(callback), error);
+    });
+}
+
+void UniqueIDBDatabase::putOrAddAfterQuotaCheck(uint64_t taskSize, const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback, const IDBError& quotaError)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
 
-    postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, value, overwriteMode));
+    startSpaceIncreaseTask(callbackID, taskSize);
+    postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, value, overwriteMode, quotaError));
 }
 
-void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const IDBValue& originalRecordValue, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const IDBValue& originalRecordValue, IndexedDB::ObjectStoreOverwriteMode overwriteMode, const IDBError& quotaError)
 {
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
 
+    ASSERT(m_backingStore);
+    ASSERT(objectStoreIdentifier);
+
     IDBKeyData usedKey;
     IDBError error;
 
-    // Quota check.
-    auto taskSize = defaultWriteOperationCost + estimateSize(keyData) + estimateSize(originalRecordValue);
-    ASSERT(m_databaseInfo);
-    auto* objectStore = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
-    if (objectStore)
-        taskSize += objectStore->indexNames().size() * taskSize;
-    if (m_server->requestSpace(m_origin, taskSize) == StorageQuotaManager::Decision::Deny) {
-        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(QuotaExceededError, quotaErrorMessageName("PutOrAdd")), usedKey));
+    if (!quotaError.isNull()) {
+        postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, quotaError, usedKey));
         return;
     }
 
-    ASSERT(m_backingStore);
-    ASSERT(objectStoreIdentifier);
     {
         LockHolder locker(m_backingStoreLock);
         if (!m_backingStore) {
@@ -1255,14 +1418,26 @@ void UniqueIDBDatabase::didPerformPutOrAdd(uint64_t callbackIdentifier, const ID
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformPutOrAdd");
 
+    finishSpaceIncreaseTask(callbackIdentifier, error.isNull());
     performKeyDataCallback(callbackIdentifier, error, resultKey);
 }
 
-void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
+void UniqueIDBDatabase::getRecord(UniqueIDBDatabaseTransaction& transaction, const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
 
+    waitForRequestSpaceCompletion(transaction, [this, requestData, getRecordData, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error), { });
+            return;
+        }
+        this->getRecordAfterQuotaCheck(requestData, getRecordData, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::getRecordAfterQuotaCheck(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1273,11 +1448,22 @@ void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBGe
         postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), getRecordData.keyRangeData, getRecordData.type));
 }
 
-void UniqueIDBDatabase::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
+void UniqueIDBDatabase::getAllRecords(UniqueIDBDatabaseTransaction& transaction, const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::getAllRecords");
 
+    waitForRequestSpaceCompletion(transaction, [this, requestData, getAllRecordsData, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error), { });
+            return;
+        }
+        this->getAllRecordsAfterQuotaCheck(requestData, getAllRecordsData, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::getAllRecordsAfterQuotaCheck(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1291,6 +1477,7 @@ void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBR
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
 
     ASSERT(m_backingStore);
+
     IDBGetResult result;
     IDBError error;
     {
@@ -1331,6 +1518,7 @@ void UniqueIDBDatabase::performGetAllRecords(uint64_t callbackIdentifier, const
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetAllRecords");
 
     ASSERT(m_backingStore);
+
     IDBGetAllResult result;
     IDBError error;
     {
@@ -1349,11 +1537,22 @@ void UniqueIDBDatabase::didPerformGetAllRecords(uint64_t callbackIdentifier, con
     performGetAllResultsCallback(callbackIdentifier, error, result);
 }
 
-void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
+void UniqueIDBDatabase::getCount(UniqueIDBDatabaseTransaction& transaction, const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::getCount");
 
+    waitForRequestSpaceCompletion(transaction, [this, requestData, range, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error), { });
+            return;
+        }
+        this->getCountAfterQuotaCheck(requestData, range, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::getCountAfterQuotaCheck(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1386,11 +1585,22 @@ void UniqueIDBDatabase::didPerformGetCount(uint64_t callbackIdentifier, const ID
     performCountCallback(callbackIdentifier, error, count);
 }
 
-void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
+void UniqueIDBDatabase::deleteRecord(UniqueIDBDatabaseTransaction& transaction, const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteRecord");
 
+    waitForRequestSpaceCompletion(transaction, [this, requestData, keyRangeData, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->deleteRecordAfterQuotaCheck(requestData, keyRangeData, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::deleteRecordAfterQuotaCheck(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1419,11 +1629,22 @@ void UniqueIDBDatabase::didPerformDeleteRecord(uint64_t callbackIdentifier, cons
     performErrorCallback(callbackIdentifier, error);
 }
 
-void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
+void UniqueIDBDatabase::openCursor(UniqueIDBDatabaseTransaction& transaction, const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::openCursor");
 
+    waitForRequestSpaceCompletion(transaction, [this, requestData, info, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error), { });
+            return;
+        }
+        this->openCursorAfterQuotaCheck(requestData, info, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::openCursorAfterQuotaCheck(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1453,11 +1674,22 @@ void UniqueIDBDatabase::didPerformOpenCursor(uint64_t callbackIdentifier, const
     performGetResultCallback(callbackIdentifier, error, result);
 }
 
-void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
+void UniqueIDBDatabase::iterateCursor(UniqueIDBDatabaseTransaction& transaction, const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::iterateCursor");
 
+    waitForRequestSpaceCompletion(transaction, [this, requestData, data, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error), { });
+            return;
+        }
+        this->iterateCursorAfterQuotaCheck(requestData, data, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::iterateCursorAfterQuotaCheck(const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1535,6 +1767,17 @@ void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transact
 
     ASSERT(transaction.databaseConnection().database() == this);
 
+    waitForRequestSpaceCompletion(transaction, [this, &transaction, callback = WTFMove(callback)](auto&& error) mutable {
+        if (!error.isNull()) {
+            callback(WTFMove(error));
+            return;
+        }
+        this->commitTransactionAfterQuotaCheck(transaction, WTFMove(callback));
+    });
+}
+
+void UniqueIDBDatabase::commitTransactionAfterQuotaCheck(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
+{
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
@@ -1592,13 +1835,24 @@ void UniqueIDBDatabase::didPerformCommitTransaction(uint64_t callbackIdentifier,
     transactionCompleted(m_finishingTransactions.take(transactionIdentifier));
 }
 
-void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
+void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, WaitForPendingTasks waitForPendingTasks, ErrorCallback callback)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::abortTransaction - %s", transaction.info().identifier().loggingString().utf8().data());
 
     ASSERT(transaction.databaseConnection().database() == this);
 
+    if (waitForPendingTasks == WaitForPendingTasks::Yes) {
+        waitForRequestSpaceCompletion(transaction, [this, &transaction, callback = WTFMove(callback)](auto&& error) mutable {
+            if (!error.isNull()) {
+                callback(WTFMove(error));
+                return;
+            }
+            this->abortTransaction(transaction, WaitForPendingTasks::No, WTFMove(callback));
+        });
+        return;
+    }
+
     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
     if (!callbackID)
         return;
index ebfc1c5..c358de4 100644 (file)
@@ -44,7 +44,6 @@
 
 namespace WebCore {
 
-struct ClientOrigin;
 class IDBError;
 class IDBGetAllResult;
 struct IDBGetRecordData;
@@ -90,15 +89,17 @@ public:
     void createIndex(UniqueIDBDatabaseTransaction&, const IDBIndexInfo&, ErrorCallback);
     void deleteIndex(UniqueIDBDatabaseTransaction&, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback);
     void renameIndex(UniqueIDBDatabaseTransaction&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback);
-    void putOrAdd(const IDBRequestData&, const IDBKeyData&, const IDBValue&, IndexedDB::ObjectStoreOverwriteMode, KeyDataCallback);
-    void getRecord(const IDBRequestData&, const IDBGetRecordData&, GetResultCallback);
-    void getAllRecords(const IDBRequestData&, const IDBGetAllRecordsData&, GetAllResultsCallback);
-    void getCount(const IDBRequestData&, const IDBKeyRangeData&, CountCallback);
-    void deleteRecord(const IDBRequestData&, const IDBKeyRangeData&, ErrorCallback);
-    void openCursor(const IDBRequestData&, const IDBCursorInfo&, GetResultCallback);
-    void iterateCursor(const IDBRequestData&, const IDBIterateCursorData&, GetResultCallback);
+    void putOrAdd(UniqueIDBDatabaseTransaction&, const IDBRequestData&, const IDBKeyData&, const IDBValue&, IndexedDB::ObjectStoreOverwriteMode, KeyDataCallback);
+    void getRecord(UniqueIDBDatabaseTransaction&, const IDBRequestData&, const IDBGetRecordData&, GetResultCallback);
+    void getAllRecords(UniqueIDBDatabaseTransaction&, const IDBRequestData&, const IDBGetAllRecordsData&, GetAllResultsCallback);
+    void getCount(UniqueIDBDatabaseTransaction&, const IDBRequestData&, const IDBKeyRangeData&, CountCallback);
+    void deleteRecord(UniqueIDBDatabaseTransaction&, const IDBRequestData&, const IDBKeyRangeData&, ErrorCallback);
+    void openCursor(UniqueIDBDatabaseTransaction&, const IDBRequestData&, const IDBCursorInfo&, GetResultCallback);
+    void iterateCursor(UniqueIDBDatabaseTransaction&, const IDBRequestData&, const IDBIterateCursorData&, GetResultCallback);
     void commitTransaction(UniqueIDBDatabaseTransaction&, ErrorCallback);
-    void abortTransaction(UniqueIDBDatabaseTransaction&, ErrorCallback);
+
+    enum class WaitForPendingTasks { No, Yes };
+    void abortTransaction(UniqueIDBDatabaseTransaction&, WaitForPendingTasks, ErrorCallback);
 
     void didFinishHandlingVersionChange(UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& transactionIdentifier);
     void transactionDestroyed(UniqueIDBDatabaseTransaction&);
@@ -139,20 +140,37 @@ private:
 
     void scheduleShutdownForClose();
 
+    void createObjectStoreAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction&, const IDBObjectStoreInfo&, ErrorCallback, const IDBError&);
+    void renameObjectStoreAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction&, uint64_t objectStoreIdentifier, const String& newName, ErrorCallback, const IDBError&);
+    void createIndexAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction&, const IDBIndexInfo&, ErrorCallback, const IDBError&);
+    void renameIndexAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback, const IDBError&);
+    void putOrAddAfterQuotaCheck(uint64_t taskSize, const IDBRequestData&, const IDBKeyData&, const IDBValue&, IndexedDB::ObjectStoreOverwriteMode, KeyDataCallback, const IDBError&);
+    void deleteRecordAfterQuotaCheck(const IDBRequestData&, const IDBKeyRangeData&, ErrorCallback);
+
+    void deleteObjectStoreAfterQuotaCheck(UniqueIDBDatabaseTransaction&, const String& objectStoreName, ErrorCallback);
+    void clearObjectStoreAfetQuotaCheck(UniqueIDBDatabaseTransaction&, uint64_t objectStoreIdentifier, ErrorCallback);
+    void deleteIndexAfterQuotaCheck(UniqueIDBDatabaseTransaction&, uint64_t objectStoreIdentifier, const String&, ErrorCallback);
+    void getRecordAfterQuotaCheck(const IDBRequestData&, const IDBGetRecordData&, GetResultCallback);
+    void getAllRecordsAfterQuotaCheck(const IDBRequestData&, const IDBGetAllRecordsData&, GetAllResultsCallback);
+    void getCountAfterQuotaCheck(const IDBRequestData&, const IDBKeyRangeData&, CountCallback);
+    void openCursorAfterQuotaCheck(const IDBRequestData&, const IDBCursorInfo&, GetResultCallback);
+    void iterateCursorAfterQuotaCheck(const IDBRequestData&, const IDBIterateCursorData&, GetResultCallback);
+    void commitTransactionAfterQuotaCheck(UniqueIDBDatabaseTransaction&, ErrorCallback);
+
     // Database thread operations
     void deleteBackingStore(const IDBDatabaseIdentifier&);
-    void openBackingStore(const IDBDatabaseIdentifier&);
+    void openBackingStore(const IDBDatabaseIdentifier&, uint64_t taskIdentifier);
     void performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier);
     void performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier);
     void beginTransactionInBackingStore(const IDBTransactionInfo&);
-    void performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&);
+    void performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&, const IDBError&);
     void performDeleteObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier);
     void performRenameObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& newName, const IDBError&);
     void performClearObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier);
-    void performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo&);
+    void performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo&, const IDBError&);
     void performDeleteIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier);
     void performRenameIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, const IDBError&);
-    void performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, const IDBValue&, IndexedDB::ObjectStoreOverwriteMode);
+    void performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, const IDBValue&, IndexedDB::ObjectStoreOverwriteMode, const IDBError&);
     void performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IDBGetRecordDataType);
     void performGetAllRecords(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData&);
     void performGetIndexRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&);
@@ -169,7 +187,7 @@ private:
 
     // Main thread callbacks
     void didDeleteBackingStore(uint64_t deletedVersion);
-    void didOpenBackingStore(const IDBDatabaseInfo&, const IDBError&);
+    void didOpenBackingStore(const IDBDatabaseInfo&, const IDBError&, uint64_t taskIdentifier);
     void didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError&, const IDBObjectStoreInfo&);
     void didPerformDeleteObjectStore(uint64_t callbackIdentifier, const IDBError&, uint64_t objectStoreIdentifier);
     void didPerformRenameObjectStore(uint64_t callbackIdentifier, const IDBError&, uint64_t objectStoreIdentifier, const String& newName);
@@ -228,6 +246,11 @@ private:
     void maybeFinishHardClose();
     bool isDoneWithHardClose();
 
+    void requestSpace(UniqueIDBDatabaseTransaction&, uint64_t taskSize, const char* errorMessage, CompletionHandler<void(IDBError&&)>&&);
+    void waitForRequestSpaceCompletion(UniqueIDBDatabaseTransaction&, CompletionHandler<void(IDBError&&)>&&);
+    void startSpaceIncreaseTask(uint64_t identifier, uint64_t taskSize);
+    void finishSpaceIncreaseTask(uint64_t identifier, bool isTaskSuccessful);
+
     void clearTransactionsOnConnection(UniqueIDBDatabaseConnection&);
 
     static uint64_t generateUniqueCallbackIdentifier();
@@ -288,9 +311,9 @@ private:
 
     HashSet<IDBResourceIdentifier> m_cursorPrefetches;
 
-    bool m_isSuspended { false };
+    HashMap<uint64_t, uint64_t> m_pendingSpaceIncreaseTasks;
 
-    ClientOrigin m_origin;
+    bool m_isSuspended { false };
 };
 
 } // namespace IDBServer
index 8006069..fe910fa 100644 (file)
@@ -76,7 +76,7 @@ void UniqueIDBDatabaseConnection::abortTransactionWithoutCallback(UniqueIDBDatab
     if (!m_database)
         return;
     
-    m_database->abortTransaction(transaction, [this, protectedThis, transactionIdentifier](const IDBError&) {
+    m_database->abortTransaction(transaction, UniqueIDBDatabase::WaitForPendingTasks::No, [this, protectedThis, transactionIdentifier](const IDBError&) {
         ASSERT(m_transactionMap.contains(transactionIdentifier));
         m_transactionMap.remove(transactionIdentifier);
     });
index 76eddc4..a8d2bdc 100644 (file)
@@ -79,7 +79,7 @@ void UniqueIDBDatabaseTransaction::abort()
     auto database = m_databaseConnection->database();
     ASSERT(database);
 
-    database->abortTransaction(*this, [this, weakThis = makeWeakPtr(*this)](auto& error) {
+    database->abortTransaction(*this, UniqueIDBDatabase::WaitForPendingTasks::Yes, [this, weakThis = makeWeakPtr(*this)](auto& error) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::abort (callback)");
         if (!weakThis)
             return;
@@ -286,7 +286,7 @@ void UniqueIDBDatabaseTransaction::putOrAdd(const IDBRequestData& requestData, c
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->putOrAdd(requestData, keyData, value, overwriteMode, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBKeyData& key) {
+    database->putOrAdd(*this, requestData, keyData, value, overwriteMode, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBKeyData& key) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::putOrAdd (callback)");
         if (!weakThis)
             return;
@@ -307,7 +307,7 @@ void UniqueIDBDatabaseTransaction::getRecord(const IDBRequestData& requestData,
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->getRecord(requestData, getRecordData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetResult& result) {
+    database->getRecord(*this, requestData, getRecordData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetResult& result) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getRecord (callback)");
         if (!weakThis)
             return;
@@ -328,7 +328,7 @@ void UniqueIDBDatabaseTransaction::getAllRecords(const IDBRequestData& requestDa
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->getAllRecords(requestData, getAllRecordsData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetAllResult& result) {
+    database->getAllRecords(*this, requestData, getAllRecordsData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetAllResult& result) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getAllRecords (callback)");
         if (!weakThis)
             return;
@@ -349,7 +349,7 @@ void UniqueIDBDatabaseTransaction::getCount(const IDBRequestData& requestData, c
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->getCount(requestData, keyRangeData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, uint64_t count) {
+    database->getCount(*this, requestData, keyRangeData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, uint64_t count) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getCount (callback)");
         if (!weakThis)
             return;
@@ -370,7 +370,7 @@ void UniqueIDBDatabaseTransaction::deleteRecord(const IDBRequestData& requestDat
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->deleteRecord(requestData, keyRangeData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error) {
+    database->deleteRecord(*this, requestData, keyRangeData, [this, weakThis = makeWeakPtr(*this), requestData](auto& error) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteRecord (callback)");
         if (!weakThis)
             return;
@@ -391,7 +391,7 @@ void UniqueIDBDatabaseTransaction::openCursor(const IDBRequestData& requestData,
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->openCursor(requestData, info, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetResult& result) {
+    database->openCursor(*this, requestData, info, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetResult& result) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::openCursor (callback)");
         if (!weakThis)
             return;
@@ -412,7 +412,7 @@ void UniqueIDBDatabaseTransaction::iterateCursor(const IDBRequestData& requestDa
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->iterateCursor(requestData, data, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetResult& result) {
+    database->iterateCursor(*this, requestData, data, [this, weakThis = makeWeakPtr(*this), requestData](auto& error, const IDBGetResult& result) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::iterateCursor (callback)");
         if (!weakThis)
             return;
index d65bd5a..9111f59 100644 (file)
@@ -64,35 +64,30 @@ InProcessIDBServer::~InProcessIDBServer() = default;
 StorageQuotaManager* InProcessIDBServer::quotaManager(const ClientOrigin& origin)
 {
     return m_quotaManagers.ensure(origin, [] {
-        return StorageQuotaManager::create(StorageQuotaManager::defaultQuota(), [] {
-            return 0;
-        }, [](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
+        return makeUnique<StorageQuotaManager>(StorageQuotaManager::defaultQuota(), [](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
             callback(quota + currentSpace + spaceIncrease);
         });
     }).iterator->value.get();
 }
 
-static inline IDBServer::IDBServer::StorageQuotaManagerSpaceRequester storageQuotaManagerSpaceRequester(InProcessIDBServer& server)
+static inline IDBServer::IDBServer::QuotaManagerGetter storageQuotaManagerGetter(InProcessIDBServer& server)
 {
-    return [server = &server, weakServer = makeWeakPtr(server)](const ClientOrigin& origin, uint64_t spaceRequested) mutable {
-        auto* storageQuotaManager = weakServer ? server->quotaManager(origin) : nullptr;
-        return storageQuotaManager ? storageQuotaManager->requestSpaceOnBackgroundThread(spaceRequested) : StorageQuotaManager::Decision::Deny;
+    return [weakServer = makeWeakPtr(server)](PAL::SessionID, const auto& origin) {
+        return weakServer ? weakServer->quotaManager(origin) : nullptr;
     };
 }
 
 InProcessIDBServer::InProcessIDBServer(PAL::SessionID sessionID)
-    : m_server(IDBServer::IDBServer::create(sessionID, storageQuotaManagerSpaceRequester(*this)))
+    : m_server(IDBServer::IDBServer::create(sessionID, storageQuotaManagerGetter(*this)))
 {
-    ASSERT(isMainThread());
     relaxAdoptionRequirement();
     m_connectionToServer = IDBClient::IDBConnectionToServer::create(*this);
     m_connectionToClient = IDBServer::IDBConnectionToClient::create(*this);
 }
 
 InProcessIDBServer::InProcessIDBServer(PAL::SessionID sessionID, const String& databaseDirectoryPath)
-    : m_server(IDBServer::IDBServer::create(sessionID, databaseDirectoryPath, storageQuotaManagerSpaceRequester(*this)))
+    : m_server(IDBServer::IDBServer::create(sessionID, databaseDirectoryPath, storageQuotaManagerGetter(*this)))
 {
-    ASSERT(isMainThread());
     relaxAdoptionRequirement();
     m_connectionToServer = IDBClient::IDBConnectionToServer::create(*this);
     m_connectionToClient = IDBServer::IDBConnectionToClient::create(*this);
index 8e736a7..c7b5321 100644 (file)
@@ -64,6 +64,7 @@ public:
     WEBCORE_EXPORT IDBClient::IDBConnectionToServer& connectionToServer() const;
     IDBServer::IDBConnectionToClient& connectionToClient() const;
     IDBServer::IDBServer& server() { return m_server.get(); }
+
     IDBServer::IDBServer& idbServer() { return m_server.get(); }
 
     // IDBConnectionToServer
@@ -134,7 +135,7 @@ private:
     RefPtr<IDBClient::IDBConnectionToServer> m_connectionToServer;
     RefPtr<IDBServer::IDBConnectionToClient> m_connectionToClient;
 
-    HashMap<ClientOrigin, RefPtr<StorageQuotaManager>> m_quotaManagers;
+    HashMap<ClientOrigin, std::unique_ptr<StorageQuotaManager>> m_quotaManagers;
 };
 
 } // namespace WebCore
index fc0c628..3c71dd0 100644 (file)
                41D28D0D2139E05800F4206F /* LibWebRTCStatsCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D28D0B2139E01D00F4206F /* LibWebRTCStatsCollector.cpp */; };
                41D41C672256874F00697942 /* ServiceWorkerInternals.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41D41C652256859200697942 /* ServiceWorkerInternals.mm */; };
                41DE7C7C222DA14300532B65 /* StorageQuotaManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DE7C7B222DA13E00532B65 /* StorageQuotaManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               41DE7C7D222DA14800532B65 /* StorageQuotaUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DE7C78222DA13C00532B65 /* StorageQuotaUser.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41DEFCB61E56C1BD000D9E5F /* JSDOMMapLike.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DEFCB41E56C1B9000D9E5F /* JSDOMMapLike.h */; };
                41E1B1D10FF5986900576B3B /* AbstractWorker.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E1B1CB0FF5986900576B3B /* AbstractWorker.h */; };
                41E9DCE7231974BF00F35949 /* BlobLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E9DCE4231973FE00F35949 /* BlobLoader.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41D28D0C2139E01E00F4206F /* LibWebRTCStatsCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCStatsCollector.h; path = libwebrtc/LibWebRTCStatsCollector.h; sourceTree = "<group>"; };
                41D41C652256859200697942 /* ServiceWorkerInternals.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ServiceWorkerInternals.mm; sourceTree = "<group>"; };
                41D51BB21E4E2E8100131A5B /* LibWebRTCAudioFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCAudioFormat.h; path = libwebrtc/LibWebRTCAudioFormat.h; sourceTree = "<group>"; };
+               41DE7C78222DA13C00532B65 /* StorageQuotaUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageQuotaUser.h; sourceTree = "<group>"; };
                41DE7C7A222DA13D00532B65 /* StorageQuotaManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StorageQuotaManager.cpp; sourceTree = "<group>"; };
                41DE7C7B222DA13E00532B65 /* StorageQuotaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageQuotaManager.h; sourceTree = "<group>"; };
                41DEFCB21E56C1B9000D9E5F /* JSDOMBindingInternals.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSDOMBindingInternals.js; sourceTree = "<group>"; };
                                1A37636A1A2E68BB009A7EE2 /* StorageNamespaceProvider.h */,
                                41DE7C7A222DA13D00532B65 /* StorageQuotaManager.cpp */,
                                41DE7C7B222DA13E00532B65 /* StorageQuotaManager.h */,
+                               41DE7C78222DA13C00532B65 /* StorageQuotaUser.h */,
                                5166D3CC1E8ED41100AD62E3 /* StorageType.h */,
                        );
                        indentWidth = 4;
                                C50D0E830FF4272900AC2644 /* StorageNamespace.h in Headers */,
                                1A37636C1A2E68BB009A7EE2 /* StorageNamespaceProvider.h in Headers */,
                                41DE7C7C222DA14300532B65 /* StorageQuotaManager.h in Headers */,
+                               41DE7C7D222DA14800532B65 /* StorageQuotaUser.h in Headers */,
                                5C9EF2F321F06190003BDC56 /* StorageSessionProvider.h in Headers */,
                                5166D3CD1E8ED48F00AD62E3 /* StorageType.h in Headers */,
                                4682D2001F79783000C863DB /* StoredCredentialsPolicy.h in Headers */,
index 0c613d1..8525752 100644 (file)
 #include "StorageQuotaManager.h"
 
 #include "Logging.h"
-#include <wtf/Ref.h>
-#include <wtf/RefCounted.h>
-#include <wtf/threads/BinarySemaphore.h>
+#include "StorageQuotaUser.h"
 
 namespace WebCore {
 
-Ref<StorageQuotaManager> StorageQuotaManager::create(uint64_t quota, UsageGetter&& usageGetter, QuotaIncreaseRequester&& quotaIncreaseRequester)
+StorageQuotaManager::~StorageQuotaManager()
 {
-    return adoptRef(*new StorageQuotaManager(quota, WTFMove(usageGetter), WTFMove(quotaIncreaseRequester)));
+    while (!m_pendingRequests.isEmpty())
+        m_pendingRequests.takeFirst().callback(Decision::Deny);
 }
 
-StorageQuotaManager::StorageQuotaManager(uint64_t quota, UsageGetter&& usageGetter, QuotaIncreaseRequester&& quotaIncreaseRequester)
-    : m_quota(quota)
-    , m_usageGetter(WTFMove(usageGetter))
-    , m_quotaIncreaseRequester(WTFMove(quotaIncreaseRequester))
-    , m_workQueue(WorkQueue::create("StorageQuotaManager Background Queue", WorkQueue::Type::Serial))
-    , m_initialQuota(quota)
+uint64_t StorageQuotaManager::spaceUsage() const
 {
+    uint64_t usage = 0;
+    for (auto& user : m_users)
+        usage += user->spaceUsed();
+    return usage;
 }
 
-void StorageQuotaManager::requestSpaceOnMainThread(uint64_t spaceRequested, RequestCallback&& callback)
+void StorageQuotaManager::updateQuotaBasedOnSpaceUsage()
 {
-    ASSERT(isMainThread());
+    if (!m_quota)
+        return;
 
-    // Fast path.
-    if (m_quotaCountDownLock.tryLock()) {
-        if (tryGrantRequest(spaceRequested)) {
-            m_quotaCountDownLock.unlock();
-            callback(Decision::Grant);
-            return;
+    auto defaultQuotaStep = m_quota / 10;
+    m_quota = std::max(m_quota, defaultQuotaStep * ((spaceUsage() / defaultQuotaStep) + 1));
+}
+
+void StorageQuotaManager::initializeUsersIfNeeded()
+{
+    if (m_pendingInitializationUsers.isEmpty())
+        return;
+
+    Vector<StorageQuotaUser*> usersToInitialize;
+    for (auto& keyValue : m_pendingInitializationUsers) {
+        if (keyValue.value == WhenInitializedCalled::No) {
+            keyValue.value = WhenInitializedCalled::Yes;
+            usersToInitialize.append(keyValue.key);
         }
-        m_quotaCountDownLock.unlock();
     }
-
-    m_workQueue->dispatch([this, protectedThis = makeRef(*this), spaceRequested, callback = WTFMove(callback)]() mutable {
-        auto decision = requestSpaceOnBackgroundThread(spaceRequested);
-        callOnMainThread([callback = WTFMove(callback), decision]() mutable {
-            callback(decision);
-        });
-    });
+    for (auto* user : usersToInitialize) {
+        if (m_pendingInitializationUsers.contains(user))
+            askUserToInitialize(*user);
+    }
 }
 
-StorageQuotaManager::Decision StorageQuotaManager::requestSpaceOnBackgroundThread(uint64_t spaceRequested)
+void StorageQuotaManager::askUserToInitialize(StorageQuotaUser& user)
 {
-    ASSERT(!isMainThread());
+    user.whenInitialized([this, &user, weakThis = makeWeakPtr(this)]() {
+        if (!weakThis)
+            return;
 
-    LockHolder locker(m_quotaCountDownLock);
+        if (m_pendingInitializationUsers.remove(&user))
+            m_users.add(&user);
 
-    if (tryGrantRequest(spaceRequested))
-        return Decision::Grant;
+        if (!m_pendingInitializationUsers.isEmpty())
+            return;
 
-    m_usage = m_usageGetter();
-    updateQuotaBasedOnUsage();
-    m_quotaCountDown = m_usage < m_quota ? m_quota - m_usage : 0;
-    if (tryGrantRequest(spaceRequested))
-        return Decision::Grant;
+        // Make sure quota is set before handling first request.
+        if (m_state == State::Uninitialized) {
+            updateQuotaBasedOnSpaceUsage();
+            m_state = State::MakingDecisionForRequest;
+        }
 
-    // Block this thread until getting decsion for quota increase.
-    BinarySemaphore semaphore;
-    callOnMainThread([this, protectedThis = makeRef(*this), spaceRequested, &semaphore]() mutable {
-        RELEASE_LOG(Storage, "%p - StorageQuotaManager asks for quota increase %" PRIu64, this, spaceRequested);
-        m_quotaIncreaseRequester(m_quota, m_usage, spaceRequested, [this, protectedThis = WTFMove(protectedThis), &semaphore](Optional<uint64_t> newQuota) mutable {
-            RELEASE_LOG(Storage, "%p - StorageQuotaManager receives quota increase response %" PRIu64, this, newQuota ? *newQuota : 0);
-            ASSERT(isMainThread());
+        processPendingRequests({ });
+    });
+}
 
-            if (newQuota)
-                m_quota = *newQuota;
+void StorageQuotaManager::addUser(StorageQuotaUser& user)
+{
+    ASSERT(!m_pendingInitializationUsers.contains(&user));
+    ASSERT(!m_users.contains(&user));
+    m_pendingInitializationUsers.add(&user, WhenInitializedCalled::No);
 
-            semaphore.signal();
-        });
-    });
+    if (!m_pendingRequests.isEmpty())
+        askUserToInitialize(user);
+}
 
-    semaphore.wait();
+bool StorageQuotaManager::shouldAskForMoreSpace(uint64_t spaceIncrease) const
+{
+    if (!spaceIncrease)
+        return false;
 
-    m_usage = m_usageGetter();
-    m_quotaCountDown = m_usage < m_quota ? m_quota - m_usage : 0;
-    return tryGrantRequest(spaceRequested) ? Decision::Grant : Decision::Deny;
+    return spaceUsage() + spaceIncrease > m_quota;
 }
 
-bool StorageQuotaManager::tryGrantRequest(uint64_t spaceRequested)
+void StorageQuotaManager::removeUser(StorageQuotaUser& user)
 {
-    ASSERT(m_quotaCountDownLock.isLocked());
-    if (spaceRequested <= m_quotaCountDown) {
-        m_quotaCountDown -= spaceRequested;
-        return true;
+    ASSERT(m_users.contains(&user) || m_pendingInitializationUsers.contains(&user));
+    m_users.remove(&user);
+    if (m_pendingInitializationUsers.remove(&user) && m_pendingInitializationUsers.isEmpty()) {
+        // When being cleared, quota users may remove themselves and add themselves to trigger reinitialization.
+        // Let's wait for addUser to be called before processing pending requests.
+        callOnMainThread([this, weakThis = makeWeakPtr(this)] {
+            if (!weakThis)
+                return;
+
+            if (m_pendingInitializationUsers.isEmpty())
+                this->processPendingRequests({ });
+        });
     }
-    return false;
 }
-    
-void StorageQuotaManager::updateQuotaBasedOnUsage()
+
+void StorageQuotaManager::requestSpace(uint64_t spaceIncrease, RequestCallback&& callback)
 {
-    // When StorageQuotaManager is used for the first time, we want to make sure its initial quota is bigger than current disk usage,
-    // based on the assumption that the quota was increased to at least the disk usage under user's permission before.
-    ASSERT(m_quotaCountDownLock.isLocked());
-    if (!m_quotaUpdatedBasedOnUsage) {
-        m_quotaUpdatedBasedOnUsage = true;
-        auto defaultQuotaStep = m_quota / 10;
-        m_quota = std::max(m_quota, defaultQuotaStep * ((m_usage / defaultQuotaStep) + 1));
+    if (!m_pendingRequests.isEmpty()) {
+        m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
+        return;
+    }
+
+    if (!spaceIncrease) {
+        callback(Decision::Grant);
+        return;
+    }
+
+    initializeUsersIfNeeded();
+
+    if (!m_pendingInitializationUsers.isEmpty()) {
+        m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
+        return;
+    }
+
+    if (shouldAskForMoreSpace(spaceIncrease)) {
+        m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
+
+        // Try processing request again after making sure usage is accurate.
+        m_state = State::ComputingSpaceUsed;
+        for (auto& user : copyToVector(m_users))
+            user->computeSpaceUsed();
+
+        if (!m_pendingInitializationUsers.isEmpty())
+            return;
+
+        m_state = State::AskingForMoreSpace;
+        askForMoreSpace(spaceIncrease);
+        return;
     }
+
+    m_state = State::MakingDecisionForRequest;
+    callback(Decision::Grant);
 }
 
-void StorageQuotaManager::resetQuotaUpdatedBasedOnUsageForTesting()
+void StorageQuotaManager::askForMoreSpace(uint64_t spaceIncrease)
 {
-    LockHolder locker(m_quotaCountDownLock);
-    m_quota = m_initialQuota;
-    m_quotaCountDown = 0;
-    m_quotaUpdatedBasedOnUsage = false;
+    ASSERT(shouldAskForMoreSpace(spaceIncrease));
+    ASSERT(m_state == State::AskingForMoreSpace);
+
+    RELEASE_LOG(Storage, "%p - StorageQuotaManager::askForMoreSpace %" PRIu64, this, spaceIncrease);
+    m_state = State::WaitingForSpaceIncreaseResponse;
+    m_spaceIncreaseRequester(m_quota, spaceUsage(), spaceIncrease, [this, weakThis = makeWeakPtr(*this)](Optional<uint64_t> newQuota) {
+        if (!weakThis)
+            return;
+
+        RELEASE_LOG(Storage, "%p - StorageQuotaManager::askForMoreSpace received response %" PRIu64, this, newQuota ? *newQuota : 0);
+
+        m_state = State::AskingForMoreSpace;
+        processPendingRequests(newQuota);
+    });
 }
 
-void StorageQuotaManager::resetQuotaForTesting()
+void StorageQuotaManager::processPendingRequests(Optional<uint64_t> newQuota)
 {
-    LockHolder locker(m_quotaCountDownLock);
-    m_quota = m_initialQuota;
-    m_quotaCountDown = 0;
+    if (m_pendingRequests.isEmpty())
+        return;
+
+    if (newQuota)
+        m_quota = *newQuota;
+
+    if (m_state == State::WaitingForSpaceIncreaseResponse)
+        return;
+
+    if (!m_pendingInitializationUsers.isEmpty())
+        return;
+
+    if (m_state == State::AskingForMoreSpace) {
+        auto request = m_pendingRequests.takeFirst();
+        bool shouldAllowRequest = !shouldAskForMoreSpace(request.spaceIncrease);
+
+        RELEASE_LOG(Storage, "%p - StorageQuotaManager::processPendingRequests first request decision is %d", this, shouldAllowRequest);
+
+        m_state = State::MakingDecisionForRequest;
+        request.callback(shouldAllowRequest ? Decision::Grant : Decision::Deny);
+    }
+
+    while (!m_pendingRequests.isEmpty()) {
+        auto& request = m_pendingRequests.first();
+
+        if (shouldAskForMoreSpace(request.spaceIncrease)) {
+            if (m_state == State::MakingDecisionForRequest) {
+                m_state = State::ComputingSpaceUsed;
+                for (auto& user : copyToVector(m_users))
+                    user->computeSpaceUsed();
+
+                if (!m_pendingInitializationUsers.isEmpty())
+                    return;
+            }
+
+            m_state = State::AskingForMoreSpace;
+            uint64_t spaceIncrease = 0;
+            for (auto& pendingRequest : m_pendingRequests)
+                spaceIncrease += pendingRequest.spaceIncrease;
+            askForMoreSpace(spaceIncrease);
+            return;
+        }
+
+        m_state = State::MakingDecisionForRequest;
+        m_pendingRequests.takeFirst().callback(Decision::Grant);
+    }
 }
 
 } // namespace WebCore
index 9bdfdd4..0956630 100644 (file)
 
 #pragma once
 
+#include "ClientOrigin.h"
 #include <wtf/CompletionHandler.h>
 #include <wtf/Deque.h>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 #include <wtf/WeakPtr.h>
-#include <wtf/WorkQueue.h>
 
 namespace WebCore {
 
-class StorageQuotaManager : public ThreadSafeRefCounted<StorageQuotaManager>, public CanMakeWeakPtr<StorageQuotaManager> {
+class StorageQuotaUser;
+
+class StorageQuotaManager : public CanMakeWeakPtr<StorageQuotaManager> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    using UsageGetter = Function<uint64_t()>;
-    using QuotaIncreaseRequester = Function<void(uint64_t currentQuota, uint64_t currentUsage, uint64_t requestedIncrease, CompletionHandler<void(Optional<uint64_t>)>&&)>;
-    WEBCORE_EXPORT static Ref<StorageQuotaManager> create(uint64_t quota, UsageGetter&&, QuotaIncreaseRequester&&);
+    using SpaceIncreaseRequester = WTF::Function<void(uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, CompletionHandler<void(Optional<uint64_t>)>&&)>;
+    StorageQuotaManager(uint64_t quota, SpaceIncreaseRequester&& spaceIncreaseRequester)
+        : m_quota(quota)
+        , m_spaceIncreaseRequester(WTFMove(spaceIncreaseRequester))
+    {
+    }
+    WEBCORE_EXPORT ~StorageQuotaManager();
 
     static constexpr uint64_t defaultThirdPartyQuotaFromPerOriginQuota(uint64_t quota) { return quota / 10; }
+
     static constexpr uint64_t defaultQuota() { return 1000 * MB; }
     static constexpr uint64_t defaultThirdPartyQuota() { return defaultThirdPartyQuotaFromPerOriginQuota(defaultQuota()); }
 
+    WEBCORE_EXPORT void addUser(StorageQuotaUser&);
+    WEBCORE_EXPORT void removeUser(StorageQuotaUser&);
+
     enum class Decision { Deny, Grant };
     using RequestCallback = CompletionHandler<void(Decision)>;
-    WEBCORE_EXPORT void requestSpaceOnMainThread(uint64_t, RequestCallback&&);
-    WEBCORE_EXPORT Decision requestSpaceOnBackgroundThread(uint64_t);
+    WEBCORE_EXPORT void requestSpace(uint64_t, RequestCallback&&);
+    void resetQuota(uint64_t newQuota) { m_quota = newQuota; }
 
-    WEBCORE_EXPORT void resetQuotaUpdatedBasedOnUsageForTesting();
-    WEBCORE_EXPORT void resetQuotaForTesting();
+    WEBCORE_EXPORT void updateQuotaBasedOnSpaceUsage();
+
+    enum class State {
+        Uninitialized,
+        ComputingSpaceUsed,
+        WaitingForSpaceIncreaseResponse,
+        AskingForMoreSpace,
+        MakingDecisionForRequest,
+    };
+    State state() const { return m_state; }
 
 private:
-    StorageQuotaManager(uint64_t quota, UsageGetter&&, QuotaIncreaseRequester&&);
-    bool tryGrantRequest(uint64_t);
+    uint64_t spaceUsage() const;
+    bool shouldAskForMoreSpace(uint64_t spaceIncrease) const;
+    void askForMoreSpace(uint64_t spaceIncrease);
+
+    void initializeUsersIfNeeded();
+    void askUserToInitialize(StorageQuotaUser&);
 
-    void updateQuotaBasedOnUsage();
+    void processPendingRequests(Optional<uint64_t>);
 
-    Lock m_quotaCountDownLock;
-    uint64_t m_quotaCountDown { 0 };
     uint64_t m_quota { 0 };
-    uint64_t m_usage { 0 };
 
-    UsageGetter m_usageGetter;
-    QuotaIncreaseRequester m_quotaIncreaseRequester;
+    SpaceIncreaseRequester m_spaceIncreaseRequester;
 
-    Ref<WorkQueue> m_workQueue;
+    enum class WhenInitializedCalled { No, Yes };
+    HashMap<StorageQuotaUser*, WhenInitializedCalled> m_pendingInitializationUsers;
+    HashSet<StorageQuotaUser*> m_users;
 
-    bool m_quotaUpdatedBasedOnUsage { false };
+    struct PendingRequest {
+        uint64_t spaceIncrease;
+        RequestCallback callback;
+    };
+    Deque<PendingRequest> m_pendingRequests;
 
-    // Test only.
-    uint64_t m_initialQuota { 0 };
+    State m_state { State::Uninitialized };
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/storage/StorageQuotaUser.h b/Source/WebCore/storage/StorageQuotaUser.h
new file mode 100644 (file)
index 0000000..b710cee
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/CompletionHandler.h>
+
+namespace WebCore {
+
+class StorageQuotaUser {
+public:
+    virtual ~StorageQuotaUser() = default;
+
+    virtual uint64_t spaceUsed() const = 0;
+    virtual void computeSpaceUsed() { };
+    virtual void whenInitialized(CompletionHandler<void()>&& callback) { callback(); }
+};
+
+} // namespace WebCore
index b95e39d..fcabb92 100644 (file)
@@ -1,3 +1,17 @@
+2019-11-23  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r252805.
+        https://bugs.webkit.org/show_bug.cgi?id=204553
+
+        Caused test failures and ASan crashes (Requested by ap on
+        #webkit).
+
+        Reverted changeset:
+
+        "Cross-thread version StorageQuotaManager"
+        https://bugs.webkit.org/show_bug.cgi?id=203971
+        https://trac.webkit.org/changeset/252805
+
 2019-11-22  Alex Christensen  <achristensen@webkit.org>
 
         Unreviewed, rolling out r252796.
index b5a3e06..5f23cc6 100644 (file)
@@ -65,7 +65,6 @@
 #include "WebsiteDataStore.h"
 #include "WebsiteDataStoreParameters.h"
 #include "WebsiteDataType.h"
-#include <WebCore/ClientOrigin.h>
 #include <WebCore/CookieJar.h>
 #include <WebCore/DNS.h>
 #include <WebCore/DeprecatedGlobalSettings.h>
@@ -317,9 +316,6 @@ void NetworkProcess::initializeNetworkProcess(NetworkProcessCreationParameters&&
     auto sessionID = parameters.defaultDataStoreParameters.networkSessionParameters.sessionID;
     setSession(sessionID, NetworkSession::create(*this, WTFMove(parameters.defaultDataStoreParameters.networkSessionParameters)));
 
-    SandboxExtension::consumePermanently(parameters.defaultDataStoreParameters.cacheStorageDirectoryExtensionHandle);
-    addSessionStorageQuotaManager(sessionID, parameters.defaultDataStoreParameters.perOriginStorageQuota, parameters.defaultDataStoreParameters.perThirdPartyOriginStorageQuota, parameters.defaultDataStoreParameters.cacheStorageDirectory, parameters.defaultDataStoreParameters.cacheStorageDirectoryExtensionHandle);
-
 #if ENABLE(INDEXED_DATABASE)
     addIndexedDatabaseSession(sessionID, parameters.defaultDataStoreParameters.indexedDatabaseDirectory, parameters.defaultDataStoreParameters.indexedDatabaseDirectoryExtensionHandle);
 #endif
@@ -330,6 +326,7 @@ void NetworkProcess::initializeNetworkProcess(NetworkProcessCreationParameters&&
         addServiceWorkerSession(PAL::SessionID::defaultSessionID(), serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
     }
 #endif
+    initializeStorageQuota(parameters.defaultDataStoreParameters);
 
     m_storageManagerSet->add(sessionID, parameters.defaultDataStoreParameters.localStorageDirectory, parameters.defaultDataStoreParameters.localStorageDirectoryExtensionHandle);
 
@@ -437,39 +434,28 @@ void NetworkProcess::clearCachedCredentials()
 
 void NetworkProcess::addWebsiteDataStore(WebsiteDataStoreParameters&& parameters)
 {
-    auto sessionID = parameters.networkSessionParameters.sessionID;
-
-    addSessionStorageQuotaManager(sessionID, parameters.perOriginStorageQuota, parameters.perThirdPartyOriginStorageQuota, parameters.cacheStorageDirectory, parameters.cacheStorageDirectoryExtensionHandle);
-
 #if ENABLE(INDEXED_DATABASE)
-    addIndexedDatabaseSession(sessionID, parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
+    addIndexedDatabaseSession(parameters.networkSessionParameters.sessionID, parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
 #endif
 
 #if ENABLE(SERVICE_WORKER)
     if (parentProcessHasServiceWorkerEntitlement())
-        addServiceWorkerSession(sessionID, parameters.serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
+        addServiceWorkerSession(parameters.networkSessionParameters.sessionID, parameters.serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
 #endif
 
-    m_storageManagerSet->add(sessionID, parameters.localStorageDirectory, parameters.localStorageDirectoryExtensionHandle);
+    m_storageManagerSet->add(parameters.networkSessionParameters.sessionID, parameters.localStorageDirectory, parameters.localStorageDirectoryExtensionHandle);
 
-    RemoteNetworkingContext::ensureWebsiteDataStoreSession(*this, WTFMove(parameters));
-}
+    initializeStorageQuota(parameters);
 
-void NetworkProcess::addSessionStorageQuotaManager(PAL::SessionID sessionID, uint64_t defaultQuota, uint64_t defaultThirdPartyQuota, const String& cacheRootPath, SandboxExtension::Handle& cacheRootPathHandle)
-{
-    LockHolder locker(m_sessionStorageQuotaManagersLock);
-    auto [iter, isNewEntry] = m_sessionStorageQuotaManagers.ensure(sessionID, [defaultQuota, defaultThirdPartyQuota, &cacheRootPath] {
-        return makeUnique<SessionStorageQuotaManager>(cacheRootPath, defaultQuota, defaultThirdPartyQuota);
-    });
-    if (isNewEntry)
-        SandboxExtension::consumePermanently(cacheRootPathHandle);
+    RemoteNetworkingContext::ensureWebsiteDataStoreSession(*this, WTFMove(parameters));
 }
 
-void NetworkProcess::removeSessionStorageQuotaManager(PAL::SessionID sessionID)
+void NetworkProcess::initializeStorageQuota(const WebsiteDataStoreParameters& parameters)
 {
-    LockHolder locker(m_sessionStorageQuotaManagersLock);
-    ASSERT(m_sessionStorageQuotaManagers.contains(sessionID));
-    m_sessionStorageQuotaManagers.remove(sessionID);
+    auto& managers =  m_storageQuotaManagers.ensure(parameters.networkSessionParameters.sessionID, [] {
+        return StorageQuotaManagers { };
+    }).iterator->value;
+    managers.setDefaultQuotas(parameters.perOriginStorageQuota, parameters.perThirdPartyOriginStorageQuota);
 }
 
 void NetworkProcess::forEachNetworkSession(const Function<void(NetworkSession&)>& functor)
@@ -590,6 +576,8 @@ void NetworkProcess::destroySession(PAL::SessionID sessionID)
 #endif
 
     m_storageManagerSet->remove(sessionID);
+
+    m_storageQuotaManagers.remove(sessionID);
 }
 
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
@@ -1480,6 +1468,9 @@ void NetworkProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<Websi
     if (websiteDataTypes.contains(WebsiteDataType::DiskCache) && !sessionID.isEphemeral())
         clearDiskCache(modifiedSince, [clearTasksHandler = WTFMove(clearTasksHandler)] { });
 
+    if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases) || websiteDataTypes.contains(WebsiteDataType::DOMCache))
+        clearStorageQuota(sessionID);
+
     if (websiteDataTypes.contains(WebsiteDataType::AdClickAttributions)) {
         if (auto* networkSession = this->networkSession(sessionID))
             networkSession->clearAdClickAttribution();
@@ -1572,6 +1563,19 @@ void NetworkProcess::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, Optio
         }
         WebCore::CredentialStorage::removeSessionCredentialsWithOrigins(originDatas);
     }
+
+    // FIXME: Implement storage quota clearing for these origins.
+}
+
+void NetworkProcess::clearStorageQuota(PAL::SessionID sessionID)
+{
+    auto iterator = m_storageQuotaManagers.find(sessionID);
+    if (iterator == m_storageQuotaManagers.end())
+        return;
+
+    auto& managers = iterator->value;
+    for (auto& manager : managers.managersPerOrigin())
+        manager.value->resetQuota(managers.defaultQuota(manager.key));
 }
 
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
@@ -2213,9 +2217,10 @@ Ref<IDBServer::IDBServer> NetworkProcess::createIDBServer(PAL::SessionID session
         path = m_idbDatabasePaths.get(sessionID);
     }
 
-    return IDBServer::IDBServer::create(sessionID, path, [this, weakThis = makeWeakPtr(this), sessionID](const auto& origin, uint64_t spaceRequested) {
-        RefPtr<StorageQuotaManager> storageQuotaManager = weakThis ? this->storageQuotaManager(sessionID, origin) : nullptr;
-        return storageQuotaManager ? storageQuotaManager->requestSpaceOnBackgroundThread(spaceRequested) : StorageQuotaManager::Decision::Deny;
+    return IDBServer::IDBServer::create(sessionID, path, [this, weakThis = makeWeakPtr(this)](PAL::SessionID sessionID, const auto& origin) -> StorageQuotaManager* {
+        if (!weakThis)
+            return nullptr;
+        return &this->storageQuotaManager(sessionID, origin);
     });
 }
 
@@ -2302,18 +2307,8 @@ void NetworkProcess::addIndexedDatabaseSession(PAL::SessionID sessionID, String&
         SandboxExtension::consumePermanently(handle);
         if (!indexedDatabaseDirectory.isEmpty())
             postStorageTask(createCrossThreadTask(*this, &NetworkProcess::ensurePathExists, indexedDatabaseDirectory));
-        setSessionStorageQuotaManagerIDBRootPath(sessionID, indexedDatabaseDirectory);
     }
 }
-
-void NetworkProcess::setSessionStorageQuotaManagerIDBRootPath(PAL::SessionID sessionID, const String& idbRootPath)
-{
-    LockHolder locker(m_sessionStorageQuotaManagersLock);
-    auto* sessionStorageQuotaManager = m_sessionStorageQuotaManagers.get(sessionID);
-    ASSERT(sessionStorageQuotaManager);
-    sessionStorageQuotaManager->setIDBRootPath(idbRootPath);
-}
-
 #endif // ENABLE(INDEXED_DATABASE)
 
 void NetworkProcess::syncLocalStorage(CompletionHandler<void()>&& completionHandler)
@@ -2330,18 +2325,9 @@ void NetworkProcess::clearLegacyPrivateBrowsingLocalStorage()
 
 void NetworkProcess::updateQuotaBasedOnSpaceUsageForTesting(PAL::SessionID sessionID, const ClientOrigin& origin)
 {
-    auto storageQuotaManager = this->storageQuotaManager(sessionID, origin);
-    storageQuotaManager->resetQuotaUpdatedBasedOnUsageForTesting();
-}
-
-void NetworkProcess::resetQuota(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
-{
-    LockHolder locker(m_sessionStorageQuotaManagersLock);
-    if (auto* sessionStorageQuotaManager = m_sessionStorageQuotaManagers.get(sessionID)) {
-        for (auto storageQuotaManager : sessionStorageQuotaManager->existingStorageQuotaManagers())
-            storageQuotaManager->resetQuotaForTesting();
-    }
-    completionHandler();
+    auto& manager = storageQuotaManager(sessionID, origin);
+    manager.resetQuota(m_storageQuotaManagers.find(sessionID)->value.defaultQuota(origin));
+    manager.updateQuotaBasedOnSpaceUsage();
 }
 
 #if ENABLE(SANDBOX_EXTENSIONS)
@@ -2418,35 +2404,62 @@ void NetworkProcess::requestStorageSpace(PAL::SessionID sessionID, const ClientO
     parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::RequestStorageSpace { sessionID, origin, quota, currentSize, spaceRequired }, WTFMove(callback), 0);
 }
 
-RefPtr<StorageQuotaManager> NetworkProcess::storageQuotaManager(PAL::SessionID sessionID, const ClientOrigin& origin)
-{
-    LockHolder locker(m_sessionStorageQuotaManagersLock);
-    auto* sessionStorageQuotaManager = m_sessionStorageQuotaManagers.get(sessionID);
-    if (!sessionStorageQuotaManager)
-        return nullptr;
+class QuotaUserInitializer final : public WebCore::StorageQuotaUser {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit QuotaUserInitializer(StorageQuotaManager& manager)
+        : m_manager(makeWeakPtr(manager))
+    {
+        manager.addUser(*this);
+    }
 
-    String idbRootPath;
-#if ENABLE(INDEXED_DATABASE)
-    idbRootPath = sessionStorageQuotaManager->idbRootPath();
-#endif
-    StorageQuotaManager::UsageGetter usageGetter = [cacheRootPath = sessionStorageQuotaManager->cacheRootPath().isolatedCopy(), idbRootPath = idbRootPath.isolatedCopy(), origin = origin.isolatedCopy()]() {
-        ASSERT(!isMainThread());    
+    ~QuotaUserInitializer()
+    {
+        if (m_manager)
+            m_manager->removeUser(*this);
+        if (m_callback)
+            m_callback();
+    }
 
-        uint64_t usage = CacheStorage::Engine::diskUsage(cacheRootPath, origin);
-#if ENABLE(INDEXED_DATABASE)
-        usage += IDBServer::IDBServer::diskUsage(idbRootPath, origin);
-#endif
+private:
+    // StorageQuotaUser API.
+    uint64_t spaceUsed() const final
+    {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
 
-        return usage;
-    };
-    StorageQuotaManager::QuotaIncreaseRequester quotaIncreaseRequester = [this, weakThis = makeWeakPtr(*this), sessionID, origin] (uint64_t currentQuota, uint64_t currentSpace, uint64_t requestedIncrease, auto&& callback) {
-        ASSERT(isMainThread());
+    void whenInitialized(CompletionHandler<void()>&& callback) final
+    {
+        m_callback = WTFMove(callback);
+    }
+
+    WeakPtr<StorageQuotaManager> m_manager;
+    CompletionHandler<void()> m_callback;
+};
+
+void NetworkProcess::initializeQuotaUsers(StorageQuotaManager& manager, PAL::SessionID sessionID, const ClientOrigin& origin)
+{
+    RunLoop::main().dispatch([this, weakThis = makeWeakPtr(this), sessionID, origin, user = makeUnique<QuotaUserInitializer>(manager)]() mutable {
         if (!weakThis)
-            callback({ });
-        requestStorageSpace(sessionID, origin, currentQuota, currentSpace, requestedIncrease, WTFMove(callback));
-    };
+            return;
+        this->idbServer(sessionID).initializeQuotaUser(origin);
+        CacheStorage::Engine::initializeQuotaUser(*this, sessionID, origin, [user = WTFMove(user)] { });
+    });
+}
 
-    return sessionStorageQuotaManager->ensureOriginStorageQuotaManager(origin, sessionStorageQuotaManager->defaultQuota(origin), WTFMove(usageGetter), WTFMove(quotaIncreaseRequester)).ptr();
+StorageQuotaManager& NetworkProcess::storageQuotaManager(PAL::SessionID sessionID, const ClientOrigin& origin)
+{
+    auto& storageQuotaManagers = m_storageQuotaManagers.ensure(sessionID, [] {
+        return StorageQuotaManagers { };
+    }).iterator->value;
+    return *storageQuotaManagers.managersPerOrigin().ensure(origin, [this, &storageQuotaManagers, sessionID, &origin] {
+        auto manager = makeUnique<StorageQuotaManager>(storageQuotaManagers.defaultQuota(origin), [this, sessionID, origin](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
+            this->requestStorageSpace(sessionID, origin, quota, currentSpace, spaceIncrease, WTFMove(callback));
+        });
+        initializeQuotaUsers(*manager, sessionID, origin);
+        return manager;
+    }).iterator->value;
 }
 
 #if !PLATFORM(COCOA)
index d3adfc1..f62f01d 100644 (file)
@@ -284,7 +284,6 @@ public:
     void clearLegacyPrivateBrowsingLocalStorage();
 
     void updateQuotaBasedOnSpaceUsageForTesting(PAL::SessionID, const WebCore::ClientOrigin&);
-    void resetQuota(PAL::SessionID, CompletionHandler<void()>&&);
 
 #if ENABLE(SANDBOX_EXTENSIONS)
     void getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, CompletionHandler<void(SandboxExtension::HandleArray&&)>&&);
@@ -328,7 +327,7 @@ public:
     void setAdClickAttributionConversionURLForTesting(PAL::SessionID, URL&&, CompletionHandler<void()>&&);
     void markAdClickAttributionsAsExpiredForTesting(PAL::SessionID, CompletionHandler<void()>&&);
 
-    RefPtr<WebCore::StorageQuotaManager> storageQuotaManager(PAL::SessionID, const WebCore::ClientOrigin&);
+    WebCore::StorageQuotaManager& storageQuotaManager(PAL::SessionID, const WebCore::ClientOrigin&);
 
     void addKeptAliveLoad(Ref<NetworkResourceLoader>&&);
     void removeKeptAliveLoad(NetworkResourceLoader&);
@@ -443,7 +442,6 @@ private:
     void collectIndexedDatabaseOriginsForVersion(const String&, HashSet<WebCore::SecurityOriginData>&);
     HashSet<WebCore::SecurityOriginData> indexedDatabaseOrigins(const String& path);
     Ref<WebCore::IDBServer::IDBServer> createIDBServer(PAL::SessionID);
-    void setSessionStorageQuotaManagerIDBRootPath(PAL::SessionID, const String& idbRootPath);
 #endif
 
 #if ENABLE(SERVICE_WORKER)
@@ -463,44 +461,8 @@ private:
     void performNextStorageTask();
     void ensurePathExists(const String& path);
 
-    class SessionStorageQuotaManager {
-        WTF_MAKE_FAST_ALLOCATED;
-    public:
-        SessionStorageQuotaManager(const String& cacheRootPath, uint64_t defaultQuota, uint64_t defaultThirdPartyQuota)
-            : m_cacheRootPath(cacheRootPath)
-            , m_defaultQuota(defaultQuota)
-            , m_defaultThirdPartyQuota(defaultThirdPartyQuota)
-        {
-        }
-        uint64_t defaultQuota(const WebCore::ClientOrigin& origin) const { return origin.topOrigin == origin.clientOrigin ? m_defaultQuota : m_defaultThirdPartyQuota; }
-
-        Ref<WebCore::StorageQuotaManager> ensureOriginStorageQuotaManager(WebCore::ClientOrigin origin, uint64_t quota, WebCore::StorageQuotaManager::UsageGetter&& usageGetter, WebCore::StorageQuotaManager::QuotaIncreaseRequester&& quotaIncreaseRequester)
-        {
-            auto [iter, isNewEntry] = m_storageQuotaManagers.ensure(origin, [quota, usageGetter = WTFMove(usageGetter), quotaIncreaseRequester = WTFMove(quotaIncreaseRequester)]() mutable {
-                return WebCore::StorageQuotaManager::create(quota, WTFMove(usageGetter), WTFMove(quotaIncreaseRequester));
-            });
-            return makeRef(*iter->value);
-        }
-
-        auto existingStorageQuotaManagers() { return m_storageQuotaManagers.values(); }
-
-        const String& cacheRootPath() const { return m_cacheRootPath; }
-#if ENABLE(INDEXED_DATABASE)
-        void setIDBRootPath(const String& idbRootPath) { m_idbRootPath = idbRootPath; }
-        const String& idbRootPath() const { return m_idbRootPath; }
-#endif
-
-    private:
-        String m_cacheRootPath;
-#if ENABLE(INDEXED_DATABASE)
-        String m_idbRootPath;
-#endif
-        uint64_t m_defaultQuota { WebCore::StorageQuotaManager::defaultQuota() };
-        uint64_t m_defaultThirdPartyQuota { WebCore::StorageQuotaManager::defaultThirdPartyQuota() };
-        HashMap<WebCore::ClientOrigin, RefPtr<WebCore::StorageQuotaManager>> m_storageQuotaManagers;
-    };
-    void addSessionStorageQuotaManager(PAL::SessionID, uint64_t defaultQuota, uint64_t defaultThirdPartyQuota, const String& cacheRootPath, SandboxExtension::Handle&);
-    void removeSessionStorageQuotaManager(PAL::SessionID);
+    void clearStorageQuota(PAL::SessionID);
+    void initializeStorageQuota(const WebsiteDataStoreParameters&);
 
     // Connections to WebProcesses.
     HashMap<WebCore::ProcessIdentifier, Ref<NetworkConnectionToWebProcess>> m_webProcessConnections;
@@ -571,8 +533,23 @@ private:
     bool m_isITPDatabaseEnabled { false };
 #endif
     
-    Lock m_sessionStorageQuotaManagersLock;
-    HashMap<PAL::SessionID, std::unique_ptr<SessionStorageQuotaManager>> m_sessionStorageQuotaManagers;
+    class StorageQuotaManagers {
+    public:
+        uint64_t defaultQuota(const WebCore::ClientOrigin& origin) const { return origin.topOrigin == origin.clientOrigin ? m_defaultQuota : m_defaultThirdPartyQuota; }
+        void setDefaultQuotas(uint64_t defaultQuota, uint64_t defaultThirdPartyQuota)
+        {
+            m_defaultQuota = defaultQuota;
+            m_defaultThirdPartyQuota = defaultThirdPartyQuota;
+        }
+
+        HashMap<WebCore::ClientOrigin, std::unique_ptr<WebCore::StorageQuotaManager>>& managersPerOrigin() { return m_managersPerOrigin; }
+
+    private:
+        uint64_t m_defaultQuota { WebCore::StorageQuotaManager::defaultQuota() };
+        uint64_t m_defaultThirdPartyQuota { WebCore::StorageQuotaManager::defaultThirdPartyQuota() };
+        HashMap<WebCore::ClientOrigin, std::unique_ptr<WebCore::StorageQuotaManager>> m_managersPerOrigin;
+    };
+    HashMap<PAL::SessionID, StorageQuotaManagers> m_storageQuotaManagers;
 
     OptionSet<NetworkCache::CacheOption> m_cacheOptions;
     WebCore::MessagePortChannelRegistry m_messagePortChannelRegistry;
index 361e907..3677677 100644 (file)
@@ -163,6 +163,4 @@ messages -> NetworkProcess LegacyReceiver {
 
     SetServiceWorkerFetchTimeoutForTesting(Seconds seconds) -> () Synchronous
     ResetServiceWorkerFetchTimeoutForTesting() -> () Synchronous
-
-    ResetQuota(PAL::SessionID sessionID) -> () Async
 }
index 3d65947..efe7e15 100644 (file)
@@ -196,68 +196,13 @@ void Engine::clearCachesForOrigin(NetworkProcess& networkProcess, PAL::SessionID
     });
 }
 
-static uint64_t getDirectorySize(const String& directoryPath)
-{
-    ASSERT(!isMainThread());
-
-    uint64_t directorySize = 0;
-    Deque<String> paths;
-    paths.append(directoryPath);
-    while (!paths.isEmpty()) {
-        auto path = paths.takeFirst();
-        if (FileSystem::fileIsDirectory(path, FileSystem::ShouldFollowSymbolicLinks::No)) {
-            auto newPaths = FileSystem::listDirectory(path, "*"_s);
-            for (auto& newPath : newPaths) {
-                // Files in /Blobs directory are hard link.
-                auto fileName = FileSystem::lastComponentOfPathIgnoringTrailingSlash(newPath);
-                if (fileName == "Blobs")
-                    continue;
-                paths.append(newPath);
-            }
-            continue;
-        }
-
-        long long fileSize = 0;
-        FileSystem::getFileSize(path, fileSize);
-        directorySize += fileSize;
-    }
-    return directorySize;
-}
-
-uint64_t Engine::diskUsage(const String& rootPath, const WebCore::ClientOrigin& origin)
+void Engine::initializeQuotaUser(NetworkProcess& networkProcess, PAL::SessionID sessionID, const WebCore::ClientOrigin& clientOrigin, CompletionHandler<void()>&& completionHandler)
 {
-    ASSERT(!isMainThread());
-
-    if (rootPath.isEmpty())
-        return 0;
-
-    String saltPath = FileSystem::pathByAppendingComponent(rootPath, "salt"_s);
-    auto salt = readOrMakeSalt(saltPath);
-    if (!salt)
-        return 0;
-
-    Key key(origin.topOrigin.toString(), origin.clientOrigin.toString(), { }, { }, *salt);
-    String directoryPath = FileSystem::pathByAppendingComponent(rootPath, key.hashAsString());
-
-    String sizeFilePath = Caches::cachesSizeFilename(directoryPath);
-    if (auto recordedSize = readSizeFile(sizeFilePath))
-        return *recordedSize;
-
-    return getDirectorySize(directoryPath);
-}
-
-void Engine::requestSpace(const ClientOrigin& origin, uint64_t spaceRequested, CompletionHandler<void(WebCore::StorageQuotaManager::Decision)>&& callback)
-{
-    ASSERT(isMainThread());
-
-    if (!m_networkProcess)
-        callback(WebCore::StorageQuotaManager::Decision::Deny);
-
-    RefPtr<WebCore::StorageQuotaManager> storageQuotaManager = m_networkProcess->storageQuotaManager(m_sessionID, origin);
-    if (!storageQuotaManager)
-        callback(WebCore::StorageQuotaManager::Decision::Deny);
-
-    storageQuotaManager->requestSpaceOnMainThread(spaceRequested, WTFMove(callback));
+    from(networkProcess, sessionID, [clientOrigin, completionHandler = WTFMove(completionHandler)](auto& engine) mutable {
+        engine.readCachesFromDisk(clientOrigin, [completionHandler = WTFMove(completionHandler)](auto&& cachesOrError) mutable {
+            completionHandler();
+        });
+    });
 }
 
 Engine::Engine(PAL::SessionID sessionID, NetworkProcess& process, String&& rootPath)
@@ -396,7 +341,7 @@ void Engine::readCachesFromDisk(const WebCore::ClientOrigin& origin, CachesCallb
 
         auto& caches = m_caches.ensure(origin, [&origin, this] {
             auto path = cachesRootPath(origin);
-            return Caches::create(*this, WebCore::ClientOrigin { origin }, WTFMove(path));
+            return Caches::create(*this, WebCore::ClientOrigin { origin }, WTFMove(path), m_networkProcess->storageQuotaManager(m_sessionID, origin));
         }).iterator->value;
 
         if (caches->isInitialized()) {
@@ -528,13 +473,12 @@ void Engine::removeFile(const String& filename)
     });
 }
 
-void Engine::writeSizeFile(const String& path, uint64_t size, CompletionHandler<void()>&& completionHandler)
+void Engine::writeSizeFile(const String& path, uint64_t size)
 {
-    CompletionHandlerCallingScope completionHandlerCaller(WTFMove(completionHandler));
     if (!shouldPersist())
         return;
 
-    m_ioQueue->dispatch([path = path.isolatedCopy(), size, completionHandlerCaller = WTFMove(completionHandlerCaller)]() mutable {
+    m_ioQueue->dispatch([path = path.isolatedCopy(), size]() {
         LockHolder locker(globalSizeFileLock);
         auto fileHandle = FileSystem::openFile(path, FileSystem::FileOpenMode::Write);
         auto closeFileHandler = makeScopeExit([&] {
@@ -545,8 +489,6 @@ void Engine::writeSizeFile(const String& path, uint64_t size, CompletionHandler<
 
         FileSystem::truncateFile(fileHandle, 0);
         FileSystem::writeToFile(fileHandle, String::number(size).utf8().data(), String::number(size).utf8().length());
-
-        RunLoop::main().dispatch([completionHandlerCaller = WTFMove(completionHandlerCaller)]() mutable { });
     });
 }
 
@@ -571,8 +513,8 @@ Optional<uint64_t> Engine::readSizeFile(const String& path)
     if (!WTF::convertSafely(fileSize, bytesToRead))
         return WTF::nullopt;
 
-    Vector<unsigned char> buffer(bytesToRead);
-    size_t totalBytesRead = FileSystem::readFromFile(fileHandle, reinterpret_cast<char*>(buffer.data()), buffer.size());
+    Vector<char> buffer(bytesToRead);
+    size_t totalBytesRead = FileSystem::readFromFile(fileHandle, buffer.data(), buffer.size());
     if (totalBytesRead != bytesToRead)
         return WTF::nullopt;
 
index 22ee66b..a3aaaf0 100644 (file)
@@ -29,7 +29,6 @@
 #include "NetworkCacheData.h"
 #include "WebsiteData.h"
 #include <WebCore/ClientOrigin.h>
-#include <WebCore/StorageQuotaManager.h>
 #include <pal/SessionID.h>
 #include <wtf/HashMap.h>
 #include <wtf/RefCounted.h>
@@ -80,15 +79,12 @@ public:
 
     static void initializeQuotaUser(NetworkProcess&, PAL::SessionID, const WebCore::ClientOrigin&, CompletionHandler<void()>&&);
 
-    static uint64_t diskUsage(const String& rootPath, const WebCore::ClientOrigin&);
-    void requestSpace(const WebCore::ClientOrigin&, uint64_t spaceRequested, CompletionHandler<void(WebCore::StorageQuotaManager::Decision)>&&);
-
     bool shouldPersist() const { return !!m_ioQueue;}
 
     void writeFile(const String& filename, NetworkCache::Data&&, WebCore::DOMCacheEngine::CompletionCallback&&);
     void readFile(const String& filename, CompletionHandler<void(const NetworkCache::Data&, int error)>&&);
     void removeFile(const String& filename);
-    void writeSizeFile(const String&, uint64_t size, CompletionHandler<void()>&&);
+    void writeSizeFile(const String&, uint64_t size);
     static Optional<uint64_t> readSizeFile(const String&);
 
     const String& rootPath() const { return m_rootPath; }
index ba134cf..6fc53e0 100644 (file)
@@ -414,11 +414,8 @@ void Cache::put(Vector<Record>&& records, RecordIdentifiersCallback&& callback)
         auto position = (sameURLRecords && !matchingRecords.isEmpty()) ? sameURLRecords->findMatching([&](const auto& item) { return item.identifier == matchingRecords[0]; }) : notFound;
 
         spaceRequired += record.responseBodySize;
-        if (position != notFound) {
-            uint64_t spaceDecreased = sameURLRecords->at(position).size;
-            if (spaceRequired >= spaceDecreased)
-                spaceRequired -= spaceDecreased;
-        }
+        if (position != notFound)
+            spaceRequired -= sameURLRecords->at(position).size;
     }
 
     m_caches.requestSpace(spaceRequired, [caches = makeRef(m_caches), identifier = m_identifier, records = WTFMove(records), callback = WTFMove(callback)](Optional<DOMCacheEngine::Error>&& error) mutable {
@@ -453,10 +450,7 @@ void Cache::remove(WebCore::ResourceRequest&& request, WebCore::CacheQueryOption
         return shouldRemove;
     });
 
-    // This operation would change caches size, so make sure callback finishes after size file is updated.
-    m_caches.updateSizeFile([callback = WTFMove(callback), recordIdentifiers = WTFMove(recordIdentifiers)]() mutable {
-        callback(WTFMove(recordIdentifiers));
-    });
+    callback(WTFMove(recordIdentifiers));
 }
 
 void Cache::removeFromRecordList(const Vector<uint64_t>& recordIdentifiers)
index f237451..03a060c 100644 (file)
@@ -56,21 +56,36 @@ String Caches::cachesSizeFilename(const String& cachesRootsPath)
     return FileSystem::pathByAppendingComponent(cachesRootsPath, "estimatedsize"_s);
 }
 
-Ref<Caches> Caches::create(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath)
+Ref<Caches> Caches::create(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath, WebCore::StorageQuotaManager& quotaManager)
 {
-    return adoptRef(*new Caches { engine, WTFMove(origin), WTFMove(rootPath) });
+    auto caches = adoptRef(*new Caches { engine, WTFMove(origin), WTFMove(rootPath), quotaManager });
+    quotaManager.addUser(caches.get());
+    return caches;
 }
 
-Caches::Caches(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath)
+Caches::Caches(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath, WebCore::StorageQuotaManager& quotaManager)
     : m_engine(&engine)
     , m_origin(WTFMove(origin))
     , m_rootPath(WTFMove(rootPath))
+    , m_quotaManager(makeWeakPtr(quotaManager))
 {
 }
 
 Caches::~Caches()
 {
     ASSERT(m_pendingWritingCachesToDiskCallbacks.isEmpty());
+
+    if (m_quotaManager)
+        m_quotaManager->removeUser(*this);
+}
+
+void Caches::whenInitialized(CompletionHandler<void()>&& callback)
+{
+    initialize([callback = WTFMove(callback)](auto&& error) mutable {
+        if (error)
+            RELEASE_LOG_ERROR(CacheStorage, "Caches::initialize failed, reported space used will be zero");
+        callback();
+    });
 }
 
 void Caches::retrieveOriginFromDirectory(const String& folderPath, WorkQueue& queue, WTF::CompletionHandler<void(Optional<WebCore::ClientOrigin>&&)>&& completionHandler)
@@ -193,14 +208,10 @@ void Caches::initialize(WebCore::DOMCacheEngine::CompletionCallback&& callback)
     });
 }
 
-void Caches::updateSizeFile(CompletionHandler<void()>&& completionHandler)
+void Caches::updateSizeFile()
 {
-    if (!m_engine) {
-        completionHandler();
-        return;
-    }
-
-    m_engine->writeSizeFile(cachesSizeFilename(m_rootPath), m_size, WTFMove(completionHandler));
+    if (m_engine)
+        m_engine->writeSizeFile(cachesSizeFilename(m_rootPath), m_size);
 }
 
 void Caches::initializeSize()
@@ -221,12 +232,13 @@ void Caches::initializeSize()
                 return;
             }
             m_size = size;
-            updateSizeFile([this, protectedThis = WTFMove(protectedThis)]() mutable {
-                m_isInitialized = true;
-                auto pendingCallbacks = WTFMove(m_pendingInitializationCallbacks);
-                for (auto& callback : pendingCallbacks)
-                    callback(WTF::nullopt);
-            });
+            updateSizeFile();
+
+            m_isInitialized = true;
+            auto pendingCallbacks = WTFMove(m_pendingInitializationCallbacks);
+            for (auto& callback : pendingCallbacks)
+                callback(WTF::nullopt);
+
             return;
         }
         auto decoded = Cache::decodeRecordHeader(*storage);
@@ -261,11 +273,13 @@ void Caches::clear(CompletionHandler<void()>&& completionHandler)
         m_storage->clear(String { }, -WallTime::infinity(), [protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
             ASSERT(RunLoop::isMain());
             protectedThis->clearMemoryRepresentation();
+            protectedThis->resetSpaceUsed();
             completionHandler();
         });
         return;
     }
     clearMemoryRepresentation();
+    resetSpaceUsed();
     clearPendingWritingCachesToDiskCallbacks();
     completionHandler();
 }
@@ -511,12 +525,12 @@ void Caches::readRecordsList(Cache& cache, NetworkCache::Storage::TraverseHandle
 
 void Caches::requestSpace(uint64_t spaceRequired, WebCore::DOMCacheEngine::CompletionCallback&& callback)
 {
-    if (!m_engine) {
+    if (!m_quotaManager) {
         callback(Error::QuotaExceeded);
         return;
     }
 
-    m_engine->requestSpace(m_origin, spaceRequired, [callback = WTFMove(callback)](auto decision) mutable {
+    m_quotaManager->requestSpace(spaceRequired, [callback = WTFMove(callback)](auto decision) mutable {
         switch (decision) {
         case WebCore::StorageQuotaManager::Decision::Deny:
             callback(Error::QuotaExceeded);
@@ -534,6 +548,7 @@ void Caches::writeRecord(const Cache& cache, const RecordInformation& recordInfo
     ASSERT(m_size >= previousRecordSize);
     m_size += recordInformation.size;
     m_size -= previousRecordSize;
+    updateSizeFile();
 
     if (!shouldPersist()) {
         m_volatileStorage.set(recordInformation.key, WTFMove(record));
@@ -541,15 +556,13 @@ void Caches::writeRecord(const Cache& cache, const RecordInformation& recordInfo
         return;
     }
 
-    m_storage->store(Cache::encode(recordInformation, record), { }, [this, protectedThis = makeRef(*this), protectedStorage = makeRef(*m_storage), callback = WTFMove(callback)](int error) mutable {
+    m_storage->store(Cache::encode(recordInformation, record), { }, [protectedStorage = makeRef(*m_storage), callback = WTFMove(callback)](int error) mutable {
         if (error) {
             RELEASE_LOG_ERROR(CacheStorage, "Caches::writeRecord failed with error %d", error);
             callback(Error::WriteDisk);
             return;
         }
-        updateSizeFile([callback = WTFMove(callback)]() mutable {
-            callback(WTF::nullopt);
-        });
+        callback(WTF::nullopt);
     });
 }
 
@@ -592,7 +605,7 @@ void Caches::removeRecord(const RecordInformation& record)
 
     ASSERT(m_size >= record.size);
     m_size -= record.size;
-    updateSizeFile([] { });
+    updateSizeFile();
 
     removeCacheEntry(record.key);
 }
@@ -608,6 +621,17 @@ void Caches::removeCacheEntry(const NetworkCache::Key& key)
     m_storage->remove(key);
 }
 
+void Caches::resetSpaceUsed()
+{
+    m_size = 0;
+    updateSizeFile();
+
+    if (m_quotaManager) {
+        m_quotaManager->removeUser(*this);
+        m_quotaManager->addUser(*this);
+    }
+}
+
 void Caches::clearMemoryRepresentation()
 {
     makeDirty();
index 5d394a0..03231f3 100644 (file)
@@ -28,6 +28,7 @@
 #include "CacheStorageEngineCache.h"
 #include "NetworkCacheStorage.h"
 #include <WebCore/ClientOrigin.h>
+#include <WebCore/StorageQuotaUser.h>
 #include <wtf/CompletionHandler.h>
 #include <wtf/Deque.h>
 
@@ -41,10 +42,10 @@ namespace CacheStorage {
 
 class Engine;
 
-class Caches final : public RefCounted<Caches> {
+class Caches final : public RefCounted<Caches>, private WebCore::StorageQuotaUser {
 public:
-    static String cachesSizeFilename(const String& cachesRootsPath);
-    static Ref<Caches> create(Engine&, WebCore::ClientOrigin&&, String&& rootPath);
+    static String cachesSizeFilename(const String&);
+    static Ref<Caches> create(Engine&, WebCore::ClientOrigin&&, String&& rootPath, WebCore::StorageQuotaManager&);
     ~Caches();
 
     static void retrieveOriginFromDirectory(const String& folderPath, WorkQueue&, WTF::CompletionHandler<void(Optional<WebCore::ClientOrigin>&&)>&&);
@@ -78,17 +79,22 @@ public:
 
     void clear(WTF::CompletionHandler<void()>&&);
     void clearMemoryRepresentation();
+    void resetSpaceUsed();
 
     uint64_t storageSize() const;
-    void updateSizeFile(CompletionHandler<void()>&&);
 
 private:
-    Caches(Engine&, WebCore::ClientOrigin&&, String&& rootPath);
+    Caches(Engine&, WebCore::ClientOrigin&&, String&& rootPath, WebCore::StorageQuotaManager&);
+
+    // StorageQuotaUser API.
+    uint64_t spaceUsed() const final { return m_size; }
 
     void initializeSize();
     void readCachesFromDisk(WTF::Function<void(Expected<Vector<Cache>, WebCore::DOMCacheEngine::Error>&&)>&&);
     void writeCachesToDisk(WebCore::DOMCacheEngine::CompletionCallback&&);
 
+    void whenInitialized(CompletionHandler<void()>&&) final;
+
     void storeOrigin(WebCore::DOMCacheEngine::CompletionCallback&&);
     static Optional<WebCore::ClientOrigin> readOrigin(const NetworkCache::Data&);
 
@@ -100,6 +106,8 @@ private:
 
     bool hasActiveCache() const;
 
+    void updateSizeFile();
+
     bool m_isInitialized { false };
     Engine* m_engine { nullptr };
     uint64_t m_updateCounter { 0 };
@@ -114,6 +122,7 @@ private:
     Vector<WebCore::DOMCacheEngine::CompletionCallback> m_pendingInitializationCallbacks;
     bool m_isWritingCachesToDisk { false };
     Deque<CompletionHandler<void(Optional<WebCore::DOMCacheEngine::Error>)>> m_pendingWritingCachesToDiskCallbacks;
+    WeakPtr<WebCore::StorageQuotaManager> m_quotaManager;
 };
 
 } // namespace CacheStorage
index 6d0c129..c0fcf9c 100644 (file)
@@ -55,8 +55,6 @@ void WebsiteDataStoreParameters::encode(IPC::Encoder& encoder) const
 
     encoder << localStorageDirectory << localStorageDirectoryExtensionHandle;
 
-    encoder << cacheStorageDirectory << cacheStorageDirectoryExtensionHandle;
-
     encoder << perOriginStorageQuota;
     encoder << perThirdPartyOriginStorageQuota;
 }
@@ -143,18 +141,6 @@ Optional<WebsiteDataStoreParameters> WebsiteDataStoreParameters::decode(IPC::Dec
         return WTF::nullopt;
     parameters.localStorageDirectoryExtensionHandle = WTFMove(*localStorageDirectoryExtensionHandle);
 
-    Optional<String> cacheStorageDirectory;
-    decoder >> cacheStorageDirectory;
-    if (!cacheStorageDirectory)
-        return WTF::nullopt;
-    parameters.cacheStorageDirectory = WTFMove(*cacheStorageDirectory);
-
-    Optional<SandboxExtension::Handle> cacheStorageDirectoryExtensionHandle;
-    decoder >> cacheStorageDirectoryExtensionHandle;
-    if (!cacheStorageDirectoryExtensionHandle)
-        return WTF::nullopt;
-    parameters.cacheStorageDirectoryExtensionHandle = WTFMove(*cacheStorageDirectoryExtensionHandle);
-
     Optional<uint64_t> perOriginStorageQuota;
     decoder >> perOriginStorageQuota;
     if (!perOriginStorageQuota)
index f27df48..095f09d 100644 (file)
@@ -71,9 +71,6 @@ struct WebsiteDataStoreParameters {
     String localStorageDirectory;
     SandboxExtension::Handle localStorageDirectoryExtensionHandle;
 
-    String cacheStorageDirectory;
-    SandboxExtension::Handle cacheStorageDirectoryExtensionHandle;
-
     uint64_t perOriginStorageQuota { WebCore::StorageQuotaManager::defaultQuota() };
     uint64_t perThirdPartyOriginStorageQuota { WebCore::StorageQuotaManager::defaultThirdPartyQuota() };
 };
index 99a4086..7eb7577 100644 (file)
@@ -686,11 +686,3 @@ void WKWebsiteDataStoreSetCacheModelSynchronouslyForTesting(WKWebsiteDataStoreRe
 {
     WebKit::toImpl(dataStoreRef)->setCacheModelSynchronouslyForTesting(WebKit::toCacheModel(cacheModel));
 }
-
-void WKWebsiteDataStoreResetQuota(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreResetQuotaCallback callback)
-{
-    WebKit::toImpl(dataStoreRef)->resetQuota([context, callback] {
-        if (callback)
-            callback(context);
-    });
-}
index 23fc2e7..95239a3 100644 (file)
@@ -155,9 +155,6 @@ WK_EXPORT void WKWebsiteDataStoreClearAdClickAttributionsThroughWebsiteDataRemov
 
 WK_EXPORT void WKWebsiteDataStoreSetCacheModelSynchronouslyForTesting(WKWebsiteDataStoreRef dataStoreRef, WKCacheModel cacheModel);
 
-typedef void (*WKWebsiteDataStoreResetQuotaCallback)(void* functionContext);
-WK_EXPORT void WKWebsiteDataStoreResetQuota(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreResetQuotaCallback callback);
-
 #ifdef __cplusplus
 }
 #endif
index 4c41c93..ad57991 100644 (file)
@@ -1367,11 +1367,6 @@ void NetworkProcessProxy::updateProcessAssertion()
     m_activityFromWebProcesses = nullptr;
 }
 
-void NetworkProcessProxy::resetQuota(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
-{
-    sendWithAsyncReply(Messages::NetworkProcess::ResetQuota(sessionID), WTFMove(completionHandler));
-}
-
 } // namespace WebKit
 
 #undef MESSAGE_CHECK
index b77ce7d..72ce425 100644 (file)
@@ -56,7 +56,6 @@ enum class StorageAccessPromptWasShown : bool;
 enum class StorageAccessWasGranted : bool;
 class SecurityOrigin;
 struct SecurityOriginData;
-struct ClientOrigin;
 }
 
 namespace WebKit {
@@ -197,8 +196,6 @@ public:
     void registerSchemeForLegacyCustomProtocol(const String&);
     void unregisterSchemeForLegacyCustomProtocol(const String&);
 
-    void resetQuota(PAL::SessionID, CompletionHandler<void()>&&);
-
 private:
     // AuxiliaryProcessProxy
     void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
index 7eeca3d..4068ee4 100644 (file)
@@ -551,12 +551,6 @@ NetworkProcessProxy& WebProcessPool::ensureNetworkProcess(WebsiteDataStore* with
     parameters.defaultDataStoreParameters.localStorageDirectory = localStorageDirectory;
     SandboxExtension::createHandleForReadWriteDirectory(localStorageDirectory, parameters.defaultDataStoreParameters.localStorageDirectoryExtensionHandle);
 
-    auto cacheStorageDirectory = m_websiteDataStore ? m_websiteDataStore->cacheStorageDirectory() : nullString();
-    if (!cacheStorageDirectory.isEmpty()) {
-        SandboxExtension::createHandleForReadWriteDirectory(cacheStorageDirectory, parameters.defaultDataStoreParameters.cacheStorageDirectoryExtensionHandle);
-        parameters.defaultDataStoreParameters.cacheStorageDirectory = WTFMove(cacheStorageDirectory);
-    }
-
     if (m_websiteDataStore)
         parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectory = m_websiteDataStore->resolvedResourceLoadStatisticsDirectory();
     if (parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectory.isEmpty())
index 07199ec..0ff3ea0 100644 (file)
@@ -191,10 +191,6 @@ WebsiteDataStoreParameters WebsiteDataStore::parameters()
     if (!parameters.localStorageDirectory.isEmpty())
         SandboxExtension::createHandleForReadWriteDirectory(parameters.localStorageDirectory, parameters.localStorageDirectoryExtensionHandle);
 
-    parameters.cacheStorageDirectory = cacheStorageDirectory();
-    if (!parameters.cacheStorageDirectory.isEmpty())
-        SandboxExtension::createHandleForReadWriteDirectory(parameters.cacheStorageDirectory, parameters.cacheStorageDirectoryExtensionHandle);
-
     parameters.perOriginStorageQuota = perOriginStorageQuota();
     parameters.perThirdPartyOriginStorageQuota = perThirdPartyOriginStorageQuota();
 
index ac2f38d..bb98416 100644 (file)
@@ -2083,12 +2083,6 @@ WebsiteDataStoreParameters WebsiteDataStore::parameters()
         SandboxExtension::createHandleForReadWriteDirectory(localStorageDirectory, parameters.localStorageDirectoryExtensionHandle);
     }
 
-    auto cacheStorageDirectory = this->cacheStorageDirectory();
-    if (!cacheStorageDirectory.isEmpty()) {
-        SandboxExtension::createHandleForReadWriteDirectory(cacheStorageDirectory, parameters.cacheStorageDirectoryExtensionHandle);
-        parameters.cacheStorageDirectory = cacheStorageDirectory;
-    }
-
 #if ENABLE(INDEXED_DATABASE)
     parameters.indexedDatabaseDirectory = resolvedIndexedDatabaseDirectory();
     if (!parameters.indexedDatabaseDirectory.isEmpty())
@@ -2175,15 +2169,6 @@ void WebsiteDataStore::getLocalStorageDetails(Function<void(Vector<LocalStorageD
     ASSERT(!completionHandler);
 }
 
-void WebsiteDataStore::resetQuota(CompletionHandler<void()>&& completionHandler)
-{
-    auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
-    for (auto& processPool : processPools()) {
-        if (auto* process = processPool->networkProcess())
-            process->resetQuota(m_sessionID, [callbackAggregator = callbackAggregator.copyRef()] { });
-    }
-}
-
 #if !PLATFORM(COCOA)
 WTF::String WebsiteDataStore::defaultMediaCacheDirectory()
 {
index f5ee422..2784fe3 100644 (file)
@@ -291,9 +291,7 @@ public:
     static WTF::String defaultMediaKeysStorageDirectory();
     static WTF::String defaultDeviceIdHashSaltsStorageDirectory();
     static WTF::String defaultJavaScriptConfigurationDirectory();
-
-    void resetQuota(CompletionHandler<void()>&&);
-
+    
 private:
     void fetchDataAndApply(OptionSet<WebsiteDataType>, OptionSet<WebsiteDataFetchOption>, RefPtr<WorkQueue>&&, Function<void(Vector<WebsiteDataRecord>)>&& apply);
 
index 45746d8..a905b2a 100644 (file)
@@ -1,3 +1,17 @@
+2019-11-23  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r252805.
+        https://bugs.webkit.org/show_bug.cgi?id=204553
+
+        Caused test failures and ASan crashes (Requested by ap on
+        #webkit).
+
+        Reverted changeset:
+
+        "Cross-thread version StorageQuotaManager"
+        https://bugs.webkit.org/show_bug.cgi?id=203971
+        https://trac.webkit.org/changeset/252805
+
 2019-11-23  Per Arne Vollan  <pvollan@apple.com>
 
         Archive step is failing after r252827
index 8252f98..d5768ed 100644 (file)
                9399BA062371114F008392BF /* IndexedDBNotInPageCache.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9399BA03237110BF008392BF /* IndexedDBNotInPageCache.html */; };
                93AF4ECE1506F064007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93AF4ECD1506F064007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp */; };
                93AF4ED11506F130007FD57E /* lots-of-images.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93AF4ECF1506F123007FD57E /* lots-of-images.html */; };
+               93B62054234EA62C00D49B97 /* StorageQuotaManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93B62053234EA32B00D49B97 /* StorageQuotaManager.cpp */; };
                93CFA8671CEB9E38000565A8 /* autofocused-text-input.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93CFA8661CEB9DE1000565A8 /* autofocused-text-input.html */; };
                93D119FC22C680F7009BE3C7 /* localstorage-open-window-private.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93D119FB22C57112009BE3C7 /* localstorage-open-window-private.html */; };
                93E2C5551FD3204100E1DF6A /* LineEnding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E2C5541FD3204100E1DF6A /* LineEnding.cpp */; };
                        dstPath = TestWebKitAPI.resources;
                        dstSubfolderSpec = 7;
                        files = (
+                               CD8394DF232AF7C000149495 /* media-loading.html in Copy Resources */,
                                55A817FF2181021A0004A39A /* 100x100-red.tga in Copy Resources */,
                                1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
                                55A81800218102210004A39A /* 400x400-green.png in Copy Resources */,
                                930AD402150698D00067970F /* lots-of-text.html in Copy Resources */,
                                AD57AC221DA7466E00FF1BDE /* many-iframes.html in Copy Resources */,
                                7772ECE122FE06C60009A799 /* many-same-origin-iframes.html in Copy Resources */,
-                               CD8394DF232AF7C000149495 /* media-loading.html in Copy Resources */,
                                CDA3159A1ED548F1009F60D3 /* MediaPlaybackSleepAssertion.html in Copy Resources */,
                                CDC9442F1EF205D60059C3C4 /* mediastreamtrack-detached.html in Copy Resources */,
                                E1220DCA155B28AA0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html in Copy Resources */,
                93AF4ECA1506F035007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NewFirstVisuallyNonEmptyLayoutForImages.cpp; sourceTree = "<group>"; };
                93AF4ECD1506F064007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp; sourceTree = "<group>"; };
                93AF4ECF1506F123007FD57E /* lots-of-images.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "lots-of-images.html"; sourceTree = "<group>"; };
+               93B62053234EA32B00D49B97 /* StorageQuotaManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StorageQuotaManager.cpp; sourceTree = "<group>"; };
                93CFA8661CEB9DE1000565A8 /* autofocused-text-input.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "autofocused-text-input.html"; sourceTree = "<group>"; };
                93CFA8681CEBCFED000565A8 /* CandidateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CandidateTests.mm; sourceTree = "<group>"; };
                93D119FB22C57112009BE3C7 /* localstorage-open-window-private.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "localstorage-open-window-private.html"; sourceTree = "<group>"; };
                                41973B5C1AF22875006C7B36 /* SharedBuffer.cpp */,
                                A17991891E1CA24100A505ED /* SharedBufferTest.cpp */,
                                A179918A1E1CA24100A505ED /* SharedBufferTest.h */,
+                               93B62053234EA32B00D49B97 /* StorageQuotaManager.cpp */,
                                ECA680CD1E68CC0900731D20 /* StringUtilities.mm */,
                                CE4D5DE51F6743BA0072CFC6 /* StringWithDirection.cpp */,
                                93A258981F92FF15003E510C /* TextCodec.cpp */,
                                930AD401150698B30067970F /* lots-of-text.html */,
                                AD57AC1D1DA7463800FF1BDE /* many-iframes.html */,
                                7772ECE022FE05E10009A799 /* many-same-origin-iframes.html */,
-                               CD8394DE232AF15E00149495 /* media-loading.html */,
                                CDC9442B1EF1FBD20059C3C4 /* mediastreamtrack-detached.html */,
                                51CD1C711B38D48400142CA5 /* modal-alerts-in-new-about-blank-window.html */,
                                7A1458FB1AD5C03500E06772 /* mouse-button-listener.html */,
                                07CD32F72065B72A0064A4BE /* video.html */,
                                1C2B81841C8924A200A5529F /* webfont.html */,
                                468F2F932368DAA700F4B864 /* window-open-then-document-open.html */,
+                               CD8394DE232AF15E00149495 /* media-loading.html */,
                        );
                        name = Resources;
                        sourceTree = "<group>";
                                7CCE7ECF1A411A7E00447C4C /* StopLoadingFromDidReceiveResponse.mm in Sources */,
                                CDC0932E21C993440030C4B0 /* StopSuspendResumeAllMedia.mm in Sources */,
                                414AD6862285D1C000777F2D /* StorageQuota.mm in Sources */,
+                               93B62054234EA62C00D49B97 /* StorageQuotaManager.cpp in Sources */,
                                515BE1711D428E4B00DD7C68 /* StoreBlobThenDelete.mm in Sources */,
                                7CCE7ED01A411A7E00447C4C /* StringByEvaluatingJavaScriptFromString.mm in Sources */,
                                7CCE7ED11A411A7E00447C4C /* StringTruncator.mm in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/StorageQuotaManager.cpp b/Tools/TestWebKitAPI/Tests/WebCore/StorageQuotaManager.cpp
new file mode 100644 (file)
index 0000000..ad1c67b
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+* Copyright (C) 2019 Apple Inc. All Rights Reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+
+#include <WebCore/StorageQuotaManager.h>
+#include <WebCore/StorageQuotaUser.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+static const int defaultQuota = 1 * KB;
+
+class MockQuotaUser final : public WebCore::StorageQuotaUser {
+public:
+    explicit MockQuotaUser(StorageQuotaManager& manager)
+        : m_manager(&manager)
+    {
+        manager.addUser(*this);
+    }
+
+    void setSpaceUsed(uint64_t spaceUsed) { m_spaceUsed = spaceUsed; }
+
+private:
+    uint64_t spaceUsed() const final
+    {
+        return m_spaceUsed;
+    }
+
+    void whenInitialized(CompletionHandler<void()>&& callback) final
+    {
+        if (!m_spaceUsed)
+            ASSERT_EQ(m_manager->state(), StorageQuotaManager::State::Uninitialized);
+        else
+            ASSERT_EQ(m_manager->state(), StorageQuotaManager::State::ComputingSpaceUsed);
+
+        // Reset usage to mock deletion.
+        m_spaceUsed = 0;
+        callback();
+    }
+
+    uint64_t m_spaceUsed { 0 };
+    StorageQuotaManager* m_manager;
+};
+    
+TEST(StorageQuotaManagerTest, Basic)
+{
+    StorageQuotaManager* storageQuotaManagerPtr = nullptr;
+    StorageQuotaManager storageQuotaManager(defaultQuota, [&storageQuotaManagerPtr](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, CompletionHandler<void(Optional<uint64_t>)>&& completionHanlder) {
+        ASSERT_TRUE(storageQuotaManagerPtr);
+        ASSERT_EQ(storageQuotaManagerPtr->state(), StorageQuotaManager::State::WaitingForSpaceIncreaseResponse);
+
+        // Allow all space increase requests.
+        completionHanlder(spaceIncrease + currentSpace);
+    });
+    storageQuotaManagerPtr = &storageQuotaManager;
+
+
+    MockQuotaUser mockUser(storageQuotaManager);
+
+    // Grant directly.
+    storageQuotaManager.requestSpace(0.1 * KB, [&](WebCore::StorageQuotaManager::Decision decision) {
+        ASSERT_EQ(decision, WebCore::StorageQuotaManager::Decision::Grant);
+        mockUser.setSpaceUsed(0.1 * KB);
+    });
+
+    // Grant after computing accurate usage.
+    storageQuotaManager.requestSpace(1.0 * KB, [&](WebCore::StorageQuotaManager::Decision decision) {
+        ASSERT_EQ(decision, WebCore::StorageQuotaManager::Decision::Grant);
+        mockUser.setSpaceUsed(1.0 * KB);
+    });
+
+    // Grant after computing accurate usage and requesting space increase.
+    storageQuotaManager.requestSpace(10 * KB, [&](WebCore::StorageQuotaManager::Decision decision) {
+        ASSERT_EQ(storageQuotaManagerPtr->state(), StorageQuotaManager::State::MakingDecisionForRequest);
+        ASSERT_EQ(decision, WebCore::StorageQuotaManager::Decision::Grant);
+    });
+}
+
+} // namespace TestWebKitAPI
index 29214bf..3a07c13 100644 (file)
@@ -981,8 +981,6 @@ bool TestController::resetStateToConsistentValues(const TestOptions& options, Re
     clearServiceWorkerRegistrations();
     clearDOMCaches();
 
-    resetQuota();
-
     WKContextSetAllowsAnySSLCertificateForServiceWorkerTesting(platformContext(), true);
 
     WKContextClearCurrentModifierStateForTesting(TestController::singleton().context());
@@ -3144,13 +3142,6 @@ void TestController::syncLocalStorage()
     runUntil(context.done, noTimeout);
 }
 
-void TestController::resetQuota()
-{
-    StorageVoidCallbackContext context(*this);
-    WKWebsiteDataStoreResetQuota(TestController::websiteDataStore(), &context, StorageVoidCallback);
-    runUntil(context.done, noTimeout);
-}
-
 struct FetchCacheOriginsCallbackContext {
     FetchCacheOriginsCallbackContext(TestController& controller, WKStringRef origin)
         : testController(controller)
index ad71c86..1b261bc 100644 (file)
@@ -269,8 +269,6 @@ public:
     void terminateNetworkProcess();
     void terminateServiceWorkerProcess();
 
-    void resetQuota();
-
     void removeAllSessionCredentials();
 
     void clearIndexedDatabases();