-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Fetch edits for multiple events in a single query #11660
Changes from 4 commits
b16ce01
4344f10
7e97e55
d4a41c8
e9908c8
7ac2a9d
aacf47e
e79d656
8132180
e00cec0
05c38f9
8400c20
e2f905b
ffad611
5ce3e07
9a7cc1a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Improve performance when fetching bundled aggregations for multiple events. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,6 +16,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| TYPE_CHECKING, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Any, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Collection, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Dict, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Iterable, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| List, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -28,7 +29,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
| import attr | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from frozendict import frozendict | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.api.constants import EventTypes, RelationTypes | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.api.constants import RelationTypes | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.events import EventBase | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.storage._base import SQLBaseStore | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.storage.database import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -44,6 +45,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
| RelationPaginationToken, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.util.caches.descriptors import cached | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.util.caches.lrucache import LruCache | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if TYPE_CHECKING: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from synapse.server import HomeServer | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -63,6 +65,11 @@ def __init__( | |||||||||||||||||||||||||||||||||||||||||||||||||
| self._msc1849_enabled = hs.config.experimental.msc1849_enabled | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self._msc3440_enabled = hs.config.experimental.msc3440_enabled | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| self.get_applicable_edit: LruCache[str, Optional[EventBase]] = LruCache( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| cache_name="get_applicable_edit", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| max_size=hs.config.caches.event_cache_size, # TODO | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @cached(tree=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async def get_relations_for_event( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -325,60 +332,96 @@ def _get_aggregation_groups_for_event_txn( | |||||||||||||||||||||||||||||||||||||||||||||||||
| "get_aggregation_groups_for_event", _get_aggregation_groups_for_event_txn | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @cached() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async def get_applicable_edit( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self, event_id: str, room_id: str | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> Optional[EventBase]: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async def _get_applicable_edits( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self, event_ids: Iterable[str] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> Dict[str, EventBase]: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| """Get the most recent edit (if any) that has happened for the given | ||||||||||||||||||||||||||||||||||||||||||||||||||
| event. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| events. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| Correctly handles checking whether edits were allowed to happen. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| event_id: The original event ID | ||||||||||||||||||||||||||||||||||||||||||||||||||
| room_id: The original event's room ID | ||||||||||||||||||||||||||||||||||||||||||||||||||
| event_ids: The original event IDs | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| The most recent edit, if any. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| A map of the most recent edit for each event. A missing event implies | ||||||||||||||||||||||||||||||||||||||||||||||||||
| there is no edits. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # A map of the original event IDs to the edit events. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| edits_by_original = {} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check if an edit for this event is currently cached. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| event_ids_to_check = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| for event_id in event_ids: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if event_id not in self.get_applicable_edit: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| event_ids_to_check.append(event_id) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| edit_event = self.get_applicable_edit[event_id] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if edit_event: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| edits_by_original[event_id] = edit_event | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # If all events were cached, all done. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if not event_ids_to_check: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return edits_by_original | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # We only allow edits for `m.room.message` events that have the same sender | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # and event type. We can't assert these things during regular event auth so | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # we have to do the checks post hoc. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Fetches latest edit that has the same type and sender as the | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # original, and is an `m.room.message`. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # TODO Should this ensure it does not return results for state events / redacted events? | ||||||||||||||||||||||||||||||||||||||||||||||||||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| sql = """ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT edit.event_id FROM events AS edit | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT original.event_id, edit.event_id FROM events AS edit | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(self.database_engine, PostgresEngine): | |
| # The `DISTINCT ON` clause will pick the *first* row it | |
| # encounters, so ordering by stream ID desc will ensure we get | |
| # the latest key. | |
| sql = """ | |
| SELECT DISTINCT ON (user_id, keytype) user_id, keytype, keydata, stream_id | |
| FROM e2e_cross_signing_keys | |
| WHERE %(clause)s | |
| ORDER BY user_id, keytype, stream_id DESC | |
| """ % { | |
| "clause": clause | |
| } | |
| else: | |
| # SQLite has special handling for bare columns when using | |
| # MIN/MAX with a `GROUP BY` clause where it picks the value from | |
| # a row that matches the MIN/MAX. | |
| sql = """ | |
| SELECT user_id, keytype, keydata, MAX(stream_id) | |
| FROM e2e_cross_signing_keys | |
| WHERE %(clause)s | |
| GROUP BY user_id, keytype | |
| """ % { | |
| "clause": clause | |
| } |
I think we can abstract out the changes in 8400c20, but that is proving a bit tedious / invasive so I'd like to do it separately.
DMRobertson marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this class depend on EventsWorkerStore instead of ignoring the error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can attempt to do that! Note that we have similar ignores all over, see #11165.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair!
Uh oh!
There was an error while loading. Please reload this page.