Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
4ec8d04
support dyn for uncompressed
lianetm Jun 5, 2026
203a410
tests
lianetm Jun 5, 2026
64147f6
config & ratio-aware chunk sizing
lianetm Jun 18, 2026
8c82cd2
integration tests
lianetm Jun 18, 2026
b71d5b7
refactor validation & upd docs
lianetm Jun 18, 2026
bdc14e9
update config
lianetm Jun 22, 2026
4e91499
fix for partition change & misc
lianetm Jun 22, 2026
9ccd47d
test updates & docs
lianetm Jun 23, 2026
860bde4
fixes
lianetm Jun 23, 2026
179e675
checkstyle
lianetm Jun 23, 2026
2bafe00
Merge branch 'trunk' into lm-producer-dyn-1
lianetm Jun 23, 2026
9b45abc
fix test
lianetm Jun 23, 2026
59af947
config internal
lianetm Jul 2, 2026
9e791c8
improvements for tryAppend
lianetm Jul 2, 2026
35c5940
release unused & test
lianetm Jul 2, 2026
63de56b
fix to loop in ensureChunkCapacity
lianetm Jul 2, 2026
a2ee30f
fix iteration up to currentChunk
lianetm Jul 2, 2026
3c896c6
remove unneeded freeup call
lianetm Jul 2, 2026
20e52d3
tests for concurrent reservation
lianetm Jul 3, 2026
8d2f5e2
fix for int max value cap
lianetm Jul 3, 2026
3e1fcd8
improve reservation when no mem available
lianetm Jul 3, 2026
36b168d
consolidate refund of pooled and non-pooled mem
lianetm Jul 3, 2026
c4dd928
add missing metric + test
lianetm Jul 8, 2026
a246f9d
O(1) capacity calculation
lianetm Jul 8, 2026
d9e21e8
Merge branch 'trunk' into lm-producer-dyn-1
lianetm Jul 8, 2026
c645114
fix for overcounting and test
lianetm Jul 9, 2026
79b05e0
Merge branch 'trunk' into lm-producer-dyn-1
lianetm Jul 9, 2026
803816a
release unused on stream close & tests
lianetm Jul 13, 2026
7301966
indentation, docs & asserts
lianetm Jul 15, 2026
1d1dcd8
rename
lianetm Jul 15, 2026
dea7c88
close for writes after buffer & test
lianetm Jul 15, 2026
1e5a006
clear index
lianetm Jul 15, 2026
1387a8b
validate deallocated & test
lianetm Jul 15, 2026
9996c77
fix accessor & simplify currentChunkIndex
lianetm Jul 15, 2026
210d0a4
remove dup math on numChunks
lianetm Jul 15, 2026
58a0bfc
consolidate deallocateExtensionChunks
lianetm Jul 15, 2026
e8c78a5
clarify over-allocation on concurrent appends
lianetm Jul 15, 2026
1d8bdd3
refactor append result
lianetm Jul 15, 2026
4f3543a
docs
lianetm Jul 15, 2026
cb440a9
Merge branch 'trunk' into lm-producer-dyn-1
lianetm Jul 15, 2026
2136f0b
fix package name
lianetm Jul 15, 2026
9eced7d
consolidate BufferPool
lianetm Jul 20, 2026
7a5afd1
addressing comments
lianetm Jul 20, 2026
68d3fee
reuse size
lianetm Jul 20, 2026
a7aa754
Merge branch 'trunk' into lm-producer-dyn-1
lianetm Jul 21, 2026
d991798
dedup on RecordAccumulator
lianetm Jul 22, 2026
058642e
pool with allocationMode
lianetm Jul 22, 2026
69828a4
addressing comments
lianetm Jul 22, 2026
87074bf
more updates in tests
lianetm Jul 22, 2026
8e9070b
assert stream closed on buffer call
lianetm Jul 22, 2026
79caa2f
validate chunk capacity on addBuffers & test
lianetm Jul 22, 2026
b1a48d9
reuse estimator
lianetm Jul 22, 2026
29bcbc4
Merge branch 'trunk' into lm-producer-dyn-1
lianetm Jul 22, 2026
e721a23
renames
lianetm Jul 24, 2026
2fd0113
Merge branch 'trunk' into lm-producer-dyn-1
lianetm Jul 24, 2026
1de3d76
improve test timeouts
lianetm Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion checkstyle/suppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
files="(Utils|Topic|Lz4BlockOutputStream|JoinGroupRequest).java"/>

