Add replication data handler concept.
This stops us having to subclass ReplicationClientHandler and override methods.pull/7185/head
parent
7966a1cde9
commit
699ccf3f0e
|
@ -64,7 +64,7 @@ from synapse.replication.slave.storage.receipts import SlavedReceiptsStore
|
||||||
from synapse.replication.slave.storage.registration import SlavedRegistrationStore
|
from synapse.replication.slave.storage.registration import SlavedRegistrationStore
|
||||||
from synapse.replication.slave.storage.room import RoomStore
|
from synapse.replication.slave.storage.room import RoomStore
|
||||||
from synapse.replication.slave.storage.transactions import SlavedTransactionStore
|
from synapse.replication.slave.storage.transactions import SlavedTransactionStore
|
||||||
from synapse.replication.tcp.client import ReplicationClientHandler
|
from synapse.replication.tcp.client import ReplicationDataHandler
|
||||||
from synapse.replication.tcp.commands import ClearUserSyncsCommand
|
from synapse.replication.tcp.commands import ClearUserSyncsCommand
|
||||||
from synapse.replication.tcp.streams import (
|
from synapse.replication.tcp.streams import (
|
||||||
AccountDataStream,
|
AccountDataStream,
|
||||||
|
@ -603,7 +603,7 @@ class GenericWorkerServer(HomeServer):
|
||||||
def remove_pusher(self, app_id, push_key, user_id):
|
def remove_pusher(self, app_id, push_key, user_id):
|
||||||
self.get_tcp_replication().send_remove_pusher(app_id, push_key, user_id)
|
self.get_tcp_replication().send_remove_pusher(app_id, push_key, user_id)
|
||||||
|
|
||||||
def build_tcp_replication(self):
|
def build_replication_data_handler(self):
|
||||||
return GenericWorkerReplicationHandler(self)
|
return GenericWorkerReplicationHandler(self)
|
||||||
|
|
||||||
def build_presence_handler(self):
|
def build_presence_handler(self):
|
||||||
|
@ -613,7 +613,7 @@ class GenericWorkerServer(HomeServer):
|
||||||
return GenericWorkerTyping(self)
|
return GenericWorkerTyping(self)
|
||||||
|
|
||||||
|
|
||||||
class GenericWorkerReplicationHandler(ReplicationClientHandler):
|
class GenericWorkerReplicationHandler(ReplicationDataHandler):
|
||||||
def __init__(self, hs):
|
def __init__(self, hs):
|
||||||
super(GenericWorkerReplicationHandler, self).__init__(hs.get_datastore())
|
super(GenericWorkerReplicationHandler, self).__init__(hs.get_datastore())
|
||||||
|
|
||||||
|
@ -644,9 +644,6 @@ class GenericWorkerReplicationHandler(ReplicationClientHandler):
|
||||||
args.update(self.send_handler.stream_positions())
|
args.update(self.send_handler.stream_positions())
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def get_currently_syncing_users(self):
|
|
||||||
return self.presence_handler.get_currently_syncing_users()
|
|
||||||
|
|
||||||
async def process_and_notify(self, stream_name, token, rows):
|
async def process_and_notify(self, stream_name, token, rows):
|
||||||
try:
|
try:
|
||||||
if self.send_handler:
|
if self.send_handler:
|
||||||
|
|
|
@ -20,7 +20,6 @@ from typing import Dict, List, Optional
|
||||||
|
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from twisted.internet.protocol import ReconnectingClientFactory
|
from twisted.internet.protocol import ReconnectingClientFactory
|
||||||
|
|
||||||
from synapse.replication.slave.storage._base import BaseSlavedStore
|
from synapse.replication.slave.storage._base import BaseSlavedStore
|
||||||
from synapse.replication.tcp.protocol import (
|
from synapse.replication.tcp.protocol import (
|
||||||
AbstractReplicationClientHandler,
|
AbstractReplicationClientHandler,
|
||||||
|
@ -37,6 +36,10 @@ from .commands import (
|
||||||
UserSyncCommand,
|
UserSyncCommand,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MYPY = False
|
||||||
|
if MYPY:
|
||||||
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,8 +87,9 @@ class ReplicationClientHandler(AbstractReplicationClientHandler):
|
||||||
By default proxies incoming replication data to the SlaveStore.
|
By default proxies incoming replication data to the SlaveStore.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, store: BaseSlavedStore):
|
def __init__(self, hs: "HomeServer"):
|
||||||
self.store = store
|
self.presence_handler = hs.get_presence_handler()
|
||||||
|
self.data_handler = hs.get_replication_data_handler()
|
||||||
|
|
||||||
# The current connection. None if we are currently (re)connecting
|
# The current connection. None if we are currently (re)connecting
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
@ -125,7 +129,7 @@ class ReplicationClientHandler(AbstractReplicationClientHandler):
|
||||||
Stream.parse_row.
|
Stream.parse_row.
|
||||||
"""
|
"""
|
||||||
logger.debug("Received rdata %s -> %s", stream_name, token)
|
logger.debug("Received rdata %s -> %s", stream_name, token)
|
||||||
self.store.process_replication_rows(stream_name, token, rows)
|
await self.data_handler.on_rdata(stream_name, token, rows)
|
||||||
|
|
||||||
async def on_position(self, stream_name, token):
|
async def on_position(self, stream_name, token):
|
||||||
"""Called when we get new position data. By default this just pokes
|
"""Called when we get new position data. By default this just pokes
|
||||||
|
@ -133,7 +137,7 @@ class ReplicationClientHandler(AbstractReplicationClientHandler):
|
||||||
|
|
||||||
Can be overriden in subclasses to handle more.
|
Can be overriden in subclasses to handle more.
|
||||||
"""
|
"""
|
||||||
self.store.process_replication_rows(stream_name, token, [])
|
await self.data_handler.on_position(stream_name, token)
|
||||||
|
|
||||||
def on_sync(self, data):
|
def on_sync(self, data):
|
||||||
"""When we received a SYNC we wake up any deferreds that were waiting
|
"""When we received a SYNC we wake up any deferreds that were waiting
|
||||||
|
@ -156,22 +160,15 @@ class ReplicationClientHandler(AbstractReplicationClientHandler):
|
||||||
map from stream name to the most recent update we have for
|
map from stream name to the most recent update we have for
|
||||||
that stream (ie, the point we want to start replicating from)
|
that stream (ie, the point we want to start replicating from)
|
||||||
"""
|
"""
|
||||||
args = self.store.stream_positions()
|
|
||||||
user_account_data = args.pop("user_account_data", None)
|
|
||||||
room_account_data = args.pop("room_account_data", None)
|
|
||||||
if user_account_data:
|
|
||||||
args["account_data"] = user_account_data
|
|
||||||
elif room_account_data:
|
|
||||||
args["account_data"] = room_account_data
|
|
||||||
|
|
||||||
return args
|
return self.data_handler.get_streams_to_replicate()
|
||||||
|
|
||||||
def get_currently_syncing_users(self):
|
def get_currently_syncing_users(self):
|
||||||
"""Get the list of currently syncing users (if any). This is called
|
"""Get the list of currently syncing users (if any). This is called
|
||||||
when a connection has been established and we need to send the
|
when a connection has been established and we need to send the
|
||||||
currently syncing users. (Overriden by the synchrotron's only)
|
currently syncing users. (Overriden by the synchrotron's only)
|
||||||
"""
|
"""
|
||||||
return []
|
return self.presence_handler.get_currently_syncing_users()
|
||||||
|
|
||||||
def send_command(self, cmd):
|
def send_command(self, cmd):
|
||||||
"""Send a command to master (when we get establish a connection if we
|
"""Send a command to master (when we get establish a connection if we
|
||||||
|
@ -245,3 +242,45 @@ class ReplicationClientHandler(AbstractReplicationClientHandler):
|
||||||
# server.
|
# server.
|
||||||
if self.factory:
|
if self.factory:
|
||||||
self.factory.resetDelay()
|
self.factory.resetDelay()
|
||||||
|
|
||||||
|
|
||||||
|
class ReplicationDataHandler:
|
||||||
|
"""A replication data handler that calls slave data stores.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, store: BaseSlavedStore):
|
||||||
|
self.store = store
|
||||||
|
|
||||||
|
async def on_rdata(self, stream_name: str, token: int, rows: list):
|
||||||
|
"""Called to handle a batch of replication data with a given stream token.
|
||||||
|
|
||||||
|
By default this just pokes the slave store. Can be overridden in subclasses to
|
||||||
|
handle more.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
stream_name (str): name of the replication stream for this batch of rows
|
||||||
|
token (int): stream token for this batch of rows
|
||||||
|
rows (list): a list of Stream.ROW_TYPE objects as returned by
|
||||||
|
Stream.parse_row.
|
||||||
|
"""
|
||||||
|
self.store.process_replication_rows(stream_name, token, rows)
|
||||||
|
|
||||||
|
def get_streams_to_replicate(self) -> Dict[str, int]:
|
||||||
|
"""Called when a new connection has been established and we need to
|
||||||
|
subscribe to streams.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
map from stream name to the most recent update we have for
|
||||||
|
that stream (ie, the point we want to start replicating from)
|
||||||
|
"""
|
||||||
|
args = self.store.stream_positions()
|
||||||
|
user_account_data = args.pop("user_account_data", None)
|
||||||
|
room_account_data = args.pop("room_account_data", None)
|
||||||
|
if user_account_data:
|
||||||
|
args["account_data"] = user_account_data
|
||||||
|
elif room_account_data:
|
||||||
|
args["account_data"] = room_account_data
|
||||||
|
return args
|
||||||
|
|
||||||
|
async def on_position(self, stream_name: str, token: int):
|
||||||
|
self.store.process_replication_rows(stream_name, token, [])
|
||||||
|
|
|
@ -87,6 +87,10 @@ from synapse.http.matrixfederationclient import MatrixFederationHttpClient
|
||||||
from synapse.notifier import Notifier
|
from synapse.notifier import Notifier
|
||||||
from synapse.push.action_generator import ActionGenerator
|
from synapse.push.action_generator import ActionGenerator
|
||||||
from synapse.push.pusherpool import PusherPool
|
from synapse.push.pusherpool import PusherPool
|
||||||
|
from synapse.replication.tcp.client import (
|
||||||
|
ReplicationClientHandler,
|
||||||
|
ReplicationDataHandler,
|
||||||
|
)
|
||||||
from synapse.replication.tcp.resource import ReplicationStreamer
|
from synapse.replication.tcp.resource import ReplicationStreamer
|
||||||
from synapse.rest.media.v1.media_repository import (
|
from synapse.rest.media.v1.media_repository import (
|
||||||
MediaRepository,
|
MediaRepository,
|
||||||
|
@ -206,6 +210,7 @@ class HomeServer(object):
|
||||||
"password_policy_handler",
|
"password_policy_handler",
|
||||||
"storage",
|
"storage",
|
||||||
"replication_streamer",
|
"replication_streamer",
|
||||||
|
"replication_data_handler",
|
||||||
]
|
]
|
||||||
|
|
||||||
REQUIRED_ON_MASTER_STARTUP = ["user_directory_handler", "stats_handler"]
|
REQUIRED_ON_MASTER_STARTUP = ["user_directory_handler", "stats_handler"]
|
||||||
|
@ -468,7 +473,7 @@ class HomeServer(object):
|
||||||
return ReadMarkerHandler(self)
|
return ReadMarkerHandler(self)
|
||||||
|
|
||||||
def build_tcp_replication(self):
|
def build_tcp_replication(self):
|
||||||
raise NotImplementedError()
|
return ReplicationClientHandler(self)
|
||||||
|
|
||||||
def build_action_generator(self):
|
def build_action_generator(self):
|
||||||
return ActionGenerator(self)
|
return ActionGenerator(self)
|
||||||
|
@ -562,6 +567,9 @@ class HomeServer(object):
|
||||||
def build_replication_streamer(self) -> ReplicationStreamer:
|
def build_replication_streamer(self) -> ReplicationStreamer:
|
||||||
return ReplicationStreamer(self)
|
return ReplicationStreamer(self)
|
||||||
|
|
||||||
|
def build_replication_data_handler(self):
|
||||||
|
return ReplicationDataHandler(self.get_datastore())
|
||||||
|
|
||||||
def remove_pusher(self, app_id, push_key, user_id):
|
def remove_pusher(self, app_id, push_key, user_id):
|
||||||
return self.get_pusherpool().remove_pusher(app_id, push_key, user_id)
|
return self.get_pusherpool().remove_pusher(app_id, push_key, user_id)
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,10 @@ class HomeServer(object):
|
||||||
self,
|
self,
|
||||||
) -> synapse.replication.tcp.client.ReplicationClientHandler:
|
) -> synapse.replication.tcp.client.ReplicationClientHandler:
|
||||||
pass
|
pass
|
||||||
|
def get_replication_data_handler(
|
||||||
|
self,
|
||||||
|
) -> synapse.replication.tcp.client.ReplicationDataHandler:
|
||||||
|
pass
|
||||||
def get_federation_registry(
|
def get_federation_registry(
|
||||||
self,
|
self,
|
||||||
) -> synapse.federation.federation_server.FederationHandlerRegistry:
|
) -> synapse.federation.federation_server.FederationHandlerRegistry:
|
||||||
|
|
Loading…
Reference in New Issue