Run database updates in a transaction (#8265)

Fixes: #6467
This commit is contained in:
Richard van der Hoff 2020-09-07 11:41:50 +01:00 committed by GitHub
parent 765437df54
commit 5b452df23b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 5 deletions

1
changelog.d/8265.bugfix Normal file
View file

@ -0,0 +1 @@
Fix logstanding bug which could lead to incomplete database upgrades on SQLite.

View file

@ -19,12 +19,15 @@ import logging
import os import os
import re import re
from collections import Counter from collections import Counter
from typing import TextIO from typing import Optional, TextIO
import attr import attr
from synapse.config.homeserver import HomeServerConfig
from synapse.storage.engines import BaseDatabaseEngine
from synapse.storage.engines.postgres import PostgresEngine from synapse.storage.engines.postgres import PostgresEngine
from synapse.storage.types import Cursor from synapse.storage.types import Connection, Cursor
from synapse.types import Collection
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -47,7 +50,12 @@ class UpgradeDatabaseException(PrepareDatabaseException):
pass pass
def prepare_database(db_conn, database_engine, config, databases=["main", "state"]): def prepare_database(
db_conn: Connection,
database_engine: BaseDatabaseEngine,
config: Optional[HomeServerConfig],
databases: Collection[str] = ["main", "state"],
):
"""Prepares a physical database for usage. Will either create all necessary tables """Prepares a physical database for usage. Will either create all necessary tables
or upgrade from an older schema version. or upgrade from an older schema version.
@ -57,15 +65,24 @@ def prepare_database(db_conn, database_engine, config, databases=["main", "state
Args: Args:
db_conn: db_conn:
database_engine: database_engine:
config (synapse.config.homeserver.HomeServerConfig|None): config :
application config, or None if we are connecting to an existing application config, or None if we are connecting to an existing
database which we expect to be configured already database which we expect to be configured already
databases (list[str]): The name of the databases that will be used databases: The name of the databases that will be used
with this physical database. Defaults to all databases. with this physical database. Defaults to all databases.
""" """
try: try:
cur = db_conn.cursor() cur = db_conn.cursor()
# sqlite does not automatically start transactions for DDL / SELECT statements,
# so we start one before running anything. This ensures that any upgrades
# are either applied completely, or not at all.
#
# (psycopg2 automatically starts a transaction as soon as we run any statements
# at all, so this is redundant but harmless there.)
cur.execute("BEGIN TRANSACTION")
version_info = _get_or_create_schema_state(cur, database_engine) version_info = _get_or_create_schema_state(cur, database_engine)
if version_info: if version_info: