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

Override global statement timeout when creating indexes in Postgres #16085

Merged
merged 5 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/16085.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Override global statement timeout when creating indexes in Postgres.
11 changes: 11 additions & 0 deletions synapse/storage/background_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ class BackgroundUpdater:
def __init__(self, hs: "HomeServer", database: "DatabasePool"):
self._clock = hs.get_clock()
self.db_pool = database
self.hs = hs

self._database_name = database.name()

Expand Down Expand Up @@ -758,6 +759,11 @@ def create_index_psql(conn: Connection) -> None:
logger.debug("[SQL] %s", sql)
c.execute(sql)

# override the global statement timeout to avoid accidentally squashing
# a long-running index creation process
timeout_sql = "SET SESSION statement_timeout = 0"
c.execute(timeout_sql)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to set this back to the default, as we're not in a transaction when creating indices I think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the autocommit being on the reason that this isn't in a transaction? The statement timeout only applies for a given transaction - if we are not in a transaction then I wonder if it will have any effect. I will do some digging in the docs but they were pretty scarce on information when I looked into this the first time. Do we have any Postgres/psychopg wizards around who might have some arcane insight into this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the autocommit being on the reason that this isn't in a transaction?

Yes

The statement timeout only applies for a given transaction - if we are not in a transaction then I wonder if it will have any effect.

https://www.postgresql.org/docs/current/sql-set.html says that LOCAL doesn't work outside a transaction, and so we'd need to use SESSION


sql = (
"CREATE %(unique)s INDEX CONCURRENTLY %(name)s"
" ON %(table)s"
Expand All @@ -772,6 +778,11 @@ def create_index_psql(conn: Connection) -> None:
logger.debug("[SQL] %s", sql)
c.execute(sql)

# mypy ignore - `statement_timeout` is defined on PostgresEngine
default_timeout = self.db_pool.engine.statement_timeout # type: ignore[attr-defined]
undo_timeout_sql = f"SET statement_timeout = {default_timeout}"
c.execute(undo_timeout_sql)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be in finally section, so if happens even if index creation raises an exception


if replaces_index is not None:
# We drop the old index as the new index has now been created.
sql = f"DROP INDEX IF EXISTS {replaces_index}"
Expand Down