@@ -35,8 +35,21 @@ type Batcher struct {
35
35
Service platform.WriteService // Service receives batches flushed from Batcher.
36
36
}
37
37
38
- // Write reads r in batches and sends to the output .
38
+ // Write reads r in batches and writes to a target specified by org and bucket .
39
39
func (b * Batcher ) Write (ctx context.Context , org , bucket platform.ID , r io.Reader ) error {
40
+ return b .writeBytes (ctx , r , func (batch []byte ) error {
41
+ return b .Service .Write (ctx , org , bucket , bytes .NewReader (batch ))
42
+ })
43
+ }
44
+
45
+ // WriteTo reads r in batches and writes to a target specified by filter.
46
+ func (b * Batcher ) WriteTo (ctx context.Context , filter platform.BucketFilter , r io.Reader ) error {
47
+ return b .writeBytes (ctx , r , func (batch []byte ) error {
48
+ return b .Service .WriteTo (ctx , filter , bytes .NewReader (batch ))
49
+ })
50
+ }
51
+
52
+ func (b * Batcher ) writeBytes (ctx context.Context , r io.Reader , writeFn func (batch []byte ) error ) error {
40
53
ctx , cancel := context .WithCancel (ctx )
41
54
defer cancel ()
42
55
@@ -47,7 +60,7 @@ func (b *Batcher) Write(ctx context.Context, org, bucket platform.ID, r io.Reade
47
60
lines := make (chan []byte )
48
61
49
62
errC := make (chan error , 2 )
50
- go b .write (ctx , org , bucket , lines , errC )
63
+ go b .write (ctx , writeFn , lines , errC )
51
64
go b .read (ctx , r , lines , errC )
52
65
53
66
// we loop twice to check if both read and write have an error. if read exits
@@ -99,95 +112,7 @@ func (b *Batcher) read(ctx context.Context, r io.Reader, lines chan<- []byte, er
99
112
// finishes when the lines channel is closed or context is done.
100
113
// if an error occurs while writing data to the write service, the error is send in the
101
114
// errC channel and the function returns.
102
- func (b * Batcher ) write (ctx context.Context , org , bucket platform.ID , lines <- chan []byte , errC chan <- error ) {
103
- flushInterval := b .MaxFlushInterval
104
- if flushInterval == 0 {
105
- flushInterval = DefaultInterval
106
- }
107
-
108
- maxBytes := b .MaxFlushBytes
109
- if maxBytes == 0 {
110
- maxBytes = DefaultMaxBytes
111
- }
112
-
113
- timer := time .NewTimer (flushInterval )
114
- defer func () { _ = timer .Stop () }()
115
-
116
- buf := make ([]byte , 0 , maxBytes )
117
- r := bytes .NewReader (buf )
118
-
119
- var line []byte
120
- var more = true
121
- // if read closes the channel normally, exit the loop
122
- for more {
123
- select {
124
- case line , more = <- lines :
125
- if more {
126
- buf = append (buf , line ... )
127
- }
128
- // write if we exceed the max lines OR read routine has finished
129
- if len (buf ) >= maxBytes || (! more && len (buf ) > 0 ) {
130
- r .Reset (buf )
131
- timer .Reset (flushInterval )
132
- if err := b .Service .Write (ctx , org , bucket , r ); err != nil {
133
- errC <- err
134
- return
135
- }
136
- buf = buf [:0 ]
137
- }
138
- case <- timer .C :
139
- if len (buf ) > 0 {
140
- r .Reset (buf )
141
- timer .Reset (flushInterval )
142
- if err := b .Service .Write (ctx , org , bucket , r ); err != nil {
143
- errC <- err
144
- return
145
- }
146
- buf = buf [:0 ]
147
- }
148
- case <- ctx .Done ():
149
- errC <- ctx .Err ()
150
- return
151
- }
152
- }
153
-
154
- errC <- nil
155
- }
156
-
157
- func (b * Batcher ) WriteTo (ctx context.Context , filter platform.BucketFilter , r io.Reader ) error {
158
- ctx , cancel := context .WithCancel (ctx )
159
- defer cancel ()
160
-
161
- if b .Service == nil {
162
- return fmt .Errorf ("destination write service required" )
163
- }
164
-
165
- lines := make (chan []byte )
166
-
167
- errC := make (chan error , 2 )
168
- go b .writeTo (ctx , filter , lines , errC )
169
- go b .read (ctx , r , lines , errC )
170
-
171
- // we loop twice to check if both read and write have an error. if read exits
172
- // cleanly, then we still want to wait for write.
173
- for i := 0 ; i < 2 ; i ++ {
174
- select {
175
- case <- ctx .Done ():
176
- return ctx .Err ()
177
- case err := <- errC :
178
- // onky if there is any error, exit immediately.
179
- if err != nil {
180
- return err
181
- }
182
- }
183
- }
184
- return nil
185
- }
186
-
187
- // finishes when the lines channel is closed or context is done.
188
- // if an error occurs while writing data to the write service, the error is send in the
189
- // errC channel and the function returns.
190
- func (b * Batcher ) writeTo (ctx context.Context , filter platform.BucketFilter , lines <- chan []byte , errC chan <- error ) {
115
+ func (b * Batcher ) write (ctx context.Context , writeFn func (batch []byte ) error , lines <- chan []byte , errC chan <- error ) {
191
116
flushInterval := b .MaxFlushInterval
192
117
if flushInterval == 0 {
193
118
flushInterval = DefaultInterval
@@ -202,7 +127,6 @@ func (b *Batcher) writeTo(ctx context.Context, filter platform.BucketFilter, lin
202
127
defer func () { _ = timer .Stop () }()
203
128
204
129
buf := make ([]byte , 0 , maxBytes )
205
- r := bytes .NewReader (buf )
206
130
207
131
var line []byte
208
132
var more = true
@@ -215,19 +139,17 @@ func (b *Batcher) writeTo(ctx context.Context, filter platform.BucketFilter, lin
215
139
}
216
140
// write if we exceed the max lines OR read routine has finished
217
141
if len (buf ) >= maxBytes || (! more && len (buf ) > 0 ) {
218
- r .Reset (buf )
219
142
timer .Reset (flushInterval )
220
- if err := b . Service . WriteTo ( ctx , filter , r ); err != nil {
143
+ if err := writeFn ( buf ); err != nil {
221
144
errC <- err
222
145
return
223
146
}
224
147
buf = buf [:0 ]
225
148
}
226
149
case <- timer .C :
227
150
if len (buf ) > 0 {
228
- r .Reset (buf )
229
151
timer .Reset (flushInterval )
230
- if err := b . Service . WriteTo ( ctx , filter , r ); err != nil {
152
+ if err := writeFn ( buf ); err != nil {
231
153
errC <- err
232
154
return
233
155
}
0 commit comments