proxmox-backup/src/rrd/cache.rs

107 lines
2.7 KiB
Rust
Raw Normal View History

2020-05-23 07:29:33 +00:00
use std::time::{SystemTime, UNIX_EPOCH};
use std::path::PathBuf;
use std::collections::HashMap;
use std::sync::{RwLock};
use anyhow::{format_err, Error};
use lazy_static::lazy_static;
2020-05-23 13:37:17 +00:00
use serde_json::{json, Value};
2020-05-23 07:29:33 +00:00
use proxmox::tools::fs::{create_path, CreateOptions};
use crate::api2::types::{RRDMode, RRDTimeFrameResolution};
2020-05-23 07:29:33 +00:00
use super::*;
const PBS_RRD_BASEDIR: &str = "/var/lib/proxmox-backup/rrdb";
lazy_static!{
static ref RRD_CACHE: RwLock<HashMap<String, RRD>> = {
RwLock::new(HashMap::new())
};
}
/// Create rrdd stat dir with correct permission
pub fn create_rrdb_dir() -> Result<(), Error> {
let backup_user = crate::backup::backup_user()?;
let opts = CreateOptions::new()
.owner(backup_user.uid)
.group(backup_user.gid);
create_path(PBS_RRD_BASEDIR, None, Some(opts))
.map_err(|err: Error| format_err!("unable to create rrdb stat dir - {}", err))?;
Ok(())
}
fn now() -> Result<f64, Error> {
let time = SystemTime::now().duration_since(UNIX_EPOCH)?;
Ok(time.as_secs_f64())
2020-05-23 07:29:33 +00:00
}
2020-05-24 14:51:28 +00:00
pub fn update_value(rel_path: &str, value: f64, dst: DST) -> Result<(), Error> {
2020-05-23 07:29:33 +00:00
let mut path = PathBuf::from(PBS_RRD_BASEDIR);
path.push(rel_path);
std::fs::create_dir_all(path.parent().unwrap())?;
let mut map = RRD_CACHE.write().unwrap();
let now = now()?;
2020-05-23 07:29:33 +00:00
if let Some(rrd) = map.get_mut(rel_path) {
rrd.update(now, value);
rrd.save(&path)?;
} else {
let mut rrd = match RRD::load(&path) {
Ok(rrd) => rrd,
2020-05-24 14:51:28 +00:00
Err(_) => RRD::new(dst),
2020-05-23 07:29:33 +00:00
};
rrd.update(now, value);
rrd.save(&path)?;
map.insert(rel_path.into(), rrd);
}
2020-05-23 07:29:33 +00:00
Ok(())
}
pub fn extract_data(
base: &str,
items: &[&str],
timeframe: RRDTimeFrameResolution,
mode: RRDMode,
) -> Result<Value, Error> {
let now = now()?;
let map = RRD_CACHE.read().unwrap();
2020-05-23 13:37:17 +00:00
let mut result = Vec::new();
for name in items.iter() {
2020-05-24 14:51:28 +00:00
let rrd = match map.get(&format!("{}/{}", base, name)) {
Some(rrd) => rrd,
None => continue,
};
2020-05-23 13:37:17 +00:00
let (start, reso, list) = rrd.extract_data(now, timeframe, mode);
let mut t = start;
for index in 0..RRD_DATA_ENTRIES {
if result.len() <= index {
if let Some(value) = list[index] {
result.push(json!({ "time": t, *name: value }));
} else {
result.push(json!({ "time": t }));
}
} else {
if let Some(value) = list[index] {
result[index][name] = value.into();
}
}
t += reso;
}
}
2020-05-23 13:37:17 +00:00
Ok(result.into())
}