Skip to content

[venice-common][controller][compact] Activate StoreMetaValue v44 / AdminOperation v99 + Java accessors#2817

Open
ymuppala wants to merge 2 commits into
linkedin:mainfrom
ymuppala:ymuppala/phase-1-2-external-storage-meta
Open

[venice-common][controller][compact] Activate StoreMetaValue v44 / AdminOperation v99 + Java accessors#2817
ymuppala wants to merge 2 commits into
linkedin:mainfrom
ymuppala:ymuppala/phase-1-2-external-storage-meta

Conversation

@ymuppala
Copy link
Copy Markdown
Collaborator

@ymuppala ymuppala commented May 22, 2026

Problem Statement

Predecessor PR in this stack stages StoreMetaValue v44 and AdminOperation v99 with the following external-storage-related fields:

  • StoreVersion (per-version): storageMode, externalDbName, externalTableName (all newly-added in v44).
  • StoreProperties (per-store): externalStorageReadMode.
  • UpdateStore (admin op): storageMode, externalStorageReadMode, externalDbName, externalTableName (operator-override surface).

build.gradle's versionOverrides list still forces the Avro compiler to use v43 / v98 instead of letting it pick the highest-numeric directory, so v44 / v99 are not yet wire-real. Downstream consumers (Fast Client metadata refresh, controller, server, VPJ producers) need typed Java accessors to start integrating against.

Solution

Drop the versionOverrides entries so the Avro compiler picks the latest schema directories (v44 / v99) naturally — that's exactly the remove-the-override step the comment above versionOverrides describes ("remove the override in a follow-up PR when actually using the new protocol"). Bump AvroProtocolDefinition constants in lockstep so the in-process protocol version matches the compiled schema. Add Java accessors that read/write directly from the now-Avro-backed StoreProperties / StoreVersion records (no transient POJO mirroring), so updates round-trip through ZK / metadata-system-store serialization.

  • build.gradle: remove the versionOverrides entries for StoreMetaValue and AdminOperation. The Avro generator now selects v44 / v99 by the default max-numeric rule.

  • AvroProtocolDefinition: bump constants so the in-process protocol version matches the compiled schema:

    • METADATA_SYSTEM_SCHEMA_STORE: 43 → 44
    • ADMIN_OPERATION: 98 → 99
  • New enums (VeniceEnumValue, EnumUtils-backed valueOf):

    • StorageMode { INTERNAL, DUAL_WRITE, EXTERNAL } — mirrors StoreVersion.storageMode.
    • ExternalStorageReadMode { VENICE_ONLY, DUAL_MODE_CONSISTENCY_CHECK, DUAL_MODE_EARLY_RETURN, EXTERNAL_ONLY } — mirrors StoreProperties.externalStorageReadMode.
  • Store-level Java accessor backed by StoreProperties Avro record:

    • Store.get/setExternalStorageReadModestoreProperties.externalStorageReadMode (int ↔ enum).

Code changes

  • Added new code behind a config. (no.)
  • Introduced new log lines. (no.)

Concurrency-Specific Checks

  • No race conditions: new fields are plain Avro-record fields on the existing storeProperties / storeVersion containers, accessed under the same synchronization invariants as the fields they sit alongside.
  • No new synchronization primitives required.
  • No blocking calls introduced.
  • No new collections; only enum singletons and a primitive-or-enum-or-String field per type.
  • No new threading.

How was this PR tested?

  • New unit tests added: ExternalStorageReadModeTest, StorageModeTest (VeniceEnumValueTest-based int-mapping coverage); new test methods in TestStoreInfo, TestZKStore, TestVersion for defaults / round-trip / clone preservation / null coercion for storageMode, externalStorageReadMode, externalDbName, externalTableName; plus "persists through Avro data model" tests on TestZKStore and TestVersion that read the value back through dataModel() to guard against a regression to transient POJO mirroring.
  • Modified or extended existing tests: yes (TestStoreInfo / TestZKStore / TestVersion).
  • Verified the controller-side createStore admin-op flow no longer NPEs on the new UpdateStore fields (TestVeniceParentHelixAdmin passes locally; previously failed with NPE on externalDbName.toString() during AdminOperationSerializer.write).
  • Verified backward compatibility: the v44 schema is forward-compatible with v43 because the new fields have defaults; downgrading a process that writes v44 records to one that reads v43 records works as long as both sides treat unknown fields as ignorable, which Avro does for record fields with defaults.

