Skip to content

[improve][metadata] Add Option-set API to MetadataStore#25710

Merged
merlimat merged 3 commits into
apache:masterfrom
merlimat:mmerli/metadata-options
May 8, 2026
Merged

[improve][metadata] Add Option-set API to MetadataStore#25710
merlimat merged 3 commits into
apache:masterfrom
merlimat:mmerli/metadata-options

Conversation

@merlimat
Copy link
Copy Markdown
Contributor

@merlimat merlimat commented May 7, 2026

Motivation

The metadata-store API exposes per-operation flags through several disjoint mechanisms that have grown over time:

  • EnumSet<CreateOption> for Ephemeral / Sequential
  • a separate Map<String, String> secondaryIndexes parameter for index hints
  • nothing today for routing hints (PartitionKey) needed by sharded backends like Oxia

Each new flag has been added as an explicit method argument or a new overload, which does not scale. PIP-471 (metadata-driven transactions) needs PartitionKey routing on most read/write methods, which would otherwise require yet another argument across the surface.

Modifications

Introduce a single options bag based on a sealed Option interface and make Set<Option> the canonical form across the metadata API.

API surface (MetadataStore, MetadataStoreExtended, MetadataCache):

  • Option sealed interface with subtypes Ephemeral, Sequential, SecondaryIndex(name, key), PartitionKey(key)
  • OptionsHelper for extracting typed values (isEphemeral, isSequential, secondaryIndexes, partitionKey)
  • Set<Option> form is the abstract canonical method on every read/write entry point (get, getChildren, getChildrenFromStore, exists, put, delete, findByIndex)
  • The legacy no-opts and EnumSet<CreateOption> / Map<String,String> overloads are now defaults that translate into the canonical Set<Option> form — old callers continue to work unchanged

Implementation wiring:

  • AbstractMetadataStore.storePut hook signature flipped to (path, data, version, Set<Option>) — single method, the EnumSet+Map overload is gone
  • LocalMemoryMetadataStore, RocksdbMetadataStore, OxiaMetadataStore (two overloads collapsed into one), and OpPut / AbstractBatchedMetadataStore (used by ZKMetadataStore) all read options via OptionsHelper
  • Wrappers (DualMetadataStore, FaultInjectionMetadataStore, DualMetadataCache) override the canonical Set<Option> methods; legacy callers route through the interface default forwarders

MetadataEvent (sync replication payload) still carries Set<CreateOption>AbstractMetadataStore bridges to/from Set<Option> at the event handler boundary; SecondaryIndex/PartitionKey are not propagated through the legacy event payload, which matches existing behavior.

Verifying this change

This change is already covered by existing tests since it preserves behavior of all current call sites — only the canonical override point moved.

Does this pull request potentially affect one of the following parts:

  • The public API (MetadataStore / MetadataStoreExtended / MetadataCache) — strictly additive: new abstract Set<Option> methods are added; legacy forms become defaults that forward, so existing callers and external implementations are unaffected.

Matching PR in forked repository

PR in forked repository: https://github.com/merlimat/pulsar/pull/new/mmerli/metadata-options

merlimat added 3 commits May 6, 2026 17:39
Introduces a `MetadataStore.Option` sealed interface and a `Set<Option>`-taking
overload on every read/write method (`get`, `getChildren`, `getChildrenFromStore`,
`exists`, `put`, `delete`, `findByIndex` on `MetadataStore`; `put` on
`MetadataStoreExtended` and `MetadataCache`). Existing methods are unchanged;
the new overloads default to the existing forms, so this commit is purely
additive — no callers need to change.

Option subtypes:
- `Ephemeral`, `Sequential` — replace `EnumSet<CreateOption>` flags
- `SecondaryIndex(name, key)` — replaces the `Map<String, String>` argument
- `PartitionKey(key)` — new; routing hint for sharded backends

`OptionsHelper` provides typed accessors (`isEphemeral`, `partitionKey`,
`secondaryIndexes`, ...) for backends and wrappers that need to consult the set.

`MetadataStoreExtended` provides a default override for the new
`put(path, value, version, Set<Option>)` that translates Option entries
back into the legacy `EnumSet<CreateOption>` + `Map<String, String>` form
and calls the existing extended-store put. This keeps every existing
implementation correct without modification.

Phase 1 of a multi-step migration: subsequent PRs wire each backend
to override the new methods natively (Oxia for `PartitionKey` first),
then migrate callers, and eventually remove the legacy forms.
Flip the direction of the Option-set <-> CreateOption translation so that
Set<Option> is the abstract canonical method on every MetadataStore /
MetadataStoreExtended / MetadataCache method, and the legacy no-opts /
EnumSet<CreateOption> overloads are defaults that translate INTO the
canonical form. Also flip the AbstractMetadataStore.storePut backend hook
to take Set<Option> directly and update every backend (LocalMemory,
RocksDB, ZK via OpPut, Oxia) to read options through OptionsHelper.
…ions

# Conflicts:
#	pulsar-metadata/src/main/java/org/apache/pulsar/metadata/api/MetadataStore.java
#	pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/AbstractMetadataStore.java
#	pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/DualMetadataStore.java
#	pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/FaultInjectionMetadataStore.java
#	pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/LocalMemoryMetadataStore.java
#	pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/RocksdbMetadataStore.java
#	pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/oxia/OxiaMetadataStore.java
@lhotari lhotari self-requested a review May 8, 2026 16:49
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 d8a823e into apache:master May 8, 2026
79 of 82 checks passed
@merlimat merlimat deleted the mmerli/metadata-options branch May 8, 2026 17:07
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