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

Commit 57f18fb

Browse files
committed
Automatically port sqlite indexes
1 parent 9186dcf commit 57f18fb

File tree

3 files changed

+44
-24
lines changed

3 files changed

+44
-24
lines changed

synapse/storage/background_updates.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import abc
1515
import logging
1616
from enum import Enum, IntEnum
17-
from io import StringIO
1817
from types import TracebackType
1918
from typing import (
2019
TYPE_CHECKING,
@@ -1055,15 +1054,15 @@ def run_validate_constraint_and_delete_rows_schema_delta(
10551054
constraint: Constraint,
10561055
sqlite_table_name: str,
10571056
sqlite_table_schema: str,
1058-
sqlite_post_schema: Optional[str],
10591057
) -> None:
10601058
"""Runs a schema delta to add a constraint to the table. This should be run
10611059
in a schema delta file.
10621060
10631061
For PostgreSQL the constraint is added and validated in the background.
10641062
10651063
For SQLite the table is recreated and data copied across immediately. This
1066-
is done by the caller passing in a script to create the new table.
1064+
is done by the caller passing in a script to create the new table. Note that
1065+
table indexes and triggers are copied over automatically.
10671066
10681067
There must be a corresponding call to
10691068
`register_background_validate_constraint_and_delete_rows` to register the
@@ -1075,8 +1074,6 @@ def run_validate_constraint_and_delete_rows_schema_delta(
10751074
new constraint constraint: A `Constraint` object describing the
10761075
constraint sqlite_table_name: For SQLite the name of the empty copy of
10771076
table sqlite_table_schema: A SQL script for creating the above table.
1078-
sqlite_post_schema: A SQL script run after migration, to add back
1079-
indices and the like.
10801077
"""
10811078

10821079
if isinstance(txn.database_engine, PostgresEngine):
@@ -1097,14 +1094,25 @@ def run_validate_constraint_and_delete_rows_schema_delta(
10971094
)
10981095
else:
10991096
# For SQLite, we:
1100-
# 1. create an empty copy of the table
1101-
# 2. copy across the rows (that satisfy the check)
1102-
# 3. replace the old table with the new able.
1103-
1104-
# We import this here to avoid circular imports.
1105-
from synapse.storage.prepare_database import execute_statements_from_stream
1097+
# 1. fetch all indexes/triggers/etc related to the table
1098+
# 2. create an empty copy of the table
1099+
# 3. copy across the rows (that satisfy the check)
1100+
# 4. replace the old table with the new able.
1101+
# 5. add back all the indexes/triggers/etc
1102+
1103+
# Fetch the indexes/triggers/etc. Note that `sql` column being null is
1104+
# due to indexes being auto created based on the class definition (e.g.
1105+
# PRIMARY KEY), and so don't need to be recreated.
1106+
txn.execute(
1107+
"""
1108+
SELECT sql FROM sqlite_schema
1109+
WHERE tbl_name = ? AND type != 'table' AND sql IS NOT NULL
1110+
""",
1111+
(table,),
1112+
)
1113+
extras = [row[0] for row in txn]
11061114

1107-
execute_statements_from_stream(txn, StringIO(sqlite_table_schema))
1115+
txn.execute(sqlite_table_schema)
11081116

11091117
sql = f"""
11101118
INSERT INTO {sqlite_table_name} SELECT * FROM {table}
@@ -1116,5 +1124,5 @@ def run_validate_constraint_and_delete_rows_schema_delta(
11161124
txn.execute(f"DROP TABLE {table}")
11171125
txn.execute(f"ALTER TABLE {sqlite_table_name} RENAME TO {table}")
11181126

1119-
if sqlite_post_schema:
1120-
execute_statements_from_stream(txn, StringIO(sqlite_post_schema))
1127+
for extra in extras:
1128+
txn.execute(extra)

synapse/storage/schema/main/delta/78/03event_extremities_constraints.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,7 @@
2929
room_id TEXT NOT NULL,
3030
UNIQUE (event_id, room_id),
3131
CONSTRAINT event_forward_extremities_event_id FOREIGN KEY (event_id) REFERENCES events (event_id)
32-
);
33-
"""
34-
35-
FORWARD_EXTREMITIES_INDICES_SCHEMA = """
36-
CREATE INDEX ev_extrem_room ON event_forward_extremities(room_id);
37-
CREATE INDEX ev_extrem_id ON event_forward_extremities(event_id);
32+
)
3833
"""
3934

4035

@@ -48,7 +43,6 @@ def run_create(cur: LoggingTransaction, database_engine: BaseDatabaseEngine) ->
4843
constraint=ForeignKeyConstraint("events", [("event_id", "event_id")]),
4944
sqlite_table_name="event_forward_extremities2",
5045
sqlite_table_schema=FORWARD_EXTREMITIES_TABLE_SCHEMA,
51-
sqlite_post_schema=FORWARD_EXTREMITIES_INDICES_SCHEMA,
5246
)
5347

5448
# We can't add a similar constraint to `event_backward_extremities` as the

tests/storage/test_background_update.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
run_validate_constraint_and_delete_rows_schema_delta,
2828
)
2929
from synapse.storage.database import LoggingTransaction
30-
from synapse.storage.engines import PostgresEngine
30+
from synapse.storage.engines import PostgresEngine, Sqlite3Engine
3131
from synapse.types import JsonDict
3232
from synapse.util import Clock
3333

@@ -440,6 +440,15 @@ def test_not_null_constraint(self) -> None:
440440
)
441441
)
442442

443+
# We add an index so that we can check that its correctly recreated when
444+
# using SQLite.
445+
index_sql = "CREATE INDEX test_index ON test_constraint(a)"
446+
self.get_success(
447+
self.store.db_pool.execute(
448+
"test_not_null_constraint", lambda _: None, index_sql
449+
)
450+
)
451+
443452
self.get_success(
444453
self.store.db_pool.simple_insert("test_constraint", {"a": 1, "b": 1})
445454
)
@@ -470,7 +479,6 @@ def delta(txn: LoggingTransaction) -> None:
470479
constraint=NotNullConstraint("b"),
471480
sqlite_table_name="test_constraint2",
472481
sqlite_table_schema=table2_sqlite,
473-
sqlite_post_schema=None,
474482
)
475483

476484
self.get_success(
@@ -513,6 +521,17 @@ def delta(txn: LoggingTransaction) -> None:
513521
exc=self.store.database_engine.module.IntegrityError,
514522
)
515523

524+
# Check the index is still there for SQLite.
525+
if isinstance(self.store.database_engine, Sqlite3Engine):
526+
# Ensure the index exists in the schema.
527+
self.get_success(
528+
self.store.db_pool.simple_select_one_onecol(
529+
table="sqlite_schema",
530+
keyvalues={"tbl_name": "test_constraint"},
531+
retcol="name",
532+
)
533+
)
534+
516535
def test_foreign_constraint(self) -> None:
517536
"""Tests adding a not foreign key constraint."""
518537

@@ -570,7 +589,6 @@ def delta(txn: LoggingTransaction) -> None:
570589
constraint=ForeignKeyConstraint("base_table", [("b", "b")]),
571590
sqlite_table_name="test_constraint2",
572591
sqlite_table_schema=table2_sqlite,
573-
sqlite_post_schema=None,
574592
)
575593

576594
self.get_success(

0 commit comments

Comments
 (0)