github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/timeutil/manual_time.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package timeutil 12 13 import ( 14 "container/heap" 15 "container/list" 16 "fmt" 17 "sort" 18 "time" 19 20 "github.com/cockroachdb/cockroachdb-parser/pkg/util/syncutil" 21 ) 22 23 // ManualTime is a testing implementation of TimeSource. 24 type ManualTime struct { 25 mu struct { 26 syncutil.Mutex 27 now time.Time 28 timers manualTimerQueue 29 // tickers is a list with element type *manualTicker. 30 tickers list.List 31 } 32 } 33 34 // NewManualTime constructs a new ManualTime. 35 func NewManualTime(initialTime time.Time) *ManualTime { 36 mt := ManualTime{} 37 mt.mu.now = initialTime 38 mt.mu.timers = manualTimerQueue{ 39 m: make(map[*manualTimer]int), 40 } 41 mt.mu.tickers.Init() 42 return &mt 43 } 44 45 var _ TimeSource = (*ManualTime)(nil) 46 47 // Now returns the current time. 48 func (m *ManualTime) Now() time.Time { 49 m.mu.Lock() 50 defer m.mu.Unlock() 51 return m.mu.now 52 } 53 54 // Since implements TimeSource interface 55 func (m *ManualTime) Since(t time.Time) time.Duration { 56 return m.Now().Sub(t) 57 } 58 59 // NewTimer constructs a new timer. 60 func (m *ManualTime) NewTimer() TimerI { 61 return &manualTimer{m: m} 62 } 63 64 // NewTicker creates a new ticker. 65 func (m *ManualTime) NewTicker(duration time.Duration) TickerI { 66 if duration <= 0 { 67 panic("non-positive interval for NewTicker") 68 } 69 m.mu.Lock() 70 defer m.mu.Unlock() 71 72 t := &manualTicker{ 73 m: m, 74 duration: duration, 75 nextTick: m.mu.now.Add(duration), 76 // We allocate a big buffer so that sending a tick never blocks. 77 ch: make(chan time.Time, 10000), 78 } 79 t.element = m.mu.tickers.PushBack(t) 80 return t 81 } 82 83 // Advance forwards the current time by the given duration. 84 func (m *ManualTime) Advance(duration time.Duration) { 85 m.AdvanceTo(m.Now().Add(duration)) 86 } 87 88 // Backwards moves the clock back by duration. Duration is expected to be 89 // positive, and it will be subtracted from the current time. 90 func (m *ManualTime) Backwards(duration time.Duration) { 91 if duration < 0 { 92 panic("invalid negative duration") 93 } 94 m.mu.Lock() 95 defer m.mu.Unlock() 96 // No timers fire when the clock goes backwards. 97 m.mu.now = m.mu.now.Add(-duration) 98 } 99 100 // AdvanceTo advances the current time to t. If t is earlier than the current 101 // time then AdvanceTo is a no-op. 102 func (m *ManualTime) AdvanceTo(now time.Time) { 103 m.mu.Lock() 104 defer m.mu.Unlock() 105 m.advanceToLocked(now) 106 } 107 108 // MustAdvanceTo is like AdvanceTo, except it panics if now is below m's current time. 109 func (m *ManualTime) MustAdvanceTo(now time.Time) { 110 m.mu.Lock() 111 defer m.mu.Unlock() 112 if now.Before(m.mu.now) { 113 panic(fmt.Sprintf("attempting to move ManualTime backwards from %s to %s", m.mu.now, now)) 114 } 115 m.advanceToLocked(now) 116 } 117 118 func (m *ManualTime) advanceToLocked(now time.Time) { 119 if !now.After(m.mu.now) { 120 return 121 } 122 m.mu.now = now 123 124 // Fire off any timers. 125 for m.mu.timers.Len() > 0 { 126 next := m.mu.timers.heap[0] 127 if next.at.After(now) { 128 break 129 } 130 next.ch <- next.at 131 heap.Pop(&m.mu.timers) 132 } 133 134 // Fire off any tickers. 135 for e := m.mu.tickers.Front(); e != nil; e = e.Next() { 136 t := e.Value.(*manualTicker) 137 for !t.nextTick.After(now) { 138 select { 139 case t.ch <- t.nextTick: 140 default: 141 panic("ticker channel full") 142 } 143 t.nextTick = t.nextTick.Add(t.duration) 144 } 145 } 146 } 147 148 func (m *ManualTime) add(mt *manualTimer) { 149 m.mu.Lock() 150 defer m.mu.Unlock() 151 152 if !mt.at.After(m.mu.now) { 153 mt.ch <- mt.at 154 } else { 155 heap.Push(&m.mu.timers, mt) 156 } 157 } 158 159 func (m *ManualTime) removeTimer(mt *manualTimer) bool { 160 m.mu.Lock() 161 defer m.mu.Unlock() 162 if idx, ok := m.mu.timers.m[mt]; ok { 163 heap.Remove(&m.mu.timers, idx) 164 return true 165 } 166 return false 167 } 168 169 func (m *ManualTime) removeTicker(t *manualTicker) { 170 m.mu.Lock() 171 defer m.mu.Unlock() 172 if t.element != nil { 173 m.mu.tickers.Remove(t.element) 174 t.element = nil 175 } 176 } 177 178 // Timers returns a snapshot of the timestamps of the pending timers. 179 func (m *ManualTime) Timers() []time.Time { 180 m.mu.Lock() 181 defer m.mu.Unlock() 182 timers := make([]time.Time, m.mu.timers.Len()) 183 for i, t := range m.mu.timers.heap { 184 timers[i] = t.at 185 } 186 sort.Slice(timers, func(i, j int) bool { 187 return timers[i].Before(timers[j]) 188 }) 189 return timers 190 } 191 192 type manualTimerQueue struct { 193 // m maintains the index for a timer in heap. 194 m map[*manualTimer]int 195 heap []*manualTimer 196 } 197 198 var _ heap.Interface = (*manualTimerQueue)(nil) 199 200 func (m *manualTimerQueue) Len() int { 201 return len(m.heap) 202 } 203 204 func (m *manualTimerQueue) Less(i, j int) bool { 205 return m.heap[i].at.Before(m.heap[j].at) 206 } 207 208 func (m *manualTimerQueue) Swap(i, j int) { 209 m.heap[i], m.heap[j] = m.heap[j], m.heap[i] 210 m.m[m.heap[i]] = i 211 m.m[m.heap[j]] = j 212 } 213 214 func (m *manualTimerQueue) Push(x interface{}) { 215 mt := x.(*manualTimer) 216 m.m[mt] = len(m.heap) 217 m.heap = append(m.heap, mt) 218 } 219 220 func (m *manualTimerQueue) Pop() interface{} { 221 lastIdx := len(m.heap) - 1 222 ret := m.heap[lastIdx] 223 delete(m.m, ret) 224 m.heap = m.heap[:lastIdx] 225 return ret 226 } 227 228 type manualTimer struct { 229 m *ManualTime 230 at time.Time 231 ch chan time.Time 232 } 233 234 var _ TimerI = (*manualTimer)(nil) 235 236 func (m *manualTimer) Reset(duration time.Duration) { 237 m.Stop() 238 m.at = m.m.Now().Add(duration) 239 m.ch = make(chan time.Time, 1) 240 m.m.add(m) 241 } 242 243 func (m *manualTimer) Stop() bool { 244 removed := m.m.removeTimer(m) 245 m.ch = nil 246 m.at = time.Time{} 247 return removed 248 } 249 250 func (m *manualTimer) Ch() <-chan time.Time { 251 return m.ch 252 } 253 254 func (m *manualTimer) MarkRead() {} 255 256 type manualTicker struct { 257 m *ManualTime 258 element *list.Element 259 260 duration time.Duration 261 nextTick time.Time 262 ch chan time.Time 263 } 264 265 // Reset is part of the TickerI interface. 266 func (t *manualTicker) Reset(duration time.Duration) { 267 panic("not implemented") 268 } 269 270 // Stop is part of the TickerI interface. 271 func (t *manualTicker) Stop() { 272 t.m.removeTicker(t) 273 } 274 275 // Ch is part of the TickerI interface. 276 func (t *manualTicker) Ch() <-chan time.Time { 277 return t.ch 278 }