/
idlequeue.go
86 lines (74 loc) · 1.68 KB
/
idlequeue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package mokumokuren
import (
"sync"
"time"
)
type idleQueueNode struct {
newer, older *idleQueueNode
time time.Time
key FlowKey
}
// An idle queue associates flow keys with the time of the
// last packet seen, and allows quick access to the least recently active flow.
type IdleQueue struct {
newest, oldest *idleQueueNode
node map[FlowKey]*idleQueueNode
lock sync.RWMutex
}
// Create a new idle queue.
func NewIdleQueue() *IdleQueue {
q := new(IdleQueue)
q.node = make(map[FlowKey]*idleQueueNode)
return q
}
func (q *IdleQueue) Tick(k FlowKey, t time.Time) {
if n, ok := q.node[k]; ok {
// remove node from present location in queue
n.newer.older = n.older
n.older.newer = n.newer
// update its time, maintaining monotonic invariant
if t.After(q.newest.time) {
n.time = t
} else {
n.time = q.newest.time
}
// and stitch it to the front
n.older = q.newest
if n.older != nil {
n.older.newer = n
}
n.newer = nil
q.newest = n
} else {
// new node. create and stitch to the front
n = new(idleQueueNode)
n.time = t
n.key = k
n.older = q.newest
if n.older != nil {
n.older.newer = n
}
q.newest = n
}
}
// Remove and return the next
func (q *IdleQueue) NextIdleBefore(t time.Time) (k FlowKey, ok bool) {
if q.oldest != nil && q.oldest.time.Before(t) {
n := q.oldest
q.oldest = q.oldest.newer
if q.oldest != nil {
q.oldest.older = nil
}
return n.key, true
} else {
return FlowKey{}, false
}
}
// Get the time associated with the least recently active flow.
func (q *IdleQueue) OldestFlowTime() time.Time {
if q.oldest != nil {
return q.oldest.time
} else {
return time.Unix(0, 0)
}
}