Repository navigation
[fix][ml][broker] Keep source ledger data on every shadow managed ledger trim, delete and offload path - #26746
Merged
Conversation
…ger trim, delete and offload path A shadow managed ledger reads the ledgers of its source managed ledger, but those ledgers and any data offloaded from them belong to the source and are managed by the source's lifecycle. Make the remaining managed ledger lifecycle paths (trimming, deletion, offloading and offload-lag trimming) follow this ownership model consistently, and store the shadow source as a persistent property of the shadow managed ledger instead of a config-only value. This also covers shadows deleted while not open or opened without the shadow config, including partitions of partitioned shadow topics created by earlier versions. The PULSAR.SHADOW_SOURCE property can no longer be removed or set to null. Removing it never produced a usable standalone topic: the shadow's metadata still lists the source's ledgers, so after a reload the topic would treat them as its own and could remove them, and the source can trim them at any time. Detaching a shadow topic would need a dedicated operation. - ManagedLedgerImpl: add ownsLedgerData(). When false, trimming keeps the ledgers, asyncOffloadPrefix fails and automatic offloading is a no-op; the PULSAR.SHADOW_SOURCE managed ledger property cannot be removed. - ShadowManagedLedgerImpl: store the shadow source in the managed ledger properties on initialization. - ManagedLedgerFactoryImpl: deleting a managed ledger with a shadow source only removes its metadata. - BrokerService: resolve a partition's shadow source from the partitioned topic metadata when deleting its managed ledger. - Admin API: removing PULSAR.SHADOW_SOURCE or setting it to null returns 412. - PersistentTopic: delete a shadow topic subscription's pending ack store with its own managed ledger config, keeping the topic's storage class and ledger offloader. Assisted-by: Claude Code
lhotari
requested review from
Technoboy-,
dao-jun,
david-streamlio,
merlimat and
nodece
September 29, 2026 12:34
merlimat
approved these changes
Sep 30, 2026
ascentstream-bot
pushed a commit
to ascentstream/pulsar
that referenced
this pull request
Oct 1, 2026
…ger trim, delete and offload path (apache#26746) (cherry picked from commit ac1b975)
ascentstream-bot
pushed a commit
to ascentstream/pulsar
that referenced
this pull request
Oct 2, 2026
…ger trim, delete and offload path (apache#26746) (cherry picked from commit ac1b975)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
A shadow managed ledger reads the ledgers of its source managed ledger, but those ledgers, and any data offloaded from them, belong to the source. The source's own lifecycle manages them. Most shadow code paths already follow this model. This change makes the remaining managed ledger lifecycle paths follow it consistently: trimming, deletion, offloading and offload-lag trimming. It also makes the shadow source a persistent property of the shadow managed ledger instead of a config-only value.
Making the ownership explicit also covers these cases:
Shadow managed ledgers that are deleted while not open, or opened without the shadow config. This includes partitions of partitioned shadow topics created by earlier versions, where the shadow source is recorded only in the partitioned topic metadata.
The
PULSAR.SHADOW_SOURCEproperty, which defines what a shadow topic is. It is kept stable for the lifetime of the topic.Removing the property never turned a shadow topic into a usable standalone topic, and it isn't part of the shadow topic lifecycle in PIP-180 or the admin API. The shadow's managed ledger metadata still lists the source's ledgers, and its cursors point into them. Without the property, the topic reloads as a regular managed ledger that treats those ledgers as its own, so trimming or deleting it would remove ledgers that belong to the source. The source can also trim those ledgers at any time on its own, so reads from such a topic would stop working in any case. That is why the property can no longer be removed or set to
null. Detaching a shadow topic from its source would need a dedicated operation, for example one that drops the source ledgers from the shadow's ledger list, and is out of scope here.Pending ack stores of shadow topic subscriptions. These own their ledgers and are cleaned up with their own managed ledger config.
Modifications
ManagedLedgerImpl: addownsLedgerData(). It returns false when the config or the stored managed ledger properties containPULSAR.SHADOW_SOURCE, and it is always false forShadowManagedLedgerImpl. When a managed ledger does not own its ledger data, trimming keeps the ledgers,asyncOffloadPrefixfails, and automatic offloading is a no-op. ThePULSAR.SHADOW_SOURCEmanaged ledger property cannot be removed.ShadowManagedLedgerImpl: store the shadow source in the managed ledger properties on initialization.ManagedLedgerFactoryImpl: deleting a managed ledger whose stored properties or supplied config contain the shadow source removes only its metadata. The shared metadata removal code is extracted into a helper method.BrokerService: when deleting the managed ledger of a partition, resolve the shadow source from the partitioned topic metadata and pass it in the deletion config.PULSAR.SHADOW_SOURCEtopic property, or setting it tonull, returns 412 Precondition Failed.PersistentTopic: when a subscription of a shadow topic is deleted, delete its pending ack store with the pending ack store's own managed ledger config. It keeps the topic's storage class and ledger offloader, so the offloader that wrote any offloaded pending ack data also cleans it up.Verifying this change
This change added tests and can be verified as follows:
ShadowManagedLedgerImplTest:testShadowTrimmingKeepsSourceLedgers,testShadowDeletionKeepsSourceLedgers,testClosedShadowDeletionKeepsSourceLedgers: trimming or deleting an open or closed shadow managed ledger leaves the source ledgers in place.testShadowReopenedWithoutSourceKeepsSourceLedgers,testExistingManagedLedgerOpenedAsShadowStoresSourceProperty,testShadowWithoutStoredSourcePropertyDeletionKeepsSourceLedgers: the stored property, or the source supplied in the deletion config, is honoured when the shadow config is absent or the metadata was written by an earlier version.testShadowSourcePropertyCannotBeRemoved.testShadowOffloadKeepsSourceOffloadedData,testShadowAutomaticOffloadAndOffloadLagTrimmingKeepSourceData: manual offload, automatic offload and offload-lag trimming leave the source's ledgers and offloaded data in place. The automatic offload test uses a clock set past the source offload timestamp instead of sleeps.ShadowTopicTest:testShadowSourcePropertyCannotBeRemoved,testShadowSourcePropertyCannotBeUpdatedToNull: the admin API returns 412 and the shadow source stays configured.testPartitionedShadowDeletionWithoutStoredSourcePropertyKeepsSourceLedgers: deleting an unloaded partition of a partitioned shadow topic leaves the source ledgers in place.testShadowTopicSubscriptionDeletionDeletesPendingAckStoreLedgers,testShadowTopicSubscriptionDeletionUsesTopicOffloaderForPendingAckStore: pending ack store ledgers are cleaned up, using the topic's offloader.Does this pull request potentially affect one of the following parts:
If the box was checked, please highlight the changes
REST endpoints: removing the
PULSAR.SHADOW_SOURCEtopic property, or setting it tonull, returns 412 Precondition Failed.