summary refs log tree commit diff
path: root/synapse/storage
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/storage')
-rw-r--r--synapse/storage/background_updates.py7
-rw-r--r--synapse/storage/databases/main/event_federation.py4
-rw-r--r--synapse/storage/schema/main/delta/78/03event_extremities_constraints.py10
3 files changed, 17 insertions, 4 deletions
diff --git a/synapse/storage/background_updates.py b/synapse/storage/background_updates.py
index 5dce0a0159..2d5ddc3e7b 100644
--- a/synapse/storage/background_updates.py
+++ b/synapse/storage/background_updates.py
@@ -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(
@@ -94,7 +98,8 @@ class ForeignKeyConstraint(Constraint):
     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)
diff --git a/synapse/storage/databases/main/event_federation.py b/synapse/storage/databases/main/event_federation.py
index dabe603c8c..b2cda52ce5 100644
--- a/synapse/storage/databases/main/event_federation.py
+++ b/synapse/storage/databases/main/event_federation.py
@@ -146,7 +146,9 @@ class EventFederationWorkerStore(SignatureWorkerStore, EventsWorkerStore, SQLBas
                 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"),
             )
 
diff --git a/synapse/storage/schema/main/delta/78/03event_extremities_constraints.py b/synapse/storage/schema/main/delta/78/03event_extremities_constraints.py
index f12e2a8f3e..bf8c57dbe8 100644
--- a/synapse/storage/schema/main/delta/78/03event_extremities_constraints.py
+++ b/synapse/storage/schema/main/delta/78/03event_extremities_constraints.py
@@ -28,19 +28,25 @@ FORWARD_EXTREMITIES_TABLE_SCHEMA = """
         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,
     )