Fix mainline ordering in state res v2 (#8971)

This had two effects 1) it'd give the wrong answer and b) would iterate
*all* power levels in the auth chain of each event. The latter of which
can be *very* expensive for certain types of IRC bridge rooms that have
large numbers of power level changes.
This commit is contained in:
Erik Johnston 2020-12-18 15:00:34 +00:00 committed by GitHub
parent 28877fade9
commit 5e7d75daa2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 2 deletions

1
changelog.d/8971.bugfix Normal file
View File

@ -0,0 +1 @@
Fix small bug in v2 state resolution algorithm, which could also cause performance issues for rooms with large numbers of power levels.

View File

@ -658,7 +658,7 @@ async def _get_mainline_depth_for_event(
# We do an iterative search, replacing `event with the power level in its # We do an iterative search, replacing `event with the power level in its
# auth events (if any) # auth events (if any)
while tmp_event: while tmp_event:
depth = mainline_map.get(event.event_id) depth = mainline_map.get(tmp_event.event_id)
if depth is not None: if depth is not None:
return depth return depth

View File

@ -88,7 +88,7 @@ class FakeEvent:
event_dict = { event_dict = {
"auth_events": [(a, {}) for a in auth_events], "auth_events": [(a, {}) for a in auth_events],
"prev_events": [(p, {}) for p in prev_events], "prev_events": [(p, {}) for p in prev_events],
"event_id": self.node_id, "event_id": self.event_id,
"sender": self.sender, "sender": self.sender,
"type": self.type, "type": self.type,
"content": self.content, "content": self.content,
@ -381,6 +381,61 @@ class StateTestCase(unittest.TestCase):
self.do_check(events, edges, expected_state_ids) self.do_check(events, edges, expected_state_ids)
def test_mainline_sort(self):
"""Tests that the mainline ordering works correctly.
"""
events = [
FakeEvent(
id="T1", sender=ALICE, type=EventTypes.Topic, state_key="", content={}
),
FakeEvent(
id="PA1",
sender=ALICE,
type=EventTypes.PowerLevels,
state_key="",
content={"users": {ALICE: 100, BOB: 50}},
),
FakeEvent(
id="T2", sender=ALICE, type=EventTypes.Topic, state_key="", content={}
),
FakeEvent(
id="PA2",
sender=ALICE,
type=EventTypes.PowerLevels,
state_key="",
content={
"users": {ALICE: 100, BOB: 50},
"events": {EventTypes.PowerLevels: 100},
},
),
FakeEvent(
id="PB",
sender=BOB,
type=EventTypes.PowerLevels,
state_key="",
content={"users": {ALICE: 100, BOB: 50}},
),
FakeEvent(
id="T3", sender=BOB, type=EventTypes.Topic, state_key="", content={}
),
FakeEvent(
id="T4", sender=ALICE, type=EventTypes.Topic, state_key="", content={}
),
]
edges = [
["END", "T3", "PA2", "T2", "PA1", "T1", "START"],
["END", "T4", "PB", "PA1"],
]
# We expect T3 to be picked as the other topics are pointing at older
# power levels. Note that without mainline ordering we'd pick T4 due to
# it being sent *after* T3.
expected_state_ids = ["T3", "PA2"]
self.do_check(events, edges, expected_state_ids)
def do_check(self, events, edges, expected_state_ids): def do_check(self, events, edges, expected_state_ids):
"""Take a list of events and edges and calculate the state of the """Take a list of events and edges and calculate the state of the
graph at END, and asserts it matches `expected_state_ids` graph at END, and asserts it matches `expected_state_ids`