Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit fdb1344

Browse files
authored
Remove concept of a non-limited stream. (#7011)
1 parent caec7d4 commit fdb1344

8 files changed

Lines changed: 71 additions & 67 deletions

File tree

changelog.d/7011.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove concept of a non-limited stream.

synapse/handlers/presence.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ async def is_visible(self, observed_user, observer_user):
747747

748748
return False
749749

750-
async def get_all_presence_updates(self, last_id, current_id):
750+
async def get_all_presence_updates(self, last_id, current_id, limit):
751751
"""
752752
Gets a list of presence update rows from between the given stream ids.
753753
Each row has:
@@ -762,7 +762,7 @@ async def get_all_presence_updates(self, last_id, current_id):
762762
"""
763763
# TODO(markjh): replicate the unpersisted changes.
764764
# This could use the in-memory stores for recent changes.
765-
rows = await self.store.get_all_presence_updates(last_id, current_id)
765+
rows = await self.store.get_all_presence_updates(last_id, current_id, limit)
766766
return rows
767767

768768
def notify_new_event(self):

synapse/handlers/typing.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import logging
1717
from collections import namedtuple
18+
from typing import List
1819

1920
from twisted.internet import defer
2021

@@ -257,7 +258,13 @@ def _push_update_local(self, member, typing):
257258
"typing_key", self._latest_room_serial, rooms=[member.room_id]
258259
)
259260

260-
async def get_all_typing_updates(self, last_id, current_id):
261+
async def get_all_typing_updates(
262+
self, last_id: int, current_id: int, limit: int
263+
) -> List[dict]:
264+
"""Get up to `limit` typing updates between the given tokens, earliest
265+
updates first.
266+
"""
267+
261268
if last_id == current_id:
262269
return []
263270

@@ -275,7 +282,7 @@ async def get_all_typing_updates(self, last_id, current_id):
275282
typing = self._room_typing[room_id]
276283
rows.append((serial, room_id, list(typing)))
277284
rows.sort()
278-
return rows
285+
return rows[:limit]
279286

280287
def get_current_token(self):
281288
return self._latest_room_serial

synapse/replication/tcp/resource.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,6 @@ async def _run_notifier_loop(self):
166166
self.pending_updates = False
167167

168168
with Measure(self.clock, "repl.stream.get_updates"):
169-
# First we tell the streams that they should update their
170-
# current tokens.
171-
for stream in self.streams:
172-
stream.advance_current_token()
173-
174169
all_streams = self.streams
175170

176171
if self._replication_torture_level is not None:
@@ -180,7 +175,7 @@ async def _run_notifier_loop(self):
180175
random.shuffle(all_streams)
181176

182177
for stream in all_streams:
183-
if stream.last_token == stream.upto_token:
178+
if stream.last_token == stream.current_token():
184179
continue
185180

186181
if self._replication_torture_level:
@@ -192,7 +187,7 @@ async def _run_notifier_loop(self):
192187
"Getting stream: %s: %s -> %s",
193188
stream.NAME,
194189
stream.last_token,
195-
stream.upto_token,
190+
stream.current_token(),
196191
)
197192
try:
198193
updates, current_token = await stream.get_updates()

synapse/replication/tcp/streams/_base.py

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
import itertools
1818
import logging
1919
from collections import namedtuple
20-
from typing import Any, List, Optional
20+
from typing import Any, List, Optional, Tuple
2121

2222
import attr
2323

24+
from synapse.types import JsonDict
25+
2426
logger = logging.getLogger(__name__)
2527

2628

@@ -119,13 +121,12 @@ class Stream(object):
119121
"""Base class for the streams.
120122
121123
Provides a `get_updates()` function that returns new updates since the last
122-
time it was called up until the point `advance_current_token` was called.
124+
time it was called.
123125
"""
124126

125127
NAME = None # type: str # The name of the stream
126128
# The type of the row. Used by the default impl of parse_row.
127129
ROW_TYPE = None # type: Any
128-
_LIMITED = True # Whether the update function takes a limit
129130

130131
@classmethod
131132
def parse_row(cls, row):
@@ -146,26 +147,15 @@ def __init__(self, hs):
146147
# The token from which we last asked for updates
147148
self.last_token = self.current_token()
148149

149-
# The token that we will get updates up to
150-
self.upto_token = self.current_token()
151-
152-
def advance_current_token(self):
153-
"""Updates `upto_token` to "now", which updates up until which point
154-
get_updates[_since] will fetch rows till.
155-
"""
156-
self.upto_token = self.current_token()
157-
158150
def discard_updates_and_advance(self):
159151
"""Called when the stream should advance but the updates would be discarded,
160152
e.g. when there are no currently connected workers.
161153
"""
162-
self.upto_token = self.current_token()
163-
self.last_token = self.upto_token
154+
self.last_token = self.current_token()
164155

165156
async def get_updates(self):
166157
"""Gets all updates since the last time this function was called (or
167-
since the stream was constructed if it hadn't been called before),
168-
until the `upto_token`
158+
since the stream was constructed if it hadn't been called before).
169159
170160
Returns:
171161
Deferred[Tuple[List[Tuple[int, Any]], int]:
@@ -178,44 +168,45 @@ async def get_updates(self):
178168

179169
return updates, current_token
180170

181-
async def get_updates_since(self, from_token):
171+
async def get_updates_since(
172+
self, from_token: int
173+
) -> Tuple[List[Tuple[int, JsonDict]], int]:
182174
"""Like get_updates except allows specifying from when we should
183175
stream updates
184176
185177
Returns:
186-
Deferred[Tuple[List[Tuple[int, Any]], int]:
187-
Resolves to a pair ``(updates, current_token)``, where ``updates`` is a
188-
list of ``(token, row)`` entries. ``row`` will be json-serialised and
189-
sent over the replication steam.
178+
Resolves to a pair `(updates, new_last_token)`, where `updates` is
179+
a list of `(token, row)` entries and `new_last_token` is the new
180+
position in stream.
190181
"""
182+
191183
if from_token in ("NOW", "now"):
192-
return [], self.upto_token
184+
return [], self.current_token()
193185

194-
current_token = self.upto_token
186+
current_token = self.current_token()
195187

196188
from_token = int(from_token)
197189

198190
if from_token == current_token:
199191
return [], current_token
200192

201-
logger.info("get_updates_since: %s", self.__class__)
202-
if self._LIMITED:
203-
rows = await self.update_function(
204-
from_token, current_token, limit=MAX_EVENTS_BEHIND + 1
205-
)
193+
rows = await self.update_function(
194+
from_token, current_token, limit=MAX_EVENTS_BEHIND + 1
195+
)
206196

207-
# never turn more than MAX_EVENTS_BEHIND + 1 into updates.
208-
rows = itertools.islice(rows, MAX_EVENTS_BEHIND + 1)
209-
else:
210-
rows = await self.update_function(from_token, current_token)
197+
# never turn more than MAX_EVENTS_BEHIND + 1 into updates.
198+
rows = itertools.islice(rows, MAX_EVENTS_BEHIND + 1)
211199

212200
updates = [(row[0], row[1:]) for row in rows]
213201

214202
# check we didn't get more rows than the limit.
215203
# doing it like this allows the update_function to be a generator.
216-
if self._LIMITED and len(updates) >= MAX_EVENTS_BEHIND:
204+
if len(updates) >= MAX_EVENTS_BEHIND:
217205
raise Exception("stream %s has fallen behind" % (self.NAME))
218206

207+
# The update function didn't hit the limit, so we must have got all
208+
# the updates to `current_token`, and can return that as our new
209+
# stream position.
219210
return updates, current_token
220211

221212
def current_token(self):
@@ -227,9 +218,8 @@ def current_token(self):
227218
"""
228219
raise NotImplementedError()
229220

230-
def update_function(self, from_token, current_token, limit=None):
231-
"""Get updates between from_token and to_token. If Stream._LIMITED is
232-
True then limit is provided, otherwise it's not.
221+
def update_function(self, from_token, current_token, limit):
222+
"""Get updates between from_token and to_token.
233223
234224
Returns:
235225
Deferred(list(tuple)): the first entry in the tuple is the token for
@@ -257,7 +247,6 @@ def __init__(self, hs):
257247

258248
class PresenceStream(Stream):
259249
NAME = "presence"
260-
_LIMITED = False
261250
ROW_TYPE = PresenceStreamRow
262251

263252
def __init__(self, hs):
@@ -272,7 +261,6 @@ def __init__(self, hs):
272261

273262
class TypingStream(Stream):
274263
NAME = "typing"
275-
_LIMITED = False
276264
ROW_TYPE = TypingStreamRow
277265

278266
def __init__(self, hs):
@@ -372,7 +360,6 @@ class DeviceListsStream(Stream):
372360
"""
373361

374362
NAME = "device_lists"
375-
_LIMITED = False
376363
ROW_TYPE = DeviceListsStreamRow
377364

378365
def __init__(self, hs):
@@ -462,7 +449,6 @@ class UserSignatureStream(Stream):
462449
"""
463450

464451
NAME = "user_signature"
465-
_LIMITED = False
466452
ROW_TYPE = UserSignatureStreamRow
467453

468454
def __init__(self, hs):

synapse/storage/data_stores/main/devices.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ def get_users_whose_signatures_changed(self, user_id, from_key):
576576
return set()
577577

578578
async def get_all_device_list_changes_for_remotes(
579-
self, from_key: int, to_key: int
579+
self, from_key: int, to_key: int, limit: int,
580580
) -> List[Tuple[int, str]]:
581581
"""Return a list of `(stream_id, entity)` which is the combined list of
582582
changes to devices and which destinations need to be poked. Entity is
@@ -592,10 +592,16 @@ async def get_all_device_list_changes_for_remotes(
592592
SELECT stream_id, destination AS entity FROM device_lists_outbound_pokes
593593
) AS e
594594
WHERE ? < stream_id AND stream_id <= ?
595+
LIMIT ?
595596
"""
596597

597598
return await self.db.execute(
598-
"get_all_device_list_changes_for_remotes", None, sql, from_key, to_key
599+
"get_all_device_list_changes_for_remotes",
600+
None,
601+
sql,
602+
from_key,
603+
to_key,
604+
limit,
599605
)
600606

601607
@cached(max_entries=10000)

synapse/storage/data_stores/main/end_to_end_keys.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ def get_e2e_cross_signing_keys_bulk(
537537

538538
return result
539539

540-
def get_all_user_signature_changes_for_remotes(self, from_key, to_key):
540+
def get_all_user_signature_changes_for_remotes(self, from_key, to_key, limit):
541541
"""Return a list of changes from the user signature stream to notify remotes.
542542
Note that the user signature stream represents when a user signs their
543543
device with their user-signing key, which is not published to other
@@ -552,13 +552,19 @@ def get_all_user_signature_changes_for_remotes(self, from_key, to_key):
552552
Deferred[list[(int,str)]] a list of `(stream_id, user_id)`
553553
"""
554554
sql = """
555-
SELECT MAX(stream_id) AS stream_id, from_user_id AS user_id
555+
SELECT stream_id, from_user_id AS user_id
556556
FROM user_signature_stream
557557
WHERE ? < stream_id AND stream_id <= ?
558-
GROUP BY user_id
558+
ORDER BY stream_id ASC
559+
LIMIT ?
559560
"""
560561
return self.db.execute(
561-
"get_all_user_signature_changes_for_remotes", None, sql, from_key, to_key
562+
"get_all_user_signature_changes_for_remotes",
563+
None,
564+
sql,
565+
from_key,
566+
to_key,
567+
limit,
562568
)
563569

564570

synapse/storage/data_stores/main/presence.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def _update_presence_txn(self, txn, stream_orderings, presence_states):
6060
"status_msg": state.status_msg,
6161
"currently_active": state.currently_active,
6262
}
63-
for state in presence_states
63+
for stream_id, state in zip(stream_orderings, presence_states)
6464
],
6565
)
6666

