Skip to content

AoD tuple sketch: zero seed hash for empty compact images, ignored on read - #789

Merged
leerho merged 2 commits into
mainfrom
aod-empty-seed-hash
Nov 3, 2026
Merged

leerho merged 2 commits into
mainfrom
aod-empty-seed-hash

Conversation

@leerho

@leerho leerho commented Nov 1, 2026

Copy link
Copy Markdown
Member

An empty compact ArrayOfDoubles (AoD) image now carries a zero seed hash, and readers ignore those bytes on an empty image. This aligns AoD with Java Theta, with the generic tuple sketch (#772), and with C++ (datasketches-cpp c11a5ea), which already writes a zero seed hash for an empty compact tuple sketch.

Changes

  • Write: HeapArrayOfDoublesCompactSketch and DirectArrayOfDoublesCompactSketch write a zero seed hash when the sketch is empty.
  • Read: heapify and wrap check the seed hash only for a non-empty image, so historical empty images that filled the field in still load.
  • Set operations: ArrayOfDoublesUnion, ArrayOfDoublesIntersection and ArrayOfDoublesAnotBImpl skip the seed-hash check for an empty input, as the Theta set operations do. A-not-B takes its seed hash from whichever input is non-empty.

Why

Java rejected every empty AoD image written by C++ (and so by Python) with Incompatible Seed Hashes. 0, 93cc. AodSketchCrossLanguageTest.checkCpp has been a known failure because of this; it passes with this change.

Compatibility

Release 9.0.0 and earlier check the seed hash of an empty AoD image, so they reject an empty compact AoD image written by this version, just as they reject the C++ ones today. Non-empty AoD images are unchanged. This will be called out in the 9.1.0 release notes.

Testing

  • New tests in HeapArrayOfDoublesCompactSketchTest cover the zero seed hash on write, ignoring it on read, and reading a historical empty image with a filled-in seed hash. The union, intersection and A-not-B tests cover empty inputs.
  • mvn verify: 2321 tests, 0 failures.
  • AodSketchCrossLanguageTest.checkCpp against the current C++ files: fails on main, passes with this change.

🤖 Generated with Claude Code

Follow what Java theta does: an empty compact ArrayOfDoubles image carries
a zero seed hash, and readers ignore those bytes on an empty image, so
historical images that filled them in still load. Set operations skip the
seed-hash check for empty inputs, as the theta set operations do.

C++ already writes a zero seed hash for an empty compact tuple sketch
(datasketches-cpp c11a5ea), which Java rejected in
AodSketchCrossLanguageTest.checkCpp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@leerho
leerho requested review from proost and tisonkun November 1, 2026 20:17
Util.checkSeedHashes(seedHash_, Util.computeSeedHash(seed));
isEmpty_ = (seg.get(JAVA_BYTE, FLAGS_BYTE) & (1 << Flags.IS_EMPTY.ordinal())) != 0;
// the seed hash of an empty image is ignored; historical images may have filled it in
if (!isEmpty_) { Util.checkSeedHashes(seedHash_, Util.computeSeedHash(seed)); }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To protect from corrupted input, can you change to (!isEmpty_ | hasEntries)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch, thanks. Done in both the heap and direct readers (f63e080): the seed hash is now checked when the image is non-empty or has entries, so a corrupt image that claims to be empty but carries entries can't skip the check. Added a test with such a corrupt image. This is also a little stricter than C++, which checks when has-entries is set.

…tries

An image is skipped by the seed hash check only when it is empty and has no
entries. A corrupt image that sets both the empty and has-entries flags is
still checked, so its entries can't bypass the check. Applies to the heap
and direct readers. As suggested in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@leerho
leerho requested a review from proost November 2, 2026 18:17

@proost proost left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

@leerho
leerho merged commit 0434495 into main Nov 3, 2026
6 checks passed
@leerho
leerho deleted the aod-empty-seed-hash branch November 3, 2026 18:02
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