#![allow(dead_code)]
use std::io::Write;
use std::path::PathBuf;
pub struct Fixture {
pub dir: tempfile::TempDir,
pub path: PathBuf,
}
fn build_tar(members: &[(&str, &[u8])]) -> Vec<u8> {
let mut b = tar::Builder::new(Vec::new());
for (name, body) in members {
let mut h = tar::Header::new_gnu();
h.set_size(body.len() as u64);
h.set_mode(0o644);
h.set_mtime(1_756_000_000);
h.set_entry_type(tar::EntryType::Regular);
h.set_cksum();
b.append_data(&mut h, name, &mut &body[..]).unwrap();
}
b.into_inner().unwrap()
}
fn write(dir: tempfile::TempDir, name: &str, bytes: &[u8]) -> Fixture {
let path = dir.path().join(name);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::File::create(&path).unwrap().write_all(bytes).unwrap();
Fixture { dir, path }
}
fn zstd_bytes(raw: &[u8]) -> Vec<u8> {
zstd::stream::encode_all(raw, 3).unwrap()
}
pub fn tar_zst(name: &str, members: &[(&str, &[u8])]) -> Fixture {
let dir = tempfile::tempdir().unwrap();
write(dir, name, &zstd_bytes(&build_tar(members)))
}
pub fn tar_zst_nested_zst(name: &str, inner: &str, body: &[u8]) -> Fixture {
let inner_zst = zstd_bytes(body);
tar_zst(name, &[(inner, inner_zst.as_slice())])
}
pub fn tgz_nested_zst(name: &str, inner: &str, body: &[u8]) -> Fixture {
let inner_zst = zstd_bytes(body);
tgz(name, &[(inner, inner_zst.as_slice())])
}
pub fn with_skippable_frame(bytes: &[u8]) -> Vec<u8> {
let mut out = vec![0x50, 0x2A, 0x4D, 0x18, 4, 0, 0, 0, 0xDE, 0xAD, 0xBE, 0xEF];
out.extend_from_slice(bytes);
out
}
pub fn tar_zst_skippable(name: &str, members: &[(&str, &[u8])]) -> Fixture {
let dir = tempfile::tempdir().unwrap();
write(dir, name, &with_skippable_frame(&zstd_bytes(&build_tar(members))))
}
pub fn tgz_nested_zst_skippable(name: &str, inner: &str, body: &[u8]) -> Fixture {
let inner_zst = with_skippable_frame(&zstd_bytes(body));
tgz(name, &[(inner, inner_zst.as_slice())])
}
pub fn zstd_long_bytes(raw: &[u8], window_log: u32) -> Vec<u8> {
use zstd::stream::raw::CParameter;
let mut e = zstd::stream::write::Encoder::new(Vec::new(), 3).unwrap();
e.set_parameter(CParameter::WindowLog(window_log)).unwrap();
e.set_parameter(CParameter::EnableLongDistanceMatching(true)).unwrap();
e.write_all(raw).unwrap();
e.finish().unwrap()
}
pub fn tar_zst_long(name: &str, members: &[(&str, &[u8])], window_log: u32) -> Fixture {
let dir = tempfile::tempdir().unwrap();
write(dir, name, &zstd_long_bytes(&build_tar(members), window_log))
}
pub fn tar_zst_truncated(name: &str, members: &[(&str, &[u8])], keep: f64) -> Fixture {
let full = zstd_bytes(&build_tar(members));
let n = ((full.len() as f64) * keep) as usize;
let dir = tempfile::tempdir().unwrap();
write(dir, name, &full[..n.max(8)])
}
pub fn xz_bytes(raw: &[u8]) -> Vec<u8> {
let mut e = liblzma::write::XzEncoder::new(Vec::new(), 6);
e.write_all(raw).unwrap();
e.finish().unwrap()
}
pub fn tar_xz(name: &str, members: &[(&str, &[u8])]) -> Fixture {
let dir = tempfile::tempdir().unwrap();
write(dir, name, &xz_bytes(&build_tar(members)))
}
pub fn tar_xz_nested_xz(name: &str, inner: &str, body: &[u8]) -> Fixture {
let inner_xz = xz_bytes(body);
tar_xz(name, &[(inner, inner_xz.as_slice())])
}
pub fn tgz_nested_xz(name: &str, inner: &str, body: &[u8]) -> Fixture {
let inner_xz = xz_bytes(body);
tgz(name, &[(inner, inner_xz.as_slice())])
}
pub fn tar_xz_truncated(name: &str, members: &[(&str, &[u8])], keep: f64) -> Fixture {
let full = xz_bytes(&build_tar(members));
let n = ((full.len() as f64) * keep) as usize;
let dir = tempfile::tempdir().unwrap();
write(dir, name, &full[..n.max(8)])
}
fn gzip(raw: &[u8]) -> Vec<u8> {
let mut e = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default());
e.write_all(raw).unwrap();
e.finish().unwrap()
}
pub fn tgz(name: &str, members: &[(&str, &[u8])]) -> Fixture {
let dir = tempfile::tempdir().unwrap();
write(dir, name, &gzip(&build_tar(members)))
}
pub fn tar_plain(name: &str, members: &[(&str, &[u8])]) -> Fixture {
let dir = tempfile::tempdir().unwrap();
write(dir, name, &build_tar(members))
}
pub fn tgz_truncated(name: &str, members: &[(&str, &[u8])], keep: f64) -> Fixture {
let full = gzip(&build_tar(members));
let n = ((full.len() as f64) * keep) as usize;
let dir = tempfile::tempdir().unwrap();
write(dir, name, &full[..n.max(64)])
}
pub fn tgz_with_hardlink(name: &str) -> Fixture {
let body = b"NEEDLE in the real member\n";
let mut b = tar::Builder::new(Vec::new());
let mut h = tar::Header::new_gnu();
h.set_size(body.len() as u64);
h.set_mode(0o644);
h.set_entry_type(tar::EntryType::Regular);
h.set_cksum();
b.append_data(&mut h, "logs/real.log", &mut &body[..]).unwrap();
let mut l = tar::Header::new_gnu();
l.set_size(0);
l.set_mode(0o644);
l.set_entry_type(tar::EntryType::Link);
l.set_link_name("logs/real.log").unwrap();
l.set_cksum();
b.append_data(&mut l, "logs/linked.log", &mut std::io::empty()).unwrap();
let raw = b.into_inner().unwrap();
let dir = tempfile::tempdir().unwrap();
write(dir, name, &gzip(&raw))
}
pub fn tgz_with_long_name(name: &str, depth: usize) -> Fixture {
let long = std::iter::repeat_n("averylongdirectorycomponent", depth)
.collect::<Vec<_>>()
.join("/");
let member = format!("{long}/access.log");
tgz(name, &[(member.as_str(), b"NEEDLE deep\n")])
}
pub fn tgz_nested_gz(name: &str, inner: &str, body: &[u8]) -> Fixture {
let inner_gz = gzip(body);
tgz(name, &[(inner, inner_gz.as_slice())])
}
#[cfg(target_os = "linux")]
pub fn resident_pages(path: &std::path::Path) -> (usize, usize) {
use std::os::unix::io::AsRawFd;
let file = std::fs::File::open(path).unwrap();
let len = file.metadata().unwrap().len() as usize;
assert!(len > 0, "cannot measure residency of an empty file");
let ps = unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as usize;
let np = len.div_ceil(ps);
let m = unsafe {
libc::mmap(std::ptr::null_mut(), len, libc::PROT_READ,
libc::MAP_SHARED, file.as_raw_fd(), 0)
};
assert_ne!(m, libc::MAP_FAILED, "mmap failed");
let mut vec = vec![0u8; np];
let rc = unsafe { libc::mincore(m, len, vec.as_mut_ptr() as *mut _) };
assert_eq!(rc, 0, "mincore failed");
let res = vec.iter().filter(|b| *b & 1 == 1).count();
unsafe { libc::munmap(m, len) };
(res, np)
}
#[cfg(target_os = "linux")]
pub fn evict(path: &std::path::Path) {
use std::os::unix::io::AsRawFd;
let file = std::fs::File::open(path).unwrap();
unsafe {
libc::posix_fadvise(file.as_raw_fd(), 0, 0, libc::POSIX_FADV_DONTNEED);
}
}
pub fn bulky_log() -> Vec<u8> {
(0..300_000u32)
.flat_map(|i| format!("2026-08-24T00:00:00Z req {i} GET /path/{i}?q={i}\n").into_bytes())
.collect()
}
pub fn run_trg(args: &[&str]) -> (String, String, Option<i32>) {
use std::process::{Command, Stdio};
use std::sync::mpsc;
let child = Command::new(env!("CARGO_BIN_EXE_trg"))
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let (tx, rx) = mpsc::channel();
std::thread::spawn(move || {
let _ = tx.send(child.wait_with_output());
});
let out = rx
.recv_timeout(std::time::Duration::from_secs(60))
.expect("trg did not exit within 60s")
.unwrap();
(
String::from_utf8_lossy(&out.stdout).into_owned(),
String::from_utf8_lossy(&out.stderr).into_owned(),
out.status.code(),
)
}
pub fn match_then_binary() -> Vec<u8> {
let mut body = b"NEEDLE first\n".to_vec();
body.extend(std::iter::repeat_n(b'x', 320 * 1024));
body.push(b'\n');
body.extend_from_slice(&[0u8; 64]);
body.push(b'\n');
body
}