@@ -621,6 +621,25 @@ async def run_background_updates_on_postgres(self) -> None:
621
621
self .postgres_store .db_pool .updates .has_completed_background_updates ()
622
622
)
623
623
624
+ @staticmethod
625
+ def _is_sqlite_autovacuum_enabled (txn : LoggingTransaction ) -> bool :
626
+ """
627
+ Returns true if auto_vacuum is enabled in SQLite.
628
+ https://www.sqlite.org/pragma.html#pragma_auto_vacuum
629
+
630
+ Vacuuming changes the rowids on rows in the database.
631
+ Auto-vacuuming is therefore dangerous when used in conjunction with this script.
632
+
633
+ Note that the auto_vacuum setting can't be changed without performing
634
+ a VACUUM after trying to change the pragma.
635
+ """
636
+ txn .execute ("PRAGMA auto_vacuum" )
637
+ row = txn .fetchone ()
638
+ assert row is not None , "`PRAGMA auto_vacuum` did not give a row."
639
+ (autovacuum_setting ,) = row
640
+ # 0 means off. 1 means full. 2 means incremental.
641
+ return autovacuum_setting != 0
642
+
624
643
async def run (self ) -> None :
625
644
"""Ports the SQLite database to a PostgreSQL database.
626
645
@@ -637,6 +656,21 @@ async def run(self) -> None:
637
656
allow_outdated_version = True ,
638
657
)
639
658
659
+ # For safety, ensure auto_vacuums are disabled.
660
+ if await self .sqlite_store .db_pool .runInteraction (
661
+ "is_sqlite_autovacuum_enabled" , self ._is_sqlite_autovacuum_enabled
662
+ ):
663
+ end_error = (
664
+ "auto_vacuum is enabled in the SQLite database."
665
+ " (This is not the default configuration.)\n "
666
+ " This script relies on rowids being consistent and must not"
667
+ " be used if the database could be vacuumed between re-runs.\n "
668
+ " To disable auto_vacuum, you need to stop Synapse and run the following SQL:\n "
669
+ " PRAGMA auto_vacuum=off;\n "
670
+ " VACUUM;"
671
+ )
672
+ return
673
+
640
674
# Check if all background updates are done, abort if not.
641
675
updates_complete = (
642
676
await self .sqlite_store .db_pool .updates .has_completed_background_updates ()
0 commit comments