Skip to content

Commit b4c376a

Browse files
author
Achille
authored
recycle compression buffers (#320)
1 parent 46aa607 commit b4c376a

File tree

3 files changed

+62
-36
lines changed

3 files changed

+62
-36
lines changed

buffer.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package kafka
2+
3+
import (
4+
"bytes"
5+
"sync"
6+
)
7+
8+
var bufferPool = sync.Pool{
9+
New: func() interface{} { return newBuffer() },
10+
}
11+
12+
func newBuffer() *bytes.Buffer {
13+
b := new(bytes.Buffer)
14+
b.Grow(65536)
15+
return b
16+
}
17+
18+
func acquireBuffer() *bytes.Buffer {
19+
return bufferPool.Get().(*bytes.Buffer)
20+
}
21+
22+
func releaseBuffer(b *bytes.Buffer) {
23+
if b != nil {
24+
b.Reset()
25+
bufferPool.Put(b)
26+
}
27+
}

compression.go

-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
)
88

99
const (
10-
CompressionNoneCode = 0
11-
1210
compressionCodecMask = 0x07
1311
)
1412

write.go

+35-34
Original file line numberDiff line numberDiff line change
@@ -321,14 +321,19 @@ func (wb *writeBuffer) writeListOffsetRequestV1(correlationID int32, clientID, t
321321
}
322322

