[improve][broker] PIP-473: transaction metadata data layer#25754
Merged
Conversation
Introduce schema-versioned JSON records (TxnHeader, TxnOp, TxnEvent, Versioned), path/index constants (TxnPaths), and a typed TxnMetadataStore façade over MetadataStore covering: header CAS, op-log append with kind- specific secondary indexes, deadline / final-state range queries, and per-segment and per-(segment, subscription) event publish + subscribe via SequenceKeysDeltas + subscribeSequence. Bundled metadata-layer fix: the synthesized "__seq_counter__" sidecar that backs SequenceKeysDeltas on non-native stores was leaking through scanChildren and the scanByIndex fallback. Filter it out in the abstract fallback plus the Memory and RocksDB native overrides (Oxia is unaffected — its sequence keys are native and have no sidecar). Regression test covers all five backends.
- Drop @JsonInclude(NON_NULL) from records — already in the global ObjectMapperFactory config. - Drop premature schema versioning (version field + CURRENT_VERSION). Will be added back if/when an incompatible change is required. - Replace TxnState and TxnOpKind constant classes with enums; Jackson serializes them by name so the wire format is unchanged. - TxnHeader: use Duration for timeout and Instant for createdAt / finalizedAt so units are obvious at the type level. - TxnMetadataStore: don't cache the ObjectMapper in a static — go through ObjectMapperFactory.getMapper() on each call so any future thread-local routing works as intended.
Member
|
Claude Code review findings to check: |
lhotari
approved these changes
May 12, 2026
Member
lhotari
left a comment
There was a problem hiding this comment.
LGTM, just check the local Claude Code review findings I added a comment
…car filter Two findings from Claude Code review (via @lhotari): 1. TxnPaths embedded raw segment URIs (which contain "://" and "/") directly into metadata-store paths. ZooKeeper's PathUtils.validatePath rejects that shape, and concatenating segment + sub into a composite key with ":" as the separator was ambiguous because segment names themselves contain ":". Fix: URL-encode the segment and subscription components everywhere they appear as a path component, partition key, or index value — same convention as MLPendingAckStore and TopicTransactionBuffer. TxnOp / TxnEvent JSON payloads keep the raw form (they're data, not keys). Test segment names switched to realistic "segment://tenant/ns/topic/..." so we actually exercise the encoding. 2. isSequenceCounterChild used a permissive String.endsWith match — a user record whose final path segment ends in the literal "__seq_counter__" would be silently filtered. Documenting that this is intentional: the suffix is a 16-character internal marker, the cost of a false positive is dropping that record from scanChildren/scanByIndex (no data loss), and a strict check would require either tracking active prefixes or reserving a delimiter that path backends forbid.
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.
Summary
Foundation data layer for PIP-473 (metadata-driven transactions). Introduces typed records + path/index constants + a
TxnMetadataStorefaçade overMetadataStore, ready for the v5 TC to plug into in a follow-up.pulsar-broker/.../transaction/metadata/:TxnHeader— header at/txn/<txnId>, the CAS linearization point forendTxnTxnOp— op-log entry written under/txn-op/<txnId>withSequenceKeysDeltasTxnEvent— per-segment / per-(segment, sub) notification eventVersioned<T>—(value, version)pair returned from reads so callers can CASTxnState,TxnOpKind— Jackson-friendly enums (serialized by name)TxnPaths— path templates, index names, key formattersTxnMetadataStorefaçade — header CRUD with CAS, op append with kind-specific secondary indexes, deadline / final-state range queries (viascanByIndex), and segment / subscription event publish + subscribe (viasubscribeSequence)__seq_counter__sidecar that backsSequenceKeysDeltason non-native stores was leaking throughscanChildrenand thescanByIndexfallback. Filter it out inAbstractMetadataStore's defaults plus the Memory and RocksDB native overrides. Oxia uses native sequence keys (no sidecar) and is unaffected.No runtime path consumes this yet — the v5 TC PR will wire it up.
Test plan
pulsar-broker:test --tests TxnMetadataStoreTest— 7 tests on Memory: header CAS lifecycle, write/ack op append + index scan, deadline range scan (filters terminal + out-of-range), final-state range scan, segment + subscription event publish + subscribepulsar-metadata:test --tests MetadataStoreScanChildrenTest— addedskipsSequenceCounterSidecarsacross ZooKeeper / Memory / RocksDB / Oxia / MockZooKeeperpulsar-metadata:test --tests SequenceKeysTest+MetadataStoreSecondaryIndexTest— pre-existing suites still green after the abstract-layer changepulsar-broker+pulsar-metadata