Track notification counts per thread (implement MSC3773)#13181
Track notification counts per thread (implement MSC3773)#13181
Conversation
80d632a to
23a632e
Compare
b325dfc to
067563b
Compare
a6d67c2 to
9b92fce
Compare
405e030 to
7d3e937
Compare
7d3e937 to
d56296a
Compare
synapse/storage/schema/main/delta/72/03thread_notifications.sql
Outdated
Show resolved
Hide resolved
…tions_by_room_for_user.
| # XXX All threads should have the same stream ordering? | ||
| max_summary_stream_ordering = max( | ||
| summary_stream_ordering, max_summary_stream_ordering | ||
| ) |
There was a problem hiding this comment.
Need to figure out what's going on here.
There was a problem hiding this comment.
Looking at my test server a bit, this isn't true (that all event_push_summary for a room/user have the same stream_ordering). I'm not really sure why I thought this, but it likely causes subtle bugs.
There was a problem hiding this comment.
I think that stream ordering is the "max" stream ordering that we rotated from the event_push_actions table:
I think that means its equivalent to the stream ordering we rotated up to? They may differ but there should never be any relevant rows in EPA between the per-thread stream ordering and the max stream ordering?
| # TODO Delete zeroed out threads completely from the database. | ||
| elif notif_count or unread_count: | ||
| thread_counts[thread_id] = NotifCounts( | ||
| notify_count=notif_count, unread_count=unread_count | ||
| ) |
There was a problem hiding this comment.
Might be worth looking at this again briefly not that some other bugs have been fixed.
|
Requesting review of this, but keeping it in draft. I think the implementation is far enough along that we could merge this, but don't want it merged accidentally. @erikjohnston had a brief conversation of "how bad would it be to back this out if perf tanks". I think it wouldn't be too bad: backing out the code should essentially revert behavior, with the caveat there would be an additional unused column getting tossed around. This column could then be dropped without an issue. |
| _rotate() | ||
| _assert_counts(0, 0, 0) | ||
|
|
||
| def test_count_aggregation_threads(self) -> None: |
There was a problem hiding this comment.
(I should possibly put this in a docstring...)
This is a "copy" of the test_count_aggregation test, but adapted to have both a "main" timeline and a thread in the same room.
|
(Oh, woops, I hit the merge develop branch on the wrong PR, sowwy) |
| ) | ||
|
|
||
| # Then any updated threads get their notification count and unread | ||
| # count updated. |
There was a problem hiding this comment.
This presumably handles the "main" thread too?
There was a problem hiding this comment.
I'm actually having trouble convincing myself this doesn't need to handle thread_id being null separately.
If the summary exists above for the "main" thread than the upsert would fail, I think? (Since it would attempt to add a new row since null isn't equivalent null.)
I think that's possible, but probably not exercised by our tests?
| } | ||
|
|
||
| # simple_upsert_many_txn doesn't support a predicate clause to force using | ||
| # the partial index (thread_id = NULL). |
There was a problem hiding this comment.
I tried a bit and was having issues with figuring out how the API should look -- a simple implementation which just accepts a string is pretty easy (I think), but a more complicated one which accepts keyvalues: Dict[str, Any] is a bit harder because you need to do conversion of = NULL to IS NULL. I'm a bit surprised we don't already have code for this?
Anyway, it is doable, yes. I can do it as a separate PR if you'd like.
There was a problem hiding this comment.
Ah, never mind if it isn't trivial. Was just a bit surprised is all.
There was a problem hiding this comment.
Looking at it, it should be doable. It would really simplify this code, so will take a look. 👍
| # XXX All threads should have the same stream ordering? | ||
| max_summary_stream_ordering = max( | ||
| summary_stream_ordering, max_summary_stream_ordering | ||
| ) |
There was a problem hiding this comment.
I think that stream ordering is the "max" stream ordering that we rotated from the event_push_actions table:
I think that means its equivalent to the stream ordering we rotated up to? They may differ but there should never be any relevant rows in EPA between the per-thread stream ordering and the max stream ordering?
|
|
||
| -- Update the unique index for `event_push_summary`. | ||
| INSERT INTO background_updates (ordering, update_name, progress_json) VALUES | ||
| (7003, 'event_push_summary_unique_index2', '{}'); |
There was a problem hiding this comment.
I'm a bit worried that a bunch of the code will break while we don't have the proper index on event_push_summary? In particular I think if it encounters threads will try and insert multiple rows and fail due to the existing unique index?
There was a problem hiding this comment.
Yes, that might be an issue -- would the solution be to drop the current index here and then add then new one in the background?
There was a problem hiding this comment.
I don't think so, as we need a unique index to have upserts work? I have a horrible suspicion that we might need to either do this as a two step PR, one to add the column and new unique index, and the other to drop the index and start populating the thread rows. Either that or have a flag that changes the behaviour from the current behaviour to the new behaviour depending on if the index has finished being created?
There was a problem hiding this comment.
Either of those seems doable. Do we have a preferred way of doing that? I think we'd have to wait for the new index regardless since we don't know for sure that an index was done just because we have a new version of Synapse?
|
|
||
| ALTER TABLE event_push_actions_staging ADD COLUMN thread_id TEXT; | ||
|
|
||
| ALTER TABLE event_push_actions ADD COLUMN thread_id TEXT; |
There was a problem hiding this comment.
I was not planning to do a background update to "fix" the thread_id for any existing event_push_actions rows -- I think with the way we summarize that's a somewhat futile effort and it should correct itself over time.
| ALTER TABLE event_push_actions_staging ADD COLUMN thread_id TEXT; | ||
|
|
||
| ALTER TABLE event_push_actions ADD COLUMN thread_id TEXT; |
There was a problem hiding this comment.
I wonder if the thread_id column should really live on the events table and not event_push_actions and event_push_actions_staging? This would be a bigger migration, but potentially more useful in the future? I don't have a strong opinion though.
Track notification counts on a per-thread basis, implementing MSC3773.
The overall design of this is to add a
thread_idcolumn to theevent_push_actions(+event_push_actions_staging) andevent_push_summarytables. This allows the results to be segmented by the "main" timeline (which is represented byNULLin the database) and any other threads (which have the root event ID in thethread_idcolumn).When retrieving counts of notifications we can then segment based on the thread, this is opt-in for the client by providing a sync flag. In the case the client doesn't want separate threads we simply sum across all threads + the main timeline.
The summarization code also needs to be updated to be per thread, instead of just per room.
Please see MSC3773 for a description of the API changes.
Part of #12550
To Do