LibWeb/IndexedDB: Remove spin_until from checking finished transactions

This commit is contained in:
Luke Wilde
2025-09-13 11:01:25 +01:00
committed by Andreas Kling
parent 52b53e52fb
commit d87c2a55b0
Notes: github-actions[bot] 2025-10-08 15:26:31 +00:00
10 changed files with 250 additions and 42 deletions

View File

@@ -12,10 +12,12 @@
#include <LibWeb/IndexedDB/IDBObjectStore.h>
#include <LibWeb/IndexedDB/Internal/Algorithms.h>
#include <LibWeb/IndexedDB/Internal/IDBDatabaseObserver.h>
#include <LibWeb/IndexedDB/Internal/IDBTransactionObserver.h>
namespace Web::IndexedDB {
GC_DEFINE_ALLOCATOR(IDBDatabase);
GC_DEFINE_ALLOCATOR(IDBDatabase::TransactionFinishState);
IDBDatabase::IDBDatabase(JS::Realm& realm, Database& db)
: EventTarget(realm)
@@ -47,6 +49,7 @@ void IDBDatabase::visit_edges(Visitor& visitor)
visitor.visit(m_object_store_set);
visitor.visit(m_associated_database);
visitor.visit(m_transactions);
visitor.visit(m_transaction_finish_queue);
}
void IDBDatabase::set_onabort(WebIDL::CallbackType* event_handler)
@@ -263,4 +266,60 @@ void IDBDatabase::set_state(ConnectionState state)
});
}
void IDBDatabase::wait_for_transactions_to_finish(ReadonlySpan<GC::Ref<IDBTransaction>> transactions, GC::Ref<GC::Function<void()>> on_complete)
{
GC::Ptr<TransactionFinishState> transaction_finish_state;
for (auto const& entry : transactions) {
if (!entry->is_finished()) {
if (!transaction_finish_state) {
transaction_finish_state = heap().allocate<TransactionFinishState>();
}
transaction_finish_state->add_transaction_to_observe(entry);
}
}
if (transaction_finish_state) {
transaction_finish_state->after_all = GC::create_function(heap(), [this, transaction_finish_state, on_complete] {
bool was_removed = m_transaction_finish_queue.remove_first_matching([transaction_finish_state](GC::Ref<TransactionFinishState> pending_transaction_finish_state) {
return pending_transaction_finish_state == transaction_finish_state;
});
VERIFY(was_removed);
queue_a_database_task(on_complete);
});
m_transaction_finish_queue.append(transaction_finish_state.as_nonnull());
} else {
queue_a_database_task(on_complete);
}
}
void IDBDatabase::TransactionFinishState::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(transaction_observers);
visitor.visit(after_all);
}
void IDBDatabase::TransactionFinishState::add_transaction_to_observe(GC::Ref<IDBTransaction> transaction)
{
auto transaction_observer = heap().allocate<IDBTransactionObserver>(transaction);
transaction_observer->set_transaction_finished_observer(GC::create_function(heap(), [this] {
transaction_observers.remove_all_matching([](GC::Ref<IDBTransactionObserver> const& transaction_observer) {
if (transaction_observer->transaction()->is_finished()) {
transaction_observer->unobserve();
return true;
}
return false;
});
if (transaction_observers.is_empty()) {
queue_a_database_task(after_all.as_nonnull());
}
}));
transaction_observers.append(transaction_observer);
}
}