Skip to content

Commit

Permalink
cache: impl. smarter hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
xoviat committed Oct 24, 2023
1 parent 983d601 commit c03aaca
Showing 1 changed file with 46 additions and 17 deletions.
63 changes: 46 additions & 17 deletions teleprobe/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::path::PathBuf;

use anyhow::{bail, Context};
use futures::{stream, StreamExt};
use log::{error, info, warn};
use object::{Object, ObjectSection};
use orion::hash::digest;
use orion::hazardous::hash::blake2::blake2b::Blake2b;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use walkdir::WalkDir;
Expand Down Expand Up @@ -76,26 +76,27 @@ pub async fn main(cmd: Command) -> anyhow::Result<()> {
#[derive(Serialize, Deserialize, Default)]
struct Cache {
/// A map of file checksums that have passed the test.
files: HashMap<String, ()>,
files: HashSet<String>,
}

#[derive(Clone, Default, Debug)]
#[derive(Clone, Debug)]
struct ElfMetadata {
target: Option<String>,
timeout: Option<u64>,
}

impl ElfMetadata {
fn from_elf(elf: &[u8]) -> anyhow::Result<Self> {
let mut meta: ElfMetadata = Default::default();
fn from_elf(elf: &[u8]) -> anyhow::Result<(Self, Blake2b)> {
let mut target = None;
let mut timeout = None;

let obj_file = object::File::parse(elf)?;

if let Some(section) = obj_file.section_by_name(".teleprobe.target") {
let data = section.data()?;
if !data.is_empty() {
match String::from_utf8(data.to_vec()) {
Ok(s) => meta.target = Some(s),
Ok(s) => target = Some(s),
Err(_) => warn!(".teleprobe.target contents are not a valid utf8 string."),
}
}
Expand All @@ -104,13 +105,36 @@ impl ElfMetadata {
if let Some(section) = obj_file.section_by_name(".teleprobe.timeout") {
let data = section.data()?;
if data.len() == 4 {
meta.timeout = Some(u32::from_le_bytes(data.try_into().unwrap()) as u64)
timeout = Some(u32::from_le_bytes(data.try_into().unwrap()) as u64)
} else {
warn!(".teleprobe.timeout contents are not a valid u32.")
}
}

Ok(meta)
let mut hasher = Blake2b::new(32)?;
for section in &mut obj_file.sections() {
let section_name = match section.name() {
Ok(name) => name,
_ => continue,
};

if section_name == "" || section_name.starts_with(".debug_") {
continue;
}

let section_data = match section.data() {
Ok(data) => data,
_ => continue,
};

let section_address = section.address();

hasher.update(section_name.as_bytes())?;
hasher.update(section_data)?;
hasher.update(&section_address.to_le_bytes())?;
}

Ok((Self { target, timeout }, hasher))
}
}

Expand Down Expand Up @@ -214,18 +238,23 @@ async fn run(creds: &Credentials, cmd: RunCommand) -> anyhow::Result<()> {

for path in files {
let elf: Vec<u8> = std::fs::read(&path)?;
let hash = hex::encode(&digest(elf.as_slice()).unwrap());
let meta = ElfMetadata::from_elf(&elf)?;
let (meta, mut hasher) = ElfMetadata::from_elf(&elf)?;

let target = cmd
.target
.clone()
.or(meta.target)
.context("You have to either set --target, or embed it in the ELF using the `teleprobe-meta` crate.")?;

if before_cache.files.contains_key(&hash) {
hasher.update(target.as_bytes())?;
hasher.update(&meta.timeout.unwrap_or_default().to_le_bytes())?;

let digest = hasher.finalize()?;
let hash = hex::encode(&digest);

if before_cache.files.contains(&hash) {
skipped_jobs.push((target, path.clone()));
after_cache.files.insert(hash, ());
after_cache.files.insert(hash);

continue;
}
Expand All @@ -241,7 +270,7 @@ async fn run(creds: &Credentials, cmd: RunCommand) -> anyhow::Result<()> {

info!("Running {} jobs across {} targets...", job_count, jobs_by_target.len());

for (target, path) in skipped_jobs {
for (target, path) in &skipped_jobs {
info!("=== {} {}: SKIPPED", target, path.display());
}

Expand All @@ -257,12 +286,12 @@ async fn run(creds: &Credentials, cmd: RunCommand) -> anyhow::Result<()> {
.collect()
.await;

let mut succeeded = 0;
let mut failed = 0;
let mut succeeded = skipped_jobs.len();
let mut failed = 0usize;
for (r, hash) in results {
match r {
true => {
after_cache.files.insert(hash, ());
after_cache.files.insert(hash);

succeeded += 1
}
Expand Down

0 comments on commit c03aaca

Please sign in to comment.