OXYGENHUB

Log without walking history when the index is the closure bf0247ee3590

When every head asked for is in the workspace's state index and every
head of the index is among them, their closure is exactly the index's
changes, which is closed: metas_of takes them all without a walk. Under
test it still walks the store and checks the two agree.

VS Code at 19,978 commits, under load: log -n 20 about 45 ms to 38 ms
(metadata 17 to 12 ms); the whole log unchanged.

refs #94
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-10 03:38 UTC
Signature
✔ signed by Andy McCall
Hash
bf0247ee3590fb9049d7f49b8c382753df9151d16636667a9f3a15cf7f9fff0f
Depends on
4cce912a0953 79b5a90ffd43 982864068a59 ac03130a2b95 f9575918477f
Depended on by
74b4a3c62ea4
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
6 atoms, 0 tree operations, 1 file

Browse the tree at this change

modified crates/oxy-core/src/repo/mod.rs +39 −4
…
1504 unchanged lines
1505 1505
1506 1506
    /// The changes of this workspace's state index (the closure of its
1507 1507
    /// heads), read without the rest of the index.
1508 +
    #[allow(clippy::type_complexity)]
1508 1509
    pub(crate) fn read_state_index_changes(
1509 1510
        &self,
1510 -
    ) -> Option<crate::fasthash::FastMap<ChangeHash, std::sync::Arc<crate::state::ChangeMeta>>>
1511 -
    {
1511 +
    ) -> Option<(
1512 +
        Vec<ChangeHash>,
1513 +
        crate::fasthash::FastMap<ChangeHash, std::sync::Arc<crate::state::ChangeMeta>>,
1514 +
    )> {
1512 1515
        use std::io::Read;
1513 1516
        let _t = crate::timing::phase("load: state index changes");
1514 1517
        let mut f = fs::File::open(self.state_indexes().first()?).ok()?;
…
2 unchanged lines
1517 1520
        let n = u32::from_le_bytes(word) as usize;
1518 1521
        let mut head = vec![0u8; 32 * n + 64 + 4];
1519 1522
        f.read_exact(&mut head).ok()?;
1523 +
        let heads: Vec<ChangeHash> = head[..32 * n]
1524 +
            .chunks_exact(32)
1525 +
            .map(|c| ObjectRef(c.try_into().unwrap()))
1526 +
            .collect();
1520 1527
        let sum = &head[32 * n..32 * n + 32];
1521 1528
        let len = u32::from_le_bytes(head[32 * n + 64..].try_into().unwrap()) as usize;
1522 1529
        let mut changes = vec![0u8; 4 + len];
…
7 unchanged lines
1530 1537
        }
1531 1538
        drop(checking);
1532 1539
        let _decoding = crate::timing::phase("load:   of which decoding");
1533 -
        State::read_index_changes(&changes[4..]).ok()
1540 +
        Some((heads, State::read_index_changes(&changes[4..]).ok()?))
1534 1541
    }
1535 1542
1536 1543
    /// Save `st`, the history-only state of `deps`, as this workspace's
…
414 unchanged lines
1951 1958
        // The state index holds the metadata of its heads' closure: a
1952 1959
        // change found there is not read from the store (a change object
1953 1960
        // can be as large as the tree it adds).
1954 -
        let mut indexed = self.read_state_index_changes();
1961 +
        let read = self.read_state_index_changes();
1962 +
        // Every one of `heads` in the index, and every head of the index
1963 +
        // among them: their closure is the index's changes, all of them
1964 +
        // (it is closed), and no walk is needed to find it.
1965 +
        if let Some((index_heads, all)) = &read {
1966 +
            let asked: crate::fasthash::FastSet<&ChangeHash> = heads.iter().collect();
1967 +
            if heads.iter().all(|h| all.contains_key(h))
1968 +
                && index_heads.iter().all(|h| asked.contains(h))
1969 +
            {
1970 +
                let (_, all) = read.expect("matched above");
1971 +
                #[cfg(test)]
1972 +
                {
1973 +
                    // The walk the shortcut saves finds the same changes.
1974 +
                    let mut seen: HashSet<ChangeHash> = HashSet::new();
1975 +
                    let mut stack = heads.to_vec();
1976 +
                    while let Some(h) = stack.pop() {
1977 +
                        if seen.insert(h) {
1978 +
                            stack.extend(self.store.get_change_meta(&h)?.deps);
1979 +
                        }
1980 +
                    }
1981 +
                    assert_eq!(seen, all.keys().copied().collect::<HashSet<_>>());
1982 +
                }
1983 +
                return Ok(all
1984 +
                    .into_iter()
1985 +
                    .map(|(h, m)| (h, std::sync::Arc::unwrap_or_clone(m)))
1986 +
                    .collect());
1987 +
            }
1988 +
        }
1989 +
        let mut indexed = read.map(|(_, all)| all);
1955 1990
        let _walk = crate::timing::phase("metadata: walk");
1956 1991
        let (mut stored, mut from_store) = (0usize, std::time::Duration::ZERO);
1957 1992
        let mut seen: crate::fasthash::FastSet<ChangeHash> = Default::default();
…
356 unchanged lines