Title: [242136] trunk/Source
Revision
242136
Author
[email protected]
Date
2019-02-27 10:55:07 -0800 (Wed, 27 Feb 2019)

Log Message

Network Process is put to suspended when holding locked IndexedDB files
https://bugs.webkit.org/show_bug.cgi?id=195024
<rdar://problem/45194169>

Reviewed by Geoffrey Garen.

Source/WebCore:

We found network process was suspended when IDBDatabase was being closed in the background database thread,
holding locks to its database file. To avoid starvation or deadlock, we need to keep network process alive by
taking background assertion in UI process until the closes are done and locks are released.

* Modules/indexeddb/server/IDBServer.cpp:
(WebCore::IDBServer::IDBServer::create):
(WebCore::IDBServer::IDBServer::IDBServer):
(WebCore::IDBServer::IDBServer::createBackingStore):
(WebCore::IDBServer::IDBServer::closeDatabase):
(WebCore::IDBServer::IDBServer::didCloseDatabase):
* Modules/indexeddb/server/IDBServer.h:
(WebCore::IDBServer::IDBServer::create):
* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::performCurrentDeleteOperation):
(WebCore::IDBServer::UniqueIDBDatabase::scheduleShutdownForClose):
(WebCore::IDBServer::UniqueIDBDatabase::didShutdownForClose):
(WebCore::IDBServer::UniqueIDBDatabase::didDeleteBackingStore):
(WebCore::IDBServer::UniqueIDBDatabase::immediateCloseForUserDelete):
(WebCore::IDBServer::UniqueIDBDatabase::notifyServerAboutClose):
* Modules/indexeddb/server/UniqueIDBDatabase.h:

Source/WebKit:

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::idbServer):
(WebKit::NetworkProcess::notifyHoldingLockedFiles):
* NetworkProcess/NetworkProcess.h:
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::didClose):
(WebKit::NetworkProcessProxy::setIsIDBDatabaseHoldingLockedFiles):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/Network/NetworkProcessProxy.messages.in:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (242135 => 242136)


--- trunk/Source/WebCore/ChangeLog	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebCore/ChangeLog	2019-02-27 18:55:07 UTC (rev 242136)
@@ -1,3 +1,32 @@
+2019-02-27  Sihui Liu  <[email protected]>
+
+        Network Process is put to suspended when holding locked IndexedDB files
+        https://bugs.webkit.org/show_bug.cgi?id=195024
+        <rdar://problem/45194169>
+
+        Reviewed by Geoffrey Garen.
+
+        We found network process was suspended when IDBDatabase was being closed in the background database thread, 
+        holding locks to its database file. To avoid starvation or deadlock, we need to keep network process alive by 
+        taking background assertion in UI process until the closes are done and locks are released.
+
+        * Modules/indexeddb/server/IDBServer.cpp:
+        (WebCore::IDBServer::IDBServer::create):
+        (WebCore::IDBServer::IDBServer::IDBServer):
+        (WebCore::IDBServer::IDBServer::createBackingStore):
+        (WebCore::IDBServer::IDBServer::closeDatabase):
+        (WebCore::IDBServer::IDBServer::didCloseDatabase):
+        * Modules/indexeddb/server/IDBServer.h:
+        (WebCore::IDBServer::IDBServer::create):
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::performCurrentDeleteOperation):
+        (WebCore::IDBServer::UniqueIDBDatabase::scheduleShutdownForClose):
+        (WebCore::IDBServer::UniqueIDBDatabase::didShutdownForClose):
+        (WebCore::IDBServer::UniqueIDBDatabase::didDeleteBackingStore):
+        (WebCore::IDBServer::UniqueIDBDatabase::immediateCloseForUserDelete):
+        (WebCore::IDBServer::UniqueIDBDatabase::notifyServerAboutClose):
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+
 2019-02-26  Simon Fraser  <[email protected]>
 
         Have a single notion of scroll position in the scrolling tree and derive layoutViewport from it

Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp (242135 => 242136)


--- trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp	2019-02-27 18:55:07 UTC (rev 242136)
@@ -42,26 +42,30 @@
 namespace WebCore {
 namespace IDBServer {
 
-Ref<IDBServer> IDBServer::create(IDBBackingStoreTemporaryFileHandler& fileHandler)
+Ref<IDBServer> IDBServer::create(IDBBackingStoreTemporaryFileHandler& fileHandler, WTF::Function<void(bool)>&& isClosingDatabaseCallback)
 {
-    return adoptRef(*new IDBServer(fileHandler));
+    return adoptRef(*new IDBServer(fileHandler, WTFMove(isClosingDatabaseCallback)));
 }
 
-Ref<IDBServer> IDBServer::create(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler& fileHandler)
+Ref<IDBServer> IDBServer::create(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler& fileHandler, WTF::Function<void(bool)>&& isClosingDatabaseCallback)
 {
-    return adoptRef(*new IDBServer(databaseDirectoryPath, fileHandler));
+    return adoptRef(*new IDBServer(databaseDirectoryPath, fileHandler, WTFMove(isClosingDatabaseCallback)));
 }
 
-IDBServer::IDBServer(IDBBackingStoreTemporaryFileHandler& fileHandler)
+IDBServer::IDBServer(IDBBackingStoreTemporaryFileHandler& fileHandler, WTF::Function<void(bool)>&& isClosingDatabaseCallback)
     : CrossThreadTaskHandler("IndexedDatabase Server")
     , m_backingStoreTemporaryFileHandler(fileHandler)
+    , m_isClosingDatabaseCallback(WTFMove(isClosingDatabaseCallback))
+    , m_isClosingDatabaseHysteresis([&](PAL::HysteresisState state) { m_isClosingDatabaseCallback(state == PAL::HysteresisState::Started); })
 {
 }
 
-IDBServer::IDBServer(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler& fileHandler)
+IDBServer::IDBServer(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler& fileHandler, WTF::Function<void(bool)>&& isClosingDatabaseCallback)
     : CrossThreadTaskHandler("IndexedDatabase Server")
     , m_databaseDirectoryPath(databaseDirectoryPath)
     , m_backingStoreTemporaryFileHandler(fileHandler)
+    , m_isClosingDatabaseCallback(WTFMove(isClosingDatabaseCallback))
+    , m_isClosingDatabaseHysteresis([&](PAL::HysteresisState state) { m_isClosingDatabaseCallback(state == PAL::HysteresisState::Started); })
 {
     LOG(IndexedDB, "IDBServer created at path %s", databaseDirectoryPath.utf8().data());
 }
@@ -652,6 +656,29 @@
         database->setQuota(quota);
 }
 
+void IDBServer::closeDatabase(UniqueIDBDatabase* database)
+{
+    ASSERT(isMainThread());
+    if (m_databaseDirectoryPath.isEmpty())
+        return;
+
+    auto addResult = m_uniqueIDBDatabasesInClose.add(database);
+    if (addResult.isNewEntry && m_uniqueIDBDatabasesInClose.size() == 1)
+        m_isClosingDatabaseHysteresis.start();
+}
+
+void IDBServer::didCloseDatabase(UniqueIDBDatabase* database)
+{
+    ASSERT(isMainThread());
+    if (m_databaseDirectoryPath.isEmpty())
+        return;
+
+    if (m_uniqueIDBDatabasesInClose.remove(database)) {
+        if (m_uniqueIDBDatabasesInClose.isEmpty())
+            m_isClosingDatabaseHysteresis.stop();
+    }
+}
+
 } // namespace IDBServer
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h (242135 => 242136)


--- trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h	2019-02-27 18:55:07 UTC (rev 242136)
@@ -31,6 +31,7 @@
 #include "IDBDatabaseIdentifier.h"
 #include "UniqueIDBDatabase.h"
 #include "UniqueIDBDatabaseConnection.h"
+#include <pal/HysteresisActivity.h>
 #include <wtf/CrossThreadTaskHandler.h>
 #include <wtf/HashMap.h>
 #include <wtf/Lock.h>
