Keep taking messages while a peer's session goes down (closes #216)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
The table's PeerDown visits every prefix under the write lock, which takes over a second on a full table. The prefix handler called it inline, so its queue filled and the streamer dropped updates. PeerDown now lets the lock go after every 10,000 prefixes. The handler runs it on a goroutine of its own, one peer at a time, and holds back the down peer's later messages until it returns, then applies them in order. Stop waits for this before its last flush, and logs the held-back messages it could not apply. Model: opus-5-5
This commit is contained in:
@@ -27,6 +27,11 @@ const (
|
||||
// kept routes in order: each of its nodes holds up to 63 times.
|
||||
keptTimesDegree = 32
|
||||
|
||||
// walkBatch is how many prefixes a walk over the whole table visits in
|
||||
// one hold of the lock: Overview's walk and PeerDown's. The others
|
||||
// waiting for the lock get it in between.
|
||||
walkBatch = 10000
|
||||
|
||||
ipv4Bits = 32
|
||||
ipv6Bits = 128
|
||||
|
||||
@@ -202,7 +207,10 @@ func (t *Table) Withdraw(prefix netip.Prefix, peer string) {
|
||||
|
||||
// PeerDown applies a peer's session going down: the peer leaves every peer
|
||||
// set, and every route of it is dropped. When the peer carries any prefix, it
|
||||
// visits every prefix in the table.
|
||||
// visits every prefix in the table. It lets the lock go after every walkBatch
|
||||
// prefixes, so the reads and updates waiting for it get in. An announcement of
|
||||
// the peer made meanwhile may be dropped too, so the caller applies the peer's
|
||||
// later updates only once PeerDown has returned.
|
||||
func (t *Table) PeerDown(peer string) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
@@ -212,6 +220,8 @@ func (t *Table) PeerDown(peer string) {
|
||||
return
|
||||
}
|
||||
|
||||
visited := 0
|
||||
|
||||
for _, f := range []*family{&t.ipv4, &t.ipv6} {
|
||||
for _, prefixes := range f.byLength {
|
||||
for prefix, origins := range prefixes {
|
||||
@@ -219,6 +229,14 @@ func (t *Table) PeerDown(peer string) {
|
||||
if o != nil {
|
||||
t.leave(prefix, o, number)
|
||||
}
|
||||
|
||||
// Go allows the map to change before the next step of
|
||||
// the range over it.
|
||||
visited++
|
||||
if visited%walkBatch == 0 {
|
||||
t.mu.Unlock()
|
||||
t.mu.Lock()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user