Skip to content

feat(inkless): Introduce CREATE_TOPICS config interceptor framework and DisklessForceCreateTopicInterceptor#614

Merged
giuseppelillo merged 4 commits into
mainfrom
tvainika/create-topics-interceptors
May 29, 2026
Merged

feat(inkless): Introduce CREATE_TOPICS config interceptor framework and DisklessForceCreateTopicInterceptor#614
giuseppelillo merged 4 commits into
mainfrom
tvainika/create-topics-interceptors

Conversation

@tvainika
Copy link
Copy Markdown
Member

Introduce CREATE_TOPICS config interceptor framework and DisklessForceCreateTopicInterceptor

Summary

Introduce a generic interceptor framework for mutating topic configs during CREATE_TOPICS API requests, then use it to add a new diskless force interceptor.

Motivation

ClassicTopicRemoteStorageForcePolicy was implemented to automatically set remote.storage.enable=true on topic creation. For Diskless-enabled-by-default, we need a similar mechanism that forces diskless.enable=true. Rather than adding another one-off policy, this PR refactors the approach into a generic, chainable interceptor pattern.

Changes

Commit 1: Interceptor framework

  • CreateTopicConfigInterceptor — interface with intercept() methods returning boolean (true = matched)
  • CreateTopicConfigInterceptors — container that chains interceptors with first-match-wins semantics
  • Refactored ClassicTopicRemoteStorageForcePolicyClassicTopicRemoteStorageForceCreateTopicInterceptor
  • Updated ReplicationControlManager to use the new abstraction

Commit 2: Diskless force interceptor

  • DisklessForceCreateTopicInterceptor — forces diskless.enable=true for topics matching an allow-list of regexes
  • Excludes system topics, compacted topics, and topics with __ prefix
  • Chained with higher priority than the classic remote storage interceptor
  • Both interceptors can be enabled simultaneously (users configure regexes to avoid overlap)

New configs

Config Type Default Description
diskless.force.enable boolean false Enable the diskless force interceptor
diskless.force.include.topic.regexes list [] Allow-list of regexes; matching topics get diskless.enable=true

Example configuration

# Enable both interceptors
classic.remote.storage.force.enable=true
classic.remote.storage.force.exclude.topic.regexes=diskless-.*

diskless.force.enable=true
diskless.force.include.topic.regexes=diskless-.*

Testing

  • Unit tests for DisklessForceCreateTopicInterceptor (regex matching, exclusions, __ prefix skip)
  • Unit tests for CreateTopicConfigInterceptors (chaining, first-match-wins, empty chain)
  • Existing ClassicTopicRemoteStorageForceCreateTopicInterceptorTest continues to pass

@tvainika tvainika changed the title Introduce CREATE_TOPICS config interceptor framework and DisklessForceCreateTopicInterceptor feat(inkless): Introduce CREATE_TOPICS config interceptor framework and DisklessForceCreateTopicInterceptor May 27, 2026
@tvainika tvainika marked this pull request as ready for review May 28, 2026 08:35
@tvainika tvainika requested a review from giuseppelillo May 28, 2026 08:35
@giuseppelillo giuseppelillo requested a review from Copilot May 28, 2026 14:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a chainable interceptor framework for mutating topic configs during CREATE_TOPICS requests, and uses it to implement a new diskless “force enable” behavior (regex allow-list), while refactoring the existing classic remote-storage forcing logic into the same framework.

Changes:

  • Added CreateTopicConfigInterceptor + CreateTopicConfigInterceptors (first-match-wins chain) and integrated it into ReplicationControlManager’s topic-creation flow.
  • Refactored classic remote storage forcing into ClassicTopicRemoteStorageForceCreateTopicInterceptor.
  • Added DisklessForceCreateTopicInterceptor with new server configs (diskless.force.enable, diskless.force.include.topic.regexes) plus unit tests.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
