Start no prefix flush after the stop deadline (closes #188)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
When a write ran past the stop deadline, a full batch's wake-up or a tick could wait beside Stop's context. The flush goroutine's select picked one of them at random, so about half the time it wrote that batch after the deadline. That was the intermittent failure of TestPrefixHandlerSkipsItsLastWriteAfterTheStopDeadline. The flush goroutine now takes a waiting stop first. A new test hands over a full batch while a write is held; it fails about half its runs on the old code. TestPrefixHandlerSkipsItsLastWriteAfterTheStopDeadline and TestPrefixHandlerStopLogsTheTableChangesLeftUnwritten also failed when the flush timer fired between two of their steps. Both now give the handler a timer interval longer than the test. Model: opus-5-5
This commit was merged in pull request #190.
This commit is contained in:
1 parent
bac531c76d
commit
ce19b14275
5 files changed
+74
-15
No files matched your search
@@ -317,7 +317,9 @@ func stopWhileAWriteIsBlocked(
|
||||
|
||||
// TestPrefixHandlerSkipsItsLastWriteAfterTheStopDeadline also checks the
|
||||
// routing table's changes: the flush whose delete is held wrote those of the
|
||||
// fill, so Stop must log the one of the extra prefix as not written.
|
||||
// fill, so Stop must log the one of the extra prefix as not written. The flush
|
||||
// timer must not fire. A flush it started before the fill would be the one
|
||||
// held, and it would not have written the fill's change.
|
||||
func TestPrefixHandlerSkipsItsLastWriteAfterTheStopDeadline(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -326,8 +328,8 @@ func TestPrefixHandlerSkipsItsLastWriteAfterTheStopDeadline(t *testing.T) {
|
||||
var logs bytes.Buffer
|
||||
|
||||
store := newBlockingStore()
|
||||
h := NewPrefixHandler(store, newErrorLogger(&logs),
|
||||
routetable.New(routetable.Params{}))
|
||||
h := newPrefixHandler(store, newErrorLogger(&logs),
|
||||
routetable.New(routetable.Params{}), longerThanAnyTest)
|
||||
fill := slices.Repeat([]string{testV4Prefix}, prefixBatchSize)
|
||||
// The peer's session goes down first, so the write held is the delete of
|
||||
// its routes, and Stop must log that peer down too.
|
||||
@@ -351,6 +353,31 @@ func TestPrefixHandlerSkipsItsLastWriteAfterTheStopDeadline(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPrefixHandlerSkipsAFullBatchAfterTheStopDeadline hands the prefix handler
|
||||
// a full batch while a write is held, so the batch's wake-up of the flush
|
||||
// goroutine waits. The stop deadline passes meanwhile. When the write ends, the
|
||||
// flush goroutine must stop instead of writing the batch.
|
||||
func TestPrefixHandlerSkipsAFullBatchAfterTheStopDeadline(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const extraPrefix = "198.51.100.0/24"
|
||||
|
||||
store := newBlockingStore()
|
||||
h := NewPrefixHandler(store, logger.New(), routetable.New(routetable.Params{}))
|
||||
fill := slices.Repeat([]string{testV4Prefix}, prefixBatchSize)
|
||||
full := slices.Repeat([]string{extraPrefix}, prefixBatchSize)
|
||||
stopWhileAWriteIsBlocked(t, store, h, h.done,
|
||||
[]*ristypes.RISMessage{prefixAnnouncement(fill)},
|
||||
prefixAnnouncement(full))
|
||||
|
||||
store.mu.Lock()
|
||||
defer store.mu.Unlock()
|
||||
|
||||
if store.prefixes[extraPrefix] {
|
||||
t.Errorf("%s was written after the stop deadline", extraPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
// tableWriteBlockingStore is a blockingStore whose writes of the routing
|
||||
// table's changes also wait until the test calls releaseWrites.
|
||||
type tableWriteBlockingStore struct {
|
||||
|
||||
Reference in new issue
Block a user