oxy cat builds only the file it prints 19303b4a06fb
file_at rendered every file of the state to return one. It now loads the state's history and tree, builds that one file's graph and renders it; the working copy's base, and a state named by its heads (-r main on main), come from the workspace's state index. VS Code at 19,978 commits: cat package.json -r main 26 s to 0.10 s, at a change from 2016 0.66 s to 0.16 s, the base 0.10 s; output unchanged for text and binary files. The full 166,000-change import: -r main 1.9 s and 1.3 GB, where it ran for over 9 minutes at 9.3 GB. closes #92
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-10-09 21:49 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
19303b4a06fbf4b02fded411fc361ffe549c29b7ef535092bc45ce77d4056456- Depends on
- 170bb436e1d5 75167672ebcd 8fd78eb52ad2 982864068a59 c6aa5bd9d1c8
- Depended on by
- c2e1d09047db 7505194116e7
- In bookmarks
- bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
- In tags
- v0.10.0 v0.11.0 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
- Edits
- 4 atoms, 0 tree operations, 2 files
Browse the tree at this change
modified CHANGELOG.md +2 −0
| … | 1 unchanged lines |
||
| 2 | 2 | ||
| 3 | 3 | ## Unreleased |
|
| 4 | 4 | ||
| 5 | + | - **Reading one file reads one file (#92).** `oxy cat` rendered every file of the state to print one. It now builds only that file, from the workspace's state index when it reads the working copy's base or the state it is on. On VS Code at 20 000 commits, `cat package.json -r main` went from 26 s to 0.10 s and at a change from 2016 from 0.66 s to 0.16 s; on the full 166 000-change history it takes 1.9 s and 1.3 GB, where it ran for minutes and used 9 GB. |
|
| 6 | + | ||
| 5 | 7 | - **A file's history in a fraction of a second (#91).** `oxy log --path` rendered every file of the tree twice just to find the path, and both it and the `touches()` revset decoded every change of the history, its text included, to see what each one touched. They now read the path from the tree alone and keep the nodes each change touches in a cache beside the store (`.oxy/index/touched`, rebuilt if missing). On VS Code at 20 000 commits, `log --path package.json` went from 53.6 s to 0.16 s (Git: 0.15 s) and `touches("package.json")` from 3.4 s to 0.16 s, with the same output. |
|
| 6 | 8 | ||
| 7 | 9 | ## 0.4.2 (2026-10-09) |
|
| … | 146 unchanged lines |
modified crates/oxy-core/src/repo/snapshot.rs +26 −6
| … | 1408 unchanged lines |
||
| 1409 | 1409 | impl Repo { |
|
| 1410 | 1410 | /// The content of `path` in a state: `heads`, or the working copy's base. |
|
| 1411 | 1411 | pub fn file_at(&self, path: &str, heads: Option<&[ChangeHash]>) -> Result<Vec<u8>> { |
|
| 1412 | - | let snapshot = match heads { |
|
| 1413 | - | Some(h) => self.load_state(h)?.materialize(), |
|
| 1414 | - | None => { |
|
| 1415 | - | let (_, wc) = self.working_copy()?; |
|
| 1416 | - | self.load_state(&wc.deps)?.materialize() |
|
| 1417 | - | } |
|
| 1412 | + | // The state's history and tree, then the one file's graph: nothing |
|
| 1413 | + | // else is built or rendered (oxygen#92). |
|
| 1414 | + | // The working copy's base, and a state named by its heads (`-r |
|
| 1415 | + | // main` on main), come from the workspace's state index. |
|
| 1416 | + | let base = if self.is_bare() { |
|
| 1417 | + | None |
|
| 1418 | + | } else { |
|
| 1419 | + | Some(self.working_copy()?.1.deps) |
|
| 1420 | + | }; |
|
| 1421 | + | let same = |a: &[ChangeHash], b: &[ChangeHash]| { |
|
| 1422 | + | let (mut a, mut b) = (a.to_vec(), b.to_vec()); |
|
| 1423 | + | a.sort(); |
|
| 1424 | + | b.sort(); |
|
| 1425 | + | a == b |
|
| 1426 | + | }; |
|
| 1427 | + | let mut state = match (heads, base) { |
|
| 1428 | + | (Some(h), Some(b)) if same(h, &b) => self.load_state_indexed(&b)?, |
|
| 1429 | + | (Some(h), _) => self.load_state_history(h)?, |
|
| 1430 | + | (None, Some(b)) => self.load_state_indexed(&b)?, |
|
| 1431 | + | (None, None) => return fail("this is a bare repository: it has no working copy"), |
|
| 1432 | + | }; |
|
| 1433 | + | let view = state.tree().view(); |
|
| 1434 | + | let Some(node) = view.entries.get(path).map(|e| e.node) else { |
|
| 1435 | + | return fail(format!("{path} is not in that state")); |
|
| 1418 | 1436 | }; |
|
| 1437 | + | self.load_graphs_of(&mut state, &[node])?; |
|
| 1438 | + | let snapshot = state.materialize_paths(view, [path]); |
|
| 1419 | 1439 | let Some(f) = snapshot.files.get(path) else { |
|
| 1420 | 1440 | return fail(format!("{path} is not in that state")); |
|
| 1421 | 1441 | }; |
|
| … | 1581 unchanged lines |