diff --git a/synapse/storage/databases/main/event_push_actions.py b/synapse/storage/databases/main/event_push_actions.py index ac60c45db5..9c5fd35906 100644 --- a/synapse/storage/databases/main/event_push_actions.py +++ b/synapse/storage/databases/main/event_push_actions.py @@ -1527,23 +1527,25 @@ class EventPushActionsWorkerStore(ReceiptsWorkerStore, StreamWorkerStore, SQLBas (user_id, room_id), ) pending_thread_ids = [row[0] for row in txn] - for pending_thread_id in pending_thread_ids: - self.db_pool.simple_upsert_txn( - txn, - table="event_push_summary", - keyvalues={ - "user_id": user_id, - "room_id": room_id, - "thread_id": pending_thread_id, - }, - values={}, - insertion_values={ - "notif_count": 0, - "unread_count": 0, - "stream_ordering": old_rotate_stream_ordering, - "last_receipt_stream_ordering": stream_ordering, - }, - ) + self.db_pool.simple_upsert_many_txn( + txn, + table="event_push_summary", + key_names=("user_id", "room_id", "thread_id"), + key_values=[ + (user_id, room_id, pending_thread_id) + for pending_thread_id in pending_thread_ids + ], + value_names=( + "notif_count", + "unread_count", + "stream_ordering", + "last_receipt_stream_ordering", + ), + value_values=[ + (0, 0, old_rotate_stream_ordering, stream_ordering) + for _ in pending_thread_ids + ], + ) # For a threaded receipt, we *always* want to update that receipt, # event if there are no new notifications in that thread. This ensures diff --git a/synapse/storage/schema/main/delta/94/05_backfill_event_push_summary_receipt.sql b/synapse/storage/schema/main/delta/94/05_backfill_event_push_summary_receipt.sql index 63538291f2..b50c871a50 100644 --- a/synapse/storage/schema/main/delta/94/05_backfill_event_push_summary_receipt.sql +++ b/synapse/storage/schema/main/delta/94/05_backfill_event_push_summary_receipt.sql @@ -1,7 +1,7 @@ -- -- This file is licensed under the Affero General Public License (AGPL) version 3. -- --- Copyright (C) 2026 New Vector Ltd +-- Copyright (C) 2026 Element Creations Ltd -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as @@ -12,15 +12,16 @@ -- . -- Backfill last_receipt_stream_ordering for event_push_summary rows created --- with last_receipt_stream_ordering=NULL by the rotation job before the code --- fix in _handle_new_receipts_for_notifs_txn was applied. +-- with last_receipt_stream_ordering=NULL by the rotation job before +-- the fix in https://github.com/element-hq/synapse/pull/19785. -- --- NULL has a dual meaning in this column (see the schema delta that added it): +-- NULL has a dual meaning in this column (see +-- synapse/storage/schema/main/delta/72/01event_push_summary_receipt.sql): -- 1. Legacy rows from old Synapse that maintained counts synchronously. -- 2. Bug-affected rows where the receipt UPDATE was a silent no-op. -- -- For a given event_push_summary row, the relevant receipts are unthreaded --- receipts (cover all threads) and the threaded receipt for that thread. +-- receipts (marks all threads as read) and the threaded receipt for that thread. -- -- For both kinds of stale row, if stream_ordering <= the max relevant receipt -- then every event in the summary predates the receipt and the counts should @@ -35,6 +36,7 @@ SET last_receipt_stream_ordering = ( WHERE r.user_id = event_push_summary.user_id AND r.room_id = event_push_summary.room_id AND r.receipt_type IN ('m.read', 'm.read.private') + AND r.event_stream_ordering IS NOT NULL AND (r.thread_id IS NULL OR r.thread_id = event_push_summary.thread_id) ), notif_count = CASE @@ -44,6 +46,7 @@ SET last_receipt_stream_ordering = ( WHERE r.user_id = event_push_summary.user_id AND r.room_id = event_push_summary.room_id AND r.receipt_type IN ('m.read', 'm.read.private') + AND r.event_stream_ordering IS NOT NULL AND (r.thread_id IS NULL OR r.thread_id = event_push_summary.thread_id) ) THEN 0 ELSE notif_count @@ -55,6 +58,7 @@ SET last_receipt_stream_ordering = ( WHERE r.user_id = event_push_summary.user_id AND r.room_id = event_push_summary.room_id AND r.receipt_type IN ('m.read', 'm.read.private') + AND r.event_stream_ordering IS NOT NULL AND (r.thread_id IS NULL OR r.thread_id = event_push_summary.thread_id) ) THEN 0 ELSE unread_count @@ -65,5 +69,6 @@ WHERE last_receipt_stream_ordering IS NULL WHERE r.user_id = event_push_summary.user_id AND r.room_id = event_push_summary.room_id AND r.receipt_type IN ('m.read', 'm.read.private') + AND r.event_stream_ordering IS NOT NULL AND (r.thread_id IS NULL OR r.thread_id = event_push_summary.thread_id) );