diff options
author | David Robertson <davidr@element.io> | 2022-07-26 18:03:28 +0100 |
---|---|---|
committer | David Robertson <davidr@element.io> | 2022-07-26 18:03:28 +0100 |
commit | 92d79770d1d1f29790a3b1c557d3bd4edb9400a1 (patch) | |
tree | cc8b22e338fe5a7af4d872f93fe77fa73fd1fae0 | |
parent | Fix typos (diff) | |
download | synapse-92d79770d1d1f29790a3b1c557d3bd4edb9400a1.tar.xz |
Watch a piece of state in the auth DAG
-rwxr-xr-x | synapse/_scripts/debug_state_res.py | 74 |
1 files changed, 52 insertions, 22 deletions
diff --git a/synapse/_scripts/debug_state_res.py b/synapse/_scripts/debug_state_res.py index 2f946401dc..4ee04df078 100755 --- a/synapse/_scripts/debug_state_res.py +++ b/synapse/_scripts/debug_state_res.py @@ -5,7 +5,17 @@ import sys from collections import defaultdict, Counter from graphlib import TopologicalSorter from pprint import pformat -from typing import Mapping, Sequence, Dict, List, Tuple, Iterable, Collection +from typing import ( + Mapping, + Sequence, + Dict, + List, + Tuple, + Iterable, + Collection, + Optional, + Callable, Awaitable, +) from unittest.mock import MagicMock, patch import dictdiffer @@ -26,6 +36,7 @@ from synapse.storage.databases.main.event_federation import EventFederationWorke from synapse.storage.databases.main.events_worker import EventsWorkerStore from synapse.storage.databases.main.room import RoomWorkerStore from synapse.storage.databases.main.state import StateGroupWorkerStore +from synapse.storage.state import StateFilter from synapse.types import ISynapseReactor, StateMap, MutableStateMap logger = logging.getLogger(sys.argv[0]) @@ -64,14 +75,14 @@ class MockHomeserver(HomeServer): ) -def node(event: EventBase, **kwargs) -> pydot.Node: - kwargs.setdefault( - "label", - f"{event.event_id}\n{event.type}", - ) +def node(event: EventBase, suffix: Optional[str] = None, **kwargs) -> pydot.Node: + label = f"{event.event_id}\n{event.type}" + if suffix: + label += f"\n{suffix}" + kwargs.setdefault("label", label) type_to_shape = {"m.room.member": "oval"} - if "shape" not in kwargs and event.type in type_to_shape: - kwargs["shape"] = type_to_shape[event.type] + if event.type in type_to_shape: + kwargs.setdefault("shape", type_to_shape[event.type]) q = pydot.quote_if_necessary return pydot.Node(q(event.event_id), **kwargs) @@ -140,23 +151,30 @@ async def dump_auth_chains( async def dump_mainlines( hs: MockHomeserver, starting_event: EventBase, + watch_func: Optional[Callable[[EventBase], Awaitable[str]]] = None, extras: Collection[EventBase] = tuple(), ): graph = pydot.Dot(rankdir="BT") graph.set_node_defaults(shape="box", style="filled") - graph.add_node(node(starting_event, fillcolor="#6699cc")) + async def new_node(event: EventBase, **kwargs: object) -> pydot.Node: + if watch_func: + return node(event, suffix=await watch_func(event), **kwargs) + else: + return node(event, **kwargs) + + graph.add_node(await new_node(starting_event, fillcolor="#6699cc")) seen = {starting_event.event_id} todo = [] for extra in extras: - graph.add_node(node(extra, fillcolor="#cc9966")) + graph.add_node(await new_node(extra, fillcolor="#cc9966")) seen.add(extra.event_id) todo.append(extra) for pid in starting_event.prev_event_ids(): parent = await hs.get_datastores().main.get_event(pid) - graph.add_node(node(parent, fillcolor="#6699cc")) + graph.add_node(await new_node(parent, fillcolor="#6699cc")) seen.add(pid) graph.add_edge(edge(starting_event, parent, style="dashed")) todo.append(parent) @@ -179,9 +197,9 @@ async def dump_mainlines( if auth_event: if auth_event.event_id not in seen: if key[0] == "m.room.power_levels": - graph.add_node(node(auth_event, fillcolor="#ffcccc")) + graph.add_node(await new_node(auth_event, fillcolor="#ffcccc")) else: - graph.add_node(node(auth_event)) + graph.add_node(await new_node(auth_event)) seen.add(auth_event.event_id) todo.append(auth_event) graph.add_edge(edge(event, auth_event)) @@ -209,21 +227,32 @@ async def debug_specific_stateres( # Fetch the event in question. event = await hs.get_datastores().main.get_event(args.event_id) assert event is not None - logger.info("event %s has %d parents, %s", event.event_id, len(event.prev_event_ids()), event.prev_event_ids()) + logger.info( + "event %s has %d parents, %s", + event.event_id, + len(event.prev_event_ids()), + event.prev_event_ids(), + ) state_after_parents = [ await hs.get_storage_controllers().state.get_state_ids_for_event(prev_event_id) for prev_event_id in event.prev_event_ids() ] - # await dump_auth_chains(hs, state_after_parents) - extras = await hs.get_datastores().main.get_events( - [ - "$SIRWGpXP-CV6XtCdeHgFY_PIJXUzOHkaCUMsRN6RFes", - "$LgVDro6FUgz-qQJhGgeLGmvgc9xFZRJlyiHuia_VH78", - ] - ) - await dump_mainlines(hs, event, extras.values()) + await dump_auth_chains(hs, state_after_parents) + if args.watch is not None: + key_pair = tuple(args.watch) + filter = StateFilter.from_types([key_pair]) + + async def watch_func(event: EventBase) -> str: + result = await hs.get_storage_controllers().state.get_state_ids_for_event( + event.event_id, filter + ) + return f"{key_pair}: {result.get(key_pair, '<Missing>')}" + else: + watch_func = None + + await dump_mainlines(hs, event, watch_func) result = await hs.get_state_resolution_handler().resolve_events_with_store( event.room_id, @@ -260,6 +289,7 @@ debug_parser = subparsers.add_parser( description="debug the stateres calculation of a specific event", ) debug_parser.add_argument("event_id", help="the event ID to be resolved") +debug_parser.add_argument("--watch", help="track a piece of state in the auth DAG", default=None, nargs=2, metavar=("TYPE", "STATE_KEY")) debug_parser.set_defaults(func=debug_specific_stateres) |