Rollout note

Activating the v44 / v99 schemas changes what the controller writes to ZK and what controllers exchange via the admin topic. All Venice services must be redeployed at this version before any caller starts setting storageMode / externalStorageReadMode / externalDbName / externalTableName to non-default values, otherwise a v43-only service performing a read-modify-write could silently drop the new fields.

Does this PR introduce any user-facing or breaking changes?

  • No (defaults preserve existing behavior; new fields are inert until callers opt in).

Copy link
Copy Markdown

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

Adds Java-level surfaces (enums + Store/Version accessors) for staged external-storage-related metadata that is not yet present in the active Avro protocol due to schema pinning, along with unit tests to validate enum int-mappings and field default/clone behavior.

Changes:

  • Introduces new VeniceEnumValue enums: StorageMode, ExternalStorageReadMode, and ExternalTableStatus with EnumUtils-backed int mappings.
  • Extends Store and Version interfaces and wires implementations through ZKStore, SystemStore, ReadOnlyStore, VersionImpl, and StoreInfo (backed by transient POJO fields pending schema-pin bump).
  • Adds/updates unit tests covering enum mappings plus defaulting/round-trip/clone preservation.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/venice-common/src/main/java/com/linkedin/venice/meta/Store.java Adds externalStorageReadMode getter/setter to the Store API.
internal/venice-common/src/main/java/com/linkedin/venice/meta/Version.java Adds external-storage-related accessors to the Version API.
internal/venice-common/src/main/java/com/linkedin/venice/meta/ZKStore.java Implements externalStorageReadMode via transient field; copy constructor propagation.
internal/venice-common/src/main/java/com/linkedin/venice/meta/SystemStore.java Delegates getter to shared store; setter unsupported.
internal/venice-common/src/main/java/com/linkedin/venice/meta/ReadOnlyStore.java Delegates new getters; setters throw UOE for store + version wrappers.
internal/venice-common/src/main/java/com/linkedin/venice/meta/StoreInfo.java Adds JSON surface + (de)faulting for externalStorageReadMode; populates from Store.
internal/venice-common/src/main/java/com/linkedin/venice/meta/VersionImpl.java Implements new Version fields via transient members; clones propagate values.
internal/venice-common/src/main/java/com/linkedin/venice/meta/StorageMode.java New enum with int mapping for per-version storage mode.
internal/venice-common/src/main/java/com/linkedin/venice/meta/ExternalStorageReadMode.java New enum with int mapping for store-level read routing mode.
internal/venice-common/src/main/java/com/linkedin/venice/meta/ExternalTableStatus.java New enum with int mapping for external table lifecycle status.
internal/venice-common/src/test/java/com/linkedin/venice/meta/TestZKStore.java Adds tests for default/round-trip/clone behavior of externalStorageReadMode.
internal/venice-common/src/test/java/com/linkedin/venice/meta/TestVersion.java Adds tests for default/round-trip/clone behavior of new Version fields.
internal/venice-common/src/test/java/com/linkedin/venice/meta/TestStoreInfo.java Adds tests for StoreInfo default/round-trip/null-coercion behavior.
internal/venice-common/src/test/java/com/linkedin/venice/meta/StorageModeTest.java Adds enum mapping test coverage.
internal/venice-common/src/test/java/com/linkedin/venice/meta/ExternalStorageReadModeTest.java Adds enum mapping test coverage.
internal/venice-common/src/test/java/com/linkedin/venice/meta/ExternalTableStatusTest.java Adds enum mapping test coverage.

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

Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/Version.java Outdated
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from ac66500 to 0b262c7 Compare May 22, 2026 16:14
Copilot AI review requested due to automatic review settings May 22, 2026 16:30
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 0b262c7 to 6208020 Compare May 22, 2026 16:30
Copy link
Copy Markdown

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 14 out of 14 changed files in this pull request and generated 4 comments.

Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/ZKStore.java Outdated
Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/ZKStore.java Outdated
Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/VersionImpl.java Outdated
Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/VersionImpl.java Outdated
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch 2 times, most recently from 27fe66b to 52697d1 Compare May 22, 2026 17:46
Copilot AI review requested due to automatic review settings May 22, 2026 18:58
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 52697d1 to 35b9c41 Compare May 22, 2026 18:58
Copy link
Copy Markdown

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 16 out of 17 changed files in this pull request and generated 3 comments.

