Skip to content

vcs: build_trend per-point build re-walks the first-parent timeline (stale O(commits)-lookup comment) #819

@dekobon

Description

@dekobon

Summary

git::build_trend computes a single shared first-parent timeline "so each point is an O(commits) lookup rather than its own walk", but since the #648 --as-of re-anchoring landed in build, every per-point build call now performs its own full first-parent walk — defeating the optimization the comment describes and making that comment stale.

Location

  • src/vcs/git/trend.rs:57-67 (the shared-timeline comment and drop(repo) / per-point build loop)
  • Interacts with src/vcs/git/mod.rs:101-119 (resolve_anchorfirst_parent_timeline whenever options.as_of.is_some())

Evidence

build_trend builds the timeline once and explains the intent:

// One first-parent walk of the base reference yields every mainline
// tip and its time, so each point is an O(commits) lookup rather than
// its own walk.
let OpenRepo { repo, .. } = repo::open(root)?;
let tip = repo::resolve_commit(&repo, &base.reference)?.id;
let timeline = first_parent_timeline(&repo, tip)?;
drop(repo);
...
for &at in &stamps {
    let Some(oid) = tip_at_or_before(&timeline, at) else { ... };
    let index = build(root, &snapshot_options(base, oid, at))?;  // re-walks!
    ...
}

snapshot_options always sets as_of = Some(at) (src/vcs/git/trend.rs:95-101). In build, any as_of triggers resolve_anchor, which unconditionally re-walks the first-parent timeline (src/vcs/git/mod.rs:106-110):

let Some(as_of) = options.as_of else { return Ok(Some(tip)); };
let timeline = trend::first_parent_timeline(repo, tip.id)?;   // P extra walks
let Some(anchor) = trend::tip_at_or_before(&timeline, as_of) else { ... };

Git history confirms the comment is stale: at the trend feature's introduction (9624098b) build had no resolve_anchor/first_parent_timeline and did not re-walk, so "an O(commits) lookup rather than its own walk" was accurate. The #648 fix (cb12db79) added the per-as_of re-anchoring walk afterwards, defeating the shared-timeline optimization without updating the trend comment.

Net effect for P points: 1 + P first-parent walks instead of the documented 1. (The first-parent walk is cheap relative to each point's window walk in collect_events, so this is wasted work rather than a correctness defect.)

Expected Behavior

Either:

  1. Pass the already-resolved historical anchor oid through to build so it skips the redundant first_parent_timeline re-walk (the comment then becomes true again), or
  2. Correct the comment to state that each point still performs its own first-parent walk inside build.

Actual Behavior

build_trend resolves the timeline once and every per-point build resolves it again, while the comment claims the per-point work is only an O(commits) lookup.

Impact

VCS-git trend consumers (bca vcs --trend, web /vcs/trend, Python vcs.trend). The shared timeline gives no run-time benefit it claims to; a reader trusting the comment would mis-model the cost, and the redundant walks scale linearly with the requested point count (up to MAX_TREND_POINTS = 120).


Resolution

Corrected the stale trend.rs comment: the shared timeline only resolves each point's tip oid; each per-point build re-walks the first-parent timeline (O(points x commits) since #648). Commit a7e35ad.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions