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

Commit

Permalink
Use READ COMMITTED isolation level when purging rooms (#12942)
Browse files Browse the repository at this point in the history
To close: #10294.

Signed off by Nick @ Beeper.
  • Loading branch information
Fizzadar authored Jul 18, 2022
1 parent c5f487b commit 6785b0f
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog.d/12942.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Use lower isolation level when purging rooms to avoid serialization errors. Contributed by Nick @ Beeper.
33 changes: 31 additions & 2 deletions synapse/storage/databases/main/purge_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from synapse.storage.database import LoggingTransaction
from synapse.storage.databases.main import CacheInvalidationWorkerStore
from synapse.storage.databases.main.state import StateGroupWorkerStore
from synapse.storage.engines import PostgresEngine
from synapse.storage.engines._base import IsolationLevel
from synapse.types import RoomStreamToken

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -317,11 +319,38 @@ async def purge_room(self, room_id: str) -> List[int]:
Returns:
The list of state groups to delete.
"""
return await self.db_pool.runInteraction(
"purge_room", self._purge_room_txn, room_id

# This first runs the purge transaction with READ_COMMITTED isolation level,
# meaning any new rows in the tables will not trigger a serialization error.
# We then run the same purge a second time without this isolation level to
# purge any of those rows which were added during the first.

state_groups_to_delete = await self.db_pool.runInteraction(
"purge_room",
self._purge_room_txn,
room_id=room_id,
isolation_level=IsolationLevel.READ_COMMITTED,
)

state_groups_to_delete.extend(
await self.db_pool.runInteraction(
"purge_room",
self._purge_room_txn,
room_id=room_id,
),
)

return state_groups_to_delete

def _purge_room_txn(self, txn: LoggingTransaction, room_id: str) -> List[int]:
# This collides with event persistence so we cannot write new events and metadata into
# a room while deleting it or this transaction will fail.
if isinstance(self.database_engine, PostgresEngine):
txn.execute(
"SELECT room_version FROM rooms WHERE room_id = ? FOR UPDATE",
(room_id,),
)

# First, fetch all the state groups that should be deleted, before
# we delete that information.
txn.execute(
Expand Down

0 comments on commit 6785b0f

Please sign in to comment.