Skip to content

[fix][broker] PIP-468: skip deleted segments in checkpoint consumer#25719

Merged
merlimat merged 3 commits into
apache:masterfrom
merlimat:st-v5-checkpoint-skip-deleted
May 8, 2026
Merged

[fix][broker] PIP-468: skip deleted segments in checkpoint consumer#25719
merlimat merged 3 commits into
apache:masterfrom
merlimat:st-v5-checkpoint-skip-deleted

Conversation

@merlimat
Copy link
Copy Markdown
Contributor

@merlimat merlimat commented May 7, 2026

Summary

Segment topics must only be created by the controller's explicit-create path — never auto-created on client connect — so a producer or consumer racing a controller-driven delete (post-prune retention GC, force-delete) can't silently re-create the topic and mask the deletion. Plus, when a checkpoint consumer does observe a missing segment topic, it must silently skip it instead of failing.

  • BrokerService.isAllowAutoTopicCreationAsync now returns false for TopicDomain.segment.
  • ScalableTopics.createScalableTopic materializes the initial segment(s) up front via the admin client (so multi-broker bundle ownership is honored) instead of relying on auto-create-on-publish.
  • Segments.createSegment switched to getTopic(name, true) for explicit creation now that the auto-create policy forbids segments.
  • Segments.deleteSegment actually propagates ?force=true to deleteForcefully() (was being silently dropped).
  • ScalableTopicController.initialize, after winning leadership, idempotently re-creates any active-segment backing topics that are missing — recovering from a createScalableTopic that committed metadata but failed to materialize all initial segments, or an out-of-band force-delete of an active segment. Sealed segments are intentionally not healed: a missing sealed topic means data was retention-pruned, and the V5 checkpoint consumer skips it.
  • ScalableCheckpointConsumer swallows TopicDoesNotExistException / NotFoundException at reader-create and during the read loop, dropping the segment from segmentReaders + lastReceivedPositions so the consumer keeps delivering from segments that still exist.

Test plan

  • New V5CheckpointConsumerSkipDeletedSegmentTest: 2-segment topic, force-delete one, open consumer → must subscribe to survivor and deliver its full backlog. Verified the new Segment backing topic deleted (retention expired); skipping log path actually fires.
  • New ScalableTopicControllerTest.testInitializeRecreatesMissingActiveSegments + testInitializeDoesNotCreateSegmentsWhenNotLeader cover the recovery path.
  • Existing ScalableTopicControllerTest.testSplitSegment / testMergeSegments updated for the new init-time createSegmentAsync calls (clearInvocations).
  • All org.apache.pulsar.client.api.v5.* and org.apache.pulsar.broker.service.scalable.* tests pass.
  • Checkstyle clean.

merlimat added 3 commits May 7, 2026 16:03
Segment topics must only be created by the controller's explicit-create
path — never auto-created on client connect — so a producer or consumer
racing a controller-driven delete (post-prune retention GC, force-delete)
can't silently re-create the topic and mask the deletion.

- BrokerService.isAllowAutoTopicCreationAsync now returns false for
  TopicDomain.segment.
- ScalableTopics.createScalableTopic materializes the initial segment(s)
  up front via the admin client (so multi-broker bundle ownership is
  honored) instead of relying on auto-create-on-publish.
- Segments.createSegment switched to getTopic(name, true) for explicit
  creation now that the auto-create policy forbids segments.
- Segments.deleteSegment actually propagates ?force=true to
  deleteForcefully() (was being silently dropped).
- ScalableCheckpointConsumer swallows TopicDoesNotExistException /
  NotFoundException at reader-create and during the read loop, dropping
  the segment from segmentReaders + lastReceivedPositions so the
  consumer keeps delivering from segments that still exist.
- ScalableTopics / Segments: replace fully-qualified java.util.{ArrayList,
  Optional} with imports.
- ScalableTopicController.initialize: after winning leadership, call
  ensureActiveSegmentsExist() which idempotently re-creates any active
  segments whose backing topics are missing — recovering from a
  createScalableTopic that committed metadata but failed to materialize
  all initial segments, or an out-of-band force-delete of an active
  segment. Sealed segments are intentionally not healed: a missing sealed
  topic means data was retention-pruned, and the V5 checkpoint consumer
  silently skips it.
- ScalableTopicControllerTest: add testInitializeRecreatesMissingActive
  Segments + testInitializeDoesNotCreateSegmentsWhenNotLeader. clear
  Invocations() in testSplitSegment / testMergeSegments so the new
  init-time createSegmentAsync calls don't perturb their existing counts.
@merlimat merlimat requested a review from lhotari May 7, 2026 23:24
Copy link
Copy Markdown
Member

@lhotari lhotari left a comment

Choose a reason for hiding this comment

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

LGTM

@merlimat merlimat merged commit 7f7cc5d into apache:master May 8, 2026
44 checks passed
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.

2 participants