@@ -1745,16 +1745,21 @@ def get_devices_not_accessed_since_txn(
17451745
17461746 return devices
17471747
1748- def _get_min_device_lists_changes_in_room_txn (self , txn : LoggingTransaction ) -> int :
1749- """Returns the minimum stream ID that we have entries for
1750- `device_lists_changes_in_room`
1748+ def _get_max_pruned_device_lists_changes_in_room_txn (
1749+ self , txn : LoggingTransaction
1750+ ) -> int :
1751+ """Returns the maximum stream ID that has been pruned from
1752+ `device_lists_changes_in_room`.
1753+
1754+ Any queries for stream IDs less than this value cannot be answered
1755+ completely, as the data has been deleted.
17511756 """
17521757
17531758 return self .db_pool .simple_select_one_onecol_txn (
17541759 txn ,
1755- table = "device_lists_changes_in_room " ,
1760+ table = "device_lists_changes_in_room_max_pruned_stream_id " ,
17561761 keyvalues = {},
1757- retcol = "COALESCE(MIN( stream_id), 0) " ,
1762+ retcol = "stream_id" ,
17581763 allow_none = False ,
17591764 )
17601765
@@ -1783,9 +1788,11 @@ async def get_device_list_changes_in_rooms(
17831788 def _get_device_list_changes_in_rooms_txn (
17841789 txn : LoggingTransaction ,
17851790 ) -> set [str ] | None :
1786- # Check if the from_token is too old.
1787- lowest_known_stream_id = self ._get_min_device_lists_changes_in_room_txn (txn )
1788- if lowest_known_stream_id > from_token .stream :
1791+ # Check if the from_token is too old (i.e. data has been pruned).
1792+ max_pruned_stream_id = (
1793+ self ._get_max_pruned_device_lists_changes_in_room_txn (txn )
1794+ )
1795+ if max_pruned_stream_id > from_token .stream :
17891796 return None
17901797
17911798 changes : set [str ] = set ()
@@ -1831,10 +1838,16 @@ async def get_all_device_list_changes(self, from_id: int, to_id: int) -> set[str
18311838 def _get_all_device_list_changes_txn (
18321839 txn : LoggingTransaction ,
18331840 ) -> set [str ] | None :
1834- # Check if the from_token is too old. We do this each time as we may
1835- # prune the table in between runs.
1836- lowest_known_stream_id = self ._get_min_device_lists_changes_in_room_txn (txn )
1837- if lowest_known_stream_id > from_id :
1841+ # Check if the from_token is too old (i.e. data has been pruned).
1842+ max_pruned_stream_id = (
1843+ self ._get_max_pruned_device_lists_changes_in_room_txn (txn )
1844+ )
1845+ if max_pruned_stream_id > from_id :
1846+ logger .warning (
1847+ "Given stream ID is too old %d < %d" ,
1848+ from_id ,
1849+ max_pruned_stream_id ,
1850+ )
18381851 return None
18391852
18401853 sql = """
@@ -1851,7 +1864,7 @@ def _get_all_device_list_changes_txn(
18511864 )
18521865
18531866 if room_ids is None :
1854- raise Exception ("Given stream ID is too old" )
1867+ raise Exception (f "Given stream ID is too old { from_id } " )
18551868
18561869 return room_ids
18571870
@@ -1870,9 +1883,11 @@ async def get_device_list_changes_in_room(
18701883 def get_device_list_changes_in_room_txn (
18711884 txn : LoggingTransaction ,
18721885 ) -> Collection [tuple [str , str ]] | None :
1873- # Check if the from_token is too old.
1874- lowest_known_stream_id = self ._get_min_device_lists_changes_in_room_txn (txn )
1875- if lowest_known_stream_id > min_stream_id :
1886+ # Check if the from_token is too old (i.e. data has been pruned).
1887+ max_pruned_stream_id = (
1888+ self ._get_max_pruned_device_lists_changes_in_room_txn (txn )
1889+ )
1890+ if max_pruned_stream_id > min_stream_id :
18761891 return None
18771892
18781893 sql = """
@@ -2511,10 +2526,9 @@ def get_prune_before_stream_id_txn(txn: LoggingTransaction) -> int | None:
25112526 if prune_before_stream_id is None :
25122527 return
25132528
2514- # Get the max stream ID that we have in the table, so that we avoid
2515- # deleting it. We want to keep the max stream ID so that the minimum
2516- # stream ID can be calculated in
2517- # `_get_min_device_lists_changes_in_room`.
2529+ # Get the max stream ID in the table so we avoid deleting it. We need
2530+ # to keep the latest row so that we can calculate the maximum stream ID
2531+ # used.
25182532 max_stream_id = await self .db_pool .simple_select_one_onecol (
25192533 table = "device_lists_changes_in_room" ,
25202534 keyvalues = {},
@@ -2586,6 +2600,15 @@ def prune_device_lists_changes_in_room_txn(txn: LoggingTransaction) -> int:
25862600 await self .clock .sleep (Duration (milliseconds = 100 ))
25872601
25882602 if num_rows_deleted :
2603+ # Update the max pruned stream ID tracking table so that the
2604+ # safety check knows data up to this point has been deleted.
2605+ await self .db_pool .simple_update_one (
2606+ table = "device_lists_changes_in_room_max_pruned_stream_id" ,
2607+ keyvalues = {},
2608+ updatevalues = {"stream_id" : prune_before_stream_id },
2609+ desc = "prune_device_lists_changes_in_room_update_max_pruned" ,
2610+ )
2611+
25892612 logger .info (
25902613 "Pruned %d rows from device_lists_changes_in_room" , num_rows_deleted
25912614 )
0 commit comments