use crate::span::Span;
use anyhow::Context;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::path::Path;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Session {
pub epoch_unix_us: i64,
pub track_t0_us: BTreeMap<String, i64>,
pub track_pid: BTreeMap<String, i64>,
#[serde(default)]
next_pid: i64,
}
impl Session {
pub fn load_or_new(trace_path: &Path) -> anyhow::Result<Self> {
let sidecar = sidecar_path(trace_path);
if sidecar.exists() {
let bytes = std::fs::read(&sidecar)
.with_context(|| format!("reading session sidecar {}", sidecar.display()))?;
let session: Session = serde_json::from_slice(&bytes)
.with_context(|| format!("parsing session sidecar {}", sidecar.display()))?;
Ok(session)
} else {
let epoch_unix_us = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("system clock before Unix epoch")
.as_micros() as i64;
Ok(Session {
epoch_unix_us,
..Default::default()
})
}
}
pub fn save(&self, trace_path: &Path) -> anyhow::Result<()> {
let sidecar = sidecar_path(trace_path);
let bytes = serde_json::to_vec_pretty(self)?;
std::fs::write(&sidecar, bytes)
.with_context(|| format!("writing session sidecar {}", sidecar.display()))
}
pub fn record_start(&mut self, track: &str, wall_clock_unix_us: i64) {
self.track_t0_us
.insert(track.to_string(), wall_clock_unix_us - self.epoch_unix_us);
}
pub fn pid_for(&mut self, track: &str) -> i64 {
if let Some(&pid) = self.track_pid.get(track) {
return pid;
}
let pid = self.next_pid;
self.next_pid += 1;
self.track_pid.insert(track.to_string(), pid);
pid
}
pub fn is_new_track(&self, track: &str) -> bool {
!self.track_pid.contains_key(track)
}
pub fn place(&self, spans: &mut [Span]) {
for s in spans {
if let Some(&t0) = self.track_t0_us.get(&s.track) {
s.start_us += t0;
}
}
}
}
fn sidecar_path(trace_path: &Path) -> std::path::PathBuf {
let mut s = trace_path.as_os_str().to_os_string();
s.push(".session");
std::path::PathBuf::from(s)
}