server-common/src/main/java/org/apache/kafka/server/config/ServerConfigs.java Adds new controller/server configs for enabling diskless forcing and defining the allow-list regexes.
core/src/main/scala/kafka/server/KafkaConfig.scala Wires new diskless force configs into KafkaConfig.
core/src/main/scala/kafka/server/ControllerServer.scala Passes diskless force settings into the controller builder.
metadata/src/main/java/org/apache/kafka/controller/QuorumController.java Threads diskless force config through QuorumControllerReplicationControlManager.
metadata/src/main/java/org/apache/kafka/controller/ReplicationControlManager.java Replaces the old policy call-sites with interceptor-chain application during create-topics processing/validation/response building.
metadata/src/main/java/org/apache/kafka/controller/CreateTopicConfigInterceptor.java Introduces the interceptor interface used for CREATE_TOPICS config mutation.
metadata/src/main/java/org/apache/kafka/controller/CreateTopicConfigInterceptors.java Implements chaining + ordering (diskless first, then remote storage) with first-match-wins semantics.
metadata/src/main/java/org/apache/kafka/controller/DisklessForceCreateTopicInterceptor.java New interceptor that forces diskless.enable=true for allow-listed topics with exclusions.
metadata/src/main/java/org/apache/kafka/controller/ClassicTopicRemoteStorageForceCreateTopicInterceptor.java Refactors classic remote storage forcing into the new interceptor model.
metadata/src/test/java/org/apache/kafka/controller/CreateTopicConfigInterceptorsTest.java Adds unit tests for chaining behavior and priority.
metadata/src/test/java/org/apache/kafka/controller/DisklessForceCreateTopicInterceptorTest.java Adds unit tests for diskless forcing, exclusions, and __ prefix behavior.
metadata/src/test/java/org/apache/kafka/controller/ClassicTopicRemoteStorageForceCreateTopicInterceptorTest.java Updates tests to reflect the refactor from policy to interceptor.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

tvainika and others added 3 commits May 29, 2026 10:22
Implement a generic way to intercept and mutate CREATE_TOPICS configs
via a chain of interceptors with first-match-wins semantics.

- Add CreateTopicConfigInterceptor interface (returns boolean to
  indicate whether it matched)
- Add CreateTopicConfigInterceptors container that chains interceptors
  and stops at the first match
- Refactor ClassicTopicRemoteStorageForcePolicy into
  ClassicTopicRemoteStorageForceCreateTopicInterceptor implementing
  the new interface
- Update ReplicationControlManager to use the new abstraction

The interceptor chain is designed so that additional interceptors
(e.g. diskless force) can be added with clear priority ordering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce a new CREATE_TOPICS config interceptor that forces
diskless.enable=true for topics matching a configurable allow list
of regexes.

Behavior:
- Forces diskless.enable=true when topic name matches at least one
  regex in diskless.force.include.topic.regexes
- Excludes system topics (ReplicationControlManager.isSystemTopic)
- Excludes compacted topics (cleanup.policy contains "compact")
- Validates at construction that regexes cannot match "__"-prefixed names

Interceptor chaining:
- DisklessForceCreateTopicInterceptor has higher priority (tried first)
- ClassicTopicRemoteStorageForceCreateTopicInterceptor is tried only if
  diskless interceptor did not match (first-match-wins semantics)
- Both can be enabled simultaneously; users should configure regexes to
  avoid overlap

New configs:
- diskless.force.enable (boolean, default false)
- diskless.force.include.topic.regexes (list, default empty)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…erceptor

The diskless force interceptor is now only activated when the
system-level diskless storage is enabled (diskless.storage.system.enable=true).

