Skip to content
Snippets Groups Projects
Unverified Commit 803f63df authored by Erik Johnston's avatar Erik Johnston Committed by GitHub
Browse files

Fix perf of `wait_for_stream_positions` (#16148)

parent 0ba17777
Branches
Tags
No related merge requests found
Fix performance degredation when there are a lot of in-flight replication requests.
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
"""A replication client for use by synapse workers. """A replication client for use by synapse workers.
""" """
import logging import logging
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple from typing import TYPE_CHECKING, Dict, Iterable, Optional, Set, Tuple
from sortedcontainers import SortedList
from twisted.internet import defer from twisted.internet import defer
from twisted.internet.defer import Deferred from twisted.internet.defer import Deferred
...@@ -86,7 +88,9 @@ class ReplicationDataHandler: ...@@ -86,7 +88,9 @@ class ReplicationDataHandler:
# Map from stream and instance to list of deferreds waiting for the stream to # Map from stream and instance to list of deferreds waiting for the stream to
# arrive at a particular position. The lists are sorted by stream position. # arrive at a particular position. The lists are sorted by stream position.
self._streams_to_waiters: Dict[Tuple[str, str], List[Tuple[int, Deferred]]] = {} self._streams_to_waiters: Dict[
Tuple[str, str], SortedList[Tuple[int, Deferred]]
] = {}
async def on_rdata( async def on_rdata(
self, stream_name: str, instance_name: str, token: int, rows: list self, stream_name: str, instance_name: str, token: int, rows: list
...@@ -238,7 +242,9 @@ class ReplicationDataHandler: ...@@ -238,7 +242,9 @@ class ReplicationDataHandler:
# Notify any waiting deferreds. The list is ordered by position so we # Notify any waiting deferreds. The list is ordered by position so we
# just iterate through the list until we reach a position that is # just iterate through the list until we reach a position that is
# greater than the received row position. # greater than the received row position.
waiting_list = self._streams_to_waiters.get((stream_name, instance_name), []) waiting_list = self._streams_to_waiters.get((stream_name, instance_name))
if not waiting_list:
return
# Index of first item with a position after the current token, i.e we # Index of first item with a position after the current token, i.e we
# have called all deferreds before this index. If not overwritten by # have called all deferreds before this index. If not overwritten by
...@@ -262,7 +268,7 @@ class ReplicationDataHandler: ...@@ -262,7 +268,7 @@ class ReplicationDataHandler:
# Drop all entries in the waiting list that were called in the above # Drop all entries in the waiting list that were called in the above
# loop. (This maintains the order so no need to resort) # loop. (This maintains the order so no need to resort)
waiting_list[:] = waiting_list[index_of_first_deferred_not_called:] del waiting_list[:index_of_first_deferred_not_called]
for deferred in deferreds_to_callback: for deferred in deferreds_to_callback:
try: try:
...@@ -322,11 +328,10 @@ class ReplicationDataHandler: ...@@ -322,11 +328,10 @@ class ReplicationDataHandler:
) )
waiting_list = self._streams_to_waiters.setdefault( waiting_list = self._streams_to_waiters.setdefault(
(stream_name, instance_name), [] (stream_name, instance_name), SortedList(key=lambda t: t[0])
) )
waiting_list.append((position, deferred)) waiting_list.add((position, deferred))
waiting_list.sort(key=lambda t: t[0])
# We measure here to get in flight counts and average waiting time. # We measure here to get in flight counts and average waiting time.
with Measure(self._clock, "repl.wait_for_stream_position"): with Measure(self._clock, "repl.wait_for_stream_position"):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment