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 |