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

Commit fb7d24a

Browse files
authored
Check that auto_vacuum is disabled when porting a SQLite database to Postgres, as VACUUMs must not be performed between runs of the script. (#13195)
1 parent 57f6f59 commit fb7d24a

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

changelog.d/13195.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Check that `auto_vacuum` is disabled when porting a SQLite database to Postgres, as `VACUUM`s must not be performed between runs of the script.

docs/postgres.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ to do step 2.
143143

144144
It is safe to at any time kill the port script and restart it.
145145

146+
However, under no circumstances should the SQLite database be `VACUUM`ed between
147+
multiple runs of the script. Doing so can lead to an inconsistent copy of your database
148+
into Postgres.
149+
To avoid accidental error, the script will check that SQLite's `auto_vacuum` mechanism
150+
is disabled, but the script is not able to protect against a manual `VACUUM` operation
151+
performed either by the administrator or by any automated task that the administrator
152+
may have configured.
153+
146154
Note that the database may take up significantly more (25% - 100% more)
147155
space on disk after porting to Postgres.
148156

synapse/_scripts/synapse_port_db.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,25 @@ async def run_background_updates_on_postgres(self) -> None:
621621
self.postgres_store.db_pool.updates.has_completed_background_updates()
622622
)
623623

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+
624643
async def run(self) -> None:
625644
"""Ports the SQLite database to a PostgreSQL database.
626645
@@ -637,6 +656,21 @@ async def run(self) -> None:
637656
allow_outdated_version=True,
638657
)
639658

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+
640674
# Check if all background updates are done, abort if not.
641675
updates_complete = (
642676
await self.sqlite_store.db_pool.updates.has_completed_background_updates()

0 commit comments

Comments
 (0)