OXYGENHUB

git verify: hold only the open frontier of ancestor sets ee6aa3e81bc8

Verify kept, for every Git commit, the set of changes of it and all its
ancestors, and never let one go: memory grew with the square of the
history, and on the VS Code import (140k commits) even --last 60 was
killed for memory. A commit's set is now dropped after its last child
has used it, and that child takes it over rather than copying it.

refs #81
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-07 19:57 UTC
Signature
✔ signed by Andy McCall
Hash
ee6aa3e81bc86069b2497a22e1be65df9408fd39190031cf9c27aeb57e4a8fdb
Depends on
57d8dc05c9d4 62794ecc7f74 79ab8528ff62
Depended on by
8b7986dd3cb0
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.1 v0.4.2 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/git.rs +30 −4
…
1127 unchanged lines
1128 1128
        // come, so a child adds its own changes instead of loading all its
1129 1129
        // history again (as the import does).
1130 1130
        let mut waiting: HashMap<&str, usize> = HashMap::new();
1131 +
        // Children still to come per commit, through any parent: a commit's
1132 +
        // closure is dropped after its last child, so only the open
1133 +
        // frontier is held. Kept for every commit, the closures grew with
1134 +
        // the square of the history and VS Code's verify ran out of memory
1135 +
        // (oxygen#81).
1136 +
        let mut children: HashMap<&str, usize> = HashMap::new();
1131 1137
        for c in &commits {
1132 1138
            if let Some(p1) = c.parents.first() {
1133 1139
                *waiting.entry(p1.as_str()).or_default() += 1;
1134 1140
            }
1141 +
            for p in &c.parents {
1142 +
                *children.entry(p.as_str()).or_default() += 1;
1143 +
            }
1135 1144
        }
1136 1145
        let mut kept: HashMap<String, State> = HashMap::new();
1137 1146
        let mut kept_order: std::collections::VecDeque<String> = std::collections::VecDeque::new();
1138 1147
        for c in &commits {
1139 1148
            rep.commits += 1;
1149 +
            // The first parent's closure, taken over when this is its last
1150 +
            // child (no copy), then the other parents' added.
1140 1151
            let mut set: BTreeSet<ChangeHash> = BTreeSet::new();
1141 -
            for p in &c.parents {
1142 -
                if let Some(ps) = closure.get(p) {
1143 -
                    set.extend(ps.iter().copied());
1152 +
            for (i, p) in c.parents.iter().enumerate() {
1153 +
                let left = children.get_mut(p.as_str()).map(|n| {
1154 +
                    *n -= 1;
1155 +
                    *n
1156 +
                });
1157 +
                let ps = if left == Some(0) {
1158 +
                    closure.remove(p)
1159 +
                } else {
1160 +
                    closure.get(p).cloned()
1161 +
                };
1162 +
                if let Some(ps) = ps {
1163 +
                    if i == 0 && set.is_empty() {
1164 +
                        set = Arc::try_unwrap(ps).unwrap_or_else(|a| (*a).clone());
1165 +
                    } else {
1166 +
                        set.extend(ps.iter().copied());
1167 +
                    }
1144 1168
                }
1145 1169
            }
1146 1170
            match imported.get(&c.sha) {
…
8 unchanged lines
1155 1179
                }
1156 1180
            }
1157 1181
            let set = Arc::new(set);
1158 -
            closure.insert(c.sha.clone(), set.clone());
1182 +
            if children.get(c.sha.as_str()).is_some_and(|n| *n > 0) {
1183 +
                closure.insert(c.sha.clone(), set.clone());
1184 +
            }
1159 1185
            if rep.mismatches.len() >= 50 {
1160 1186
                break;
1161 1187
            }
…
218 unchanged lines