fangorn/ex_git_objectstore
public
ref:1ad0b2b22aa4b08be0fdf4531570983f050f12a8
feat(graph): batched ahead_behind_many — walk base ancestors once for N heads
`ahead_behind/3` walks `ancestors(base) ∪ ancestors(head)` from
scratch on every call. When a caller asks the same question for many
heads against one base — typical PR-list page where every PR has
`base = main` — that re-walks `ancestors(base)` N times.
Add a batched variant that walks `ancestors(base)` once into a set,
then for each head:
- BFS from head, classifying each commit as in-base (merge point) or
not (head-only → ahead);
- DOWN-BFS within base_ancestors from the merge points to size the
intersection; behind = |base_ancestors| - |intersection|.
Cost goes from O(N · |ancestors(base)|) to
O(|ancestors(base)| + Σ head walks).
Public API wraps with the standard graph/fallback routing: if the
graph isn't loaded, every head goes through per-head `ahead_behind/3`
(which already has its own cat_object fallback). If specific heads
aren't in the graph (just-pushed branches), they fall back per-head
while the rest take the fast path.
Measured against chiron (393-commit main, 70 PRs, graph built):
- per-head loop: 33 ms
- batched: 6 ms (5.5×)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SHA:
1ad0b2b22aa4b08be0fdf4531570983f050f12a8
Author:
Cole Christensen <cole.christensen@macmillan.com>
Date:
2026-04-30 04:45
Parents:
03224cd
4 files changed
+332
-0
| Type | ||
|---|---|---|
|
|
lib/ex_git_objectstore.ex | +55 −0 |
|
||