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

Fix UPSERTs on SQLite 3.24+ #4477

Merged
merged 7 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion changelog.d/4306.misc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Synapse will now take advantage of native UPSERT functionality in PostgreSQL 9.5+.
Synapse will now take advantage of native UPSERT functionality in PostgreSQL 9.5+ and SQLite 3.24+.
2 changes: 1 addition & 1 deletion changelog.d/4471.misc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Synapse will now take advantage of native UPSERT functionality in PostgreSQL 9.5+.
Synapse will now take advantage of native UPSERT functionality in PostgreSQL 9.5+ and SQLite 3.24+.
1 change: 1 addition & 0 deletions changelog.d/4477.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Synapse will now take advantage of native UPSERT functionality in PostgreSQL 9.5+ and SQLite 3.24+.
10 changes: 8 additions & 2 deletions synapse/storage/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

from synapse.api.errors import StoreError
from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.storage.engines import PostgresEngine
from synapse.storage.engines import PostgresEngine, Sqlite3Engine
from synapse.util.caches.descriptors import Cache
from synapse.util.logcontext import LoggingContext, PreserveLoggingContext
from synapse.util.stringutils import exception_to_unicode
Expand Down Expand Up @@ -196,6 +196,12 @@ def __init__(self, db_conn, hs):
# A set of tables that are not safe to use native upserts in.
self._unsafe_to_upsert_tables = {"user_ips"}

# We add the user_directory_search table to the blacklist on SQLite
# because the existing search table does not have an index, making it
# unsafe to use native upserts.
if isinstance(self.database_engine, Sqlite3Engine):
self._unsafe_to_upsert_tables.add("user_directory_search")

if self.database_engine.can_native_upsert:
# Check ASAP (and then later, every 1s) to see if we have finished
# background updates of tables that aren't safe to update.
Expand Down Expand Up @@ -230,7 +236,7 @@ def _check_safe_to_upsert(self):
self._unsafe_to_upsert_tables.discard("user_ips")

# If there's any tables left to check, reschedule to run.
if self._unsafe_to_upsert_tables:
if self.updates:
self._clock.call_later(
15.0,
run_as_background_process,
Expand Down
10 changes: 3 additions & 7 deletions synapse/storage/engines/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,10 @@ def __init__(self, database_module, database_config):
@property
def can_native_upsert(self):
"""
Do we support native UPSERTs?
Do we support native UPSERTs? This requires SQLite3 3.24+, plus some
more work we haven't done yet to tell what was inserted vs updated.
"""
# SQLite3 3.24+ supports them, but empirically the unit tests don't work
# when its enabled.
# FIXME: Figure out what is wrong so we can re-enable native upserts

# return self.module.sqlite_version_info >= (3, 24, 0)
return False
return self.module.sqlite_version_info >= (3, 24, 0)

def check_database(self, txn):
pass
Expand Down
12 changes: 9 additions & 3 deletions synapse/storage/monthly_active_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,21 @@ def upsert_monthly_active_user(self, user_id):
if is_support:
return

is_insert = yield self.runInteraction(
yield self.runInteraction(
"upsert_monthly_active_user", self.upsert_monthly_active_user_txn,
user_id
)

if is_insert:
self.user_last_seen_monthly_active.invalidate((user_id,))
user_in_mau = self.user_last_seen_monthly_active.cache.get(
(user_id,),
None,
update_metrics=False
)
if user_in_mau is None:
self.get_monthly_active_count.invalidate(())

self.user_last_seen_monthly_active.invalidate((user_id,))

def upsert_monthly_active_user_txn(self, txn, user_id):
"""Updates or inserts monthly active user member

Expand Down
7 changes: 5 additions & 2 deletions tests/storage/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,17 @@ def runWithConnection(func, *args, **kwargs):
self.db_pool.runWithConnection = runWithConnection

config = Mock()
config._enable_native_upserts = False
config._disable_native_upserts = True
config.event_cache_size = 1
config.database_config = {"name": "sqlite3"}
engine = create_engine(config.database_config)
fake_engine = Mock(wraps=engine)
fake_engine.can_native_upsert = False
hs = TestHomeServer(
"test",
db_pool=self.db_pool,
config=config,
database_engine=create_engine(config.database_config),
database_engine=fake_engine,
)

self.datastore = SQLBaseStore(None, hs)
Expand Down
4 changes: 2 additions & 2 deletions tests/storage/test_monthly_active_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

from synapse.api.constants import UserTypes

from tests.unittest import HomeserverTestCase
from tests import unittest

FORTY_DAYS = 40 * 24 * 60 * 60


class MonthlyActiveUsersTestCase(HomeserverTestCase):
class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase):
def make_homeserver(self, reactor, clock):

hs = self.setup_test_homeserver()
Expand Down