OXYGENHUB

Use the loaded state for last change, blame and tree rows (oxy-core log_for_path_of, blame_of, log_of): cold file pages no longer rebuild the state b19606f28101

refs #14
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-28 14:22 UTC
Signature
✔ signed by Andy McCall
Hash
b19606f28101e4fa0c7fc3588f84f9af2afd54943f6e2138cc1cad04094fbc3e
Depends on
75d611ab99d1 9ff27da517fe d23464c0ac60
Depended on by
df15b74774ca
In bookmarks
api-unknown-fields cancel-landed-runs clear-waiting close-proposal-140 diffusion-pin-bookmark draft-ready image-check job-waits main oh-comment-body-file proposal-list-fast run-one-job wiki-says-so
In tags
v0.1.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.5.0 v0.5.1 v0.5.2 v0.6.0 v0.6.1 v0.7.0 v0.8.0 v0.9.0 v0.9.1 v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.2 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
Edits
8 atoms, 0 tree operations, 1 file

Browse the tree at this change

modified crates/hub/src/repos/view.rs +17 −11
…
610 unchanged lines
611 611
        FileBody::Text(String::from_utf8_lossy(&bytes).into_owned())
612 612
    };
613 613
    let labels = head_labels(repo)?;
614 -
    let last_change = last_change_of(repo, &target.heads, path)
614 +
    let last_change = last_change_of(repo, &loaded.state, &target.heads, path)
615 615
        .and_then(|h| loaded.state.get(&h).map(|meta| change_view(repo, &h, meta, loaded.state.heads().contains(&h), &labels)));
616 616
    let name = path.rsplit('/').next().unwrap_or(path).to_string();
617 617
    Ok(FileView {
…
46 unchanged lines
664 664
}
665 665
666 666
/// The newest change touching `path` in the state, from a cache of 4 MiB.
667 -
pub fn last_change_of(repo: &Repo, heads: &[ChangeHash], path: &str) -> Option<ChangeHash> {
667 +
pub fn last_change_of(repo: &Repo, state: &oxy_core::state::State, heads: &[ChangeHash], path: &str) -> Option<ChangeHash> {
668 668
    static C: std::sync::OnceLock<crate::render::cache::Lru<Last>> = std::sync::OnceLock::new();
669 669
    let cache = C.get_or_init(|| crate::render::cache::Lru::new(4 << 20));
670 670
    let key = state_path_key(b"last1", heads, path);
671 -
    cache.get_or(key, || Last(repo.log_for_path_in(path, heads).ok().and_then(|l| l.into_iter().next()).map(|e| e.hash))).0
671 +
    cache.get_or(key, || Last(repo.log_for_path_of(state, path, Some(1)).ok().and_then(|l| l.into_iter().next()).map(|e| e.hash))).0
672 672
}
673 673
674 674
struct BlameLines(Vec<BlameLine>);
…
5 unchanged lines
680 680
}
681 681
682 682
/// `Repo::blame_in`, cached by state and path (64 MiB).
683 -
fn blame_cached(repo: &Repo, heads: &[ChangeHash], path: &str) -> Result<Vec<BlameLine>> {
683 +
fn blame_cached(repo: &Repo, cache_state: &StateCache, heads: &[ChangeHash], path: &str) -> Result<Vec<BlameLine>> {
684 684
    static C: std::sync::OnceLock<crate::render::cache::Lru<BlameLines>> = std::sync::OnceLock::new();
685 685
    let cache = C.get_or_init(|| crate::render::cache::Lru::new(64 << 20));
686 686
    let key = state_path_key(b"blame1", heads, path);
687 687
    let mut failure = None;
688 -
    let lines = cache.get_or(key, || match repo.blame_in(path, heads) {
689 -
        Ok(l) => BlameLines(l),
690 -
        Err(e) => {
691 -
            failure = Some(e);
692 -
            BlameLines(Vec::new())
688 +
    let lines = cache.get_or(key, || {
689 +
        match cache_state
690 +
            .load(repo, heads)
691 +
            .map_err(|e| oxy_core::repo::RepoError::Msg(e.to_string()))
692 +
            .and_then(|loaded| repo.blame_of(&loaded.state, &loaded.snapshot.tree, path))
693 +
        {
694 +
            Ok(l) => BlameLines(l),
695 +
            Err(e) => {
696 +
                failure = Some(e);
697 +
                BlameLines(Vec::new())
698 +
            }
693 699
        }
694 700
    });
695 701
    if let Some(e) = failure {
…
19 unchanged lines
715 721
    let snapshot = &loaded.snapshot;
716 722
    // Newest change touching each node, from one pass over the log.
717 723
    let mut newest: HashMap<oxy_core::ids::NodeId, (ChangeHash, u64)> = HashMap::new();
718 -
    for e in repo.log_state(heads)? {
724 +
    for e in repo.log_of(state) {
719 725
        let Ok(c) = repo.store().get_change(&e.hash) else { continue };
720 726
        let when = e.change.hlc.wall_ms;
721 727
        for node in c.tree_ops.iter().map(|o| o.node()).chain(c.edits.iter().map(|x| x.node())) {
…
39 unchanged lines
761 767
pub fn blame(repo: &Repo, cache: &StateCache, target: RefTarget, path: &str, render_limit: u64) -> Result<Blame> {
762 768
    let heads = target.heads.clone();
763 769
    let file = file(repo, cache, target, path, render_limit)?;
764 -
    let lines = blame_cached(repo, &heads, path)?;
770 +
    let lines = blame_cached(repo, cache, &heads, path)?;
765 771
    let mut before = HashMap::new();
766 772
    for l in &lines {
767 773
        before.entry(l.hash).or_insert_with(|| repo.store().get_change(&l.hash).ok().and_then(|c| state_spec(&c.deps)));
…
415 unchanged lines