Skip to content

Commit 2203987

Browse files
authored
Merge pull request #4 from vimeo/fakeclock_abort_sleep_counters
fake clock: Add tracking for sleep/abort-counters
2 parents 9d82324 + e367bbc commit 2203987

File tree

1 file changed

+55
-5
lines changed

1 file changed

+55
-5
lines changed

clocks/fake_clock.go

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ type FakeClock struct {
2222

2323
// counter tracking the number of wakeups (protected by mu)
2424
wakeups int
25+
26+
// counter tracking the number of cancelled sleeps (protected by mu)
27+
sleepAborts int
28+
29+
// counter tracking the number of sleepers who have ever gone to sleep
30+
// (protected by mu)
31+
sleepersAggregate int
2532
}
2633

2734
// NewFakeClock returns an initialized FakeClock instance.
@@ -75,6 +82,22 @@ func (f *FakeClock) NumSleepers() int {
7582
return len(f.sleepers)
7683
}
7784

85+
// NumAggSleepers returns the number of goroutines who have ever slept under
86+
// SleepFor and SleepUntil calls.
87+
func (f *FakeClock) NumAggSleepers() int {
88+
f.mu.Lock()
89+
defer f.mu.Unlock()
90+
return f.sleepersAggregate
91+
}
92+
93+
// NumSleepAborts returns the number of calls to SleepFor and SleepUntil which
94+
// have ended prematurely due to canceled contexts.
95+
func (f *FakeClock) NumSleepAborts() int {
96+
f.mu.Lock()
97+
defer f.mu.Unlock()
98+
return f.sleepAborts
99+
}
100+
78101
// Sleepers returns the number of goroutines waiting in SleepFor and SleepUntil
79102
// calls.
80103
func (f *FakeClock) Sleepers() []time.Time {
@@ -96,6 +119,26 @@ func (f *FakeClock) AwaitSleepers(n int) {
96119
}
97120
}
98121

122+
// AwaitAggSleepers waits until the aggregate number of sleepers exceeds its
123+
// argument
124+
func (f *FakeClock) AwaitAggSleepers(n int) {
125+
f.mu.Lock()
126+
defer f.mu.Unlock()
127+
for f.sleepersAggregate < n {
128+
f.cond.Wait()
129+
}
130+
}
131+
132+
// AwaitSleepAborts waits until the number of aborted sleepers exceeds its
133+
// argument
134+
func (f *FakeClock) AwaitSleepAborts(n int) {
135+
f.mu.Lock()
136+
defer f.mu.Unlock()
137+
for f.sleepAborts < n {
138+
f.cond.Wait()
139+
}
140+
}
141+
99142
// Wakeups returns the number of sleepers that have been awoken (useful for
100143
// verifying that nothing was woken up when advancing time)
101144
func (f *FakeClock) Wakeups() int {
@@ -127,24 +170,30 @@ func (f *FakeClock) setAbsoluteWaiter(until time.Time) chan struct{} {
127170
return ch
128171
}
129172
f.sleepers[ch] = until
173+
f.sleepersAggregate++
130174

131175
f.cond.Broadcast()
132176
return ch
133177
}
134178

135-
func (f *FakeClock) removeWaiter(ch chan struct{}) {
179+
func (f *FakeClock) removeWaiter(ch chan struct{}, abort bool) {
136180
f.mu.Lock()
137181
defer f.mu.Unlock()
182+
// If the channel is present, and this was an abort, increment the
183+
// aborts counter.
184+
if _, ok := f.sleepers[ch]; ok && abort {
185+
f.sleepAborts++
186+
}
138187
delete(f.sleepers, ch)
139188
f.cond.Broadcast()
140189
}
141190

142191
// SleepUntil blocks until either ctx expires or until arrives.
143192
// Return value is false if context-cancellation/expiry prompted an
144193
// early return
145-
func (f *FakeClock) SleepUntil(ctx context.Context, until time.Time) bool {
194+
func (f *FakeClock) SleepUntil(ctx context.Context, until time.Time) (success bool) {
146195
ch := f.setAbsoluteWaiter(until)
147-
defer f.removeWaiter(ch)
196+
defer func() { f.removeWaiter(ch, !success) }()
148197
select {
149198
case <-ch:
150199
return true
@@ -158,17 +207,18 @@ func (f *FakeClock) setRelativeWaiter(dur time.Duration) chan struct{} {
158207
f.mu.Lock()
159208
defer f.mu.Unlock()
160209
f.sleepers[ch] = f.current.Add(dur)
210+
f.sleepersAggregate++
161211
f.cond.Broadcast()
162212
return ch
163213
}
164214

165215
// SleepFor is the relative-time equivalent of SleepUntil.
166-
func (f *FakeClock) SleepFor(ctx context.Context, dur time.Duration) bool {
216+
func (f *FakeClock) SleepFor(ctx context.Context, dur time.Duration) (success bool) {
167217
if dur <= 0 {
168218
return true
169219
}
170220
ch := f.setRelativeWaiter(dur)
171-
defer f.removeWaiter(ch)
221+
defer func() { f.removeWaiter(ch, !success) }()
172222
select {
173223
case <-ch:
174224
return true

0 commit comments

Comments
 (0)