forked from MirrorHub/synapse
Merge pull request #162 from matrix-org/erikj/backfill_fixes
backfill fixes
This commit is contained in:
commit
5ebd33302f
3 changed files with 153 additions and 94 deletions
|
@ -165,10 +165,11 @@ class FederationClient(FederationBase):
|
||||||
for p in transaction_data["pdus"]
|
for p in transaction_data["pdus"]
|
||||||
]
|
]
|
||||||
|
|
||||||
for i, pdu in enumerate(pdus):
|
# FIXME: We should handle signature failures more gracefully.
|
||||||
pdus[i] = yield self._check_sigs_and_hash(pdu)
|
pdus[:] = yield defer.gatherResults(
|
||||||
|
[self._check_sigs_and_hash(pdu) for pdu in pdus],
|
||||||
# FIXME: We should handle signature failures more gracefully.
|
consumeErrors=True,
|
||||||
|
).addErrback(unwrapFirstError)
|
||||||
|
|
||||||
defer.returnValue(pdus)
|
defer.returnValue(pdus)
|
||||||
|
|
||||||
|
|
|
@ -230,27 +230,65 @@ class FederationHandler(BaseHandler):
|
||||||
if not extremities:
|
if not extremities:
|
||||||
extremities = yield self.store.get_oldest_events_in_room(room_id)
|
extremities = yield self.store.get_oldest_events_in_room(room_id)
|
||||||
|
|
||||||
pdus = yield self.replication_layer.backfill(
|
events = yield self.replication_layer.backfill(
|
||||||
dest,
|
dest,
|
||||||
room_id,
|
room_id,
|
||||||
limit,
|
limit=limit,
|
||||||
extremities=extremities,
|
extremities=extremities,
|
||||||
)
|
)
|
||||||
|
|
||||||
events = []
|
event_map = {e.event_id: e for e in events}
|
||||||
|
|
||||||
for pdu in pdus:
|
event_ids = set(e.event_id for e in events)
|
||||||
event = pdu
|
|
||||||
|
|
||||||
# FIXME (erikj): Not sure this actually works :/
|
edges = [
|
||||||
context = yield self.state_handler.compute_event_context(event)
|
ev.event_id
|
||||||
|
for ev in events
|
||||||
|
if set(e_id for e_id, _ in ev.prev_events) - event_ids
|
||||||
|
]
|
||||||
|
|
||||||
events.append((event, context))
|
# For each edge get the current state.
|
||||||
|
|
||||||
yield self.store.persist_event(
|
auth_events = {}
|
||||||
event,
|
events_to_state = {}
|
||||||
context=context,
|
for e_id in edges:
|
||||||
backfilled=True
|
state, auth = yield self.replication_layer.get_state_for_room(
|
||||||
|
destination=dest,
|
||||||
|
room_id=room_id,
|
||||||
|
event_id=e_id
|
||||||
|
)
|
||||||
|
auth_events.update({a.event_id: a for a in auth})
|
||||||
|
events_to_state[e_id] = state
|
||||||
|
|
||||||
|
yield defer.gatherResults(
|
||||||
|
[
|
||||||
|
self._handle_new_event(dest, a)
|
||||||
|
for a in auth_events.values()
|
||||||
|
],
|
||||||
|
consumeErrors=True,
|
||||||
|
).addErrback(unwrapFirstError)
|
||||||
|
|
||||||
|
yield defer.gatherResults(
|
||||||
|
[
|
||||||
|
self._handle_new_event(
|
||||||
|
dest, event_map[e_id],
|
||||||
|
state=events_to_state[e_id],
|
||||||
|
backfilled=True,
|
||||||
|
)
|
||||||
|
for e_id in events_to_state
|
||||||
|
],
|
||||||
|
consumeErrors=True
|
||||||
|
).addErrback(unwrapFirstError)
|
||||||
|
|
||||||
|
events.sort(key=lambda e: e.depth)
|
||||||
|
|
||||||
|
for event in events:
|
||||||
|
if event in events_to_state:
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield self._handle_new_event(
|
||||||
|
dest, event,
|
||||||
|
backfilled=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
defer.returnValue(events)
|
defer.returnValue(events)
|
||||||
|
@ -347,7 +385,7 @@ class FederationHandler(BaseHandler):
|
||||||
logger.info(e.message)
|
logger.info(e.message)
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(
|
logger.exception(
|
||||||
"Failed to backfill from %s because %s",
|
"Failed to backfill from %s because %s",
|
||||||
dom, e,
|
dom, e,
|
||||||
)
|
)
|
||||||
|
@ -517,54 +555,9 @@ class FederationHandler(BaseHandler):
|
||||||
# FIXME
|
# FIXME
|
||||||
pass
|
pass
|
||||||
|
|
||||||
auth_ids_to_deferred = {}
|
yield self._handle_auth_events(
|
||||||
|
origin, [e for e in auth_chain if e.event_id != event.event_id]
|
||||||
def process_auth_ev(ev):
|
)
|
||||||
auth_ids = [e_id for e_id, _ in ev.auth_events]
|
|
||||||
|
|
||||||
prev_ds = [
|
|
||||||
auth_ids_to_deferred[i]
|
|
||||||
for i in auth_ids
|
|
||||||
if i in auth_ids_to_deferred
|
|
||||||
]
|
|
||||||
|
|
||||||
d = defer.Deferred()
|
|
||||||
|
|
||||||
auth_ids_to_deferred[ev.event_id] = d
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def f(*_):
|
|
||||||
ev.internal_metadata.outlier = True
|
|
||||||
|
|
||||||
try:
|
|
||||||
auth = {
|
|
||||||
(e.type, e.state_key): e for e in auth_chain
|
|
||||||
if e.event_id in auth_ids
|
|
||||||
}
|
|
||||||
|
|
||||||
yield self._handle_new_event(
|
|
||||||
origin, ev, auth_events=auth
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
logger.exception(
|
|
||||||
"Failed to handle auth event %s",
|
|
||||||
ev.event_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
d.callback(None)
|
|
||||||
|
|
||||||
if prev_ds:
|
|
||||||
dx = defer.DeferredList(prev_ds)
|
|
||||||
dx.addBoth(f)
|
|
||||||
else:
|
|
||||||
f()
|
|
||||||
|
|
||||||
for e in auth_chain:
|
|
||||||
if e.event_id == event.event_id:
|
|
||||||
return
|
|
||||||
process_auth_ev(e)
|
|
||||||
|
|
||||||
yield defer.DeferredList(auth_ids_to_deferred.values())
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def handle_state(e):
|
def handle_state(e):
|
||||||
|
@ -1348,3 +1341,52 @@ class FederationHandler(BaseHandler):
|
||||||
},
|
},
|
||||||
"missing": [e.event_id for e in missing_locals],
|
"missing": [e.event_id for e in missing_locals],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def _handle_auth_events(self, origin, auth_events):
|
||||||
|
auth_ids_to_deferred = {}
|
||||||
|
|
||||||
|
def process_auth_ev(ev):
|
||||||
|
auth_ids = [e_id for e_id, _ in ev.auth_events]
|
||||||
|
|
||||||
|
prev_ds = [
|
||||||
|
auth_ids_to_deferred[i]
|
||||||
|
for i in auth_ids
|
||||||
|
if i in auth_ids_to_deferred
|
||||||
|
]
|
||||||
|
|
||||||
|
d = defer.Deferred()
|
||||||
|
|
||||||
|
auth_ids_to_deferred[ev.event_id] = d
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def f(*_):
|
||||||
|
ev.internal_metadata.outlier = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = {
|
||||||
|
(e.type, e.state_key): e for e in auth_events
|
||||||
|
if e.event_id in auth_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
yield self._handle_new_event(
|
||||||
|
origin, ev, auth_events=auth
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
logger.exception(
|
||||||
|
"Failed to handle auth event %s",
|
||||||
|
ev.event_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
d.callback(None)
|
||||||
|
|
||||||
|
if prev_ds:
|
||||||
|
dx = defer.DeferredList(prev_ds)
|
||||||
|
dx.addBoth(f)
|
||||||
|
else:
|
||||||
|
f()
|
||||||
|
|
||||||
|
for e in auth_events:
|
||||||
|
process_auth_ev(e)
|
||||||
|
|
||||||
|
yield defer.DeferredList(auth_ids_to_deferred.values())
|
||||||
|
|
|
@ -19,6 +19,7 @@ from ._base import SQLBaseStore, cached
|
||||||
from syutil.base64util import encode_base64
|
from syutil.base64util import encode_base64
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from Queue import PriorityQueue, Empty
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -363,7 +364,11 @@ class EventFederationStore(SQLBaseStore):
|
||||||
return self.runInteraction(
|
return self.runInteraction(
|
||||||
"get_backfill_events",
|
"get_backfill_events",
|
||||||
self._get_backfill_events, room_id, event_list, limit
|
self._get_backfill_events, room_id, event_list, limit
|
||||||
).addCallback(self._get_events)
|
).addCallback(
|
||||||
|
self._get_events
|
||||||
|
).addCallback(
|
||||||
|
lambda l: sorted(l, key=lambda e: -e.depth)
|
||||||
|
)
|
||||||
|
|
||||||
def _get_backfill_events(self, txn, room_id, event_list, limit):
|
def _get_backfill_events(self, txn, room_id, event_list, limit):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
@ -371,43 +376,54 @@ class EventFederationStore(SQLBaseStore):
|
||||||
room_id, repr(event_list), limit
|
room_id, repr(event_list), limit
|
||||||
)
|
)
|
||||||
|
|
||||||
event_results = event_list
|
event_results = set()
|
||||||
|
|
||||||
front = event_list
|
# We want to make sure that we do a breadth-first, "depth" ordered
|
||||||
|
# search.
|
||||||
|
|
||||||
query = (
|
query = (
|
||||||
"SELECT prev_event_id FROM event_edges "
|
"SELECT depth, prev_event_id FROM event_edges"
|
||||||
"WHERE room_id = ? AND event_id = ? "
|
" INNER JOIN events"
|
||||||
"LIMIT ?"
|
" ON prev_event_id = events.event_id"
|
||||||
|
" AND event_edges.room_id = events.room_id"
|
||||||
|
" WHERE event_edges.room_id = ? AND event_edges.event_id = ?"
|
||||||
|
" AND event_edges.is_state = ?"
|
||||||
|
" LIMIT ?"
|
||||||
)
|
)
|
||||||
|
|
||||||
# We iterate through all event_ids in `front` to select their previous
|
queue = PriorityQueue()
|
||||||
# events. These are dumped in `new_front`.
|
|
||||||
# We continue until we reach the limit *or* new_front is empty (i.e.,
|
|
||||||
# we've run out of things to select
|
|
||||||
while front and len(event_results) < limit:
|
|
||||||
|
|
||||||
new_front = []
|
for event_id in event_list:
|
||||||
for event_id in front:
|
depth = self._simple_select_one_onecol_txn(
|
||||||
logger.debug(
|
txn,
|
||||||
"_backfill_interaction: id=%s",
|
table="events",
|
||||||
event_id
|
keyvalues={
|
||||||
)
|
"event_id": event_id,
|
||||||
|
},
|
||||||
|
retcol="depth"
|
||||||
|
)
|
||||||
|
|
||||||
txn.execute(
|
queue.put((-depth, event_id))
|
||||||
query,
|
|
||||||
(room_id, event_id, limit - len(event_results))
|
|
||||||
)
|
|
||||||
|
|
||||||
for row in txn.fetchall():
|
while not queue.empty() and len(event_results) < limit:
|
||||||
logger.debug(
|
try:
|
||||||
"_backfill_interaction: got id=%s",
|
_, event_id = queue.get_nowait()
|
||||||
*row
|
except Empty:
|
||||||
)
|
break
|
||||||
new_front.append(row[0])
|
|
||||||
|
|
||||||
front = new_front
|
if event_id in event_results:
|
||||||
event_results += new_front
|
continue
|
||||||
|
|
||||||
|
event_results.add(event_id)
|
||||||
|
|
||||||
|
txn.execute(
|
||||||
|
query,
|
||||||
|
(room_id, event_id, False, limit - len(event_results))
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in txn.fetchall():
|
||||||
|
if row[1] not in event_results:
|
||||||
|
queue.put((-row[0], row[1]))
|
||||||
|
|
||||||
return event_results
|
return event_results
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue