1 use std
::time
::{SystemTime, UNIX_EPOCH}
;
2 use std
::path
::PathBuf
;
3 use std
::collections
::HashMap
;
4 use std
::sync
::{RwLock}
;
6 use anyhow
::{format_err, Error}
;
7 use lazy_static
::lazy_static
;
8 use serde_json
::{json, Value}
;
10 use proxmox
::tools
::fs
::{create_path, CreateOptions}
;
12 use crate::api2
::types
::{RRDMode, RRDTimeFrameResolution}
;
16 const PBS_RRD_BASEDIR
: &str = "/var/lib/proxmox-backup/rrdb";
19 static ref RRD_CACHE
: RwLock
<HashMap
<String
, RRD
>> = {
20 RwLock
::new(HashMap
::new())
24 /// Create rrdd stat dir with correct permission
25 pub fn create_rrdb_dir() -> Result
<(), Error
> {
27 let backup_user
= crate::backup
::backup_user()?
;
28 let opts
= CreateOptions
::new()
29 .owner(backup_user
.uid
)
30 .group(backup_user
.gid
);
32 create_path(PBS_RRD_BASEDIR
, None
, Some(opts
))
33 .map_err(|err
: Error
| format_err
!("unable to create rrdb stat dir - {}", err
))?
;
38 fn now() -> Result
<f64, Error
> {
39 let time
= SystemTime
::now().duration_since(UNIX_EPOCH
)?
;
40 Ok(time
.as_secs_f64())
43 pub fn update_value(rel_path
: &str, value
: f64, dst
: DST
, save
: bool
) -> Result
<(), Error
> {
45 let mut path
= PathBuf
::from(PBS_RRD_BASEDIR
);
48 std
::fs
::create_dir_all(path
.parent().unwrap())?
;
50 let mut map
= RRD_CACHE
.write().unwrap();
53 if let Some(rrd
) = map
.get_mut(rel_path
) {
54 rrd
.update(now
, value
);
55 if save { rrd.save(&path)?; }
57 let mut rrd
= match RRD
::load(&path
) {
60 if err
.kind() != std
::io
::ErrorKind
::NotFound
{
61 eprintln
!("overwriting RRD file {:?}, because of load error: {}", path
, err
);
66 rrd
.update(now
, value
);
67 if save { rrd.save(&path)?; }
68 map
.insert(rel_path
.into(), rrd
);
77 timeframe
: RRDTimeFrameResolution
,
79 ) -> Result
<Value
, Error
> {
83 let map
= RRD_CACHE
.read().unwrap();
85 let mut result
= Vec
::new();
87 for name
in items
.iter() {
88 let rrd
= match map
.get(&format
!("{}/{}", base
, name
)) {
92 let (start
, reso
, list
) = rrd
.extract_data(now
, timeframe
, mode
);
94 for index
in 0..RRD_DATA_ENTRIES
{
95 if result
.len() <= index
{
96 if let Some(value
) = list
[index
] {
97 result
.push(json
!({ "time": t, *name: value }
));
99 result
.push(json
!({ "time": t }
));
102 if let Some(value
) = list
[index
] {
103 result
[index
][name
] = value
.into();