@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 35b9c41 to 6becf52 Compare May 22, 2026 20:03
Copilot AI review requested due to automatic review settings May 22, 2026 20:51
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 6becf52 to 47c0a43 Compare May 22, 2026 20:51
@ymuppala ymuppala changed the title [venice-common][protocol] Java accessors for storageMode + externalStorageReadMode + external-table identity [venice-common][protocol] Activate StoreMetaValue v44 / AdminOperation v99 + Java accessors May 22, 2026
Copy link
Copy Markdown

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 17 out of 18 changed files in this pull request and generated 3 comments.

@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 47c0a43 to 68d06c5 Compare May 22, 2026 21:02
Copilot AI review requested due to automatic review settings May 22, 2026 21:23
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 68d06c5 to 71e2c80 Compare May 22, 2026 21:23
Copy link
Copy Markdown

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 17 out of 18 changed files in this pull request and generated 2 comments.

Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/ZKStore.java Outdated
Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/VersionImpl.java Outdated
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 71e2c80 to 10d4365 Compare May 22, 2026 22:06
@ymuppala ymuppala changed the title [venice-common][protocol] Activate StoreMetaValue v44 / AdminOperation v99 + Java accessors [venice-common][controller][protocol] Activate StoreMetaValue v44 / AdminOperation v99 + Java accessors May 22, 2026
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from d7d0a99 to 06a562a Compare May 22, 2026 22:30
Copy link
Copy Markdown

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 18 out of 19 changed files in this pull request and generated 1 comment.

@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from 06a562a to c9d3be4 Compare May 22, 2026 22:49
Copilot AI review requested due to automatic review settings May 22, 2026 23:01
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from c9d3be4 to fc79d45 Compare May 22, 2026 23:01
Copy link
Copy Markdown

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 17 out of 18 changed files in this pull request and generated 2 comments.

Comment thread internal/venice-common/src/main/java/com/linkedin/venice/meta/Version.java Outdated
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from fc79d45 to d3d1dc7 Compare May 22, 2026 23:12
Copilot AI review requested due to automatic review settings May 23, 2026 00:59
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from d3d1dc7 to e415893 Compare May 23, 2026 00:59
Copy link
Copy Markdown

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 15 out of 16 changed files in this pull request and generated 3 comments.

@sixpluszero sixpluszero changed the title [venice-common][controller][protocol] Activate StoreMetaValue v44 / AdminOperation v99 + Java accessors [venice-common][controller][compact] Activate StoreMetaValue v44 / AdminOperation v99 + Java accessors May 23, 2026
@sixpluszero sixpluszero requested a review from Copilot May 23, 2026 01:38
Copy link
Copy Markdown

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 15 out of 16 changed files in this pull request and generated no new comments.

sixpluszero
sixpluszero previously approved these changes May 23, 2026
Copy link
Copy Markdown
Contributor

@sixpluszero sixpluszero left a comment

Choose a reason for hiding this comment

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

Note for others: this is only store r/w accessor. Not controller changes. Controller changes will be pumped in in other PR.

sixpluszero added a commit to sixpluszero/venice that referenced this pull request May 23, 2026
… copy to

new versions at creation

The previous implementation in this PR applied UpdateStore.storageMode by
iterating store.getVersions() and calling setStorageMode on every Version,
which (a) violates the schema doc that says "existing versions are unaffected"
and (b) throws UnsupportedOperationException at runtime because
ZKStore.getVersions() returns ReadOnlyVersion wrappers.

Switch to the schema-doc semantics: UpdateStore.storageMode is a store-level
default; existing StoreVersion records stay untouched; new versions inherit
the current default at creation time.

- v44 StoreMetaValue StoreProperties: add storageMode (int, default 0)
  alongside externalStorageReadMode. v44 is not yet in production (still
  staged by PR linkedin#2817's versionOverrides removal), so amending it in place
  is safer than bumping to v45.
- Store interface: add getStorageMode / setStorageMode at the store level
  (distinct from the per-version Version.getStorageMode/setStorageMode
  added by PR linkedin#2817). ZKStore wires both to the new
  storeProperties.storageMode Avro field; ReadOnlyStore delegates the
  getter and throws UOE on the setter; SystemStore delegates to
  zkSharedStore and throws on the setter; StoreInfo.fromStore mirrors the
  field for JSON. ZKStore copy constructor propagates store-level
  storageMode like every other store-level field.
- VeniceHelixAdmin.internalUpdateStore: storageMode.ifPresent now applies
  store.setStorageMode(mode) only -- no version iteration -- so the
  ReadOnlyVersion UOE from the prior commit is gone.
- AbstractStore.addVersion (the !isClonedVersion branch that seeds
  compressionStrategy/chunkingEnabled/blobDbEnabled/... on a new version)
  also seeds version.setStorageMode(getStorageMode()). New pushes pick up
  the current store-level default; existing versions are never
  retroactively rewritten.

- TestZKStore: store-level storageMode default / round-trip / clone
  preservation / "persists through Avro data model" tests, plus an
  addVersion test that confirms (a) a freshly added version inherits the
  store-level default at creation time and (b) a later store-level change
  does NOT mutate the previously-added version.
- TestUpdateStoreExternalStorage (integration): reworked to match the
  store-level semantics: assert UpdateStore propagates the store-level
  default to all child regions, v1 (created before the update) stays at
  INTERNAL, a subsequent empty-push creates v2 which inherits the new
  default. The regions-filter test now asserts dc0 receives the store-level
  update while dc1 stays at the schema defaults.

- New code behind a config: no.
- New log lines: no.

- No race conditions: storageMode is a plain int on the existing
  storeProperties record, accessed under the same locks as every other
  store-level field.

- v44 schema gains a new field with default 0, so v43 readers still parse
  v44 records (unknown field ignored). All Venice services must be
  redeployed at this version before any caller starts setting non-default
  storageMode, since a v43-only service performing a read-modify-write
  could silently drop the new field.

- No (defaults preserve existing behavior).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from e415893 to bd5d0bc Compare May 23, 2026 22:49
…dminOperation v99 + Java accessors

Predecessor PR (the schema PR in this stack) stages StoreMetaValue v44 and
AdminOperation v99 with these external-storage-related fields:

  * StoreVersion: storageMode, externalDbName, externalTableName (per-version,
    all newly-added in v44).
  * StoreProperties: externalStorageReadMode (store-level, per-store).
  * UpdateStore (admin op): storageMode, externalStorageReadMode,
    externalDbName, externalTableName (mirrors for operator-override).

build.gradle's `versionOverrides` list still forces the Avro compiler to use
v43 / v98 instead of letting it pick the highest-numeric directory, so v44 /
v99 are not yet wire-real. Downstream consumers (Fast Client metadata
refresh, controller, server, VPJ producers) need typed Java accessors to
start integrating against.

Drop the `versionOverrides` entries so the Avro compiler picks the latest
schema directories (v44 / v99) naturally — that's exactly the
remove-the-override step the comment above `versionOverrides` describes
("remove the override in a follow-up PR when actually using the new
protocol"). Bump `AvroProtocolDefinition` constants in lockstep so the
in-process protocol version matches the compiled schema. Add Java accessors
that read/write directly from the now-Avro-backed `StoreProperties` /
`StoreVersion` records (no transient POJO mirroring), so updates round-trip
through ZK / metadata-system-store serialization.

- `build.gradle`: remove the `versionOverrides` entries for StoreMetaValue
  and AdminOperation. The Avro generator now selects v44 / v99 by the
  default max-numeric rule.
- `AvroProtocolDefinition`: bump constants
  (`METADATA_SYSTEM_SCHEMA_STORE` 43 -> 44; `ADMIN_OPERATION` 98 -> 99)
  so the in-process protocol version matches the compiled schema.

- New enums (`VeniceEnumValue`, `EnumUtils`-backed `valueOf`):
  * `StorageMode { INTERNAL, DUAL_WRITE, EXTERNAL }` — mirrors
    `StoreVersion.storageMode`.
  * `ExternalStorageReadMode { VENICE_ONLY, DUAL_MODE_CONSISTENCY_CHECK,
    DUAL_MODE_EARLY_RETURN, EXTERNAL_ONLY }` — mirrors
    `StoreProperties.externalStorageReadMode`.

- Store-level Java accessor backed by `StoreProperties` Avro record:
  * `Store.get/setExternalStorageReadMode` → `storeProperties.externalStorageReadMode`.

  Implemented on `ZKStore` (int <-> enum). `ReadOnlyStore` delegates the
  getter and throws UOE on the setter; `SystemStore` does the same via its
  existing `throwUnsupportedOperationException` helper. `StoreInfo.fromStore`
  mirrors the field for JSON.

- Version-level Java accessors backed by `StoreVersion` Avro record:
  * `Version.get/setStorageMode` → `storeVersion.storageMode` (int <-> enum).
  * `Version.get/setExternalDbName` → `storeVersion.externalDbName`
    (null-coerces to "NOT_SPECIFIED", the schema default).
  * `Version.get/setExternalTableName` → `storeVersion.externalTableName`
    (null-coerces to "NOT_SPECIFIED", the schema default).

  Implemented on `VersionImpl`; `cloneVersion` propagates all three through
  the Avro-record copy. `ReadOnlyVersion` delegates getters and throws UOE
  on setters.

- `AdminMessageType.UPDATE_STORE.getNewInstance()` initializes the two new
  `UpdateStore` string fields (externalDbName, externalTableName) to "" at
  construction so the Avro generic writer does not NPE on null values. The
  Avro schema default for these fields on UpdateStore is "" (the "no-op for
  this admin op" sentinel), which is only applied at deserialization time;
  explicit initialization is required so existing controller code paths
  that call `getNewInstance()` and then conditionally set fields can
  serialize the result without populating every new field.

- [ ] Added new code behind a config. (no.)
- [ ] Introduced new log lines. (no.)

- [x] No race conditions: new fields are plain Avro-record fields on the
      existing storeProperties / storeVersion containers, accessed under
      the same synchronization invariants as the fields they sit alongside.
- [x] No new synchronization primitives required.
- [x] No blocking calls introduced.
- [x] No new collections; only enum singletons and a primitive-or-enum-or-String
      field per type.
- [x] No new threading.

- [x] New unit tests added: `ExternalStorageReadModeTest`, `StorageModeTest`
      (`VeniceEnumValueTest`-based int-mapping coverage); new test methods
      in `TestStoreInfo`, `TestZKStore`, `TestVersion` for defaults /
      round-trip / clone preservation / null coercion for storageMode,
      externalStorageReadMode, externalDbName, externalTableName; plus
      "persists through Avro data model" tests on `TestZKStore` and
      `TestVersion` that read the value back through `dataModel()` to
      guard against a regression to transient POJO mirroring.
- [x] Modified or extended existing tests: yes (`TestStoreInfo` /
      `TestZKStore` / `TestVersion`).
- [x] Verified the controller-side createStore admin-op flow no longer
      NPEs on the new UpdateStore fields (TestVeniceParentHelixAdmin
      passes locally; previously failed with NPE on
      `externalDbName.toString()` during AdminOperationSerializer write).
- [x] Verified backward compatibility: the v44 schema is forward-compatible
      with v43 because the new fields have defaults; downgrading a process
      that writes v44 records to one that reads v43 records works as long
      as both sides treat unknown fields as ignorable, which Avro does for
      record fields with defaults.

Activating the v44 / v99 schemas changes what the controller writes to ZK
and what controllers exchange via the admin topic. All Venice services
must be redeployed at this version before any caller starts setting
`storageMode` / `externalStorageReadMode` / `externalDbName` /
`externalTableName` to non-default values, otherwise a v43-only service
performing a read-modify-write could silently drop the new fields.

- [x] No (defaults preserve existing behavior; new fields are inert until
      callers opt in).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ymuppala ymuppala force-pushed the ymuppala/phase-1-2-external-storage-meta branch from bd5d0bc to 620b46b Compare May 23, 2026 22:55
Copilot AI review requested due to automatic review settings May 24, 2026 03:25
Copy link
Copy Markdown

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 15 out of 16 changed files in this pull request and generated no new comments.

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