[
https://issues.apache.org/jira/browse/NIFI-16517?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18133070#comment-18133070
]
Paweł Rzepiński commented on NIFI-16517:
----------------------------------------
The current record format writes them with different lengths. A null value is
length -1 and has no payload. An empty buffer is length 0 followed by zero
bytes.
DefaultRecord.writeTo
(https://github.com/apache/kafka/blob/26b251a451ce941d3d7a55e6487bcb7f16b5ad48/clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecord.java#L191-L197):
if (value == null) {
ByteUtils.writeVarint(-1, out);
} else {
int valueSize = value.remaining();
ByteUtils.writeVarint(valueSize, out);
Utils.writeTo(out, value, valueSize);
}
On read, a negative length comes back as null. A length of 0 comes back as an
empty buffer.
Utils.readBytes
(https://github.com/apache/kafka/blob/26b251a451ce941d3d7a55e6487bcb7f16b5ad48/clients/src/main/java/org/apache/kafka/common/utils/Utils.java#L750-L758):
public static ByteBuffer readBytes(ByteBuffer srcBuf, int bytesToRead) {
if (bytesToRead < 0)
return null;
final ByteBuffer dstBuf = srcBuf.slice();
dstBuf.limit(bytesToRead);
srcBuf.position(srcBuf.position() + bytesToRead);
return dstBuf;
}
Record.hasValue() is true whenever the value is not null, so an empty value
still counts as present. DefaultRecord checks value != null.
PartialDefaultRecord checks valueSize >= 0. The older message formats do the
same: a null value is stored as the int -1, and hasNullValue() is valueSize() <
0.
The client marks a record as a tombstone only when that check fails.
MemoryRecords.filterBatch
(https://github.com/apache/kafka/blob/26b251a451ce941d3d7a55e6487bcb7f16b5ad48/clients/src/main/java/org/apache/kafka/common/record/internal/MemoryRecords.java#L230-L238):
if (filter.shouldRetainRecord(batch, record)) {
if (record.offset() > maxOffset)
maxOffset = record.offset();
retainedRecords.add(record);
if (!record.hasValue()) {
containsTombstones = true;
}
So a producer can send both. ProducerRecord allows a null value. After a round
trip, the consumer sees value() == null for the tombstone and a non-null
zero-length buffer for the empty message.
> ConsumeKafka sets tombstone attribute to true for empty payload in FLOW_FILE
> Processing Strategy
> ------------------------------------------------------------------------------------------------
>
> Key: NIFI-16517
> URL: https://issues.apache.org/jira/browse/NIFI-16517
> Project: Apache NiFi
> Issue Type: Bug
> Reporter: Paweł Rzepiński
> Priority: Minor
>
> Both null and empty (zero bytes array) payload results in empty flow file
> with tombstone attribute set to "true" in FLOW_FILE Processing Strategy.
> Only null payload should do that.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)