forked from MirrorHub/synapse
Merge/remove Slaved*
stores into WorkerStores
(#14375)
This commit is contained in:
parent
13ca8bb2fc
commit
3a4f80f8c6
17 changed files with 202 additions and 377 deletions
1
changelog.d/14375.misc
Normal file
1
changelog.d/14375.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Cleanup old worker datastore classes. Contributed by Nick @ Beeper (@fizzadar).
|
|
@ -28,10 +28,6 @@ from synapse.config.homeserver import HomeServerConfig
|
||||||
from synapse.config.logger import setup_logging
|
from synapse.config.logger import setup_logging
|
||||||
from synapse.events import EventBase
|
from synapse.events import EventBase
|
||||||
from synapse.handlers.admin import ExfiltrationWriter
|
from synapse.handlers.admin import ExfiltrationWriter
|
||||||
from synapse.replication.slave.storage.devices import SlavedDeviceStore
|
|
||||||
from synapse.replication.slave.storage.events import SlavedEventStore
|
|
||||||
from synapse.replication.slave.storage.filtering import SlavedFilteringStore
|
|
||||||
from synapse.replication.slave.storage.push_rule import SlavedPushRuleStore
|
|
||||||
from synapse.server import HomeServer
|
from synapse.server import HomeServer
|
||||||
from synapse.storage.database import DatabasePool, LoggingDatabaseConnection
|
from synapse.storage.database import DatabasePool, LoggingDatabaseConnection
|
||||||
from synapse.storage.databases.main.account_data import AccountDataWorkerStore
|
from synapse.storage.databases.main.account_data import AccountDataWorkerStore
|
||||||
|
@ -40,10 +36,24 @@ from synapse.storage.databases.main.appservice import (
|
||||||
ApplicationServiceWorkerStore,
|
ApplicationServiceWorkerStore,
|
||||||
)
|
)
|
||||||
from synapse.storage.databases.main.deviceinbox import DeviceInboxWorkerStore
|
from synapse.storage.databases.main.deviceinbox import DeviceInboxWorkerStore
|
||||||
|
from synapse.storage.databases.main.devices import DeviceWorkerStore
|
||||||
|
from synapse.storage.databases.main.event_federation import EventFederationWorkerStore
|
||||||
|
from synapse.storage.databases.main.event_push_actions import (
|
||||||
|
EventPushActionsWorkerStore,
|
||||||
|
)
|
||||||
|
from synapse.storage.databases.main.events_worker import EventsWorkerStore
|
||||||
|
from synapse.storage.databases.main.filtering import FilteringWorkerStore
|
||||||
|
from synapse.storage.databases.main.push_rule import PushRulesWorkerStore
|
||||||
from synapse.storage.databases.main.receipts import ReceiptsWorkerStore
|
from synapse.storage.databases.main.receipts import ReceiptsWorkerStore
|
||||||
from synapse.storage.databases.main.registration import RegistrationWorkerStore
|
from synapse.storage.databases.main.registration import RegistrationWorkerStore
|
||||||
|
from synapse.storage.databases.main.relations import RelationsWorkerStore
|
||||||
from synapse.storage.databases.main.room import RoomWorkerStore
|
from synapse.storage.databases.main.room import RoomWorkerStore
|
||||||
|
from synapse.storage.databases.main.roommember import RoomMemberWorkerStore
|
||||||
|
from synapse.storage.databases.main.signatures import SignatureWorkerStore
|
||||||
|
from synapse.storage.databases.main.state import StateGroupWorkerStore
|
||||||
|
from synapse.storage.databases.main.stream import StreamWorkerStore
|
||||||
from synapse.storage.databases.main.tags import TagsWorkerStore
|
from synapse.storage.databases.main.tags import TagsWorkerStore
|
||||||
|
from synapse.storage.databases.main.user_erasure_store import UserErasureWorkerStore
|
||||||
from synapse.types import StateMap
|
from synapse.types import StateMap
|
||||||
from synapse.util import SYNAPSE_VERSION
|
from synapse.util import SYNAPSE_VERSION
|
||||||
from synapse.util.logcontext import LoggingContext
|
from synapse.util.logcontext import LoggingContext
|
||||||
|
@ -52,17 +62,25 @@ logger = logging.getLogger("synapse.app.admin_cmd")
|
||||||
|
|
||||||
|
|
||||||
class AdminCmdSlavedStore(
|
class AdminCmdSlavedStore(
|
||||||
SlavedFilteringStore,
|
FilteringWorkerStore,
|
||||||
SlavedPushRuleStore,
|
DeviceWorkerStore,
|
||||||
SlavedEventStore,
|
|
||||||
SlavedDeviceStore,
|
|
||||||
TagsWorkerStore,
|
TagsWorkerStore,
|
||||||
DeviceInboxWorkerStore,
|
DeviceInboxWorkerStore,
|
||||||
AccountDataWorkerStore,
|
AccountDataWorkerStore,
|
||||||
|
PushRulesWorkerStore,
|
||||||
ApplicationServiceTransactionWorkerStore,
|
ApplicationServiceTransactionWorkerStore,
|
||||||
ApplicationServiceWorkerStore,
|
ApplicationServiceWorkerStore,
|
||||||
RegistrationWorkerStore,
|
RoomMemberWorkerStore,
|
||||||
|
RelationsWorkerStore,
|
||||||
|
EventFederationWorkerStore,
|
||||||
|
EventPushActionsWorkerStore,
|
||||||
|
StateGroupWorkerStore,
|
||||||
|
SignatureWorkerStore,
|
||||||
|
UserErasureWorkerStore,
|
||||||
ReceiptsWorkerStore,
|
ReceiptsWorkerStore,
|
||||||
|
StreamWorkerStore,
|
||||||
|
EventsWorkerStore,
|
||||||
|
RegistrationWorkerStore,
|
||||||
RoomWorkerStore,
|
RoomWorkerStore,
|
||||||
):
|
):
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
|
@ -48,12 +48,6 @@ from synapse.http.site import SynapseRequest, SynapseSite
|
||||||
from synapse.logging.context import LoggingContext
|
from synapse.logging.context import LoggingContext
|
||||||
from synapse.metrics import METRICS_PREFIX, MetricsResource, RegistryProxy
|
from synapse.metrics import METRICS_PREFIX, MetricsResource, RegistryProxy
|
||||||
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
|
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
|
||||||
from synapse.replication.slave.storage.devices import SlavedDeviceStore
|
|
||||||
from synapse.replication.slave.storage.events import SlavedEventStore
|
|
||||||
from synapse.replication.slave.storage.filtering import SlavedFilteringStore
|
|
||||||
from synapse.replication.slave.storage.keys import SlavedKeyStore
|
|
||||||
from synapse.replication.slave.storage.push_rule import SlavedPushRuleStore
|
|
||||||
from synapse.replication.slave.storage.pushers import SlavedPusherStore
|
|
||||||
from synapse.rest.admin import register_servlets_for_media_repo
|
from synapse.rest.admin import register_servlets_for_media_repo
|
||||||
from synapse.rest.client import (
|
from synapse.rest.client import (
|
||||||
account_data,
|
account_data,
|
||||||
|
@ -101,8 +95,16 @@ from synapse.storage.databases.main.appservice import (
|
||||||
from synapse.storage.databases.main.censor_events import CensorEventsStore
|
from synapse.storage.databases.main.censor_events import CensorEventsStore
|
||||||
from synapse.storage.databases.main.client_ips import ClientIpWorkerStore
|
from synapse.storage.databases.main.client_ips import ClientIpWorkerStore
|
||||||
from synapse.storage.databases.main.deviceinbox import DeviceInboxWorkerStore
|
from synapse.storage.databases.main.deviceinbox import DeviceInboxWorkerStore
|
||||||
|
from synapse.storage.databases.main.devices import DeviceWorkerStore
|
||||||
from synapse.storage.databases.main.directory import DirectoryWorkerStore
|
from synapse.storage.databases.main.directory import DirectoryWorkerStore
|
||||||
from synapse.storage.databases.main.e2e_room_keys import EndToEndRoomKeyStore
|
from synapse.storage.databases.main.e2e_room_keys import EndToEndRoomKeyStore
|
||||||
|
from synapse.storage.databases.main.event_federation import EventFederationWorkerStore
|
||||||
|
from synapse.storage.databases.main.event_push_actions import (
|
||||||
|
EventPushActionsWorkerStore,
|
||||||
|
)
|
||||||
|
from synapse.storage.databases.main.events_worker import EventsWorkerStore
|
||||||
|
from synapse.storage.databases.main.filtering import FilteringWorkerStore
|
||||||
|
from synapse.storage.databases.main.keys import KeyStore
|
||||||
from synapse.storage.databases.main.lock import LockStore
|
from synapse.storage.databases.main.lock import LockStore
|
||||||
from synapse.storage.databases.main.media_repository import MediaRepositoryStore
|
from synapse.storage.databases.main.media_repository import MediaRepositoryStore
|
||||||
from synapse.storage.databases.main.metrics import ServerMetricsStore
|
from synapse.storage.databases.main.metrics import ServerMetricsStore
|
||||||
|
@ -111,17 +113,25 @@ from synapse.storage.databases.main.monthly_active_users import (
|
||||||
)
|
)
|
||||||
from synapse.storage.databases.main.presence import PresenceStore
|
from synapse.storage.databases.main.presence import PresenceStore
|
||||||
from synapse.storage.databases.main.profile import ProfileWorkerStore
|
from synapse.storage.databases.main.profile import ProfileWorkerStore
|
||||||
|
from synapse.storage.databases.main.push_rule import PushRulesWorkerStore
|
||||||
|
from synapse.storage.databases.main.pusher import PusherWorkerStore
|
||||||
from synapse.storage.databases.main.receipts import ReceiptsWorkerStore
|
from synapse.storage.databases.main.receipts import ReceiptsWorkerStore
|
||||||
from synapse.storage.databases.main.registration import RegistrationWorkerStore
|
from synapse.storage.databases.main.registration import RegistrationWorkerStore
|
||||||
|
from synapse.storage.databases.main.relations import RelationsWorkerStore
|
||||||
from synapse.storage.databases.main.room import RoomWorkerStore
|
from synapse.storage.databases.main.room import RoomWorkerStore
|
||||||
from synapse.storage.databases.main.room_batch import RoomBatchStore
|
from synapse.storage.databases.main.room_batch import RoomBatchStore
|
||||||
|
from synapse.storage.databases.main.roommember import RoomMemberWorkerStore
|
||||||
from synapse.storage.databases.main.search import SearchStore
|
from synapse.storage.databases.main.search import SearchStore
|
||||||
from synapse.storage.databases.main.session import SessionStore
|
from synapse.storage.databases.main.session import SessionStore
|
||||||
|
from synapse.storage.databases.main.signatures import SignatureWorkerStore
|
||||||
|
from synapse.storage.databases.main.state import StateGroupWorkerStore
|
||||||
from synapse.storage.databases.main.stats import StatsStore
|
from synapse.storage.databases.main.stats import StatsStore
|
||||||
|
from synapse.storage.databases.main.stream import StreamWorkerStore
|
||||||
from synapse.storage.databases.main.tags import TagsWorkerStore
|
from synapse.storage.databases.main.tags import TagsWorkerStore
|
||||||
from synapse.storage.databases.main.transactions import TransactionWorkerStore
|
from synapse.storage.databases.main.transactions import TransactionWorkerStore
|
||||||
from synapse.storage.databases.main.ui_auth import UIAuthWorkerStore
|
from synapse.storage.databases.main.ui_auth import UIAuthWorkerStore
|
||||||
from synapse.storage.databases.main.user_directory import UserDirectoryStore
|
from synapse.storage.databases.main.user_directory import UserDirectoryStore
|
||||||
|
from synapse.storage.databases.main.user_erasure_store import UserErasureWorkerStore
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict
|
||||||
from synapse.util import SYNAPSE_VERSION
|
from synapse.util import SYNAPSE_VERSION
|
||||||
from synapse.util.httpresourcetree import create_resource_tree
|
from synapse.util.httpresourcetree import create_resource_tree
|
||||||
|
@ -232,26 +242,36 @@ class GenericWorkerSlavedStore(
|
||||||
EndToEndRoomKeyStore,
|
EndToEndRoomKeyStore,
|
||||||
PresenceStore,
|
PresenceStore,
|
||||||
DeviceInboxWorkerStore,
|
DeviceInboxWorkerStore,
|
||||||
SlavedDeviceStore,
|
DeviceWorkerStore,
|
||||||
SlavedPushRuleStore,
|
|
||||||
TagsWorkerStore,
|
TagsWorkerStore,
|
||||||
AccountDataWorkerStore,
|
AccountDataWorkerStore,
|
||||||
SlavedPusherStore,
|
|
||||||
CensorEventsStore,
|
CensorEventsStore,
|
||||||
ClientIpWorkerStore,
|
ClientIpWorkerStore,
|
||||||
SlavedEventStore,
|
# KeyStore isn't really safe to use from a worker, but for now we do so and hope that
|
||||||
SlavedKeyStore,
|
# the races it creates aren't too bad.
|
||||||
|
KeyStore,
|
||||||
RoomWorkerStore,
|
RoomWorkerStore,
|
||||||
RoomBatchStore,
|
RoomBatchStore,
|
||||||
DirectoryWorkerStore,
|
DirectoryWorkerStore,
|
||||||
|
PushRulesWorkerStore,
|
||||||
ApplicationServiceTransactionWorkerStore,
|
ApplicationServiceTransactionWorkerStore,
|
||||||
ApplicationServiceWorkerStore,
|
ApplicationServiceWorkerStore,
|
||||||
ProfileWorkerStore,
|
ProfileWorkerStore,
|
||||||
SlavedFilteringStore,
|
FilteringWorkerStore,
|
||||||
MonthlyActiveUsersWorkerStore,
|
MonthlyActiveUsersWorkerStore,
|
||||||
MediaRepositoryStore,
|
MediaRepositoryStore,
|
||||||
ServerMetricsStore,
|
ServerMetricsStore,
|
||||||
|
PusherWorkerStore,
|
||||||
|
RoomMemberWorkerStore,
|
||||||
|
RelationsWorkerStore,
|
||||||
|
EventFederationWorkerStore,
|
||||||
|
EventPushActionsWorkerStore,
|
||||||
|
StateGroupWorkerStore,
|
||||||
|
SignatureWorkerStore,
|
||||||
|
UserErasureWorkerStore,
|
||||||
ReceiptsWorkerStore,
|
ReceiptsWorkerStore,
|
||||||
|
StreamWorkerStore,
|
||||||
|
EventsWorkerStore,
|
||||||
RegistrationWorkerStore,
|
RegistrationWorkerStore,
|
||||||
SearchStore,
|
SearchStore,
|
||||||
TransactionWorkerStore,
|
TransactionWorkerStore,
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
# Copyright 2016 OpenMarket Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Any, Iterable
|
|
||||||
|
|
||||||
from synapse.replication.slave.storage._slaved_id_tracker import SlavedIdTracker
|
|
||||||
from synapse.replication.tcp.streams._base import DeviceListsStream, UserSignatureStream
|
|
||||||
from synapse.storage.database import DatabasePool, LoggingDatabaseConnection
|
|
||||||
from synapse.storage.databases.main.devices import DeviceWorkerStore
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from synapse.server import HomeServer
|
|
||||||
|
|
||||||
|
|
||||||
class SlavedDeviceStore(DeviceWorkerStore):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
database: DatabasePool,
|
|
||||||
db_conn: LoggingDatabaseConnection,
|
|
||||||
hs: "HomeServer",
|
|
||||||
):
|
|
||||||
self.hs = hs
|
|
||||||
|
|
||||||
self._device_list_id_gen = SlavedIdTracker(
|
|
||||||
db_conn,
|
|
||||||
"device_lists_stream",
|
|
||||||
"stream_id",
|
|
||||||
extra_tables=[
|
|
||||||
("user_signature_stream", "stream_id"),
|
|
||||||
("device_lists_outbound_pokes", "stream_id"),
|
|
||||||
("device_lists_changes_in_room", "stream_id"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(database, db_conn, hs)
|
|
||||||
|
|
||||||
def get_device_stream_token(self) -> int:
|
|
||||||
return self._device_list_id_gen.get_current_token()
|
|
||||||
|
|
||||||
def process_replication_rows(
|
|
||||||
self, stream_name: str, instance_name: str, token: int, rows: Iterable[Any]
|
|
||||||
) -> None:
|
|
||||||
if stream_name == DeviceListsStream.NAME:
|
|
||||||
self._device_list_id_gen.advance(instance_name, token)
|
|
||||||
self._invalidate_caches_for_devices(token, rows)
|
|
||||||
elif stream_name == UserSignatureStream.NAME:
|
|
||||||
self._device_list_id_gen.advance(instance_name, token)
|
|
||||||
for row in rows:
|
|
||||||
self._user_signature_stream_cache.entity_has_changed(row.user_id, token)
|
|
||||||
return super().process_replication_rows(stream_name, instance_name, token, rows)
|
|
||||||
|
|
||||||
def _invalidate_caches_for_devices(
|
|
||||||
self, token: int, rows: Iterable[DeviceListsStream.DeviceListsStreamRow]
|
|
||||||
) -> None:
|
|
||||||
for row in rows:
|
|
||||||
# The entities are either user IDs (starting with '@') whose devices
|
|
||||||
# have changed, or remote servers that we need to tell about
|
|
||||||
# changes.
|
|
||||||
if row.entity.startswith("@"):
|
|
||||||
self._device_list_stream_cache.entity_has_changed(row.entity, token)
|
|
||||||
self.get_cached_devices_for_user.invalidate((row.entity,))
|
|
||||||
self._get_cached_user_device.invalidate((row.entity,))
|
|
||||||
self.get_device_list_last_stream_id_for_remote.invalidate((row.entity,))
|
|
||||||
|
|
||||||
else:
|
|
||||||
self._device_list_federation_stream_cache.entity_has_changed(
|
|
||||||
row.entity, token
|
|
||||||
)
|
|
|
@ -1,79 +0,0 @@
|
||||||
# Copyright 2016 OpenMarket Ltd
|
|
||||||
# Copyright 2018 New Vector Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
import logging
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from synapse.storage.database import DatabasePool, LoggingDatabaseConnection
|
|
||||||
from synapse.storage.databases.main.event_federation import EventFederationWorkerStore
|
|
||||||
from synapse.storage.databases.main.event_push_actions import (
|
|
||||||
EventPushActionsWorkerStore,
|
|
||||||
)
|
|
||||||
from synapse.storage.databases.main.events_worker import EventsWorkerStore
|
|
||||||
from synapse.storage.databases.main.relations import RelationsWorkerStore
|
|
||||||
from synapse.storage.databases.main.roommember import RoomMemberWorkerStore
|
|
||||||
from synapse.storage.databases.main.signatures import SignatureWorkerStore
|
|
||||||
from synapse.storage.databases.main.state import StateGroupWorkerStore
|
|
||||||
from synapse.storage.databases.main.stream import StreamWorkerStore
|
|
||||||
from synapse.storage.databases.main.user_erasure_store import UserErasureWorkerStore
|
|
||||||
from synapse.util.caches.stream_change_cache import StreamChangeCache
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from synapse.server import HomeServer
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
# So, um, we want to borrow a load of functions intended for reading from
|
|
||||||
# a DataStore, but we don't want to take functions that either write to the
|
|
||||||
# DataStore or are cached and don't have cache invalidation logic.
|
|
||||||
#
|
|
||||||
# Rather than write duplicate versions of those functions, or lift them to
|
|
||||||
# a common base class, we going to grab the underlying __func__ object from
|
|
||||||
# the method descriptor on the DataStore and chuck them into our class.
|
|
||||||
|
|
||||||
|
|
||||||
class SlavedEventStore(
|
|
||||||
EventFederationWorkerStore,
|
|
||||||
RoomMemberWorkerStore,
|
|
||||||
EventPushActionsWorkerStore,
|
|
||||||
StreamWorkerStore,
|
|
||||||
StateGroupWorkerStore,
|
|
||||||
SignatureWorkerStore,
|
|
||||||
EventsWorkerStore,
|
|
||||||
UserErasureWorkerStore,
|
|
||||||
RelationsWorkerStore,
|
|
||||||
):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
database: DatabasePool,
|
|
||||||
db_conn: LoggingDatabaseConnection,
|
|
||||||
hs: "HomeServer",
|
|
||||||
):
|
|
||||||
super().__init__(database, db_conn, hs)
|
|
||||||
|
|
||||||
events_max = self._stream_id_gen.get_current_token()
|
|
||||||
curr_state_delta_prefill, min_curr_state_delta_id = self.db_pool.get_cache_dict(
|
|
||||||
db_conn,
|
|
||||||
"current_state_delta_stream",
|
|
||||||
entity_column="room_id",
|
|
||||||
stream_column="stream_id",
|
|
||||||
max_value=events_max, # As we share the stream id with events token
|
|
||||||
limit=1000,
|
|
||||||
)
|
|
||||||
self._curr_state_delta_stream_cache = StreamChangeCache(
|
|
||||||
"_curr_state_delta_stream_cache",
|
|
||||||
min_curr_state_delta_id,
|
|
||||||
prefilled_cache=curr_state_delta_prefill,
|
|
||||||
)
|
|
|
@ -1,35 +0,0 @@
|
||||||
# Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from synapse.storage._base import SQLBaseStore
|
|
||||||
from synapse.storage.database import DatabasePool, LoggingDatabaseConnection
|
|
||||||
from synapse.storage.databases.main.filtering import FilteringStore
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from synapse.server import HomeServer
|
|
||||||
|
|
||||||
|
|
||||||
class SlavedFilteringStore(SQLBaseStore):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
database: DatabasePool,
|
|
||||||
db_conn: LoggingDatabaseConnection,
|
|
||||||
hs: "HomeServer",
|
|
||||||
):
|
|
||||||
super().__init__(database, db_conn, hs)
|
|
||||||
|
|
||||||
# Filters are immutable so this cache doesn't need to be expired
|
|
||||||
get_user_filter = FilteringStore.__dict__["get_user_filter"]
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
from synapse.storage.databases.main.keys import KeyStore
|
|
||||||
|
|
||||||
# KeyStore isn't really safe to use from a worker, but for now we do so and hope that
|
|
||||||
# the races it creates aren't too bad.
|
|
||||||
|
|
||||||
SlavedKeyStore = KeyStore
|
|
|
@ -1,35 +0,0 @@
|
||||||
# Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
# Copyright 2018 New Vector Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
from typing import Any, Iterable
|
|
||||||
|
|
||||||
from synapse.replication.tcp.streams import PushRulesStream
|
|
||||||
from synapse.storage.databases.main.push_rule import PushRulesWorkerStore
|
|
||||||
|
|
||||||
from .events import SlavedEventStore
|
|
||||||
|
|
||||||
|
|
||||||
class SlavedPushRuleStore(SlavedEventStore, PushRulesWorkerStore):
|
|
||||||
def get_max_push_rules_stream_id(self) -> int:
|
|
||||||
return self._push_rules_stream_id_gen.get_current_token()
|
|
||||||
|
|
||||||
def process_replication_rows(
|
|
||||||
self, stream_name: str, instance_name: str, token: int, rows: Iterable[Any]
|
|
||||||
) -> None:
|
|
||||||
if stream_name == PushRulesStream.NAME:
|
|
||||||
self._push_rules_stream_id_gen.advance(instance_name, token)
|
|
||||||
for row in rows:
|
|
||||||
self.get_push_rules_for_user.invalidate((row.user_id,))
|
|
||||||
self.push_rules_stream_cache.entity_has_changed(row.user_id, token)
|
|
||||||
return super().process_replication_rows(stream_name, instance_name, token, rows)
|
|
|
@ -1,47 +0,0 @@
|
||||||
# Copyright 2016 OpenMarket Ltd
|
|
||||||
# Copyright 2018 New Vector Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
from typing import TYPE_CHECKING, Any, Iterable
|
|
||||||
|
|
||||||
from synapse.replication.tcp.streams import PushersStream
|
|
||||||
from synapse.storage.database import DatabasePool, LoggingDatabaseConnection
|
|
||||||
from synapse.storage.databases.main.pusher import PusherWorkerStore
|
|
||||||
|
|
||||||
from ._slaved_id_tracker import SlavedIdTracker
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from synapse.server import HomeServer
|
|
||||||
|
|
||||||
|
|
||||||
class SlavedPusherStore(PusherWorkerStore):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
database: DatabasePool,
|
|
||||||
db_conn: LoggingDatabaseConnection,
|
|
||||||
hs: "HomeServer",
|
|
||||||
):
|
|
||||||
super().__init__(database, db_conn, hs)
|
|
||||||
self._pushers_id_gen = SlavedIdTracker( # type: ignore
|
|
||||||
db_conn, "pushers", "id", extra_tables=[("deleted_pushers", "stream_id")]
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_pushers_stream_token(self) -> int:
|
|
||||||
return self._pushers_id_gen.get_current_token()
|
|
||||||
|
|
||||||
def process_replication_rows(
|
|
||||||
self, stream_name: str, instance_name: str, token: int, rows: Iterable[Any]
|
|
||||||
) -> None:
|
|
||||||
if stream_name == PushersStream.NAME:
|
|
||||||
self._pushers_id_gen.advance(instance_name, token)
|
|
||||||
return super().process_replication_rows(stream_name, instance_name, token, rows)
|
|
|
@ -26,9 +26,7 @@ from synapse.storage.database import (
|
||||||
from synapse.storage.databases.main.stats import UserSortOrder
|
from synapse.storage.databases.main.stats import UserSortOrder
|
||||||
from synapse.storage.engines import BaseDatabaseEngine
|
from synapse.storage.engines import BaseDatabaseEngine
|
||||||
from synapse.storage.types import Cursor
|
from synapse.storage.types import Cursor
|
||||||
from synapse.storage.util.id_generators import StreamIdGenerator
|
|
||||||
from synapse.types import JsonDict, get_domain_from_id
|
from synapse.types import JsonDict, get_domain_from_id
|
||||||
from synapse.util.caches.stream_change_cache import StreamChangeCache
|
|
||||||
|
|
||||||
from .account_data import AccountDataStore
|
from .account_data import AccountDataStore
|
||||||
from .appservice import ApplicationServiceStore, ApplicationServiceTransactionStore
|
from .appservice import ApplicationServiceStore, ApplicationServiceTransactionStore
|
||||||
|
@ -138,41 +136,8 @@ class DataStore(
|
||||||
self._clock = hs.get_clock()
|
self._clock = hs.get_clock()
|
||||||
self.database_engine = database.engine
|
self.database_engine = database.engine
|
||||||
|
|
||||||
self._device_list_id_gen = StreamIdGenerator(
|
|
||||||
db_conn,
|
|
||||||
"device_lists_stream",
|
|
||||||
"stream_id",
|
|
||||||
extra_tables=[
|
|
||||||
("user_signature_stream", "stream_id"),
|
|
||||||
("device_lists_outbound_pokes", "stream_id"),
|
|
||||||
("device_lists_changes_in_room", "stream_id"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(database, db_conn, hs)
|
super().__init__(database, db_conn, hs)
|
||||||
|
|
||||||
events_max = self._stream_id_gen.get_current_token()
|
|
||||||
curr_state_delta_prefill, min_curr_state_delta_id = self.db_pool.get_cache_dict(
|
|
||||||
db_conn,
|
|
||||||
"current_state_delta_stream",
|
|
||||||
entity_column="room_id",
|
|
||||||
stream_column="stream_id",
|
|
||||||
max_value=events_max, # As we share the stream id with events token
|
|
||||||
limit=1000,
|
|
||||||
)
|
|
||||||
self._curr_state_delta_stream_cache = StreamChangeCache(
|
|
||||||
"_curr_state_delta_stream_cache",
|
|
||||||
min_curr_state_delta_id,
|
|
||||||
prefilled_cache=curr_state_delta_prefill,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._stream_order_on_start = self.get_room_max_stream_ordering()
|
|
||||||
self._min_stream_order_on_start = self.get_room_min_stream_ordering()
|
|
||||||
|
|
||||||
def get_device_stream_token(self) -> int:
|
|
||||||
# TODO: shouldn't this be moved to `DeviceWorkerStore`?
|
|
||||||
return self._device_list_id_gen.get_current_token()
|
|
||||||
|
|
||||||
async def get_users(self) -> List[JsonDict]:
|
async def get_users(self) -> List[JsonDict]:
|
||||||
"""Function to retrieve a list of users in users table.
|
"""Function to retrieve a list of users in users table.
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import abc
|
|
||||||
import logging
|
import logging
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
|
@ -39,6 +38,8 @@ from synapse.logging.opentracing import (
|
||||||
whitelisted_homeserver,
|
whitelisted_homeserver,
|
||||||
)
|
)
|
||||||
from synapse.metrics.background_process_metrics import wrap_as_background_process
|
from synapse.metrics.background_process_metrics import wrap_as_background_process
|
||||||
|
from synapse.replication.slave.storage._slaved_id_tracker import SlavedIdTracker
|
||||||
|
from synapse.replication.tcp.streams._base import DeviceListsStream, UserSignatureStream
|
||||||
from synapse.storage._base import SQLBaseStore, db_to_json, make_in_list_sql_clause
|
from synapse.storage._base import SQLBaseStore, db_to_json, make_in_list_sql_clause
|
||||||
from synapse.storage.database import (
|
from synapse.storage.database import (
|
||||||
DatabasePool,
|
DatabasePool,
|
||||||
|
@ -49,6 +50,11 @@ from synapse.storage.database import (
|
||||||
from synapse.storage.databases.main.end_to_end_keys import EndToEndKeyWorkerStore
|
from synapse.storage.databases.main.end_to_end_keys import EndToEndKeyWorkerStore
|
||||||
from synapse.storage.databases.main.roommember import RoomMemberWorkerStore
|
from synapse.storage.databases.main.roommember import RoomMemberWorkerStore
|
||||||
from synapse.storage.types import Cursor
|
from synapse.storage.types import Cursor
|
||||||
|
from synapse.storage.util.id_generators import (
|
||||||
|
AbstractStreamIdGenerator,
|
||||||
|
AbstractStreamIdTracker,
|
||||||
|
StreamIdGenerator,
|
||||||
|
)
|
||||||
from synapse.types import JsonDict, get_verify_key_from_cross_signing_key
|
from synapse.types import JsonDict, get_verify_key_from_cross_signing_key
|
||||||
from synapse.util import json_decoder, json_encoder
|
from synapse.util import json_decoder, json_encoder
|
||||||
from synapse.util.caches.descriptors import cached, cachedList
|
from synapse.util.caches.descriptors import cached, cachedList
|
||||||
|
@ -80,9 +86,32 @@ class DeviceWorkerStore(RoomMemberWorkerStore, EndToEndKeyWorkerStore):
|
||||||
):
|
):
|
||||||
super().__init__(database, db_conn, hs)
|
super().__init__(database, db_conn, hs)
|
||||||
|
|
||||||
|
if hs.config.worker.worker_app is None:
|
||||||
|
self._device_list_id_gen: AbstractStreamIdTracker = StreamIdGenerator(
|
||||||
|
db_conn,
|
||||||
|
"device_lists_stream",
|
||||||
|
"stream_id",
|
||||||
|
extra_tables=[
|
||||||
|
("user_signature_stream", "stream_id"),
|
||||||
|
("device_lists_outbound_pokes", "stream_id"),
|
||||||
|
("device_lists_changes_in_room", "stream_id"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._device_list_id_gen = SlavedIdTracker(
|
||||||
|
db_conn,
|
||||||
|
"device_lists_stream",
|
||||||
|
"stream_id",
|
||||||
|
extra_tables=[
|
||||||
|
("user_signature_stream", "stream_id"),
|
||||||
|
("device_lists_outbound_pokes", "stream_id"),
|
||||||
|
("device_lists_changes_in_room", "stream_id"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# Type-ignore: _device_list_id_gen is mixed in from either DataStore (as a
|
# Type-ignore: _device_list_id_gen is mixed in from either DataStore (as a
|
||||||
# StreamIdGenerator) or SlavedDataStore (as a SlavedIdTracker).
|
# StreamIdGenerator) or SlavedDataStore (as a SlavedIdTracker).
|
||||||
device_list_max = self._device_list_id_gen.get_current_token() # type: ignore[attr-defined]
|
device_list_max = self._device_list_id_gen.get_current_token()
|
||||||
device_list_prefill, min_device_list_id = self.db_pool.get_cache_dict(
|
device_list_prefill, min_device_list_id = self.db_pool.get_cache_dict(
|
||||||
db_conn,
|
db_conn,
|
||||||
"device_lists_stream",
|
"device_lists_stream",
|
||||||
|
@ -136,6 +165,39 @@ class DeviceWorkerStore(RoomMemberWorkerStore, EndToEndKeyWorkerStore):
|
||||||
self._prune_old_outbound_device_pokes, 60 * 60 * 1000
|
self._prune_old_outbound_device_pokes, 60 * 60 * 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def process_replication_rows(
|
||||||
|
self, stream_name: str, instance_name: str, token: int, rows: Iterable[Any]
|
||||||
|
) -> None:
|
||||||
|
if stream_name == DeviceListsStream.NAME:
|
||||||
|
self._device_list_id_gen.advance(instance_name, token)
|
||||||
|
self._invalidate_caches_for_devices(token, rows)
|
||||||
|
elif stream_name == UserSignatureStream.NAME:
|
||||||
|
self._device_list_id_gen.advance(instance_name, token)
|
||||||
|
for row in rows:
|
||||||
|
self._user_signature_stream_cache.entity_has_changed(row.user_id, token)
|
||||||
|
return super().process_replication_rows(stream_name, instance_name, token, rows)
|
||||||
|
|
||||||
|
def _invalidate_caches_for_devices(
|
||||||
|
self, token: int, rows: Iterable[DeviceListsStream.DeviceListsStreamRow]
|
||||||
|
) -> None:
|
||||||
|
for row in rows:
|
||||||
|
# The entities are either user IDs (starting with '@') whose devices
|
||||||
|
# have changed, or remote servers that we need to tell about
|
||||||
|
# changes.
|
||||||
|
if row.entity.startswith("@"):
|
||||||
|
self._device_list_stream_cache.entity_has_changed(row.entity, token)
|
||||||
|
self.get_cached_devices_for_user.invalidate((row.entity,))
|
||||||
|
self._get_cached_user_device.invalidate((row.entity,))
|
||||||
|
self.get_device_list_last_stream_id_for_remote.invalidate((row.entity,))
|
||||||
|
|
||||||
|
else:
|
||||||
|
self._device_list_federation_stream_cache.entity_has_changed(
|
||||||
|
row.entity, token
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_device_stream_token(self) -> int:
|
||||||
|
return self._device_list_id_gen.get_current_token()
|
||||||
|
|
||||||
async def count_devices_by_users(self, user_ids: Optional[List[str]] = None) -> int:
|
async def count_devices_by_users(self, user_ids: Optional[List[str]] = None) -> int:
|
||||||
"""Retrieve number of all devices of given users.
|
"""Retrieve number of all devices of given users.
|
||||||
Only returns number of devices that are not marked as hidden.
|
Only returns number of devices that are not marked as hidden.
|
||||||
|
@ -677,11 +739,6 @@ class DeviceWorkerStore(RoomMemberWorkerStore, EndToEndKeyWorkerStore):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_device_stream_token(self) -> int:
|
|
||||||
"""Get the current stream id from the _device_list_id_gen"""
|
|
||||||
...
|
|
||||||
|
|
||||||
@trace
|
@trace
|
||||||
@cancellable
|
@cancellable
|
||||||
async def get_user_devices_from_cache(
|
async def get_user_devices_from_cache(
|
||||||
|
@ -1481,6 +1538,10 @@ class DeviceBackgroundUpdateStore(SQLBaseStore):
|
||||||
|
|
||||||
|
|
||||||
class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||||
|
# Because we have write access, this will be a StreamIdGenerator
|
||||||
|
# (see DeviceWorkerStore.__init__)
|
||||||
|
_device_list_id_gen: AbstractStreamIdGenerator
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
database: DatabasePool,
|
database: DatabasePool,
|
||||||
|
@ -1805,7 +1866,7 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
|
|
||||||
async with self._device_list_id_gen.get_next_mult( # type: ignore[attr-defined]
|
async with self._device_list_id_gen.get_next_mult(
|
||||||
len(device_ids)
|
len(device_ids)
|
||||||
) as stream_ids:
|
) as stream_ids:
|
||||||
await self.db_pool.runInteraction(
|
await self.db_pool.runInteraction(
|
||||||
|
@ -2044,7 +2105,7 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
||||||
async with self._device_list_id_gen.get_next_mult(len(hosts)) as stream_ids: # type: ignore[attr-defined]
|
async with self._device_list_id_gen.get_next_mult(len(hosts)) as stream_ids:
|
||||||
return await self.db_pool.runInteraction(
|
return await self.db_pool.runInteraction(
|
||||||
"add_device_list_outbound_pokes",
|
"add_device_list_outbound_pokes",
|
||||||
add_device_list_outbound_pokes_txn,
|
add_device_list_outbound_pokes_txn,
|
||||||
|
@ -2058,7 +2119,7 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||||
updates during partial joins.
|
updates during partial joins.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async with self._device_list_id_gen.get_next() as stream_id: # type: ignore[attr-defined]
|
async with self._device_list_id_gen.get_next() as stream_id:
|
||||||
await self.db_pool.simple_upsert(
|
await self.db_pool.simple_upsert(
|
||||||
table="device_lists_remote_pending",
|
table="device_lists_remote_pending",
|
||||||
keyvalues={
|
keyvalues={
|
||||||
|
|
|
@ -81,6 +81,7 @@ from synapse.util import unwrapFirstError
|
||||||
from synapse.util.async_helpers import ObservableDeferred, delay_cancellation
|
from synapse.util.async_helpers import ObservableDeferred, delay_cancellation
|
||||||
from synapse.util.caches.descriptors import cached, cachedList
|
from synapse.util.caches.descriptors import cached, cachedList
|
||||||
from synapse.util.caches.lrucache import AsyncLruCache
|
from synapse.util.caches.lrucache import AsyncLruCache
|
||||||
|
from synapse.util.caches.stream_change_cache import StreamChangeCache
|
||||||
from synapse.util.cancellation import cancellable
|
from synapse.util.cancellation import cancellable
|
||||||
from synapse.util.iterutils import batch_iter
|
from synapse.util.iterutils import batch_iter
|
||||||
from synapse.util.metrics import Measure
|
from synapse.util.metrics import Measure
|
||||||
|
@ -233,6 +234,21 @@ class EventsWorkerStore(SQLBaseStore):
|
||||||
db_conn, "events", "stream_ordering", step=-1
|
db_conn, "events", "stream_ordering", step=-1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
events_max = self._stream_id_gen.get_current_token()
|
||||||
|
curr_state_delta_prefill, min_curr_state_delta_id = self.db_pool.get_cache_dict(
|
||||||
|
db_conn,
|
||||||
|
"current_state_delta_stream",
|
||||||
|
entity_column="room_id",
|
||||||
|
stream_column="stream_id",
|
||||||
|
max_value=events_max, # As we share the stream id with events token
|
||||||
|
limit=1000,
|
||||||
|
)
|
||||||
|
self._curr_state_delta_stream_cache: StreamChangeCache = StreamChangeCache(
|
||||||
|
"_curr_state_delta_stream_cache",
|
||||||
|
min_curr_state_delta_id,
|
||||||
|
prefilled_cache=curr_state_delta_prefill,
|
||||||
|
)
|
||||||
|
|
||||||
if hs.config.worker.run_background_tasks:
|
if hs.config.worker.run_background_tasks:
|
||||||
# We periodically clean out old transaction ID mappings
|
# We periodically clean out old transaction ID mappings
|
||||||
self._clock.looping_call(
|
self._clock.looping_call(
|
||||||
|
|
|
@ -24,7 +24,7 @@ from synapse.types import JsonDict
|
||||||
from synapse.util.caches.descriptors import cached
|
from synapse.util.caches.descriptors import cached
|
||||||
|
|
||||||
|
|
||||||
class FilteringStore(SQLBaseStore):
|
class FilteringWorkerStore(SQLBaseStore):
|
||||||
@cached(num_args=2)
|
@cached(num_args=2)
|
||||||
async def get_user_filter(
|
async def get_user_filter(
|
||||||
self, user_localpart: str, filter_id: Union[int, str]
|
self, user_localpart: str, filter_id: Union[int, str]
|
||||||
|
@ -46,6 +46,8 @@ class FilteringStore(SQLBaseStore):
|
||||||
|
|
||||||
return db_to_json(def_json)
|
return db_to_json(def_json)
|
||||||
|
|
||||||
|
|
||||||
|
class FilteringStore(FilteringWorkerStore):
|
||||||
async def add_user_filter(self, user_localpart: str, user_filter: JsonDict) -> int:
|
async def add_user_filter(self, user_localpart: str, user_filter: JsonDict) -> int:
|
||||||
def_json = encode_canonical_json(user_filter)
|
def_json = encode_canonical_json(user_filter)
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,13 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import abc
|
|
||||||
import logging
|
import logging
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
Collection,
|
Collection,
|
||||||
Dict,
|
Dict,
|
||||||
|
Iterable,
|
||||||
List,
|
List,
|
||||||
Mapping,
|
Mapping,
|
||||||
Optional,
|
Optional,
|
||||||
|
@ -31,6 +31,7 @@ from typing import (
|
||||||
from synapse.api.errors import StoreError
|
from synapse.api.errors import StoreError
|
||||||
from synapse.config.homeserver import ExperimentalConfig
|
from synapse.config.homeserver import ExperimentalConfig
|
||||||
from synapse.replication.slave.storage._slaved_id_tracker import SlavedIdTracker
|
from synapse.replication.slave.storage._slaved_id_tracker import SlavedIdTracker
|
||||||
|
from synapse.replication.tcp.streams import PushRulesStream
|
||||||
from synapse.storage._base import SQLBaseStore
|
from synapse.storage._base import SQLBaseStore
|
||||||
from synapse.storage.database import (
|
from synapse.storage.database import (
|
||||||
DatabasePool,
|
DatabasePool,
|
||||||
|
@ -90,8 +91,6 @@ def _load_rules(
|
||||||
return filtered_rules
|
return filtered_rules
|
||||||
|
|
||||||
|
|
||||||
# The ABCMeta metaclass ensures that it cannot be instantiated without
|
|
||||||
# the abstract methods being implemented.
|
|
||||||
class PushRulesWorkerStore(
|
class PushRulesWorkerStore(
|
||||||
ApplicationServiceWorkerStore,
|
ApplicationServiceWorkerStore,
|
||||||
PusherWorkerStore,
|
PusherWorkerStore,
|
||||||
|
@ -99,7 +98,6 @@ class PushRulesWorkerStore(
|
||||||
ReceiptsWorkerStore,
|
ReceiptsWorkerStore,
|
||||||
EventsWorkerStore,
|
EventsWorkerStore,
|
||||||
SQLBaseStore,
|
SQLBaseStore,
|
||||||
metaclass=abc.ABCMeta,
|
|
||||||
):
|
):
|
||||||
"""This is an abstract base class where subclasses must implement
|
"""This is an abstract base class where subclasses must implement
|
||||||
`get_max_push_rules_stream_id` which can be called in the initializer.
|
`get_max_push_rules_stream_id` which can be called in the initializer.
|
||||||
|
@ -136,14 +134,23 @@ class PushRulesWorkerStore(
|
||||||
prefilled_cache=push_rules_prefill,
|
prefilled_cache=push_rules_prefill,
|
||||||
)
|
)
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_max_push_rules_stream_id(self) -> int:
|
def get_max_push_rules_stream_id(self) -> int:
|
||||||
"""Get the position of the push rules stream.
|
"""Get the position of the push rules stream.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int
|
int
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
return self._push_rules_stream_id_gen.get_current_token()
|
||||||
|
|
||||||
|
def process_replication_rows(
|
||||||
|
self, stream_name: str, instance_name: str, token: int, rows: Iterable[Any]
|
||||||
|
) -> None:
|
||||||
|
if stream_name == PushRulesStream.NAME:
|
||||||
|
self._push_rules_stream_id_gen.advance(instance_name, token)
|
||||||
|
for row in rows:
|
||||||
|
self.get_push_rules_for_user.invalidate((row.user_id,))
|
||||||
|
self.push_rules_stream_cache.entity_has_changed(row.user_id, token)
|
||||||
|
return super().process_replication_rows(stream_name, instance_name, token, rows)
|
||||||
|
|
||||||
@cached(max_entries=5000)
|
@cached(max_entries=5000)
|
||||||
async def get_push_rules_for_user(self, user_id: str) -> FilteredPushRules:
|
async def get_push_rules_for_user(self, user_id: str) -> FilteredPushRules:
|
||||||
|
|
|
@ -27,13 +27,19 @@ from typing import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from synapse.push import PusherConfig, ThrottleParams
|
from synapse.push import PusherConfig, ThrottleParams
|
||||||
|
from synapse.replication.slave.storage._slaved_id_tracker import SlavedIdTracker
|
||||||
|
from synapse.replication.tcp.streams import PushersStream
|
||||||
from synapse.storage._base import SQLBaseStore, db_to_json
|
from synapse.storage._base import SQLBaseStore, db_to_json
|
||||||
from synapse.storage.database import (
|
from synapse.storage.database import (
|
||||||
DatabasePool,
|
DatabasePool,
|
||||||
LoggingDatabaseConnection,
|
LoggingDatabaseConnection,
|
||||||
LoggingTransaction,
|
LoggingTransaction,
|
||||||
)
|
)
|
||||||
from synapse.storage.util.id_generators import StreamIdGenerator
|
from synapse.storage.util.id_generators import (
|
||||||
|
AbstractStreamIdGenerator,
|
||||||
|
AbstractStreamIdTracker,
|
||||||
|
StreamIdGenerator,
|
||||||
|
)
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict
|
||||||
from synapse.util import json_encoder
|
from synapse.util import json_encoder
|
||||||
from synapse.util.caches.descriptors import cached
|
from synapse.util.caches.descriptors import cached
|
||||||
|
@ -52,8 +58,20 @@ class PusherWorkerStore(SQLBaseStore):
|
||||||
hs: "HomeServer",
|
hs: "HomeServer",
|
||||||
):
|
):
|
||||||
super().__init__(database, db_conn, hs)
|
super().__init__(database, db_conn, hs)
|
||||||
self._pushers_id_gen = StreamIdGenerator(
|
|
||||||
db_conn, "pushers", "id", extra_tables=[("deleted_pushers", "stream_id")]
|
if hs.config.worker.worker_app is None:
|
||||||
|
self._pushers_id_gen: AbstractStreamIdTracker = StreamIdGenerator(
|
||||||
|
db_conn,
|
||||||
|
"pushers",
|
||||||
|
"id",
|
||||||
|
extra_tables=[("deleted_pushers", "stream_id")],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._pushers_id_gen = SlavedIdTracker(
|
||||||
|
db_conn,
|
||||||
|
"pushers",
|
||||||
|
"id",
|
||||||
|
extra_tables=[("deleted_pushers", "stream_id")],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.db_pool.updates.register_background_update_handler(
|
self.db_pool.updates.register_background_update_handler(
|
||||||
|
@ -96,6 +114,16 @@ class PusherWorkerStore(SQLBaseStore):
|
||||||
|
|
||||||
yield PusherConfig(**r)
|
yield PusherConfig(**r)
|
||||||
|
|
||||||
|
def get_pushers_stream_token(self) -> int:
|
||||||
|
return self._pushers_id_gen.get_current_token()
|
||||||
|
|
||||||
|
def process_replication_rows(
|
||||||
|
self, stream_name: str, instance_name: str, token: int, rows: Iterable[Any]
|
||||||
|
) -> None:
|
||||||
|
if stream_name == PushersStream.NAME:
|
||||||
|
self._pushers_id_gen.advance(instance_name, token)
|
||||||
|
return super().process_replication_rows(stream_name, instance_name, token, rows)
|
||||||
|
|
||||||
async def get_pushers_by_app_id_and_pushkey(
|
async def get_pushers_by_app_id_and_pushkey(
|
||||||
self, app_id: str, pushkey: str
|
self, app_id: str, pushkey: str
|
||||||
) -> Iterator[PusherConfig]:
|
) -> Iterator[PusherConfig]:
|
||||||
|
@ -545,8 +573,9 @@ class PusherBackgroundUpdatesStore(SQLBaseStore):
|
||||||
|
|
||||||
|
|
||||||
class PusherStore(PusherWorkerStore, PusherBackgroundUpdatesStore):
|
class PusherStore(PusherWorkerStore, PusherBackgroundUpdatesStore):
|
||||||
def get_pushers_stream_token(self) -> int:
|
# Because we have write access, this will be a StreamIdGenerator
|
||||||
return self._pushers_id_gen.get_current_token()
|
# (see PusherWorkerStore.__init__)
|
||||||
|
_pushers_id_gen: AbstractStreamIdGenerator
|
||||||
|
|
||||||
async def add_pusher(
|
async def add_pusher(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -415,6 +415,7 @@ class StreamWorkerStore(EventsWorkerStore, SQLBaseStore):
|
||||||
)
|
)
|
||||||
|
|
||||||
self._stream_order_on_start = self.get_room_max_stream_ordering()
|
self._stream_order_on_start = self.get_room_max_stream_ordering()
|
||||||
|
self._min_stream_order_on_start = self.get_room_min_stream_ordering()
|
||||||
|
|
||||||
def get_room_max_stream_ordering(self) -> int:
|
def get_room_max_stream_ordering(self) -> int:
|
||||||
"""Get the stream_ordering of regular events that we have committed up to
|
"""Get the stream_ordering of regular events that we have committed up to
|
||||||
|
|
|
@ -21,11 +21,11 @@ from synapse.api.constants import ReceiptTypes
|
||||||
from synapse.api.room_versions import RoomVersions
|
from synapse.api.room_versions import RoomVersions
|
||||||
from synapse.events import FrozenEvent, _EventInternalMetadata, make_event_from_dict
|
from synapse.events import FrozenEvent, _EventInternalMetadata, make_event_from_dict
|
||||||
from synapse.handlers.room import RoomEventSource
|
from synapse.handlers.room import RoomEventSource
|
||||||
from synapse.replication.slave.storage.events import SlavedEventStore
|
|
||||||
from synapse.storage.databases.main.event_push_actions import (
|
from synapse.storage.databases.main.event_push_actions import (
|
||||||
NotifCounts,
|
NotifCounts,
|
||||||
RoomNotifCounts,
|
RoomNotifCounts,
|
||||||
)
|
)
|
||||||
|
from synapse.storage.databases.main.events_worker import EventsWorkerStore
|
||||||
from synapse.storage.roommember import GetRoomsForUserWithStreamOrdering, RoomsForUser
|
from synapse.storage.roommember import GetRoomsForUserWithStreamOrdering, RoomsForUser
|
||||||
from synapse.types import PersistedEventPosition
|
from synapse.types import PersistedEventPosition
|
||||||
|
|
||||||
|
@ -58,9 +58,9 @@ def patch__eq__(cls):
|
||||||
return unpatch
|
return unpatch
|
||||||
|
|
||||||
|
|
||||||
class SlavedEventStoreTestCase(BaseSlavedStoreTestCase):
|
class EventsWorkerStoreTestCase(BaseSlavedStoreTestCase):
|
||||||
|
|
||||||
STORE_TYPE = SlavedEventStore
|
STORE_TYPE = EventsWorkerStore
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Patch up the equality operator for events so that we can check
|
# Patch up the equality operator for events so that we can check
|
||||||
|
|
Loading…
Reference in a new issue