Skip to content

Fix digest mismatch in non-unique secondary index trees - #43

Merged
hadashiA merged 1 commit into
mainfrom
claude/fix-nonunique-index-digests
Nov 7, 2026
Merged

hadashiA merged 1 commit into
mainfrom
claude/fix-nonunique-index-digests

Conversation

@hadashiA

@hadashiA hadashiA commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

Fixes #41
Fixes #42

Problem

Non-unique secondary index trees are built from composite keys (source key + 4-byte rid), but TreeBuilder computed entry digests with the source encoding reported by KeyValueList.KeyEncoding, while the read side (NonUniqueSecondaryIndexQuery) digests through DuplicateKeyEncoding, which strips the rid first. The two digest functions disagreed, which broke GetAll/GetRange in two ways:

Fix

Redefine KeyValueList.KeyEncoding as the encoding of the keys the list actually enumerates: DuplicateKeyValueList overrides it with DuplicateKeyEncoding, which digests the source part only and keeps the default IsKeyDigestExact = false, so TreeBuilder computes digests exactly the way readers do and duplicate-key trees never omit key bytes. The list's internals (Add, the grouping comparer) keep using the source encoding. One file changed; unique trees are unchanged.

Verification

  • Both issues' repro code now returns the expected counts (156/157/1000 → all rows; 10 groups × 500 → 500 each; 7-byte and 8-byte Ascii keys → 2 each).
  • dotnet test: 95/95 passing.

Note: databases already built with an affected version need to be rebuilt — the bad digests/omitted keys are baked into the file.

🤖 Generated with Claude Code

Non-unique secondary index trees are built from composite keys
(source key + 4-byte rid), but TreeBuilder computed entry digests
with the source encoding reported by KeyValueList.KeyEncoding,
while readers digest through DuplicateKeyEncoding (source part only).
The mismatch broke GetAll/GetRange in two ways:

- Sources with exact digests (e.g. Int64) enabled OmittedKeys although
  the composite keys are not recoverable from the digest: every
  duplicate collides and the rid tiebreaker is lost, so queries return
  only part of the entries once the tree spans more than one leaf
  (#41, regression in format 1.4).
- Ascii source keys shorter than 8 bytes leaked the rid's leading
  bytes into the stored digests, so only the rid-0 entry matched the
  query digest and bound searches stopped at the first digest
  mismatch (#42, present since key digests were introduced).

Redefine KeyValueList.KeyEncoding as the encoding of the keys the
list enumerates: DuplicateKeyValueList overrides it with
DuplicateKeyEncoding, which digests the source part only and never
reports exact digests, so TreeBuilder computes digests the same way
readers do and duplicate-key trees never omit key bytes.

Fixes #41
Fixes #42

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hadashiA
hadashiA force-pushed the claude/fix-nonunique-index-digests branch from 84140ea to e32a764 Compare November 7, 2026 03:37
@hadashiA
hadashiA merged commit e337597 into main Nov 7, 2026
1 check passed
@hadashiA
hadashiA deleted the claude/fix-nonunique-index-digests branch November 7, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant