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 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion changelog.d/4306.misc
@@ -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
@@ -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
@@ -0,0 +1 @@
Synapse will now take advantage of native UPSERT functionality in PostgreSQL 9.5+ and SQLite 3.24+.
7 changes: 5 additions & 2 deletions synapse/storage/_base.py
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,9 @@ 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"}

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 +233,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
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
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
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
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