Changeset 244687 in webkit


Ignore:
Timestamp:
Apr 26, 2019 9:08:40 AM (5 years ago)
Author:
sihui_liu@apple.com
Message:

Stop IDB transactions to release locked database files when network process is ready to suspend
https://bugs.webkit.org/show_bug.cgi?id=196372
<rdar://problem/48930116>

Reviewed by Brady Eidson.

Source/WebCore:

Suspend IDB database thread and finish ongoing IDB transactions on the main thread before suspending network
process.

API test: IndexedDB.IndexedDBSuspendImminently

  • Modules/indexeddb/server/IDBBackingStore.h:
  • Modules/indexeddb/server/IDBServer.cpp:

(WebCore::IDBServer::IDBServer::tryStop):
(WebCore::IDBServer::IDBServer::resume):

  • Modules/indexeddb/server/IDBServer.h:
  • Modules/indexeddb/server/MemoryIDBBackingStore.h:
  • Modules/indexeddb/server/SQLiteIDBBackingStore.cpp: Remove some error log messages, because now we may try

performing database operations without an active transaction if the transaction is finished on the main thread.
(WebCore::IDBServer::SQLiteIDBBackingStore::createObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::renameObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::clearObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::renameIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::keyExistsInObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteRange):
(WebCore::IDBServer::SQLiteIDBBackingStore::addRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getAllObjectStoreRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getAllIndexRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getCount):
(WebCore::IDBServer::SQLiteIDBBackingStore::generateKeyNumber):
(WebCore::IDBServer::SQLiteIDBBackingStore::revertGeneratedKeyNumber):
(WebCore::IDBServer::SQLiteIDBBackingStore::maybeUpdateKeyGeneratorNumber):
(WebCore::IDBServer::SQLiteIDBBackingStore::openCursor):
(WebCore::IDBServer::SQLiteIDBBackingStore::iterateCursor):
(WebCore::IDBServer::SQLiteIDBBackingStore::hasTransaction const):

  • Modules/indexeddb/server/SQLiteIDBBackingStore.h:
  • Modules/indexeddb/server/UniqueIDBDatabase.cpp:

(WebCore::IDBServer::UniqueIDBDatabase::prepareToFinishTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::commitTransactionAfterQuotaCheck):
(WebCore::IDBServer::UniqueIDBDatabase::didPerformCommitTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::abortTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::didPerformAbortTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::abortTransactionOnMainThread):
(WebCore::IDBServer::UniqueIDBDatabase::commitTransactionOnMainThread):
(WebCore::IDBServer::UniqueIDBDatabase::finishActiveTransactions):

  • Modules/indexeddb/server/UniqueIDBDatabase.h:
  • Modules/indexeddb/server/UniqueIDBDatabaseTransaction.h:

(WebCore::IDBServer::UniqueIDBDatabaseTransaction::setState):
(WebCore::IDBServer::UniqueIDBDatabaseTransaction::state const):
(WebCore::IDBServer::UniqueIDBDatabaseTransaction::setResult):
(WebCore::IDBServer::UniqueIDBDatabaseTransaction::result const):

  • platform/sql/SQLiteDatabaseTracker.cpp:

(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress):

  • platform/sql/SQLiteDatabaseTracker.h:

Source/WebKit:

  • NetworkProcess/NetworkProcess.cpp:

(WebKit::NetworkProcess::processWillSuspendImminently):
(WebKit::NetworkProcess::prepareToSuspend):
(WebKit::NetworkProcess::resume):

Source/WTF:

Provide a method to suspend the thread and block main thread until the thread is suspended.

  • wtf/CrossThreadTaskHandler.cpp:

(WTF::CrossThreadTaskHandler::taskRunLoop):
(WTF::CrossThreadTaskHandler::suspendAndWait):
(WTF::CrossThreadTaskHandler::resume):

  • wtf/CrossThreadTaskHandler.h:

Tools:

  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WebKitCocoa/IndexedDBSuspendImminently.html: Added.
  • TestWebKitAPI/Tests/WebKitCocoa/IndexedDBSuspendImminently.mm: Added.

(-[IndexedDBSuspendImminentlyMessageHandler userContentController:didReceiveScriptMessage:]):
(runTestAndCheckResult):
(keepNetworkProcessActive):
(TEST):

Location:
trunk
Files:
2 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r244676 r244687  
     12019-04-26  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Stop IDB transactions to release locked database files when network process is ready to suspend
     4        https://bugs.webkit.org/show_bug.cgi?id=196372
     5        <rdar://problem/48930116>
     6
     7        Reviewed by Brady Eidson.
     8
     9        Provide a method to suspend the thread and block main thread until the thread is suspended.
     10
     11        * wtf/CrossThreadTaskHandler.cpp:
     12        (WTF::CrossThreadTaskHandler::taskRunLoop):
     13        (WTF::CrossThreadTaskHandler::suspendAndWait):
     14        (WTF::CrossThreadTaskHandler::resume):
     15        * wtf/CrossThreadTaskHandler.h:
     16
    1172019-04-25  Fujii Hironori  <Hironori.Fujii@sony.com>
    218
  • trunk/Source/WTF/wtf/CrossThreadTaskHandler.cpp

    r237099 r244687  
    6969    }
    7070
    71     while (!m_taskQueue.isKilled())
     71    while (!m_taskQueue.isKilled()) {
    7272        m_taskQueue.waitForMessage().performTask();
     73
     74        Locker<Lock> shouldSuspendLocker(m_shouldSuspendLock);
     75        while (m_shouldSuspend) {
     76            m_suspendedLock.lock();
     77            if (!m_suspended) {
     78                m_suspended = true;
     79                m_suspendedCondition.notifyOne();
     80            }
     81            m_suspendedLock.unlock();
     82            m_shouldSuspendCondition.wait(m_shouldSuspendLock);
     83        }
     84    }
    7385}
    7486
     
    8496}
    8597
     98void CrossThreadTaskHandler::suspendAndWait()
     99{
     100    ASSERT(isMainThread());
     101    {
     102        Locker<Lock> locker(m_shouldSuspendLock);
     103        m_shouldSuspend = true;
     104    }
     105
     106    // Post an empty task to ensure database thread knows m_shouldSuspend and sets m_suspended.
     107    postTask(CrossThreadTask([]() { }));
     108
     109    Locker<Lock> locker(m_suspendedLock);
     110    while (!m_suspended)
     111        m_suspendedCondition.wait(m_suspendedLock);
     112}
     113
     114void CrossThreadTaskHandler::resume()
     115{
     116    ASSERT(isMainThread());
     117    Locker<Lock> locker(m_shouldSuspendLock);
     118    if (m_shouldSuspend) {
     119        m_suspendedLock.lock();
     120        if (m_suspended)
     121            m_suspended = false;
     122        m_suspendedLock.unlock();
     123        m_shouldSuspend = false;
     124        m_shouldSuspendCondition.notifyOne();
     125    }
     126}
    86127
    87128} // namespace WTF
  • trunk/Source/WTF/wtf/CrossThreadTaskHandler.h

    r225998 r244687  
    4545    WTF_EXPORT_PRIVATE void postTask(CrossThreadTask&&);
    4646    WTF_EXPORT_PRIVATE void postTaskReply(CrossThreadTask&&);
     47    WTF_EXPORT_PRIVATE void suspendAndWait();
     48    WTF_EXPORT_PRIVATE void resume();
    4749
    4850private:
     
    5456    bool m_mainThreadReplyScheduled { false };
    5557
     58    bool m_shouldSuspend { false };
     59    Condition m_shouldSuspendCondition;
     60    Lock m_shouldSuspendLock;
     61   
     62    bool m_suspended { false };
     63    Condition m_suspendedCondition;
     64    Lock m_suspendedLock;
     65
    5666    CrossThreadQueue<CrossThreadTask> m_taskQueue;
    5767    CrossThreadQueue<CrossThreadTask> m_taskReplyQueue;
  • trunk/Source/WebCore/ChangeLog

    r244684 r244687  
     12019-04-26  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Stop IDB transactions to release locked database files when network process is ready to suspend
     4        https://bugs.webkit.org/show_bug.cgi?id=196372
     5        <rdar://problem/48930116>
     6
     7        Reviewed by Brady Eidson.
     8
     9        Suspend IDB database thread and finish ongoing IDB transactions on the main thread before suspending network
     10        process.
     11
     12        API test: IndexedDB.IndexedDBSuspendImminently
     13
     14        * Modules/indexeddb/server/IDBBackingStore.h:
     15        * Modules/indexeddb/server/IDBServer.cpp:
     16        (WebCore::IDBServer::IDBServer::tryStop):
     17        (WebCore::IDBServer::IDBServer::resume):
     18        * Modules/indexeddb/server/IDBServer.h:
     19        * Modules/indexeddb/server/MemoryIDBBackingStore.h:
     20        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp: Remove some error log messages, because now we may try
     21        performing database operations without an active transaction if the transaction is finished on the main thread.
     22        (WebCore::IDBServer::SQLiteIDBBackingStore::createObjectStore):
     23        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteObjectStore):
     24        (WebCore::IDBServer::SQLiteIDBBackingStore::renameObjectStore):
     25        (WebCore::IDBServer::SQLiteIDBBackingStore::clearObjectStore):
     26        (WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
     27        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteIndex):
     28        (WebCore::IDBServer::SQLiteIDBBackingStore::renameIndex):
     29        (WebCore::IDBServer::SQLiteIDBBackingStore::keyExistsInObjectStore):
     30        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteRange):
     31        (WebCore::IDBServer::SQLiteIDBBackingStore::addRecord):
     32        (WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
     33        (WebCore::IDBServer::SQLiteIDBBackingStore::getAllObjectStoreRecords):
     34        (WebCore::IDBServer::SQLiteIDBBackingStore::getAllIndexRecords):
     35        (WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
     36        (WebCore::IDBServer::SQLiteIDBBackingStore::getCount):
     37        (WebCore::IDBServer::SQLiteIDBBackingStore::generateKeyNumber):
     38        (WebCore::IDBServer::SQLiteIDBBackingStore::revertGeneratedKeyNumber):
     39        (WebCore::IDBServer::SQLiteIDBBackingStore::maybeUpdateKeyGeneratorNumber):
     40        (WebCore::IDBServer::SQLiteIDBBackingStore::openCursor):
     41        (WebCore::IDBServer::SQLiteIDBBackingStore::iterateCursor):
     42        (WebCore::IDBServer::SQLiteIDBBackingStore::hasTransaction const):
     43        * Modules/indexeddb/server/SQLiteIDBBackingStore.h:
     44        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
     45        (WebCore::IDBServer::UniqueIDBDatabase::prepareToFinishTransaction):
     46        (WebCore::IDBServer::UniqueIDBDatabase::commitTransactionAfterQuotaCheck):
     47        (WebCore::IDBServer::UniqueIDBDatabase::didPerformCommitTransaction):
     48        (WebCore::IDBServer::UniqueIDBDatabase::abortTransaction):
     49        (WebCore::IDBServer::UniqueIDBDatabase::didPerformAbortTransaction):
     50        (WebCore::IDBServer::UniqueIDBDatabase::abortTransactionOnMainThread):
     51        (WebCore::IDBServer::UniqueIDBDatabase::commitTransactionOnMainThread):
     52        (WebCore::IDBServer::UniqueIDBDatabase::finishActiveTransactions):
     53        * Modules/indexeddb/server/UniqueIDBDatabase.h:
     54        * Modules/indexeddb/server/UniqueIDBDatabaseTransaction.h:
     55        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::setState):
     56        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::state const):
     57        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::setResult):
     58        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::result const):
     59        * platform/sql/SQLiteDatabaseTracker.cpp:
     60        (WebCore::SQLiteDatabaseTracker::hasTransactionInProgress):
     61        * platform/sql/SQLiteDatabaseTracker.h:
     62
    1632019-04-26  Takashi Komori  <Takashi.Komori@sony.com>
    264
  • trunk/Source/WebCore/Modules/indexeddb/server/IDBBackingStore.h

    r242911 r244687  
    102102    virtual uint64_t databasesSizeForOrigin() const = 0;
    103103    virtual void setQuota(uint64_t) = 0;
     104
     105    virtual bool hasTransaction(const IDBResourceIdentifier&) const = 0;
    104106protected:
    105107    IDBBackingStore() { RELEASE_ASSERT(!isMainThread()); }
  • trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp

    r244077 r244687  
    3434#include "MemoryIDBBackingStore.h"
    3535#include "SQLiteDatabase.h"
     36#include "SQLiteDatabaseTracker.h"
    3637#include "SQLiteFileSystem.h"
    3738#include "SQLiteIDBBackingStore.h"
     
    829830}
    830831
     832void IDBServer::tryStop(ShouldForceStop shouldForceStop)
     833{
     834    // Only stop non-ephemeral IDBServers that can hold locked database files.
     835    if (m_sessionID.isEphemeral())
     836        return;
     837
     838    suspendAndWait();
     839    if (shouldForceStop == ShouldForceStop::No && SQLiteDatabaseTracker::hasTransactionInProgress()) {
     840        CrossThreadTaskHandler::resume();
     841        return;
     842    }
     843
     844    for (auto& database : m_uniqueIDBDatabaseMap.values())
     845        database->finishActiveTransactions();
     846}
     847
     848void IDBServer::resume()
     849{
     850    if (m_sessionID.isEphemeral())
     851        return;
     852
     853    CrossThreadTaskHandler::resume();
     854}
     855
    831856} // namespace IDBServer
    832857} // namespace WebCore
  • trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h

    r244077 r244687  
    5959class IDBBackingStoreTemporaryFileHandler;
    6060
     61enum class ShouldForceStop : bool { No, Yes };
     62
    6163class IDBServer : public RefCounted<IDBServer>, public CrossThreadTaskHandler, public CanMakeWeakPtr<IDBServer> {
    6264public:
     
    125127    void initializeQuotaUser(const ClientOrigin& origin) { ensureQuotaUser(origin); }
    126128
     129    WEBCORE_EXPORT void tryStop(ShouldForceStop);
     130    WEBCORE_EXPORT void resume();
     131
    127132private:
    128133    IDBServer(PAL::SessionID, IDBBackingStoreTemporaryFileHandler&, QuotaManagerGetter&&);
  • trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.h

    r242911 r244687  
    8686    void restoreObjectStoreForVersionChangeAbort(Ref<MemoryObjectStore>&&);
    8787
     88    bool hasTransaction(const IDBResourceIdentifier& identifier) const final { return m_transactions.contains(identifier); }
     89
    8890private:
    8991    RefPtr<MemoryObjectStore> takeObjectStoreByIdentifier(uint64_t identifier);
  • trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp

    r244436 r244687  
    10061006
    10071007    auto* transaction = m_transactions.get(transactionIdentifier);
    1008     if (!transaction || !transaction->inProgress()) {
    1009         LOG_ERROR("Attempt to create an object store without an in-progress transaction");
     1008    if (!transaction || !transaction->inProgress())
    10101009        return IDBError { UnknownError, "Attempt to create an object store without an in-progress transaction"_s };
    1011     }
     1010
    10121011    if (transaction->mode() != IDBTransactionMode::Versionchange) {
    10131012        LOG_ERROR("Attempt to create an object store in a non-version-change transaction");
     
    10621061
    10631062    auto* transaction = m_transactions.get(transactionIdentifier);
    1064     if (!transaction || !transaction->inProgress()) {
    1065         LOG_ERROR("Attempt to delete an object store without an in-progress transaction");
     1063    if (!transaction || !transaction->inProgress())
    10661064        return IDBError { UnknownError, "Attempt to delete an object store without an in-progress transaction"_s };
    1067     }
     1065
    10681066    if (transaction->mode() != IDBTransactionMode::Versionchange) {
    10691067        LOG_ERROR("Attempt to delete an object store in a non-version-change transaction");
     
    11541152
    11551153    auto* transaction = m_transactions.get(transactionIdentifier);
    1156     if (!transaction || !transaction->inProgress()) {
    1157         LOG_ERROR("Attempt to rename an object store without an in-progress transaction");
     1154    if (!transaction || !transaction->inProgress())
    11581155        return IDBError { UnknownError, "Attempt to rename an object store without an in-progress transaction"_s };
    1159     }
     1156
    11601157    if (transaction->mode() != IDBTransactionMode::Versionchange) {
    11611158        LOG_ERROR("Attempt to rename an object store in a non-version-change transaction");
     
    11891186
    11901187    auto* transaction = m_transactions.get(transactionIdentifier);
    1191     if (!transaction || !transaction->inProgress()) {
    1192         LOG_ERROR("Attempt to clear an object store without an in-progress transaction");
     1188    if (!transaction || !transaction->inProgress())
    11931189        return IDBError { UnknownError, "Attempt to clear an object store without an in-progress transaction"_s };
    1194     }
     1190
    11951191    if (transaction->mode() == IDBTransactionMode::Readonly) {
    11961192        LOG_ERROR("Attempt to clear an object store in a read-only transaction");
     
    12301226
    12311227    auto* transaction = m_transactions.get(transactionIdentifier);
    1232     if (!transaction || !transaction->inProgress()) {
    1233         LOG_ERROR("Attempt to create an index without an in-progress transaction");
     1228    if (!transaction || !transaction->inProgress())
    12341229        return IDBError { UnknownError, "Attempt to create an index without an in-progress transaction"_s };
    1235     }
     1230
    12361231    if (transaction->mode() != IDBTransactionMode::Versionchange) {
    12371232        LOG_ERROR("Attempt to create an index in a non-version-change transaction");
     
    14231418
    14241419    auto* transaction = m_transactions.get(transactionIdentifier);
    1425     if (!transaction || !transaction->inProgress()) {
    1426         LOG_ERROR("Attempt to delete index without an in-progress transaction");
     1420    if (!transaction || !transaction->inProgress())
    14271421        return IDBError { UnknownError, "Attempt to delete index without an in-progress transaction"_s };
    1428     }
    14291422
    14301423    if (transaction->mode() != IDBTransactionMode::Versionchange) {
     
    14781471
    14791472    auto* transaction = m_transactions.get(transactionIdentifier);
    1480     if (!transaction || !transaction->inProgress()) {
    1481         LOG_ERROR("Attempt to rename an index without an in-progress transaction");
     1473    if (!transaction || !transaction->inProgress())
    14821474        return IDBError { UnknownError, "Attempt to rename an index without an in-progress transaction"_s };
    1483     }
    14841475
    14851476    if (transaction->mode() != IDBTransactionMode::Versionchange) {
     
    15171508
    15181509    auto* transaction = m_transactions.get(transactionIdentifier);
    1519     if (!transaction || !transaction->inProgress()) {
    1520         LOG_ERROR("Attempt to see if key exists in objectstore without an in-progress transaction");
     1510    if (!transaction || !transaction->inProgress())
    15211511        return IDBError { UnknownError, "Attempt to see if key exists in objectstore without an in-progress transaction"_s };
    1522     }
    15231512
    15241513    RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
     
    16921681
    16931682    auto* transaction = m_transactions.get(transactionIdentifier);
    1694     if (!transaction || !transaction->inProgress()) {
    1695         LOG_ERROR("Attempt to delete range from database without an in-progress transaction");
     1683    if (!transaction || !transaction->inProgress())
    16961684        return IDBError { UnknownError, "Attempt to delete range from database without an in-progress transaction"_s };
    1697     }
     1685
    16981686    if (transaction->mode() == IDBTransactionMode::Readonly) {
    16991687        LOG_ERROR("Attempt to delete records from an object store in a read-only transaction");
     
    18151803
    18161804    auto* transaction = m_transactions.get(transactionIdentifier);
    1817     if (!transaction || !transaction->inProgress()) {
    1818         LOG_ERROR("Attempt to store a record in an object store without an in-progress transaction");
     1805    if (!transaction || !transaction->inProgress())
    18191806        return IDBError { UnknownError, "Attempt to store a record in an object store without an in-progress transaction"_s };
    1820     }
     1807
    18211808    if (transaction->mode() == IDBTransactionMode::Readonly) {
    18221809        LOG_ERROR("Attempt to store a record in an object store in a read-only transaction");
     
    19841971
    19851972    auto* transaction = m_transactions.get(transactionIdentifier);
    1986     if (!transaction || !transaction->inProgress()) {
    1987         LOG_ERROR("Attempt to get a record from database without an in-progress transaction");
     1973    if (!transaction || !transaction->inProgress())
    19881974        return IDBError { UnknownError, "Attempt to get a record from database without an in-progress transaction"_s };
    1989     }
    19901975
    19911976    auto key = keyRange.lowerKey;
     
    21612146
    21622147    auto* transaction = m_transactions.get(transactionIdentifier);
    2163     if (!transaction || !transaction->inProgress()) {
    2164         LOG_ERROR("Attempt to get records from database without an in-progress transaction");
     2148    if (!transaction || !transaction->inProgress())
    21652149        return IDBError { UnknownError, "Attempt to get records from database without an in-progress transaction"_s };
    2166     }
    21672150
    21682151    auto key = getAllRecordsData.keyRangeData.lowerKey;
     
    22572240
    22582241    auto* transaction = m_transactions.get(transactionIdentifier);
    2259     if (!transaction || !transaction->inProgress()) {
    2260         LOG_ERROR("Attempt to get all index records from database without an in-progress transaction");
     2242    if (!transaction || !transaction->inProgress())
    22612243        return IDBError { UnknownError, "Attempt to get all index records from database without an in-progress transaction"_s };
    2262     }
    22632244
    22642245    auto cursor = transaction->maybeOpenBackingStoreCursor(getAllRecordsData.objectStoreIdentifier, getAllRecordsData.indexIdentifier, getAllRecordsData.keyRangeData);
     
    23072288
    23082289    auto* transaction = m_transactions.get(transactionIdentifier);
    2309     if (!transaction || !transaction->inProgress()) {
    2310         LOG_ERROR("Attempt to get an index record from database without an in-progress transaction");
     2290    if (!transaction || !transaction->inProgress())
    23112291        return IDBError { UnknownError, "Attempt to get an index record from database without an in-progress transaction"_s };
    2312     }
    23132292
    23142293    if (range.isExactlyOneKey())
     
    24132392
    24142393    auto* transaction = m_transactions.get(transactionIdentifier);
    2415     if (!transaction || !transaction->inProgress()) {
    2416         LOG_ERROR("Attempt to get count from database without an in-progress transaction");
     2394    if (!transaction || !transaction->inProgress())
    24172395        return IDBError { UnknownError, "Attempt to get count from database without an in-progress transaction"_s };
    2418     }
    24192396
    24202397    auto cursor = transaction->maybeOpenBackingStoreCursor(objectStoreIdentifier, indexIdentifier, range);
     
    24762453
    24772454    auto* transaction = m_transactions.get(transactionIdentifier);
    2478     if (!transaction || !transaction->inProgress()) {
    2479         LOG_ERROR("Attempt to generate key in database without an in-progress transaction");
     2455    if (!transaction || !transaction->inProgress())
    24802456        return IDBError { UnknownError, "Attempt to generate key in database without an in-progress transaction"_s };
    2481     }
     2457
    24822458    if (transaction->mode() == IDBTransactionMode::Readonly) {
    24832459        LOG_ERROR("Attempt to generate key in a read-only transaction");
     
    25052481
    25062482    auto* transaction = m_transactions.get(transactionIdentifier);
    2507     if (!transaction || !transaction->inProgress()) {
    2508         LOG_ERROR("Attempt to revert key generator value in database without an in-progress transaction");
     2483    if (!transaction || !transaction->inProgress())
    25092484        return IDBError { UnknownError, "Attempt to revert key generator value in database without an in-progress transaction"_s };
    2510     }
     2485
    25112486    if (transaction->mode() == IDBTransactionMode::Readonly) {
    25122487        LOG_ERROR("Attempt to revert key generator value in a read-only transaction");
     
    25262501
    25272502    auto* transaction = m_transactions.get(transactionIdentifier);
    2528     if (!transaction || !transaction->inProgress()) {
    2529         LOG_ERROR("Attempt to update key generator value in database without an in-progress transaction");
     2503    if (!transaction || !transaction->inProgress())
    25302504        return IDBError { UnknownError, "Attempt to update key generator value in database without an in-progress transaction"_s };
    2531     }
     2505
    25322506    if (transaction->mode() == IDBTransactionMode::Readonly) {
    25332507        LOG_ERROR("Attempt to update key generator value in a read-only transaction");
     
    25522526
    25532527    auto* transaction = m_transactions.get(transactionIdentifier);
    2554     if (!transaction || !transaction->inProgress()) {
    2555         LOG_ERROR("Attempt to open a cursor in database without an in-progress transaction");
     2528    if (!transaction || !transaction->inProgress())
    25562529        return IDBError { UnknownError, "Attempt to open a cursor in database without an in-progress transaction"_s };
    2557     }
    25582530
    25592531    auto* cursor = transaction->maybeOpenCursor(info);
     
    25862558    ASSERT_UNUSED(transactionIdentifier, cursor->transaction()->transactionIdentifier() == transactionIdentifier);
    25872559
    2588     if (!cursor->transaction() || !cursor->transaction()->inProgress()) {
    2589         LOG_ERROR("Attempt to iterate a cursor without an in-progress transaction");
     2560    if (!cursor->transaction() || !cursor->transaction()->inProgress())
    25902561        return IDBError { UnknownError, "Attempt to iterate a cursor without an in-progress transaction"_s };
    2591     }
    25922562
    25932563    auto key = data.keyData;
     
    27192689}
    27202690
     2691bool SQLiteIDBBackingStore::hasTransaction(const IDBResourceIdentifier& transactionIdentifier) const
     2692{
     2693    ASSERT(isMainThread());
     2694    return m_transactions.contains(transactionIdentifier);
     2695}
     2696
    27212697} // namespace IDBServer
    27222698} // namespace WebCore
  • trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h

    r243019 r244687  
    101101    static String databaseNameFromFile(const String&);
    102102
     103    bool hasTransaction(const IDBResourceIdentifier&) const final;
    103104private:
    104105    String filenameForDatabaseName() const;
  • trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp

    r244436 r244687  
    15681568}
    15691569
    1570 bool UniqueIDBDatabase::prepareToFinishTransaction(UniqueIDBDatabaseTransaction& transaction)
     1570bool UniqueIDBDatabase::prepareToFinishTransaction(UniqueIDBDatabaseTransaction& transaction, UniqueIDBDatabaseTransaction::State state)
    15711571{
    15721572    auto takenTransaction = m_inProgressTransactions.take(transaction.info().identifier());
     
    15751575
    15761576    ASSERT(!m_finishingTransactions.contains(transaction.info().identifier()));
     1577    takenTransaction->setState(state);
    15771578    m_finishingTransactions.set(transaction.info().identifier(), WTFMove(takenTransaction));
    15781579
     
    16021603        return;
    16031604
    1604     if (!prepareToFinishTransaction(transaction)) {
     1605    if (!prepareToFinishTransaction(transaction, UniqueIDBDatabaseTransaction::State::Committing)) {
    16051606        if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
    16061607            // This database connection is closing or has already closed, so there is no point in messaging back to it about the commit failing.
     
    16301631    LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCommitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
    16311632
    1632     performErrorCallback(callbackIdentifier, error);
     1633    IDBError result = error;
     1634    auto transaction = m_finishingTransactions.get(transactionIdentifier);
     1635    switch (transaction->state()) {
     1636    case UniqueIDBDatabaseTransaction::State::Aborted:
     1637        result = IDBError { UnknownError, "Transaction is already aborted"_s };
     1638        break;
     1639    case UniqueIDBDatabaseTransaction::State::Committed:
     1640        result = transaction->result();
     1641        break;
     1642    case UniqueIDBDatabaseTransaction::State::Committing:
     1643        break;
     1644    case UniqueIDBDatabaseTransaction::State::Running:
     1645    case UniqueIDBDatabaseTransaction::State::Aborting:
     1646        ASSERT_NOT_REACHED();
     1647    }
     1648
     1649    performErrorCallback(callbackIdentifier, result);
    16331650
    16341651    transactionCompleted(m_finishingTransactions.take(transactionIdentifier));
     
    16571674        return;
    16581675
    1659     if (!prepareToFinishTransaction(transaction)) {
     1676    if (!prepareToFinishTransaction(transaction, UniqueIDBDatabaseTransaction::State::Aborting)) {
    16601677        if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
    16611678            // This database connection is closing or has already closed, so there is no point in messaging back to it about the abort failing.
     
    17141731    }
    17151732
    1716     performErrorCallback(callbackIdentifier, error);
     1733    IDBError result = transaction->state() == UniqueIDBDatabaseTransaction::State::Aborted ? transaction->result() : error;
     1734    performErrorCallback(callbackIdentifier, result);
    17171735
    17181736    transactionCompleted(WTFMove(transaction));
     
    22782296}
    22792297
     2298void UniqueIDBDatabase::abortTransactionOnMainThread(UniqueIDBDatabaseTransaction& transaction)
     2299{
     2300    transaction.setResult(m_backingStore->abortTransaction(transaction.info().identifier()));
     2301    transaction.setState(UniqueIDBDatabaseTransaction::State::Aborted);
     2302}
     2303
     2304void UniqueIDBDatabase::commitTransactionOnMainThread(UniqueIDBDatabaseTransaction& transaction)
     2305{
     2306    transaction.setResult(m_backingStore->commitTransaction(transaction.info().identifier()));
     2307    transaction.setState(UniqueIDBDatabaseTransaction::State::Committed);
     2308}
     2309
     2310void UniqueIDBDatabase::finishActiveTransactions()
     2311{
     2312    ASSERT(isMainThread());
     2313
     2314    for (auto& identifier : copyToVector(m_inProgressTransactions.keys())) {
     2315        auto transaction = m_inProgressTransactions.get(identifier);
     2316        abortTransactionOnMainThread(*transaction);
     2317    }
     2318
     2319    for (auto& identifier : copyToVector(m_finishingTransactions.keys())) {
     2320        if (!m_backingStore->hasTransaction(identifier))
     2321            continue;
     2322
     2323        auto transaction = m_finishingTransactions.get(identifier);
     2324        switch (transaction->state()) {
     2325        case UniqueIDBDatabaseTransaction::State::Aborting:
     2326            abortTransactionOnMainThread(*transaction);
     2327            break;
     2328        case UniqueIDBDatabaseTransaction::State::Committing:
     2329            commitTransactionOnMainThread(*transaction);
     2330            break;
     2331        case UniqueIDBDatabaseTransaction::State::Running:
     2332        case UniqueIDBDatabaseTransaction::State::Aborted:
     2333        case UniqueIDBDatabaseTransaction::State::Committed:
     2334            ASSERT_NOT_REACHED();
     2335        }
     2336    }
     2337}
     2338
    22802339} // namespace IDBServer
    22812340} // namespace WebCore
  • trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h

    r244077 r244687  
    128128    void setQuota(uint64_t);
    129129
     130    void finishActiveTransactions();
     131
    130132private:
    131133    void handleDatabaseOperations();
     
    238240    RefPtr<UniqueIDBDatabaseTransaction> takeNextRunnableTransaction(bool& hadDeferredTransactions);
    239241
    240     bool prepareToFinishTransaction(UniqueIDBDatabaseTransaction&);
     242    bool prepareToFinishTransaction(UniqueIDBDatabaseTransaction&, UniqueIDBDatabaseTransaction::State);
     243    void abortTransactionOnMainThread(UniqueIDBDatabaseTransaction&);
     244    void commitTransactionOnMainThread(UniqueIDBDatabaseTransaction&);
    241245   
    242246    void clearStalePendingOpenDBRequests();
  • trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseTransaction.h

    r244115 r244687  
    5757class UniqueIDBDatabaseTransaction : public RefCounted<UniqueIDBDatabaseTransaction> {
    5858public:
     59    enum class State { Running, Aborting, Committing, Aborted, Committed };
     60
    5961    static Ref<UniqueIDBDatabaseTransaction> create(UniqueIDBDatabaseConnection&, const IDBTransactionInfo&);
    6062
     
    9193    const Vector<uint64_t>& objectStoreIdentifiers();
    9294
     95    void setState(State state) { m_state = state; }
     96    State state() const { return m_state; }
     97    void setResult(const IDBError& error) { m_result = error; }
     98    const IDBError& result() const { return m_result; }
     99
    93100private:
    94101    UniqueIDBDatabaseTransaction(UniqueIDBDatabaseConnection&, const IDBTransactionInfo&);
     
    101108
    102109    Vector<uint64_t> m_objectStoreIdentifiers;
     110
     111    State m_state { State::Running };
     112    IDBError m_result;
    103113};
    104114
  • trunk/Source/WebCore/platform/sql/SQLiteDatabaseTracker.cpp

    r243939 r244687  
    6969}
    7070
    71 #if !ASSERT_DISABLED
    7271bool hasTransactionInProgress()
    7372{
     
    7574    return !s_staticSQLiteDatabaseTrackerClient || s_transactionInProgressCounter > 0;
    7675}
    77 #endif
    7876
    7977} // namespace SQLiteDatabaseTracker
  • trunk/Source/WebCore/platform/sql/SQLiteDatabaseTracker.h

    r179929 r244687  
    3838WEBCORE_EXPORT void setClient(SQLiteDatabaseTrackerClient*);
    3939
    40 #if !ASSERT_DISABLED
    4140WEBCORE_EXPORT bool hasTransactionInProgress();
    42 #endif
    4341
    4442};
  • trunk/Source/WebKit/ChangeLog

    r244683 r244687  
     12019-04-26  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Stop IDB transactions to release locked database files when network process is ready to suspend
     4        https://bugs.webkit.org/show_bug.cgi?id=196372
     5        <rdar://problem/48930116>
     6
     7        Reviewed by Brady Eidson.
     8
     9        * NetworkProcess/NetworkProcess.cpp:
     10        (WebKit::NetworkProcess::processWillSuspendImminently):
     11        (WebKit::NetworkProcess::prepareToSuspend):
     12        (WebKit::NetworkProcess::resume):
     13
    1142019-04-25  Myles C. Maxfield  <mmaxfield@apple.com>
    215
  • trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp

    r244659 r244687  
    20082008void NetworkProcess::processWillSuspendImminently(CompletionHandler<void(bool)>&& completionHandler)
    20092009{
     2010#if PLATFORM(IOS_FAMILY) && ENABLE(INDEXED_DATABASE)
     2011    for (auto& server : m_idbServers.values())
     2012        server->tryStop(IDBServer::ShouldForceStop::Yes);
     2013#endif
    20102014    actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::No);
    20112015    completionHandler(true);
     
    20152019{
    20162020    RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::prepareToSuspend()", this);
     2021
     2022#if PLATFORM(IOS_FAMILY) && ENABLE(INDEXED_DATABASE)
     2023    for (auto& server : m_idbServers.values())
     2024        server->tryStop(IDBServer::ShouldForceStop::No);
     2025#endif
    20172026    actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::Yes);
    20182027}
     
    20532062    for (auto& server : m_swServers.values())
    20542063        server->endSuspension();
     2064#endif
     2065#if PLATFORM(IOS_FAMILY) && ENABLE(INDEXED_DATABASE)
     2066    for (auto& server : m_idbServers.values())
     2067        server->resume();
    20552068#endif
    20562069}
  • trunk/Tools/ChangeLog

    r244675 r244687  
     12019-04-26  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Stop IDB transactions to release locked database files when network process is ready to suspend
     4        https://bugs.webkit.org/show_bug.cgi?id=196372
     5        <rdar://problem/48930116>
     6
     7        Reviewed by Brady Eidson.
     8
     9        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     10        * TestWebKitAPI/Tests/WebKitCocoa/IndexedDBSuspendImminently.html: Added.
     11        * TestWebKitAPI/Tests/WebKitCocoa/IndexedDBSuspendImminently.mm: Added.
     12        (-[IndexedDBSuspendImminentlyMessageHandler userContentController:didReceiveScriptMessage:]):
     13        (runTestAndCheckResult):
     14        (keepNetworkProcessActive):
     15        (TEST):
     16
    1172019-04-25  Simon Fraser  <simon.fraser@apple.com>
    218
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r244644 r244687  
    784784                C9E6DD351EA97D0800DD78AA /* FirstResponderSuppression.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9E6DD311EA972D800DD78AA /* FirstResponderSuppression.mm */; };
    785785                C9E8EE7521DED94300797765 /* long-test.mp4 in Copy Resources */ = {isa = PBXBuildFile; fileRef = C9E8EE7421DED91E00797765 /* long-test.mp4 */; };
     786                CA2879DB226E69A5001026F5 /* IndexedDBSuspendImminently.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA2879DA226E6986001026F5 /* IndexedDBSuspendImminently.mm */; };
     787                CA2879DC226E69B6001026F5 /* IndexedDBSuspendImminently.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CA2879D9226E6978001026F5 /* IndexedDBSuspendImminently.html */; };
    786788                CA38459620AE17A900990D3B /* LocalStorageDatabaseTracker.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA38459520AE012E00990D3B /* LocalStorageDatabaseTracker.mm */; };
    787789                CA5B94D22190C0F40059FE38 /* IndexedDBTempFileSize-1.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CA5B94D02190C0E00059FE38 /* IndexedDBTempFileSize-1.html */; };
     
    11781180                                57599E2A1F071AA000A3FB8C /* IndexedDBStructuredCloneBackwardCompatibilityRead.html in Copy Resources */,
    11791181                                57599E2B1F071AA000A3FB8C /* IndexedDBStructuredCloneBackwardCompatibilityWrite.html in Copy Resources */,
     1182                                CA2879DC226E69B6001026F5 /* IndexedDBSuspendImminently.html in Copy Resources */,
    11801183                                CA5B94D22190C0F40059FE38 /* IndexedDBTempFileSize-1.html in Copy Resources */,
    11811184                                CA5B94D32190C0F40059FE38 /* IndexedDBTempFileSize-2.html in Copy Resources */,
     
    21332136                C9E6DD311EA972D800DD78AA /* FirstResponderSuppression.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstResponderSuppression.mm; sourceTree = "<group>"; };
    21342137                C9E8EE7421DED91E00797765 /* long-test.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "long-test.mp4"; sourceTree = "<group>"; };
     2138                CA2879D9226E6978001026F5 /* IndexedDBSuspendImminently.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = IndexedDBSuspendImminently.html; sourceTree = "<group>"; };
     2139                CA2879DA226E6986001026F5 /* IndexedDBSuspendImminently.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexedDBSuspendImminently.mm; sourceTree = "<group>"; };
    21352140                CA38459520AE012E00990D3B /* LocalStorageDatabaseTracker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalStorageDatabaseTracker.mm; sourceTree = "<group>"; };
    21362141                CA5B94D02190C0E00059FE38 /* IndexedDBTempFileSize-1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBTempFileSize-1.html"; sourceTree = "<group>"; };
     
    25982603                                51B1EE8D1C80F5880064FB98 /* IndexedDBPersistence.mm */,
    25992604                                57599E201F07191700A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm */,
     2605                                CA2879DA226E6986001026F5 /* IndexedDBSuspendImminently.mm */,
    26002606                                CA5B94D62191005B0059FE38 /* IndexedDBTempFileSize.mm */,
    26012607                                CA97B3922193663B0045DF6F /* IndexedDBUserDelete.mm */,
     
    30003006                                57599E251F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibilityRead.html */,
    30013007                                57599E231F07192C00A3FB8C /* IndexedDBStructuredCloneBackwardCompatibilityWrite.html */,
     3008                                CA2879D9226E6978001026F5 /* IndexedDBSuspendImminently.html */,
    30023009                                CA5B94D02190C0E00059FE38 /* IndexedDBTempFileSize-1.html */,
    30033010                                CA5B94D12190C0E00059FE38 /* IndexedDBTempFileSize-2.html */,
     
    41804187                                7C83E0BF1D0A652200FEBCF3 /* IndexedDBPersistence.mm in Sources */,
    41814188                                57599E211F07191900A3FB8C /* IndexedDBStructuredCloneBackwardCompatibility.mm in Sources */,
     4189                                CA2879DB226E69A5001026F5 /* IndexedDBSuspendImminently.mm in Sources */,
    41824190                                CA5B94D72191005B0059FE38 /* IndexedDBTempFileSize.mm in Sources */,
    41834191                                CA97B394219366600045DF6F /* IndexedDBUserDelete.mm in Sources */,
Note: See TracChangeset for help on using the changeset viewer.