Skip to content

Commit 5aed92d

Browse files
committed
added batch library
1 parent 6bf600b commit 5aed92d

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

common/batch/batch.go

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// batch.go
2+
3+
package batch
4+
5+
import (
6+
"sync/atomic"
7+
"time"
8+
9+
"github.com/ethereum/go-ethereum/log"
10+
)
11+
12+
type Batch struct {
13+
toInterval time.Duration
14+
timeout time.Duration
15+
batchCount int
16+
ch chan interface{}
17+
count int32
18+
f func(interface{}, int) error
19+
}
20+
21+
func NewBatch(toInterval, timeout time.Duration, batchCount int, f func(interface{}, int) error) *Batch {
22+
return &Batch{
23+
toInterval: toInterval,
24+
timeout: timeout,
25+
batchCount: batchCount,
26+
ch: make(chan interface{}, batchCount*10),
27+
count: 0,
28+
f: f,
29+
}
30+
}
31+
32+
func (b *Batch) Run() {
33+
var (
34+
data []interface{}
35+
lt time.Time = time.Now() // last time
36+
ln int = 0 // last count
37+
)
38+
39+
timer := time.NewTimer(0)
40+
<-timer.C // drain the initial timeout
41+
42+
eod := false
43+
for {
44+
itstimer := false
45+
fire := false
46+
47+
select {
48+
case d := <-b.ch:
49+
atomic.AddInt32(&b.count, -1)
50+
if d == nil {
51+
eod = true
52+
} else {
53+
data = append(data, d)
54+
}
55+
case <-timer.C:
56+
itstimer = true
57+
}
58+
last := b.count == 0
59+
60+
if eod {
61+
break
62+
}
63+
64+
// when to fire
65+
// 1. timer fired
66+
// 1.1 no count change
67+
// 1.2 more than 50 ms passed from the initial
68+
// 2. count >= 100
69+
70+
if !itstimer {
71+
if ln == 0 {
72+
lt = time.Now()
73+
ln = len(data)
74+
timer.Stop()
75+
timer.Reset(b.toInterval)
76+
} else if len(data) >= b.batchCount {
77+
fire = true
78+
}
79+
} else if last {
80+
et := time.Since(lt)
81+
if (len(data) == ln && et > b.toInterval) || et > b.timeout {
82+
fire = true
83+
}
84+
}
85+
86+
if fire {
87+
if len(data) < b.batchCount {
88+
// do it
89+
e := b.f(data, len(data))
90+
if e != nil {
91+
log.Error("Metadium Server", "Failed", e)
92+
} else {
93+
log.Debug("Metadium Server", "Count", len(data))
94+
}
95+
data = nil
96+
} else {
97+
for {
98+
if len(data) < b.batchCount {
99+
break
100+
}
101+
102+
// do it
103+
e := b.f(data, b.batchCount)
104+
if e != nil {
105+
log.Error("Metadium Server", "Failed", e)
106+
} else {
107+
log.Debug("Metadium Server", "Count", b.batchCount)
108+
}
109+
data = data[b.batchCount:]
110+
}
111+
}
112+
}
113+
114+
lt = time.Now()
115+
ln = len(data)
116+
117+
if itstimer && ln != 0 {
118+
timer.Reset(b.toInterval)
119+
} else if !itstimer && ln == 0 {
120+
timer.Stop()
121+
}
122+
}
123+
124+
// got eod, flush the remaining data
125+
for len(data) > 0 {
126+
l := len(data)
127+
if l > b.batchCount {
128+
l = b.batchCount
129+
}
130+
e := b.f(data, l)
131+
if e != nil {
132+
log.Error("Metadium Server", "Failed", e)
133+
} else {
134+
log.Debug("Metadium Server", "Count", l)
135+
}
136+
data = data[l:]
137+
}
138+
}
139+
140+
func (b *Batch) Stop() {
141+
b.ch <- nil
142+
}
143+
144+
func (b *Batch) Put(data interface{}) {
145+
b.ch <- data
146+
atomic.AddInt32(&b.count, 1)
147+
}
148+
149+
// EOF

0 commit comments

Comments
 (0)