The prefix, AS and peer handlers skipped a timed write unless one interval had passed since the last write ended. The next tick came a little less than one interval after that, so every other tick was skipped. Each tick now writes. A full batch's write restarts the timer, so the next timed write comes one interval after that write began. Comparing clock readings would not do: two ticks one interval apart can read a hair under it. flushBatch no longer reports whether it wrote a batch, since nothing reads that. A new test runs the loop on a fake clock and fails on the old code. Model: opus-5-5
This commit was merged in pull request #193.
This commit is contained in:
1 parent
05b39eee7a
commit
2c304a0022
6 files changed
+78
-30
No files matched your search
@@ -9,6 +9,7 @@ import (
|
||||
"slices"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/routewatch/internal/database"
|
||||
@@ -27,6 +28,58 @@ const (
|
||||
stillWaitingAfter = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
// TestFlushLoopWritesOnEveryTick runs flushLoop in a synctest bubble, whose
|
||||
// clock is fake: time.Sleep there moves the clock on and returns at once. Each
|
||||
// write takes a tenth of the interval. Two timed writes must start one interval
|
||||
// apart. A full batch's write, which starts as the second timed write ends,
|
||||
// must be followed by a timed write one interval after it began.
|
||||
func TestFlushLoopWritesOnEveryTick(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
const (
|
||||
interval = time.Second
|
||||
writeTime = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
writeStarts := make(chan time.Time)
|
||||
batchFullCh := make(chan struct{}, 1)
|
||||
stopCh := make(chan context.Context, 1)
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
flushLoop(interval, batchFullCh, stopCh, done, func() {
|
||||
writeStarts <- time.Now()
|
||||
|
||||
time.Sleep(writeTime)
|
||||
})
|
||||
}()
|
||||
|
||||
first := <-writeStarts
|
||||
second := <-writeStarts
|
||||
|
||||
if gap := second.Sub(first); gap != interval {
|
||||
t.Errorf("the second timed write started %s after the first, "+
|
||||
"want %s", gap, interval)
|
||||
}
|
||||
|
||||
batchFullCh <- struct{}{}
|
||||
|
||||
full := <-writeStarts
|
||||
timed := <-writeStarts
|
||||
|
||||
if gap := timed.Sub(full); gap != interval {
|
||||
t.Errorf("the timed write after a full batch's started %s after "+
|
||||
"it, want %s", gap, interval)
|
||||
}
|
||||
|
||||
stopCh <- t.Context()
|
||||
|
||||
<-writeStarts // Stop's last write
|
||||
<-done
|
||||
})
|
||||
}
|
||||
|
||||
// blockingStore is a mockStore whose batch writes for the AS, peer and prefix
|
||||
// handlers, delete of a peer's routes and peering write wait until the test
|
||||
// calls releaseWrites. writeStarted is closed when the first of them starts. It
|
||||
|
||||
Reference in new issue
Block a user