Skip to main content

reflog_resources/
reflog_resources.rs

1//! Original bounded history fixtures; warm-cache read, interpretation and root recovery
2//! observations.
3use std::sync::atomic::AtomicBool;
4use std::time::Instant;
5
6use girt::refs::{Backend, ImportedRecord, RefName, ReflogLimits};
7use girt::{InitKind, ObjectFormat, ObjectId, Repository};
8
9fn descriptors() -> Option<usize> {
10    #[cfg(target_os = "linux")]
11    let path = "/proc/self/fd";
12    #[cfg(target_os = "macos")]
13    let path = "/dev/fd";
14    #[cfg(any(target_os = "linux", target_os = "macos"))]
15    return std::fs::read_dir(path).ok().map(Iterator::count);
16    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
17    None
18}
19
20fn main() -> Result<(), Box<dyn std::error::Error>> {
21    for format in [ObjectFormat::Sha1, ObjectFormat::Sha256] {
22        for count in [100, 10_000] {
23            probe(format, count, Backend::Files)?;
24            probe(format, count, Backend::Reftable)?;
25        }
26    }
27    Ok(())
28}
29
30fn probe(
31    format: ObjectFormat,
32    count: usize,
33    backend: Backend,
34) -> Result<(), Box<dyn std::error::Error>> {
35    let root = tempfile::tempdir()?;
36    let repo =
37        Repository::init_with_backend(format, root.path().join("repo"), InitKind::Bare, backend)?;
38
39    let tip = ObjectId::from_hex(format, &"12".repeat(format.digest_len()))?;
40    let record = format!(
41        "{} {tip} A <a@b> 1700000000 +0000\tfixture\n",
42        ObjectId::null(format)
43    );
44    let bytes = record.repeat(count);
45
46    if backend == Backend::Files {
47        std::fs::create_dir_all(repo.git_dir().join("logs"))?;
48        std::fs::write(repo.git_dir().join("logs/HEAD"), &bytes)?;
49    } else {
50        write_binary(&repo, tip, count)?;
51    }
52
53    let refs = repo.references()?;
54    let name = RefName::HEAD;
55    let cancel = AtomicBool::new(false);
56    let before = descriptors();
57    let retained = refs
58        .imported_reflog(&name, ReflogLimits::default(), &cancel)?
59        .unwrap();
60    let during = descriptors();
61    assert!(retained.is_complete());
62
63    let payload: usize = retained
64        .records()
65        .iter()
66        .map(|r| match r {
67            ImportedRecord::File { bytes, .. } => Ok(bytes.len()),
68            ImportedRecord::Reftable { value, .. } => Ok(value.name.len()
69                + value.email.len()
70                + value.message.len()
71                + 2 * format.digest_len()
72                + 18),
73            _ => Err("unsupported imported reflog record"),
74        })
75        .sum::<Result<usize, _>>()?;
76
77    drop(retained);
78    let after = descriptors();
79
80    let mut samples = Vec::new();
81    for _ in 0..30 {
82        let start = Instant::now();
83        let log = refs
84            .imported_reflog(&name, ReflogLimits::default(), &cancel)?
85            .unwrap();
86        assert!(log.is_complete());
87        assert_eq!(log.recoverable_roots().count(), count);
88        drop(log);
89        samples.push(start.elapsed().as_nanos());
90    }
91
92    samples.sort_unstable();
93    println!(
94        "backend={backend:?} format={format} records={count} payload={payload} min_ns={} median_ns={} max_ns={} descriptors={before:?}/{during:?}/{after:?}",
95        samples[0], samples[15], samples[29]
96    );
97
98    Ok(())
99}
100
101fn write_binary(
102    repo: &Repository,
103    tip: ObjectId,
104    count: usize,
105) -> Result<(), Box<dyn std::error::Error>> {
106    use girt::refs::reftable::{Limits, LogRecord, LogValue, RecordName, Table};
107
108    let table = Table {
109        format: tip.format(),
110        min_update_index: 1,
111        max_update_index: count as u64,
112        references: Vec::new(),
113        logs: (1..=count as u64)
114            .rev()
115            .map(|index| LogRecord {
116                name: RecordName::new(b"HEAD").unwrap(),
117                update_index: index,
118                value: Some(LogValue {
119                    old: ObjectId::null(tip.format()),
120                    new: tip,
121                    name: b"A".to_vec(),
122                    email: b"a@b".to_vec(),
123                    seconds: 1700000000,
124                    offset_minutes: 0,
125                    message: b"fixture\n".to_vec(),
126                }),
127            })
128            .collect(),
129    };
130
131    std::fs::write(
132        repo.git_dir().join("reftable/original.ref"),
133        table.encode(Limits::default())?,
134    )?;
135    std::fs::write(
136        repo.git_dir().join("reftable/tables.list"),
137        b"original.ref\n",
138    )?;
139
140    Ok(())
141}