ladybird/Libraries/LibWeb/IndexedDB/Internal/Database.cpp

216 lines
6.5 KiB
C++
Raw Permalink Normal View History

2024-11-04 14:44:43 -03:00
/*
* Copyright (c) 2024-2025, stelar7 <dudedbz@gmail.com>
2024-11-04 14:44:43 -03:00
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/NeverDestroyed.h>
#include <LibGC/Heap.h>
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
#include <LibWeb/IndexedDB/IDBDatabase.h>
#include <LibWeb/IndexedDB/IDBTransaction.h>
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
#include <LibWeb/IndexedDB/Internal/Algorithms.h>
#include <LibWeb/IndexedDB/Internal/ConnectionQueueHandler.h>
2024-11-04 14:44:43 -03:00
#include <LibWeb/IndexedDB/Internal/Database.h>
namespace Web::IndexedDB {
using IDBDatabaseMapping = HashMap<StorageAPI::StorageKey, HashMap<String, GC::Root<Database>>>;
static IDBDatabaseMapping& idb_databases()
{
static NeverDestroyed<IDBDatabaseMapping> databases;
return *databases;
}
void Database::for_each_database(AK::Function<void(Database&)> const& visitor)
{
for (auto const& [key, mapping] : idb_databases()) {
for (auto const& [_, database] : mapping) {
if (!database)
continue;
visitor(*database);
}
}
}
GC_DEFINE_ALLOCATOR(Database);
2024-11-04 14:44:43 -03:00
Database::~Database() = default;
GC::Ref<Database> Database::create(GC::Heap& heap, String const& name)
2024-11-04 14:44:43 -03:00
{
return heap.allocate<Database>(name);
2024-11-04 14:44:43 -03:00
}
void Database::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_upgrade_transaction);
visitor.visit(m_object_stores);
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
if (m_pending_connection_wait.has_value())
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
visitor.visit(m_pending_connection_wait->callback);
2024-11-04 14:44:43 -03:00
}
GC::Ptr<ObjectStore> Database::object_store_with_name(String const& name) const
{
for (auto const& object_store : m_object_stores) {
if (object_store->name() == name)
return object_store;
}
return nullptr;
}
Vector<GC::Weak<Database>> Database::for_key(StorageAPI::StorageKey const& key)
{
Vector<GC::Weak<Database>> databases;
for (auto const& database_mapping : idb_databases().get(key).value_or({})) {
databases.append(*database_mapping.value);
}
return databases;
}
RequestList& ConnectionQueueHandler::for_key_and_name(StorageAPI::StorageKey const& key, String const& name)
{
auto& instance = ConnectionQueueHandler::the();
auto maybe_connection = instance.m_open_requests.find_if([&key, &name](Connection const& connection) {
return connection.storage_key == key && connection.name == name;
});
if (!maybe_connection.is_end())
return (*maybe_connection)->request_list;
auto new_connection = adopt_ref(*new Connection(key, name));
instance.m_open_requests.append(new_connection);
return new_connection->request_list;
}
Optional<Database&> Database::for_key_and_name(StorageAPI::StorageKey const& key, String const& name)
{
auto database_mapping = idb_databases().ensure(key, [] { return HashMap<String, GC::Root<Database>>(); });
if (auto maybe_database = database_mapping.get(name); maybe_database.has_value())
return *maybe_database.value();
return {};
}
ErrorOr<GC::Ref<Database>> Database::create_for_key_and_name(GC::Heap& heap, StorageAPI::StorageKey const& key, String const& name)
{
auto database_mapping = TRY(idb_databases().try_ensure(key, [] {
return HashMap<String, GC::Root<Database>>();
}));
auto value = Database::create(heap, name);
database_mapping.set(name, value);
idb_databases().set(key, database_mapping);
return value;
}
ErrorOr<void> Database::delete_for_key_and_name(StorageAPI::StorageKey const& key, String const& name)
{
// FIXME: Is a missing entry a failure?
auto maybe_database_mapping = idb_databases().get(key);
if (!maybe_database_mapping.has_value())
return {};
auto& database_mapping = maybe_database_mapping.value();
auto maybe_database = database_mapping.get(name);
if (!maybe_database.has_value())
return {};
auto did_remove = database_mapping.remove(name);
if (!did_remove)
return {};
idb_databases().set(key, database_mapping);
return {};
}
2024-11-04 14:44:43 -03:00
void Database::associate(GC::Ref<IDBDatabase> connection)
{
m_associated_connections.append(connection);
}
void Database::dissociate(IDBDatabase& connection)
{
m_associated_connections.remove_first_matching([&](auto& entry) { return entry == &connection; });
}
GC::Ref<Database::AssociatedConnections> Database::associated_connections_as_heap_vector(GC::Heap& heap)
{
auto connections = heap.allocate<AssociatedConnections>();
for (auto& associated_connection : m_associated_connections) {
if (associated_connection)
connections->elements().append(*associated_connection);
}
return connections;
}
GC::RootVector<GC::Ref<IDBDatabase>> Database::associated_connections_as_root_vector()
{
GC::RootVector<GC::Ref<IDBDatabase>> connections {};
for (auto& connection : m_associated_connections) {
if (connection)
connections.append(*connection);
}
return connections;
}
GC::Ref<Database::AssociatedConnections> Database::associated_connections_as_heap_vector_except(GC::Heap& heap, IDBDatabase& connection)
{
auto connections = heap.allocate<AssociatedConnections>();
for (auto& associated_connection : m_associated_connections) {
if (associated_connection && associated_connection != &connection)
connections->elements().append(*associated_connection);
}
return connections;
}
void Database::wait_for_connections_to_close(ReadonlySpan<GC::Ref<IDBDatabase>> connections, GC::Ref<GC::Function<void()>> after_all)
{
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
bool all_closed = true;
for (auto const& entry : connections) {
if (entry->state() != ConnectionState::Closed) {
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
all_closed = false;
break;
}
}
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
if (all_closed) {
queue_a_database_task(after_all);
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
return;
}
VERIFY(!m_pending_connection_wait.has_value());
Vector<GC::Weak<IDBDatabase>> weak_connections;
weak_connections.ensure_capacity(connections.size());
for (auto const& connection : connections)
weak_connections.unchecked_append(connection);
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
m_pending_connection_wait = PendingConnectionWait {
.connections = move(weak_connections),
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
.callback = after_all,
};
}
void Database::check_pending_connection_wait()
{
if (!m_pending_connection_wait.has_value())
return;
auto& wait = m_pending_connection_wait.value();
for (auto const& connection : wait.connections) {
if (connection && connection->state() != ConnectionState::Closed)
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
return;
}
LibWeb: Refactor IndexedDB to handle requests serially Previously, after one request was marked as processed, we would synchronously queue another task to process the next request. This would mean that two open requests on the same database could interleave. This was especially problematic when one of the requests would cause the database to upgrade, since the second open request would begin processing before the upgradeneeded event fired, causing an exception to be thrown in the second open(). The solution is to explicitly check for continuation conditions after events have been fired in order to ensure that every step for the request is completed before starting any further request processing. For connection requests, the spec states: > Open requests are processed in a connection queue. The queue contains > all open requests associated with an storage key and a name. Requests > added to the connection queue processed in order and each request > must run to completion before the next request is processed. An open > request may be blocked on other connections, requiring those > connections to close before the request can complete and allow > further requests to be processed. For requests against a transaction, the spec states: > Once the transaction has been started the implementation can begin > executing the requests placed against the transaction. Requests must > be executed in the order in which they were made against the > transaction. Likewise, their results must be returned in the order > the requests were placed against a specific transaction. There is no > guarantee about the order that results from requests in different > transactions are returned. In the process of reworking it to use this approach, I've added a bunch of new tests that cover things that our imported WPTs weren't checking. With the fix for serializing connection requests, we can now fully download the assets for the emscripten-compiled asm.js games in the Humble Mozilla Bundle, particularly FTL: Faster Than Light. There were no regressions in our test suite. One web platform test, 'idbindex_reverse_cursor.any.html', has one newly-failing subtest, but the subtest was apparently only passing by chance due synchronous execution of requests. A few web platform tests that were added in a prior commit improved. The delete-request-queue.any.html test has stopped crashing, and the close-in-upgrade-needed.any.html test has stopped flaking, so they are both imported here as well. Incidentally fixes #7512, for which a crash test has been added.
2026-03-03 22:16:07 -03:00
// All connections are closed - invoke the callback and clear the wait
auto callback = wait.callback;
m_pending_connection_wait.clear();
queue_a_database_task(callback);
}
2024-11-04 14:44:43 -03:00
}