OXYGENHUB

Test: a state index's long changes block reads back whole and in order 2cd6bf89adb4

5 000 changes with varied deps and messages round-trip through the
listed reader the log uses, and a truncated block is refused. Two
speed-ups tried and dropped (measured on the VS Code history): reading
the index through mmap (1 ms of 27) and decoding the block in parallel
runs (slower: 31 against 27 ms).

Refs #94
Author
Andy McCall @andymccall <[email protected]>
via
agent Claude Code <[email protected]> · delegate for changes, until 2026-11-13 19:00Z · key ea5f78160088
When
· 2026-10-17 06:10 UTC
Signature
✔ signed by Claude Code
Hash
2cd6bf89adb40edea6e55e0254b24e00c44f47e9b7b6b5901d223d5665000788
Depends on
ff0af1ee299d
Depended on by
nothing yet
In bookmarks
carried-not-removed doctor-trust identical-sides keyless-tags main merge-remote-bookmark paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state
In tags
v0.10.0 v0.11.0 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
1 atom, 0 tree operations, 1 file

Browse the tree at this change

modified crates/oxy-core/src/state.rs +39 −0
…
270 unchanged lines
271 271
#[cfg(test)]
272 272
mod tests {
273 273
    use super::*;
274 +
275 +
    /// A changes block of thousands comes back whole and in order, and a
276 +
    /// truncated one is refused (oxygen#94).
277 +
    #[test]
278 +
    fn a_long_changes_block_decodes_in_order() {
279 +
        use crate::flat::Writer;
280 +
        let metas: Vec<(ChangeHash, ChangeMeta)> = (0..5000u32)
281 +
            .map(|i| {
282 +
                let mut h = [0u8; 32];
283 +
                h[..4].copy_from_slice(&i.to_le_bytes());
284 +
                let meta = ChangeMeta {
285 +
                    change_id: crate::ids::ChangeId([i as u8; 16]),
286 +
                    deps: (0..i % 3).map(|d| ObjectRef([d as u8; 32])).collect(),
287 +
                    author: ObjectRef([7; 32]),
288 +
                    hlc: Hlc {
289 +
                        wall_ms: 1_000_000 - i as u64,
290 +
                        logical: i,
291 +
                    },
292 +
                    message: "x".repeat((i % 50) as usize),
293 +
                    kind: ChangeKind::Normal,
294 +
                };
295 +
                (ObjectRef(h), meta)
296 +
            })
297 +
            .collect();
298 +
        let mut w = Writer::default();
299 +
        w.fixed(State::INDEX_MAGIC);
300 +
        w.count(metas.len());
301 +
        for (h, m) in &metas {
302 +
            w.object(h);
303 +
            m.write_flat(&mut w);
304 +
        }
305 +
        assert_eq!(State::read_index_changes_listed(&w.0).unwrap(), metas);
306 +
        let mut cut = w.0.clone();
307 +
        cut.pop();
308 +
        assert!(
309 +
            State::read_index_changes_listed(&cut).is_err(),
310 +
            "a truncated block is refused"
311 +
        );
312 +
    }
274 313
    use crate::ids::ChangeId;
275 314
    use crate::objects::{AtomRange, ChangeKind, Hlc, OpRef};
276 315
…
116 unchanged lines