Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 73c16c1

Browse files
committed
kgo: do not trigger draining early if a partition moves sinks while lingering
This extracts the 3x duplicated logic for triggering draining to a new function. The buffering record logic LOOKED different, but was the same. We now use this new function when a partition moves sinks: rather than always triggering draining, we take lingering into consideration.
1 parent d506614 commit 73c16c1

File tree

1 file changed

+25
-46
lines changed

1 file changed

+25
-46
lines changed

pkg/kgo/sink.go

Lines changed: 25 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ func (s *sink) createReq(id int64, epoch int16) (*produceRequest, *kmsg.AddParti
134134
recBuf.inflight++
135135

136136
recBuf.batchDrainIdx++
137+
recBuf.lockedStopLinger()
137138
recBuf.seq = incrementSequence(recBuf.seq, int32(len(batch.records)))
138-
moreToDrain = recBuf.tryStopLingerForDraining() || moreToDrain
139+
moreToDrain = recBuf.checkIfShouldDrainOrStartLinger() || moreToDrain
139140
recBuf.mu.Unlock()
140141

141142
txnBuilder.add(recBuf)
@@ -1384,18 +1385,17 @@ func (recBuf *recBuf) bufferRecord(pr promisedRec, abortOnNewBatch bool) bool {
13841385
}
13851386

13861387
var (
1387-
newBatch = true
1388-
onDrainBatch = recBuf.batchDrainIdx == len(recBuf.batches)
1388+
mkNewBatch = true
13891389
produceVersion = recBuf.sink.produceVersion.Load()
13901390
)
13911391

1392-
if !onDrainBatch {
1392+
if recBuf.batchDrainIdx != len(recBuf.batches) {
13931393
batch := recBuf.batches[len(recBuf.batches)-1]
13941394
appended, _ := batch.tryBuffer(pr, produceVersion, recBuf.maxRecordBatchBytes, false)
1395-
newBatch = !appended
1395+
mkNewBatch = !appended
13961396
}
13971397

1398-
if newBatch {
1398+
if mkNewBatch {
13991399
newBatch := recBuf.newRecordBatch()
14001400
appended, aborted := newBatch.tryBuffer(pr, produceVersion, recBuf.maxRecordBatchBytes, abortOnNewBatch)
14011401

@@ -1413,22 +1413,7 @@ func (recBuf *recBuf) bufferRecord(pr promisedRec, abortOnNewBatch bool) bool {
14131413
recBuf.batches = append(recBuf.batches, newBatch)
14141414
}
14151415

1416-
if recBuf.cl.cfg.linger == 0 {
1417-
if onDrainBatch {
1418-
recBuf.sink.maybeDrain()
1419-
}
1420-
} else {
1421-
// With linger, if this is a new batch but not the first, we
1422-
// stop lingering and begin draining. The drain loop will
1423-
// restart our linger once this buffer has one batch left.
1424-
if newBatch && !onDrainBatch ||
1425-
// If this is the first batch, try lingering; if
1426-
// we cannot, we are being flushed and must drain.
1427-
onDrainBatch && !recBuf.lockedMaybeLinger() {
1428-
recBuf.lockedStopLinger()
1429-
recBuf.sink.maybeDrain()
1430-
}
1431-
}
1416+
recBuf.maybeTriggerDrain()
14321417

14331418
recBuf.buffered.Add(1)
14341419
if recBuf.cl.producer.hooks != nil && len(recBuf.cl.producer.hooks.partitioned) > 0 {
@@ -1440,19 +1425,22 @@ func (recBuf *recBuf) bufferRecord(pr promisedRec, abortOnNewBatch bool) bool {
14401425
return true
14411426
}
14421427

1443-
// Stops lingering, potentially restarting it, and returns whether there is
1444-
// more to drain.
1445-
//
1446-
// If lingering, if there are more than one batches ready, there is definitely
1447-
// more to drain and we should not linger. Otherwise, if we cannot restart
1448-
// lingering, then we are flushing and also indicate there is more to drain.
1449-
func (recBuf *recBuf) tryStopLingerForDraining() bool {
1450-
recBuf.lockedStopLinger()
1451-
canLinger := recBuf.cl.cfg.linger != 0
1452-
moreToDrain := !canLinger && len(recBuf.batches) > recBuf.batchDrainIdx ||
1453-
canLinger && (len(recBuf.batches) > recBuf.batchDrainIdx+1 ||
1454-
len(recBuf.batches) == recBuf.batchDrainIdx+1 && !recBuf.lockedMaybeLinger())
1455-
return moreToDrain
1428+
// Maybe drains, maybe starts a linger.
1429+
// Must be called while locked.
1430+
func (recBuf *recBuf) maybeTriggerDrain() {
1431+
if recBuf.checkIfShouldDrainOrStartLinger() {
1432+
recBuf.lockedStopLinger()
1433+
recBuf.sink.maybeDrain()
1434+
}
1435+
}
1436+
1437+
// Checks and returns if we should drain; if not, this potentially starts a
1438+
// linger timer.
1439+
func (recBuf *recBuf) checkIfShouldDrainOrStartLinger() bool {
1440+
nbufBatches := len(recBuf.batches) - recBuf.batchDrainIdx
1441+
return recBuf.cl.cfg.linger == 0 && nbufBatches > 0 || // no lingering, and any batch exists? drain
1442+
nbufBatches > 1 || // lingering, and more than one batch exists? drain -- one is full
1443+
nbufBatches == 1 && !recBuf.lockedMaybeLinger() // only one batch; if we cannot start lingering, we are being flushed or have too much buffered and have to drain
14561444
}
14571445

14581446
// Begins a linger timer unless the producer is being flushed.
@@ -1584,9 +1572,7 @@ func (recBuf *recBuf) clearFailing() {
15841572
defer recBuf.mu.Unlock()
15851573

15861574
recBuf.failing = false
1587-
if len(recBuf.batches) != recBuf.batchDrainIdx {
1588-
recBuf.sink.maybeDrain()
1589-
}
1575+
recBuf.maybeTriggerDrain()
15901576
}
15911577

15921578
func (recBuf *recBuf) resetBatchDrainIdx() {
@@ -1763,14 +1749,7 @@ func (b *recBatch) decInflight() {
17631749
return
17641750
}
17651751
recBuf.inflightOnSink = nil
1766-
1767-
nbufBatches := len(recBuf.batches) - recBuf.batchDrainIdx
1768-
if recBuf.cl.cfg.linger == 0 && nbufBatches > 0 ||
1769-
nbufBatches > 1 ||
1770-
nbufBatches == 1 && !recBuf.lockedMaybeLinger() {
1771-
recBuf.lockedStopLinger()
1772-
recBuf.sink.maybeDrain()
1773-
}
1752+
recBuf.maybeTriggerDrain()
17741753
}
17751754

17761755
////////////////////

0 commit comments

Comments
 (0)