20260407 & 20260408 基于cir 三方replay对齐,并且materialize 使用hard link优化
This commit is contained in:
79
src/bin/cir_extract_inputs.rs
Normal file
79
src/bin/cir_extract_inputs.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn usage() -> &'static str {
|
||||
"Usage: cir_extract_inputs --cir <path> --tals-dir <path> --meta-json <path>"
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(err) = run(std::env::args().collect()) {
|
||||
eprintln!("error: {err}");
|
||||
std::process::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
fn run(argv: Vec<String>) -> Result<(), String> {
|
||||
let mut cir_path: Option<PathBuf> = None;
|
||||
let mut tals_dir: Option<PathBuf> = None;
|
||||
let mut meta_json: Option<PathBuf> = None;
|
||||
|
||||
let mut i = 1usize;
|
||||
while i < argv.len() {
|
||||
match argv[i].as_str() {
|
||||
"--help" | "-h" => return Err(usage().to_string()),
|
||||
"--cir" => {
|
||||
i += 1;
|
||||
cir_path = Some(PathBuf::from(argv.get(i).ok_or("--cir requires a value")?));
|
||||
}
|
||||
"--tals-dir" => {
|
||||
i += 1;
|
||||
tals_dir = Some(PathBuf::from(argv.get(i).ok_or("--tals-dir requires a value")?));
|
||||
}
|
||||
"--meta-json" => {
|
||||
i += 1;
|
||||
meta_json = Some(PathBuf::from(argv.get(i).ok_or("--meta-json requires a value")?));
|
||||
}
|
||||
other => return Err(format!("unknown argument: {other}\n\n{}", usage())),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let cir_path = cir_path.ok_or_else(|| format!("--cir is required\n\n{}", usage()))?;
|
||||
let tals_dir = tals_dir.ok_or_else(|| format!("--tals-dir is required\n\n{}", usage()))?;
|
||||
let meta_json = meta_json.ok_or_else(|| format!("--meta-json is required\n\n{}", usage()))?;
|
||||
|
||||
let bytes = std::fs::read(&cir_path)
|
||||
.map_err(|e| format!("read CIR failed: {}: {e}", cir_path.display()))?;
|
||||
let cir = rpki::cir::decode_cir(&bytes).map_err(|e| e.to_string())?;
|
||||
|
||||
std::fs::create_dir_all(&tals_dir)
|
||||
.map_err(|e| format!("create tals dir failed: {}: {e}", tals_dir.display()))?;
|
||||
|
||||
let mut tal_files = Vec::new();
|
||||
for (idx, tal) in cir.tals.iter().enumerate() {
|
||||
let filename = format!("tal-{:03}.tal", idx + 1);
|
||||
let path = tals_dir.join(filename);
|
||||
std::fs::write(&path, &tal.tal_bytes)
|
||||
.map_err(|e| format!("write TAL failed: {}: {e}", path.display()))?;
|
||||
tal_files.push(serde_json::json!({
|
||||
"talUri": tal.tal_uri,
|
||||
"path": path,
|
||||
}));
|
||||
}
|
||||
|
||||
let validation_time = cir
|
||||
.validation_time
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.map_err(|e| format!("format validationTime failed: {e}"))?;
|
||||
let meta = serde_json::json!({
|
||||
"validationTime": validation_time,
|
||||
"talFiles": tal_files,
|
||||
});
|
||||
if let Some(parent) = meta_json.parent() {
|
||||
std::fs::create_dir_all(parent)
|
||||
.map_err(|e| format!("create meta parent failed: {}: {e}", parent.display()))?;
|
||||
}
|
||||
std::fs::write(&meta_json, serde_json::to_vec_pretty(&meta).unwrap())
|
||||
.map_err(|e| format!("write meta json failed: {}: {e}", meta_json.display()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
77
src/bin/cir_materialize.rs
Normal file
77
src/bin/cir_materialize.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn usage() -> &'static str {
|
||||
"Usage: cir_materialize --cir <path> --static-root <path> --mirror-root <path> [--keep-db]"
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(err) = run(std::env::args().collect()) {
|
||||
eprintln!("error: {err}");
|
||||
std::process::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
fn run(argv: Vec<String>) -> Result<(), String> {
|
||||
let mut cir_path: Option<PathBuf> = None;
|
||||
let mut static_root: Option<PathBuf> = None;
|
||||
let mut mirror_root: Option<PathBuf> = None;
|
||||
let mut keep_db = false;
|
||||
|
||||
let mut i = 1usize;
|
||||
while i < argv.len() {
|
||||
match argv[i].as_str() {
|
||||
"--help" | "-h" => return Err(usage().to_string()),
|
||||
"--cir" => {
|
||||
i += 1;
|
||||
cir_path = Some(PathBuf::from(argv.get(i).ok_or("--cir requires a value")?));
|
||||
}
|
||||
"--static-root" => {
|
||||
i += 1;
|
||||
static_root = Some(PathBuf::from(
|
||||
argv.get(i).ok_or("--static-root requires a value")?,
|
||||
));
|
||||
}
|
||||
"--mirror-root" => {
|
||||
i += 1;
|
||||
mirror_root = Some(PathBuf::from(
|
||||
argv.get(i).ok_or("--mirror-root requires a value")?,
|
||||
));
|
||||
}
|
||||
"--keep-db" => keep_db = true,
|
||||
other => return Err(format!("unknown argument: {other}\n\n{}", usage())),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let cir_path = cir_path.ok_or_else(|| format!("--cir is required\n\n{}", usage()))?;
|
||||
let static_root =
|
||||
static_root.ok_or_else(|| format!("--static-root is required\n\n{}", usage()))?;
|
||||
let mirror_root =
|
||||
mirror_root.ok_or_else(|| format!("--mirror-root is required\n\n{}", usage()))?;
|
||||
|
||||
let bytes = std::fs::read(&cir_path)
|
||||
.map_err(|e| format!("read CIR failed: {}: {e}", cir_path.display()))?;
|
||||
let cir = rpki::cir::decode_cir(&bytes).map_err(|e| e.to_string())?;
|
||||
|
||||
let result = rpki::cir::materialize_cir(&cir, &static_root, &mirror_root, true);
|
||||
match result {
|
||||
Ok(summary) => {
|
||||
eprintln!(
|
||||
"materialized CIR: mirror={} objects={} linked={} copied={} keep_db={}",
|
||||
mirror_root.display(),
|
||||
summary.object_count,
|
||||
summary.linked_files,
|
||||
summary.copied_files,
|
||||
keep_db
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
if !keep_db && mirror_root.exists() {
|
||||
let _ = std::fs::remove_dir_all(&mirror_root);
|
||||
}
|
||||
Err(err.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
108
src/bin/repository_view_stats.rs
Normal file
108
src/bin/repository_view_stats.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
use rocksdb::{DB, IteratorMode, Options};
|
||||
use rpki::storage::{column_family_descriptors, CF_REPOSITORY_VIEW};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn usage() -> String {
|
||||
let bin = "repository_view_stats";
|
||||
format!(
|
||||
"\
|
||||
Usage:
|
||||
{bin} --db <path>
|
||||
|
||||
Options:
|
||||
--db <path> RocksDB directory
|
||||
--help Show this help
|
||||
"
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_args(argv: &[String]) -> Result<PathBuf, String> {
|
||||
if argv.iter().any(|arg| arg == "--help" || arg == "-h") {
|
||||
return Err(usage());
|
||||
}
|
||||
let mut db_path: Option<PathBuf> = None;
|
||||
let mut i = 1usize;
|
||||
while i < argv.len() {
|
||||
match argv[i].as_str() {
|
||||
"--db" => {
|
||||
i += 1;
|
||||
let value = argv.get(i).ok_or("--db requires a value")?;
|
||||
db_path = Some(PathBuf::from(value));
|
||||
}
|
||||
other => return Err(format!("unknown argument: {other}\n\n{}", usage())),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
db_path.ok_or_else(|| format!("--db is required\n\n{}", usage()))
|
||||
}
|
||||
|
||||
fn dir_size(path: &Path) -> Result<u64, Box<dyn std::error::Error>> {
|
||||
let mut total = 0u64;
|
||||
for entry in fs::read_dir(path)? {
|
||||
let entry = entry?;
|
||||
let file_type = entry.file_type()?;
|
||||
if file_type.is_file() {
|
||||
total = total.saturating_add(entry.metadata()?.len());
|
||||
} else if file_type.is_dir() {
|
||||
total = total.saturating_add(dir_size(&entry.path())?);
|
||||
}
|
||||
}
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let argv: Vec<String> = std::env::args().collect();
|
||||
let db_path = parse_args(&argv).map_err(|e| -> Box<dyn std::error::Error> { e.into() })?;
|
||||
|
||||
let mut opts = Options::default();
|
||||
opts.create_if_missing(false);
|
||||
opts.create_missing_column_families(false);
|
||||
let db = DB::open_cf_descriptors(&opts, &db_path, column_family_descriptors())?;
|
||||
let cf = db
|
||||
.cf_handle(CF_REPOSITORY_VIEW)
|
||||
.ok_or("missing repository_view column family")?;
|
||||
|
||||
let mut kv_count = 0u64;
|
||||
let mut key_bytes_total = 0u64;
|
||||
let mut value_bytes_total = 0u64;
|
||||
let mut max_key_bytes = 0usize;
|
||||
let mut max_value_bytes = 0usize;
|
||||
|
||||
for entry in db.iterator_cf(cf, IteratorMode::Start) {
|
||||
let (key, value) = entry?;
|
||||
kv_count += 1;
|
||||
key_bytes_total += key.len() as u64;
|
||||
value_bytes_total += value.len() as u64;
|
||||
max_key_bytes = max_key_bytes.max(key.len());
|
||||
max_value_bytes = max_value_bytes.max(value.len());
|
||||
}
|
||||
|
||||
let logical_total_bytes = key_bytes_total + value_bytes_total;
|
||||
let avg_key_bytes = if kv_count > 0 {
|
||||
key_bytes_total as f64 / kv_count as f64
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let avg_value_bytes = if kv_count > 0 {
|
||||
value_bytes_total as f64 / kv_count as f64
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let out = serde_json::json!({
|
||||
"db_path": db_path.display().to_string(),
|
||||
"column_family": CF_REPOSITORY_VIEW,
|
||||
"kv_count": kv_count,
|
||||
"key_bytes_total": key_bytes_total,
|
||||
"value_bytes_total": value_bytes_total,
|
||||
"logical_total_bytes": logical_total_bytes,
|
||||
"db_dir_on_disk_bytes": dir_size(&db_path)?,
|
||||
"avg_key_bytes": avg_key_bytes,
|
||||
"avg_value_bytes": avg_value_bytes,
|
||||
"max_key_bytes": max_key_bytes,
|
||||
"max_value_bytes": max_value_bytes,
|
||||
});
|
||||
println!("{}", serde_json::to_string_pretty(&out)?);
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user