@@ -73,19 +73,22 @@ def _update_presence_txn(self, txn, stream_orderings, presence_states):
7373
)
7474
txn.execute(sql + clause, [stream_id] + list(args))
7575

76-
def get_all_presence_updates(self, last_id, current_id):
76+
def get_all_presence_updates(self, last_id, current_id, limit):
7777
if last_id == current_id:
7878
return defer.succeed([])
7979

8080
def get_all_presence_updates_txn(txn):
81-
sql = (
82-
"SELECT stream_id, user_id, state, last_active_ts,"
83-
" last_federation_update_ts, last_user_sync_ts, status_msg,"
84-
" currently_active"
85-
" FROM presence_stream"
86-
" WHERE ? < stream_id AND stream_id <= ?"
87-
)
88-
txn.execute(sql, (last_id, current_id))
81+
sql = """
82+
SELECT stream_id, user_id, state, last_active_ts,
83+
last_federation_update_ts, last_user_sync_ts,
84+
status_msg,
85+
currently_active
86+
FROM presence_stream
87+
WHERE ? < stream_id AND stream_id <= ?
88+
ORDER BY stream_id ASC
89+
LIMIT ?
90+
"""
91+
txn.execute(sql, (last_id, current_id, limit))
8992
return txn.fetchall()
9093

9194
return self.db.runInteraction(

0 commit comments

Comments
 (0)