Take every down peer out of the table in one walk (closes #225)
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:
2026-11-02 06:38:11 +00:00
committed by sneak
parent d66c59ef07
commit 9d37f98239
15 changed files with 436 additions and 123 deletions
+37
View File
@@ -295,6 +295,43 @@ func TestStatsAnswerCarriesChurnPerMinute(t *testing.T) {
}
}
// heldBackMessages is how many messages heldBackHandler holds back.
const heldBackMessages = 7
// heldBackHandler is a stream handler that wants no message and holds back
// heldBackMessages messages.
type heldBackHandler struct{}
func (heldBackHandler) WantsMessage(string) bool { return false }
func (heldBackHandler) HandleMessage(*ristypes.RISMessage) {}
func (heldBackHandler) QueueCapacity() int { return 1 }
func (heldBackHandler) HeldBackCount() int { return heldBackMessages }
// TestStatsAnswerGivesHowManyMessagesAHandlerHoldsBack registers a handler
// that holds back messages. Its figures in /api/v1/stats, which the status
// page shows, must give how many.
func TestStatsAnswerGivesHowManyMessagesAHandlerHoldsBack(t *testing.T) {
t.Parallel()
s := newServerWithTestRoutes(t)
s.streamer.RegisterHandler(heldBackHandler{})
var body struct {
Data StatsResponse `json:"data"`
}
err := json.Unmarshal(get(t, s, statsPath).Body.Bytes(), &body)
if err != nil {
t.Fatalf("decoding the answer: %v", err)
}
stats := body.Data.HandlerStats
if len(stats) != 1 || stats[0].HeldBackCount != heldBackMessages {
t.Errorf("handler figures %+v, want one handler holding back %d "+
"messages", stats, heldBackMessages)
}
}
// fixedIntervalASNFetcher is a WHOIS fetcher that does nothing and reports
// interval as its wait between fetches.
type fixedIntervalASNFetcher struct {