diff --git a/AK/Debug.h.in b/AK/Debug.h.in index ddb495e39fa..85c58a87efd 100644 --- a/AK/Debug.h.in +++ b/AK/Debug.h.in @@ -114,6 +114,10 @@ # cmakedefine01 ICO_DEBUG #endif +#ifndef IDB_DEBUG +# cmakedefine01 IDB_DEBUG +#endif + #ifndef IDL_DEBUG # cmakedefine01 IDL_DEBUG #endif diff --git a/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp b/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp index 808fc11d4bd..99afae48d30 100644 --- a/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBDatabase.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,7 @@ IDBDatabase::IDBDatabase(JS::Realm& realm, Database& db) , m_name(db.name()) , m_associated_database(db) { + m_uuid = MUST(Crypto::generate_random_uuid()); db.associate(*this); m_object_store_set = Vector> { db.object_stores() }; } diff --git a/Libraries/LibWeb/IndexedDB/IDBDatabase.h b/Libraries/LibWeb/IndexedDB/IDBDatabase.h index 69fa58e3b57..e83e0ad142b 100644 --- a/Libraries/LibWeb/IndexedDB/IDBDatabase.h +++ b/Libraries/LibWeb/IndexedDB/IDBDatabase.h @@ -46,6 +46,7 @@ public: void set_close_pending(bool close_pending) { m_close_pending = close_pending; } void set_state(ConnectionState state) { m_state = state; } + [[nodiscard]] String uuid() const { return m_uuid; } [[nodiscard]] String name() const { return m_name; } [[nodiscard]] u64 version() const { return m_version; } [[nodiscard]] bool close_pending() const { return m_close_pending; } @@ -95,6 +96,9 @@ private: // NOTE: There is an associated database in the spec, but there is no mention where it is assigned, nor where its from // So we stash the one we have when opening a connection. GC::Ref m_associated_database; + + // NOTE: Used for debug purposes + String m_uuid; }; } diff --git a/Libraries/LibWeb/IndexedDB/IDBRequest.cpp b/Libraries/LibWeb/IndexedDB/IDBRequest.cpp index a2d6f81c5a7..25bb6febff2 100644 --- a/Libraries/LibWeb/IndexedDB/IDBRequest.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBRequest.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -21,6 +22,7 @@ IDBRequest::IDBRequest(JS::Realm& realm, IDBRequestSource source) : EventTarget(realm) , m_source(source) { + m_uuid = MUST(Crypto::generate_random_uuid()); } void IDBRequest::initialize(JS::Realm& realm) diff --git a/Libraries/LibWeb/IndexedDB/IDBRequest.h b/Libraries/LibWeb/IndexedDB/IDBRequest.h index 796cd4c9dad..a1c6509952f 100644 --- a/Libraries/LibWeb/IndexedDB/IDBRequest.h +++ b/Libraries/LibWeb/IndexedDB/IDBRequest.h @@ -30,6 +30,7 @@ public: [[nodiscard]] bool processed() const { return m_processed; } [[nodiscard]] IDBRequestSource source() const { return m_source; } [[nodiscard]] GC::Ptr transaction() const { return m_transaction; } + [[nodiscard]] String uuid() const { return m_uuid; } [[nodiscard]] Bindings::IDBRequestReadyState ready_state() const; [[nodiscard]] WebIDL::ExceptionOr> error() const; @@ -56,15 +57,22 @@ protected: private: // A request has a processed flag which is initially false. bool m_processed { false }; + // A request has a done flag which is initially false. bool m_done { false }; + // A request has a result and an error JS::Value m_result; GC::Ptr m_error; + // A request has a source object. IDBRequestSource m_source; + // A request has a transaction which is initially null. GC::Ptr m_transaction; + + // NOTE: Used for debug purposes + String m_uuid; }; } diff --git a/Libraries/LibWeb/IndexedDB/IDBTransaction.cpp b/Libraries/LibWeb/IndexedDB/IDBTransaction.cpp index 0a1d94dc966..a1d56e322cf 100644 --- a/Libraries/LibWeb/IndexedDB/IDBTransaction.cpp +++ b/Libraries/LibWeb/IndexedDB/IDBTransaction.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -22,6 +23,7 @@ IDBTransaction::IDBTransaction(JS::Realm& realm, GC::Ref connection , m_durability(durability) , m_scope(move(scopes)) { + m_uuid = MUST(Crypto::generate_random_uuid()); } GC::Ref IDBTransaction::create(JS::Realm& realm, GC::Ref connection, Bindings::IDBTransactionMode mode, Bindings::IDBTransactionDurability durability = Bindings::IDBTransactionDurability::Default, Vector> scopes = {}) diff --git a/Libraries/LibWeb/IndexedDB/IDBTransaction.h b/Libraries/LibWeb/IndexedDB/IDBTransaction.h index a7b35fd75e2..5ca6ee15325 100644 --- a/Libraries/LibWeb/IndexedDB/IDBTransaction.h +++ b/Libraries/LibWeb/IndexedDB/IDBTransaction.h @@ -45,6 +45,7 @@ public: [[nodiscard]] bool aborted() const { return m_aborted; } [[nodiscard]] GC::Ref object_store_names(); [[nodiscard]] ReadonlySpan> scope() const { return m_scope; } + [[nodiscard]] String uuid() const { return m_uuid; } void set_mode(Bindings::IDBTransactionMode mode) { m_mode = mode; } void set_state(TransactionState state) { m_state = state; } @@ -100,5 +101,8 @@ private: // A transaction optionally has a cleanup event loop which is an event loop. GC::Ptr m_cleanup_event_loop; + + // NOTE: Used for debug purposes + String m_uuid; }; } diff --git a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp index 621ab2a2dab..9dc3b7b72d6 100644 --- a/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp @@ -36,9 +36,18 @@ WebIDL::ExceptionOr> open_a_database_connection(JS::Realm& // 2. Add request to queue. queue.append(request); + dbgln_if(IDB_DEBUG, "open_a_database_connection: added request {} to queue", request->uuid()); // 3. Wait until all previous requests in queue have been processed. HTML::main_thread_event_loop().spin_until(GC::create_function(realm.vm().heap(), [queue, request]() { + if constexpr (IDB_DEBUG) { + dbgln("open_a_database_connection: waiting for step 3"); + dbgln("requests in queue:"); + for (auto const& item : queue) { + dbgln("[{}] - {} = {}", item == request ? "x"sv : " "sv, item->uuid(), item->processed() ? "processed"sv : "not processed"sv); + } + } + return queue.all_previous_requests_processed(request); })); @@ -71,6 +80,7 @@ WebIDL::ExceptionOr> open_a_database_connection(JS::Realm& // 8. Let connection be a new connection to db. auto connection = IDBDatabase::create(realm, *db); + dbgln_if(IDB_DEBUG, "Created new connection with UUID: {}", connection->uuid()); // 9. Set connection’s version to version. connection->set_version(version); @@ -97,6 +107,11 @@ WebIDL::ExceptionOr> open_a_database_connection(JS::Realm& // 3. Wait for all of the events to be fired. HTML::main_thread_event_loop().spin_until(GC::create_function(realm.vm().heap(), [&events_to_fire, &events_fired]() { + if constexpr (IDB_DEBUG) { + dbgln("open_a_database_connection: waiting for step 10.3"); + dbgln("events_fired: {}, events_to_fire: {}", events_fired, events_to_fire); + } + return events_fired == events_to_fire; })); @@ -112,6 +127,14 @@ WebIDL::ExceptionOr> open_a_database_connection(JS::Realm& // 5. Wait until all connections in openConnections are closed. HTML::main_thread_event_loop().spin_until(GC::create_function(realm.vm().heap(), [open_connections]() { + if constexpr (IDB_DEBUG) { + dbgln("open_a_database_connection: waiting for step 10.5"); + dbgln("open connections: {}", open_connections.size()); + for (auto const& connection : open_connections) { + dbgln(" - {}", connection->uuid()); + } + } + for (auto const& entry : open_connections) { if (entry->state() != IDBDatabase::ConnectionState::Closed) { return false; @@ -314,6 +337,7 @@ GC::Ref upgrade_a_database(JS::Realm& realm, GC::Ref> { connection->object_store_set() }); + dbgln_if(IDB_DEBUG, "Created new upgrade transaction with UUID: {}", transaction->uuid()); // 4. Set db’s upgrade transaction to transaction. db->set_upgrade_transaction(transaction); @@ -364,6 +388,7 @@ GC::Ref upgrade_a_database(JS::Realm& realm, GC::Ref delete_a_database(JS::Realm& realm, StorageAPI::Storage // 2. Add request to queue. queue.append(request); + dbgln_if(IDB_DEBUG, "delete_a_database: added request {} to queue", request->uuid()); // 3. Wait until all previous requests in queue have been processed. HTML::main_thread_event_loop().spin_until(GC::create_function(realm.vm().heap(), [queue, request]() { + if constexpr (IDB_DEBUG) { + dbgln("delete_a_database: waiting for step 3"); + dbgln("requests in queue:"); + for (auto const& item : queue) { + dbgln("[{}] - {} = {}", item == request ? "x"sv : " "sv, item->uuid(), item->processed() ? "processed"sv : "not processed"sv); + } + } + return queue.all_previous_requests_processed(request); })); @@ -411,6 +445,11 @@ WebIDL::ExceptionOr delete_a_database(JS::Realm& realm, StorageAPI::Storage // 7. Wait for all of the events to be fired. HTML::main_thread_event_loop().spin_until(GC::create_function(realm.vm().heap(), [&events_to_fire, &events_fired]() { + if constexpr (IDB_DEBUG) { + dbgln("delete_a_database: waiting for step 7"); + dbgln("events_fired: {}, events_to_fire: {}", events_fired, events_to_fire); + } + return events_fired == events_to_fire; })); @@ -425,6 +464,14 @@ WebIDL::ExceptionOr delete_a_database(JS::Realm& realm, StorageAPI::Storage // 9. Wait until all connections in openConnections are closed. HTML::main_thread_event_loop().spin_until(GC::create_function(realm.vm().heap(), [open_connections]() { + if constexpr (IDB_DEBUG) { + dbgln("delete_a_database: waiting for step 9"); + dbgln("open connections: {}", open_connections.size()); + for (auto const& connection : open_connections) { + dbgln(" - {}", connection->uuid()); + } + } + for (auto const& entry : open_connections) { if (entry->state() != IDBDatabase::ConnectionState::Closed) { return false; @@ -451,6 +498,7 @@ void abort_a_transaction(GC::Ref transaction, GC::Ptrset_aborted(true); + dbgln_if(IDB_DEBUG, "abort_a_transaction: transaction {} is aborting", transaction->uuid()); // FIXME: 1. All the changes made to the database by the transaction are reverted. // For upgrade transactions this includes changes to the set of object stores and indexes, as well as the change to the version. diff --git a/Meta/CMake/all_the_debug_macros.cmake b/Meta/CMake/all_the_debug_macros.cmake index 47d2db25da5..7e947c28df9 100644 --- a/Meta/CMake/all_the_debug_macros.cmake +++ b/Meta/CMake/all_the_debug_macros.cmake @@ -24,6 +24,7 @@ set(HTML_SCRIPT_DEBUG ON) set(HTTPJOB_DEBUG ON) set(HUNKS_DEBUG ON) set(ICO_DEBUG ON) +set(IDB_DEBUG ON) set(IDL_DEBUG ON) set(IMAGE_DECODER_DEBUG ON) set(IMAGE_LOADER_DEBUG ON)