optimize zfs

This commit is contained in:
Robin Appelman 2021-03-27 23:27:40 +01:00
commit 5544b9984a
3 changed files with 67 additions and 40 deletions

View file

@ -1,5 +1,7 @@
use iai::black_box; use iai::black_box;
use palantir::get_metrics; use palantir::get_metrics;
use palantir::heim::temperatures;
use palantir::zfs::pools;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
fn iai_get_metrics() -> String { fn iai_get_metrics() -> String {
@ -7,4 +9,13 @@ fn iai_get_metrics() -> String {
rt.block_on(async { black_box(get_metrics().await.unwrap()) }) rt.block_on(async { black_box(get_metrics().await.unwrap()) })
} }
iai::main!(iai_get_metrics); fn iai_zfs_pool() {
black_box(pools().collect::<Vec<_>>());
}
fn iai_temperatures() {
let rt = Runtime::new().unwrap();
rt.block_on(async { black_box(temperatures().await).unwrap() });
}
iai::main!(iai_get_metrics, iai_zfs_pool, iai_temperatures);

View file

@ -1,27 +1,17 @@
pub(crate) mod heim; pub mod heim;
mod zfs; pub mod zfs;
use crate::heim::*; use crate::heim::*;
use crate::zfs::pools; use crate::zfs::pools;
use color_eyre::Result; use color_eyre::Result;
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
use futures_util::{pin_mut, try_join}; use futures_util::{pin_mut, try_join};
use std::collections::{HashMap, HashSet}; use std::collections::HashSet;
use std::fmt::Write; use std::fmt::Write;
pub async fn get_metrics() -> Result<String> { pub async fn get_metrics() -> Result<String> {
let (hostname, pools, cpu, memory, network, temperatures, disks, disk_usage): ( let (hostname, cpu, memory, network, temperatures, disks, disk_usage) = try_join! {
String,
Vec<DiskUsage>,
f64,
Memory,
_,
HashMap<TemperatureLabel, f32>,
_,
_,
) = try_join! {
hostname(), hostname(),
pools(),
cpu_time(), cpu_time(),
memory(), memory(),
network_stats(), network_stats(),
@ -29,6 +19,7 @@ pub async fn get_metrics() -> Result<String> {
disk_stats(), disk_stats(),
disk_usage(), disk_usage(),
}?; }?;
let pools = pools();
pin_mut!(network); pin_mut!(network);
pin_mut!(disks); pin_mut!(disks);
pin_mut!(disk_usage); pin_mut!(disk_usage);

View file

@ -1,31 +1,56 @@
use crate::heim::DiskUsage; use crate::heim::DiskUsage;
use color_eyre::Result; use color_eyre::Result;
use std::process::Command; use std::process::Command;
use tokio::task::spawn_blocking;
pub async fn pools() -> Result<Vec<DiskUsage>> { pub fn pools() -> impl Iterator<Item = DiskUsage> {
spawn_blocking(move || { OutputParser {
str: zpool_command().unwrap_or_default(),
pos: 0,
}
}
fn zpool_command() -> Result<String> {
let mut z = Command::new("zpool"); let mut z = Command::new("zpool");
z.args(&["list", "-p", "-H", "-o", "name,size,free"]); z.args(&["list", "-p", "-H", "-o", "name,size,free"]);
let out = match z.output() { let out = z.output()?;
Ok(out) => out,
Err(_) => return Ok(Vec::new()),
};
if out.status.success() { if out.status.success() {
let output = String::from_utf8(out.stdout)?; Ok(String::from_utf8(out.stdout)?)
Ok(output } else {
.lines() Ok(String::new())
.flat_map(|line| { }
}
fn parse_line(line: &str) -> Option<DiskUsage> {
let mut parts = line.split_ascii_whitespace(); let mut parts = line.split_ascii_whitespace();
let name = parts.next()?.to_string(); let name = parts.next()?.to_string();
let size = parts.next()?.parse().ok()?; let size = parts.next()?.parse().ok()?;
let free = parts.next()?.parse().ok()?; let free = parts.next()?.parse().ok()?;
Some(DiskUsage { name, size, free }) Some(DiskUsage { name, size, free })
})
.collect())
} else {
Ok(Vec::new())
} }
})
.await? struct OutputParser {
str: String,
pos: usize,
}
impl Iterator for OutputParser {
type Item = DiskUsage;
fn next(&mut self) -> Option<Self::Item> {
let str = self.str.as_str();
let line = match str[self.pos..].find('\n') {
Some(next_pos) => {
let old_pos = self.pos;
self.pos += next_pos;
Some(&str[old_pos..self.pos])
}
None if self.pos < str.len() => {
let old_pos = self.pos;
self.pos = str.len();
Some(&str[old_pos..])
}
None => None,
};
line.and_then(parse_line)
}
} }