323323
func (wb *writeBuffer) writeProduceRequestV2(codec CompressionCodec, correlationID int32, clientID, topic string, partition int32, timeout time.Duration, requiredAcks int16, msgs ...Message) (err error) {
324-
attributes := int8(CompressionNoneCode)
325-
if codec != nil {
326-
if msgs, err = compressMessageSet(codec, msgs...); err != nil {
327-
return err
324+
var size int32
325+
var attributes int8
326+
var compressed *bytes.Buffer
327+
328+
if codec == nil {
329+
size = messageSetSize(msgs...)
330+
} else {
331+
compressed, attributes, size, err = compressMessageSet(codec, msgs...)
332+
if err != nil {
333+
return
328334
}
329-
attributes = codec.Code()
335+
msgs = []Message{{Value: compressed.Bytes()}}
330336
}
331-
size := messageSetSize(msgs...)
332337

333338
h := requestHeader{
334339
ApiKey: int16(produceRequest),
@@ -365,13 +370,14 @@ func (wb *writeBuffer) writeProduceRequestV2(codec CompressionCodec, correlation
365370
wb.writeMessage(msg.Offset, attributes, msg.Time, msg.Key, msg.Value, cw)
366371
}
367372

373+
releaseBuffer(compressed)
368374
return wb.Flush()
369375
}
370376

371377
func (wb *writeBuffer) writeProduceRequestV3(codec CompressionCodec, correlationID int32, clientID, topic string, partition int32, timeout time.Duration, requiredAcks int16, transactionalID *string, msgs ...Message) (err error) {
372378
var size int32
373-
var compressed []byte
374379
var attributes int16
380+
var compressed *bytes.Buffer
375381

376382
if codec == nil {
377383
size = recordBatchSize(msgs...)
@@ -417,10 +423,11 @@ func (wb *writeBuffer) writeProduceRequestV3(codec CompressionCodec, correlation
417423
baseTime := msgs[0].Time
418424
lastTime := msgs[len(msgs)-1].Time
419425

420-
if codec != nil {
426+
if compressed != nil {
421427
wb.writeRecordBatch(attributes, size, len(msgs), baseTime, lastTime, func(wb *writeBuffer) {
422-
wb.Write(compressed)
428+
wb.Write(compressed.Bytes())
423429
})
430+
releaseBuffer(compressed)
424431
} else {
425432
wb.writeRecordBatch(attributes, size, len(msgs), baseTime, lastTime, func(wb *writeBuffer) {
426433
for i, msg := range msgs {
@@ -434,8 +441,8 @@ func (wb *writeBuffer) writeProduceRequestV3(codec CompressionCodec, correlation
434441

435442
func (wb *writeBuffer) writeProduceRequestV7(codec CompressionCodec, correlationID int32, clientID, topic string, partition int32, timeout time.Duration, requiredAcks int16, transactionalID *string, msgs ...Message) (err error) {
436443
var size int32
437-
var compressed []byte
438444
var attributes int16
445+
var compressed *bytes.Buffer
439446

440447
if codec == nil {
441448
size = recordBatchSize(msgs...)
@@ -480,10 +487,11 @@ func (wb *writeBuffer) writeProduceRequestV7(codec CompressionCodec, correlation
480487
baseTime := msgs[0].Time
481488
lastTime := msgs[len(msgs)-1].Time
482489

483-
if codec != nil {
490+
if compressed != nil {
484491
wb.writeRecordBatch(attributes, size, len(msgs), baseTime, lastTime, func(wb *writeBuffer) {
485-
wb.Write(compressed)
492+
wb.Write(compressed.Bytes())
486493
})
494+
releaseBuffer(compressed)
487495
} else {
488496
wb.writeRecordBatch(attributes, size, len(msgs), baseTime, lastTime, func(wb *writeBuffer) {
489497
for i, msg := range msgs {
@@ -539,49 +547,42 @@ func (wb *writeBuffer) writeRecordBatch(attributes int16, size int32, count int,
539547
write(wb)
540548
}
541549

542-
var maxDate = time.Date(5000, time.January, 0, 0, 0, 0, 0, time.UTC)
543-
544-
func compressMessageSet(codec CompressionCodec, msgs ...Message) ([]Message, error) {
545-
estimatedLen := 0
546-
547-
for _, msg := range msgs {
548-
estimatedLen += int(messageSize(msg.Key, msg.Value))
549-
}
550-
551-
buffer := &bytes.Buffer{}
552-
buffer.Grow(estimatedLen / 2)
553-
compressor := codec.NewWriter(buffer)
550+
func compressMessageSet(codec CompressionCodec, msgs ...Message) (compressed *bytes.Buffer, attributes int8, size int32, err error) {
551+
compressed = acquireBuffer()
552+
compressor := codec.NewWriter(compressed)
554553
wb := &writeBuffer{w: compressor}
555554
cw := &crc32Writer{table: crc32.IEEETable}
556555

557556
for offset, msg := range msgs {
558-
wb.writeMessage(int64(offset), CompressionNoneCode, msg.Time, msg.Key, msg.Value, cw)
557+
wb.writeMessage(int64(offset), 0, msg.Time, msg.Key, msg.Value, cw)
559558
}
560559

561-
if err := compressor.Close(); err != nil {
562-
return nil, err
560+
if err = compressor.Close(); err != nil {
561+
releaseBuffer(compressed)
562+
return
563563
}
564564

565-
return []Message{{Value: buffer.Bytes()}}, nil
565+
attributes = codec.Code()
566+
size = messageSetSize(Message{Value: compressed.Bytes()})
567+
return
566568
}
567569

568-
func compressRecordBatch(codec CompressionCodec, msgs ...Message) (compressed []byte, attributes int16, size int32, err error) {
569-
recordBuf := &bytes.Buffer{}
570-
recordBuf.Grow(int(recordBatchSize(msgs...)) / 2)
571-
compressor := codec.NewWriter(recordBuf)
570+
func compressRecordBatch(codec CompressionCodec, msgs ...Message) (compressed *bytes.Buffer, attributes int16, size int32, err error) {
571+
compressed = acquireBuffer()
572+
compressor := codec.NewWriter(compressed)
572573
wb := &writeBuffer{w: compressor}
573574

574575
for i, msg := range msgs {
575576
wb.writeRecord(0, msgs[0].Time, int64(i), msg)
576577
}
577578

578579
if err = compressor.Close(); err != nil {
580+
releaseBuffer(compressed)
579581
return
580582
}
581583

582-
compressed = recordBuf.Bytes()
583584
attributes = int16(codec.Code())
584-
size = recordBatchHeaderSize + int32(len(compressed))
585+
size = recordBatchHeaderSize + int32(compressed.Len())
585586
return
586587
}
587588

0 commit comments

Comments
 (0)