Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 835da407c8 | |||
| 46a64f473d | |||
| cec8ef5890 | |||
| 0f48724e00 | |||
| 7780a71abf | |||
| 55c6252edd | |||
| 6e2140364b | |||
| 6e5663b291 | |||
| b81cab0794 | |||
| d8dc12a95c | |||
| f8f06fc773 | |||
| 05e8a5d298 | |||
| 3e2e76ca15 |
+15
@@ -1,3 +1,18 @@
|
||||
Synapse 1.57.1 (2022-04-20)
|
||||
===========================
|
||||
|
||||
This is a patch release that only affects the Docker image. It is only of interest to administrators using [the LDAP module][LDAPModule] to authenticate their users.
|
||||
If you have already upgraded to Synapse 1.57.0 without problem, then you have no need to upgrade to this patch release.
|
||||
|
||||
[LDAPModule]: https://github.com/matrix-org/matrix-synapse-ldap3
|
||||
|
||||
|
||||
Updates to the Docker image
|
||||
---------------------------
|
||||
|
||||
- Include version 0.2.0 of the Synapse LDAP Auth Provider module in the Docker image. This matches the version that was present in the Docker image for Synapse v1.56.0. ([\#12512](https://github.com/matrix-org/synapse/issues/12512))
|
||||
|
||||
|
||||
Synapse 1.57.0 (2022-04-19)
|
||||
===========================
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Optimise room backfill, to reduce memory usage.
|
||||
Vendored
+6
@@ -1,3 +1,9 @@
|
||||
matrix-synapse-py3 (1.57.1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.57.1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Wed, 20 Apr 2022 15:27:21 +0100
|
||||
|
||||
matrix-synapse-py3 (1.57.0) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.57.0.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# syntax=docker/dockerfile:experimental
|
||||
# Dockerfile to build the matrixdotorg/synapse docker images.
|
||||
#
|
||||
# Note that it uses features which are only available in BuildKit - see
|
||||
|
||||
Generated
+8
-4
@@ -558,17 +558,20 @@ test = ["tox", "twisted", "aiounittest"]
|
||||
|
||||
[[package]]
|
||||
name = "matrix-synapse-ldap3"
|
||||
version = "0.1.5"
|
||||
version = "0.2.0"
|
||||
description = "An LDAP3 auth provider for Synapse"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
ldap3 = ">=2.8"
|
||||
service_identity = "*"
|
||||
service-identity = "*"
|
||||
Twisted = ">=15.1.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["matrix-synapse", "tox", "ldaptor", "mypy (==0.910)", "types-setuptools", "black (==21.9b0)", "flake8 (==4.0.1)", "isort (==5.9.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.6.1"
|
||||
@@ -2084,7 +2087,8 @@ matrix-common = [
|
||||
{file = "matrix_common-1.1.0.tar.gz", hash = "sha256:a8238748afc2b37079818367fed5156f355771b07c8ff0a175934f47e0ff3276"},
|
||||
]
|
||||
matrix-synapse-ldap3 = [
|
||||
{file = "matrix-synapse-ldap3-0.1.5.tar.gz", hash = "sha256:9fdf8df7c8ec756642aa0fea53b31c0b2f1924f70d7f049a2090b523125456fe"},
|
||||
{file = "matrix-synapse-ldap3-0.2.0.tar.gz", hash = "sha256:91a0715b43a41ec3033244174fca20846836da98fda711fb01687f7199eecd2e"},
|
||||
{file = "matrix_synapse_ldap3-0.2.0-py3-none-any.whl", hash = "sha256:0128ca7c3058987adc2e8a88463bb46879915bfd3d373309632813b353e30f9f"},
|
||||
]
|
||||
mccabe = [
|
||||
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ skip_gitignore = true
|
||||
|
||||
[tool.poetry]
|
||||
name = "matrix-synapse"
|
||||
version = "1.57.0"
|
||||
version = "1.57.1"
|
||||
description = "Homeserver for the Matrix decentralised comms protocol"
|
||||
authors = ["Matrix.org Team and Contributors <packages@matrix.org>"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
__version__ = "1.57.0"
|
||||
__version__ = "1.57.1"
|
||||
|
||||
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
|
||||
# We import here so that we don't have to install a bunch of deps when
|
||||
|
||||
+110
-81
@@ -1,4 +1,4 @@
|
||||
# Copyright 2014-2021 The Matrix.org Foundation C.I.C.
|
||||
# Copyright 2014-2022 The Matrix.org Foundation C.I.C.
|
||||
# Copyright 2020 Sorunome
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -15,9 +15,10 @@
|
||||
|
||||
"""Contains handlers for federation events."""
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from http import HTTPStatus
|
||||
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple, Union
|
||||
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple, Union
|
||||
|
||||
from signedjson.key import decode_verify_key_bytes
|
||||
from signedjson.sign import verify_signed_json
|
||||
@@ -178,68 +179,24 @@ class FederationHandler:
|
||||
logger.debug("Not backfilling as no extremeties found.")
|
||||
return False
|
||||
|
||||
# We only want to paginate if we can actually see the events we'll get,
|
||||
# as otherwise we'll just spend a lot of resources to get redacted
|
||||
# events.
|
||||
#
|
||||
# We do this by filtering all the backwards extremities and seeing if
|
||||
# any remain. Given we don't have the extremity events themselves, we
|
||||
# need to actually check the events that reference them.
|
||||
#
|
||||
# *Note*: the spec wants us to keep backfilling until we reach the start
|
||||
# of the room in case we are allowed to see some of the history. However
|
||||
# in practice that causes more issues than its worth, as a) its
|
||||
# relatively rare for there to be any visible history and b) even when
|
||||
# there is its often sufficiently long ago that clients would stop
|
||||
# attempting to paginate before backfill reached the visible history.
|
||||
#
|
||||
# TODO: If we do do a backfill then we should filter the backwards
|
||||
# extremities to only include those that point to visible portions of
|
||||
# history.
|
||||
#
|
||||
# TODO: Correctly handle the case where we are allowed to see the
|
||||
# forward event but not the backward extremity, e.g. in the case of
|
||||
# initial join of the server where we are allowed to see the join
|
||||
# event but not anything before it. This would require looking at the
|
||||
# state *before* the event, ignoring the special casing certain event
|
||||
# types have.
|
||||
|
||||
forward_event_ids = await self.store.get_successor_events(
|
||||
list(oldest_events_with_depth)
|
||||
)
|
||||
|
||||
extremities_events = await self.store.get_events(
|
||||
forward_event_ids,
|
||||
redact_behaviour=EventRedactBehaviour.AS_IS,
|
||||
get_prev_content=False,
|
||||
)
|
||||
|
||||
# We set `check_history_visibility_only` as we might otherwise get false
|
||||
# positives from users having been erased.
|
||||
filtered_extremities = await filter_events_for_server(
|
||||
self.storage,
|
||||
self.server_name,
|
||||
list(extremities_events.values()),
|
||||
redact=False,
|
||||
check_history_visibility_only=True,
|
||||
# we now have a list of potential places to backpaginate from. We prefer to
|
||||
# start with the most recent (ie, max depth), so let's sort the list.
|
||||
sorted_extremeties_tuples: List[Tuple[str, int]] = sorted(
|
||||
itertools.chain(
|
||||
oldest_events_with_depth.items(),
|
||||
insertion_events_to_be_backfilled.items(),
|
||||
),
|
||||
key=lambda e: -int(e[1]),
|
||||
)
|
||||
logger.debug(
|
||||
"_maybe_backfill_inner: filtered_extremities %s", filtered_extremities
|
||||
"_maybe_backfill_inner: room_id: %s: current_depth: %s, limit: %s, extrems (%d): %s",
|
||||
room_id,
|
||||
current_depth,
|
||||
limit,
|
||||
len(sorted_extremeties_tuples),
|
||||
sorted_extremeties_tuples,
|
||||
)
|
||||
|
||||
if not filtered_extremities and not insertion_events_to_be_backfilled:
|
||||
return False
|
||||
|
||||
extremities = {
|
||||
**oldest_events_with_depth,
|
||||
# TODO: insertion_events_to_be_backfilled is currently skipping the filtered_extremities checks
|
||||
**insertion_events_to_be_backfilled,
|
||||
}
|
||||
|
||||
# Check if we reached a point where we should start backfilling.
|
||||
sorted_extremeties_tuple = sorted(extremities.items(), key=lambda e: -int(e[1]))
|
||||
max_depth = sorted_extremeties_tuple[0][1]
|
||||
|
||||
# If we're approaching an extremity we trigger a backfill, otherwise we
|
||||
# no-op.
|
||||
#
|
||||
@@ -249,6 +206,11 @@ class FederationHandler:
|
||||
# chose more than one times the limit in case of failure, but choosing a
|
||||
# much larger factor will result in triggering a backfill request much
|
||||
# earlier than necessary.
|
||||
#
|
||||
# XXX: shouldn't we do this *after* the filter by depth below? Again, we don't
|
||||
# care about events that have happened after our current position.
|
||||
#
|
||||
max_depth = sorted_extremeties_tuples[0][1]
|
||||
if current_depth - 2 * limit > max_depth:
|
||||
logger.debug(
|
||||
"Not backfilling as we don't need to. %d < %d - 2 * %d",
|
||||
@@ -265,31 +227,98 @@ class FederationHandler:
|
||||
# 2. we have likely previously tried and failed to backfill from that
|
||||
# extremity, so to avoid getting "stuck" requesting the same
|
||||
# backfill repeatedly we drop those extremities.
|
||||
filtered_sorted_extremeties_tuple = [
|
||||
t for t in sorted_extremeties_tuple if int(t[1]) <= current_depth
|
||||
]
|
||||
|
||||
logger.debug(
|
||||
"room_id: %s, backfill: current_depth: %s, limit: %s, max_depth: %s, extrems (%d): %s filtered_sorted_extremeties_tuple: %s",
|
||||
room_id,
|
||||
current_depth,
|
||||
limit,
|
||||
max_depth,
|
||||
len(sorted_extremeties_tuple),
|
||||
sorted_extremeties_tuple,
|
||||
filtered_sorted_extremeties_tuple,
|
||||
)
|
||||
|
||||
#
|
||||
# However, we need to check that the filtered extremities are non-empty.
|
||||
# If they are empty then either we can a) bail or b) still attempt to
|
||||
# backfill. We opt to try backfilling anyway just in case we do get
|
||||
# relevant events.
|
||||
if filtered_sorted_extremeties_tuple:
|
||||
sorted_extremeties_tuple = filtered_sorted_extremeties_tuple
|
||||
#
|
||||
filtered_sorted_extremeties_tuples = [
|
||||
t for t in sorted_extremeties_tuples if int(t[1]) <= current_depth
|
||||
]
|
||||
if filtered_sorted_extremeties_tuples:
|
||||
logger.debug(
|
||||
"_maybe_backfill_inner: extrems before current depth: %s",
|
||||
filtered_sorted_extremeties_tuples,
|
||||
)
|
||||
sorted_extremeties_tuples = filtered_sorted_extremeties_tuples
|
||||
else:
|
||||
logger.debug(
|
||||
"_maybe_backfill_inner: all extrems are *after* current depth. Backfilling anyway."
|
||||
)
|
||||
|
||||
# We don't want to specify too many extremities as it causes the backfill
|
||||
# request URI to be too long.
|
||||
extremities = dict(sorted_extremeties_tuple[:5])
|
||||
# We still need to narrow down the list of extremities we pass to the remote
|
||||
# server. We limit to 5 of them, to avoid the request URI becoming too long.
|
||||
#
|
||||
# However, we only want to paginate from a particular extremity if we can
|
||||
# actually see the events we'll get, as otherwise we'll just spend a lot of
|
||||
# resources to get redacted events.
|
||||
#
|
||||
# We do this by filtering all the backwards extremities and seeing if
|
||||
# any remain. Given we don't have the extremity events themselves, we
|
||||
# need to actually check the events that reference them - their "successor"
|
||||
# events.
|
||||
#
|
||||
# *Note*: the spec wants us to keep backfilling until we reach the start
|
||||
# of the room in case we are allowed to see some of the history. However
|
||||
# in practice that causes more issues than its worth, as a) its
|
||||
# relatively rare for there to be any visible history and b) even when
|
||||
# there is its often sufficiently long ago that clients would stop
|
||||
# attempting to paginate before backfill reached the visible history.
|
||||
#
|
||||
# Calculating the visibility of each extremity is quite expensive, and there
|
||||
# can be thousands of them in a big gappy room, so we just check them one
|
||||
# by one until we've checked them all, or we've got 5 of them.
|
||||
#
|
||||
# TODO: Correctly handle the case where we are allowed to see the
|
||||
# successor event but not the backward extremity, e.g. in the case of
|
||||
# initial join of the server where we are allowed to see the join
|
||||
# event but not anything before it. This would require looking at the
|
||||
# state *before* the event, ignoring the special casing certain event
|
||||
# types have.
|
||||
|
||||
extremities_to_request: Set[str] = set()
|
||||
for extremity_event_id, _ in sorted_extremeties_tuples:
|
||||
if len(extremities_to_request) >= 5:
|
||||
break
|
||||
|
||||
successor_event_ids = await self.store.get_successor_events(
|
||||
[extremity_event_id]
|
||||
)
|
||||
|
||||
successor_events = await self.store.get_events_as_list(
|
||||
successor_event_ids,
|
||||
redact_behaviour=EventRedactBehaviour.AS_IS,
|
||||
get_prev_content=False,
|
||||
)
|
||||
|
||||
# We set `check_history_visibility_only` as we might otherwise get false
|
||||
# positives from users having been erased.
|
||||
filtered_extremities = await filter_events_for_server(
|
||||
self.storage,
|
||||
self.server_name,
|
||||
successor_events,
|
||||
redact=False,
|
||||
check_history_visibility_only=True,
|
||||
)
|
||||
|
||||
if filtered_extremities:
|
||||
extremities_to_request.add(extremity_event_id)
|
||||
else:
|
||||
logger.debug(
|
||||
"_maybe_backfill_inner: skipping extremity %s as it would not be visible.",
|
||||
extremity_event_id,
|
||||
)
|
||||
|
||||
if not extremities_to_request:
|
||||
logger.debug(
|
||||
"_maybe_backfill_inner: found no extremities which would be visible"
|
||||
)
|
||||
return False
|
||||
|
||||
logger.debug(
|
||||
"_maybe_backfill_inner: extremities_to_request %s", extremities_to_request
|
||||
)
|
||||
|
||||
# Now we need to decide which hosts to hit first.
|
||||
|
||||
@@ -309,7 +338,7 @@ class FederationHandler:
|
||||
for dom in domains:
|
||||
try:
|
||||
await self._federation_event_handler.backfill(
|
||||
dom, room_id, limit=100, extremities=extremities
|
||||
dom, room_id, limit=100, extremities=extremities_to_request
|
||||
)
|
||||
# If this succeeded then we probably already have the
|
||||
# appropriate stuff.
|
||||
|
||||
@@ -419,6 +419,13 @@ async def _event_to_memberships(
|
||||
return {}
|
||||
|
||||
# for each event, get the event_ids of the membership state at those events.
|
||||
#
|
||||
# TODO: this means that we request the entire membership list. If there are only
|
||||
# one or two users on this server, and the room is huge, this is very wasteful
|
||||
# (it means more db work, and churns the *stateGroupMembersCache*).
|
||||
# It might be that we could extend StateFilter to specify "give me keys matching
|
||||
# *:<server_name>", to avoid this.
|
||||
|
||||
event_to_state_ids = await storage.state.get_state_ids_for_events(
|
||||
frozenset(e.event_id for e in events),
|
||||
state_filter=StateFilter.from_types(types=((EventTypes.Member, None),)),
|
||||
|
||||
Reference in New Issue
Block a user