Skip to content

ReftableReader fails to read refs from a valid reftable with a multi-block root index #289

Description

@guancheng-lai

Version

7.7

Operating System

Linux/Unix

Bug description

Bug description

A valid reftable written by C Git can have a highest index level that
spans multiple sibling index blocks. ReftableReader starts at the index
position recorded in the footer, reads the first index block, and returns
no match when the requested key sorts after that block. It does not
continue to the next index block at the same level.

This makes JGit internally inconsistent: a full ref scan returns a ref,
while point-lookup APIs cannot find that same ref. Native Git resolves the
ref successfully.

I attached jgit-reftable-multi-root-reproducer.zip, which contains the
complete read-only probe source and an example broken repository:

  • JGitReftableReadProbe.java compares JGit full enumeration, JGit
    exactRef, findRef, and resolve, and native Git point lookup.
  • broken-repository.git is a synthetic bare repository written by C Git
    2.54 using extensions.refStorage=reftable.
  • The repository has 10,000 generic refs pointing to one empty synthetic
    commit. It contains no production source or ref names.

Archive SHA-256:

d6e91da54a8456d6b787ad49932ecc88a441c1987a84b639aef75fe0c9e475a8

Run the complete probe with a JGit runtime classpath:

java --class-path '/path/to/jgit.jar:/path/to/dependencies/*' \
  JGitReftableReadProbe.java \
  broken-repository.git \
  refs/heads/archive/7fff4ea22b8a03452de95dca17404a632d111489

jgit-reftable-multi-root-reproducer.zip

Actual behavior

Actual behavior

With unmodified JGit 7.7:

refDatabase=org.eclipse.jgit.internal.storage.file.FileReftableDatabase
extensions.refStorage=reftable
jgitFullScan.count=10001
jgitFullScanVsExactRef.mismatchCount=4349
ref=refs/heads/archive/7fff4ea22b8a03452de95dca17404a632d111489 enumerated=1485913eca8d3370fc05352a45977a99720acb1c exactRef=null findRef=null resolve=null nativeExit=0 native=1485913eca8d3370fc05352a45977a99720acb1c
BUG_REPRODUCED=true

The failure is deterministic for every ref routed through the second
root-index block.

Expected behavior

Expected behavior

Every ref returned by the full scan should also be found by exactRef,
findRef, and resolve. JGit point lookup should agree with native Git.

With the proposed fix:

jgitFullScan.count=10001
jgitFullScanVsExactRef.mismatchCount=0
ref=refs/heads/archive/7fff4ea22b8a03452de95dca17404a632d111489 enumerated=1485913eca8d3370fc05352a45977a99720acb1c exactRef=1485913eca8d3370fc05352a45977a99720acb1c findRef=1485913eca8d3370fc05352a45977a99720acb1c resolve=1485913eca8d3370fc05352a45977a99720acb1c nativeExit=0 native=1485913eca8d3370fc05352a45977a99720acb1c
BUG_REPRODUCED=false

Relevant log output

Other information

Other information

The footer's index position is the start of the highest index level; it
is not a guarantee that the level consists of only one block. The current
lookup treats the first block as the entire root level.

The proposed fix walks sibling index blocks at the highest level until it
finds the block whose key range contains the requested key, or reaches
the next reftable section. It handles adjacent unaligned blocks,
block-aligned NUL padding, and an oversized root block. The same logic is
used for ref, object, and log indexes.

The accompanying tests cover aligned and unaligned multi-block ref root
indexes, object and log indexes, missing keys, and an oversized
single-level root index.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions