Skip to content

[common] Fix equals/hashCode contract violation in Schema.PrimaryKey#3629

Open
NestDream wants to merge 1 commit into
apache:mainfrom
NestDream:fix-schema-primarykey-hashcode
Open

[common] Fix equals/hashCode contract violation in Schema.PrimaryKey#3629
NestDream wants to merge 1 commit into
apache:mainfrom
NestDream:fix-schema-primarykey-hashcode

Conversation

@NestDream

@NestDream NestDream commented Jul 10, 2026

Copy link
Copy Markdown

Purpose

Linked issue: close #3628

Schema.PrimaryKey.hashCode() folds in super.hashCode() (the Object per-instance hash) while equals() compares only columnNames, so two value-equal primary keys return different hash codes. This violates the Object.equals/hashCode contract and propagates through Schema.hashCode() and the public TableDescriptor, so an equal schema/table descriptor can be missing from a HashSet/HashMap (e.g. after a toJsonBytes/fromJsonBytes round-trip). Standalone reproduction against the released 0.9.1-incubating artifact: https://github.com/NestDream/fluss-pk-hashcode-demo

Brief change log

  • Schema.PrimaryKey.hashCode(): Objects.hash(super.hashCode(), columnNames)Objects.hash(columnNames), matching the field equals() compares and the value-based hashing already used by Schema and Column.

Tests

  • TableSchemaTest#testPrimaryKeySchemaSurvivesJsonRoundTripAsHashKey (unit): round-trips a primary-key schema via toJsonBytes/fromJsonBytes and asserts the reloaded schema hashes equally and is found in a HashSet<Schema>; also asserts two primary keys with equal columns but different constraint names are equal and hash-equal. Fails before the fix, passes after.
  • FlussAdminITCase#testPrimaryKeySchemaReadBackIsUsableAsHashKey (end-to-end): creates a primary-key table via Admin.createTable, reads the schema back via Admin.getTableSchema, and asserts it is usable as a hash key. Fails before the fix, passes after.
  • Existing TableSchemaTest, TableDescriptorTest, SchemaJsonSerdeTest continue to pass (mvn verify -pl fluss-common: 1684 tests, 0 failures).

API and Format

No public API or storage format change. hashCode() is never persisted or transmitted (SchemaJsonSerde writes explicit fields; on-the-wire schema identity is the separate schemaId).

Documentation

No documentation change; behavior-only fix.

  • No generative AI tools used
  • Yes (please specify the tool below)

Assisted by: Claude Code (Fable 5) following the guidelines

Schema.PrimaryKey.equals() compares only the primary-key column names,
but hashCode() folded in super.hashCode() (the Object identity hash).
Two value-equal PrimaryKey instances therefore returned different hash
codes, violating the general contract of Object.hashCode() ("equal
objects must have equal hash codes"). The defect propagates to
Schema.hashCode() and to the public TableDescriptor, which include the
primary key.

Schema and PrimaryKey are public API (@PublicEvolving / @PublicStable),
so any code that puts a schema or table descriptor into a HashSet/HashMap
is affected. This is easy to hit after a schema round-trips through its
JSON form (as Fluss does when it persists a schema to ZooKeeper via
SchemaZNode and reads it back): the reloaded schema is equal() to the
in-memory one but hashes differently, so a hash-based lookup misses it.

Compute hashCode() over columnNames only, matching the field equals()
compares and aligning with the value-based hashing already used by
Schema and Column.

Tests:
- TableSchemaTest#testPrimaryKeySchemaSurvivesJsonRoundTripAsHashKey:
  unit test over the toJsonBytes/fromJsonBytes round-trip; also asserts
  that two primary keys with equal columns but different constraint
  names are equal and hash-equal.
- FlussAdminITCase#testPrimaryKeySchemaReadBackIsUsableAsHashKey:
  end-to-end test that creates a primary-key table via the Admin API and
  asserts the schema read back from the cluster is usable as a hash key.
Both fail before the fix and pass after.

Generated-by: Claude Code (Fable 5) following https://github.com/apache/fluss/blob/main/AGENTS.md
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.

[common] Schema.PrimaryKey violates the equals/hashCode contract

1 participant