Tighten sha256convert: scanner, recursion, dead field, fsck match, close, memoization · Entire
Tighten sha256convert: scanner, recursion, dead field, fsck match, close, memoization
d63f3ab→main·
nodo·1mo ago·2 files·+178 added/-47 removed
fsckHasError used bufio.Scanner with the default 64 KiB buffer, so a single long line (paths in repository-scale fsck output) would silently truncate and we'd miss whatever followed it. Switch to bytes.Split on raw newlines.
discoverReachable was recursive, which on long linear chains (kernel-scale: ~70k commits on the deepest single-parent path) grew the goroutine stack into the tens of MiB. Iterativize with an explicit work stack — memory now scales with the in-flight frontier, not the longest chain. translate() stays recursive: its edges are dynamic (tree entries + commit parents
- tag targets + message-reference edges resolved against the in-progress mapping), and rewriting it would risk silent corruption of message rewrites. Documented the rationale and the depth math.
translator.dst was set in newTranslator but never read — a landmine inviting a future contributor to call go-git's SHA1-hardcoded SetEncodedObject. Field removed; the type assertion stays (with
__) so a memory-backed dst is still refused with a clear error.fsckHasError's error-line matcher was prefix-only and case- sensitive ("error:" / "fatal:"). Broaden to any line whose first token starts with "error" or "fatal" (case-insensitive), keep the "missing "/"broken link"/"bad " object reports for older git. Closer to the previous substring match's coverage without the path-substring false positive.
writeMappingFile dropped Close errors via a deferred Close. On NFS or quota-bound filesystems write failures surface at close time, not flush time, so the caller would think the mapping landed when it hadn't. Explicit Close on the success path, with the deferred Close kept as a best-effort net for the failure path.
resolveMessageRef ran a full O(len(reachable)) scan for every short hash prefix, hit twice per token (once by extractMessageReferences, once by rewriteHashesInMessage). reachable is frozen before translation starts, so the (prefix → matchResult) mapping is stable; memoize it on the translator. Halves the documented quadratic ceiling on message-token resolution.
Tests cover the long-line + case-insensitive fsck path and the resolveMessageRef cache (second call returns the cached answer even after reachable is mutated).
Sessions
Transcript data is unavailable for this checkpoint.
Changes
2
cmd/git-sync/internal/sha256convert
Msha256convert.go+106/-47
- Msha256convert_test.go+72
664 unmodified lines
return checks
// fsckHasError reports whether git-fsck output contains a line that signals
// a real problem (an "error:" or "fatal:" prefix, or a "missing"/"bad"
// object report). Dangling and warning lines are ignored.
// fsckHasError reports whether git-fsck output contains a line that
// signals a real problem. We match (case-insensitively) any line whose
// first token starts with "error" or "fatal" — covering "error:",
// "fatal:", and the rare "errorInX:" variants — plus the
// "missing