Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

holperf/src/seed.rs

//! Seed one store per format: the same package count, the same small and large
//! artifact sizes, a sealed znippy archive on the same disk (/home on oden).

use std::path::{Path, PathBuf};
use std::sync::Arc;

use anyhow::Result;
use traits::RepositoryBackendTrait;
use znippy_common::plugin::PluginRegistry;

use crate::gen;
use crate::harness::Scenario;

pub type Open = Box<dyn Fn() -> Arc<dyn RepositoryBackendTrait> + Send + Sync>;

/// Write `files` under `dir/src`, pack into `dir/store.znippy` (once; reused).
pub fn pack(
    dir: &Path,
    files: impl FnOnce() -> Vec<(String, Vec<u8>)>,
    plugin: Option<PluginRegistry>,
) -> Result<PathBuf> {
    let archive = dir.join("store.znippy");
    if archive.exists() {
        return Ok(archive);
    }
    let src = dir.join("src");
    let _ = std::fs::remove_dir_all(&src);
    for (p, b) in files() {
        let f = src.join(&p);
        std::fs::create_dir_all(f.parent().unwrap())?;
        std::fs::write(f, b)?;
    }
    std::fs::create_dir_all(dir)?;
    znippy_compress::compress_dir(&src, &archive, false, plugin.as_ref(), None, None)?;
    std::fs::remove_dir_all(&src)?;
    Ok(archive)
}

fn name(i: usize) -> String {
    format!("pkg{i:05}")
}

/// The index requests cycle over these packages.
fn picks(n: usize) -> Vec<usize> {
    (0..64).map(|k| (k * 7919) % n).collect()
}

pub fn want(only: Option<&[String]>, f: &str) -> bool {
    only.is_none_or(|o| o.iter().any(|x| x == f))
}

pub fn all(
    root: &Path,
    n: usize,
    small: usize,
    large: usize,
    only: Option<&[String]>,
) -> Result<Vec<Scenario>> {
    let mut v = Vec::new();
    let vers = ["1.0.0", "1.1.0"];

    // ── Rust (sealed archive, the "drift" path) ──
    if want(only, "rust") {
        let dir = root.join(format!("rust-{n}"));
        let a = pack(
            &dir,
            || {
                let mut f = Vec::new();
                for i in 0..n {
                    for (j, ver) in vers.iter().enumerate() {
                        f.push((
                            format!("{}-{ver}.crate", name(i)),
                            gen::crate_file(&name(i), ver, small, (i * 2 + j) as u64),
                        ));
                    }
                }
                f.push((
                    "bigpkg-1.0.0.crate".into(),
                    gen::crate_file("bigpkg", "1.0.0", large, 7),
                ));
                f
            },
            None,
        )?;
        let open: Open = Box::new(move || {
            Arc::new(r_rust::RustRepoZnippy::with_archive("rust".into(), a.clone()).unwrap())
        });
        v.push(Scenario {
            format: "rust",
            route: "rust".into(),
            open,
            dir,
            index: picks(n)
                .iter()
                .map(|&i| format!("/rust/index/pk/g0/{}", name(i)))
                .collect(),
            meta2: vec!["/rust/index/config.json".into()],
            small: picks(n)
                .iter()
                .map(|&i| format!("/rust/crates/{}/1.0.0/download", name(i)))
                .collect(),
            large: vec!["/rust/crates/bigpkg/1.0.0/download".into()],
            small_size: small as u64,
            large_size: large as u64,
            packages: n,
        });
    }

    // ── Rust writable (HotArchive, the /cache + /sparring path), seeded by put ──
    if want(only, "rust-hot") {
        let dir = root.join(format!("rusthot-{n}"));
        let a = dir.join("hot.znippy");
        if !a.exists() {
            std::fs::create_dir_all(&dir)?;
            let r = r_rust::RustRepoZnippy::with_writable_archive("rusthot".into(), a.clone());
            for i in 0..n {
                for (j, ver) in vers.iter().enumerate() {
                    let id = traits::ArtifactId {
                        namespace: None,
                        name: name(i),
                        version: (*ver).into(),
                    };
                    r.put(
                        &id,
                        &gen::crate_file(&name(i), ver, small, (i * 2 + j) as u64),
                    )?;
                }
            }
            let id = traits::ArtifactId {
                namespace: None,
                name: "bigpkg".into(),
                version: "1.0.0".into(),
            };
            r.put(&id, &gen::crate_file("bigpkg", "1.0.0", large, 7))?;
        }
        let open: Open = Box::new(move || {
            Arc::new(r_rust::RustRepoZnippy::with_writable_archive(
                "rusthot".into(),
                a.clone(),
            ))
        });
        v.push(Scenario {
            format: "rust-hot",
            route: "rusthot".into(),
            open,
            dir,
            index: picks(n)
                .iter()
                .map(|&i| format!("/rusthot/index/pk/g0/{}", name(i)))
                .collect(),
            meta2: vec![],
            small: picks(n)
                .iter()
                .map(|&i| format!("/rusthot/crates/{}/1.0.0/download", name(i)))
                .collect(),
            large: vec!["/rusthot/crates/bigpkg/1.0.0/download".into()],
            small_size: small as u64,
            large_size: large as u64,
            packages: n,
        });
    }

    // ── Python / pip (PEP 503 + 691) ──
    if want(only, "pip") {
        let dir = root.join(format!("pip-{n}"));
        let a = pack(
            &dir,
            || {
                let mut f = Vec::new();
                for i in 0..n {
                    for (j, ver) in vers.iter().enumerate() {
                        f.push((
                            format!("packages/{0}/{0}-{ver}-py3-none-any.whl", name(i)),
                            gen::wheel(&name(i), ver, small, (i * 2 + j) as u64),
                        ));
                    }
                }
                f.push((
                    "packages/bigpkg/bigpkg-1.0.0-py3-none-any.whl".into(),
                    gen::wheel("bigpkg", "1.0.0", large, 7),
                ));
                f
            },
            None,
        )?;
        let open: Open = Box::new(move || {
            Arc::new(r_python::PipRepoZnippy::with_archive("pypi".into(), a.clone()).unwrap())
        });
        v.push(Scenario {
            format: "pip",
            route: "pypi".into(),
            open,
            dir,
            index: picks(n)
                .iter()
                .map(|&i| format!("/pypi/simple/{}/", name(i)))
                .collect(),
            meta2: vec!["/pypi/simple/".into()],
            small: picks(n)
                .iter()
                .map(|&i| format!("/pypi/packages/{0}/{0}-1.0.0-py3-none-any.whl", name(i)))
                .collect(),
            large: vec!["/pypi/packages/bigpkg/bigpkg-1.0.0-py3-none-any.whl".into()],
            small_size: small as u64,
            large_size: large as u64,
            packages: n,
        });
    }

    // ── Maven (no typed view: the chain-view live path) and Maven with the plugin view ──
    for (fmt, plugin) in [("maven", false), ("maven-view", true)] {
        if !want(only, fmt) {
            continue;
        }
        let dir = root.join(format!("{fmt}-{n}"));
        let reg = plugin
            .then(|| PluginRegistry::with_plugin(Box::new(znippy_plugin_maven::NativeMavenPlugin)));
        let a = pack(
            &dir,
            || {
                let mut f = Vec::new();
                for i in 0..n {
                    for (j, ver) in vers.iter().enumerate() {
                        let base = format!("org/bench/{0}/{ver}/{0}-{ver}", name(i));
                        f.push((
                            format!("{base}.jar"),
                            gen::jar("org.bench", &name(i), ver, small, (i * 2 + j) as u64),
                        ));
                        f.push((
                            format!("{base}.pom"),
                            gen::pom("org.bench", &name(i), ver).into_bytes(),
                        ));
                    }
                }
                f.push((
                    "org/bench/bigpkg/1.0.0/bigpkg-1.0.0.jar".into(),
                    gen::jar("org.bench", "bigpkg", "1.0.0", large, 7),
                ));
                f.push((
                    "org/bench/bigpkg/1.0.0/bigpkg-1.0.0.pom".into(),
                    gen::pom("org.bench", "bigpkg", "1.0.0").into_bytes(),
                ));
                f
            },
            reg,
        )?;
        let open: Open = Box::new(move || {
            Arc::new(r_maven::MavenRepoZnippy::with_archive("maven".into(), a.clone()).unwrap())
        });
        v.push(Scenario {
            format: fmt,
            route: "maven".into(),
            open,
            dir,
            index: picks(n)
                .iter()
                .map(|&i| format!("/maven/org/bench/{}/maven-metadata.xml", name(i)))
                .collect(),
            meta2: picks(n)
                .iter()
                .map(|&i| format!("/maven/org/bench/{0}/1.0.0/{0}-1.0.0.jar.sha1", name(i)))
                .collect(),
            small: picks(n)
                .iter()
                .map(|&i| format!("/maven/org/bench/{0}/1.0.0/{0}-1.0.0.jar", name(i)))
                .collect(),
            large: vec!["/maven/org/bench/bigpkg/1.0.0/bigpkg-1.0.0.jar".into()],
            small_size: small as u64,
            large_size: large as u64,
            packages: n,
        });
    }

    // ── npm (packument needs the typed view: NpmPlugin) ──
    if want(only, "npm") {
        let dir = root.join(format!("npm-{n}"));
        let reg = PluginRegistry::with_plugin(Box::new(
            znippy_common::plugins::native::npm_native::NpmPlugin,
        ));
        let a = pack(
            &dir,
            || {
                let mut f = Vec::new();
                for i in 0..n {
                    for (j, ver) in vers.iter().enumerate() {
                        f.push((
                            format!("{0}/-/{0}-{ver}.tgz", name(i)),
                            gen::npm_tgz(&name(i), ver, small, (i * 2 + j) as u64),
                        ));
                    }
                }
                f.push((
                    "bigpkg/-/bigpkg-1.0.0.tgz".into(),
                    gen::npm_tgz("bigpkg", "1.0.0", large, 7),
                ));
                f
            },
            Some(reg),
        )?;
        let open: Open = Box::new(move || {
            Arc::new(r_npm::NpmRepoZnippy::with_archive("npm".into(), a.clone()).unwrap())
        });
        v.push(Scenario {
            format: "npm",
            route: "npm".into(),
            open,
            dir,
            index: picks(n)
                .iter()
                .map(|&i| format!("/npm/{}", name(i)))
                .collect(),
            meta2: vec!["/npm/bigpkg".into()],
            small: picks(n)
                .iter()
                .map(|&i| format!("/npm/{0}/-/{0}-1.0.0.tgz", name(i)))
                .collect(),
            large: vec!["/npm/bigpkg/-/bigpkg-1.0.0.tgz".into()],
            small_size: small as u64,
            large_size: large as u64,
            packages: n,
        });
    }

    // ── Go (GOPROXY) ──
    if want(only, "go") {
        let dir = root.join(format!("go-{n}"));
        let a = pack(
            &dir,
            || {
                let mut f = Vec::new();
                let mut add = |m: &str, ver: &str, size: usize, seed: u64| {
                    f.push((format!("{m}/@v/{ver}.zip"), gen::go_zip(m, ver, size, seed)));
                    f.push((
                        format!("{m}/@v/{ver}.mod"),
                        format!("module {m}\n").into_bytes(),
                    ));
                    f.push((
                        format!("{m}/@v/{ver}.info"),
                        format!("{{\"Version\":\"{ver}\",\"Time\":\"2026-01-01T00:00:00Z\"}}")
                            .into_bytes(),
                    ));
                };
                for i in 0..n {
                    for (j, ver) in ["v1.0.0", "v1.1.0"].iter().enumerate() {
                        add(
                            &format!("example.com/m/{}", name(i)),
                            ver,
                            small,
                            (i * 2 + j) as u64,
                        );
                    }
                }
                add("example.com/m/bigpkg", "v1.0.0", large, 7);
                f
            },
            None,
        )?;
        let open: Open = Box::new(move || {
            Arc::new(r_go::GoRepoZnippy::with_archive("go".into(), a.clone()).unwrap())
        });
        v.push(Scenario {
            format: "go",
            route: "go".into(),
            open,
            dir,
            index: picks(n)
                .iter()
                .map(|&i| format!("/go/example.com/m/{}/@v/list", name(i)))
                .collect(),
            meta2: picks(n)
                .iter()
                .map(|&i| format!("/go/example.com/m/{}/@v/v1.0.0.info", name(i)))
                .collect(),
            small: picks(n)
                .iter()
                .map(|&i| format!("/go/example.com/m/{}/@v/v1.0.0.zip", name(i)))
                .collect(),
            large: vec!["/go/example.com/m/bigpkg/@v/v1.0.0.zip".into()],
            small_size: small as u64,
            large_size: large as u64,
            packages: n,
        });
    }

    crate::seed2::more(root, n, small, large, only, &mut v)?;
    Ok(v)
}