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

Commit 800ba87

Browse files
authored
Refactor and convert Linearizer to async (#12357)
Refactor and convert `Linearizer` to async. This makes a `Linearizer` cancellation bug easier to fix. Also refactor to use an async context manager, which eliminates an unlikely footgun where code that doesn't immediately use the context manager could forget to release the lock. Signed-off-by: Sean Quah <[email protected]>
1 parent ab3fdcf commit 800ba87

File tree

21 files changed

+104
-115
lines changed

21 files changed

+104
-115
lines changed

changelog.d/12357.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Refactor `Linearizer`, convert methods to async and use an async context manager.

synapse/federation/federation_server.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ async def _handle_old_staged_events(self) -> None:
188188
async def on_backfill_request(
189189
self, origin: str, room_id: str, versions: List[str], limit: int
190190
) -> Tuple[int, Dict[str, Any]]:
191-
with (await self._server_linearizer.queue((origin, room_id))):
191+
async with self._server_linearizer.queue((origin, room_id)):
192192
origin_host, _ = parse_server_name(origin)
193193
await self.check_server_matches_acl(origin_host, room_id)
194194

@@ -218,7 +218,7 @@ async def on_timestamp_to_event_request(
218218
Tuple indicating the response status code and dictionary response
219219
body including `event_id`.
220220
"""
221-
with (await self._server_linearizer.queue((origin, room_id))):
221+
async with self._server_linearizer.queue((origin, room_id)):
222222
origin_host, _ = parse_server_name(origin)
223223
await self.check_server_matches_acl(origin_host, room_id)
224224

@@ -529,7 +529,7 @@ async def on_room_state_request(
529529
# in the cache so we could return it without waiting for the linearizer
530530
# - but that's non-trivial to get right, and anyway somewhat defeats
531531
# the point of the linearizer.
532-
with (await self._server_linearizer.queue((origin, room_id))):
532+
async with self._server_linearizer.queue((origin, room_id)):
533533
resp: JsonDict = dict(
534534
await self._state_resp_cache.wrap(
535535
(room_id, event_id),
@@ -883,7 +883,7 @@ async def _on_send_membership_event(
883883
async def on_event_auth(
884884
self, origin: str, room_id: str, event_id: str
885885
) -> Tuple[int, Dict[str, Any]]:
886-
with (await self._server_linearizer.queue((origin, room_id))):
886+
async with self._server_linearizer.queue((origin, room_id)):
887887
origin_host, _ = parse_server_name(origin)
888888
await self.check_server_matches_acl(origin_host, room_id)
889889

@@ -945,7 +945,7 @@ async def on_get_missing_events(
945945
latest_events: List[str],
946946
limit: int,
947947
) -> Dict[str, list]:
948-
with (await self._server_linearizer.queue((origin, room_id))):
948+
async with self._server_linearizer.queue((origin, room_id)):
949949
origin_host, _ = parse_server_name(origin)
950950
await self.check_server_matches_acl(origin_host, room_id)
951951

synapse/handlers/appservice.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,10 +330,8 @@ async def _notify_interested_services_ephemeral(
330330
continue
331331

332332
# Since we read/update the stream position for this AS/stream
333-
with (
334-
await self._ephemeral_events_linearizer.queue(
335-
(service.id, stream_key)
336-
)
333+
async with self._ephemeral_events_linearizer.queue(
334+
(service.id, stream_key)
337335
):
338336
if stream_key == "receipt_key":
339337
events = await self._handle_receipts(service, new_token)

synapse/handlers/device.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ async def incoming_device_list_update(
833833
async def _handle_device_updates(self, user_id: str) -> None:
834834
"Actually handle pending updates."
835835

836-
with (await self._remote_edu_linearizer.queue(user_id)):
836+
async with self._remote_edu_linearizer.queue(user_id):
837837
pending_updates = self._pending_updates.pop(user_id, [])
838838
if not pending_updates:
839839
# This can happen since we batch updates

synapse/handlers/e2e_keys.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ async def query_devices(
118118
from_device_id: the device making the query. This is used to limit
119119
the number of in-flight queries at a time.
120120
"""
121-
with await self._query_devices_linearizer.queue((from_user_id, from_device_id)):
121+
async with self._query_devices_linearizer.queue((from_user_id, from_device_id)):
122122
device_keys_query: Dict[str, Iterable[str]] = query_body.get(
123123
"device_keys", {}
124124
)
@@ -1386,7 +1386,7 @@ async def _handle_signing_key_updates(self, user_id: str) -> None:
13861386
device_handler = self.e2e_keys_handler.device_handler
13871387
device_list_updater = device_handler.device_list_updater
13881388

1389-
with (await self._remote_edu_linearizer.queue(user_id)):
1389+
async with self._remote_edu_linearizer.queue(user_id):
13901390
pending_updates = self._pending_updates.pop(user_id, [])
13911391
if not pending_updates:
13921392
# This can happen since we batch updates

synapse/handlers/e2e_room_keys.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ async def get_room_keys(
8383

8484
# we deliberately take the lock to get keys so that changing the version
8585
# works atomically
86-
with (await self._upload_linearizer.queue(user_id)):
86+
async with self._upload_linearizer.queue(user_id):
8787
# make sure the backup version exists
8888
try:
8989
await self.store.get_e2e_room_keys_version_info(user_id, version)
@@ -126,7 +126,7 @@ async def delete_room_keys(
126126
"""
127127

128128
# lock for consistency with uploading
129-
with (await self._upload_linearizer.queue(user_id)):
129+
async with self._upload_linearizer.queue(user_id):
130130
# make sure the backup version exists
131131
try:
132132
version_info = await self.store.get_e2e_room_keys_version_info(
@@ -187,7 +187,7 @@ async def upload_room_keys(
187187
# TODO: Validate the JSON to make sure it has the right keys.
188188

189189
# XXX: perhaps we should use a finer grained lock here?
190-
with (await self._upload_linearizer.queue(user_id)):
190+
async with self._upload_linearizer.queue(user_id):
191191

192192
# Check that the version we're trying to upload is the current version
193193
try:
@@ -332,7 +332,7 @@ async def create_version(self, user_id: str, version_info: JsonDict) -> str:
332332
# TODO: Validate the JSON to make sure it has the right keys.
333333

334334
# lock everyone out until we've switched version
335-
with (await self._upload_linearizer.queue(user_id)):
335+
async with self._upload_linearizer.queue(user_id):
336336
new_version = await self.store.create_e2e_room_keys_version(
337337
user_id, version_info
338338
)
@@ -359,7 +359,7 @@ async def get_version_info(
359359
}
360360
"""
361361

362-
with (await self._upload_linearizer.queue(user_id)):
362+
async with self._upload_linearizer.queue(user_id):
363363
try:
364364
res = await self.store.get_e2e_room_keys_version_info(user_id, version)
365365
except StoreError as e:
@@ -383,7 +383,7 @@ async def delete_version(self, user_id: str, version: Optional[str] = None) -> N
383383
NotFoundError: if this backup version doesn't exist
384384
"""
385385

386-
with (await self._upload_linearizer.queue(user_id)):
386+
async with self._upload_linearizer.queue(user_id):
387387
try:
388388
await self.store.delete_e2e_room_keys_version(user_id, version)
389389
except StoreError as e:
@@ -413,7 +413,7 @@ async def update_version(
413413
raise SynapseError(
414414
400, "Version in body does not match", Codes.INVALID_PARAM
415415
)
416-
with (await self._upload_linearizer.queue(user_id)):
416+
async with self._upload_linearizer.queue(user_id):
417417
try:
418418
old_info = await self.store.get_e2e_room_keys_version_info(
419419
user_id, version

synapse/handlers/federation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ async def maybe_backfill(
151151
return. This is used as part of the heuristic to decide if we
152152
should back paginate.
153153
"""
154-
with (await self._room_backfill.queue(room_id)):
154+
async with self._room_backfill.queue(room_id):
155155
return await self._maybe_backfill_inner(room_id, current_depth, limit)
156156

157157
async def _maybe_backfill_inner(

synapse/handlers/federation_event.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ async def on_receive_pdu(self, origin: str, pdu: EventBase) -> None:
224224
len(missing_prevs),
225225
shortstr(missing_prevs),
226226
)
227-
with (await self._room_pdu_linearizer.queue(pdu.room_id)):
227+
async with self._room_pdu_linearizer.queue(pdu.room_id):
228228
logger.info(
229229
"Acquired room lock to fetch %d missing prev_events",
230230
len(missing_prevs),

synapse/handlers/message.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ async def create_and_send_nonmember_event(
851851
# a situation where event persistence can't keep up, causing
852852
# extremities to pile up, which in turn leads to state resolution
853853
# taking longer.
854-
with (await self.limiter.queue(event_dict["room_id"])):
854+
async with self.limiter.queue(event_dict["room_id"]):
855855
if txn_id and requester.access_token_id:
856856
existing_event_id = await self.store.get_event_id_from_transaction_id(
857857
event_dict["room_id"],

synapse/handlers/presence.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,7 @@ async def update_external_syncs_row(
10301030
is_syncing: Whether or not the user is now syncing
10311031
sync_time_msec: Time in ms when the user was last syncing
10321032
"""
1033-
with (await self.external_sync_linearizer.queue(process_id)):
1033+
async with self.external_sync_linearizer.queue(process_id):
10341034
prev_state = await self.current_state_for_user(user_id)
10351035

10361036
process_presence = self.external_process_to_current_syncs.setdefault(
@@ -1071,7 +1071,7 @@ async def update_external_syncs_clear(self, process_id: str) -> None:
10711071
10721072
Used when the process has stopped/disappeared.
10731073
"""
1074-
with (await self.external_sync_linearizer.queue(process_id)):
1074+
async with self.external_sync_linearizer.queue(process_id):
10751075
process_presence = self.external_process_to_current_syncs.pop(
10761076
process_id, set()
10771077
)

0 commit comments

Comments
 (0)