If diskless.force.enable=true but system-level diskless is not enabled,
a warning is logged and the interceptor is not added to the chain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tvainika tvainika force-pushed the tvainika/create-topics-interceptors branch from 0b8370a to 6ccb30a Compare May 29, 2026 07:29
@tvainika tvainika requested a review from Copilot May 29, 2026 07:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@giuseppelillo giuseppelillo merged commit 9db5135 into main May 29, 2026
4 checks passed
@giuseppelillo giuseppelillo deleted the tvainika/create-topics-interceptors branch May 29, 2026 08:44
tvainika pushed a commit that referenced this pull request May 29, 2026
… regexes (#622)

The diskless.force.include.topic.regexes LIST config added in #614 was
missing a case in testFromPropsInvalid(), causing the nightly CI to fail
when the catch-all tested "not_a_number" (valid for a list type).
Also adds KafkaConfigTest to the regular Inkless PR CI workflow.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
giuseppelillo pushed a commit that referenced this pull request May 29, 2026
…nd DisklessForceCreateTopicInterceptor (#614)

* Introduce CREATE_TOPICS config interceptor framework

Implement a generic way to intercept and mutate CREATE_TOPICS configs
via a chain of interceptors with first-match-wins semantics.

- Add CreateTopicConfigInterceptor interface (returns boolean to
  indicate whether it matched)
- Add CreateTopicConfigInterceptors container that chains interceptors
  and stops at the first match
- Refactor ClassicTopicRemoteStorageForcePolicy into
  ClassicTopicRemoteStorageForceCreateTopicInterceptor implementing
  the new interface
- Update ReplicationControlManager to use the new abstraction

The interceptor chain is designed so that additional interceptors
(e.g. diskless force) can be added with clear priority ordering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add DisklessForceCreateTopicInterceptor

Introduce a new CREATE_TOPICS config interceptor that forces
diskless.enable=true for topics matching a configurable allow list
of regexes.

Behavior:
- Forces diskless.enable=true when topic name matches at least one
  regex in diskless.force.include.topic.regexes
- Excludes system topics (ReplicationControlManager.isSystemTopic)
- Excludes compacted topics (cleanup.policy contains "compact")
- Validates at construction that regexes cannot match "__"-prefixed names

Interceptor chaining:
- DisklessForceCreateTopicInterceptor has higher priority (tried first)
- ClassicTopicRemoteStorageForceCreateTopicInterceptor is tried only if
  diskless interceptor did not match (first-match-wins semantics)
- Both can be enabled simultaneously; users should configure regexes to
  avoid overlap

New configs:
- diskless.force.enable (boolean, default false)
- diskless.force.include.topic.regexes (list, default empty)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Require system-level diskless to activate DisklessForceCreateTopicInterceptor

The diskless force interceptor is now only activated when the
system-level diskless storage is enabled (diskless.storage.system.enable=true).

If diskless.force.enable=true but system-level diskless is not enabled,
a warning is logged and the interceptor is not added to the chain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Document "__" prefix exclusion

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
giuseppelillo pushed a commit that referenced this pull request May 29, 2026
… regexes (#622)

The diskless.force.include.topic.regexes LIST config added in #614 was
missing a case in testFromPropsInvalid(), causing the nightly CI to fail
when the catch-all tested "not_a_number" (valid for a list type).
Also adds KafkaConfigTest to the regular Inkless PR CI workflow.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
giuseppelillo pushed a commit that referenced this pull request May 29, 2026
…nd DisklessForceCreateTopicInterceptor (#614)

* Introduce CREATE_TOPICS config interceptor framework

Implement a generic way to intercept and mutate CREATE_TOPICS configs
via a chain of interceptors with first-match-wins semantics.

- Add CreateTopicConfigInterceptor interface (returns boolean to
  indicate whether it matched)
- Add CreateTopicConfigInterceptors container that chains interceptors
  and stops at the first match
- Refactor ClassicTopicRemoteStorageForcePolicy into
  ClassicTopicRemoteStorageForceCreateTopicInterceptor implementing
  the new interface
- Update ReplicationControlManager to use the new abstraction

The interceptor chain is designed so that additional interceptors
(e.g. diskless force) can be added with clear priority ordering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add DisklessForceCreateTopicInterceptor

Introduce a new CREATE_TOPICS config interceptor that forces
diskless.enable=true for topics matching a configurable allow list
of regexes.

Behavior:
- Forces diskless.enable=true when topic name matches at least one
  regex in diskless.force.include.topic.regexes
- Excludes system topics (ReplicationControlManager.isSystemTopic)
- Excludes compacted topics (cleanup.policy contains "compact")
- Validates at construction that regexes cannot match "__"-prefixed names

Interceptor chaining:
- DisklessForceCreateTopicInterceptor has higher priority (tried first)
- ClassicTopicRemoteStorageForceCreateTopicInterceptor is tried only if
  diskless interceptor did not match (first-match-wins semantics)
- Both can be enabled simultaneously; users should configure regexes to
  avoid overlap

New configs:
- diskless.force.enable (boolean, default false)
- diskless.force.include.topic.regexes (list, default empty)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Require system-level diskless to activate DisklessForceCreateTopicInterceptor

The diskless force interceptor is now only activated when the
system-level diskless storage is enabled (diskless.storage.system.enable=true).

If diskless.force.enable=true but system-level diskless is not enabled,
a warning is logged and the interceptor is not added to the chain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Document "__" prefix exclusion

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
giuseppelillo pushed a commit that referenced this pull request May 29, 2026
… regexes (#622)

The diskless.force.include.topic.regexes LIST config added in #614 was
missing a case in testFromPropsInvalid(), causing the nightly CI to fail
when the catch-all tested "not_a_number" (valid for a list type).
Also adds KafkaConfigTest to the regular Inkless PR CI workflow.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

3 participants