forked from obsidiandynamics/goharvest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
battery.go
88 lines (73 loc) · 1.42 KB
/
battery.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
87
88
package goharvest
import (
"hash/fnv"
)
type cell struct {
records chan OutboxRecord
done chan int
}
func (c cell) stop() {
close(c.records)
}
func (c cell) await() {
<-c.done
}
func (c cell) enqueue(rec OutboxRecord) bool {
select {
case <-c.done:
return false
case c.records <- rec:
return true
}
}
type cellHandler func(records chan OutboxRecord)
func newCell(buffer int, handler cellHandler) cell {
c := cell{
records: make(chan OutboxRecord),
done: make(chan int),
}
go func() {
defer close(c.done)
handler(c.records)
}()
return c
}
type battery interface {
stop()
await()
shutdown()
enqueue(rec OutboxRecord) bool
}
type concurrentBattery []cell
func (b *concurrentBattery) stop() {
for _, c := range *b {
c.stop()
}
}
func (b *concurrentBattery) await() {
for _, c := range *b {
c.await()
}
}
func (b *concurrentBattery) shutdown() {
b.stop()
b.await()
}
func (b *concurrentBattery) enqueue(rec OutboxRecord) bool {
if length := len(*b); length > 1 {
return (*b)[hash(rec.KafkaKey)%uint32(length)].enqueue(rec)
}
return (*b)[0].enqueue(rec)
}
func newConcurrentBattery(concurrency int, buffer int, handler cellHandler) *concurrentBattery {
b := make(concurrentBattery, concurrency)
for i := 0; i < concurrency; i++ {
b[i] = newCell(buffer, handler)
}
return &b
}
func hash(str string) uint32 {
algorithm := fnv.New32a()
algorithm.Write([]byte(str))
return algorithm.Sum32()
}