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

Commit

Permalink
Fix downgrading to previous version of Synapse (#15907)
Browse files Browse the repository at this point in the history
We do this by marking the constraint as deferrable.
  • Loading branch information
erikjohnston authored Jul 10, 2023
1 parent 6774f26 commit e55a9b3
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 6 deletions.
1 change: 1 addition & 0 deletions changelog.d/15907.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add foreign key constraint to `event_forward_extremities`.
7 changes: 6 additions & 1 deletion synapse/storage/background_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,14 @@ class ForeignKeyConstraint(Constraint):
Attributes:
referenced_table: The "parent" table name.
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
columns: Sequence[Tuple[str, str]]
deferred: bool

def make_check_clause(self, table: str) -> str:
join_clause = " AND ".join(
Expand All @@ -94,7 +98,8 @@ def make_check_clause(self, table: str) -> str:
def make_constraint_clause_postgres(self) -> str:
column1_list = ", ".join(col1 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)
Expand Down
4 changes: 3 additions & 1 deletion synapse/storage/databases/main/event_federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ def __init__(
update_name="event_forward_extremities_event_id_foreign_key_constraint_update",
table="event_forward_extremities",
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"),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,25 @@
event_id TEXT NOT NULL,
room_id TEXT NOT NULL,
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:
# 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(
cur,
ordering=7803,
update_name="event_forward_extremities_event_id_foreign_key_constraint_update",
table="event_forward_extremities",
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_schema=FORWARD_EXTREMITIES_TABLE_SCHEMA,
)
Expand Down
8 changes: 6 additions & 2 deletions tests/storage/test_background_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,9 @@ def delta(txn: LoggingTransaction) -> None:
update_name="test_bg_update",
table="test_constraint",
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_schema=table2_sqlite,
)
Expand All @@ -604,7 +606,9 @@ def delta(txn: LoggingTransaction) -> None:
"test_bg_update",
table="test_constraint",
constraint_name="test_constraint_name",
constraint=ForeignKeyConstraint("base_table", [("b", "b")]),
constraint=ForeignKeyConstraint(
"base_table", [("b", "b")], deferred=False
),
unique_columns=["a"],
)

Expand Down

0 comments on commit e55a9b3

Please sign in to comment.