@@ -21,10 +21,19 @@ type batch struct {
21
21
done multiDone
22
22
}
23
23
24
+ type batcherSettings [K any ] struct {
25
+ sizerType request.SizerType
26
+ sizer request.Sizer [K ]
27
+ next sender.SendFunc [K ]
28
+ maxWorkers int
29
+ }
30
+
24
31
// defaultBatcher continuously batch incoming requests and flushes asynchronously if minimum size limit is met or on timeout.
25
32
type defaultBatcher struct {
26
- batchCfg BatchConfig
33
+ cfg BatchConfig
27
34
workerPool chan struct {}
35
+ sizerType request.SizerType
36
+ sizer request.Sizer [request.Request ]
28
37
consumeFunc sender.SendFunc [request.Request ]
29
38
stopWG sync.WaitGroup
30
39
currentBatchMu sync.Mutex
@@ -33,35 +42,37 @@ type defaultBatcher struct {
33
42
shutdownCh chan struct {}
34
43
}
35
44
36
- func newDefaultBatcher (batchCfg BatchConfig , consumeFunc sender. SendFunc [request.Request ], maxWorkers int ) * defaultBatcher {
45
+ func newDefaultBatcher (bCfg BatchConfig , bSet batcherSettings [request.Request ]) * defaultBatcher {
37
46
// TODO: Determine what is the right behavior for this in combination with async queue.
38
47
var workerPool chan struct {}
39
- if maxWorkers != 0 {
40
- workerPool = make (chan struct {}, maxWorkers )
41
- for i := 0 ; i < maxWorkers ; i ++ {
48
+ if bSet . maxWorkers != 0 {
49
+ workerPool = make (chan struct {}, bSet . maxWorkers )
50
+ for i := 0 ; i < bSet . maxWorkers ; i ++ {
42
51
workerPool <- struct {}{}
43
52
}
44
53
}
45
54
return & defaultBatcher {
46
- batchCfg : batchCfg ,
55
+ cfg : bCfg ,
47
56
workerPool : workerPool ,
48
- consumeFunc : consumeFunc ,
57
+ sizerType : bSet .sizerType ,
58
+ sizer : bSet .sizer ,
59
+ consumeFunc : bSet .next ,
49
60
stopWG : sync.WaitGroup {},
50
61
shutdownCh : make (chan struct {}, 1 ),
51
62
}
52
63
}
53
64
54
65
func (qb * defaultBatcher ) resetTimer () {
55
- if qb .batchCfg .FlushTimeout > 0 {
56
- qb .timer .Reset (qb .batchCfg .FlushTimeout )
66
+ if qb .cfg .FlushTimeout > 0 {
67
+ qb .timer .Reset (qb .cfg .FlushTimeout )
57
68
}
58
69
}
59
70
60
71
func (qb * defaultBatcher ) Consume (ctx context.Context , req request.Request , done Done ) {
61
72
qb .currentBatchMu .Lock ()
62
73
63
74
if qb .currentBatch == nil {
64
- reqList , mergeSplitErr := req .MergeSplit (ctx , qb .batchCfg .MaxSize , request . SizerTypeItems , nil )
75
+ reqList , mergeSplitErr := req .MergeSplit (ctx , int ( qb .cfg .MaxSize ), qb . sizerType , nil )
65
76
if mergeSplitErr != nil || len (reqList ) == 0 {
66
77
done .OnDone (mergeSplitErr )
67
78
qb .currentBatchMu .Unlock ()
@@ -76,7 +87,7 @@ func (qb *defaultBatcher) Consume(ctx context.Context, req request.Request, done
76
87
// We have at least one result in the reqList. Last in the list may not have enough data to be flushed.
77
88
// Find if it has at least MinSize, and if it does then move that as the current batch.
78
89
lastReq := reqList [len (reqList )- 1 ]
79
- if lastReq . ItemsCount ( ) < qb .batchCfg .MinSize {
90
+ if qb . sizer . Sizeof ( lastReq ) < qb .cfg .MinSize {
80
91
// Do not flush the last item and add it to the current batch.
81
92
reqList = reqList [:len (reqList )- 1 ]
82
93
qb .currentBatch = & batch {
@@ -95,7 +106,7 @@ func (qb *defaultBatcher) Consume(ctx context.Context, req request.Request, done
95
106
return
96
107
}
97
108
98
- reqList , mergeSplitErr := qb .currentBatch .req .MergeSplit (ctx , qb .batchCfg .MaxSize , request . SizerTypeItems , req )
109
+ reqList , mergeSplitErr := qb .currentBatch .req .MergeSplit (ctx , int ( qb .cfg .MaxSize ), qb . sizerType , req )
99
110
// If failed to merge signal all Done callbacks from current batch as well as the current request and reset the current batch.
100
111
if mergeSplitErr != nil || len (reqList ) == 0 {
101
112
done .OnDone (mergeSplitErr )
@@ -121,7 +132,7 @@ func (qb *defaultBatcher) Consume(ctx context.Context, req request.Request, done
121
132
// cannot unlock and re-lock because we are not done processing all the responses.
122
133
var firstBatch * batch
123
134
// Need to check the currentBatch if more than 1 result returned or if 1 result return but larger than MinSize.
124
- if len (reqList ) > 1 || qb .currentBatch .req . ItemsCount ( ) >= qb .batchCfg .MinSize {
135
+ if len (reqList ) > 1 || qb .sizer . Sizeof ( qb . currentBatch .req ) >= qb .cfg .MinSize {
125
136
firstBatch = qb .currentBatch
126
137
qb .currentBatch = nil
127
138
}
@@ -131,7 +142,7 @@ func (qb *defaultBatcher) Consume(ctx context.Context, req request.Request, done
131
142
// If we still have results to process, then we need to check if the last result has enough data to flush, or we add it to the currentBatch.
132
143
if len (reqList ) > 0 {
133
144
lastReq := reqList [len (reqList )- 1 ]
134
- if lastReq . ItemsCount ( ) < qb .batchCfg .MinSize {
145
+ if qb . sizer . Sizeof ( lastReq ) < qb .cfg .MinSize {
135
146
// Do not flush the last item and add it to the current batch.
136
147
reqList = reqList [:len (reqList )- 1 ]
137
148
qb .currentBatch = & batch {
@@ -170,8 +181,8 @@ func (qb *defaultBatcher) startTimeBasedFlushingGoroutine() {
170
181
171
182
// Start starts the goroutine that reads from the queue and flushes asynchronously.
172
183
func (qb * defaultBatcher ) Start (_ context.Context , _ component.Host ) error {
173
- if qb .batchCfg .FlushTimeout > 0 {
174
- qb .timer = time .NewTimer (qb .batchCfg .FlushTimeout )
184
+ if qb .cfg .FlushTimeout > 0 {
185
+ qb .timer = time .NewTimer (qb .cfg .FlushTimeout )
175
186
qb .startTimeBasedFlushingGoroutine ()
176
187
}
177
188
0 commit comments