Take every down peer out of the table in one walk (closes #225)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
The prefix handler ran one PeerDown per peer, one after another, and stopped taking messages at 20,000 held-back messages. Sessions going down together queued up their walks, so a returning full-table peer could reach that limit. The table's PeersDown now takes several peers out of every prefix in one walk. One walk runs at a time. The next one takes every peer whose session went down meanwhile, so a message is held back for two walks at most. Each walk takes about 2.6 seconds for each full-table peer it takes out. The limit is now 150,000 messages, about 150 MiB: enough when four full-table peers go down together. The status page shows how many messages each handler holds back. Model: opus-5-5
This commit is contained in:
@@ -69,10 +69,10 @@ func withdraw(peer string) step {
|
||||
}
|
||||
}
|
||||
|
||||
// peerDown is the step of peer's session going down.
|
||||
func peerDown(peer string) step {
|
||||
// peersDown is the step of the sessions of peers going down.
|
||||
func peersDown(peers ...string) step {
|
||||
return func(table *routetable.Table, _ netip.Prefix) {
|
||||
table.PeerDown(peer)
|
||||
table.PeersDown(peers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,21 +272,28 @@ func TestWithdrawalsAndPeerDowns(t *testing.T) {
|
||||
{
|
||||
name: "a peer going down leaves the prefix",
|
||||
steps: []step{announce(peerA, asA, 10), announce(peerB, asA, 20),
|
||||
peerDown(peerB)},
|
||||
peersDown(peerB)},
|
||||
want: []routetable.Origin{{ASN: asA, Peers: []string{peerA},
|
||||
Routes: []routetable.Route{routeOf(peerA, asA, 10)}}},
|
||||
},
|
||||
{
|
||||
name: "a peer going down after it withdrew changes nothing",
|
||||
steps: []step{announce(peerA, asA, 10), announce(peerB, asA, 20),
|
||||
withdraw(peerB), peerDown(peerB)},
|
||||
withdraw(peerB), peersDown(peerB)},
|
||||
want: []routetable.Origin{{ASN: asA, Peers: []string{peerA},
|
||||
Routes: []routetable.Route{routeOf(peerA, asA, 10)}}},
|
||||
},
|
||||
{
|
||||
name: "peers going down together each leave the prefix",
|
||||
steps: []step{announce(peerA, asA, 10), announce(peerB, asB, 20),
|
||||
announce(peerC, asB, 30), peersDown(peerA, peerB)},
|
||||
want: []routetable.Origin{{ASN: asB, Peers: []string{peerC},
|
||||
Routes: []routetable.Route{routeOf(peerC, asB, 30)}}},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeerDownLeavesEveryPrefix(t *testing.T) {
|
||||
func TestPeersDownLeavesEveryPrefix(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
table := routetable.New(routetable.Params{})
|
||||
@@ -303,7 +310,7 @@ func TestPeerDownLeavesEveryPrefix(t *testing.T) {
|
||||
}
|
||||
|
||||
table.Announce(prefixes[0], asB, routeOf(peerB, asB, 20))
|
||||
table.PeerDown(peerA)
|
||||
table.PeersDown([]string{peerA})
|
||||
|
||||
want := []routetable.Origin{{ASN: asB, Peers: []string{peerB},
|
||||
Routes: []routetable.Route{routeOf(peerB, asB, 20)}}}
|
||||
@@ -333,6 +340,32 @@ func TestPeerDownLeavesEveryPrefix(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPeersDownTakesOutPeersOfDifferentPrefixes takes peerA and peerB out in
|
||||
// one PeersDown. peerA carries only prefixV4, and peerB only prefixV6. So
|
||||
// peerA's leaving removes prefixV4 before PeersDown looks for peerB there. Both
|
||||
// prefixes must then be gone.
|
||||
func TestPeersDownTakesOutPeersOfDifferentPrefixes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
table := routetable.New(routetable.Params{})
|
||||
prefixes := []netip.Prefix{
|
||||
netip.MustParsePrefix(prefixV4),
|
||||
netip.MustParsePrefix(prefixV6),
|
||||
}
|
||||
|
||||
table.Announce(prefixes[0], asA, routeOf(peerA, asA, 10))
|
||||
table.Announce(prefixes[1], asB, routeOf(peerB, asB, 20))
|
||||
table.PeersDown([]string{peerA, peerB})
|
||||
|
||||
for _, prefix := range prefixes {
|
||||
got := table.Origins(prefix)
|
||||
if got != nil {
|
||||
t.Errorf("Origins(%s) = %+v after its only peer went down, want nil",
|
||||
prefix, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCountsOriginsWithoutKeptRoute(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -358,7 +391,7 @@ func TestCountsOriginsWithoutKeptRoute(t *testing.T) {
|
||||
{announce(peerC, asA, 30), 0},
|
||||
{withdraw(peerB), 0},
|
||||
{withdraw(peerC), 1},
|
||||
{peerDown(peerA), 0},
|
||||
{peersDown(peerA), 0},
|
||||
}
|
||||
|
||||
for i, s := range steps {
|
||||
@@ -464,7 +497,7 @@ func TestTakeChangesHoldsOnlyPairsThatChanged(t *testing.T) {
|
||||
checkChanges(t, table, []change{}, map[string]uint{})
|
||||
|
||||
// peerA going down changes v4, the one prefix it carries.
|
||||
table.PeerDown(peerA)
|
||||
table.PeersDown([]string{peerA})
|
||||
checkChanges(t, table, []change{
|
||||
{Prefix: prefixV4, OriginASN: asA, Peers: []uint{1, 2},
|
||||
Routes: []routetable.Route{
|
||||
@@ -473,7 +506,7 @@ func TestTakeChangesHoldsOnlyPairsThatChanged(t *testing.T) {
|
||||
}, map[string]uint{})
|
||||
|
||||
// peerA, which carries nothing now, goes down again.
|
||||
table.PeerDown(peerA)
|
||||
table.PeersDown([]string{peerA})
|
||||
checkChanges(t, table, []change{}, map[string]uint{})
|
||||
}
|
||||
|
||||
@@ -617,7 +650,7 @@ func TestConcurrentUse(t *testing.T) {
|
||||
func(round int) { table.Announce(prefix, asA, routeOf(peerA, asA, round)) },
|
||||
func(round int) { table.Announce(prefix, asB, routeOf(peerB, asB, round)) },
|
||||
func(int) { table.Withdraw(prefix, peerA) },
|
||||
func(int) { table.PeerDown(peerB) },
|
||||
func(int) { table.PeersDown([]string{peerB}) },
|
||||
func(int) { table.PutBackChanges(table.TakeChanges(math.MaxInt)) },
|
||||
func(int) { table.ChangeCount() },
|
||||
func(int) { table.Lookup(prefix.Addr()) },
|
||||
|
||||
Reference in New Issue
Block a user