1+ /*
2+ Copyright 2015 Workiva, LLC
3+
4+ Licensed under the Apache License, Version 2.0 (the "License");
5+ you may not use this file except in compliance with the License.
6+ You may obtain a copy of the License at
7+
8+ http://www.apache.org/licenses/LICENSE-2.0
9+
10+ Unless required by applicable law or agreed to in writing, software
11+ distributed under the License is distributed on an "AS IS" BASIS,
12+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ See the License for the specific language governing permissions and
14+ limitations under the License.
15+ */
16+
117package batcher
218
319import (
@@ -15,9 +31,15 @@ type Batcher interface {
1531 // one of the conditions for a "complete" batch is reached.
1632 Get () ([]interface {}, error )
1733
34+ // Flush forcibly completes the batch currently being built
35+ Flush () error
36+
1837 // Dispose will dispose of the batcher. Any calls to Put or Get
1938 // will return errors.
2039 Dispose ()
40+
41+ // IsDisposed will determine if the batcher is disposed
42+ IsDisposed () bool
2143}
2244
2345// ErrDisposed is the error returned for a disposed Batcher
@@ -30,7 +52,6 @@ type basicBatcher struct {
3052 maxTime time.Duration
3153 maxItems uint
3254 maxBytes uint
33- queueLen uint
3455 calculateBytes CalculateBytes
3556 disposed bool
3657 items []interface {}
@@ -55,7 +76,6 @@ func New(maxTime time.Duration, maxItems, maxBytes, queueLen uint, calculate Cal
5576 maxTime : maxTime ,
5677 maxItems : maxItems ,
5778 maxBytes : maxBytes ,
58- queueLen : queueLen ,
5979 calculateBytes : calculate ,
6080 items : make ([]interface {}, 0 , maxItems ),
6181 batchChan : make (chan []interface {}, queueLen ),
@@ -71,11 +91,11 @@ func (b *basicBatcher) Put(item interface{}) error {
7191 }
7292
7393 b .items = append (b .items , item )
74- b .availableBytes += b .calculateBytes (item )
94+ if b .calculateBytes != nil {
95+ b .availableBytes += b .calculateBytes (item )
96+ }
7597 if b .ready () {
76- b .batchChan <- b .items
77- b .items = make ([]interface {}, 0 , b .maxItems )
78- b .availableBytes = 0
98+ b .flush ()
7999 }
80100
81101 b .lock .Unlock ()
@@ -85,12 +105,8 @@ func (b *basicBatcher) Put(item interface{}) error {
85105// Get retrieves a batch from the batcher. This call will block until
86106// one of the conditions for a "complete" batch is reached.
87107func (b * basicBatcher ) Get () ([]interface {}, error ) {
88- b .lock .RLock ()
89- if b .disposed {
90- b .lock .RUnlock ()
91- return nil , ErrDisposed
92- }
93- b .lock .RUnlock ()
108+ // Don't check disposed yet so any items remaining in the queue
109+ // will be returned properly.
94110
95111 var timeout <- chan time.Time
96112 if b .maxTime > 0 {
@@ -117,16 +133,49 @@ func (b *basicBatcher) Get() ([]interface{}, error) {
117133 }
118134}
119135
136+ // Flush forcibly completes the batch currently being built
137+ func (b * basicBatcher ) Flush () error {
138+ b .lock .Lock ()
139+ if b .disposed {
140+ b .lock .Unlock ()
141+ return ErrDisposed
142+ }
143+ b .flush ()
144+ b .lock .Unlock ()
145+ return nil
146+ }
147+
120148// Dispose will dispose of the batcher. Any calls to Put or Get
121149// will return errors.
122150func (b * basicBatcher ) Dispose () {
123151 b .lock .Lock ()
152+ if b .disposed {
153+ b .lock .Unlock ()
154+ return
155+ }
156+ b .flush ()
124157 b .disposed = true
125158 b .items = nil
126159 close (b .batchChan )
127160 b .lock .Unlock ()
128161}
129162
163+ // IsDisposed will determine if the batcher is disposed
164+ func (b * basicBatcher ) IsDisposed () bool {
165+ b .lock .RLock ()
166+ disposed := b .disposed
167+ b .lock .RUnlock ()
168+ return disposed
169+ }
170+
171+ // flush adds the batch currently being built to the queue of completed batches.
172+ // flush is not threadsafe, so should be synchronized externally.
173+ func (b * basicBatcher ) flush () {
174+ b .batchChan <- b .items
175+ b .items = make ([]interface {}, 0 , b .maxItems )
176+ b .availableBytes = 0
177+ }
178+
130179func (b * basicBatcher ) ready () bool {
131180 if b .maxItems != 0 && uint (len (b .items )) >= b .maxItems {
132181 return true
0 commit comments