-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a58c48b
commit 21a6c7c
Showing
5 changed files
with
357 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package queue // import "go.opentelemetry.io/collector/exporter/internal/queue" | ||
|
||
import ( | ||
"context" | ||
"math" | ||
"sync" | ||
"time" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
) | ||
|
||
// QueueBatcher continuosly reads from the queue and flushes asynchronously if size limit is met or on timeout. | ||
type QueueBatcher struct { | ||
BaseBatcher | ||
currentBatchMu sync.Mutex | ||
currentBatch *batch | ||
timer *time.Timer | ||
shutdownCh chan bool | ||
} | ||
|
||
func (qb *QueueBatcher) resetTimer() { | ||
if qb.batchCfg.FlushTimeout != 0 { | ||
qb.timer.Reset(qb.batchCfg.FlushTimeout) | ||
} | ||
} | ||
|
||
// Start starts the goroutine that reads from the queue and flushes asynchronously. | ||
func (qb *QueueBatcher) Start(_ context.Context, _ component.Host) error { | ||
qb.startWorkerPool() | ||
qb.shutdownCh = make(chan bool, 1) | ||
|
||
if qb.batchCfg.FlushTimeout == 0 { | ||
qb.timer = time.NewTimer(math.MaxInt) | ||
qb.timer.Stop() | ||
} else { | ||
qb.timer = time.NewTimer(qb.batchCfg.FlushTimeout) | ||
} | ||
|
||
// This goroutine reads and then flushes. | ||
// 1. Reading from the queue is blocked until the queue is non-empty or until the queue is stopped. | ||
// 2. flushAsync() blocks until there are idle workers in the worker pool. | ||
qb.stopWG.Add(1) | ||
go func() { | ||
defer qb.stopWG.Done() | ||
for { | ||
idx, ctx, req, ok := qb.queue.Read(context.Background()) | ||
if !ok { | ||
qb.shutdownCh <- true | ||
return | ||
} | ||
|
||
qb.currentBatchMu.Lock() | ||
if qb.currentBatch == nil || qb.currentBatch.req == nil { | ||
qb.resetTimer() | ||
qb.currentBatch = &batch{ | ||
req: req, | ||
ctx: ctx, | ||
idxList: []uint64{idx}} | ||
} else { | ||
mergedReq, mergeErr := qb.currentBatch.req.Merge(qb.currentBatch.ctx, req) | ||
if mergeErr != nil { | ||
qb.queue.OnProcessingFinished(idx, mergeErr) | ||
qb.currentBatchMu.Unlock() | ||
continue | ||
} | ||
qb.currentBatch = &batch{ | ||
req: mergedReq, | ||
ctx: qb.currentBatch.ctx, | ||
idxList: append(qb.currentBatch.idxList, idx)} | ||
} | ||
|
||
if qb.currentBatch.req.ItemsCount() > qb.batchCfg.MinSizeItems { | ||
batchToFlush := *qb.currentBatch | ||
qb.currentBatch = nil | ||
qb.currentBatchMu.Unlock() | ||
qb.flushAsync(batchToFlush) // returns when it successfully started a goroutine for flushing. | ||
qb.resetTimer() | ||
} else { | ||
qb.currentBatchMu.Unlock() | ||
} | ||
} | ||
}() | ||
|
||
qb.stopWG.Add(1) | ||
go func() { | ||
defer qb.stopWG.Done() | ||
for { | ||
select { | ||
case <-qb.shutdownCh: | ||
return | ||
case <-qb.timer.C: | ||
qb.currentBatchMu.Lock() | ||
if qb.currentBatch == nil || qb.currentBatch.req == nil { | ||
qb.currentBatchMu.Unlock() | ||
continue | ||
} | ||
batchToFlush := *qb.currentBatch | ||
qb.currentBatch = nil | ||
qb.currentBatchMu.Unlock() | ||
qb.flushAsync(batchToFlush) // returns when it successfully started a goroutine for flushing. | ||
qb.resetTimer() | ||
} | ||
|
||
} | ||
}() | ||
|
||
return nil | ||
} |
Oops, something went wrong.