Fix downgrading to previous version of Synapse (#15907)

We do this by marking the constraint as deferrable.
This commit is contained in:
Erik Johnston 2023-07-10 16:24:42 +01:00 committed by GitHub
parent 6774f265b4
commit e55a9b3e41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 6 deletions

1
changelog.d/15907.misc Normal file
View file

@ -0,0 +1 @@
Add foreign key constraint to `event_forward_extremities`.

View file

@ -80,10 +80,14 @@ class ForeignKeyConstraint(Constraint):
Attributes: Attributes:
referenced_table: The "parent" table name. referenced_table: The "parent" table name.
columns: The list of mappings of columns from table to referenced table columns: The list of mappings of columns from table to referenced table
deferred: Whether to defer checking of the constraint to the end of the
transaction. This is useful for e.g. backwards compatibility where
an older version inserted data in the wrong order.
""" """
referenced_table: str referenced_table: str
columns: Sequence[Tuple[str, str]] columns: Sequence[Tuple[str, str]]
deferred: bool
def make_check_clause(self, table: str) -> str: def make_check_clause(self, table: str) -> str:
join_clause = " AND ".join( join_clause = " AND ".join(
@ -94,7 +98,8 @@ class ForeignKeyConstraint(Constraint):
def make_constraint_clause_postgres(self) -> str: def make_constraint_clause_postgres(self) -> str:
column1_list = ", ".join(col1 for col1, col2 in self.columns) column1_list = ", ".join(col1 for col1, col2 in self.columns)
column2_list = ", ".join(col2 for col1, col2 in self.columns) column2_list = ", ".join(col2 for col1, col2 in self.columns)
return f"FOREIGN KEY ({column1_list}) REFERENCES {self.referenced_table} ({column2_list})" defer_clause = " DEFERRABLE INITIALLY DEFERRED" if self.deferred else ""
return f"FOREIGN KEY ({column1_list}) REFERENCES {self.referenced_table} ({column2_list}) {defer_clause}"
@attr.s(auto_attribs=True) @attr.s(auto_attribs=True)

View file

@ -146,7 +146,9 @@ class EventFederationWorkerStore(SignatureWorkerStore, EventsWorkerStore, SQLBas
update_name="event_forward_extremities_event_id_foreign_key_constraint_update", update_name="event_forward_extremities_event_id_foreign_key_constraint_update",
table="event_forward_extremities", table="event_forward_extremities",
constraint_name="event_forward_extremities_event_id", constraint_name="event_forward_extremities_event_id",
constraint=ForeignKeyConstraint("events", [("event_id", "event_id")]), constraint=ForeignKeyConstraint(
"events", [("event_id", "event_id")], deferred=True
),
unique_columns=("event_id", "room_id"), unique_columns=("event_id", "room_id"),
) )

View file

@ -28,19 +28,25 @@ FORWARD_EXTREMITIES_TABLE_SCHEMA = """
event_id TEXT NOT NULL, event_id TEXT NOT NULL,
room_id TEXT NOT NULL, room_id TEXT NOT NULL,
UNIQUE (event_id, room_id), UNIQUE (event_id, room_id),
CONSTRAINT event_forward_extremities_event_id FOREIGN KEY (event_id) REFERENCES events (event_id) CONSTRAINT event_forward_extremities_event_id FOREIGN KEY (event_id) REFERENCES events (event_id) DEFERRABLE INITIALLY DEFERRED
) )
""" """
def run_create(cur: LoggingTransaction, database_engine: BaseDatabaseEngine) -> None: def run_create(cur: LoggingTransaction, database_engine: BaseDatabaseEngine) -> None:
# We mark this as a deferred constraint, as the previous version of Synapse
# inserted the event into the forward extremities *before* the events table.
# By marking as deferred we ensure that downgrading to the previous version
# will continue to work.
run_validate_constraint_and_delete_rows_schema_delta( run_validate_constraint_and_delete_rows_schema_delta(
cur, cur,
ordering=7803, ordering=7803,
update_name="event_forward_extremities_event_id_foreign_key_constraint_update", update_name="event_forward_extremities_event_id_foreign_key_constraint_update",
table="event_forward_extremities", table="event_forward_extremities",
constraint_name="event_forward_extremities_event_id", constraint_name="event_forward_extremities_event_id",
constraint=ForeignKeyConstraint("events", [("event_id", "event_id")]), constraint=ForeignKeyConstraint(
"events", [("event_id", "event_id")], deferred=True
),
sqlite_table_name="event_forward_extremities2", sqlite_table_name="event_forward_extremities2",
sqlite_table_schema=FORWARD_EXTREMITIES_TABLE_SCHEMA, sqlite_table_schema=FORWARD_EXTREMITIES_TABLE_SCHEMA,
) )

View file

@ -586,7 +586,9 @@ class BackgroundUpdateValidateConstraintTestCase(unittest.HomeserverTestCase):
update_name="test_bg_update", update_name="test_bg_update",
table="test_constraint", table="test_constraint",
constraint_name="test_constraint_name", constraint_name="test_constraint_name",
constraint=ForeignKeyConstraint("base_table", [("b", "b")]), constraint=ForeignKeyConstraint(
"base_table", [("b", "b")], deferred=False
),
sqlite_table_name="test_constraint2", sqlite_table_name="test_constraint2",
sqlite_table_schema=table2_sqlite, sqlite_table_schema=table2_sqlite,
) )
@ -604,7 +606,9 @@ class BackgroundUpdateValidateConstraintTestCase(unittest.HomeserverTestCase):
"test_bg_update", "test_bg_update",
table="test_constraint", table="test_constraint",
constraint_name="test_constraint_name", constraint_name="test_constraint_name",
constraint=ForeignKeyConstraint("base_table", [("b", "b")]), constraint=ForeignKeyConstraint(
"base_table", [("b", "b")], deferred=False
),
unique_columns=["a"], unique_columns=["a"],
) )