<suppress checks="CyclomaticComplexity"
files="(AbstractFetch|ClientTelemetryReporter|ConsumerCoordinator|CommitRequestManager|FetchCollector|OffsetFetcherUtils|KafkaProducer|Sender|ConfigDef|KerberosLogin|AbstractRequest|AbstractResponse|Selector|SslFactory|SslTransportLayer|SaslClientAuthenticator|SaslClientCallbackHandler|SaslServerAuthenticator|AbstractCoordinator|TransactionManager|AbstractStickyAssignor|DefaultSslEngineFactory|Authorizer|RecordAccumulator|MemoryRecords|FetchSessionHandler|MockAdminClient).java"/>
files="(AbstractFetch|BufferPool|ClientTelemetryReporter|ConsumerCoordinator|CommitRequestManager|FetchCollector|OffsetFetcherUtils|KafkaProducer|Sender|ConfigDef|KerberosLogin|AbstractRequest|AbstractResponse|Selector|SslFactory|SslTransportLayer|SaslClientAuthenticator|SaslClientCallbackHandler|SaslServerAuthenticator|AbstractCoordinator|TransactionManager|AbstractStickyAssignor|DefaultSslEngineFactory|Authorizer|RecordAccumulator|MemoryRecords|FetchSessionHandler|MockAdminClient).java"/>

<suppress checks="JavaNCSS"
files="(AbstractRequest|AbstractResponse|KerberosLogin|WorkerSinkTaskTest|TransactionManagerTest|SenderTest|KafkaAdminClient|ConsumerCoordinatorTest|KafkaAdminClientTest|KafkaProducerTest).java"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.kafka.clients.consumer.OffsetCommitCallback;
import org.apache.kafka.clients.producer.internals.BufferPool;
import org.apache.kafka.clients.producer.internals.BuiltInPartitioner;
import org.apache.kafka.clients.producer.internals.ChunkedRecordAccumulator;
import org.apache.kafka.clients.producer.internals.KafkaProducerMetrics;
import org.apache.kafka.clients.producer.internals.ProducerInterceptors;
import org.apache.kafka.clients.producer.internals.ProducerMetadata;
Expand Down Expand Up @@ -92,6 +93,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -458,19 +460,49 @@ public KafkaProducer(Properties properties, Serializer<K> keySerializer, Seriali
// As per Kafka producer configuration documentation batch.size may be set to 0 to explicitly disable
// batching which in practice actually means using a batch size of 1.
int batchSize = Math.max(1, config.getInt(ProducerConfig.BATCH_SIZE_CONFIG));
this.accumulator = new RecordAccumulator(logContext,
batchSize,
compression,
lingerMs(config),
retryBackoffMs,
retryBackoffMaxMs,
deliveryTimeoutMs,
partitionerConfig,
metrics,
PRODUCER_METRIC_GROUP_NAME,
time,
transactionManager,
new BufferPool(this.totalMemorySize, batchSize, metrics, time, PRODUCER_METRIC_GROUP_NAME));
String allocationStrategy = config.getString(ProducerConfig.BUFFER_MEMORY_ALLOCATION_STRATEGY_CONFIG)
.toLowerCase(Locale.ROOT);
boolean incremental = ProducerConfig.BUFFER_MEMORY_ALLOCATION_STRATEGY_INCREMENTAL.equals(allocationStrategy);
// Use the chunked path only when a batch is at least one full chunk
// (batch.size >= CHUNK_SIZE). Below that, a batch can't fill even one chunk, so chunking
// would over-reserve and the producer falls back to the full strategy instead.
boolean useIncremental = incremental && batchSize >= ChunkedRecordAccumulator.CHUNK_SIZE;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we switch automatically to full because of the batch size, it might be useful to log a warning.

// The chunked path does not support compression yet (TODO: KAFKA-20579)
if (useIncremental && compression.type() != CompressionType.NONE) {
throw new ConfigException("The " + ProducerConfig.BUFFER_MEMORY_ALLOCATION_STRATEGY_INCREMENTAL
+ " " + ProducerConfig.BUFFER_MEMORY_ALLOCATION_STRATEGY_CONFIG
+ " does not support compression yet. " + ProducerConfig.COMPRESSION_TYPE_CONFIG
+ " must be set to none.");
}
if (useIncremental) {
this.accumulator = new ChunkedRecordAccumulator(logContext,
batchSize,
compression,
lingerMs(config),
retryBackoffMs,
retryBackoffMaxMs,
deliveryTimeoutMs,
partitionerConfig,
metrics,
PRODUCER_METRIC_GROUP_NAME,
time,
transactionManager,
new BufferPool(this.totalMemorySize, ChunkedRecordAccumulator.CHUNK_SIZE, metrics, time, PRODUCER_METRIC_GROUP_NAME, BufferPool.AllocationMode.INCREMENTAL));
} else {
this.accumulator = new RecordAccumulator(logContext,
batchSize,
compression,
lingerMs(config),
retryBackoffMs,
retryBackoffMaxMs,
deliveryTimeoutMs,
partitionerConfig,
metrics,
PRODUCER_METRIC_GROUP_NAME,
time,
transactionManager,
new BufferPool(this.totalMemorySize, batchSize, metrics, time, PRODUCER_METRIC_GROUP_NAME, BufferPool.AllocationMode.FULL));
}

this.errors = this.metrics.sensor("errors");
this.sender = newSender(logContext, kafkaClient, this.metadata);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,20 @@ public class ProducerConfig extends AbstractConfig {
+ "not all memory the producer uses is used for buffering. Some additional memory will be used for compression (if "
+ "compression is enabled) as well as for maintaining in-flight requests.";

/** <code>buffer.memory.allocation.strategy</code> */
public static final String BUFFER_MEMORY_ALLOCATION_STRATEGY_CONFIG = "buffer.memory.allocation.strategy";
public static final String BUFFER_MEMORY_ALLOCATION_STRATEGY_FULL = "full";
public static final String BUFFER_MEMORY_ALLOCATION_STRATEGY_INCREMENTAL = "incremental";
private static final String BUFFER_MEMORY_ALLOCATION_STRATEGY_DOC = "Controls how the producer allocates memory from <code>" + BUFFER_MEMORY_CONFIG + "</code> for record batches. The following values are supported: "
+ "<ul>"
+ "<li><code>" + BUFFER_MEMORY_ALLOCATION_STRATEGY_FULL + "</code>: reserves a full <code>" + BATCH_SIZE_CONFIG + "</code> up front when a batch is created, "
+ "regardless of how much data it ends up holding. Pool memory therefore scales with the number of active partitions.</li>"
+ "<li><code>" + BUFFER_MEMORY_ALLOCATION_STRATEGY_INCREMENTAL + "</code>: allocates memory on demand as records are appended, growing a batch "
+ "up to <code>" + BATCH_SIZE_CONFIG + "</code>. Pool memory therefore scales with the data actually buffered rather than the number of active "
+ "partitions, allowing larger <code>" + BATCH_SIZE_CONFIG + "</code> values (e.g. for high-latency clusters) without reserving "
+ "<code>" + BATCH_SIZE_CONFIG + "</code> for every active partition.</li>"
+ "</ul>";

/** <code>retry.backoff.ms</code> */
public static final String RETRY_BACKOFF_MS_CONFIG = CommonClientConfigs.RETRY_BACKOFF_MS_CONFIG;

Expand Down Expand Up @@ -401,6 +415,14 @@ public class ProducerConfig extends AbstractConfig {
Importance.MEDIUM,
CommonClientConfigs.CLIENT_DNS_LOOKUP_DOC)
.define(BUFFER_MEMORY_CONFIG, Type.LONG, 32 * 1024 * 1024L, atLeast(0L), Importance.HIGH, BUFFER_MEMORY_DOC)
// Internal until the incremental strategy is fully implemented
.defineInternal(BUFFER_MEMORY_ALLOCATION_STRATEGY_CONFIG,
Type.STRING,
BUFFER_MEMORY_ALLOCATION_STRATEGY_FULL,
ConfigDef.CaseInsensitiveValidString
.in(BUFFER_MEMORY_ALLOCATION_STRATEGY_FULL, BUFFER_MEMORY_ALLOCATION_STRATEGY_INCREMENTAL),
Importance.MEDIUM,
BUFFER_MEMORY_ALLOCATION_STRATEGY_DOC)
.define(RETRIES_CONFIG, Type.INT, Integer.MAX_VALUE, between(0, Integer.MAX_VALUE), Importance.HIGH, RETRIES_DOC)
.define(ACKS_CONFIG,
Type.STRING,
Expand Down
Loading
Loading