proxmox-rrd: improve developer docs
This commit is contained in:
parent
dbc42e6f75
commit
0191759316
|
@ -8,7 +8,7 @@ use proxmox::tools::fs::{create_path, CreateOptions};
|
||||||
|
|
||||||
use proxmox_rrd_api_types::{RRDMode, RRDTimeFrameResolution};
|
use proxmox_rrd_api_types::{RRDMode, RRDTimeFrameResolution};
|
||||||
|
|
||||||
use super::*;
|
use crate::{DST, rrd::RRD};
|
||||||
|
|
||||||
/// RRD cache - keep RRD data in RAM, but write updates to disk
|
/// RRD cache - keep RRD data in RAM, but write updates to disk
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,5 +1,21 @@
|
||||||
mod rrd;
|
//! # Simple Round Robin Database files with fixed format
|
||||||
pub use rrd::*;
|
//!
|
||||||
|
//! ## Features
|
||||||
|
//!
|
||||||
|
//! * One file stores a single data source
|
||||||
|
//! * Small/constant file size (6008 bytes)
|
||||||
|
//! * Stores avarage and maximum values
|
||||||
|
//! * Stores data for different time resolution ([RRDTimeFrameResolution](proxmox_rrd_api_types::RRDTimeFrameResolution))
|
||||||
|
|
||||||
|
pub mod rrd;
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
pub use cache::*;
|
pub use cache::*;
|
||||||
|
|
||||||
|
/// RRD data source tyoe
|
||||||
|
pub enum DST {
|
||||||
|
/// Gauge values are stored unmodified.
|
||||||
|
Gauge,
|
||||||
|
/// Stores the difference to the previous value.
|
||||||
|
Derive,
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
//! # Round Robin Database file format
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
|
||||||
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
||||||
|
|
||||||
|
@ -14,10 +17,11 @@ pub const RRD_DATA_ENTRIES: usize = 70;
|
||||||
// openssl::sha::sha256(b"Proxmox Round Robin Database file v1.0")[0..8];
|
// openssl::sha::sha256(b"Proxmox Round Robin Database file v1.0")[0..8];
|
||||||
pub const PROXMOX_RRD_MAGIC_1_0: [u8; 8] = [206, 46, 26, 212, 172, 158, 5, 186];
|
pub const PROXMOX_RRD_MAGIC_1_0: [u8; 8] = [206, 46, 26, 212, 172, 158, 5, 186];
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use crate::DST;
|
||||||
|
|
||||||
bitflags!{
|
bitflags!{
|
||||||
struct RRAFlags: u64 {
|
/// Flags to specify the data soure type and consolidation function
|
||||||
|
pub struct RRAFlags: u64 {
|
||||||
// Data Source Types
|
// Data Source Types
|
||||||
const DST_GAUGE = 1;
|
const DST_GAUGE = 1;
|
||||||
const DST_DERIVE = 2;
|
const DST_DERIVE = 2;
|
||||||
|
@ -31,20 +35,24 @@ bitflags!{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RRD data source tyoe
|
/// Round Robin Archive with [RRD_DATA_ENTRIES] data slots.
|
||||||
pub enum DST {
|
///
|
||||||
Gauge,
|
/// This data structure is used inside [RRD] and directly written to the
|
||||||
Derive,
|
/// RRD files.
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct RRA {
|
pub struct RRA {
|
||||||
flags: RRAFlags,
|
/// Defined the data soure type and consolidation function
|
||||||
resolution: u64,
|
pub flags: RRAFlags,
|
||||||
last_update: f64,
|
/// Resulution (seconds) from [RRDTimeFrameResolution]
|
||||||
last_count: u64,
|
pub resolution: u64,
|
||||||
counter_value: f64, // used for derive/counters
|
/// Last update time (epoch)
|
||||||
data: [f64; RRD_DATA_ENTRIES],
|
pub last_update: f64,
|
||||||
|
/// Count values computed inside this update interval
|
||||||
|
pub last_count: u64,
|
||||||
|
/// Stores the last value, used to compute differential value for derive/counters
|
||||||
|
pub counter_value: f64,
|
||||||
|
/// Data slots
|
||||||
|
pub data: [f64; RRD_DATA_ENTRIES],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RRA {
|
impl RRA {
|
||||||
|
@ -157,24 +165,37 @@ impl RRA {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Round Robin Database file format with fixed number of [RRA]s
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
// Note: Avoid alignment problems by using 8byte types only
|
// Note: Avoid alignment problems by using 8byte types only
|
||||||
pub struct RRD {
|
pub struct RRD {
|
||||||
magic: [u8; 8],
|
/// The magic number to identify the file type
|
||||||
hour_avg: RRA,
|
pub magic: [u8; 8],
|
||||||
hour_max: RRA,
|
/// Hourly data (average values)
|
||||||
day_avg: RRA,
|
pub hour_avg: RRA,
|
||||||
day_max: RRA,
|
/// Hourly data (maximum values)
|
||||||
week_avg: RRA,
|
pub hour_max: RRA,
|
||||||
week_max: RRA,
|
/// Dayly data (average values)
|
||||||
month_avg: RRA,
|
pub day_avg: RRA,
|
||||||
month_max: RRA,
|
/// Dayly data (maximum values)
|
||||||
year_avg: RRA,
|
pub day_max: RRA,
|
||||||
year_max: RRA,
|
/// Weekly data (average values)
|
||||||
|
pub week_avg: RRA,
|
||||||
|
/// Weekly data (maximum values)
|
||||||
|
pub week_max: RRA,
|
||||||
|
/// Monthly data (average values)
|
||||||
|
pub month_avg: RRA,
|
||||||
|
/// Monthly data (maximum values)
|
||||||
|
pub month_max: RRA,
|
||||||
|
/// Yearly data (average values)
|
||||||
|
pub year_avg: RRA,
|
||||||
|
/// Yearly data (maximum values)
|
||||||
|
pub year_max: RRA,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RRD {
|
impl RRD {
|
||||||
|
|
||||||
|
/// Create a new empty instance
|
||||||
pub fn new(dst: DST) -> Self {
|
pub fn new(dst: DST) -> Self {
|
||||||
let flags = match dst {
|
let flags = match dst {
|
||||||
DST::Gauge => RRAFlags::DST_GAUGE,
|
DST::Gauge => RRAFlags::DST_GAUGE,
|
||||||
|
@ -226,6 +247,7 @@ impl RRD {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract data from the archive
|
||||||
pub fn extract_data(
|
pub fn extract_data(
|
||||||
&self,
|
&self,
|
||||||
time: f64,
|
time: f64,
|
||||||
|
@ -276,6 +298,7 @@ impl RRD {
|
||||||
(start, reso, list)
|
(start, reso, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create instance from raw data, testing data len and magic number
|
||||||
pub fn from_raw(mut raw: &[u8]) -> Result<Self, std::io::Error> {
|
pub fn from_raw(mut raw: &[u8]) -> Result<Self, std::io::Error> {
|
||||||
let expected_len = std::mem::size_of::<RRD>();
|
let expected_len = std::mem::size_of::<RRD>();
|
||||||
if raw.len() != expected_len {
|
if raw.len() != expected_len {
|
||||||
|
@ -297,11 +320,13 @@ impl RRD {
|
||||||
Ok(rrd)
|
Ok(rrd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load data from a file
|
||||||
pub fn load(path: &Path) -> Result<Self, std::io::Error> {
|
pub fn load(path: &Path) -> Result<Self, std::io::Error> {
|
||||||
let raw = std::fs::read(path)?;
|
let raw = std::fs::read(path)?;
|
||||||
Self::from_raw(&raw)
|
Self::from_raw(&raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Store data into a file (atomic replace file)
|
||||||
pub fn save(&self, filename: &Path, options: CreateOptions) -> Result<(), Error> {
|
pub fn save(&self, filename: &Path, options: CreateOptions) -> Result<(), Error> {
|
||||||
let rrd_slice = unsafe {
|
let rrd_slice = unsafe {
|
||||||
std::slice::from_raw_parts(self as *const _ as *const u8, std::mem::size_of::<RRD>())
|
std::slice::from_raw_parts(self as *const _ as *const u8, std::mem::size_of::<RRD>())
|
||||||
|
@ -309,7 +334,9 @@ impl RRD {
|
||||||
replace_file(filename, rrd_slice, options)
|
replace_file(filename, rrd_slice, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the value (in memory)
|
||||||
|
///
|
||||||
|
/// Note: This does not call [Self::save].
|
||||||
pub fn update(&mut self, time: f64, value: f64) {
|
pub fn update(&mut self, time: f64, value: f64) {
|
||||||
self.hour_avg.update(time, value);
|
self.hour_avg.update(time, value);
|
||||||
self.hour_max.update(time, value);
|
self.hour_max.update(time, value);
|
||||||
|
|
|
@ -7,7 +7,7 @@ use pbs_api_types::{
|
||||||
NODE_SCHEMA, RRDMode, RRDTimeFrameResolution, PRIV_SYS_AUDIT,
|
NODE_SCHEMA, RRDMode, RRDTimeFrameResolution, PRIV_SYS_AUDIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
use proxmox_rrd::RRD_DATA_ENTRIES;
|
use proxmox_rrd::rrd::RRD_DATA_ENTRIES;
|
||||||
|
|
||||||
use crate::RRD_CACHE;
|
use crate::RRD_CACHE;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue