Skip to content

MINOR: add versioning to request and response headers#7372

Merged
mumrah merged 2 commits intoapache:trunkfrom
cmccabe:header_versioning
Sep 26, 2019
Merged

MINOR: add versioning to request and response headers#7372
mumrah merged 2 commits intoapache:trunkfrom
cmccabe:header_versioning

Conversation

@cmccabe
Copy link
Copy Markdown
Contributor

@cmccabe cmccabe commented Sep 19, 2019

Add a version number to request and response headers. The header version is determined by the first two 16 bit fields read (API key and API version). For now, ControlledShutdown v0 has header version 0, and all other requests have v1. Once KIP-482 is implemented, there will be a v2 of the header which supports tagged fields.

Copy link
Copy Markdown
Contributor

@soondenana soondenana left a comment

Choose a reason for hiding this comment

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

Looks good, left a few comments/nits.

Looking forward to see the PR where v2 is introduced.

Comment thread clients/src/main/java/org/apache/kafka/common/requests/RequestHeader.java Outdated
Comment thread clients/src/main/java/org/apache/kafka/common/requests/RequestHeader.java Outdated
Comment thread clients/src/main/java/org/apache/kafka/common/requests/ResponseHeader.java Outdated
Comment thread clients/src/main/java/org/apache/kafka/common/requests/OffsetFetchRequest.java Outdated
Copy link
Copy Markdown
Member

@dajac dajac left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for the PR.

It seems checkstyle does not pass though.

Comment thread clients/src/main/java/org/apache/kafka/common/protocol/ApiKeys.java Outdated
Copy link
Copy Markdown
Member

@jsancio jsancio left a comment

Choose a reason for hiding this comment

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

Thanks for the changes @colinhicks. I have a few questions.

Comment thread clients/src/main/java/org/apache/kafka/common/protocol/ApiKeys.java Outdated
Comment thread clients/src/main/java/org/apache/kafka/common/protocol/Protocol.java Outdated
Comment thread clients/src/main/java/org/apache/kafka/common/requests/RequestHeader.java Outdated
Comment thread clients/src/main/resources/common/message/RequestHeader.json Outdated
Add a version number to request and response headers.  The header
version is determined by the first two 16 bit fields read (API key and
API version).  For now, ControlledShutdown v0 has header version 0, and
all other requests have v1.  Once KIP-482 is implemented, there will be
a v2 of the header which supports tagged fields.
@cmccabe
Copy link
Copy Markdown
Contributor Author

cmccabe commented Sep 25, 2019

rebased on trunk

@cmccabe
Copy link
Copy Markdown
Contributor Author

cmccabe commented Sep 25, 2019

Jenkins is having git errors again ☹️

08:31:06 ERROR: Error cloning remote repo 'origin'
08:31:06 hudson.plugins.git.GitException: Command "git fetch --tags --progress git://github.com/apache/kafka.git +refs/heads/*:refs/remotes/origin/*" returned status code 128:

Copy link
Copy Markdown
Member

@mumrah mumrah left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks Colin, formalizing the header fields as a schema and decoupling them from the protocols is a big improvement. +1

@mumrah
Copy link
Copy Markdown
Member

mumrah commented Sep 25, 2019

retest this please

@mumrah mumrah merged commit 0566dfd into apache:trunk Sep 26, 2019
ijuma added a commit to confluentinc/kafka that referenced this pull request Sep 29, 2019
Conflicts:
* .gitignore: addition of clients/src/generated-test was near
local additions for support-metrics.
* checkstyle/suppressions.xml: upstream refactoring of exclusions
for generator were near the local changes for support-metrics.
* gradle.properties: scala version bump caused a minor conflict
due to the kafka version change locally.
gradle/dependencies.gradle: bcpkix version bump was near avro
additions in the local version.

* apache-github/trunk: (49 commits)
  KAFKA-8471: Replace control requests/responses with automated protocol (apache#7353)
  MINOR: Don't generate unnecessary strings for debug logging in FetchSessionHandler (apache#7394)
  MINOR:fixed typo and removed outdated varilable name (apache#7402)
  KAFKA-8934: Create version file during build for Streams (apache#7397)
  KAFKA-8319: Make KafkaStreamsTest a non-integration test class (apache#7382)
  KAFKA-6883: Add toUpperCase support to sasl.kerberos.principal.to.local rule (KIP-309)
  KAFKA-8907; Return topic configs in CreateTopics response (KIP-525) (apache#7380)
  MINOR: Address review comments for KIP-504 authorizer changes (apache#7379)
  MINOR: add versioning to request and response headers (apache#7372)
  KAFKA-7273: Extend Connect Converter to support headers (apache#6362)
  MINOR: improve the Kafka RPC code generator (apache#7340)
  MINOR: Improve the org.apache.kafka.common.protocol code (apache#7344)
  KAFKA-8880: Docs on upgrade-guide (apache#7385)
  KAFKA-8179: do not suspend standby tasks during rebalance (apache#7321)
  KAFKA-8580: Compute RocksDB metrics (apache#7263)
  KAFKA-8880: Add overloaded function of Consumer.committed (apache#7304)
  HOTFIX: fix Kafka Streams upgrade note for broker backward compatibility (apache#7363)
  KAFKA-8848; Update system tests to use new AclAuthorizer (apache#7374)
  MINOR: remove unnecessary null check (apache#7299)
  KAFKA-6958: Overload methods for group and windowed stream to allow to name operation name using the new Named class (apache#6413)
  ...
if (struct.hasField(CLIENT_ID_FIELD_NAME))
clientId = struct.getString(CLIENT_ID_FIELD_NAME);
else
clientId = "";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There's a bit of a change in behavior in this PR. We would previously return an empty string for older request versions and now we return null. Is that intended @cmccabe? cc @hachikuji

Copy link
Copy Markdown
Member

@ijuma ijuma Oct 10, 2019

Choose a reason for hiding this comment

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

Actually, it's not just older requests, the default was always "" whereas I am seeing null after this PR. It looks like there are two issues:

  1. We didn't set a default of "" for clientId in the json schema.
  2. The generated protocol code behaves differently with regards to default values. It only uses the default if the field is not present. The Struct code uses it if value == null.
        Object value = this.values[field.index];
        if (value != null)
            return value;
        else if (field.def.hasDefaultValue)
            return field.def.defaultValue;
        else if (field.def.type.isNullable())
            return null;
        else
            throw new SchemaException("Missing value for field '" + field.def.name + "' which has no default value.");

This is the generated code after I add the "" default for clientId.

public void read(Readable readable, short version) {
        this.requestApiKey = readable.readShort();
        this.requestApiVersion = readable.readShort();
        this.correlationId = readable.readInt();
        if (version >= 1) {
            this.clientId = readable.readNullableString();
        } else {
            this.clientId = "";
        }
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The out-of-the-box default for string fields in the generated schema is always the empty string, never null. null would have to have been specifically chosen, which we did not. So you shouldn't have to specifically choose the empty string as a default.

I was (am?) confused about whether null is a valid clientId. I saw some unit tests that were using that value, but I didn't see anywhere else in the code that was doing it. It's not clear to me what the distinction between a null clientId and an empty one is. If they are just treated interchangeably by the code, maybe what we really need is some code to translate null -> the empty string on the server side. This will help ensure that weird old clients keep working.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The protocol behavior is that null is valid while we use a default empty string so that it's never seen by users. The generated protocol classes definitely change behavior here as it caused a previously passing test to fail with a NPE. I'll share the details with you offline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants