proxmox-rrd: improve developer docs

This commit is contained in:
Dietmar Maurer 2021-10-06 12:19:54 +02:00
parent dbc42e6f75
commit 0191759316
4 changed files with 74 additions and 31 deletions

View File

@ -8,7 +8,7 @@ use proxmox::tools::fs::{create_path, CreateOptions};
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
///

View File

@ -1,5 +1,21 @@
mod rrd;
pub use rrd::*;
//! # Simple Round Robin Database files with fixed format
//!
//! ## 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;
pub use cache::*;
/// RRD data source tyoe
pub enum DST {
/// Gauge values are stored unmodified.
Gauge,
/// Stores the difference to the previous value.
Derive,
}

View File

@ -1,7 +1,10 @@
//! # Round Robin Database file format
use std::io::Read;
use std::path::Path;
use anyhow::Error;
use bitflags::bitflags;
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];
pub const PROXMOX_RRD_MAGIC_1_0: [u8; 8] = [206, 46, 26, 212, 172, 158, 5, 186];
use bitflags::bitflags;
use crate::DST;
bitflags!{
struct RRAFlags: u64 {
/// Flags to specify the data soure type and consolidation function
pub struct RRAFlags: u64 {
// Data Source Types
const DST_GAUGE = 1;
const DST_DERIVE = 2;
@ -31,20 +35,24 @@ bitflags!{
}
}
/// RRD data source tyoe
pub enum DST {
Gauge,
Derive,
}
/// Round Robin Archive with [RRD_DATA_ENTRIES] data slots.
///
/// This data structure is used inside [RRD] and directly written to the
/// RRD files.
#[repr(C)]
struct RRA {
flags: RRAFlags,
resolution: u64,
last_update: f64,
last_count: u64,
counter_value: f64, // used for derive/counters
data: [f64; RRD_DATA_ENTRIES],
pub struct RRA {
/// Defined the data soure type and consolidation function
pub flags: RRAFlags,
/// Resulution (seconds) from [RRDTimeFrameResolution]
pub resolution: u64,
/// Last update time (epoch)
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 {
@ -157,24 +165,37 @@ impl RRA {
}
}
/// Round Robin Database file format with fixed number of [RRA]s
#[repr(C)]
// Note: Avoid alignment problems by using 8byte types only
pub struct RRD {
magic: [u8; 8],
hour_avg: RRA,
hour_max: RRA,
day_avg: RRA,
day_max: RRA,
week_avg: RRA,
week_max: RRA,
month_avg: RRA,
month_max: RRA,
year_avg: RRA,
year_max: RRA,
/// The magic number to identify the file type
pub magic: [u8; 8],
/// Hourly data (average values)
pub hour_avg: RRA,
/// Hourly data (maximum values)
pub hour_max: RRA,
/// Dayly data (average values)
pub day_avg: RRA,
/// Dayly data (maximum values)
pub day_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 {
/// Create a new empty instance
pub fn new(dst: DST) -> Self {
let flags = match dst {
DST::Gauge => RRAFlags::DST_GAUGE,
@ -226,6 +247,7 @@ impl RRD {
}
}
/// Extract data from the archive
pub fn extract_data(
&self,
time: f64,
@ -276,6 +298,7 @@ impl RRD {
(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> {
let expected_len = std::mem::size_of::<RRD>();
if raw.len() != expected_len {
@ -297,11 +320,13 @@ impl RRD {
Ok(rrd)
}
/// Load data from a file
pub fn load(path: &Path) -> Result<Self, std::io::Error> {
let raw = std::fs::read(path)?;
Self::from_raw(&raw)
}
/// Store data into a file (atomic replace file)
pub fn save(&self, filename: &Path, options: CreateOptions) -> Result<(), Error> {
let rrd_slice = unsafe {
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)
}
/// Update the value (in memory)
///
/// Note: This does not call [Self::save].
pub fn update(&mut self, time: f64, value: f64) {
self.hour_avg.update(time, value);
self.hour_max.update(time, value);

View File

@ -7,7 +7,7 @@ use pbs_api_types::{
NODE_SCHEMA, RRDMode, RRDTimeFrameResolution, PRIV_SYS_AUDIT,
};
use proxmox_rrd::RRD_DATA_ENTRIES;
use proxmox_rrd::rrd::RRD_DATA_ENTRIES;
use crate::RRD_CACHE;