@@ -54,8 +55,8 @@
 
 class IDBServer : public RefCounted<IDBServer>, public CrossThreadTaskHandler {
 public:
-    static Ref<IDBServer> create(IDBBackingStoreTemporaryFileHandler&);
-    WEBCORE_EXPORT static Ref<IDBServer> create(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler&);
+    static Ref<IDBServer> create(IDBBackingStoreTemporaryFileHandler&, WTF::Function<void(bool)>&& isClosingDatabaseCallback = [](bool) { });
+    WEBCORE_EXPORT static Ref<IDBServer> create(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler&, WTF::Function<void(bool)>&& isClosingDatabaseCallback = [](bool) { });
 
     WEBCORE_EXPORT void registerConnection(IDBConnectionToClient&);
     WEBCORE_EXPORT void unregisterConnection(IDBConnectionToClient&);
@@ -109,9 +110,13 @@
     uint64_t perOriginQuota() const { return m_perOriginQuota; }
     WEBCORE_EXPORT void setPerOriginQuota(uint64_t);
 
+    void closeDatabase(UniqueIDBDatabase*);
+    void didCloseDatabase(UniqueIDBDatabase*);
+    void hysteresisUpdated(PAL::HysteresisState);
+
 private:
-    IDBServer(IDBBackingStoreTemporaryFileHandler&);
-    IDBServer(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler&);
+    IDBServer(IDBBackingStoreTemporaryFileHandler&, WTF::Function<void(bool)>&&);
+    IDBServer(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler&, WTF::Function<void(bool)>&&);
 
     UniqueIDBDatabase& getOrCreateUniqueIDBDatabase(const IDBDatabaseIdentifier&);
 
@@ -124,6 +129,7 @@
 
     HashMap<uint64_t, RefPtr<IDBConnectionToClient>> m_connectionMap;
     HashMap<IDBDatabaseIdentifier, std::unique_ptr<UniqueIDBDatabase>> m_uniqueIDBDatabaseMap;
+    HashSet<UniqueIDBDatabase*> m_uniqueIDBDatabasesInClose;
 
     HashMap<uint64_t, UniqueIDBDatabaseConnection*> m_databaseConnections;
     HashMap<IDBResourceIdentifier, UniqueIDBDatabaseTransaction*> m_transactions;
@@ -134,6 +140,9 @@
     IDBBackingStoreTemporaryFileHandler& m_backingStoreTemporaryFileHandler;
 
     uint64_t m_perOriginQuota { defaultPerOriginQuota };
+
+    WTF::Function<void(bool)> m_isClosingDatabaseCallback;
+    PAL::HysteresisActivity m_isClosingDatabaseHysteresis;
 };
 
 } // namespace IDBServer

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (242135 => 242136)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2019-02-27 18:55:07 UTC (rev 242136)
@@ -226,6 +226,7 @@
             didDeleteBackingStore(0);
         else {
             m_deleteBackingStoreInProgress = true;
+            notifyServerAboutClose(CloseState::Start);
             postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::deleteBackingStore, m_identifier));
         }
     }
@@ -278,6 +279,7 @@
     RELEASE_ASSERT(!m_owningPointerForClose);
     m_owningPointerForClose = m_server.closeAndTakeUniqueIDBDatabase(*this);
 
+    notifyServerAboutClose(CloseState::Start);
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::shutdownForClose));
 }
 
@@ -305,6 +307,7 @@
 {
     ASSERT(m_databaseReplyQueue.isEmpty());
     m_databaseReplyQueue.kill();
+    notifyServerAboutClose(CloseState::Done);
 }
 
 void UniqueIDBDatabase::didDeleteBackingStore(uint64_t deletedVersion)
@@ -340,6 +343,7 @@
 
     if (m_hardClosedForUserDelete)
         return;
+    notifyServerAboutClose(CloseState::Done);
 
     invokeOperationAndTransactionTimer();
 }
@@ -1891,6 +1895,7 @@
     if (m_owningPointerForClose)
         return;
 
+    notifyServerAboutClose(CloseState::Start);
     // Otherwise, this database is still potentially active.
     // So we'll have it own itself and then perform a clean unconditional delete on the background thread.
     m_owningPointerForClose = m_server.closeAndTakeUniqueIDBDatabase(*this);
@@ -1966,6 +1971,19 @@
         m_backingStore->setQuota(quota);
 }
 
+void UniqueIDBDatabase::notifyServerAboutClose(CloseState state)
+{
+    ASSERT(isMainThread());
+#if PLATFORM(IOS_FAMILY)
+    if (state == CloseState::Start) 
+        m_server.closeDatabase(this);
+    else
+        m_server.didCloseDatabase(this);
+#else
+    UNUSED_PARAM(state);
+#endif
+}
+
 } // namespace IDBServer
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h (242135 => 242136)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h	2019-02-27 18:55:07 UTC (rev 242136)
@@ -121,6 +121,8 @@
 
     void setQuota(uint64_t);
 private:
+    enum class CloseState { Start, Done };
+
     void handleDatabaseOperations();
     void handleCurrentOperation();
     void performCurrentOpenOperation();
@@ -225,6 +227,8 @@
     void maybeFinishHardClose();
     bool isDoneWithHardClose();
 
+    void notifyServerAboutClose(CloseState);
+
     IDBServer& m_server;
     IDBDatabaseIdentifier m_identifier;
     

Modified: trunk/Source/WebKit/ChangeLog (242135 => 242136)


--- trunk/Source/WebKit/ChangeLog	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebKit/ChangeLog	2019-02-27 18:55:07 UTC (rev 242136)
@@ -1,3 +1,21 @@
+2019-02-27  Sihui Liu  <[email protected]>
+
+        Network Process is put to suspended when holding locked IndexedDB files
+        https://bugs.webkit.org/show_bug.cgi?id=195024
+        <rdar://problem/45194169>
+
+        Reviewed by Geoffrey Garen.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::idbServer):
+        (WebKit::NetworkProcess::notifyHoldingLockedFiles):
+        * NetworkProcess/NetworkProcess.h:
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::didClose):
+        (WebKit::NetworkProcessProxy::setIsIDBDatabaseHoldingLockedFiles):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/Network/NetworkProcessProxy.messages.in:
+
 2019-02-26  Simon Fraser  <[email protected]>
 
         Have a single notion of scroll position in the scrolling tree and derive layoutViewport from it

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (242135 => 242136)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2019-02-27 18:55:07 UTC (rev 242136)
@@ -1984,7 +1984,9 @@
     // If there's not, then where did this PAL::SessionID come from?
     ASSERT(!path.isEmpty());
     
-    addResult.iterator->value = IDBServer::IDBServer::create(path, *this);
+    addResult.iterator->value = IDBServer::IDBServer::create(path, *this, [this](bool isHoldingLockedFiles) {
+        notifyHoldingLockedFiles(isHoldingLockedFiles);
+    });
     addResult.iterator->value->setPerOriginQuota(m_idbPerOriginQuota);
     return *addResult.iterator->value;
 }
@@ -2322,4 +2324,9 @@
     completionHandler();
 }
 
+void NetworkProcess::notifyHoldingLockedFiles(bool isIDBDatabaseHoldingLockedFiles)
+{
+    parentProcessConnection()->send(Messages::NetworkProcessProxy::SetIsIDBDatabaseHoldingLockedFiles(isIDBDatabaseHoldingLockedFiles), 0);
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (242135 => 242136)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2019-02-27 18:55:07 UTC (rev 242136)
@@ -389,6 +389,7 @@
     void syncAllCookies();
     void didSyncAllCookies();
 
+    void notifyHoldingLockedFiles(bool isIDBDatabaseHoldingLockedFiles);
 #if USE(SOUP)
     void setIgnoreTLSErrors(bool);
     void userPreferredLanguagesChanged(const Vector<String>&);

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp (242135 => 242136)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2019-02-27 18:55:07 UTC (rev 242136)
@@ -269,6 +269,7 @@
 #endif
 
     m_tokenForHoldingLockedFiles = nullptr;
+    m_tokenForIDBDatabaseHoldingLockedFiles = nullptr;
     
     m_syncAllCookiesToken = nullptr;
     m_syncAllCookiesCounter = 0;
@@ -981,6 +982,19 @@
     }
 }
 
+void NetworkProcessProxy::setIsIDBDatabaseHoldingLockedFiles(bool isIDBDatabaseHoldingLockedFiles)
+{
+    if (!isIDBDatabaseHoldingLockedFiles) {
+        RELEASE_LOG(ProcessSuspension, "UIProcess is releasing a background assertion because the Network process is no longer holding locked files for IDBDatabase");
+        m_tokenForIDBDatabaseHoldingLockedFiles = nullptr;
+        return;
+    }
+    if (!m_tokenForIDBDatabaseHoldingLockedFiles) {
+        RELEASE_LOG(ProcessSuspension, "UIProcess is taking a background assertion because the Network process is holding locked files for IDBDatabase");
+        m_tokenForIDBDatabaseHoldingLockedFiles = m_throttler.backgroundActivityToken();
+    }
+}
+
 void NetworkProcessProxy::syncAllCookies()
 {
     send(Messages::NetworkProcess::SyncAllCookies(), 0);

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h (242135 => 242136)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2019-02-27 18:55:07 UTC (rev 242136)
@@ -136,7 +136,8 @@
     void sendProcessDidTransitionToBackground();
 
     void setIsHoldingLockedFiles(bool);
-    
+    void setIsIDBDatabaseHoldingLockedFiles(bool);
+
     void syncAllCookies();
     void didSyncAllCookies();
 
@@ -230,6 +231,7 @@
 #endif
     ProcessThrottler m_throttler;
     ProcessThrottler::BackgroundActivityToken m_tokenForHoldingLockedFiles;
+    ProcessThrottler::BackgroundActivityToken m_tokenForIDBDatabaseHoldingLockedFiles;
     ProcessThrottler::BackgroundActivityToken m_syncAllCookiesToken;
     
     unsigned m_syncAllCookiesCounter { 0 };

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in (242135 => 242136)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in	2019-02-27 18:49:24 UTC (rev 242135)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in	2019-02-27 18:55:07 UTC (rev 242136)
@@ -33,6 +33,7 @@
 
     ProcessReadyToSuspend()
     SetIsHoldingLockedFiles(bool isHoldingLockedFiles)
+    SetIsIDBDatabaseHoldingLockedFiles(bool isIDBDatabaseHoldingLockedFiles)
 
     # Diagnostic messages logging
     LogDiagnosticMessage(uint64_t pageID, String message, String description, enum:bool WebCore::ShouldSample shouldSample)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to