aboutsummaryrefslogtreecommitdiff
path: root/core/timer.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/timer.go')
-rw-r--r--core/timer.go113
1 files changed, 113 insertions, 0 deletions
diff --git a/core/timer.go b/core/timer.go
new file mode 100644
index 0000000..3d17299
--- /dev/null
+++ b/core/timer.go
@@ -0,0 +1,113 @@
1package core
2
3import (
4 "container/heap"
5 "context"
6)
7
8// If using rockDB no need priority queue anymore
9// implement priority queue from golang
10// ref: https://pkg.go.dev/container/heap#example-package-PriorityQueue
11
12type timerServiceKey struct{}
13
14// InjectTimerService inject the timer into Context
15func InjectTimerService(ctx context.Context, ts TimerService) context.Context {
16 return context.WithValue(ctx, timerServiceKey{}, ts)
17}
18
19// ExtractTimerService get the timer for user from context
20func ExtractTimerService(ctx context.Context) (TimerService, bool) {
21 ts, ok := ctx.Value(timerServiceKey{}).(TimerService)
22 return ts, ok
23}
24
25type Timer struct {
26 // Timestamp is the time when Timer is triggered
27 Timestamp int64
28 // Key is for who User involve
29 Key string
30 // Window is for time range start-end of
31 // String actually cost more bytes than Window(16bytes)
32 // and we dont want to decode from namespace to Window
33 Namespace any
34}
35
36// Priority Queue (Min Heap). Smallest timestamp will be on top
37
38type timerHeap []Timer
39
40func (h *timerHeap) Len() int { return len(*h) }
41func (h *timerHeap) Less(i, j int) bool { return (*h)[i].Timestamp < (*h)[j].Timestamp }
42func (h *timerHeap) Swap(i, j int) {
43 (*h)[i], (*h)[j] = (*h)[j], (*h)[i]
44}
45
46func (h *timerHeap) Push(x any) {
47 *h = append(*h, x.(Timer))
48}
49
50func (h *timerHeap) Pop() any {
51 old := *h
52 n := len(old)
53 last := old[n-1]
54 *h = old[:n-1]
55 return last
56}
57
58type TimerService interface {
59 Register(time int64, key string, keyspace any)
60 CurrentWatermark() int64
61}
62
63type InternalTimerService interface {
64 TimerService
65 AdvanceWatermark(watermark int64) []Timer
66}
67
68type timerService struct {
69 queue timerHeap
70 currentWatermark int64
71}
72
73func NewTimerService() InternalTimerService {
74 return &timerService{
75 queue: make(timerHeap, 0),
76 currentWatermark: -1,
77 }
78}
79
80func (t *timerService) Register(time int64, key string, namespace any) {
81 heap.Push(&t.queue, Timer{
82 Timestamp: time,
83 Key: key,
84 Namespace: namespace,
85 })
86}
87
88func (t *timerService) CurrentWatermark() int64 {
89 return t.currentWatermark
90}
91
92func (t *timerService) AdvanceWatermark(watermark int64) []Timer {
93 if watermark < t.currentWatermark {
94 // no need to advance when get smaller
95 return nil
96 }
97
98 t.currentWatermark = watermark
99
100 var timers []Timer
101 for t.queue.Len() > 0 {
102 earliestTimer := t.queue[0]
103
104 if earliestTimer.Timestamp > watermark {
105 break
106 }
107
108 pop := heap.Pop(&t.queue).(Timer)
109 timers = append(timers, pop)
110 }
111
112 return timers
113}