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

Commit

Permalink
Fix 'no unique or exclusion constraint' error (#4591)
Browse files Browse the repository at this point in the history
Add more tables to the list of tables which need a background update to
complete before we can upsert into them, which fixes a race against the
background updates.
  • Loading branch information
richvdh authored Feb 8, 2019
1 parent 9cd33d2 commit 56710c7
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 6 deletions.
1 change: 1 addition & 0 deletions changelog.d/4591.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix 'no unique or exclusion constraint' error
27 changes: 21 additions & 6 deletions synapse/storage/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@
sql_txn_timer = Histogram("synapse_storage_transaction_time", "sec", ["desc"])


# Unique indexes which have been added in background updates. Maps from table name
# to the name of the background update which added the unique index to that table.
#
# This is used by the upsert logic to figure out which tables are safe to do a proper
# UPSERT on: until the relevant background update has completed, we
# have to emulate an upsert by locking the table.
#
UNIQUE_INDEX_BACKGROUND_UPDATES = {
"user_ips": "user_ips_device_unique_index",
"device_lists_remote_extremeties": "device_lists_remote_extremeties_unique_idx",
"device_lists_remote_cache": "device_lists_remote_cache_unique_idx",
"event_search": "event_search_event_id_idx",
}


class LoggingTransaction(object):
"""An object that almost-transparently proxies for the 'txn' object
passed to the constructor. Adds logging and metrics to the .execute()
Expand Down Expand Up @@ -194,7 +209,7 @@ def __init__(self, db_conn, hs):
self.database_engine = hs.database_engine

# A set of tables that are not safe to use native upserts in.
self._unsafe_to_upsert_tables = {"user_ips"}
self._unsafe_to_upsert_tables = set(UNIQUE_INDEX_BACKGROUND_UPDATES.keys())

# We add the user_directory_search table to the blacklist on SQLite
# because the existing search table does not have an index, making it
Expand Down Expand Up @@ -230,12 +245,12 @@ def _check_safe_to_upsert(self):
)
updates = [x["update_name"] for x in updates]

# The User IPs table in schema #53 was missing a unique index, which we
# run as a background update.
if "user_ips_device_unique_index" not in updates:
self._unsafe_to_upsert_tables.discard("user_ips")
for table, update_name in UNIQUE_INDEX_BACKGROUND_UPDATES.items():
if update_name not in updates:
logger.debug("Now safe to upsert in %s", table)
self._unsafe_to_upsert_tables.discard(table)

# If there's any tables left to check, reschedule to run.
# If there's any updates still running, reschedule to run.
if updates:
self._clock.call_later(
15.0,
Expand Down

0 comments on commit 56710c7

Please sign in to comment.