mirror of
https://github.com/hoernschen/dendrite.git
synced 2024-12-27 23:48:27 +00:00
Associate events in db before queueing them to send (#2833)
Fixes a race condition between sending federation events and having them fully associated in the database.
This commit is contained in:
parent
a74aea0714
commit
97491a174b
2 changed files with 60 additions and 34 deletions
|
@ -76,6 +76,9 @@ func (oq *destinationQueue) sendEvent(event *gomatrixserverlib.HeaderedEvent, re
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the destination is blacklisted. If it isn't then wake
|
||||||
|
// up the queue.
|
||||||
|
if !oq.statistics.Blacklisted() {
|
||||||
// If there's room in memory to hold the event then add it to the
|
// If there's room in memory to hold the event then add it to the
|
||||||
// list.
|
// list.
|
||||||
oq.pendingMutex.Lock()
|
oq.pendingMutex.Lock()
|
||||||
|
@ -93,6 +96,7 @@ func (oq *destinationQueue) sendEvent(event *gomatrixserverlib.HeaderedEvent, re
|
||||||
oq.wakeQueueAndNotify()
|
oq.wakeQueueAndNotify()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sendEDU adds the EDU event to the pending queue for the destination.
|
// sendEDU adds the EDU event to the pending queue for the destination.
|
||||||
// If the queue is empty then it starts a background goroutine to
|
// If the queue is empty then it starts a background goroutine to
|
||||||
|
@ -103,6 +107,9 @@ func (oq *destinationQueue) sendEDU(event *gomatrixserverlib.EDU, receipt *share
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the destination is blacklisted. If it isn't then wake
|
||||||
|
// up the queue.
|
||||||
|
if !oq.statistics.Blacklisted() {
|
||||||
// If there's room in memory to hold the event then add it to the
|
// If there's room in memory to hold the event then add it to the
|
||||||
// list.
|
// list.
|
||||||
oq.pendingMutex.Lock()
|
oq.pendingMutex.Lock()
|
||||||
|
@ -120,6 +127,7 @@ func (oq *destinationQueue) sendEDU(event *gomatrixserverlib.EDU, receipt *share
|
||||||
oq.wakeQueueAndNotify()
|
oq.wakeQueueAndNotify()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handleBackoffNotifier is registered as the backoff notification
|
// handleBackoffNotifier is registered as the backoff notification
|
||||||
// callback with Statistics. It will wakeup and notify the queue
|
// callback with Statistics. It will wakeup and notify the queue
|
||||||
|
|
|
@ -247,9 +247,10 @@ func (oqs *OutgoingQueues) SendEvent(
|
||||||
return fmt.Errorf("sendevent: oqs.db.StoreJSON: %w", err)
|
return fmt.Errorf("sendevent: oqs.db.StoreJSON: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destQueues := make([]*destinationQueue, 0, len(destmap))
|
||||||
for destination := range destmap {
|
for destination := range destmap {
|
||||||
if queue := oqs.getQueue(destination); queue != nil && !queue.statistics.Blacklisted() {
|
if queue := oqs.getQueue(destination); queue != nil {
|
||||||
queue.sendEvent(ev, nid)
|
destQueues = append(destQueues, queue)
|
||||||
} else {
|
} else {
|
||||||
delete(destmap, destination)
|
delete(destmap, destination)
|
||||||
}
|
}
|
||||||
|
@ -267,6 +268,14 @@ func (oqs *OutgoingQueues) SendEvent(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE : PDUs should be associated with destinations before sending
|
||||||
|
// them, otherwise this is technically a race.
|
||||||
|
// If the send completes before they are associated then they won't
|
||||||
|
// get properly cleaned up in the database.
|
||||||
|
for _, queue := range destQueues {
|
||||||
|
queue.sendEvent(ev, nid)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,20 +344,21 @@ func (oqs *OutgoingQueues) SendEDU(
|
||||||
return fmt.Errorf("sendevent: oqs.db.StoreJSON: %w", err)
|
return fmt.Errorf("sendevent: oqs.db.StoreJSON: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destQueues := make([]*destinationQueue, 0, len(destmap))
|
||||||
for destination := range destmap {
|
for destination := range destmap {
|
||||||
if queue := oqs.getQueue(destination); queue != nil && !queue.statistics.Blacklisted() {
|
if queue := oqs.getQueue(destination); queue != nil {
|
||||||
queue.sendEDU(e, nid)
|
destQueues = append(destQueues, queue)
|
||||||
} else {
|
} else {
|
||||||
delete(destmap, destination)
|
delete(destmap, destination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a database entry that associates the given PDU NID with
|
// Create a database entry that associates the given PDU NID with
|
||||||
// this destination queue. We'll then be able to retrieve the PDU
|
// these destination queues. We'll then be able to retrieve the PDU
|
||||||
// later.
|
// later.
|
||||||
if err := oqs.db.AssociateEDUWithDestinations(
|
if err := oqs.db.AssociateEDUWithDestinations(
|
||||||
oqs.process.Context(),
|
oqs.process.Context(),
|
||||||
destmap, // the destination server name
|
destmap, // the destination server names
|
||||||
nid, // NIDs from federationapi_queue_json table
|
nid, // NIDs from federationapi_queue_json table
|
||||||
e.Type,
|
e.Type,
|
||||||
nil, // this will use the default expireEDUTypes map
|
nil, // this will use the default expireEDUTypes map
|
||||||
|
@ -357,6 +367,14 @@ func (oqs *OutgoingQueues) SendEDU(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE : EDUs should be associated with destinations before sending
|
||||||
|
// them, otherwise this is technically a race.
|
||||||
|
// If the send completes before they are associated then they won't
|
||||||
|
// get properly cleaned up in the database.
|
||||||
|
for _, queue := range destQueues {
|
||||||
|
queue.sendEDU(e, nid)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue